From 14ebf42f3f408c784a73f476587f9e39facfa97a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 8 Aug 2017 10:26:35 +0900 Subject: [PATCH 0001/1313] Add basic support of IETF QUIC (draft-04) Some features listed on the First Implementation is supported. - Version negotiation - Basic packetization and reliability - Basic STREAM sending and receiving - Integration with TLS 1.3 handshake (1-RTT) - Authentication for cleartext - PADDING frames - Connection ID - Packet protection - Frame parsing for all frames This commit also has - Simple echo QUIC application But this commit doesn't support - Connection Close Many features which are out of scope of First Implementation are also not supported. - The entire HTTP mapping - Congestion control ...etc Co-authored-by: Masakazu Kitajo --- .gitignore | 13 + configure.ac | 29 + iocore/eventsystem/I_Event.h | 2 + iocore/eventsystem/I_Thread.h | 5 + iocore/net/I_NetProcessor.h | 2 + iocore/net/Makefile.am | 8 + iocore/net/P_Net.h | 5 + iocore/net/P_QUICNetProcessor.h | 73 + iocore/net/P_QUICNetVConnection.h | 205 +++ iocore/net/P_QUICPacketHandler.h | 47 + iocore/net/P_SSLUtils.h | 1 + iocore/net/QUICNetProcessor.cc | 144 ++ iocore/net/QUICNetVConnection.cc | 530 +++++++ iocore/net/QUICPacketHandler.cc | 148 ++ iocore/net/SSLUtils.cc | 75 + iocore/net/quic/Makefile.am | 66 + iocore/net/quic/Mock.h | 233 +++ iocore/net/quic/QUICAckFrameCreator.cc | 102 ++ iocore/net/quic/QUICAckFrameCreator.h | 69 + iocore/net/quic/QUICApplication.cc | 139 ++ iocore/net/quic/QUICApplication.h | 79 + iocore/net/quic/QUICCongestionController.cc | 40 + iocore/net/quic/QUICCongestionController.h | 36 + iocore/net/quic/QUICConnectionManager.cc | 42 + iocore/net/quic/QUICConnectionManager.h | 40 + iocore/net/quic/QUICCrypto.cc | 405 +++++ iocore/net/quic/QUICCrypto.h | 121 ++ iocore/net/quic/QUICCrypto_boringssl.cc | 144 ++ iocore/net/quic/QUICCrypto_openssl.cc | 236 +++ iocore/net/quic/QUICDebugNames.cc | 118 ++ iocore/net/quic/QUICDebugNames.h | 35 + iocore/net/quic/QUICEchoApp.cc | 85 ++ iocore/net/quic/QUICEchoApp.h | 42 + iocore/net/quic/QUICEvents.h | 31 + iocore/net/quic/QUICFlowController.cc | 42 + iocore/net/quic/QUICFlowController.h | 36 + iocore/net/quic/QUICFrame.cc | 1315 +++++++++++++++++ iocore/net/quic/QUICFrame.h | 616 ++++++++ iocore/net/quic/QUICFrameDispatcher.cc | 148 ++ iocore/net/quic/QUICFrameDispatcher.h | 53 + iocore/net/quic/QUICFrameHandler.h | 31 + iocore/net/quic/QUICFrameTransmitter.h | 37 + iocore/net/quic/QUICHandshake.cc | 249 ++++ iocore/net/quic/QUICHandshake.h | 68 + iocore/net/quic/QUICLossDetector.cc | 325 ++++ iocore/net/quic/QUICLossDetector.h | 108 ++ iocore/net/quic/QUICPacket.cc | 673 +++++++++ iocore/net/quic/QUICPacket.h | 191 +++ iocore/net/quic/QUICPacketTransmitter.h | 50 + iocore/net/quic/QUICStream.cc | 331 +++++ iocore/net/quic/QUICStream.h | 98 ++ iocore/net/quic/QUICStreamManager.cc | 114 ++ iocore/net/quic/QUICStreamManager.h | 55 + iocore/net/quic/QUICStreamState.cc | 58 + iocore/net/quic/QUICStreamState.h | 54 + iocore/net/quic/QUICTransportParameters.cc | 132 ++ iocore/net/quic/QUICTransportParameters.h | 120 ++ iocore/net/quic/QUICTypes.cc | 140 ++ iocore/net/quic/QUICTypes.h | 179 +++ iocore/net/quic/QUICVersionNegotiator.cc | 63 + iocore/net/quic/QUICVersionNegotiator.h | 47 + iocore/net/quic/test/Makefile.am | 368 +++++ iocore/net/quic/test/event_processor_main.cc | 53 + iocore/net/quic/test/main.cc | 27 + .../net/quic/test/test_QUICAckFrameCreator.cc | 69 + iocore/net/quic/test/test_QUICCrypto.cc | 189 +++ iocore/net/quic/test/test_QUICFrame.cc | 607 ++++++++ .../net/quic/test/test_QUICFrameDispatcher.cc | 74 + iocore/net/quic/test/test_QUICLossDetector.cc | 57 + iocore/net/quic/test/test_QUICPacket.cc | 96 ++ .../net/quic/test/test_QUICPacketFactory.cc | 69 + iocore/net/quic/test/test_QUICStream.cc | 140 ++ iocore/net/quic/test/test_QUICStreamState.cc | 47 + .../quic/test/test_QUICTransportParameters.cc | 164 ++ iocore/net/quic/test/test_QUICTypeUtil.cc | 69 + .../quic/test/test_QUICVersionNegotiator.cc | 47 + lib/records/I_RecHttp.h | 26 +- lib/records/RecHttp.cc | 17 + proxy/Main.cc | 5 + proxy/Makefile.am | 5 +- proxy/hq/HQ.cc | 32 + proxy/hq/HQ.h | 44 + proxy/hq/HQSessionAccept.cc | 85 ++ proxy/hq/HQSessionAccept.h | 56 + proxy/hq/Makefile.am | 43 + proxy/http/HttpProxyServerMain.cc | 11 +- proxy/http/Makefile.am | 3 +- 87 files changed, 11082 insertions(+), 4 deletions(-) create mode 100644 iocore/net/P_QUICNetProcessor.h create mode 100644 iocore/net/P_QUICNetVConnection.h create mode 100644 iocore/net/P_QUICPacketHandler.h create mode 100644 iocore/net/QUICNetProcessor.cc create mode 100644 iocore/net/QUICNetVConnection.cc create mode 100644 iocore/net/QUICPacketHandler.cc create mode 100644 iocore/net/quic/Makefile.am create mode 100644 iocore/net/quic/Mock.h create mode 100644 iocore/net/quic/QUICAckFrameCreator.cc create mode 100644 iocore/net/quic/QUICAckFrameCreator.h create mode 100644 iocore/net/quic/QUICApplication.cc create mode 100644 iocore/net/quic/QUICApplication.h create mode 100644 iocore/net/quic/QUICCongestionController.cc create mode 100644 iocore/net/quic/QUICCongestionController.h create mode 100644 iocore/net/quic/QUICConnectionManager.cc create mode 100644 iocore/net/quic/QUICConnectionManager.h create mode 100644 iocore/net/quic/QUICCrypto.cc create mode 100644 iocore/net/quic/QUICCrypto.h create mode 100644 iocore/net/quic/QUICCrypto_boringssl.cc create mode 100644 iocore/net/quic/QUICCrypto_openssl.cc create mode 100644 iocore/net/quic/QUICDebugNames.cc create mode 100644 iocore/net/quic/QUICDebugNames.h create mode 100644 iocore/net/quic/QUICEchoApp.cc create mode 100644 iocore/net/quic/QUICEchoApp.h create mode 100644 iocore/net/quic/QUICEvents.h create mode 100644 iocore/net/quic/QUICFlowController.cc create mode 100644 iocore/net/quic/QUICFlowController.h create mode 100644 iocore/net/quic/QUICFrame.cc create mode 100644 iocore/net/quic/QUICFrame.h create mode 100644 iocore/net/quic/QUICFrameDispatcher.cc create mode 100644 iocore/net/quic/QUICFrameDispatcher.h create mode 100644 iocore/net/quic/QUICFrameHandler.h create mode 100644 iocore/net/quic/QUICFrameTransmitter.h create mode 100644 iocore/net/quic/QUICHandshake.cc create mode 100644 iocore/net/quic/QUICHandshake.h create mode 100644 iocore/net/quic/QUICLossDetector.cc create mode 100644 iocore/net/quic/QUICLossDetector.h create mode 100644 iocore/net/quic/QUICPacket.cc create mode 100644 iocore/net/quic/QUICPacket.h create mode 100644 iocore/net/quic/QUICPacketTransmitter.h create mode 100644 iocore/net/quic/QUICStream.cc create mode 100644 iocore/net/quic/QUICStream.h create mode 100644 iocore/net/quic/QUICStreamManager.cc create mode 100644 iocore/net/quic/QUICStreamManager.h create mode 100644 iocore/net/quic/QUICStreamState.cc create mode 100644 iocore/net/quic/QUICStreamState.h create mode 100644 iocore/net/quic/QUICTransportParameters.cc create mode 100644 iocore/net/quic/QUICTransportParameters.h create mode 100644 iocore/net/quic/QUICTypes.cc create mode 100644 iocore/net/quic/QUICTypes.h create mode 100644 iocore/net/quic/QUICVersionNegotiator.cc create mode 100644 iocore/net/quic/QUICVersionNegotiator.h create mode 100644 iocore/net/quic/test/Makefile.am create mode 100644 iocore/net/quic/test/event_processor_main.cc create mode 100644 iocore/net/quic/test/main.cc create mode 100644 iocore/net/quic/test/test_QUICAckFrameCreator.cc create mode 100644 iocore/net/quic/test/test_QUICCrypto.cc create mode 100644 iocore/net/quic/test/test_QUICFrame.cc create mode 100644 iocore/net/quic/test/test_QUICFrameDispatcher.cc create mode 100644 iocore/net/quic/test/test_QUICLossDetector.cc create mode 100644 iocore/net/quic/test/test_QUICPacket.cc create mode 100644 iocore/net/quic/test/test_QUICPacketFactory.cc create mode 100644 iocore/net/quic/test/test_QUICStream.cc create mode 100644 iocore/net/quic/test/test_QUICStreamState.cc create mode 100644 iocore/net/quic/test/test_QUICTransportParameters.cc create mode 100644 iocore/net/quic/test/test_QUICTypeUtil.cc create mode 100644 iocore/net/quic/test/test_QUICVersionNegotiator.cc create mode 100644 proxy/hq/HQ.cc create mode 100644 proxy/hq/HQ.h create mode 100644 proxy/hq/HQSessionAccept.cc create mode 100644 proxy/hq/HQSessionAccept.h create mode 100644 proxy/hq/Makefile.am diff --git a/.gitignore b/.gitignore index 6c62df41fc5..a5a618f9733 100644 --- a/.gitignore +++ b/.gitignore @@ -87,6 +87,19 @@ lib/perl/lib/Apache/TS.pm iocore/net/test_certlookup iocore/net/test_UDPNet +iocore/net/quic/test/test_QUICFrame +iocore/net/quic/test/test_QUICFrameDispatcher +iocore/net/quic/test/test_QUICPacket +iocore/net/quic/test/test_QUICPacketFactory +iocore/net/quic/test/test_QUICStream +iocore/net/quic/test/test_QUICStreamState +iocore/net/quic/test/test_QUICTransportParameters +iocore/net/quic/test/test_QUICCrypto +iocore/net/quic/test/test_QUICLossDetector +iocore/net/quic/test/test_QUICTypeUtil +iocore/net/quic/test/test_QUICAckFrameCreator +iocore/net/quic/test/test_QUICVersionNegotiator +iocore/net/quic/ts_quic_client iocore/aio/test_AIO iocore/eventsystem/test_Buffer iocore/eventsystem/test_Event diff --git a/configure.ac b/configure.ac index 33ccce827c8..4e1692d550a 100644 --- a/configure.ac +++ b/configure.ac @@ -1174,6 +1174,31 @@ AC_CHECK_FUNC([EVP_MD_CTX_reset], [], AC_CHECK_FUNC([EVP_MD_CTX_free], [], [AC_DEFINE([EVP_MD_CTX_free], [EVP_MD_CTX_destroy], [Renamed in OpenSSL 1.1])]) +AC_MSG_CHECKING([for TLS 1.3 is supported]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ + #ifndef TLS1_3_VERSION + # error no TLS1_3 support + #endif + ]]) + ], + [AC_MSG_RESULT([yes])], + [AC_ERROR(OpenSSL 1.1.1+ or BoringSSL is required); + AC_MSG_RESULT([no])]) + + +AC_MSG_CHECKING([for OpenSSL is BoringSSL]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ + #ifndef OPENSSL_IS_BORINGSSL + # error not boringssl + #endif + ]]) + ], + [AC_MSG_RESULT([yes]); openssl_is_boringssl=1], + [AC_MSG_RESULT([no])]) +AM_CONDITIONAL([OPENSSL_IS_BORINGSSL], [test -n "$openssl_is_boringssl"]) + LIBS="$saved_LIBS" # @@ -1875,6 +1900,7 @@ AC_SUBST([default_stack_size], [$with_default_stack_size]) iocore_include_dirs="\ -I\$(abs_top_srcdir)/iocore/eventsystem \ -I\$(abs_top_srcdir)/iocore/net \ +-I\$(abs_top_srcdir)/iocore/net/quic \ -I\$(abs_top_srcdir)/iocore/aio \ -I\$(abs_top_srcdir)/iocore/hostdb \ -I\$(abs_top_srcdir)/iocore/cache \ @@ -1932,6 +1958,8 @@ AC_CONFIG_FILES([ iocore/eventsystem/Makefile iocore/hostdb/Makefile iocore/net/Makefile + iocore/net/quic/Makefile + iocore/net/quic/test/Makefile iocore/utils/Makefile lib/Makefile lib/cppapi/Makefile @@ -1961,6 +1989,7 @@ AC_CONFIG_FILES([ proxy/http/Makefile proxy/http/remap/Makefile proxy/http2/Makefile + proxy/hq/Makefile proxy/logging/Makefile proxy/shared/Makefile rc/Makefile diff --git a/iocore/eventsystem/I_Event.h b/iocore/eventsystem/I_Event.h index cfb99ba0a0e..cfc2045df9b 100644 --- a/iocore/eventsystem/I_Event.h +++ b/iocore/eventsystem/I_Event.h @@ -74,6 +74,8 @@ #define HTTP2_SESSION_EVENTS_START 2250 #define HTTP_TUNNEL_EVENTS_START 2300 #define HTTP_SCH_UPDATE_EVENTS_START 2400 +#define QUIC_EVENT_EVENTS_START 2500 +#define HQ_SESSION_EVENTS_START 2600 #define NT_ASYNC_CONNECT_EVENT_EVENTS_START 3000 #define NT_ASYNC_IO_EVENT_EVENTS_START 3100 #define RAFT_EVENT_EVENTS_START 3200 diff --git a/iocore/eventsystem/I_Thread.h b/iocore/eventsystem/I_Thread.h index f053dec1633..a4926b8dddf 100644 --- a/iocore/eventsystem/I_Thread.h +++ b/iocore/eventsystem/I_Thread.h @@ -129,9 +129,14 @@ class Thread ProxyAllocator eventAllocator; ProxyAllocator netVCAllocator; ProxyAllocator sslNetVCAllocator; + ProxyAllocator quicNetVCAllocator; ProxyAllocator http1ClientSessionAllocator; ProxyAllocator http2ClientSessionAllocator; ProxyAllocator http2StreamAllocator; + ProxyAllocator quicClientSessionAllocator; + ProxyAllocator quicHandshakeAllocator; + ProxyAllocator quicStreamAllocator; + ProxyAllocator quicStreamManagerAllocator; ProxyAllocator httpServerSessionAllocator; ProxyAllocator hdrHeapAllocator; ProxyAllocator strHeapAllocator; diff --git a/iocore/net/I_NetProcessor.h b/iocore/net/I_NetProcessor.h index 75ecf064eb0..3e5252846f8 100644 --- a/iocore/net/I_NetProcessor.h +++ b/iocore/net/I_NetProcessor.h @@ -269,4 +269,6 @@ extern inkcoreapi NetProcessor &netProcessor; */ extern inkcoreapi NetProcessor &sslNetProcessor; +extern inkcoreapi NetProcessor &quicNetProcessor; + #endif diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am index f994b549a5f..252a4c3aa8f 100644 --- a/iocore/net/Makefile.am +++ b/iocore/net/Makefile.am @@ -16,6 +16,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +SUBDIRS = quic + AM_CPPFLAGS += \ $(iocore_include_dirs) \ -I$(abs_top_srcdir)/lib \ @@ -112,6 +114,9 @@ libinknet_a_SOURCES = \ P_UDPIOEvent.h \ P_UDPNet.h \ P_UDPPacket.h \ + P_QUICPacketHandler.h \ + P_QUICNetProcessor.h \ + P_QUICNetVConnection.h \ P_UnixCompletionUtil.h \ P_UnixNet.h \ P_UnixNetProcessor.h \ @@ -134,6 +139,9 @@ libinknet_a_SOURCES = \ OCSPStapling.cc \ Socks.cc \ UDPIOEvent.cc \ + QUICPacketHandler.cc \ + QUICNetProcessor.cc \ + QUICNetVConnection.cc \ UnixConnection.cc \ UnixNet.cc \ UnixNetAccept.cc \ diff --git a/iocore/net/P_Net.h b/iocore/net/P_Net.h index 9fecf199216..87456c49e84 100644 --- a/iocore/net/P_Net.h +++ b/iocore/net/P_Net.h @@ -109,6 +109,11 @@ extern RecRawStatBlock *net_rsb; #include "P_SSLNetAccept.h" #include "P_SSLCertLookup.h" +#include "P_QUICNetVConnection.h" +#include "P_QUICNetProcessor.h" +#include "P_QUICPacketHandler.h" +// #include "P_QUICCertLookup.h" + #undef NET_SYSTEM_MODULE_VERSION #define NET_SYSTEM_MODULE_VERSION \ makeModuleVersion(NET_SYSTEM_MODULE_MAJOR_VERSION, NET_SYSTEM_MODULE_MINOR_VERSION, PRIVATE_MODULE_HEADER) diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h new file mode 100644 index 00000000000..461afddd8f7 --- /dev/null +++ b/iocore/net/P_QUICNetProcessor.h @@ -0,0 +1,73 @@ +/** @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 + + */ + +/**************************************************************************** + + P_QUICNetProcessor.h + + The QUIC version of the UnixNetProcessor class. The majority of the logic + is in UnixNetProcessor. The QUICNetProcessor provides the following: + + * QUIC library initialization through the start() method. + * Allocation of a QUICNetVConnection through the allocate_vc virtual method. + + Possibly another pass through could simplify the allocate_vc logic too, but + I think I will stop here for now. + + ****************************************************************************/ +#pragma once + +#include "ts/ink_platform.h" +#include "P_Net.h" +// #include "P_QUICConfig.h" +#include "ts/Map.h" + +class UnixNetVConnection; +struct NetAccept; + +////////////////////////////////////////////////////////////////// +// +// class QUICNetProcessor +// +////////////////////////////////////////////////////////////////// +struct QUICNetProcessor : public UnixNetProcessor { +public: + QUICNetProcessor(); + virtual ~QUICNetProcessor(); + + virtual int start(int, size_t stacksize) override; + void cleanup(); + + virtual NetAccept *createNetAccept(const NetProcessor::AcceptOptions &opt) override; + virtual NetVConnection *allocate_vc(EThread *t) override; + + Action *main_accept(Continuation *cont, SOCKET fd, AcceptOptions const &opt) override; + +private: + QUICNetProcessor(const QUICNetProcessor &); + QUICNetProcessor &operator=(const QUICNetProcessor &); + + SSL_CTX *_ssl_ctx; +}; + +extern QUICNetProcessor quic_NetProcessor; diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h new file mode 100644 index 00000000000..e0bd7cc4223 --- /dev/null +++ b/iocore/net/P_QUICNetVConnection.h @@ -0,0 +1,205 @@ +/** @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. + */ + +/**************************************************************************** + + QUICNetVConnection.h + + This file implements an I/O Processor for network I/O. + + + ****************************************************************************/ +#pragma once + +#include + +#include "ts/ink_platform.h" +#include "P_Net.h" +#include "P_EventSystem.h" +#include "P_UnixNetVConnection.h" +#include "P_UnixNet.h" +#include "P_UDPNet.h" +#include "ts/apidefs.h" +#include "ts/List.h" + +#include "quic/QUICVersionNegotiator.h" +#include "quic/QUICPacket.h" +#include "quic/QUICFrame.h" +#include "quic/QUICFrameDispatcher.h" +#include "quic/QUICHandshake.h" +#include "quic/QUICApplication.h" +#include "quic/QUICStream.h" +#include "quic/QUICCrypto.h" +#include "quic/QUICAckFrameCreator.h" +#include "quic/QUICLossDetector.h" +#include "quic/QUICPacketTransmitter.h" +#include "quic/QUICFrameTransmitter.h" +#include "quic/QUICStreamManager.h" +#include "quic/QUICConnectionManager.h" +#include "quic/QUICFlowController.h" +#include "quic/QUICCongestionController.h" + +// These are included here because older OpenQUIC libraries don't have them. +// Don't copy these defines, or use their values directly, they are merely +// here to avoid compiler errors. +#ifndef QUIC_TLSEXT_ERR_OK +#define QUIC_TLSEXT_ERR_OK 0 +#endif + +#ifndef QUIC_TLSEXT_ERR_NOACK +#define QUIC_TLSEXT_ERR_NOACK 3 +#endif + +#define QUIC_OP_HANDSHAKE 0x16 + +// TS-2503: dynamic TLS record sizing +// For smaller records, we should also reserve space for various TCP options +// (timestamps, SACKs.. up to 40 bytes [1]), and account for TLS record overhead +// (another 20-60 bytes on average, depending on the negotiated ciphersuite [2]). +// All in all: 1500 - 40 (IP) - 20 (TCP) - 40 (TCP options) - TLS overhead (60-100) +// For larger records, the size is determined by TLS protocol record size +#define QUIC_DEF_TLS_RECORD_SIZE 1300 // 1500 - 40 (IP) - 20 (TCP) - 40 (TCP options) - TLS overhead (60-100) +#define QUIC_MAX_TLS_RECORD_SIZE 16383 // 2^14 - 1 +#define QUIC_DEF_TLS_RECORD_BYTE_THRESHOLD 1000000 +#define QUIC_DEF_TLS_RECORD_MSEC_THRESHOLD 1000 + +// class QUICNextProtocolSet; +// struct QUICCertLookup; + +typedef enum { + QUIC_HOOK_OP_DEFAULT, ///< Null / initialization value. Do normal processing. + QUIC_HOOK_OP_TUNNEL, ///< Switch to blind tunnel + QUIC_HOOK_OP_TERMINATE, ///< Termination connection / transaction. + QUIC_HOOK_OP_LAST = QUIC_HOOK_OP_TERMINATE ///< End marker value. +} QuicVConnOp; + +////////////////////////////////////////////////////////////////// +// +// class NetVConnection +// +// A VConnection for a network socket. +// +////////////////////////////////////////////////////////////////// + +typedef std::unique_ptr ats_uint8_t_unique_ptr; + +struct QUICPacketHandler; +class QUICLossDetector; + +/** + * @class QUICNetVConnection + * @brief A NetVConnection for a QUIC network socket + * @detail + * + * state_handshake() + * | READ: + * | _state_handshake_process_initial_client_packet() + * | _state_handshake_process_client_cleartext_packet() + * | _state_handshake_process_zero_rtt_protected_packet() + * | WRITE: + * | _state_common_send_packet() + * v + * state_connection_established() + * | READ: + * | _state_connection_established_process_packet() + * | WRITE: + * | _state_common_send_packet() + * v + * X + * + **/ +class QUICNetVConnection : public UnixNetVConnection, public QUICPacketTransmitter, public QUICFrameTransmitter +{ + typedef UnixNetVConnection super; ///< Parent type. + +public: + QUICNetVConnection(); + + void init(UDPConnection *, QUICPacketHandler *); + + void reenable(VIO *vio) override; + VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override; + VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) override; + int startEvent(int event, Event *e); + int state_handshake(int event, Event *data); + int state_connection_established(int event, Event *data); + void start(SSL_CTX *); + uint32_t maximum_quic_packet_size(); + uint32_t minimum_quic_packet_size(); + virtual void transmit_packet(std::unique_ptr packet) override; + virtual void retransmit_packet(const QUICPacket &packet) override; + virtual Ptr get_transmitter_mutex() override; + void push_packet(std::unique_ptr packet); + virtual void transmit_frame(std::unique_ptr frame) override; + void close(QUICError error); + void free(EThread *t) override; + + UDPConnection *get_udp_con(); + QUICApplication *get_application(QUICStreamId stream_id); + QUICCrypto *get_crypto(); + + virtual void net_read_io(NetHandler *nh, EThread *lthread) override; + virtual int64_t load_buffer_and_write(int64_t towrite, MIOBufferAccessor &buf, int64_t &total_written, int &needs) override; + +private: + QUICConnectionId _quic_connection_id; + UDPConnection *_udp_con = nullptr; + QUICPacketHandler *_packet_handler = nullptr; + QUICPacketFactory _packet_factory; + QUICFrameFactory _frame_factory; + QUICAckFrameCreator _ack_frame_creator; + + uint32_t _pmtu = 1280; + + // TODO: use custom allocator and make them std::unique_ptr or std::shared_ptr + // or make them just member variables. + QUICVersionNegotiator *_version_negotiator = nullptr; + QUICHandshake *_handshake_handler = nullptr; + QUICApplication *_application = nullptr; + QUICCrypto *_crypto = nullptr; + std::shared_ptr _loss_detector = nullptr; + std::shared_ptr _stream_manager = nullptr; + QUICFrameDispatcher *_frame_dispatcher = nullptr; + + Queue _packet_recv_queue; + Queue _packet_send_queue; + std::queue> _frame_buffer; + + void _packetize_frames(); + std::unique_ptr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, + QUICPacketType type = QUICPacketType::UNINITIALIZED); + + void _recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_num); + + QUICError _state_handshake_process_initial_client_packet(std::unique_ptr packet); + QUICError _state_handshake_process_client_cleartext_packet(std::unique_ptr packet); + QUICError _state_handshake_process_zero_rtt_protected_packet(std::unique_ptr packet); + QUICError _state_connection_established_process_packet(std::unique_ptr packet); + QUICError _state_common_send_packet(); + + Ptr _transmitter_mutex; +}; + +typedef int (QUICNetVConnection::*QUICNetVConnHandler)(int, void *); + +extern ClassAllocator quicNetVCAllocator; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h new file mode 100644 index 00000000000..4d21060854b --- /dev/null +++ b/iocore/net/P_QUICPacketHandler.h @@ -0,0 +1,47 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include "ts/ink_platform.h" +#include "P_Connection.h" +#include "P_NetAccept.h" +#include "P_QUICNetVConnection.h" + +struct QUICPacketHandler : public NetAccept { +public: + QUICPacketHandler(const NetProcessor::AcceptOptions &opt, SSL_CTX *); + virtual ~QUICPacketHandler(); + + virtual NetProcessor *getNetProcessor() const override; + virtual NetAccept *clone() const override; + virtual int acceptEvent(int event, void *e) override; + void init_accept(EThread *t) override; + void send_packet(const QUICPacket &packet, QUICNetVConnection *vc); + +private: + void _recv_packet(int event, UDPPacket *udpPacket); + + Map _connections; + SSL_CTX *_ssl_ctx; +}; diff --git a/iocore/net/P_SSLUtils.h b/iocore/net/P_SSLUtils.h index a3d530df825..01a629876de 100644 --- a/iocore/net/P_SSLUtils.h +++ b/iocore/net/P_SSLUtils.h @@ -161,6 +161,7 @@ void SSLDebugBufferPrint(const char *tag, const char *buffer, unsigned buflen, c // Load the SSL certificate configuration. bool SSLParseCertificateConfiguration(const SSLConfigParams *params, SSLCertLookup *lookup); +bool SSLParseCertificateConfiguration(const SSLConfigParams *params, SSL_CTX *ssl_ctx); // Attach a SSL NetVC back pointer to a SSL session. void SSLNetVCAttach(SSL *ssl, SSLNetVConnection *vc); diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc new file mode 100644 index 00000000000..72fb4e14df9 --- /dev/null +++ b/iocore/net/QUICNetProcessor.cc @@ -0,0 +1,144 @@ +/** @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 "ts/ink_config.h" + +#include "P_Net.h" +#include "ts/I_Layout.h" +#include "I_RecHttp.h" +// #include "P_QUICUtils.h" + +// +// Global Data +// + +QUICNetProcessor quic_NetProcessor; + +QUICNetProcessor::QUICNetProcessor() +{ +} + +QUICNetProcessor::~QUICNetProcessor() +{ + cleanup(); +} + +void +QUICNetProcessor::cleanup() +{ + SSL_CTX_free(this->_ssl_ctx); +} + +int +QUICNetProcessor::start(int, size_t stacksize) +{ + // This initialization order matters ... + // QUICInitializeLibrary(); + // QUICConfig::startup(); + + // if (!QUICCertificateConfig::startup()) + // return -1; + + // Acquire a QUICConfigParams instance *after* we start QUIC up. + // QUICConfig::scoped_config params; + + // Initialize QUIC statistics. This depends on an initial set of certificates being loaded above. + // QUICInitializeStatistics(); + + // TODO: load certs from SSLConfig + this->_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(this->_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(this->_ssl_ctx, TLS1_3_VERSION); + + SSLConfig::scoped_config params; + SSLParseCertificateConfiguration(params, this->_ssl_ctx); + + if (SSL_CTX_check_private_key(this->_ssl_ctx) != 1) { + Error("check private key failed"); + ink_assert(false); + } + + return 0; +} + +NetAccept * +QUICNetProcessor::createNetAccept(const NetProcessor::AcceptOptions &opt) +{ + return (NetAccept *)new QUICPacketHandler(opt, this->_ssl_ctx); +} + +NetVConnection * +QUICNetProcessor::allocate_vc(EThread *t) +{ + QUICNetVConnection *vc; + + if (t) { + vc = THREAD_ALLOC_INIT(quicNetVCAllocator, t); + } else { + if (likely(vc = quicNetVCAllocator.alloc())) { + vc->from_accept_thread = true; + } + } + + return vc; +} + +Action * +QUICNetProcessor::main_accept(Continuation *cont, SOCKET fd, AcceptOptions const &opt) +{ + // UnixNetProcessor *this_unp = static_cast(this); + Debug("iocore_net_processor", "NetProcessor::main_accept - port %d,recv_bufsize %d, send_bufsize %d, sockopt 0x%0x", + opt.local_port, opt.recv_bufsize, opt.send_bufsize, opt.sockopt_flags); + + ProxyMutex *mutex = this_ethread()->mutex.get(); + int accept_threads = opt.accept_threads; // might be changed. + IpEndpoint accept_ip; // local binding address. + // char thr_name[MAX_THREAD_NAME_LENGTH]; + + NetAccept *na = createNetAccept(opt); + if (opt.accept_threads < 0) { + REC_ReadConfigInteger(accept_threads, "proxy.config.accept_threads"); + } + NET_INCREMENT_DYN_STAT(net_accepts_currently_open_stat); + + if (opt.localhost_only) { + accept_ip.setToLoopback(opt.ip_family); + } else if (opt.local_ip.isValid()) { + accept_ip.assign(opt.local_ip); + } else { + accept_ip.setToAnyAddr(opt.ip_family); + } + ink_assert(0 < opt.local_port && opt.local_port < 65536); + accept_ip.port() = htons(opt.local_port); + + na->accept_fn = net_accept; + na->server.fd = fd; + ats_ip_copy(&na->server.accept_addr, &accept_ip); + + na->action_ = new NetAcceptAction(); + *na->action_ = cont; + na->action_->server = &na->server; + na->init_accept(); + + udpNet.UDPBind((Continuation *)na, &na->server.accept_addr.sa, 1024000, 1024000); + + return na->action_.get(); +} diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc new file mode 100644 index 00000000000..926568f4a77 --- /dev/null +++ b/iocore/net/QUICNetVConnection.cc @@ -0,0 +1,530 @@ +/** @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 +#include + +#include "ts/ink_config.h" +#include "ts/EventNotify.h" +#include "records/I_RecHttp.h" +#include "ts/Diags.h" + +#include "P_Net.h" +#include "InkAPIInternal.h" // Added to include the quic_hook definitions +#include "BIO_fastopen.h" +#include "Log.h" + +#include "QUICEchoApp.h" +#include "QUICDebugNames.h" +#include "QUICEvents.h" + +#define STATE_FROM_VIO(_x) ((NetState *)(((char *)(_x)) - STATE_VIO_OFFSET)) +#define STATE_VIO_OFFSET ((uintptr_t) & ((NetState *)0)->vio) + +const static char *tag = "quic_net"; + +const static uint32_t MINIMUM_MTU = 1280; +const static uint32_t MAX_PACKET_OVERHEAD = 25; // Max long header len(17) + FNV-1a hash len(8) + +ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); + +QUICNetVConnection::QUICNetVConnection() : UnixNetVConnection() +{ + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_handshake); +} + +void +QUICNetVConnection::init(UDPConnection *udp_con, QUICPacketHandler *packet_handler) +{ + this->_transmitter_mutex = new_ProxyMutex(); + this->_udp_con = udp_con; + this->_transmitter_mutex = new_ProxyMutex(); + this->_packet_handler = packet_handler; + this->_quic_connection_id.randomize(); +} + +VIO * +QUICNetVConnection::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + return super::do_io_read(c, nbytes, buf); +} + +VIO * +QUICNetVConnection::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +{ + return super::do_io_write(c, nbytes, buf, owner); +} + +int +QUICNetVConnection::startEvent(int /*event ATS_UNUSED */, Event *e) +{ + return EVENT_DONE; +} + +// XXX This might be called on ET_UDP thread +void +QUICNetVConnection::start(SSL_CTX *ssl_ctx) +{ + this->_version_negotiator = new QUICVersionNegotiator(&this->_packet_factory, this); + this->_crypto = new QUICCrypto(ssl_ctx, this->netvc_context); + this->_packet_factory.set_crypto_module(this->_crypto); + + // FIXME Should these have to be shared_ptr? + this->_loss_detector = std::make_shared(this); + this->_stream_manager = std::make_shared(); + this->_stream_manager->init(this); + this->_stream_manager->set_connection(this); // FIXME Want to remove; + + std::shared_ptr connectionManager = std::make_shared(this); + std::shared_ptr flowController = std::make_shared(); + std::shared_ptr congestionController = std::make_shared(); + this->_frame_dispatcher = + new QUICFrameDispatcher(connectionManager, this->_stream_manager, flowController, congestionController, this->_loss_detector); + + // TODO set timeout from conf + this->set_active_timeout(0); + this->set_inactivity_timeout(2); +} + +// TODO: call free when close connection +void +QUICNetVConnection::free(EThread *t) +{ + this->_udp_con = nullptr; + this->_packet_handler = nullptr; + + delete this->_version_negotiator; + delete this->_handshake_handler; + delete this->_application; + delete this->_crypto; + delete this->_frame_dispatcher; + // XXX _loss_detector and _stream_manager are std::shared_ptr + + // TODO: clear member variables like `UnixNetVConnection::free(EThread *t)` + this->mutex.clear(); + + if (from_accept_thread) { + quicNetVCAllocator.free(this); + } else { + THREAD_FREE(this, quicNetVCAllocator, t); + } +} + +void +QUICNetVConnection::reenable(VIO *vio) +{ + return; +} + +uint32_t +QUICNetVConnection::minimum_quic_packet_size() +{ + if (this->options.ip_family == PF_INET6) { + return MINIMUM_MTU - 48; + } else { + return MINIMUM_MTU - 28; + } +} + +uint32_t +QUICNetVConnection::maximum_quic_packet_size() +{ + if (this->options.ip_family == PF_INET6) { + return this->_pmtu - 48; + } else { + return this->_pmtu - 28; + } +} + +void +QUICNetVConnection::transmit_packet(std::unique_ptr packet) +{ + // TODO Remove const_cast + this->_packet_send_queue.enqueue(const_cast(packet.release())); + eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); +} + +void +QUICNetVConnection::retransmit_packet(const QUICPacket &packet) +{ + uint16_t size = packet.payload_size(); + const uint8_t *payload = packet.payload(); + + std::unique_ptr frame(nullptr, &QUICFrameDeleter::delete_null_frame); + uint16_t cursor = 0; + + while (cursor < size) { + frame = QUICFrameFactory::create(payload + cursor, size - cursor); + cursor += frame->size(); + + switch (frame->type()) { + case QUICFrameType::PADDING: + case QUICFrameType::ACK: + break; + default: + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), packet); + this->transmit_frame(std::move(frame)); + break; + } + } +} + +Ptr +QUICNetVConnection::get_transmitter_mutex() +{ + return this->_transmitter_mutex; +} + +void +QUICNetVConnection::push_packet(std::unique_ptr packet) +{ + Debug(tag, "Type=%s Size=%u", QUICDebugNames::packet_type(packet->type()), packet->size()); + this->_packet_recv_queue.enqueue(const_cast(packet.release())); +} + +void +QUICNetVConnection::transmit_frame(std::unique_ptr frame) +{ + Debug(tag, "Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); + this->_frame_buffer.push(std::move(frame)); + eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); +} + +void +QUICNetVConnection::close(QUICError error) +{ + this->transmit_frame(QUICFrameFactory::create_connection_close_frame(error.code, 0, "")); +} + +int +QUICNetVConnection::state_handshake(int event, Event *data) +{ + QUICError error; + + if (!thread) { + thread = this_ethread(); + } + + if (!nh) { + nh = get_NetHandler(this_ethread()); + } + + switch (event) { + case QUIC_EVENT_PACKET_READ_READY: { + std::unique_ptr p = std::unique_ptr(this->_packet_recv_queue.dequeue()); + switch (p->type()) { + case QUICPacketType::CLIENT_INITIAL: + error = this->_state_handshake_process_initial_client_packet(std::move(p)); + break; + case QUICPacketType::CLIENT_CLEARTEXT: + error = this->_state_handshake_process_client_cleartext_packet(std::move(p)); + break; + case QUICPacketType::ZERO_RTT_PROTECTED: + error = this->_state_handshake_process_zero_rtt_protected_packet(std::move(p)); + break; + default: + error = QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + break; + } + + break; + } + case QUIC_EVENT_PACKET_WRITE_READY: { + error = this->_state_common_send_packet(); + break; + } + default: + Debug(tag, "Unexpected event: %u", event); + } + + if (error.cls != QUICErrorClass::NONE) { + // TODO: Send error if needed + Debug(tag, "QUICError: cls=%u, code=0x%x", error.cls, error.code); + } + + if (this->_handshake_handler && this->_handshake_handler->is_completed()) { + Debug(tag, "Enter state_connection_established"); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); + } + + return EVENT_CONT; +} + +int +QUICNetVConnection::state_connection_established(int event, Event *data) +{ + QUICError error; + switch (event) { + case QUIC_EVENT_PACKET_READ_READY: { + std::unique_ptr p = std::unique_ptr(this->_packet_recv_queue.dequeue()); + switch (p->type()) { + case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: + case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: + error = this->_state_connection_established_process_packet(std::move(p)); + break; + default: + error = QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + break; + } + break; + } + case QUIC_EVENT_PACKET_WRITE_READY: { + error = this->_state_common_send_packet(); + break; + } + } + + if (error.cls != QUICErrorClass::NONE) { + // TODO: Send error if needed + Debug(tag, "QUICError: cls=%u, code=0x%x", error.cls, error.code); + } + + return EVENT_CONT; +} + +UDPConnection * +QUICNetVConnection::get_udp_con() +{ + return this->_udp_con; +} + +QUICApplication * +QUICNetVConnection::get_application(QUICStreamId stream_id) +{ + if (stream_id == STREAM_ID_FOR_HANDSHAKE) { + return static_cast(this->_handshake_handler); + } else { + if (!this->_application) { + Debug(tag, "setup quic application"); + // TODO: Instantiate negotiated application + const uint8_t *application = this->_handshake_handler->negotiated_application_name(); + if (memcmp(application, "hq", 2) == 0) { + QUICEchoApp *echo_app = new QUICEchoApp(new_ProxyMutex(), this); + this->_application = echo_app; + } + } + } + return this->_application; +} + +QUICCrypto * +QUICNetVConnection::get_crypto() +{ + return this->_crypto; +} + +void +QUICNetVConnection::net_read_io(NetHandler *nh, EThread *lthread) +{ + ink_assert(false); + + return; +} + +int64_t +QUICNetVConnection::load_buffer_and_write(int64_t towrite, MIOBufferAccessor &buf, int64_t &total_written, int &needs) +{ + ink_assert(false); + + return 0; +} + +QUICError +QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_ptr packet) +{ + if (packet->size() < this->minimum_quic_packet_size()) { + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + } + + // Negotiate version + if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) { + if (packet->type() != QUICPacketType::CLIENT_INITIAL) { + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + } + if (packet->version()) { + if (this->_version_negotiator->negotiate(packet.get()) == QUICVersionNegotiationStatus::NEGOTIATED) { + Debug(tag, "Version negotiation succeeded: %x", packet->version()); + this->_packet_factory.set_version(packet->version()); + // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing) + if (packet->has_valid_fnv1a_hash()) { + this->_handshake_handler = new QUICHandshake(new_ProxyMutex(), this); + this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size()); + } else { + Debug(tag, "Invalid FNV-1a hash value"); + } + } else { + Debug(tag, "Version negotiation failed: %x", packet->version()); + } + } else { + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + } + } + + return QUICError(QUICErrorClass::NONE); +} + +QUICError +QUICNetVConnection::_state_handshake_process_client_cleartext_packet(std::unique_ptr packet) +{ + // The payload of this packet contains STREAM frames and could contain PADDING and ACK frames + if (packet->has_valid_fnv1a_hash()) { + this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); + } else { + Debug(tag, "Invalid FNV-1a hash value"); + } + return QUICError(QUICErrorClass::NONE); +} + +QUICError +QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(std::unique_ptr packet) +{ + // TODO: Decrypt the packet + // decrypt(payload, p); + // TODO: Not sure what we have to do + return QUICError(QUICErrorClass::NONE); +} + +QUICError +QUICNetVConnection::_state_connection_established_process_packet(std::unique_ptr packet) +{ + // TODO: fix size + 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; + + if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, packet->payload(), packet->payload_size(), + packet->packet_number(), packet->header(), packet->header_size(), packet->key_phase())) { + Debug(tag, "Decrypt Packet, pkt_num: %llu, header_len: %hu, payload_len: %zu", packet->packet_number(), packet->header_size(), + plain_txt_len); + + this->_recv_and_ack(plain_txt.get(), plain_txt_len, packet->packet_number()); + + return QUICError(QUICErrorClass::NONE); + } else { + Debug(tag, "CRYPTOGRAPHIC Error"); + + return QUICError(QUICErrorClass::CRYPTOGRAPHIC); + } +} + +QUICError +QUICNetVConnection::_state_common_send_packet() +{ + this->_packetize_frames(); + + const QUICPacket *packet; + while ((packet = this->_packet_send_queue.dequeue()) != nullptr) { + this->_packet_handler->send_packet(*packet, this); + this->_loss_detector->on_packet_sent(std::unique_ptr(packet)); + } + + return QUICError(QUICErrorClass::NONE); +} + +void +QUICNetVConnection::_packetize_frames() +{ + uint32_t max_size = this->maximum_quic_packet_size(); + uint32_t min_size = this->minimum_quic_packet_size(); + ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); + size_t len = 0; + + // Put frames into buf as many as possible + std::unique_ptr frame(nullptr, nullptr); + bool retransmittable = false; + QUICPacketType previous_packet_type = QUICPacketType::UNINITIALIZED; + QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; + + while (this->_frame_buffer.size() > 0) { + frame = std::move(this->_frame_buffer.front()); + this->_frame_buffer.pop(); + QUICRetransmissionFrame *rf = dynamic_cast(frame.get()); + previous_packet_type = current_packet_type; + if (rf) { + current_packet_type = rf->packet_type(); + } else { + current_packet_type = QUICPacketType::UNINITIALIZED; + } + if (len + frame->size() + MAX_PACKET_OVERHEAD > max_size || (previous_packet_type != current_packet_type && len > 0)) { + ink_assert(len > 0); + SCOPED_MUTEX_LOCK(transmitter_lock, this->get_transmitter_mutex().get(), this_ethread()); + this->transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, previous_packet_type)); + len = 0; + } + retransmittable = retransmittable || (frame->type() != QUICFrameType::ACK && frame->type() != QUICFrameType::PADDING); + + if (buf == nullptr) { + buf = ats_unique_malloc(max_size); + } + size_t l = 0; + Debug(tag, "type=%s", QUICDebugNames::frame_type(frame->type())); + frame->store(buf.get() + len, &l); + len += l; + } + + if (len != 0) { + // Pad with PADDING frames + if (min_size > len) { + // FIXME QUICNetVConnection should not know the actual type value of PADDING frame + memset(buf.get() + len, 0, min_size - len); + len += min_size - len; + } + SCOPED_MUTEX_LOCK(transmitter_lock, this->get_transmitter_mutex().get(), this_ethread()); + this->transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, current_packet_type)); + } +} + +void +QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_num) +{ + bool should_send_ack = this->_frame_dispatcher->receive_frames(payload, size); + this->_ack_frame_creator.update(packet_num, should_send_ack); + std::unique_ptr ack_frame = this->_ack_frame_creator.create_if_needed(); + if (ack_frame != nullptr) { + this->transmit_frame(std::move(ack_frame)); + eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + } +} + +std::unique_ptr +QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type) +{ + std::unique_ptr packet; + Debug(tag, "retransmittable %u", retransmittable); + + switch (type) { + case QUICPacketType::SERVER_CLEARTEXT: + packet = this->_packet_factory.create_server_cleartext_packet(this->_quic_connection_id, std::move(buf), len, retransmittable); + break; + default: + if (this->_handshake_handler && this->_handshake_handler->is_completed()) { + packet = + this->_packet_factory.create_server_protected_packet(this->_quic_connection_id, std::move(buf), len, retransmittable); + } else { + packet = + this->_packet_factory.create_server_cleartext_packet(this->_quic_connection_id, std::move(buf), len, retransmittable); + } + break; + } + + return packet; +} diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc new file mode 100644 index 00000000000..88474296fdc --- /dev/null +++ b/iocore/net/QUICPacketHandler.cc @@ -0,0 +1,148 @@ +/** @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 "ts/ink_config.h" +#include "P_Net.h" + +#include "QUICPacket.h" +#include "QUICDebugNames.h" +#include "QUICEvents.h" + +QUICPacketHandler::QUICPacketHandler(const NetProcessor::AcceptOptions &opt, SSL_CTX *ctx) : NetAccept(opt), _ssl_ctx(ctx) +{ + this->mutex = new_ProxyMutex(); +} + +QUICPacketHandler::~QUICPacketHandler() +{ +} + +NetProcessor * +QUICPacketHandler::getNetProcessor() const +{ + return &quic_NetProcessor; +} + +NetAccept * +QUICPacketHandler::clone() const +{ + NetAccept *na; + na = new QUICPacketHandler(opt, this->_ssl_ctx); + *na = *this; + return na; +} + +int +QUICPacketHandler::acceptEvent(int event, void *data) +{ + // NetVConnection *netvc; + ink_release_assert(event == NET_EVENT_DATAGRAM_OPEN || event == NET_EVENT_DATAGRAM_READ_READY || + event == NET_EVENT_DATAGRAM_ERROR); + ink_release_assert((event == NET_EVENT_DATAGRAM_OPEN) ? (data != nullptr) : (1)); + ink_release_assert((event == NET_EVENT_DATAGRAM_READ_READY) ? (data != nullptr) : (1)); + + if (event == NET_EVENT_DATAGRAM_OPEN) { + // Nothing to do. + return EVENT_CONT; + } else if (event == NET_EVENT_DATAGRAM_READ_READY) { + Queue *queue = (Queue *)data; + UDPPacket *packet_r; + ip_port_text_buffer ipb; + while ((packet_r = queue->dequeue())) { + Debug("quic_sec", "received packet from %s, size=%lld", ats_ip_nptop(&packet_r->from.sa, ipb, sizeof(ipb)), + packet_r->getPktLength()); + this->_recv_packet(event, packet_r); + } + return EVENT_CONT; + } + + ///////////////// + // EVENT_ERROR // + ///////////////// + if (((long)data) == -ECONNABORTED) { + } + + ink_abort("QUIC accept received fatal error: errno = %d", -((int)(intptr_t)data)); + return EVENT_CONT; + return 0; +} + +void +QUICPacketHandler::init_accept(EThread *t = nullptr) +{ + SET_HANDLER(&QUICPacketHandler::acceptEvent); +} + +void +QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) +{ + IOBufferBlock *block = udpPacket->getIOBlockChain(); + + std::unique_ptr qPkt = std::unique_ptr(QUICPacketFactory::create(block)); + QUICNetVConnection *vc = this->_connections.get(qPkt->connection_id()); + + if (!vc) { + // Unknown Connection ID + Connection con; + con.setRemote(&udpPacket->from.sa); + vc = + static_cast(getNetProcessor()->allocate_vc(((UnixUDPConnection *)udpPacket->getConnection())->ethread)); + vc->init(udpPacket->getConnection(), this); + vc->id = net_next_connection_number(); + vc->con.move(con); + vc->submit_time = Thread::get_hrtime(); + vc->mutex = this->mutex; + vc->action_ = *this->action_; + vc->set_is_transparent(this->opt.f_inbound_transparent); + vc->set_context(NET_VCONNECTION_IN); + vc->read.triggered = 1; + vc->start(this->_ssl_ctx); + // TODO: Handle Connection ID of Client Cleartext / Non-Final Server Cleartext Packet + this->_connections.put(qPkt->connection_id(), vc); + } + + vc->push_packet(std::move(qPkt)); + + // send to EThread + eventProcessor.schedule_imm(vc, ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr); +} + +// TODO: Should be called via eventProcessor? +void +QUICPacketHandler::send_packet(const QUICPacket &packet, QUICNetVConnection *vc) +{ + // TODO: remove a connection which is created by Client Initial + // or update key to new one + if (!this->_connections.get(packet.connection_id())) { + this->_connections.put(packet.connection_id(), vc); + } + + uint8_t udp_payload[65536]; + size_t udp_len; + packet.store(udp_payload, &udp_len); + UDPPacket *udpPkt = new_UDPPacket(vc->con.addr, 0, reinterpret_cast(udp_payload), udp_len); + + // NOTE: p will be enqueued to udpOutQueue of UDPNetHandler + ip_port_text_buffer ipb; + Debug("quic_sec", "send %s packet to %s, size=%lld", QUICDebugNames::packet_type(packet.type()), + ats_ip_nptop(&udpPkt->to.sa, ipb, sizeof(ipb)), udpPkt->getPktLength()); + vc->get_udp_con()->send(this, udpPkt); +} diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc index 49cb5e3ce5c..a01510e2dda 100644 --- a/iocore/net/SSLUtils.cc +++ b/iocore/net/SSLUtils.cc @@ -1965,6 +1965,81 @@ ssl_extract_certificate(const matcher_line *line_info, ssl_user_config &sslMultC return true; } +// TODO: remove this function and setup SSL_CTX for QUIC somehow +bool +SSLParseCertificateConfiguration(const SSLConfigParams *params, SSL_CTX *ssl_ctx) +{ + char *tok_state = nullptr; + char *line = nullptr; + ats_scoped_str file_buf; + unsigned line_num = 0; + matcher_line line_info; + + const matcher_tags sslCertTags = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, false}; + + Note("loading SSL certificate configuration from %s", params->configFilePath); + + if (params->configFilePath) { + file_buf = readIntoBuffer(params->configFilePath, __func__, nullptr); + } + + if (!file_buf) { + Error("failed to read SSL certificate configuration from %s", params->configFilePath); + return false; + } + + // Optionally elevate/allow file access to read root-only + // certificates. The destructor will drop privilege for us. + uint32_t elevate_setting = 0; + REC_ReadConfigInteger(elevate_setting, "proxy.config.ssl.cert.load_elevated"); + ElevateAccess elevate_access(elevate_setting ? ElevateAccess::FILE_PRIVILEGE : 0); + + line = tokLine(file_buf, &tok_state); + while (line != nullptr) { + line_num++; + + // Skip all blank spaces at beginning of line. + while (*line && isspace(*line)) { + line++; + } + + if (*line != '\0' && *line != '#') { + ssl_user_config sslMultiCertSettings; + const char *errPtr; + + errPtr = parseConfigLine(line, &line_info, &sslCertTags); + + if (errPtr != nullptr) { + RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "%s: discarding %s entry at line %d: %s", __func__, params->configFilePath, + line_num, errPtr); + } else { + if (ssl_extract_certificate(&line_info, sslMultiCertSettings)) { + // There must be a certificate specified unless the tunnel action is set + if (sslMultiCertSettings.cert || sslMultiCertSettings.opt != SSLCertContext::OPT_TUNNEL) { + if (SSL_CTX_use_PrivateKey_file(ssl_ctx, sslMultiCertSettings.key.get(), SSL_FILETYPE_PEM) != 1) { + Error("Couldn't load private_key: %s", sslMultiCertSettings.key.get()); + return false; + } + + if (SSL_CTX_use_certificate_chain_file(ssl_ctx, sslMultiCertSettings.cert.get()) != 1) { + Error("Couldn't load cert: %s", sslMultiCertSettings.cert.get()); + return false; + } + + return true; + + } else { + Warning("No ssl_cert_name specified and no tunnel action set"); + } + } + } + } + + line = tokLine(nullptr, &tok_state); + } + return true; +} + bool SSLParseCertificateConfiguration(const SSLConfigParams *params, SSLCertLookup *lookup) { diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am new file mode 100644 index 00000000000..b0b799aecaa --- /dev/null +++ b/iocore/net/quic/Makefile.am @@ -0,0 +1,66 @@ +# Makefile.am for the traffic/iocore/net hierarchy +# +# 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. + +SUBDIRS = test + +AM_CPPFLAGS += \ + $(iocore_include_dirs) \ + -I$(abs_top_srcdir)/lib \ + -I$(abs_top_srcdir)/lib/records \ + -I$(abs_top_srcdir)/proxy \ + -I$(abs_top_srcdir)/proxy/hdrs \ + -I$(abs_top_srcdir)/proxy/shared \ + -I$(abs_top_srcdir)/proxy/logging \ + -I$(abs_top_srcdir)/mgmt \ + -I$(abs_top_srcdir)/mgmt/utils \ + -I$(abs_top_srcdir)/proxy/http \ + @OPENSSL_INCLUDES@ + +noinst_LIBRARIES = libquic.a + +if OPENSSL_IS_BORINGSSL +QUICCrypto_impl = QUICCrypto_boringssl.cc +else +QUICCrypto_impl = QUICCrypto_openssl.cc +endif + +libquic_a_SOURCES = \ + QUICTypes.cc \ + QUICPacket.cc \ + QUICFrame.cc \ + QUICFrameDispatcher.cc \ + QUICVersionNegotiator.cc \ + QUICConnectionManager.cc \ + QUICLossDetector.cc \ + QUICStreamManager.cc \ + QUICFlowController.cc \ + QUICCongestionController.cc \ + QUICStreamState.cc \ + QUICStream.cc \ + QUICHandshake.cc \ + QUICCrypto.cc \ + $(QUICCrypto_impl) \ + QUICAckFrameCreator.cc \ + QUICDebugNames.cc \ + QUICApplication.cc \ + QUICEchoApp.cc + +include $(top_srcdir)/build/tidy.mk + +tidy-local: $(DIST_SOURCES) + $(CXX_Clang_Tidy) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h new file mode 100644 index 00000000000..094bce30be5 --- /dev/null +++ b/iocore/net/quic/Mock.h @@ -0,0 +1,233 @@ +#include "QUICConnectionManager.h" +#include "QUICStreamManager.h" +#include "QUICFlowController.h" +#include "QUICCongestionController.h" +#include "QUICLossDetector.h" +#include "QUICEvents.h" +#include "QUICPacketTransmitter.h" + +class MockQUICPacketTransmitter : public QUICPacketTransmitter +{ +public: + MockQUICPacketTransmitter() : QUICPacketTransmitter() { + this->_mutex= new_ProxyMutex(); + }; + + void + transmit_packet(std::unique_ptr packet) override + { + ++_transmit_count; + } + + void + retransmit_packet(const QUICPacket &packet) override + { + ++_retransmit_count; + } + + Ptr + get_transmitter_mutex() override + { + return this->_mutex; + } + + int _transmit_count = 0; + int _retransmit_count = 0; + Ptr _mutex; +}; + +class MockQUICFrameTransmitter : public QUICFrameTransmitter +{ + void + transmit_frame(std::unique_ptr frame) + { + } +}; + +class MockQUICLossDetector : public QUICLossDetector +{ +public: + MockQUICLossDetector() : QUICLossDetector(new MockQUICPacketTransmitter()) {} + + void + rcv_frame(std::shared_ptr) + { + } + + void + on_packet_sent(std::unique_ptr packet) + { + } +}; + +class MockQUICConnectionManager : public QUICConnectionManager +{ +public: + MockQUICConnectionManager() : QUICConnectionManager(new MockQUICFrameTransmitter()) {} + + // Override + virtual void + handle_frame(std::shared_ptr f) override + { + ++_frameCount[static_cast(f->type())]; + ++_totalFrameCount; + } + + // for Test + int + getStreamFrameCount() + { + return _frameCount[static_cast(QUICFrameType::STREAM)]; + } + + int + getAckFrameCount() + { + return _frameCount[static_cast(QUICFrameType::ACK)]; + } + + int + getPingFrameCount() + { + return _frameCount[static_cast(QUICFrameType::PING)]; + } + + int + getTotalFrameCount() + { + return _totalFrameCount; + } + +private: + int _totalFrameCount = 0; + int _frameCount[256] = {0}; +}; + +class MockQUICStreamManager : public QUICStreamManager +{ +public: + MockQUICStreamManager() : QUICStreamManager() {} + + // Override + virtual void + handle_frame(std::shared_ptr f) override + { + ++_frameCount[static_cast(f->type())]; + ++_totalFrameCount; + } + + // for Test + int + getStreamFrameCount() + { + return _frameCount[static_cast(QUICFrameType::STREAM)]; + } + + int + getAckFrameCount() + { + return _frameCount[static_cast(QUICFrameType::ACK)]; + } + + int + getPingFrameCount() + { + return _frameCount[static_cast(QUICFrameType::PING)]; + } + + int + getTotalFrameCount() + { + return _totalFrameCount; + } + +private: + int _totalFrameCount = 0; + int _frameCount[256] = {0}; +}; + +class MockQUICCongestionController : public QUICCongestionController +{ +public: + MockQUICCongestionController() : QUICCongestionController() {} + + // Override + virtual void + handle_frame(std::shared_ptr f) override + { + ++_frameCount[static_cast(f->type())]; + ++_totalFrameCount; + } + + // for Test + int + getStreamFrameCount() + { + return _frameCount[static_cast(QUICFrameType::STREAM)]; + } + + int + getAckFrameCount() + { + return _frameCount[static_cast(QUICFrameType::ACK)]; + } + + int + getPingFrameCount() + { + return _frameCount[static_cast(QUICFrameType::PING)]; + } + + int + getTotalFrameCount() + { + return _totalFrameCount; + } + +private: + int _totalFrameCount = 0; + int _frameCount[256] = {0}; +}; + +class MockQUICFlowController : public QUICFlowController +{ +public: + MockQUICFlowController() {} + + // Override + virtual void + handle_frame(std::shared_ptr f) override + { + ++_frameCount[static_cast(f->type())]; + ++_totalFrameCount; + } + + // for Test + int + getStreamFrameCount() + { + return _frameCount[static_cast(QUICFrameType::STREAM)]; + } + + int + getAckFrameCount() + { + return _frameCount[static_cast(QUICFrameType::ACK)]; + } + + int + getPingFrameCount() + { + return _frameCount[static_cast(QUICFrameType::PING)]; + } + + int + getTotalFrameCount() + { + return _totalFrameCount; + } + +private: + int _totalFrameCount = 0; + int _frameCount[256] = {0}; +}; diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc new file mode 100644 index 00000000000..26c8199c085 --- /dev/null +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -0,0 +1,102 @@ +/** @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 "QUICAckFrameCreator.h" +#include + +int +QUICAckFrameCreator::update(QUICPacketNumber packet_number, bool acknowledgable) +{ + if (this->_packet_count == MAXIMUM_PACKET_COUNT) { + return -1; + } + if (packet_number > this->_largest_ack_number) { + this->_largest_ack_number = packet_number; + this->_largest_ack_received_time = Thread::get_hrtime(); + } + this->_packet_numbers[this->_packet_count++] = packet_number - this->_last_ack_number; + if (acknowledgable && !this->_can_send) { + this->_can_send = true; + } + + return 0; +} + +std::unique_ptr +QUICAckFrameCreator::create() +{ + std::unique_ptr ack_frame = {nullptr, QUICFrameDeleter::delete_null_frame}; + if (this->_can_send) { + ack_frame = this->_create_ack_frame(); + this->_last_ack_number = this->_largest_ack_number; + this->_can_send = false; + this->_packet_count = 0; + } + return ack_frame; +} + +std::unique_ptr +QUICAckFrameCreator::create_if_needed() +{ + // TODO What would be criteria? + return this->create(); +} + +void +QUICAckFrameCreator::_sort_packet_numbers() +{ + // TODO Find more smart way + std::sort(this->_packet_numbers, this->_packet_numbers + this->_packet_count); +} + +std::unique_ptr +QUICAckFrameCreator::_create_ack_frame() +{ + std::unique_ptr ack_frame = {nullptr, QUICFrameDeleter::delete_null_frame}; + this->_sort_packet_numbers(); + uint16_t start = this->_packet_numbers[0]; + uint8_t gap; + int i; + uint64_t length = 0; + for (i = 0, length = 0; i < this->_packet_count; ++i, ++length) { + if (this->_packet_numbers[i] == start + length) { + continue; + } + if (ack_frame) { + ack_frame->ack_block_section()->add_ack_block({gap, length}); + } else { + uint16_t delay = (Thread::get_hrtime() - this->_largest_ack_received_time) / 1000; // TODO Milliseconds? + ack_frame = QUICFrameFactory::create_ack_frame(this->_largest_ack_number, delay, length); + } + gap = this->_packet_numbers[i] - this->_packet_numbers[i - 1] - 1; + start = this->_packet_numbers[i]; + length = 0; + } + if (ack_frame) { + ack_frame->ack_block_section()->add_ack_block({gap, length}); + } else { + uint16_t delay = (Thread::get_hrtime() - this->_largest_ack_received_time) / 1000; // TODO Milliseconds? + ack_frame = QUICFrameFactory::create_ack_frame(this->_largest_ack_number, delay, length); + } + return ack_frame; +} diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h new file mode 100644 index 00000000000..8b940a4431c --- /dev/null +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -0,0 +1,69 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ts/ink_hrtime.h" +#include "QUICTypes.h" +#include "QUICFrame.h" + +class QUICAckFrameCreator +{ +public: + static const int MAXIMUM_PACKET_COUNT = 256; + QUICAckFrameCreator(){}; + + /* + * All packet numbers ATS received need to be passed to this method. + * Returns 0 if updated successfully. + */ + int update(QUICPacketNumber packet_number, bool acknowledgable); + + /* + * Returns QUICAckFrame only if ACK frame is able to be sent. + * Caller must send the ACK frame to the peer if it was returned. + * Usually you should use create_if_needed() instead, but you may want to + * call this when ATS receives PING frame. + */ + std::unique_ptr create(); + + /* + * Returns QUICAckFrame only if ACK frame need to be sent, + * because sending an ACK frame per incoming ACK-able packet isn't sufficient. + * Caller must send the ACK frame to the peer if it was returned. + */ + std::unique_ptr create_if_needed(); + +private: + bool _can_send = false; + + QUICPacketNumber _largest_ack_number = 0; + QUICPacketNumber _last_ack_number = 0; + ink_hrtime _largest_ack_received_time = 0; + + uint16_t _packet_numbers[MAXIMUM_PACKET_COUNT]; + uint16_t _packet_count = 0; + + void _sort_packet_numbers(); + std::unique_ptr _create_ack_frame(); +}; diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc new file mode 100644 index 00000000000..343a6bed715 --- /dev/null +++ b/iocore/net/quic/QUICApplication.cc @@ -0,0 +1,139 @@ +/** @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 "QUICApplication.h" + +#include "ts/MemView.h" +#include "QUICStream.h" + +const static char *tag = "quic_app"; + +// +// QUICStreamIO +// +QUICStreamIO::QUICStreamIO(QUICApplication *app, QUICStream *stream) +{ + this->_read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + this->_write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + + this->_read_buffer_reader = _read_buffer->alloc_reader(); + this->_write_buffer_reader = _write_buffer->alloc_reader(); + + this->_read_vio = stream->do_io_read(app, 0, _read_buffer); + this->_write_vio = stream->do_io_write(app, 0, _write_buffer_reader); +} + +int64_t +QUICStreamIO::read_avail() +{ + return this->_read_buffer_reader->read_avail(); +} + +int64_t +QUICStreamIO::read(uint8_t *buf, int64_t len) +{ + return this->_read_buffer_reader->read(const_cast(buf), len); +} + +int64_t +QUICStreamIO::write(uint8_t *buf, int64_t len) +{ + SCOPED_MUTEX_LOCK(lock, this->_write_vio->mutex, this_ethread()); + + int64_t bytes_add = this->_write_buffer->write(buf, len); + this->_write_vio->nbytes += bytes_add; + + return bytes_add; +} + +void +QUICStreamIO::read_reenable() +{ + return this->_read_vio->reenable(); +} + +void +QUICStreamIO::write_reenable() +{ + return this->_write_vio->reenable(); +} + +// +// QUICApplication +// +QUICApplication::QUICApplication(ProxyMutex *m, QUICNetVConnection *vc) : Continuation(m) +{ + this->_client_vc = vc; +} + +// @brief Bind stream and application +void +QUICApplication::set_stream(QUICStream *stream) +{ + QUICStreamIO *stream_io = new QUICStreamIO(this, stream); + this->_stream_map.insert(std::make_pair(stream->id(), stream_io)); +} + +bool +QUICApplication::is_stream_set(QUICStream *stream) +{ + auto result = this->_stream_map.find(stream->id()); + + return result != this->_stream_map.end(); +} + +void +QUICApplication::reenable(QUICStream *stream) +{ + QUICStreamIO *stream_io = this->_find_stream_io(stream->id()); + if (stream_io) { + stream_io->read_reenable(); + stream_io->write_reenable(); + } else { + Debug(tag, "Unknown Stream, id: %d", stream->id()); + } + + return; +} + +void +QUICApplication::unset_stream(QUICStream *stream) +{ + QUICStreamIO *stream_io = this->_find_stream_io(stream->id()); + if (stream_io) { + this->_stream_map.erase(stream->id()); + delete stream_io; + } +} + +QUICStreamIO * +QUICApplication::_find_stream_io(QUICStreamId id) +{ + auto result = this->_stream_map.find(id); + + if (result == this->_stream_map.end()) { + return nullptr; + } else { + return result->second; + } +} diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h new file mode 100644 index 00000000000..d876e6adbe7 --- /dev/null +++ b/iocore/net/quic/QUICApplication.h @@ -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. + */ + +#pragma once + +#include "I_VConnection.h" +#include "QUICTypes.h" + +class QUICNetVConnection; +class QUICStream; +class QUICApplication; + +/** + * @brief QUICStream I/O interface from QUIC Application + */ +class QUICStreamIO +{ +public: + QUICStreamIO(QUICApplication *app, QUICStream *stream); + + int64_t read_avail(); + int64_t read(uint8_t *buf, int64_t len); + int64_t write(uint8_t *buf, int64_t len); + void read_reenable(); + void write_reenable(); + +private: + MIOBuffer *_read_buffer = nullptr; + MIOBuffer *_write_buffer = nullptr; + + IOBufferReader *_read_buffer_reader = nullptr; + IOBufferReader *_write_buffer_reader = nullptr; + + VIO *_read_vio = nullptr; + VIO *_write_vio = nullptr; +}; + +/** + * @brief Abstruct QUIC Application Class + * @detail Every quic application must inherits this class + */ +class QUICApplication : public Continuation +{ +public: + QUICApplication(ProxyMutex *m, QUICNetVConnection *vc); + + void set_stream(QUICStream *stream); + bool is_stream_set(QUICStream *stream); + void reenable(QUICStream *stream); + void unset_stream(QUICStream *stream); + +protected: + QUICStreamIO *_find_stream_io(QUICStreamId id); + + QUICNetVConnection *_client_vc = nullptr; + +private: + std::map _stream_map; +}; diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc new file mode 100644 index 00000000000..79df5d855a1 --- /dev/null +++ b/iocore/net/quic/QUICCongestionController.cc @@ -0,0 +1,40 @@ +/** @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 + +const static char *tag = "quic_congestion_controller"; + +void +QUICCongestionController::handle_frame(std::shared_ptr frame) +{ + switch (frame->type()) { + case QUICFrameType::STREAM: + case QUICFrameType::ACK: + break; + default: + Debug(tag, "Unexpected frame type: %02x", frame->type()); + ink_assert(false); + break; + } +} diff --git a/iocore/net/quic/QUICCongestionController.h b/iocore/net/quic/QUICCongestionController.h new file mode 100644 index 00000000000..a579a4866af --- /dev/null +++ b/iocore/net/quic/QUICCongestionController.h @@ -0,0 +1,36 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +// TODO Implement congestion controll. +// Congestion controller will be required after the 2nd implementation draft. +class QUICCongestionController : public QUICFrameHandler +{ +public: + virtual void handle_frame(std::shared_ptr) override; + +private: +}; diff --git a/iocore/net/quic/QUICConnectionManager.cc b/iocore/net/quic/QUICConnectionManager.cc new file mode 100644 index 00000000000..fc1240b3144 --- /dev/null +++ b/iocore/net/quic/QUICConnectionManager.cc @@ -0,0 +1,42 @@ +/** @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 + +const static char *tag = "quic_connection_manager"; + +void +QUICConnectionManager::handle_frame(std::shared_ptr frame) +{ + switch (frame->type()) { + case QUICFrameType::CONNECTION_CLOSE: + case QUICFrameType::STREAM: + case QUICFrameType::GOAWAY: + case QUICFrameType::PING: + break; + default: + Debug(tag, "Unexpected frame type: %02x", frame->type()); + ink_assert(false); + break; + } +} diff --git a/iocore/net/quic/QUICConnectionManager.h b/iocore/net/quic/QUICConnectionManager.h new file mode 100644 index 00000000000..3a677343a93 --- /dev/null +++ b/iocore/net/quic/QUICConnectionManager.h @@ -0,0 +1,40 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include "QUICFrameTransmitter.h" + +class QUICConnectionManager : public QUICFrameHandler +{ +public: + QUICConnectionManager(QUICFrameTransmitter *tx) : _tx(tx){}; + virtual void handle_frame(std::shared_ptr frame) override; + +private: + QUICFrameTransmitter *_tx = nullptr; + + void _handle_ping_frame(const QUICPingFrame *); +}; diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc new file mode 100644 index 00000000000..2707dfaa0a7 --- /dev/null +++ b/iocore/net/quic/QUICCrypto.cc @@ -0,0 +1,405 @@ +/** @file + * + * QUIC Crypto (TLS to Secure QUIC) + * + * @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 "QUICCrypto.h" + +#include +#include +#include + +#include "ts/Diags.h" +#include "ts/MemView.h" +#include "QUICTypes.h" + +constexpr static char tag[] = "quic_crypto"; + +// constexpr static ts::StringView _exporter_label_0_rtt("EXPORTER-QUIC 0-RTT Secret", ts::StringView::literal); +constexpr static ts::StringView exporter_label_client_1_rtt("EXPORTER-QUIC client 1-RTT Secret", ts::StringView::literal); +constexpr static ts::StringView exporter_label_server_1_rtt("EXPORTER-QUIC server 1-RTT Secret", ts::StringView::literal); + +// [quic-tls draft-04] "TLS 1.3, " + Label +// constexpr static ts::StringView expand_label_client_1_rtt("TLS 1.3, QUIC client 1-RTT secret", ts::StringView::literal); +// constexpr static ts::StringView expand_label_server_1_rtt("TLS 1.3, QUIC server 1-RTT secret", ts::StringView::literal); +constexpr static ts::StringView expand_label_key("TLS 1.3, key", ts::StringView::literal); +constexpr static ts::StringView expand_label_iv("TLS 1.3, iv", ts::StringView::literal); + +// +// QUICPacketProtection +// + +QUICPacketProtection::~QUICPacketProtection() +{ + delete this->_phase_0_key; + delete this->_phase_1_key; +} + +void +QUICPacketProtection::set_key(KeyMaterial *km, QUICKeyPhase phase) +{ + this->_key_phase = phase; + if (phase == QUICKeyPhase::PHASE_0) { + this->_phase_0_key = km; + } else { + this->_phase_1_key = km; + } +} + +const KeyMaterial * +QUICPacketProtection::get_key(QUICKeyPhase phase) const +{ + if (phase == QUICKeyPhase::PHASE_0) { + return this->_phase_0_key; + } else { + return this->_phase_1_key; + } +} + +QUICKeyPhase +QUICPacketProtection::key_phase() const +{ + return this->_key_phase; +} + +// +// QUICCrypto +// +QUICCrypto::QUICCrypto(SSL_CTX *ssl_ctx, NetVConnectionContext_t c) : _netvc_context(c) +{ + this->_ssl = SSL_new(ssl_ctx); + if (this->_netvc_context == NET_VCONNECTION_IN) { + SSL_set_accept_state(this->_ssl); + } else if (this->_netvc_context == NET_VCONNECTION_OUT) { + SSL_set_connect_state(this->_ssl); + } else { + ink_assert(false); + } + + this->_client_pp = new QUICPacketProtection(); + this->_server_pp = new QUICPacketProtection(); +} + +QUICCrypto::~QUICCrypto() +{ + SSL_free(this->_ssl); + delete this->_client_pp; + delete this->_server_pp; +} + +bool +QUICCrypto::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) +{ + ink_assert(this->_ssl != nullptr); + + BIO *rbio = BIO_new(BIO_s_mem()); + BIO *wbio = BIO_new(BIO_s_mem()); + if (in != nullptr || in_len != 0) { + BIO_write(rbio, in, in_len); + } + SSL_set_bio(this->_ssl, rbio, wbio); + + if (!SSL_is_init_finished(this->_ssl)) { + ERR_clear_error(); + int ret = SSL_do_handshake(this->_ssl); + if (ret <= 0) { + int err = SSL_get_error(this->_ssl, ret); + + switch (err) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + break; + default: + char err_buf[32] = {0}; + ERR_error_string_n(err, err_buf, sizeof(err_buf)); + Debug(tag, "Handshake error: %s (%d)", err_buf, err); + return false; + } + } + } + + // OpenSSL doesn't have BIO_mem_contents + // const uint8_t *buf; + // if (!BIO_mem_contents(wbio, &buf, &out_len)) { + // return false; + // } + // if (out_len <= 0) { + // return false; + // } + + out_len = BIO_read(wbio, out, max_out_len); + if (out_len <= 0) { + return false; + } + + return true; +} + +bool +QUICCrypto::is_handshake_finished() const +{ + return SSL_is_init_finished(this->_ssl); +} + +int +QUICCrypto::setup_session() +{ + const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); + this->_digest = _get_handshake_digest(cipher); + this->_aead = _get_evp_aead(cipher); + + size_t secret_len = EVP_MD_size(this->_digest); + size_t key_len = _get_aead_key_len(this->_aead); + size_t iv_len = max(static_cast(8), _get_aead_nonce_len(this->_aead)); + + int r = 0; + + r = _export_client_keymaterial(secret_len, key_len, iv_len); + if (r != 1) { + return r; + } + + r = _export_server_keymaterial(secret_len, key_len, iv_len); + if (r != 1) { + return r; + } + + Debug(tag, "Negotiated ciper: %s, secret_len: %zu, key_len: %zu, iv_len: %zu", SSL_CIPHER_get_name(cipher), secret_len, key_len, + iv_len); + return 1; +} + +/** + * update client_pp_secret_ and keying material + */ +int +QUICCrypto::update_client_keymaterial() +{ + return 0; + // KeyMaterial *km_n = nullptr; + // KeyMaterial *km_n_1 = new KeyMaterial(km_n->secret_len, km_n->key_len, km_n->iv_len); + // uint8_t secret[256] = {0}; + // int r = 0; + + // r = _hkdf_expand_label(secret, km_n->secret_len, km_n->secret, km_n->secret_len, _expand_label_client_1_rtt, + // sizeof(_expand_label_client_1_rtt), this->_digest); + // if (r != 1) { + // return r; + // } + + // r = km_n_1->init(this->_aead, this->_digest, secret); + // if (r != 1) { + // return r; + // } + // this->_server_pp->set_key(km_n_1, new_key_phase); + + // return 1; +} + +/** + * update server_pp_secret_ and keying material + */ +int +QUICCrypto::update_server_keymaterial() +{ + return 0; + // KeyMaterial *km_n = nullptr; + // KeyMaterial *km_n_1 = new KeyMaterial(km_n->secret_len, km_n->key_len, km_n->iv_len); + // uint8_t secret[256] = {0}; + // int r = 0; + + // r = _hkdf_expand_label(secret, km_n->secret_len, km_n->secret, km_n->secret_len, _expand_label_server_1_rtt, + // sizeof(_expand_label_server_1_rtt), this->_digest); + // if (r != 1) { + // return r; + // } + + // r = km_n_1->init(this->_aead, this->_digest, secret); + // if (r != 1) { + // return r; + // } + // this->_server_pp->set_key(km_n_1, new_key_phase); + + // return 1; +} + +bool +QUICCrypto::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const +{ + const KeyMaterial *km = nullptr; + + switch (this->_netvc_context) { + case NET_VCONNECTION_IN: { + km = this->_server_pp->get_key(phase); + break; + } + case NET_VCONNECTION_OUT: { + km = this->_client_pp->get_key(phase); + break; + } + default: + ink_assert(false); + return false; + } + + size_t tag_len = _get_aead_tag_len(SSL_get_current_cipher(this->_ssl)); + return _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, km->key, km->key_len, km->iv, + km->iv_len, tag_len); +} + +bool +QUICCrypto::decrypt(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, QUICKeyPhase phase) const +{ + const KeyMaterial *km = nullptr; + + switch (this->_netvc_context) { + case NET_VCONNECTION_IN: { + km = this->_client_pp->get_key(phase); + break; + } + case NET_VCONNECTION_OUT: { + km = this->_server_pp->get_key(phase); + break; + } + default: + ink_assert(false); + return false; + } + + size_t tag_len = _get_aead_tag_len(SSL_get_current_cipher(this->_ssl)); + return _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, km->key, km->key_len, km->iv, + km->iv_len, tag_len); +} + +int +QUICCrypto::_export_secret(uint8_t *dst, size_t dst_len, const char *label, size_t label_len) const +{ + return SSL_export_keying_material(this->_ssl, dst, dst_len, label, label_len, reinterpret_cast(""), 0, 1); +} + +/** + * export client_pp_secret_0 and keying material + */ +int +QUICCrypto::_export_client_keymaterial(size_t secret_len, size_t key_len, size_t iv_len) +{ + KeyMaterial *km = new KeyMaterial(secret_len, key_len, iv_len); + int r = 0; + + r = _export_secret(km->secret, secret_len, exporter_label_client_1_rtt.ptr(), exporter_label_client_1_rtt.size()); + if (r != 1) { + Debug(tag, "Failed to export secret"); + return r; + } + + r = _hkdf_expand_label(km->key, key_len, km->secret, secret_len, expand_label_key.ptr(), expand_label_key.size(), this->_digest); + if (r != 1) { + Debug(tag, "Failed to expand label for key"); + return r; + } + + r = _hkdf_expand_label(km->iv, iv_len, km->secret, secret_len, expand_label_iv.ptr(), expand_label_iv.size(), this->_digest); + if (r != 1) { + Debug(tag, "Failed to expand label for iv"); + return r; + } + + this->_client_pp->set_key(km, QUICKeyPhase::PHASE_0); + + return 1; +} + +/** + * export server_pp_secret_0 and keying material + */ +int +QUICCrypto::_export_server_keymaterial(size_t secret_len, size_t key_len, size_t iv_len) +{ + KeyMaterial *km = new KeyMaterial(secret_len, key_len, iv_len); + int r = 0; + + r = _export_secret(km->secret, secret_len, exporter_label_server_1_rtt.ptr(), exporter_label_server_1_rtt.size()); + if (r != 1) { + return r; + } + + r = _hkdf_expand_label(km->key, key_len, km->secret, secret_len, expand_label_key.ptr(), expand_label_key.size(), this->_digest); + if (r != 1) { + Debug(tag, "Failed to expand label for key"); + return r; + } + + r = _hkdf_expand_label(km->iv, iv_len, km->secret, secret_len, expand_label_iv.ptr(), expand_label_iv.size(), this->_digest); + if (r != 1) { + Debug(tag, "Failed to expand label for iv"); + return r; + } + + this->_server_pp->set_key(km, QUICKeyPhase::PHASE_0); + + return 1; +} + +/** + * Example iv_len = 12 + * + * 0 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 (byte) + * +-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | iv | // IV + * +-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0|0|0|0| pkt num | // network byte order & left-padded with zeros + * +-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | nonce | // nonce = iv xor pkt_num + * +-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +void +QUICCrypto::_gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const +{ + nonce_len = iv_len; + memcpy(nonce, iv, iv_len); + + pkt_num = htobe64(pkt_num); + uint8_t *p = reinterpret_cast(&pkt_num); + + for (size_t i = 0; i < 8; ++i) { + nonce[iv_len - 8 + i] ^= p[i]; + } +} + +bool +QUICCrypto::_gen_info(uint8_t *info, size_t &info_len, const char *label, size_t label_len, size_t length) const +{ + info[0] = length / 256; + info[1] = length % 256; + info[2] = label_len; + info_len += 3; + + memcpy(info + info_len, label, label_len); + info_len += label_len; + + info[info_len] = 0x00; + ++info_len; + + return true; +} diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICCrypto.h new file mode 100644 index 00000000000..e018680ed7d --- /dev/null +++ b/iocore/net/quic/QUICCrypto.h @@ -0,0 +1,121 @@ +/** @file + * + * QUIC TLS + * + * @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. + */ + +#ifndef __QUIC_CRYPTO__ +#define __QUIC_CRYPTO__ + +#include + +#ifdef OPENSSL_IS_BORINGSSL +#include +#include +#else +#include +#endif + +#include "I_EventSystem.h" +#include "I_NetVConnection.h" +#include "QUICTypes.h" + +struct KeyMaterial { + KeyMaterial(size_t secret_len, size_t key_len, size_t iv_len) : secret_len(secret_len), key_len(key_len), iv_len(iv_len) {} + + uint8_t secret[EVP_MAX_MD_SIZE] = {0}; + uint8_t key[EVP_MAX_KEY_LENGTH] = {0}; + uint8_t iv[EVP_MAX_IV_LENGTH] = {0}; + size_t secret_len = 0; + size_t key_len = 0; + size_t iv_len = 0; +}; + +class QUICPacketProtection +{ +public: + QUICPacketProtection(){}; + ~QUICPacketProtection(); + void set_key(KeyMaterial *km, QUICKeyPhase phase); + const KeyMaterial *get_key(QUICKeyPhase phase) const; + QUICKeyPhase key_phase() const; + +private: + KeyMaterial *_phase_0_key = nullptr; + KeyMaterial *_phase_1_key = nullptr; + QUICKeyPhase _key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; +}; + +class QUICCrypto +{ +public: + QUICCrypto(SSL_CTX *, NetVConnectionContext_t); + ~QUICCrypto(); + + bool handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len); + bool is_handshake_finished() const; + int setup_session(); + bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, + const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const; + bool decrypt(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, QUICKeyPhase phase) const; + int update_client_keymaterial(); + int update_server_keymaterial(); + +private: + int _export_secret(uint8_t *dst, size_t dst_len, const char *label, size_t label_len) const; + int _export_client_keymaterial(size_t secret_len, size_t key_len, size_t iv_len); + int _export_server_keymaterial(size_t secret_len, size_t key_len, size_t iv_len); + void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; + bool _gen_info(uint8_t *info, size_t &info_len, const char *label, size_t label_len, size_t length) const; + int _hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, + size_t label_len, const EVP_MD *digest) const; +#ifdef OPENSSL_IS_BORINGSSL + const EVP_AEAD *_get_evp_aead(const SSL_CIPHER *cipher) const; + size_t _get_aead_key_len(const EVP_AEAD *aead) const; + size_t _get_aead_nonce_len(const EVP_AEAD *aead) const; +#else + const EVP_CIPHER *_get_evp_aead(const SSL_CIPHER *cipher) const; + size_t _get_aead_key_len(const EVP_CIPHER *aead) const; + size_t _get_aead_nonce_len(const EVP_CIPHER *aead) const; +#endif // OPENSSL_IS_BORINGSSL + const EVP_MD *_get_handshake_digest(const SSL_CIPHER *cipher) const; + size_t _get_aead_tag_len(const SSL_CIPHER *cipher) const; + + bool _encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, + size_t iv_len, size_t tag_len) const; + bool _decrypt(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, size_t key_len, const uint8_t *iv, size_t iv_len, + size_t tag_len) const; + + SSL *_ssl = nullptr; +#ifdef OPENSSL_IS_BORINGSSL + const EVP_AEAD *_aead = nullptr; +#else + const EVP_CIPHER *_aead = nullptr; +#endif // OPENSSL_IS_BORINGSSL + const EVP_MD *_digest = nullptr; + QUICPacketProtection *_client_pp = nullptr; + QUICPacketProtection *_server_pp = nullptr; + NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; +}; + +#endif // __QUIC_CRYPTO__ diff --git a/iocore/net/quic/QUICCrypto_boringssl.cc b/iocore/net/quic/QUICCrypto_boringssl.cc new file mode 100644 index 00000000000..bd4a0c02d04 --- /dev/null +++ b/iocore/net/quic/QUICCrypto_boringssl.cc @@ -0,0 +1,144 @@ +/** @file + * + * QUIC Crypto (TLS to Secure QUIC) using BoringSSL + * + * @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 "QUICCrypto.h" + +#include +#include +#include +#include +#include +#include + +const static char tag[] = "quic_crypto"; + +const EVP_AEAD * +QUICCrypto::_get_evp_aead(const SSL_CIPHER *cipher) const +{ + ink_assert(SSL_CIPHER_is_AEAD(cipher)); + + if (SSL_CIPHER_is_AES128GCM(cipher)) { + return EVP_aead_aes_128_gcm(); + } else if ((cipher->algorithm_enc & 0x00000010L) != 0) { + // SSL_AES256GCM is 0x00000010L ( defined in `ssl/internal.h` ). + // There're no `SSL_CIPHER_is_AES256GCM(const SSL_CIPHER *cipher)`. + return EVP_aead_aes_256_gcm(); + } else if (SSL_CIPHER_is_CHACHA20POLY1305(cipher)) { + return EVP_aead_chacha20_poly1305(); + } else { + return nullptr; + } +} + +// SSL_HANDSHAKE_MAC_SHA256, SSL_HANDSHAKE_MAC_SHA384 are defind in `ssl/internal.h` of BoringSSL +const EVP_MD * +QUICCrypto::_get_handshake_digest(const SSL_CIPHER *cipher) const +{ + switch (cipher->algorithm_prf) { + case 0x2: + // SSL_HANDSHAKE_MAC_SHA256: + return EVP_sha256(); + case 0x4: + // SSL_HANDSHAKE_MAC_SHA384: + return EVP_sha384(); + default: + return nullptr; + } +} + +size_t +QUICCrypto::_get_aead_tag_len(const SSL_CIPHER * /* cipher */) const +{ + return EVP_AEAD_DEFAULT_TAG_LENGTH; +} + +size_t +QUICCrypto::_get_aead_key_len(const EVP_AEAD *aead) const +{ + return EVP_AEAD_key_length(aead); +} + +size_t +QUICCrypto::_get_aead_nonce_len(const EVP_AEAD *aead) const +{ + return EVP_AEAD_nonce_length(aead); +} + +int +QUICCrypto::_hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, + size_t label_len, const EVP_MD *digest) const +{ + uint8_t info[256] = {0}; + size_t info_len = 0; + _gen_info(info, info_len, label, label_len, dst_len); + return HKDF(dst, dst_len, digest, secret, secret_len, nullptr, 0, info, info_len); +} + +bool +QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, + size_t iv_len, size_t tag_len) const +{ + uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; + size_t nonce_len = 0; + _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); + + EVP_AEAD_CTX *aead_ctx = EVP_AEAD_CTX_new(this->_aead, key, key_len, tag_len); + if (!aead_ctx) { + Debug(tag, "Failed to create EVP_AEAD_CTX"); + return false; + } + + if (!EVP_AEAD_CTX_seal(aead_ctx, cipher, &cipher_len, max_cipher_len, nonce, nonce_len, plain, plain_len, ad, ad_len)) { + Debug(tag, "Failed to encrypt"); + return false; + } + + EVP_AEAD_CTX_free(aead_ctx); + + return true; +} + +bool +QUICCrypto::_decrypt(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, size_t key_len, const uint8_t *iv, + size_t iv_len, size_t tag_len) const +{ + uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; + size_t nonce_len = 0; + _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); + + EVP_AEAD_CTX *aead_ctx = EVP_AEAD_CTX_new(this->_aead, key, key_len, tag_len); + if (!aead_ctx) { + Debug(tag, "Failed to create EVP_AEAD_CTX"); + return false; + } + + if (!EVP_AEAD_CTX_open(aead_ctx, plain, &plain_len, max_plain_len, nonce, nonce_len, cipher, cipher_len, ad, ad_len)) { + Debug(tag, "Failed to decrypt"); + return false; + } + + EVP_AEAD_CTX_free(aead_ctx); + + return true; +} diff --git a/iocore/net/quic/QUICCrypto_openssl.cc b/iocore/net/quic/QUICCrypto_openssl.cc new file mode 100644 index 00000000000..d0a6f2d3fc8 --- /dev/null +++ b/iocore/net/quic/QUICCrypto_openssl.cc @@ -0,0 +1,236 @@ +/** @file + * + * QUIC Crypto (TLS to Secure QUIC) using OpenSSL + * + * @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 "QUICCrypto.h" + +#include +#include +#include +#include +#include + +const static char tag[] = "quic_crypto"; + +const EVP_CIPHER * +QUICCrypto::_get_evp_aead(const SSL_CIPHER *cipher) const +{ + switch (SSL_CIPHER_get_id(cipher)) { + case TLS1_3_CK_AES_128_GCM_SHA256: + return EVP_aes_128_gcm(); + case TLS1_3_CK_AES_256_GCM_SHA384: + return EVP_aes_256_gcm(); + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + return EVP_chacha20_poly1305(); + case TLS1_3_CK_AES_128_CCM_SHA256: + case TLS1_3_CK_AES_128_CCM_8_SHA256: + return EVP_aes_128_ccm(); + default: + ink_assert(false); + return nullptr; + } +} + +const EVP_MD * +QUICCrypto::_get_handshake_digest(const SSL_CIPHER *cipher) const +{ + switch (SSL_CIPHER_get_id(cipher)) { + case TLS1_3_CK_AES_128_GCM_SHA256: + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + case TLS1_3_CK_AES_128_CCM_SHA256: + case TLS1_3_CK_AES_128_CCM_8_SHA256: + return EVP_sha256(); + case TLS1_3_CK_AES_256_GCM_SHA384: + return EVP_sha384(); + default: + ink_assert(false); + return nullptr; + } +} + +size_t +QUICCrypto::_get_aead_tag_len(const SSL_CIPHER *cipher) const +{ + switch (SSL_CIPHER_get_id(cipher)) { + case TLS1_3_CK_AES_128_GCM_SHA256: + case TLS1_3_CK_AES_256_GCM_SHA384: + return EVP_GCM_TLS_TAG_LEN; + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + return EVP_CHACHAPOLY_TLS_TAG_LEN; + case TLS1_3_CK_AES_128_CCM_SHA256: + return EVP_CCM_TLS_TAG_LEN; + case TLS1_3_CK_AES_128_CCM_8_SHA256: + return EVP_CCM8_TLS_TAG_LEN; + default: + ink_assert(false); + return -1; + } +} + +size_t +QUICCrypto::_get_aead_key_len(const EVP_CIPHER *aead) const +{ + return EVP_CIPHER_key_length(aead); +} + +size_t +QUICCrypto::_get_aead_nonce_len(const EVP_CIPHER *aead) const +{ + return EVP_CIPHER_iv_length(aead); +} + +int +QUICCrypto::_hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, + size_t label_len, const EVP_MD *digest) const +{ + uint8_t info[256] = {0}; + size_t info_len = 0; + _gen_info(info, info_len, label, label_len, dst_len); + + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr); + if (!EVP_PKEY_derive_init(pctx)) { + return -1; + } + if (!EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY)) { + return -1; + } + if (!EVP_PKEY_CTX_set_hkdf_md(pctx, digest)) { + return -1; + } + if (!EVP_PKEY_CTX_set1_hkdf_salt(pctx, "", 0)) { + return -1; + } + if (!EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secret_len)) { + return -1; + } + if (!EVP_PKEY_CTX_add1_hkdf_info(pctx, info, info_len)) { + return -1; + } + if (!EVP_PKEY_derive(pctx, dst, &dst_len)) { + return -1; + } + + return 1; +} + +bool +QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, + size_t iv_len, size_t tag_len) const +{ + uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; + size_t nonce_len = 0; + _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); + + EVP_CIPHER_CTX *aead_ctx; + int len; + + if (!(aead_ctx = EVP_CIPHER_CTX_new())) { + return false; + } + if (!EVP_EncryptInit_ex(aead_ctx, this->_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; + } + if (!EVP_EncryptUpdate(aead_ctx, cipher, &len, plain, plain_len)) { + return false; + } + cipher_len = len; + + if (!EVP_EncryptFinal_ex(aead_ctx, 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 +QUICCrypto::_decrypt(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, size_t key_len, const uint8_t *iv, + size_t iv_len, size_t tag_len) const +{ + uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; + size_t nonce_len = 0; + _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); + + EVP_CIPHER_CTX *aead_ctx; + int len; + + if (!(aead_ctx = EVP_CIPHER_CTX_new())) { + return false; + } + if (!EVP_DecryptInit_ex(aead_ctx, this->_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(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"); + return false; + } +} diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc new file mode 100644 index 00000000000..74f7a2a742f --- /dev/null +++ b/iocore/net/quic/QUICDebugNames.cc @@ -0,0 +1,118 @@ +/** @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 "QUICDebugNames.h" +#include "I_VConnection.h" + +const char * +QUICDebugNames::packet_type(QUICPacketType type) +{ + switch (type) { + case QUICPacketType::VERSION_NEGOTIATION: + return "VERSION_NEGOTIATION"; + case QUICPacketType::CLIENT_INITIAL: + return "CLIENT_INITIAL"; + case QUICPacketType::SERVER_STATELESS_RETRY: + return "SERVER_STATELESS_RETRY"; + case QUICPacketType::SERVER_CLEARTEXT: + return "SERVER_CLEARTEXT"; + case QUICPacketType::CLIENT_CLEARTEXT: + return "CLIENT_CLEARTEXT"; + case QUICPacketType::ZERO_RTT_PROTECTED: + return "ZERO_RTT_PROTECTED"; + case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: + return "ONE_RTT_PROTECTED_KEY_PHASE_0"; + case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: + return "ONE_RTT_PROTECTED_KEY_PHASE_1"; + case QUICPacketType::PUBLIC_RESET: + return "PUBLIC_RESET"; + case QUICPacketType::UNINITIALIZED: + default: + return "UNKNOWN"; + } +} + +const char * +QUICDebugNames::frame_type(QUICFrameType type) +{ + switch (type) { + case QUICFrameType::PADDING: + return "PADDING"; + case QUICFrameType::RST_STREAM: + return "RST_STREAM"; + case QUICFrameType::CONNECTION_CLOSE: + return "CONNECTION_CLOSE"; + case QUICFrameType::GOAWAY: + return "GOAWAY"; + case QUICFrameType::MAX_DATA: + return "MAX_DATA"; + case QUICFrameType::MAX_STREAM_DATA: + return "MAX_STREAM_DATA"; + case QUICFrameType::MAX_STREAM_ID: + return "MAX_STREAM_ID"; + case QUICFrameType::PING: + return "PING"; + case QUICFrameType::BLOCKED: + return "BLOCKED"; + case QUICFrameType::STREAM_BLOCKED: + return "STREAM_BLOCKED"; + case QUICFrameType::STREAM_ID_NEEDED: + return "STREAM_ID_NEEDED"; + case QUICFrameType::NEW_CONNECTION_ID: + return "NEW_CONNECTION_ID"; + case QUICFrameType::ACK: + return "ACK"; + case QUICFrameType::STREAM: + return "STREAM"; + case QUICFrameType::UNKNOWN: + default: + return "UNKNOWN"; + } +} + +const char * +QUICDebugNames::vc_event(int event) +{ + switch (event) { + case VC_EVENT_READ_READY: + return "VC_EVENT_READ_READY"; + case VC_EVENT_READ_COMPLETE: + return "VC_EVENT_READ_COMPLETE"; + case VC_EVENT_WRITE_READY: + return "VC_EVENT_WRITE_READY"; + case VC_EVENT_WRITE_COMPLETE: + return "VC_EVENT_WRITE_COMPLETE"; + case VC_EVENT_EOS: + return "VC_EVENT_EOS"; + case VC_EVENT_ERROR: + return "VC_EVENT_ERROR"; + case VC_EVENT_INACTIVITY_TIMEOUT: + return "VC_EVENT_INACTIVITY_TIMEOUT"; + case VC_EVENT_ACTIVE_TIMEOUT: + return "VC_EVENT_ACTIVE_TIMEOUT"; + case VC_EVENT_OOB_COMPLETE: + return "VC_EVENT_OOB_COMPLETE"; + default: + return "UNKNOWN"; + } +} diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h new file mode 100644 index 00000000000..a6fe7154ad0 --- /dev/null +++ b/iocore/net/quic/QUICDebugNames.h @@ -0,0 +1,35 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICTypes.h" + +class QUICDebugNames +{ +public: + static const char *packet_type(QUICPacketType type); + static const char *frame_type(QUICFrameType type); + // TODO: move to somewhere + static const char *vc_event(int event); +}; diff --git a/iocore/net/quic/QUICEchoApp.cc b/iocore/net/quic/QUICEchoApp.cc new file mode 100644 index 00000000000..45bb4f9c8aa --- /dev/null +++ b/iocore/net/quic/QUICEchoApp.cc @@ -0,0 +1,85 @@ +/** @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 "QUICEchoApp.h" + +#include "P_Net.h" +#include "P_QUICNetVConnection.h" +#include "QUICDebugNames.h" + +const static char *tag = "quic_echo_app"; + +QUICEchoApp::QUICEchoApp(ProxyMutex *m, QUICNetVConnection *vc) : QUICApplication(m, vc) +{ + SET_HANDLER(&QUICEchoApp::main_event_handler); +} + +int +QUICEchoApp::main_event_handler(int event, Event *data) +{ + Debug(tag, "%s", QUICDebugNames::vc_event(event)); + + QUICStream *stream = reinterpret_cast(data->cookie); + QUICStreamIO *stream_io = this->_find_stream_io(stream->id()); + if (stream_io == nullptr) { + Debug(tag, "Unknown Stream, id: %d", stream->id()); + return -1; + } + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + uint8_t msg[1024] = {0}; + int64_t msg_len = 1024; + + int64_t read_len = stream_io->read(msg, msg_len); + + if (read_len) { + Debug(tag, "msg: %s, len: %" PRId64, msg, read_len); + + stream_io->write(msg, read_len); + stream_io->write_reenable(); + stream_io->read_reenable(); + } else { + Debug(tag, "No MSG"); + } + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + // do nothing + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + ink_assert(false); + break; + } + default: + break; + } + + return EVENT_CONT; +} diff --git a/iocore/net/quic/QUICEchoApp.h b/iocore/net/quic/QUICEchoApp.h new file mode 100644 index 00000000000..a8310b70cbf --- /dev/null +++ b/iocore/net/quic/QUICEchoApp.h @@ -0,0 +1,42 @@ +/** @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. + */ + +#ifndef __QUIC_ECHOAPP__ +#define __QUIC_ECHOAPP__ + +#include "I_VConnection.h" +#include "QUICApplication.h" + +/** + * @brief Echo over QUIC + * @detail An example application over QUIC. + * Receive DATA of STREAM Frame and echo it. + */ +class QUICEchoApp : public QUICApplication +{ +public: + QUICEchoApp(ProxyMutex *m, QUICNetVConnection *vc); + + int main_event_handler(int event, Event *data); +}; +#endif // __QUIC_HANDSHAKE__ diff --git a/iocore/net/quic/QUICEvents.h b/iocore/net/quic/QUICEvents.h new file mode 100644 index 00000000000..1a8a9b2d9c2 --- /dev/null +++ b/iocore/net/quic/QUICEvents.h @@ -0,0 +1,31 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "I_Event.h" + +enum { + QUIC_EVENT_PACKET_READ_READY = QUIC_EVENT_EVENTS_START, + QUIC_EVENT_PACKET_WRITE_READY, +}; diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc new file mode 100644 index 00000000000..b746aa2a726 --- /dev/null +++ b/iocore/net/quic/QUICFlowController.cc @@ -0,0 +1,42 @@ +/** @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 + +const static char *tag = "quic_flow_controller"; + +void +QUICFlowController::handle_frame(std::shared_ptr frame) +{ + switch (frame->type()) { + case QUICFrameType::MAX_DATA: + case QUICFrameType::MAX_STREAM_DATA: + case QUICFrameType::BLOCKED: + case QUICFrameType::STREAM: + break; + default: + Debug(tag, "Unexpected frame type: %02x", frame->type()); + ink_assert(false); + break; + } +} diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h new file mode 100644 index 00000000000..6009d2cf51c --- /dev/null +++ b/iocore/net/quic/QUICFlowController.h @@ -0,0 +1,36 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +// TODO Implement flow controll +// Flow controll will be required for the 2nd implementation draft +class QUICFlowController : QUICFrameHandler +{ +public: + virtual void handle_frame(std::shared_ptr) override; + +private: +}; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc new file mode 100644 index 00000000000..8ca581d97b1 --- /dev/null +++ b/iocore/net/quic/QUICFrame.cc @@ -0,0 +1,1315 @@ +/** @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 "QUICFrame.h" + +ClassAllocator quicStreamFrameAllocator("quicStreamFrameAllocator"); +ClassAllocator quicAckFrameAllocator("quicAckFrameAllocator"); +ClassAllocator quicPaddingFrameAllocator("quicPaddingFrameAllocator"); +ClassAllocator quicRstStreamFrameAllocator("quicRstStreamFrameAllocator"); +ClassAllocator quicConnectionCloseFrameAllocator("quicConnectionCloseFrameAllocator"); +ClassAllocator quicGoawayFrameAllocator("quicGoawayAllocator"); +ClassAllocator quicMaxDataFrameAllocator("quicMaxDataFrameAllocator"); +ClassAllocator quicMaxStreamDataFrameAllocator("quicMaxStreamDataFrameAllocator"); +ClassAllocator quicMaxStreamIdFrameAllocator("quicMaxStreamDataIdAllocator"); +ClassAllocator quicPingFrameAllocator("quicPingFrameAllocator"); +ClassAllocator quicBlockedFrameAllocator("quicBlockedFrameAllocator"); +ClassAllocator quicStreamBlockedFrameAllocator("quicStreamBlockedFrameAllocator"); +ClassAllocator quicStreamIdNeededFrameAllocator("quicStreamIdNeededFrameAllocator"); +ClassAllocator quicNewConnectionIdFrameAllocator("quicNewConnectionIdFrameAllocator"); +ClassAllocator quicRetransmissionFrameAllocator("quicRetransmissionFrameAllocator"); + +QUICFrameType +QUICFrame::type() const +{ + return QUICFrame::type(this->_buf); +} + +QUICFrameType +QUICFrame::type(const uint8_t *buf) +{ + if (buf[0] >= static_cast(QUICFrameType::STREAM)) { + return QUICFrameType::STREAM; + } else if (buf[0] >= static_cast(QUICFrameType::ACK)) { + return QUICFrameType::ACK; + } else if (static_cast(QUICFrameType::NEW_CONNECTION_ID) < buf[0] && buf[0] < static_cast(QUICFrameType::ACK)) { + return QUICFrameType::UNKNOWN; + } else { + return static_cast(buf[0]); + } +} + +void +QUICFrame::reset(const uint8_t *buf, size_t len) +{ + this->_buf = buf; + this->_len = len; +} + +// +// STREAM Frame +// + +QUICStreamFrame::QUICStreamFrame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset) +{ + this->_data = data; + this->_data_len = data_len; + this->_stream_id = stream_id; + this->_offset = offset; +} + +QUICFrameType +QUICStreamFrame::type() const +{ + return QUICFrameType::STREAM; +} + +size_t +QUICStreamFrame::size() const +{ + if (this->_buf) { + return this->_get_data_offset() + this->data_length(); + } else { + return 1 + 4 + 8 + 2 + this->data_length(); + } +} + +void +QUICStreamFrame::store(uint8_t *buf, size_t *len) const +{ + this->store(buf, len, true); +} + +void +QUICStreamFrame::store(uint8_t *buf, size_t *len, bool include_length_field) const +{ + size_t n; + // Build Frame Type: "11FSSOOD" + buf[0] = static_cast(QUICFrameType::STREAM); + *len = 1; + + // "SS" of "11FSSOOD" + // use 32 bit length for now + buf[0] += (0x03 << 3); + QUICTypeUtil::write_QUICStreamId(this->stream_id(), 4, buf + *len, &n); + *len += n; + + // "OO" of "11FSSOOD" + // use 64 bit length for now + buf[0] += (0x03 << 1); + QUICTypeUtil::write_QUICOffset(this->offset(), 8, buf + *len, &n); + *len += n; + + // "D" of "11FSSOOD" + if (include_length_field) { + buf[0] += 0x01; + QUICTypeUtil::write_uint_as_nbytes(this->data_length(), 2, buf + *len, &n); + *len += n; + } + + memcpy(buf + *len, this->data(), this->data_length()); + *len += this->data_length(); +} + +QUICStreamId +QUICStreamFrame::stream_id() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICStreamId(this->_buf + this->_get_stream_id_offset(), this->_get_stream_id_len()); + } else { + return this->_stream_id; + } +} + +QUICOffset +QUICStreamFrame::offset() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICOffset(this->_buf + this->_get_offset_offset(), this->_get_offset_len()); + } else { + return this->_offset; + } +} + +const uint8_t * +QUICStreamFrame::data() const +{ + if (this->_buf) { + return this->_buf + this->_get_data_offset(); + } else { + return this->_data; + } +} + +size_t +QUICStreamFrame::data_length() const +{ + if (this->_buf) { + if (this->has_data_length_field()) { + return QUICTypeUtil::read_nbytes_as_uint(this->_buf + this->_get_offset_offset() + this->_get_offset_len(), 2); + } else { + return this->_len - this->_get_data_offset(); + } + } else { + return this->_data_len; + } +} + +/** + * "D" of "11FSSOOD" + */ +bool +QUICStreamFrame::has_data_length_field() const +{ + return (this->_buf[0] & 0x01) != 0; +} + +/** + * "F" of "11FSSOOD" + */ +bool +QUICStreamFrame::has_fin_flag() const +{ + if (this->_buf) { + return (this->_buf[0] & 0x20) != 0; + } else { + return this->_fin; + } +} + +size_t +QUICStreamFrame::_get_stream_id_offset() const +{ + return 1; +} + +size_t +QUICStreamFrame::_get_offset_offset() const +{ + return this->_get_stream_id_offset() + this->_get_stream_id_len(); +} + +size_t +QUICStreamFrame::_get_data_offset() const +{ + if (this->_buf) { + if (this->has_data_length_field()) { + return this->_get_offset_offset() + this->_get_offset_len() + 2; + } else { + return this->_get_offset_offset() + this->_get_offset_len(); + } + } else { + return 0; + } +} + +/** + * "SS" of "11FSSOOD" + * The value 00, 01, 02, and 03 indicate lengths of 8, 16, 24, and 32 bits long respectively. + */ +size_t +QUICStreamFrame::_get_stream_id_len() const +{ + return ((this->_buf[0] & 0x18) >> 3) + 1; +} + +/** + * "OO" of "11FSSOOD" + * The values 00, 01, 02, and 03 indicate lengths of 0, 16, 32, and 64 bits long respectively. + */ +size_t +QUICStreamFrame::_get_offset_len() const +{ + int OO_bits = (this->_buf[0] & 0x06) >> 1; + if (OO_bits == 0) { + return 0; + } else { + return 0x01 << OO_bits; + } +} + +// +// ACK frame +// + +QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) +{ + this->reset(buf, len); +} + +QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint16_t ack_delay, uint64_t first_ack_block_length) +{ + this->_largest_acknowledged = largest_acknowledged; + this->_ack_delay = ack_delay; + this->_ack_block_section = new AckBlockSection(first_ack_block_length); +} + +QUICAckFrame::~QUICAckFrame() +{ + if (this->_ack_block_section) { + delete this->_ack_block_section; + this->_ack_block_section = nullptr; + } +} + +void +QUICAckFrame::reset(const uint8_t *buf, size_t len) +{ + QUICFrame::reset(buf, len); + this->_ack_block_section = + new AckBlockSection(buf + this->_get_ack_block_section_offset(), this->num_blocks(), this->_get_ack_block_length()); +} + +QUICFrameType +QUICAckFrame::type() const +{ + return QUICFrameType::ACK; +} + +size_t +QUICAckFrame::size() const +{ + if (this->_buf) { + return this->_get_timestamp_section_offset() + this->timestamp_section()->size(); + } else { + return 0; + } +} + +void +QUICAckFrame::store(uint8_t *buf, size_t *len) const +{ + size_t n; + uint8_t *p = buf; + + // Build Frame Type: "101NLLMM" + buf[0] = static_cast(QUICFrameType::ACK); + p += 1; + + // "N" of "101NLLMM" + if (this->_ack_block_section->count() > 0) { + buf[0] += 0x10; + *p = this->_ack_block_section->count(); + p += 1; + } + + *p = this->_timestamp_section->count(); + p += 1; + + // "LL" of "101NLLMM" + if (this->_largest_acknowledged <= 0xff) { + QUICTypeUtil::write_uint_as_nbytes(this->_largest_acknowledged, 1, p, &n); + } else if (this->_largest_acknowledged <= 0xffff) { + buf[0] += 0x01 << 2; + QUICTypeUtil::write_uint_as_nbytes(this->_largest_acknowledged, 2, p, &n); + } else if (this->_largest_acknowledged <= 0xffffffff) { + buf[0] += 0x02 << 2; + QUICTypeUtil::write_uint_as_nbytes(this->_largest_acknowledged, 4, p, &n); + } else { + buf[0] += 0x03 << 2; + QUICTypeUtil::write_uint_as_nbytes(this->_largest_acknowledged, 6, p, &n); + } + p += n; + + QUICTypeUtil::write_uint_as_nbytes(this->_ack_delay, 2, p, &n); + p += n; + + // "MM" of "101NLLMM" + // use 32 bit length for now + // TODO The length should be returned by ackBlockSection + buf[0] += 0x02; + this->_ack_block_section->store(p, &n); + p += n; + + this->_timestamp_section->store(p, &n); + p += n; + + *len = p - buf; +} + +uint8_t +QUICAckFrame::num_blocks() const +{ + if (this->has_ack_blocks()) { + if (this->_buf) { + return this->_buf[1]; + } else { + return this->_ack_block_section->count(); + } + } else { + return 0; + } +} + +uint8_t +QUICAckFrame::num_timestamps() const +{ + return this->_buf[this->_get_num_timestamp_offset()]; +} + +QUICPacketNumber +QUICAckFrame::largest_acknowledged() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICPacketNumber(this->_buf + this->_get_largest_acknowledged_offset(), + this->_get_largest_acknowledged_length()); + } else { + return this->_largest_acknowledged; + } +} + +uint16_t +QUICAckFrame::ack_delay() const +{ + if (this->_buf) { + return QUICTypeUtil::read_nbytes_as_uint(this->_buf + this->_get_ack_delay_offset(), 2); + } else { + return this->_ack_delay; + } +} + +/** + * N of 101NLLMM + */ +bool +QUICAckFrame::has_ack_blocks() const +{ + if (this->_buf) { + return (this->_buf[0] & 0x10) != 0; + } else { + return this->_ack_block_section->count() != 0; + } +} + +QUICAckFrame::AckBlockSection * +QUICAckFrame::ack_block_section() +{ + return this->_ack_block_section; +} + +const QUICAckFrame::AckBlockSection * +QUICAckFrame::ack_block_section() const +{ + return this->_ack_block_section; +} + +const QUICAckFrame::TimestampSection * +QUICAckFrame::timestamp_section() const +{ + return this->_timestamp_section; +} + +size_t +QUICAckFrame::_get_num_timestamp_offset() const +{ + if (this->has_ack_blocks()) { + return 2; + } else { + return 1; + } +} + +/** + * LL of 101NLLMM + */ +size_t +QUICAckFrame::_get_largest_acknowledged_length() const +{ + /* + * 0 -> 1 byte + * 1 -> 2 byte + * 2 -> 4 byte + * 3 -> 6 byte + */ + int n = (this->_buf[0] & 0x0c) >> 2; + if (n == 0) { + return 1; + } else { + return n * 2; + } +} + +size_t +QUICAckFrame::_get_largest_acknowledged_offset() const +{ + return this->_get_num_timestamp_offset() + 1; +} + +/** + * MM of 101NLLMM + */ +size_t +QUICAckFrame::_get_ack_block_length() const +{ + /* + * 0 -> 1 byte + * 1 -> 2 byte + * 2 -> 4 byte + * 3 -> 6 byte + */ + int n = this->_buf[0] & 0x03; + if (n == 0) { + return 1; + } else { + return n * 2; + } +} + +size_t +QUICAckFrame::_get_ack_delay_offset() const +{ + return this->_get_largest_acknowledged_offset() + this->_get_largest_acknowledged_length(); +} + +size_t +QUICAckFrame::_get_ack_block_section_offset() const +{ + return this->_get_ack_delay_offset() + 2; +} + +size_t +QUICAckFrame::_get_timestamp_section_offset() const +{ + return this->_get_ack_block_section_offset() + this->ack_block_section()->size(); +} + +QUICAckFrame::AckBlockSection::AckBlockSection(const uint8_t *buf, uint8_t num_blocks, uint8_t ack_block_length) +{ + this->_buf = buf; + this->_num_blocks = num_blocks; + this->_ack_block_length = ack_block_length; +} + +QUICAckFrame::AckBlockSection::AckBlockSection(uint64_t first_ack_block_length) +{ + this->_first_ack_block_length = first_ack_block_length; +} + +QUICAckFrame::AckBlock::AckBlock(const uint8_t *buf, uint8_t ack_block_length) +{ + uint8_t gap = buf[0]; + uint64_t length = QUICTypeUtil::read_nbytes_as_uint(buf + 1, ack_block_length); + this->_data = (static_cast(gap) << 56) + length; +} + +QUICAckFrame::AckBlock::AckBlock(uint8_t gap, uint64_t length) +{ + this->_data = (static_cast(gap) << 56) + length; +} + +uint8_t +QUICAckFrame::AckBlock::gap() const +{ + return this->_data >> 56; +} + +uint64_t +QUICAckFrame::AckBlock::length() const +{ + return this->_data & 0x0000FFFFFFFFFFFF; +} + +uint8_t +QUICAckFrame::AckBlockSection::count() const +{ + if (this->_buf) { + return this->_num_blocks; + } else { + return this->_ack_blocks.size(); + } +} + +size_t +QUICAckFrame::AckBlockSection::size() const +{ + if (this->_buf) { + return this->_ack_block_length + (this->_ack_block_length + 1) * this->_num_blocks; + } else { + // TODO Which block length should we use? + return 48 + (48 + 1) * this->_ack_blocks.size(); + } +} + +void +QUICAckFrame::AckBlockSection::store(uint8_t *buf, size_t *len) const +{ + uint8_t *p = buf; + size_t dummy; + QUICTypeUtil::write_uint_as_nbytes(this->_first_ack_block_length, 4, buf, &dummy); + p += 4; + for (auto &&block : *this) { + p[0] = block.gap(); + p += 1; + QUICTypeUtil::write_uint_as_nbytes(block.length(), 4, buf, &dummy); + p += 4; + } + *len = p - buf; +} + +uint64_t +QUICAckFrame::AckBlockSection::first_ack_block_length() const +{ + return this->_first_ack_block_length; +} + +void +QUICAckFrame::AckBlockSection::add_ack_block(AckBlock block) +{ + this->_ack_blocks.push_back(block); +} + +QUICAckFrame::AckBlockSection::const_iterator +QUICAckFrame::AckBlockSection::begin() const +{ + if (this->_buf) { + return const_iterator(0, this->_buf, this->_num_blocks, this->_ack_block_length); + } else { + return const_iterator(0, &this->_ack_blocks); + } +} + +QUICAckFrame::AckBlockSection::const_iterator +QUICAckFrame::AckBlockSection::end() const +{ + if (this->_buf) { + return const_iterator(this->_num_blocks, this->_buf, this->_num_blocks, this->_ack_block_length); + } else { + return const_iterator(this->_ack_blocks.size(), &this->_ack_blocks); + } +} + +QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, const uint8_t *buf, uint8_t num_blocks, + uint8_t ack_block_length) +{ + this->_index = index; + this->_buf = buf; + this->_current_block = AckBlock(buf, ack_block_length); +} + +QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, const std::vector *ack_block) +{ + this->_index = index; + this->_ack_blocks = ack_block; + if (this->_ack_blocks->size()) { + if (this->_ack_blocks->size() == this->_index) { + this->_current_block = {0, 0ULL}; + } else { + this->_current_block = this->_ack_blocks->at(this->_index); + } + } +} + +uint8_t +QUICAckFrame::TimestampSection::count() const +{ + return 0; +} + +size_t +QUICAckFrame::TimestampSection::size() const +{ + return 0; +} + +void +QUICAckFrame::TimestampSection::store(uint8_t *buf, size_t *len) const +{ + if (this->count() == 0) { + *len = 0; + return; + } + + // TODO: Store timestamp data +} + +// +// RST_STREAM frame +// + +QUICRstStreamFrame::QUICRstStreamFrame(QUICErrorCode error_code, QUICStreamId stream_id, QUICOffset final_offset) + : _error_code(error_code), _stream_id(stream_id), _final_offset(final_offset) +{ +} + +QUICFrameType +QUICRstStreamFrame::type() const +{ + return QUICFrameType::RST_STREAM; +} + +size_t +QUICRstStreamFrame::size() const +{ + return 17; +} + +void +QUICRstStreamFrame::store(uint8_t *buf, size_t *len) const +{ + size_t n; + uint8_t *p = buf; + *p = 0x01; + ++p; + QUICTypeUtil::write_QUICErrorCode(this->_error_code, p, &n); + p += n; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n); + p += n; + QUICTypeUtil::write_QUICOffset(this->_final_offset, 8, p, &n); + p += n; + + *len = p - buf; +} + +QUICErrorCode +QUICRstStreamFrame::error_code() const +{ + return QUICTypeUtil::read_QUICErrorCode(this->_buf + 1); +} + +QUICStreamId +QUICRstStreamFrame::stream_id() const +{ + return QUICTypeUtil::read_QUICStreamId(this->_buf + 5, 4); +} + +QUICOffset +QUICRstStreamFrame::final_offset() const +{ + return QUICTypeUtil::read_QUICOffset(this->_buf + 9, 8); +} + +// +// PING frame +// +QUICFrameType +QUICPingFrame::type() const +{ + return QUICFrameType::PING; +} + +size_t +QUICPingFrame::size() const +{ + return 1; +} + +void +QUICPingFrame::store(uint8_t *buf, size_t *len) const +{ + buf[0] = 0x07; + *len = 1; +} + +// +// PADDING frame +// +QUICFrameType +QUICPaddingFrame::type() const +{ + return QUICFrameType::PADDING; +} + +size_t +QUICPaddingFrame::size() const +{ + return 1; +} + +void +QUICPaddingFrame::store(uint8_t *buf, size_t *len) const +{ + buf[0] = 0x00; + *len = 1; +} + +// +// GOAWAY frame +// + +QUICGoawayFrame::QUICGoawayFrame(QUICStreamId client_stream_id, QUICStreamId server_stream_id) +{ + this->_client_stream_id = client_stream_id; + this->_server_stream_id = server_stream_id; +} + +QUICFrameType +QUICGoawayFrame::type() const +{ + return QUICFrameType::GOAWAY; +} + +size_t +QUICGoawayFrame::size() const +{ + return 9; +} + +void +QUICGoawayFrame::store(uint8_t *buf, size_t *len) const +{ + size_t n; + uint8_t *p = buf; + *p = 0x03; + ++p; + QUICTypeUtil::write_QUICStreamId(this->_client_stream_id, 4, p, &n); + p += n; + QUICTypeUtil::write_QUICStreamId(this->_server_stream_id, 4, p, &n); + p += n; + *len = p - buf; +} + +QUICStreamId +QUICGoawayFrame::client_stream_id() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICStreamId(this->_buf + 1, 4); + } else { + return this->_client_stream_id; + } +} + +QUICStreamId +QUICGoawayFrame::server_stream_id() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICStreamId(this->_buf + 5, 4); + } else { + return this->_server_stream_id; + } +} + +// +// CONNECTION_CLOSE frame +// + +QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICErrorCode error_code, uint16_t reason_phrase_length, + const char *reason_phrase) +{ + this->_error_code = error_code; + this->_reason_phrase_length = reason_phrase_length; + this->_reason_phrase = reason_phrase; +} + +QUICFrameType +QUICConnectionCloseFrame::type() const +{ + return QUICFrameType::CONNECTION_CLOSE; +} + +size_t +QUICConnectionCloseFrame::size() const +{ + return 7 + this->reason_phrase_length(); +} + +void +QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len) const +{ + size_t n; + uint8_t *p = buf; + *p = 0x02; + ++p; + QUICTypeUtil::write_QUICErrorCode(this->_error_code, p, &n); + p += n; + QUICTypeUtil::write_uint_as_nbytes(this->_reason_phrase_length, 2, p, &n); + p += n; + memcpy(p, this->_reason_phrase, this->_reason_phrase_length); + p += this->_reason_phrase_length; + + *len = p - buf; +} + +QUICErrorCode +QUICConnectionCloseFrame::error_code() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICErrorCode(this->_buf + 1); + } else { + return this->_error_code; + } +} + +uint16_t +QUICConnectionCloseFrame::reason_phrase_length() const +{ + if (this->_buf) { + return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 5, 2); + } else { + return this->_reason_phrase_length; + } +} + +const char * +QUICConnectionCloseFrame::reason_phrase() const +{ + if (this->_buf) { + return reinterpret_cast(this->_buf + 7); + } else { + return this->_reason_phrase; + } +} + +// +// MAX_DATA frame +// +QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data) +{ + this->_maximum_data = maximum_data; +} + +QUICFrameType +QUICMaxDataFrame::type() const +{ + return QUICFrameType::MAX_DATA; +} + +size_t +QUICMaxDataFrame::size() const +{ + return 9; +} + +void +QUICMaxDataFrame::store(uint8_t *buf, size_t *len) const +{ + size_t n; + uint8_t *p = buf; + *p = 0x04; + ++p; + QUICTypeUtil::write_uint_as_nbytes(this->_maximum_data, 8, p, &n); + p += n; + + *len = p - buf; +} + +uint64_t +QUICMaxDataFrame::maximum_data() const +{ + if (this->_buf) { + return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 1, 8); + } else { + return this->_maximum_data; + } +} + +// +// MAX_STREAM_DATA +// +QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data) +{ + this->_stream_id = stream_id; + this->_maximum_stream_data = maximum_stream_data; +} + +QUICFrameType +QUICMaxStreamDataFrame::type() const +{ + return QUICFrameType::MAX_STREAM_DATA; +} + +size_t +QUICMaxStreamDataFrame::size() const +{ + return 13; +} + +void +QUICMaxStreamDataFrame::store(uint8_t *buf, size_t *len) const +{ + size_t n; + uint8_t *p = buf; + *p = 0x05; + ++p; + QUICTypeUtil::write_uint_as_nbytes(this->_stream_id, 4, p, &n); + p += n; + QUICTypeUtil::write_uint_as_nbytes(this->_maximum_stream_data, 8, p, &n); + p += n; + + *len = p - buf; +} + +QUICStreamId +QUICMaxStreamDataFrame::stream_id() const +{ + if (this->_buf) { + return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 1, 4); + } else { + return this->_stream_id; + } +} + +uint64_t +QUICMaxStreamDataFrame::maximum_stream_data() const +{ + if (this->_buf) { + return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 5, 8); + } else { + return this->_maximum_stream_data; + } +} + +// +// MAX_STREAM_ID +// +QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id) +{ + this->_maximum_stream_id = maximum_stream_id; +} + +QUICFrameType +QUICMaxStreamIdFrame::type() const +{ + return QUICFrameType::MAX_STREAM_ID; +} + +size_t +QUICMaxStreamIdFrame::size() const +{ + return 5; +} + +void +QUICMaxStreamIdFrame::store(uint8_t *buf, size_t *len) const +{ + size_t n; + uint8_t *p = buf; + *p = 0x06; + ++p; + QUICTypeUtil::write_uint_as_nbytes(this->_maximum_stream_id, 4, p, &n); + p += n; + + *len = p - buf; +} + +QUICStreamId +QUICMaxStreamIdFrame::maximum_stream_id() const +{ + if (this->_buf) { + return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 1, 4); + } else { + return this->_maximum_stream_id; + } +} + +// +// BLOCKED frame +// +QUICFrameType +QUICBlockedFrame::type() const +{ + return QUICFrameType::BLOCKED; +} + +size_t +QUICBlockedFrame::size() const +{ + return 1; +} + +void +QUICBlockedFrame::store(uint8_t *buf, size_t *len) const +{ + buf[0] = 0x08; + *len = 1; +} + +// +// STREAM_BLOCKED frame +// +QUICStreamBlockedFrame::QUICStreamBlockedFrame(QUICStreamId stream_id) +{ + this->_stream_id = stream_id; +} + +QUICFrameType +QUICStreamBlockedFrame::type() const +{ + return QUICFrameType::STREAM_BLOCKED; +} + +size_t +QUICStreamBlockedFrame::size() const +{ + return 5; +} + +void +QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len) const +{ + size_t n; + uint8_t *p = buf; + *p = 0x09; + ++p; + QUICTypeUtil::write_uint_as_nbytes(this->_stream_id, 4, p, &n); + p += n; + + *len = p - buf; +} + +QUICStreamId +QUICStreamBlockedFrame::stream_id() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICStreamId(this->_buf + 1, 4); + } else { + return this->_stream_id; + } +} + +// +// STREAM_ID_NEEDED frame +// +QUICFrameType +QUICStreamIdNeededFrame::type() const +{ + return QUICFrameType::STREAM_ID_NEEDED; +} + +size_t +QUICStreamIdNeededFrame::size() const +{ + return 1; +} + +void +QUICStreamIdNeededFrame::store(uint8_t *buf, size_t *len) const +{ + buf[0] = 0x0a; + *len = 1; +} + +// +// NEW_CONNECTION_ID frame +// + +QUICNewConnectionIdFrame::QUICNewConnectionIdFrame(uint16_t sequence, QUICConnectionId connection_id) +{ + this->_sequence = sequence; + this->_connection_id = connection_id; +} + +QUICFrameType +QUICNewConnectionIdFrame::type() const +{ + return QUICFrameType::NEW_CONNECTION_ID; +} + +size_t +QUICNewConnectionIdFrame::size() const +{ + return 11; +} + +void +QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len) const +{ + size_t n; + uint8_t *p = buf; + *p = 0x0b; + ++p; + QUICTypeUtil::write_uint_as_nbytes(this->_sequence, 2, p, &n); + p += n; + QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, p, &n); + p += n; + + *len = p - buf; +} + +uint16_t +QUICNewConnectionIdFrame::sequence() const +{ + if (this->_buf) { + return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 1, 2); + } else { + return this->_sequence; + } +} + +QUICConnectionId +QUICNewConnectionIdFrame::connection_id() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICConnectionId(this->_buf + 3, 8); + } else { + return this->_connection_id; + } +} + +// +// QUICRetransmissionFrame +// +QUICRetransmissionFrame::QUICRetransmissionFrame(std::unique_ptr original_frame, + const QUICPacket &original_packet) + : QUICFrame(), _packet_type(original_packet.type()) +{ + size_t dummy; + this->_size = original_frame->size(); + this->_data = ats_unique_malloc(this->_size); + this->_buf = this->_data.get(); + original_frame->store(this->_data.get(), &dummy); +} + +size_t +QUICRetransmissionFrame::size() const +{ + return this->_size; +} + +void +QUICRetransmissionFrame::store(uint8_t *buf, size_t *len) const +{ + memcpy(buf, this->_data.get(), this->_size); + *len = this->_size; +} + +QUICPacketType +QUICRetransmissionFrame::packet_type() const +{ + return this->_packet_type; +} + +// +// QUICFrameFactory +// + +std::unique_ptr +QUICFrameFactory::create(const uint8_t *buf, size_t len) +{ + QUICFrame *frame; + + switch (QUICFrame::type(buf)) { + case QUICFrameType::STREAM: + frame = quicStreamFrameAllocator.alloc(); + new (frame) QUICStreamFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_frame); + case QUICFrameType::ACK: + frame = quicAckFrameAllocator.alloc(); + new (frame) QUICAckFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_ack_frame); + case QUICFrameType::PADDING: + frame = quicPaddingFrameAllocator.alloc(); + new (frame) QUICPaddingFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_padding_frame); + case QUICFrameType::RST_STREAM: + frame = quicRstStreamFrameAllocator.alloc(); + new (frame) QUICRstStreamFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_rst_stream_frame); + case QUICFrameType::CONNECTION_CLOSE: + frame = quicConnectionCloseFrameAllocator.alloc(); + new (frame) QUICConnectionCloseFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); + case QUICFrameType::GOAWAY: + frame = quicGoawayFrameAllocator.alloc(); + new (frame) QUICGoawayFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_goaway_frame); + case QUICFrameType::MAX_DATA: + frame = quicMaxDataFrameAllocator.alloc(); + new (frame) QUICMaxDataFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_data_frame); + case QUICFrameType::MAX_STREAM_DATA: + frame = quicMaxStreamDataFrameAllocator.alloc(); + new (frame) QUICMaxStreamDataFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); + case QUICFrameType::MAX_STREAM_ID: + frame = quicMaxStreamIdFrameAllocator.alloc(); + new (frame) QUICMaxStreamIdFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_id_frame); + case QUICFrameType::PING: + frame = quicPingFrameAllocator.alloc(); + new (frame) QUICPingFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_ping_frame); + case QUICFrameType::BLOCKED: + frame = quicBlockedFrameAllocator.alloc(); + new (frame) QUICBlockedFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_blocked_frame); + case QUICFrameType::STREAM_BLOCKED: + frame = quicStreamBlockedFrameAllocator.alloc(); + new (frame) QUICStreamBlockedFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); + case QUICFrameType::STREAM_ID_NEEDED: + frame = quicStreamIdNeededFrameAllocator.alloc(); + new (frame) QUICStreamIdNeededFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_id_needed_frame); + case QUICFrameType::NEW_CONNECTION_ID: + frame = quicNewConnectionIdFrameAllocator.alloc(); + new (frame) QUICNewConnectionIdFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_connection_id_frame); + default: + // Unknown frame + return std::unique_ptr(nullptr, &QUICFrameDeleter::delete_null_frame); + } +} + +std::shared_ptr +QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) +{ + if (QUICFrame::type(buf) == QUICFrameType::UNKNOWN) { + return nullptr; + } + + std::shared_ptr frame = this->_reusable_frames[static_cast(QUICFrame::type(buf))]; + + if (frame == nullptr) { + frame = QUICFrameFactory::create(buf, len); + if (frame != nullptr) { + this->_reusable_frames[static_cast(QUICFrame::type(buf))] = frame; + } + } else { + frame->reset(buf, len); + } + + return frame; +} + +std::unique_ptr +QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset) +{ + QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); + new (frame) QUICStreamFrame(data, data_len, stream_id, offset); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_frame); +} + +std::unique_ptr +QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint16_t ack_delay, uint64_t first_ack_block_length) +{ + QUICAckFrame *frame = quicAckFrameAllocator.alloc(); + new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block_length); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_ack_frame); +} + +std::unique_ptr +QUICFrameFactory::create_connection_close_frame(QUICErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase) +{ + QUICConnectionCloseFrame *frame = quicConnectionCloseFrameAllocator.alloc(); + new (frame) QUICConnectionCloseFrame(error_code, reason_phrase_length, reason_phrase); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); +} + +std::unique_ptr +QUICFrameFactory::create_retransmission_frame(std::unique_ptr original_frame, + const QUICPacket &original_packet) +{ + QUICRetransmissionFrame *frame = quicRetransmissionFrameAllocator.alloc(); + new (frame) QUICRetransmissionFrame(std::move(original_frame), original_packet); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_retransmission_frame); +} diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h new file mode 100644 index 00000000000..a4247802d63 --- /dev/null +++ b/iocore/net/quic/QUICFrame.h @@ -0,0 +1,616 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include "ts/List.h" +#include +#include + +#include "QUICTypes.h" +#include "QUICPacket.h" + +class QUICFrame +{ +public: + QUICFrame(const uint8_t *buf, size_t len) : _buf(buf), _len(len){}; + virtual QUICFrameType type() const; + virtual size_t size() const = 0; + virtual void store(uint8_t *buf, size_t *len) const = 0; + virtual void reset(const uint8_t *buf, size_t len); + static QUICFrameType type(const uint8_t *buf); + + LINK(QUICFrame, link); + +protected: + QUICFrame() {} + const uint8_t *_buf = nullptr; + size_t _len = 0; +}; + +// +// STREAM Frame +// + +class QUICStreamFrame : public QUICFrame +{ +public: + QUICStreamFrame() : QUICFrame() {} + QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICStreamFrame(const uint8_t *buf, size_t len, QUICStreamId streamid, QUICOffset offset); + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + void store(uint8_t *buf, size_t *len, bool include_length_field) const; + QUICStreamId stream_id() const; + QUICOffset offset() const; + const uint8_t *data() const; + size_t data_length() const; + bool has_data_length_field() const; + bool has_fin_flag() const; + + LINK(QUICStreamFrame, link); + +private: + const uint8_t *_data = nullptr; + size_t _data_len = 0; + QUICStreamId _stream_id = 0; + QUICOffset _offset = 0; + bool _fin = false; + size_t _get_data_offset() const; + size_t _get_stream_id_offset() const; + size_t _get_offset_offset() const; + size_t _get_stream_id_len() const; + size_t _get_offset_len() const; +}; + +// +// ACK Frame +// + +class QUICAckFrame : public QUICFrame +{ +public: + class AckBlock + { + public: + AckBlock(const uint8_t *buf, uint8_t ack_block_length); + AckBlock(uint8_t gap, uint64_t length); + uint8_t gap() const; + uint64_t length() const; + LINK(QUICAckFrame::AckBlock, link); + + private: + uint64_t _data = 0; + }; + + class AckBlockSection + { + public: + class const_iterator : public std::iterator + { + public: + const_iterator(uint8_t index, const uint8_t *buf, uint8_t num_blocks, uint8_t ack_block_length); + const_iterator(uint8_t index, const std::vector *ack_blocks); + + const QUICAckFrame::AckBlock &operator*() const { return this->_current_block; }; + const QUICAckFrame::AckBlock *operator->() const { return &this->_current_block; }; + + const QUICAckFrame::AckBlock &operator++() + { + ++(this->_index); + + if (this->_buf) { + // TODO Parse Ack Block + } else { + if (this->_ack_blocks->size() == this->_index) { + this->_current_block = {0, 0ULL}; + } else { + this->_current_block = this->_ack_blocks->at(this->_index); + } + } + + return this->_current_block; + }; + + const bool + operator!=(const const_iterator &ite) const + { + return this->_index != ite._index; + }; + + const bool + operator==(const const_iterator &ite) const + { + return this->_index == ite._index; + }; + + private: + uint8_t _index; + const uint8_t *_buf; + const std::vector *_ack_blocks = nullptr; + QUICAckFrame::AckBlock _current_block = {0, 0ULL}; + }; + + AckBlockSection(uint64_t first_ack_block_length); + AckBlockSection(const uint8_t *buf, uint8_t num_blocks, uint8_t ack_block_length); + uint8_t count() const; + size_t size() const; + void store(uint8_t *buf, size_t *len) const; + uint64_t first_ack_block_length() const; + void add_ack_block(const AckBlock block); + const_iterator begin() const; + const_iterator end() const; + + private: + const uint8_t *_buf = nullptr; + uint64_t _first_ack_block_length = 0; + uint8_t _num_blocks = 0; + uint8_t _ack_block_length = 0; + std::vector _ack_blocks; + }; + + class TimestampSection + { + public: + uint8_t count() const; + size_t size() const; + void store(uint8_t *buf, size_t *len) const; + void add_timestamp(); + }; + + QUICAckFrame() : QUICFrame() {} + QUICAckFrame(const uint8_t *buf, size_t len); + QUICAckFrame(QUICPacketNumber largest_acknowledged, uint16_t ack_delay, uint64_t first_ack_block_length); + ~QUICAckFrame(); + virtual void reset(const uint8_t *buf, size_t len) override; + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + uint8_t num_blocks() const; + uint8_t num_timestamps() const; + QUICPacketNumber largest_acknowledged() const; + uint16_t ack_delay() const; + const AckBlockSection *ack_block_section() const; + AckBlockSection *ack_block_section(); + const TimestampSection *timestamp_section() const; + bool has_ack_blocks() const; + +private: + size_t _get_num_timestamp_offset() const; + size_t _get_largest_acknowledged_offset() const; + size_t _get_largest_acknowledged_length() const; + size_t _get_ack_block_length() const; + size_t _get_ack_delay_offset() const; + size_t _get_ack_block_section_offset() const; + size_t _get_timestamp_section_offset() const; + QUICPacketNumber _largest_acknowledged = 0; + uint16_t _ack_delay = 0; + AckBlockSection *_ack_block_section = nullptr; + TimestampSection *_timestamp_section = nullptr; +}; + +// +// RST_STREAM +// + +class QUICRstStreamFrame : public QUICFrame +{ +public: + QUICRstStreamFrame() : QUICFrame() {} + QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICRstStreamFrame(QUICErrorCode error_code, QUICStreamId stream_id, QUICOffset final_offset); + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + QUICErrorCode error_code() const; + QUICStreamId stream_id() const; + QUICOffset final_offset() const; + +private: + QUICErrorCode _error_code; + QUICStreamId _stream_id = 0; + QUICOffset _final_offset = 0; +}; + +// +// PING +// + +class QUICPingFrame : public QUICFrame +{ +public: + QUICPingFrame() : QUICFrame() {} + QUICPingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; +}; + +// PADDING + +class QUICPaddingFrame : public QUICFrame +{ +public: + QUICPaddingFrame() : QUICFrame() {} + QUICPaddingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; +}; + +// +// GOAWAY +// + +class QUICGoawayFrame : public QUICFrame +{ +public: + QUICGoawayFrame() : QUICFrame() {} + QUICGoawayFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICGoawayFrame(QUICStreamId client_stream_id, QUICStreamId server_stream_id); + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + QUICStreamId client_stream_id() const; + QUICStreamId server_stream_id() const; + +private: + QUICStreamId _client_stream_id = 0; + QUICStreamId _server_stream_id = 0; +}; + +// +// CONNECTION_CLOSE +// + +class QUICConnectionCloseFrame : public QUICFrame +{ +public: + QUICConnectionCloseFrame() : QUICFrame() {} + QUICConnectionCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICConnectionCloseFrame(QUICErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase); + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + QUICErrorCode error_code() const; + uint16_t reason_phrase_length() const; + const char *reason_phrase() const; + +private: + QUICErrorCode _error_code; + uint16_t _reason_phrase_length = 0; + const char *_reason_phrase = nullptr; +}; + +// +// MAX_DATA +// + +class QUICMaxDataFrame : public QUICFrame +{ +public: + QUICMaxDataFrame() : QUICFrame() {} + QUICMaxDataFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICMaxDataFrame(uint64_t maximum_data); + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + uint64_t maximum_data() const; + +private: + uint64_t _maximum_data = 0; +}; + +// +// MAX_STREAM_DATA +// + +class QUICMaxStreamDataFrame : public QUICFrame +{ +public: + QUICMaxStreamDataFrame() : QUICFrame() {} + QUICMaxStreamDataFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data); + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + QUICStreamId stream_id() const; + uint64_t maximum_stream_data() const; + +private: + QUICStreamId _stream_id = 0; + uint64_t _maximum_stream_data = 0; +}; + +// +// MAX_STREAM_ID +// + +class QUICMaxStreamIdFrame : public QUICFrame +{ +public: + QUICMaxStreamIdFrame() : QUICFrame() {} + QUICMaxStreamIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id); + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + QUICStreamId maximum_stream_id() const; + +private: + QUICStreamId _maximum_stream_id = 0; +}; + +// +// BLOCKED +// +class QUICBlockedFrame : public QUICFrame +{ +public: + QUICBlockedFrame() : QUICFrame() {} + QUICBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; +}; + +// +// STREAM_BLOCKED +// + +class QUICStreamBlockedFrame : public QUICFrame +{ +public: + QUICStreamBlockedFrame() : QUICFrame() {} + QUICStreamBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICStreamBlockedFrame(QUICStreamId stream_id); + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + QUICStreamId stream_id() const; + +private: + QUICStreamId _stream_id; +}; + +// +// STREAM_ID_NEEDED +// +class QUICStreamIdNeededFrame : public QUICFrame +{ +public: + QUICStreamIdNeededFrame() : QUICFrame() {} + QUICStreamIdNeededFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; +}; + +// +// NEW_CONNECTION_ID +// + +class QUICNewConnectionIdFrame : public QUICFrame +{ +public: + QUICNewConnectionIdFrame() : QUICFrame() {} + QUICNewConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICNewConnectionIdFrame(uint16_t sequence, QUICConnectionId connection_id); + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + uint16_t sequence() const; + QUICConnectionId connection_id() const; + +private: + uint16_t _sequence = 0; + QUICConnectionId _connection_id = 0; +}; + +typedef void (*QUICFrameDeleterFunc)(QUICFrame *p); + +// +// Retransmission Frame +// + +class QUICRetransmissionFrame : public QUICFrame +{ +public: + QUICRetransmissionFrame() : QUICFrame() {} + QUICRetransmissionFrame(std::unique_ptr original_frame, const QUICPacket &original_packet); + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + QUICPacketType packet_type() const; + +private: + std::unique_ptr _frame = std::unique_ptr(nullptr, nullptr); + ats_unique_buf _data = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); + size_t _size; + QUICPacketType _packet_type; +}; + +extern ClassAllocator quicStreamFrameAllocator; +extern ClassAllocator quicAckFrameAllocator; +extern ClassAllocator quicPaddingFrameAllocator; +extern ClassAllocator quicRstStreamFrameAllocator; +extern ClassAllocator quicConnectionCloseFrameAllocator; +extern ClassAllocator quicGoawayFrameAllocator; +extern ClassAllocator quicMaxDataFrameAllocator; +extern ClassAllocator quicMaxStreamDataFrameAllocator; +extern ClassAllocator quicMaxStreamIdFrameAllocator; +extern ClassAllocator quicPingFrameAllocator; +extern ClassAllocator quicBlockedFrameAllocator; +extern ClassAllocator quicStreamBlockedFrameAllocator; +extern ClassAllocator quicStreamIdNeededFrameAllocator; +extern ClassAllocator quicNewConnectionIdFrameAllocator; +extern ClassAllocator quicRetransmissionFrameAllocator; + +class QUICFrameDeleter +{ +public: + // TODO Probably these methods should call destructor + static void + delete_null_frame(QUICFrame *frame) + { + } + + static void + delete_stream_frame(QUICFrame *frame) + { + quicStreamFrameAllocator.free(static_cast(frame)); + } + + static void + delete_ack_frame(QUICFrame *frame) + { + quicAckFrameAllocator.free(static_cast(frame)); + } + + static void + delete_padding_frame(QUICFrame *frame) + { + quicPaddingFrameAllocator.free(static_cast(frame)); + } + + static void + delete_rst_stream_frame(QUICFrame *frame) + { + quicRstStreamFrameAllocator.free(static_cast(frame)); + } + + static void + delete_connection_close_frame(QUICFrame *frame) + { + quicConnectionCloseFrameAllocator.free(static_cast(frame)); + } + + static void + delete_goaway_frame(QUICFrame *frame) + { + quicGoawayFrameAllocator.free(static_cast(frame)); + } + + static void + delete_max_data_frame(QUICFrame *frame) + { + quicMaxDataFrameAllocator.free(static_cast(frame)); + } + + static void + delete_max_stream_data_frame(QUICFrame *frame) + { + quicMaxStreamDataFrameAllocator.free(static_cast(frame)); + } + + static void + delete_max_stream_id_frame(QUICFrame *frame) + { + quicMaxStreamIdFrameAllocator.free(static_cast(frame)); + } + + static void + delete_ping_frame(QUICFrame *frame) + { + quicPingFrameAllocator.free(static_cast(frame)); + } + + static void + delete_blocked_frame(QUICFrame *frame) + { + quicBlockedFrameAllocator.free(static_cast(frame)); + } + + static void + delete_stream_blocked_frame(QUICFrame *frame) + { + quicStreamBlockedFrameAllocator.free(static_cast(frame)); + } + + static void + delete_stream_id_needed_frame(QUICFrame *frame) + { + quicStreamIdNeededFrameAllocator.free(static_cast(frame)); + } + + static void + delete_new_connection_id_frame(QUICFrame *frame) + { + quicNewConnectionIdFrameAllocator.free(static_cast(frame)); + } + + static void + delete_retransmission_frame(QUICFrame *frame) + { + quicRetransmissionFrameAllocator.free(static_cast(frame)); + } +}; + +// +// QUICFrameFactory +// +class QUICFrameFactory +{ +public: + /* + * This is used for creating a QUICFrame object based on received data. + */ + static std::unique_ptr create(const uint8_t *buf, size_t len); + + /* + * 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. + */ + std::shared_ptr fast_create(const uint8_t *buf, size_t len); + + /* + * Creates a STREAM frame. + * You have to make sure that the data size won't exceed the maximum size of QUIC packet. + */ + static std::unique_ptr create_stream_frame(const uint8_t *data, size_t data_len, + QUICStreamId stream_id, QUICOffset offset); + /* + * Creates a ACK frame. + * You shouldn't call this directly but through QUICAckFrameCreator because QUICAckFrameCreator manages packet numbers that we + * need to ack. + */ + static std::unique_ptr create_ack_frame(QUICPacketNumber largest_acknowledged, + uint16_t ack_delay, uint64_t first_ack_block_length); + /* + * Creates a CONNECTION_CLOSE frame. + */ + static std::unique_ptr create_connection_close_frame( + QUICErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase); + + /* + * Creates a retransmission frame, which is very special. + * This retransmission frame will be used only for retransmission and it's not a standard frame type. + */ + static std::unique_ptr create_retransmission_frame( + std::unique_ptr original_frame, const QUICPacket &original_packet); + +private: + // FIXME Actual number of frame types is several but some of the values are not sequential. + std::shared_ptr _reusable_frames[256] = {nullptr}; +}; diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc new file mode 100644 index 00000000000..2a79560371a --- /dev/null +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -0,0 +1,148 @@ +/** @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 "QUICFrameDispatcher.h" +#include "QUICConnectionManager.h" +#include "QUICStreamManager.h" +#include "QUICFlowController.h" +#include "QUICCongestionController.h" +#include "QUICLossDetector.h" +#include "QUICEvents.h" + +const static char *tag = "quic_frame_handler"; + +// +// Frame Dispatcher +// +QUICFrameDispatcher::QUICFrameDispatcher(const std::shared_ptr cmgr, + const std::shared_ptr smgr, + const std::shared_ptr fctlr, + const std::shared_ptr cctlr, + const std::shared_ptr ld) +{ + connectionManager = cmgr; + streamManager = smgr; + flowController = fctlr; + congestionController = cctlr; + lossDetector = ld; +} + +bool +QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size) +{ + std::shared_ptr frame(nullptr); + uint16_t cursor = 0; + bool should_send_ack = false; + + while (cursor < size) { + frame = this->_frame_factory.fast_create(payload + cursor, size - cursor); + if (frame == nullptr) { + Debug(tag, "Failed to create a frame (%u bytes skipped)", size - cursor); + break; + } + cursor += frame->size(); + + // TODO: check debug build + if (frame->type() != QUICFrameType::PADDING) { + Debug(tag, "frame type %d, size %zu", frame->type(), frame->size()); + } + + // FIXME We should probably use a mapping table. All the objects has the common interface (QUICFrameHandler). + switch (frame->type()) { + case QUICFrameType::PADDING: { + // NOTE: do nothing + break; + } + case QUICFrameType::RST_STREAM: { + streamManager->handle_frame(frame); + should_send_ack = true; + break; + } + case QUICFrameType::CONNECTION_CLOSE: { + connectionManager->handle_frame(frame); + should_send_ack = true; + break; + } + case QUICFrameType::GOAWAY: { + connectionManager->handle_frame(frame); + should_send_ack = true; + break; + } + case QUICFrameType::MAX_DATA: { + flowController->handle_frame(frame); + should_send_ack = true; + break; + } + case QUICFrameType::MAX_STREAM_DATA: { + flowController->handle_frame(frame); + should_send_ack = true; + break; + } + case QUICFrameType::MAX_STREAM_ID: { + should_send_ack = true; + break; + } + case QUICFrameType::PING: { + connectionManager->handle_frame(frame); + should_send_ack = true; + break; + } + case QUICFrameType::BLOCKED: { + flowController->handle_frame(frame); + should_send_ack = true; + break; + } + case QUICFrameType::STREAM_BLOCKED: { + should_send_ack = true; + break; + } + case QUICFrameType::STREAM_ID_NEEDED: { + should_send_ack = true; + break; + } + case QUICFrameType::NEW_CONNECTION_ID: { + should_send_ack = true; + break; + } + case QUICFrameType::ACK: { + congestionController->handle_frame(frame); + this->lossDetector->handle_frame(frame); + break; + } + case QUICFrameType::STREAM: { + streamManager->handle_frame(frame); + flowController->handle_frame(frame); + congestionController->handle_frame(frame); + should_send_ack = true; + break; + } + default: + // Unknown frame + Debug(tag, "Unknown frame type: %02x", frame->type()); + ink_assert(false); + + break; + } + } + return should_send_ack; +} diff --git a/iocore/net/quic/QUICFrameDispatcher.h b/iocore/net/quic/QUICFrameDispatcher.h new file mode 100644 index 00000000000..c16316b01bb --- /dev/null +++ b/iocore/net/quic/QUICFrameDispatcher.h @@ -0,0 +1,53 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICFrame.h" + +class QUICStreamManager; +class QUICFlowController; +class QUICConnectionManager; +class QUICCongestionController; +class QUICLossDetector; + +class QUICFrameDispatcher +{ +public: + QUICFrameDispatcher(const std::shared_ptr cmgr, const std::shared_ptr smgr, + const std::shared_ptr fctlr, const std::shared_ptr cctlr, + const std::shared_ptr ld); + /* + * Returns true if ACK frame should be sent + */ + bool receive_frames(const uint8_t *payload, uint16_t size); + + std::shared_ptr connectionManager = nullptr; + std::shared_ptr streamManager = nullptr; + std::shared_ptr flowController = nullptr; + std::shared_ptr congestionController = nullptr; + std::shared_ptr lossDetector = nullptr; + +private: + QUICFrameFactory _frame_factory; +}; diff --git a/iocore/net/quic/QUICFrameHandler.h b/iocore/net/quic/QUICFrameHandler.h new file mode 100644 index 00000000000..6a99bac4f53 --- /dev/null +++ b/iocore/net/quic/QUICFrameHandler.h @@ -0,0 +1,31 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +class QUICFrameHandler +{ + virtual void handle_frame(std::shared_ptr frame) = 0; +}; diff --git a/iocore/net/quic/QUICFrameTransmitter.h b/iocore/net/quic/QUICFrameTransmitter.h new file mode 100644 index 00000000000..8612dafa5af --- /dev/null +++ b/iocore/net/quic/QUICFrameTransmitter.h @@ -0,0 +1,37 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICFrame.h" + +class QUICFrameTransmitter +{ +public: + /* + * Enqueue a frame for transmission + * + * This sends QUIC_PACKET_WRITE_READY event. + */ + virtual void transmit_frame(std::unique_ptr frame) = 0; +}; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc new file mode 100644 index 00000000000..e4221ae1345 --- /dev/null +++ b/iocore/net/quic/QUICHandshake.cc @@ -0,0 +1,249 @@ +/** @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 "QUICHandshake.h" + +#include "P_Net.h" +#include "P_QUICNetVConnection.h" +#include "QUICApplication.h" + +#define I_WANNA_DUMP_THIS_BUF(buf, len) \ + { \ + int i, j; \ + fprintf(stderr, "len=%lld\n", len); \ + for (i = 0; i < len / 8; i++) { \ + fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x ", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3], \ + buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6], buf[i * 8 + 7]); \ + if ((i + 1) % 4 == 0 || (len % 8 == 0 && i + 1 == len / 8)) { \ + fprintf(stderr, "\n"); \ + } \ + } \ + if (len % 8 != 0) { \ + fprintf(stderr, "%0x", buf[i * 8 + 0]); \ + for (j = 1; j < len % 8; j++) { \ + fprintf(stderr, " %02x", buf[i * 8 + j]); \ + } \ + fprintf(stderr, "\n"); \ + } \ + } + +const static char *tag = "quic_handshake"; +const static int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; +// TODO: fix size +const static int MAX_HANDSHAKE_MSG_LEN = 65527; + +QUICHandshake::QUICHandshake(ProxyMutex *m, QUICNetVConnection *vc) : QUICApplication(m, vc) +{ + SET_HANDLER(&QUICHandshake::state_read_client_hello); +} + +bool +QUICHandshake::is_completed() +{ + QUICCrypto *crypto = this->_client_vc->get_crypto(); + return crypto->is_handshake_finished(); +} + +const uint8_t * +QUICHandshake::negotiated_application_name() +{ + // TODO Use the protocol name negotiated on ALPN + return reinterpret_cast("hq"); +} + +int +QUICHandshake::state_read_client_hello(int event, Event *data) +{ + QUICError error; + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + error = this->_process_client_hello(); + break; + } + default: + Debug(tag, "event: %d", event); + break; + } + + if (error.cls != QUICErrorClass::NONE) { + this->_client_vc->close(error); + Debug(tag, "Enter state_closed"); + SET_HANDLER(&QUICHandshake::state_closed); + } + + return EVENT_CONT; +} + +int +QUICHandshake::state_read_client_finished(int event, Event *data) +{ + QUICError error; + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + error = this->_process_client_finished(); + break; + } + default: + Debug(tag, "event: %d", event); + break; + } + + if (error.cls != QUICErrorClass::NONE) { + this->_client_vc->close(error); + Debug(tag, "Enter state_closed"); + SET_HANDLER(&QUICHandshake::state_closed); + } + + return EVENT_CONT; +} + +int +QUICHandshake::state_address_validation(int event, void *data) +{ + // TODO Address validation should be implemented for the 2nd implementation draft + return EVENT_CONT; +} + +int +QUICHandshake::state_complete(int event, void *data) +{ + Debug(tag, "event: %d", event); + Debug(tag, "Got an event on complete state. Ignoring it for now."); + + return EVENT_CONT; +} + +int +QUICHandshake::state_closed(int event, void *data) +{ + return EVENT_CONT; +} + +QUICError +QUICHandshake::_process_client_hello() +{ + QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); + + // Complete message should fit in a packet and be able to read + uint8_t msg[UDP_MAXIMUM_PAYLOAD_SIZE] = {0}; + int64_t msg_len = stream_io->read_avail(); + stream_io->read(msg, msg_len); + + if (msg_len <= 0) { + Debug(tag, "No message"); + return QUICError(QUICErrorClass::NONE); + } + + // ----- DEBUG -----> + I_WANNA_DUMP_THIS_BUF(msg, msg_len); + // <----- DEBUG ----- + + QUICCrypto *crypto = this->_client_vc->get_crypto(); + + uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t server_hello_len = 0; + bool result = false; + result = crypto->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, msg, msg_len); + + if (result) { + // ----- DEBUG -----> + I_WANNA_DUMP_THIS_BUF(server_hello, static_cast(server_hello_len)); + // <----- DEBUG ----- + + Debug(tag, "Enter state_read_client_finished"); + SET_HANDLER(&QUICHandshake::state_read_client_finished); + + stream_io->write(server_hello, server_hello_len); + stream_io->write_reenable(); + stream_io->read_reenable(); + + return QUICError(QUICErrorClass::NONE); + } else { + return QUICError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::TLS_HANDSHAKE_FAILED); + } +} + +QUICError +QUICHandshake::_process_client_finished() +{ + QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); + + // Complete message should fit in a packet and be able to read + uint8_t msg[UDP_MAXIMUM_PAYLOAD_SIZE] = {0}; + int64_t msg_len = stream_io->read_avail(); + stream_io->read(msg, msg_len); + + if (msg_len <= 0) { + Debug(tag, "No message"); + return QUICError(QUICErrorClass::NONE); + } + + // ----- DEBUG -----> + I_WANNA_DUMP_THIS_BUF(msg, msg_len); + // <----- DEBUG ----- + + QUICCrypto *crypto = this->_client_vc->get_crypto(); + + uint8_t out[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t out_len = 0; + bool result = false; + result = crypto->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, msg, msg_len); + + if (result) { + // ----- DEBUG -----> + I_WANNA_DUMP_THIS_BUF(out, static_cast(out_len)); + // <----- DEBUG ----- + + ink_assert(this->is_completed()); + Debug(tag, "Handshake is completed"); + + Debug(tag, "Enter state_complete"); + SET_HANDLER(&QUICHandshake::state_complete); + _process_handshake_complete(); + + stream_io->write(out, out_len); + stream_io->write_reenable(); + stream_io->read_reenable(); + + return QUICError(QUICErrorClass::NONE); + } else { + return QUICError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::TLS_HANDSHAKE_FAILED); + } +} + +QUICError +QUICHandshake::_process_handshake_complete() +{ + QUICCrypto *crypto = this->_client_vc->get_crypto(); + int r = crypto->setup_session(); + + if (r) { + Debug(tag, "Keying Materials are exported"); + } else { + Debug(tag, "Failed to export Keying Materials"); + } + + return QUICError(QUICErrorClass::NONE); +} diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h new file mode 100644 index 00000000000..28854ec13f5 --- /dev/null +++ b/iocore/net/quic/QUICHandshake.h @@ -0,0 +1,68 @@ +/** @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. + */ + +#ifndef __QUIC_HANDSHAKE__ +#define __QUIC_HANDSHAKE__ + +#include "I_VConnection.h" +#include "QUICApplication.h" + +class QUICNetVConnection; + +/** + * @class QUICHandshake + * @brief Do handshake as a QUIC application + * @detail + * + * state_read_client_hello() + * | | _process_client_hello() + * | v + * | state_read_client_finished() + * | | | _process_client_finished() + * | / | _process_handshake_complete() + * | v + * | state_complete() + * | + * v + * state_closed() + */ +class QUICHandshake : public QUICApplication +{ +public: + QUICHandshake(ProxyMutex *m, QUICNetVConnection *vc); + + int state_read_client_hello(int event, Event *data); + int state_read_client_finished(int event, Event *data); + int state_address_validation(int event, void *data); + int state_complete(int event, void *data); + int state_closed(int event, void *data); + bool is_completed(); + const uint8_t *negotiated_application_name(); + +private: + QUICError _process_client_hello(); + QUICError _process_client_finished(); + QUICError _process_handshake_complete(); +}; + +#endif // __QUIC_HANDSHAKE__ diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc new file mode 100644 index 00000000000..5ffc58f4621 --- /dev/null +++ b/iocore/net/quic/QUICLossDetector.cc @@ -0,0 +1,325 @@ +/** @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 "QUICLossDetector.h" +#include "QUICEvents.h" +#include "ts/ink_assert.h" + +QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter) : _transmitter(transmitter) +{ + this->mutex = new_ProxyMutex(); + + this->_loss_detection_alarm = nullptr; + this->_handshake_count = 0; + this->_tlp_count = 0; + this->_rto_count = 0; + if (this->_time_loss_detection) { + this->_reordering_threshold = INFINITY; + this->_time_reordering_fraction = this->_TIME_REORDERING_FRACTION; + } else { + this->_reordering_threshold = this->_REORDERING_THRESHOLD; + this->_time_reordering_fraction = INFINITY; + } + this->_loss_time = 0; + this->_smoothed_rtt = 0; + this->_rttvar = 0; + this->_largest_sent_before_rto = 0; + this->_time_of_last_sent_packet = 0; + + SET_HANDLER(&QUICLossDetector::event_handler); +} + +int +QUICLossDetector::event_handler(int event, Event *edata) +{ + switch (event) { + case EVENT_INTERVAL: + this->_on_loss_detection_alarm(); + break; + default: + break; + } + return EVENT_CONT; +} + +void +QUICLossDetector::handle_frame(std::shared_ptr frame) +{ + switch (frame->type()) { + case QUICFrameType::ACK: + this->_on_ack_received(std::dynamic_pointer_cast(frame)); + break; + default: + Debug("quic_loss_detector", "Unexpected frame type: %02x", frame->type()); + ink_assert(false); + break; + } +} + +void +QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_number) +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + this->_loss_time = 0; + std::set lost_packets; + uint32_t delay_until_lost = UINT32_MAX; + + if (this->_time_reordering_fraction != INFINITY) { + delay_until_lost = (1 + this->_time_reordering_fraction) * max(this->_latest_rtt, this->_smoothed_rtt); + } else if (largest_acked_packet_number == this->_largest_sent_packet) { + // Early retransmit alarm. + delay_until_lost = 9 / 8 * max(this->_latest_rtt, this->_smoothed_rtt); + } + for (auto &unacked : this->_sent_packets) { + if (unacked.first >= largest_acked_packet_number) { + break; + } + ink_hrtime time_since_sent = Thread::get_hrtime() - unacked.second->time; + uint64_t packet_delta = largest_acked_packet_number - unacked.second->packet_number; + if (time_since_sent > delay_until_lost) { + lost_packets.insert(unacked.first); + } else if (packet_delta > this->_reordering_threshold) { + lost_packets.insert(unacked.first); + } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) { + this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent; + } + } + + // Inform the congestion controller of lost packets and + // lets it decide whether to retransmit immediately. + if (!lost_packets.empty()) { + // TODO cc->on_packets_lost(lost_packets); + for (auto packet_number : lost_packets) { + this->_decrement_packet_count(packet_number); + this->_sent_packets.erase(packet_number); + } + } +} + +void +QUICLossDetector::on_packet_sent(std::unique_ptr packet) +{ + bool is_handshake = false; + QUICPacketType type = packet->type(); + if (type != QUICPacketType::ZERO_RTT_PROTECTED || type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 || + type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { + is_handshake = true; + } + return this->_on_packet_sent(packet->packet_number(), packet->is_retransmittable(), is_handshake, packet->size(), + std::move(packet)); +} + +void +QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_retransmittable, bool is_handshake, size_t sent_bytes, + std::unique_ptr packet) +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + this->_largest_sent_packet = packet_number; + this->_time_of_last_sent_packet = Thread::get_hrtime(); + // FIXME Should we really keep actual packet object? + + std::unique_ptr packet_info(new PacketInfo( + {packet_number, this->_time_of_last_sent_packet, is_retransmittable, is_handshake, sent_bytes, std::move(packet)})); + this->_sent_packets.insert(std::pair>(packet_number, std::move(packet_info))); + if (is_handshake) { + ++this->_handshake_outstanding; + } + if (is_retransmittable) { + ++this->_retransmittable_outstanding; + this->_set_loss_detection_alarm(); + } +} + +void +QUICLossDetector::_on_ack_received(std::shared_ptr ack_frame) +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + // If the largest acked is newly acked, update the RTT. + auto pi = this->_sent_packets.find(ack_frame->largest_acknowledged()); + if (pi != this->_sent_packets.end()) { + this->_latest_rtt = Thread::get_hrtime() - pi->second->time; + if (this->_latest_rtt > ack_frame->ack_delay()) { + this->_latest_rtt -= ack_frame->ack_delay(); + } + this->_update_rtt(this->_latest_rtt); + } + // Find all newly acked packets. + for (auto acked_packet_number : this->_determine_newly_acked_packets(*ack_frame)) { + this->_on_packet_acked(acked_packet_number); + } + + this->_detect_lost_packets(ack_frame->largest_acknowledged()); + Debug("quic_loss_detector", "Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, + this->_retransmittable_outstanding); + this->_set_loss_detection_alarm(); +} + +void +QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number) +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + Debug("quic_loss_detector", "Packet number %llu has been acked", acked_packet_number); + this->_largest_acked_packet = acked_packet_number; + // If a packet sent prior to RTO was acked, then the RTO + // was spurious. Otherwise, inform congestion control. + if (this->_rto_count > 0 && acked_packet_number > this->_largest_sent_before_rto) { + // TODO cc->on_retransmission_timeout_verified(); + } + this->_handshake_count = 0; + this->_tlp_count = 0; + this->_rto_count = 0; + this->_decrement_packet_count(acked_packet_number); + this->_sent_packets.erase(acked_packet_number); +} + +void +QUICLossDetector::_decrement_packet_count(QUICPacketNumber packet_number) +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + auto ite = this->_sent_packets.find(packet_number); + if (ite != this->_sent_packets.end()) { + if (ite->second->handshake) { + --this->_handshake_outstanding; + } + if (ite->second->retransmittable) { + --this->_retransmittable_outstanding; + } + } +} + +void +QUICLossDetector::_on_loss_detection_alarm() +{ + if (this->_handshake_outstanding) { + // Handshake retransmission alarm. + this->_retransmit_handshake_packets(); + this->_handshake_count++; + } else if (this->_loss_time != 0) { + // Early retransmit or Time Loss Detection + this->_detect_lost_packets(this->_largest_acked_packet); + } else if (this->_tlp_count < this->_MAX_TLPS) { + // Tail Loss Probe. + // eventProcessor.schedule_imm(this->_handler, ET_CALL, QUIC_EVENT_RETRANSMIT_ONE_PACKET); + this->_tlp_count++; + } else { + // RTO. + if (this->_rto_count == 0) { + this->_largest_sent_before_rto = this->_largest_sent_packet; + } + // eventProcessor.schedule_imm(this->_handler, ET_CALL, QUIC_EVENT_RETRANSMIT_TWO_PACKET); + this->_rto_count++; + } + Debug("quic_loss_detector", "Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, + this->_retransmittable_outstanding); + this->_set_loss_detection_alarm(); +} + +void +QUICLossDetector::_update_rtt(uint32_t latest_rtt) +{ + // Based on {{RFC6298}}. + if (this->_smoothed_rtt == 0) { + this->_smoothed_rtt = latest_rtt; + this->_rttvar = latest_rtt / 2; + } else { + this->_rttvar = 3 / 4 * this->_rttvar + 1 / 4 * (this->_smoothed_rtt - latest_rtt); + this->_smoothed_rtt = 7 / 8 * this->_smoothed_rtt + 1 / 8 * latest_rtt; + } +} + +void +QUICLossDetector::_set_loss_detection_alarm() +{ + uint32_t alarm_duration; + if (!this->_retransmittable_outstanding && this->_loss_detection_alarm) { + this->_loss_detection_alarm->cancel(); + this->_loss_detection_alarm = nullptr; + Debug("quic_loss_detection", "Loss detection alarm has been unset"); + return; + } + if (this->_handshake_outstanding) { + // Handshake retransmission alarm. + if (this->_smoothed_rtt == 0) { + alarm_duration = 2 * this->_DEFAULT_INITIAL_RTT; + } else { + alarm_duration = 2 * this->_smoothed_rtt; + } + alarm_duration = max(alarm_duration, this->_MIN_TLP_TIMEOUT); + alarm_duration = alarm_duration * (2 ^ this->_handshake_count); + Debug("quic_loss_detection", "Handshake retransmission alarm will be set"); + } else if (this->_loss_time != 0) { + // Early retransmit timer or time loss detection. + alarm_duration = this->_loss_time - Thread::get_hrtime(); + Debug("quic_loss_detection", "Early retransmit timer or time loss detection will be set"); + } else if (this->_tlp_count < this->_MAX_TLPS) { + // Tail Loss Probe + if (this->_retransmittable_outstanding) { + alarm_duration = 1.5 * this->_smoothed_rtt + this->_DELAYED_ACK_TIMEOUT; + } else { + alarm_duration = this->_MIN_TLP_TIMEOUT; + } + alarm_duration = max(alarm_duration, 2 * this->_smoothed_rtt); + Debug("quic_loss_detection", "TLP alarm will be set"); + } else { + // RTO alarm + alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar; + alarm_duration = max(alarm_duration, this->_MIN_RTO_TIMEOUT); + alarm_duration = alarm_duration * (2 ^ this->_rto_count); + Debug("quic_loss_detection", "RTO alarm will be set"); + } + + if (this->_loss_detection_alarm) { + this->_loss_detection_alarm->cancel(); + } + this->_loss_detection_alarm = eventProcessor.schedule_in(this, alarm_duration); + Debug("quic_loss_detection", "Loss detection alarm has been set to %u", alarm_duration); +} + +std::set +QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame) +{ + std::set packets; + QUICPacketNumber x = ack_frame.largest_acknowledged(); + packets.insert(x); + for (auto &&block : *(ack_frame.ack_block_section())) { + for (int i = 0; i < block.gap(); ++i) { + packets.insert(++x); + } + x += block.length(); + } + + return packets; +} + +void +QUICLossDetector::_retransmit_handshake_packets() +{ + SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_transmitter_mutex().get(), this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + for (auto &info : this->_sent_packets) { + if (!info.second->handshake) { + break; + } + this->_transmitter->retransmit_packet(*info.second->packet); + } +} diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h new file mode 100644 index 00000000000..0a2b71cc996 --- /dev/null +++ b/iocore/net/quic/QUICLossDetector.h @@ -0,0 +1,108 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// TODO Using STL Map because ts/Map lacks remove method +#include +#include + +#include "../../eventsystem/I_EventSystem.h" +#include "../../eventsystem/I_Action.h" +#include "ts/ink_hrtime.h" +#include "I_VConnection.h" +#include "P_Net.h" +#include "QUICTypes.h" +#include "QUICPacket.h" +#include "QUICFrame.h" +#include "QUICFrameHandler.h" +#include "QUICPacketTransmitter.h" + +class QUICLossDetector : public Continuation, public QUICFrameHandler +{ +public: + QUICLossDetector(QUICPacketTransmitter *transmitter); + + int event_handler(int event, Event *edata); + + virtual void handle_frame(std::shared_ptr) override; + void on_packet_sent(std::unique_ptr packet); + +private: + struct PacketInfo { + QUICPacketNumber packet_number; + ink_hrtime time; + bool retransmittable; + bool handshake; + size_t bytes; + std::unique_ptr packet; + }; + + bool _time_loss_detection = false; + + // TODO QUICCongestionController *cc = nullptr; + + // 3.2.1. Constants of interest + uint32_t _MAX_TLPS = 2; + uint32_t _REORDERING_THRESHOLD = 3; + double _TIME_REORDERING_FRACTION = 1 / 8; + uint32_t _MIN_TLP_TIMEOUT = HRTIME_MSECONDS(10); + uint32_t _MIN_RTO_TIMEOUT = HRTIME_MSECONDS(200); + uint32_t _DELAYED_ACK_TIMEOUT = HRTIME_MSECONDS(25); + uint32_t _DEFAULT_INITIAL_RTT = HRTIME_MSECONDS(100); + + // 3.2.2. Variables of interest + Action *_loss_detection_alarm; + uint32_t _handshake_count = 0; + uint32_t _tlp_count = 0; + uint32_t _rto_count = 0; + uint32_t _largest_sent_before_rto; + uint32_t _largest_sent_packet; + uint32_t _largest_acked_packet; + uint32_t _time_of_last_sent_packet; + uint32_t _latest_rtt; + uint32_t _smoothed_rtt; + uint32_t _rttvar; + uint32_t _reordering_threshold; + double _time_reordering_fraction; + uint32_t _loss_time; + std::map> _sent_packets; + + uint32_t _handshake_outstanding = 0; + uint32_t _retransmittable_outstanding = 0; + void _decrement_packet_count(QUICPacketNumber packet_number); + + void _on_packet_sent(QUICPacketNumber packet_number, bool is_retransmittable, bool is_handshake, size_t sent_bytes, + std::unique_ptr packet); + void _on_ack_received(std::shared_ptr ack_frame); + void _on_packet_acked(QUICPacketNumber acked_packet_number); + void _update_rtt(uint32_t latest_rtt); + void _detect_lost_packets(QUICPacketNumber largest_acked); + void _set_loss_detection_alarm(); + void _on_loss_detection_alarm(); + std::set _determine_newly_acked_packets(const QUICAckFrame &ack_frame); + + void _retransmit_handshake_packets(); + + QUICPacketTransmitter *_transmitter = nullptr; +}; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc new file mode 100644 index 00000000000..135dd85ee94 --- /dev/null +++ b/iocore/net/quic/QUICPacket.cc @@ -0,0 +1,673 @@ +/** @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 +#include "QUICPacket.h" + +static const int OFFSET_CONNECTION_ID = 1; +static const int OFFSET_PACKET_NUMBER = 9; +static const int OFFSET_VERSION = 13; +static const int OFFSET_PAYLOAD = 17; +static const int LONGHEADER_LENGTH = 17; +static const int FNV1A_HASH_LEN = 8; + +ats_unique_buf +ats_unique_malloc(size_t size) +{ + return ats_unique_buf(reinterpret_cast(ats_malloc(size)), [](void *p) { ats_free(p); }); +} + +const uint8_t * +QUICPacketHeader::buf() +{ + return this->_buf; +} + +QUICPacketHeader * +QUICPacketHeader::load(const uint8_t *buf, size_t len) +{ + if (QUICTypeUtil::hasLongHeader(buf)) { + return new QUICPacketLongHeader(buf, len); + } else { + return new QUICPacketShortHeader(buf, len); + } +} + +QUICPacketHeader * +QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICVersion version, + ats_unique_buf payload, size_t len) +{ + return new QUICPacketLongHeader(type, connection_id, packet_number, version, std::move(payload), len); +} + +QUICPacketHeader * +QUICPacketHeader::build(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len) +{ + return new QUICPacketShortHeader(type, packet_number, std::move(payload), len); +} + +QUICPacketHeader * +QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, + size_t len) +{ + return new QUICPacketShortHeader(type, connection_id, packet_number, std::move(payload), len); +} + +// QUICPacketLongHeader + +QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICVersion version, ats_unique_buf buf, size_t len) +{ + this->_type = type; + this->_has_connection_id = true; + this->_connection_id = connection_id; + this->_packet_number = packet_number; + this->_has_version = true; + this->_version = version; + this->_payload = std::move(buf); + this->_payload_len = len; +} + +QUICPacketType +QUICPacketLongHeader::type() const +{ + if (this->_buf) { + int type = this->_buf[0] & 0x7F; + if (type < static_cast(QUICPacketType::UNINITIALIZED)) { + return static_cast(type); + } else { + return QUICPacketType::UNINITIALIZED; + } + } else { + return this->_type; + } +} + +QUICConnectionId +QUICPacketLongHeader::connection_id() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICConnectionId(this->_buf + OFFSET_CONNECTION_ID, 8); + } else { + return this->_connection_id; + } +} + +QUICPacketNumber +QUICPacketLongHeader::packet_number() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICPacketNumber(this->_buf + OFFSET_PACKET_NUMBER, 4); + } else { + return this->_packet_number; + } +} + +bool +QUICPacketLongHeader::has_version() const +{ + return true; +} + +QUICVersion +QUICPacketLongHeader::version() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICVersion(this->_buf + OFFSET_VERSION); + } else { + return this->_version; + } +} + +bool +QUICPacketLongHeader::has_connection_id() const +{ + return true; +} + +const uint8_t * +QUICPacketLongHeader::payload() const +{ + if (this->_buf) { + return this->_buf + OFFSET_PAYLOAD; + } else { + return this->_payload.get(); + } +} + +bool +QUICPacketLongHeader::has_key_phase() const +{ + return false; +} + +QUICKeyPhase +QUICPacketLongHeader::key_phase() const +{ + return QUICKeyPhase::PHASE_0; +} + +uint16_t +QUICPacketLongHeader::length() const +{ + return LONGHEADER_LENGTH; +} + +void +QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const +{ + size_t n; + *len = 0; + buf[0] = 0x80; + buf[0] += static_cast(this->_type); + *len += 1; + QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, buf + *len, &n); + *len += n; + QUICTypeUtil::write_QUICPacketNumber(this->_packet_number, 4, buf + *len, &n); + *len += n; + QUICTypeUtil::write_QUICVersion(this->_version, buf + *len, &n); + *len += n; +} + +// QUICPacketShortHeader + +QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf buf, size_t len) +{ + this->_type = type; + this->_has_key_phase = true; + this->_packet_number = packet_number; + this->_payload = std::move(buf); + this->_payload_len = len; + + if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0) { + this->_key_phase = QUICKeyPhase::PHASE_0; + } else if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { + this->_key_phase = QUICKeyPhase::PHASE_1; + } else { + ink_assert(false); + this->_key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; + } + + if (packet_number <= 0xFF) { + this->_packet_number_type = QUICPacketShortHeaderType::ONE; + } else if (packet_number <= 0xFFFF) { + this->_packet_number_type = QUICPacketShortHeaderType::TWO; + } else { + this->_packet_number_type = QUICPacketShortHeaderType::THREE; + } +} + +QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + ats_unique_buf buf, size_t len) +{ + this->_type = type; + this->_has_key_phase = true; + this->_has_connection_id = true; + this->_connection_id = connection_id; + this->_packet_number = packet_number; + this->_payload = std::move(buf); + this->_payload_len = len; + + if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0) { + this->_key_phase = QUICKeyPhase::PHASE_0; + } else if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { + this->_key_phase = QUICKeyPhase::PHASE_1; + } else { + ink_assert(false); + this->_key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; + } + + if (packet_number <= 0xFF) { + this->_packet_number_type = QUICPacketShortHeaderType::ONE; + } else if (packet_number <= 0xFFFF) { + this->_packet_number_type = QUICPacketShortHeaderType::TWO; + } else { + this->_packet_number_type = QUICPacketShortHeaderType::THREE; + } +} + +QUICPacketType +QUICPacketShortHeader::type() const +{ + QUICKeyPhase key_phase = this->key_phase(); + + switch (key_phase) { + case QUICKeyPhase::PHASE_0: { + return QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0; + } + case QUICKeyPhase::PHASE_1: { + return QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1; + } + default: + ink_assert(false); + return QUICPacketType::UNINITIALIZED; + } +} + +QUICConnectionId +QUICPacketShortHeader::connection_id() const +{ + if (this->_buf) { + ink_release_assert(this->has_connection_id()); + return QUICTypeUtil::read_QUICConnectionId(this->_buf + OFFSET_CONNECTION_ID, 8); + } else { + return _connection_id; + } +} + +QUICPacketNumber +QUICPacketShortHeader::packet_number() const +{ + if (this->_buf) { + int n = this->_packet_numberLen(); + int offset = 1; + if (this->has_connection_id()) { + offset = OFFSET_PACKET_NUMBER; + } + + return QUICTypeUtil::read_QUICPacketNumber(this->_buf + offset, n); + } else { + return this->_packet_number; + } +} + +bool +QUICPacketShortHeader::has_version() const +{ + return false; +} + +QUICVersion +QUICPacketShortHeader::version() const +{ + return 0; +} + +int +QUICPacketShortHeader::_packet_numberLen() const +{ + QUICPacketShortHeaderType type; + if (this->_buf) { + type = static_cast(this->_buf[0] & 0x1F); + } else { + type = this->_packet_number_type; + } + + switch (type) { + case QUICPacketShortHeaderType::ONE: + return 1; + case QUICPacketShortHeaderType::TWO: + return 2; + case QUICPacketShortHeaderType::THREE: + return 4; + default: + ink_assert(false); + return 0; + } +} + +bool +QUICPacketShortHeader::has_connection_id() const +{ + if (this->_buf) { + return (this->_buf[0] & 0x40) != 0; + } else { + return this->_has_connection_id; + } +} + +const uint8_t * +QUICPacketShortHeader::payload() const +{ + if (this->_buf) { + return this->_buf + length(); + } else { + return this->_payload.get(); + } +} + +bool +QUICPacketShortHeader::has_key_phase() const +{ + return true; +} + +QUICKeyPhase +QUICPacketShortHeader::key_phase() const +{ + if (this->_buf) { + if (this->_buf[0] & 0x20) { + return QUICKeyPhase::PHASE_1; + } else { + return QUICKeyPhase::PHASE_0; + } + } else { + return _key_phase; + } +} + +/** + * Header Length (doesn't include payload length) + */ +uint16_t +QUICPacketShortHeader::length() const +{ + uint16_t len = 1; + + if (this->has_connection_id()) { + len += 8; + } + len += this->_packet_numberLen(); + + return len; +} + +void +QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const +{ + size_t n; + *len = 0; + buf[0] = 0x00; + if (this->_has_connection_id) { + buf[0] += 0x40; + } + if (this->_key_phase == QUICKeyPhase::PHASE_1) { + buf[0] += 0x20; + } + buf[0] += static_cast(this->_packet_number_type); + *len += 1; + if (this->_has_connection_id) { + QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, buf + *len, &n); + *len += n; + } + switch (this->_packet_number_type) { + case QUICPacketShortHeaderType::ONE: + QUICTypeUtil::write_QUICPacketNumber(this->_packet_number, 1, buf + *len, &n); + break; + case QUICPacketShortHeaderType::TWO: + QUICTypeUtil::write_QUICPacketNumber(this->_packet_number, 2, buf + *len, &n); + break; + case QUICPacketShortHeaderType::THREE: + QUICTypeUtil::write_QUICPacketNumber(this->_packet_number, 4, buf + *len, &n); + break; + default: + ink_release_assert(0); + } + *len += n; +} + +// QUICPacket + +QUICPacket::QUICPacket(IOBufferBlock *block) : _block(block) +{ + this->_size = block->size(); + this->_header = QUICPacketHeader::load(reinterpret_cast(this->_block->buf()), this->_block->size()); +} + +QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICVersion version, + ats_unique_buf payload, size_t len, bool retransmittable) +{ + this->_header = QUICPacketHeader::build(type, connection_id, packet_number, version, std::move(payload), len); + this->_size = this->_header->length() + len; + if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && + type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { + this->_size += FNV1A_HASH_LEN; + } + this->_is_retransmittable = retransmittable; +} + +QUICPacket::QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len, + bool retransmittable) +{ + this->_header = QUICPacketHeader::build(type, packet_number, std::move(payload), len); + this->_size = this->_header->length() + len; + if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && + type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { + this->_size += FNV1A_HASH_LEN; + } + this->_is_retransmittable = retransmittable; +} + +QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, + size_t len, bool retransmittable) +{ + this->_header = QUICPacketHeader::build(type, connection_id, packet_number, std::move(payload), len); + this->_size = this->_header->length() + len; + if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && + type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { + this->_size += FNV1A_HASH_LEN; + } + this->_is_retransmittable = retransmittable; +} + +/** + * 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 +{ + return this->_header->type(); +} + +QUICConnectionId +QUICPacket::connection_id() const +{ + return this->_header->connection_id(); +} + +QUICPacketNumber +QUICPacket::packet_number() const +{ + return this->_header->packet_number(); +} + +const uint8_t * +QUICPacket::header() const +{ + return this->_header->buf(); +} + +const uint8_t * +QUICPacket::payload() const +{ + return this->_header->payload(); +} + +QUICVersion +QUICPacket::version() const +{ + return this->_header->version(); +} + +bool +QUICPacket::is_retransmittable() const +{ + return this->_is_retransmittable; +} + +uint16_t +QUICPacket::size() const +{ + return this->_size; +} + +uint16_t +QUICPacket::header_size() const +{ + return this->_header->length(); +} + +uint16_t +QUICPacket::payload_size() const +{ + // FIXME Protected packets may / may not contain something at the end + if (this->type() != QUICPacketType::ZERO_RTT_PROTECTED && this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && + this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { + return this->_size - this->_header->length() - FNV1A_HASH_LEN; + } else { + return this->_size - this->_header->length(); + } +} + +QUICKeyPhase +QUICPacket::key_phase() const +{ + return this->_header->key_phase(); +} + +void +QUICPacket::store(uint8_t *buf, size_t *len) const +{ + this->_header->store(buf, len); + ink_assert(this->size() >= *len); + + if (this->type() != QUICPacketType::ZERO_RTT_PROTECTED && this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && + this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { + memcpy(buf + *len, this->payload(), this->payload_size()); + *len += this->payload_size(); + + fnv1a(buf, *len, buf + *len); + *len += FNV1A_HASH_LEN; + } else { + ink_assert(this->_protected_payload); + memcpy(buf + *len, this->_protected_payload.get(), this->_protected_payload_size); + *len += this->_protected_payload_size; + } +} + +void +QUICPacket::store_header(uint8_t *buf, size_t *len) const +{ + this->_header->store(buf, len); +} + +bool +QUICPacket::has_valid_fnv1a_hash() const +{ + uint8_t hash[FNV1A_HASH_LEN]; + fnv1a(reinterpret_cast(this->_block->buf()), this->_block->size() - FNV1A_HASH_LEN, hash); + return memcmp(this->_block->buf() + this->_block->size() - FNV1A_HASH_LEN, hash, 8) == 0; +} + +void +QUICPacket::set_protected_payload(ats_unique_buf cipher_txt, size_t cipher_txt_len) +{ + this->_protected_payload = std::move(cipher_txt); + this->_protected_payload_size = cipher_txt_len; +} + +QUICPacket * +QUICPacketFactory::create(IOBufferBlock *block) +{ + // TODO: Use custom allocator + return new QUICPacket(block); +} + +std::unique_ptr +QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_sent_by_client) +{ + size_t len = sizeof(QUICVersion) * countof(QUIC_SUPPORTED_VERSIONS); + ats_unique_buf versions(reinterpret_cast(ats_malloc(len)), [](void *p) { ats_free(p); }); + uint8_t *p = versions.get(); + + size_t n; + for (auto v : QUIC_SUPPORTED_VERSIONS) { + QUICTypeUtil::write_QUICVersion(v, p, &n); + p += n; + } + + // TODO: Use custom allocator + return std::unique_ptr(new QUICPacket(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), + packet_sent_by_client->packet_number(), packet_sent_by_client->version(), + std::move(versions), len, false)); +} + +std::unique_ptr +QUICPacketFactory::create_server_cleartext_packet(QUICConnectionId connection_id, ats_unique_buf payload, size_t len, + bool retransmittable) +{ + // TODO: Use custom allocator + return std::unique_ptr(new QUICPacket(QUICPacketType::SERVER_CLEARTEXT, connection_id, + this->_packet_number_generator.next(), this->_version, std::move(payload), len, + retransmittable)); +} + +std::unique_ptr +QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id, ats_unique_buf payload, size_t len, + bool retransmittable) +{ + // TODO Key phase should be picked up from QUICCrypto, probably + // TODO Use class allocator + auto packet = + std::unique_ptr(new QUICPacket(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, connection_id, + this->_packet_number_generator.next(), std::move(payload), len, retransmittable)); + + // TODO: use pmtu of UnixNetVConnection + size_t max_cipher_txt_len = 2048; + ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); + size_t cipher_txt_len = 0; + + // TODO: do not dump header twice + uint8_t ad[17] = {0}; + size_t ad_len = 0; + packet->store_header(ad, &ad_len); + + if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, packet->payload(), packet->payload_size(), + packet->packet_number(), ad, ad_len, packet->key_phase())) { + packet->set_protected_payload(std::move(cipher_txt), cipher_txt_len); + Debug("quic_packet_factory", "Encrypt Packet, pkt_num: %llu, header_len: %zu payload: %zu", packet->packet_number(), ad_len, + cipher_txt_len); + return packet; + } else { + Debug("quic_packet_factory", "CRYPTOGRAPHIC Error"); + return nullptr; + } +} + +std::unique_ptr +QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, QUICVersion version, ats_unique_buf payload, + size_t len) +{ + return std::unique_ptr(new QUICPacket(QUICPacketType::CLIENT_INITIAL, connection_id, + this->_packet_number_generator.next(), version, std::move(payload), len, true)); +} + +void +QUICPacketFactory::set_version(QUICVersion negotiated_version) +{ + ink_assert(this->_version == 0); + this->_version = negotiated_version; +} + +void +QUICPacketFactory::set_crypto_module(QUICCrypto *crypto) +{ + this->_crypto = crypto; +} + +QUICPacketNumber +QUICPacketNumberGenerator::next() +{ + return this->_current++; +} diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h new file mode 100644 index 00000000000..e7192368fb5 --- /dev/null +++ b/iocore/net/quic/QUICPacket.h @@ -0,0 +1,191 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "ts/List.h" +#include "I_IOBuffer.h" + +#include "QUICTypes.h" +#include "QUICCrypto.h" + +#define QUIC_FIELD_OFFSET_CONNECTION_ID 1 +#define QUIC_FIELD_OFFSET_PACKET_NUMBER 4 +#define QUIC_FIELD_OFFSET_PAYLOAD 5 + +// TODO: move to lib/ts/ink_memory.h? +using ats_unique_buf = std::unique_ptr; +ats_unique_buf ats_unique_malloc(size_t size); + +class QUICPacketHeader +{ +public: + QUICPacketHeader(const uint8_t *buf, size_t len) : _buf(buf) {} + const uint8_t *buf(); + virtual QUICPacketType type() const = 0; + virtual QUICConnectionId connection_id() const = 0; + virtual QUICPacketNumber packet_number() const = 0; + virtual QUICVersion version() const = 0; + virtual const uint8_t *payload() const = 0; + virtual QUICKeyPhase key_phase() const = 0; + virtual uint16_t length() const = 0; + virtual void store(uint8_t *buf, size_t *len) const = 0; + static QUICPacketHeader *load(const uint8_t *buf, size_t len); + static QUICPacketHeader *build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICVersion version, ats_unique_buf payload, size_t len); + static QUICPacketHeader *build(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len); + static QUICPacketHeader *build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + ats_unique_buf payload, size_t len); + virtual bool has_key_phase() const = 0; + virtual bool has_connection_id() const = 0; + virtual bool has_version() const = 0; + +protected: + QUICPacketHeader(){}; + + const uint8_t *_buf = nullptr; + ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); + QUICPacketType _type = QUICPacketType::UNINITIALIZED; + QUICKeyPhase _key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; + QUICConnectionId _connection_id = 0; + QUICPacketNumber _packet_number = 0; + QUICVersion _version = 0; + size_t _payload_len = 0; + bool _has_key_phase = false; + bool _has_connection_id = false; + bool _has_version = false; +}; + +class QUICPacketLongHeader : public QUICPacketHeader +{ +public: + QUICPacketLongHeader(const uint8_t *buf, size_t len) : QUICPacketHeader(buf, len) {} + QUICPacketLongHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICVersion version, + ats_unique_buf buf, size_t len); + QUICPacketType type() const; + QUICConnectionId connection_id() const; + QUICPacketNumber packet_number() const; + bool has_version() const; + QUICVersion version() const; + const uint8_t *payload() const; + bool has_connection_id() const; + QUICKeyPhase key_phase() const; + bool has_key_phase() const; + uint16_t length() const; + void store(uint8_t *buf, size_t *len) const; +}; + +class QUICPacketShortHeader : public QUICPacketHeader +{ +public: + QUICPacketShortHeader(const uint8_t *buf, size_t len) : QUICPacketHeader(buf, len) {} + QUICPacketShortHeader(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf buf, size_t len); + QUICPacketShortHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf buf, + size_t len); + QUICPacketType type() const; + QUICConnectionId connection_id() const; + QUICPacketNumber packet_number() const; + bool has_version() const; + QUICVersion version() const; + const uint8_t *payload() const; + bool has_connection_id() const; + QUICKeyPhase key_phase() const; + bool has_key_phase() const; + uint16_t length() const; + void store(uint8_t *buf, size_t *len) const; + +private: + int _packet_numberLen() const; + QUICPacketShortHeaderType _packet_number_type = QUICPacketShortHeaderType::UNINITIALIZED; +}; + +class QUICPacket +{ +public: + QUICPacket(IOBufferBlock *block); + QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICVersion version, + ats_unique_buf payload, size_t len, bool retransmittable); + QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len, bool retransmittable); + QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, + size_t len, bool retransmittabl); + + void set_protected_payload(ats_unique_buf cipher_txt, size_t cipher_txt_len); + QUICPacketType type() const; + QUICConnectionId connection_id() const; + QUICPacketNumber packet_number() const; + QUICVersion version() const; + const uint8_t *header() const; + const uint8_t *payload() const; + bool is_retransmittable() const; + uint16_t size() const; + uint16_t header_size() const; + uint16_t payload_size() const; + void store(uint8_t *buf, size_t *len) const; + void store_header(uint8_t *buf, size_t *len) const; + bool has_valid_fnv1a_hash() const; + QUICKeyPhase key_phase() const; + LINK(QUICPacket, link); + +private: + IOBufferBlock *_block = nullptr; + ats_unique_buf _protected_payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); + size_t _size = 0; + size_t _protected_payload_size = 0; + QUICPacketHeader *_header; + bool _is_retransmittable = false; +}; + +class QUICPacketNumberGenerator +{ +public: + QUICPacketNumberGenerator(QUICPacketNumber initial_number = 0) : _current(initial_number){}; + QUICPacketNumber next(); + +private: + QUICPacketNumber _current = 0; +}; + +class QUICPacketFactory +{ +public: + static QUICPacket *create(IOBufferBlock *block); + std::unique_ptr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client); + std::unique_ptr create_server_cleartext_packet(QUICConnectionId connection_id, ats_unique_buf payload, size_t len, + bool retransmittable); + std::unique_ptr create_server_protected_packet(QUICConnectionId connection_id, ats_unique_buf payload, size_t len, + bool retransmittable); + std::unique_ptr create_client_initial_packet(QUICConnectionId connection_id, QUICVersion version, + ats_unique_buf payload, size_t len); + void set_version(QUICVersion negotiated_version); + void set_crypto_module(QUICCrypto *crypto); + +private: + QUICVersion _version = 0; + QUICCrypto *_crypto = nullptr; + QUICPacketNumberGenerator _packet_number_generator; +}; + +void fnv1a(const uint8_t *data, size_t len, uint8_t *hash); diff --git a/iocore/net/quic/QUICPacketTransmitter.h b/iocore/net/quic/QUICPacketTransmitter.h new file mode 100644 index 00000000000..d8b8a41cb08 --- /dev/null +++ b/iocore/net/quic/QUICPacketTransmitter.h @@ -0,0 +1,50 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICPacket.h" + +class QUICPacketTransmitter +{ +public: + /* + * Enqueue a packetfor transmission + * + * This sends QUIC_PACKET_WRITE_READY event. + */ + virtual void transmit_packet(std::unique_ptr packet) = 0; + + /* + * Enqueue a packet for retransmission + * All frames except ACK and PADDING frames in the original packet will be retransmitted on a new packet. + * This sends QUIC_PACKET_WRITE_READY event. + */ + virtual void retransmit_packet(const QUICPacket &packet) = 0; + + /* + * Returns a mutex for transmitter interfaces. + * You have to acquire a lock with this mutex before calling any methods provieded by QUICPacketTransmitter + */ + virtual Ptr get_transmitter_mutex() = 0; +}; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc new file mode 100644 index 00000000000..1e820952e51 --- /dev/null +++ b/iocore/net/quic/QUICStream.cc @@ -0,0 +1,331 @@ +/** @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 "QUICStream.h" + +#include "I_Event.h" +#include "QUICStreamManager.h" +#include "QUICDebugNames.h" + +const static char *tag = "quic_stream"; + +void +QUICStream::init(QUICStreamManager *manager, QUICStreamId id) +{ + this->_streamManager = manager; + + this->_id = id; + + this->mutex = new_ProxyMutex(); +} + +void +QUICStream::start() +{ + SET_HANDLER(&QUICStream::main_event_handler); +} + +uint32_t +QUICStream::id() +{ + return this->_id; +} + +int +QUICStream::main_event_handler(int event, void *data) +{ + Debug(tag, "%s", QUICDebugNames::vc_event(event)); + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + this->_signal_read_event(true); + this->_read_event = nullptr; + + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + this->_send(); + this->_signal_write_event(true); + this->_write_event = nullptr; + + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + ink_assert(false); + break; + } + default: + Debug(tag, "unknown event"); + ink_assert(false); + } + + return EVENT_CONT; +} + +VIO * +QUICStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + if (buf) { + this->_read_vio.buffer.writer_for(buf); + } else { + this->_read_vio.buffer.clear(); + } + + this->_read_vio.mutex = c ? c->mutex : this->mutex; + this->_read_vio._cont = c; + this->_read_vio.nbytes = nbytes; + this->_read_vio.ndone = 0; + this->_read_vio.vc_server = this; + this->_read_vio.op = VIO::READ; + + // TODO: If read function is added, call reenable here + this->_read_vio.reenable(); + + return &this->_read_vio; +} + +VIO * +QUICStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +{ + if (buf) { + this->_write_vio.buffer.reader_for(buf); + } else { + this->_write_vio.buffer.clear(); + } + + this->_write_vio.mutex = c ? c->mutex : this->mutex; + this->_write_vio._cont = c; + this->_write_vio.nbytes = nbytes; + this->_write_vio.ndone = 0; + this->_write_vio.vc_server = this; + this->_write_vio.op = VIO::WRITE; + + this->_write_vio.reenable(); + + return &this->_write_vio; +} + +void +QUICStream::do_io_close(int lerrno) +{ + this->_read_vio.buffer.clear(); + this->_read_vio.nbytes = 0; + this->_read_vio.op = VIO::NONE; + this->_read_vio._cont = nullptr; + + this->_write_vio.buffer.clear(); + this->_write_vio.nbytes = 0; + this->_write_vio.op = VIO::NONE; + this->_write_vio._cont = nullptr; +} + +void +QUICStream::do_io_shutdown(ShutdownHowTo_t howto) +{ + ink_assert(false); // unimplemented yet +} + +void +QUICStream::reenable(VIO *vio) +{ + if (vio->op == VIO::READ) { + SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); + + if (this->_read_vio.nbytes > 0) { + int event = (this->_read_vio.ntodo() == 0) ? VC_EVENT_READ_COMPLETE : VC_EVENT_READ_READY; + + if (this->_read_event == nullptr) { + this->_read_event = this_ethread()->schedule_imm_local(this, event); + } + } + } else if (vio->op == VIO::WRITE) { + SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); + + if (this->_write_vio.nbytes > 0) { + int event = (this->_write_vio.ntodo() == 0) ? VC_EVENT_WRITE_COMPLETE : VC_EVENT_WRITE_READY; + + if (this->_write_event == nullptr) { + this->_write_event = this_ethread()->schedule_imm_local(this, event); + } + } + } +} + +/** + * @brief Signal event to this->_read_vio._cont + * @param (call_update) If true, safe to call vio handler directly. + * Or called from do_io_read. Still setting things up. Send event to handle this after the dust settles + */ +void +QUICStream::_signal_read_event(bool direct) +{ + int event = (this->_read_vio.ntodo() == 0) ? VC_EVENT_READ_COMPLETE : VC_EVENT_READ_READY; + Continuation *cont = this->_read_vio._cont; + + if (direct) { + Event *e = eventAllocator.alloc(); + e->callback_event = event; + e->cookie = this; + e->init(cont, 0, 0); + + cont->handleEvent(event, e); + } else { + this_ethread()->schedule_imm(cont, event, this); + } +} + +/** + * @brief Signal event to this->_write_vio._cont + * @param (call_update) If true, safe to call vio handler directly. + * Or called from do_io_write. Still setting things up. Send event to handle this after the dust settles + */ +void +QUICStream::_signal_write_event(bool direct) +{ + int event = (this->_write_vio.ntodo() == 0) ? VC_EVENT_WRITE_COMPLETE : VC_EVENT_WRITE_READY; + Continuation *cont = this->_write_vio._cont; + + if (direct) { + Event *e = eventAllocator.alloc(); + e->callback_event = event; + e->cookie = this; + e->init(cont, 0, 0); + + cont->handleEvent(event, e); + } else { + this_ethread()->schedule_imm(cont, event, this); + } +} + +void +QUICStream::_write_to_read_vio(std::shared_ptr frame) +{ + SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); + + int bytes_added = this->_read_vio.buffer.writer()->write(frame->data(), frame->data_length()); + this->_read_vio.nbytes += bytes_added; + this->_request_buffer_offset += frame->data_length(); +} + +void +QUICStream::_reorder_data() +{ + while (auto frame = _request_stream_frame_buffer[this->_request_buffer_offset]) { + this->_request_stream_frame_buffer.erase(this->_request_buffer_offset); + this->_write_to_read_vio(frame); + } +} + +/** + * @brief Receive STREAM frame + * @detail When receive STREAM frame, reorder frames and write to buffer of read_vio. + * If the reordering or writting operation is heavy, split out them to read function, + * which is called by application via do_io_read() or reenable(). + */ +void +QUICStream::recv(std::shared_ptr frame) +{ + ink_assert(_id == frame->stream_id()); + ink_assert(this->_read_vio.op == VIO::READ); + + if (!this->_state.is_allowed_to_receive(*frame)) { + this->reset(); + return; + } + this->_state.update_with_received_frame(*frame); + + if (this->_request_buffer_offset > frame->offset()) { + // Do nothing. Just ignore STREAM frame. + return; + } else if (this->_request_buffer_offset == frame->offset()) { + this->_write_to_read_vio(frame); + this->_reorder_data(); + } else { + // NOTE: push fragments in _request_stream_frame_buffer temporally. + // They will be reordered when missing data is filled and offset is matched. + this->_request_stream_frame_buffer.insert(std::make_pair(frame->offset(), frame)); + } + + return; +} + +/** + * @brief Send STREAM DATA from _response_buffer + */ +void +QUICStream::_send() +{ + SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); + + IOBufferReader *reader = this->_write_vio.get_reader(); + int64_t bytes_avail = reader->read_avail(); + int64_t total_len = 0; + // TODO: refer maximum_quic_packet_size + // uint32_t max_size = this->client_vc->maximum_quic_packet_size() - MAX_STREAM_FRAME_HEADER_LEN(15) - MAX_PACKET_OVERHEAD(25); + uint32_t max_size = 1212; + + while (total_len < bytes_avail) { + int64_t data_len = reader->block_read_avail(); + size_t len = 0; + + if (data_len > max_size) { + len = max_size; + } else { + len = data_len; + } + + std::unique_ptr frame = QUICFrameFactory::create_stream_frame( + reinterpret_cast(reader->start()), len, this->_id, this->_response_buffer_offset); + + this->_response_buffer_offset += len; + reader->consume(len); + this->_write_vio.ndone += len; + total_len += len; + + if (!this->_state.is_allowed_to_send(*frame)) { + // FIXME: What should we do? + break; + } + this->_state.update_with_sent_frame(*frame); + this->_streamManager->send_frame(std::move(frame)); + } + + return; +} + +void +QUICStream::reset() +{ + // TODO: Create a RST_STREAM frame and pass it to Stream Manager +} + +bool +QUICStream::is_read_ready() +{ + return this->_read_vio.nbytes > 0; +} diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h new file mode 100644 index 00000000000..7cae47f9a52 --- /dev/null +++ b/iocore/net/quic/QUICStream.h @@ -0,0 +1,98 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ts/List.h" +#include "ts/PriorityQueue.h" + +#include "I_VConnection.h" + +#include "QUICFrame.h" +#include "QUICStreamState.h" + +class QUICStreamState; +class QUICStreamManager; + +/** + * @brief QUIC Stream + * TODO: This is similar to Http2Stream. Need to think some integration. + */ +class QUICStream : public VConnection +{ +public: + QUICStream() : VConnection(nullptr) {} + ~QUICStream() {} + + void init(QUICStreamManager *manager, uint32_t id); + void start(); + int main_event_handler(int event, void *data); + + uint32_t id(); + + // Implement VConnection interface. + VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) override; + VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; + void do_io_close(int lerrno = -1) override; + void do_io_shutdown(ShutdownHowTo_t howto) override; + void reenable(VIO *vio) override; + + void recv(std::shared_ptr frame); + void reset(); + + bool is_read_ready(); + + LINK(QUICStream, link); + +private: + QUICStreamState _state; + + void _send(); + + void _write_to_read_vio(std::shared_ptr); + void _reorder_data(); + // NOTE: Those are called update_read_request/update_write_request in Http2Stream + // void _read_from_net(uint64_t read_len, bool direct); + // void _write_to_net(IOBufferReader *buf_reader, int64_t write_len, bool direct); + + void _signal_read_event(bool call_update); + void _signal_write_event(bool call_update); + + Event *_send_tracked_event(Event *event, int send_event, VIO *vio); + + QUICStreamId _id = 0; + QUICOffset _request_buffer_offset = 0; + QUICOffset _response_buffer_offset = 0; + + VIO _read_vio; + VIO _write_vio; + + Event *_read_event; + Event *_write_event; + + // Fragments of received STREAM frame (offset is unmatched) + // TODO: Consider to replace with ts/RbTree.h or other data structure + std::map> _request_stream_frame_buffer; + + QUICStreamManager *_streamManager; +}; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc new file mode 100644 index 00000000000..c5bb46efbf9 --- /dev/null +++ b/iocore/net/quic/QUICStreamManager.cc @@ -0,0 +1,114 @@ +/** @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 + +#include +#include + +const static char *tag = "quic_stream_manager"; + +ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); +ClassAllocator quicStreamAllocator("quicStreamAllocator"); + +int +QUICStreamManager::init(QUICFrameTransmitter *tx) +{ + this->_tx = tx; + return 0; +} + +void +QUICStreamManager::set_connection(QUICNetVConnection *vc) +{ + this->_vc = vc; +} + +void +QUICStreamManager::handle_frame(std::shared_ptr frame) +{ + switch (frame->type()) { + case QUICFrameType::STREAM: + this->_handle_stream_frame(std::dynamic_pointer_cast(frame)); + break; + default: + Debug(tag, "Unexpected frame type: %02x", frame->type()); + ink_assert(false); + break; + } +} + +void +QUICStreamManager::_handle_stream_frame(std::shared_ptr frame) +{ + QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); + QUICApplication *application = this->_vc->get_application(frame->stream_id()); + + if (!application->is_stream_set(stream)) { + application->set_stream(stream); + } + + stream->recv(frame); + // FIXME: schedule VC_EVENT_READ_READY to application every single frame? + // If application reading buffer continuously, do not schedule event. + this_ethread()->schedule_imm(application, VC_EVENT_READ_READY, stream); + + return; +} + +/** + * @brief Send stream frame + */ +void +QUICStreamManager::send_frame(std::unique_ptr frame) +{ + this->_tx->transmit_frame(std::move(frame)); + + return; +} + +QUICStream * +QUICStreamManager::_find_stream(QUICStreamId id) +{ + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + if (s->id() == id) { + return s; + } + } + return nullptr; +} + +QUICStream * +QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) +{ + QUICStream *stream = this->_find_stream(stream_id); + if (!stream) { + // TODO Free the stream somewhere + stream = THREAD_ALLOC_INIT(quicStreamAllocator, this_ethread()); + stream->init(this, stream_id); + stream->start(); + + this->stream_list.push(stream); + } + return stream; +} diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h new file mode 100644 index 00000000000..3daff59aa57 --- /dev/null +++ b/iocore/net/quic/QUICStreamManager.h @@ -0,0 +1,55 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICTypes.h" +#include "QUICStream.h" +#include "QUICFrameHandler.h" +#include "QUICFrame.h" +#include "QUICFrameTransmitter.h" + +class QUICNetVConnection; + +class QUICStreamManager : public QUICFrameHandler +{ +public: + QUICStreamManager(){}; + + int init(QUICFrameTransmitter *tx); + void set_connection(QUICNetVConnection *vc); // FIXME Want to remove. + virtual void handle_frame(std::shared_ptr) override; + void send_frame(std::unique_ptr frame); + + DLL stream_list; + +private: + QUICStream *_find_or_create_stream(QUICStreamId stream_id); + QUICStream *_find_stream(QUICStreamId id); + + QUICNetVConnection *_vc = nullptr; + QUICFrameTransmitter *_tx = nullptr; + +private: + void _handle_stream_frame(std::shared_ptr); +}; diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc new file mode 100644 index 00000000000..dfe9f4dd13b --- /dev/null +++ b/iocore/net/quic/QUICStreamState.cc @@ -0,0 +1,58 @@ +#include "QUICStreamState.h" +#include "ts/ink_assert.h" + +const QUICStreamState::State +QUICStreamState::get() const +{ + return this->_state; +} + +bool +QUICStreamState::is_allowed_to_send(const QUICFrame &frame) const +{ + return true; +} + +bool +QUICStreamState::is_allowed_to_receive(const QUICFrame &frame) const +{ + return true; +} + +void +QUICStreamState::update_with_received_frame(const QUICFrame &frame) +{ + switch (this->_state) { + case State::idle: + this->_set_state(State::open); + // fall through + case State::open: { + if (frame.type() == QUICFrameType::STREAM && dynamic_cast(frame).has_fin_flag()) { + this->_set_state(State::half_closed_remote); + } else if (frame.type() == QUICFrameType::RST_STREAM) { + this->_set_state(State::closed); + } + } break; + case State::half_closed_local: + case State::half_closed_remote: + case State::closed: + case State::illegal: + // Once we get illegal state, no way to recover it + break; + default: + break; + } +} + +void +QUICStreamState::update_with_sent_frame(const QUICFrame &frame) +{ +} + +void +QUICStreamState::_set_state(State s) +{ + ink_assert(s != State::idle); + ink_assert(s != State::illegal); + this->_state = s; +} diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h new file mode 100644 index 00000000000..047930847b0 --- /dev/null +++ b/iocore/net/quic/QUICStreamState.h @@ -0,0 +1,54 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICFrame.h" + +class QUICStreamState +{ +public: + // 10.1. Life of a Stream + enum class State { + idle, + open, + half_closed_remote, + half_closed_local, + closed, + illegal // not on the specification, just for internal use + }; + const State get() const; + bool is_allowed_to_send(const QUICFrame &frame) const; + bool is_allowed_to_receive(const QUICFrame &frame) const; + + /* + * Updates its internal state + * Internal state will be "illegal" state if inappropriate frame was passed + */ + void update_with_received_frame(const QUICFrame &frame); + void update_with_sent_frame(const QUICFrame &frame); + +private: + void _set_state(State s); + State _state = State::idle; +}; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc new file mode 100644 index 00000000000..4b483a22b40 --- /dev/null +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -0,0 +1,132 @@ +#include +#include "QUICTransportParameters.h" + +QUICTransportParameterValue +QUICTransportParameters::get(QUICTransportParameterId tpid) const +{ + QUICTransportParameterValue value; + const uint8_t *p = this->_buf + this->_parameters_offset(); + + uint16_t n = (p[0] << 8) + p[1]; + p += 2; + for (; n > 0; --n) { + uint16_t _id = (p[0] << 8) + p[1]; + p += 2; + uint16_t _value_len = (p[0] << 8) + p[1]; + p += 2; + if (tpid == _id) { + value.data = p; + value.len = _value_len; + return value; + } + p += _value_len; + } + value.data = nullptr; + value.len = 0; + return value; +} + +void +QUICTransportParameters::add(QUICTransportParameterId id, QUICTransportParameterValue value) +{ + _parameters.put(id, value); +} + +void +QUICTransportParameters::store(uint8_t *buf, uint16_t *len) const +{ + uint8_t *p = buf; + + // Why Map::get() doesn't have const?? + QUICTransportParameters *me = const_cast(this); + + // Write QUIC versions + this->_store(p, len); + p += *len; + + // Write parameters + Vec keys; + me->_parameters.get_keys(keys); + unsigned int n = keys.length(); + p[0] = (n & 0xff00) >> 8; + p[1] = n & 0xff; + p += 2; + for (unsigned int i = 0; i < n; ++i) { + QUICTransportParameterValue value; + p[0] = (keys[i] & 0xff00) >> 8; + p[1] = keys[i] & 0xff; + p += 2; + value = me->_parameters.get(keys[i]); + p[0] = (value.len & 0xff00) >> 8; + p[1] = value.len & 0xff; + p += 2; + memcpy(p, value.data, value.len); + p += value.len; + } + *len = (p - buf); +} + +void +QUICTransportParametersInClientHello::_store(uint8_t *buf, uint16_t *len) const +{ + size_t l; + *len = 0; + QUICTypeUtil::write_QUICVersion(this->_negotiated_version, buf, &l); + buf += l; + *len += l; + QUICTypeUtil::write_QUICVersion(this->_initial_version, buf, &l); + *len += l; +} + +std::ptrdiff_t +QUICTransportParametersInClientHello::_parameters_offset() const +{ + return 8; // sizeof(QUICVersion) + sizeof(QUICVersion) +} + +QUICVersion +QUICTransportParametersInClientHello::negotiated_version() const +{ + return QUICTypeUtil::read_QUICVersion(this->_buf); +} + +QUICVersion +QUICTransportParametersInClientHello::initial_version() const +{ + return QUICTypeUtil::read_QUICVersion(this->_buf + sizeof(QUICVersion)); +} + +void +QUICTransportParametersInEncryptedExtensions::_store(uint8_t *buf, uint16_t *len) const +{ + uint8_t *p = buf; + size_t l; + + p[0] = (this->_n_versions & 0xff00) >> 8; + p[1] = this->_n_versions & 0xff; + p += 2; + for (int i = 0; i < this->_n_versions; ++i) { + QUICTypeUtil::write_QUICVersion(this->_versions[i], p, &l); + p += l; + } + *len = p - buf; +} + +const uint8_t * +QUICTransportParametersInEncryptedExtensions::supported_versions(uint16_t *n) const +{ + *n = (this->_buf[0] << 8) + this->_buf[1]; + return this->_buf + 2; +} + +void +QUICTransportParametersInEncryptedExtensions::add_version(QUICVersion version) +{ + this->_versions[this->_n_versions++] = version; +} + +std::ptrdiff_t +QUICTransportParametersInEncryptedExtensions::_parameters_offset() const +{ + return 2 + 4 * ((this->_buf[0] << 8) + this->_buf[1]); +} diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h new file mode 100644 index 00000000000..244b33e2ec4 --- /dev/null +++ b/iocore/net/quic/QUICTransportParameters.h @@ -0,0 +1,120 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICTypes.h" +#include "ts/Map.h" +#include + +class QUICTransportParameterId +{ +public: + enum { + INITIAL_MAX_STREAM_DATA = 0, + INITIAL_MAX_DATA, + INITIAL_MAX_STREAM_ID, + IDLE_TIMEOUT, + TRUNCATE_CONNECTION_ID, + MAX_PACKET_SIZE, + }; + + explicit operator bool() const { return true; } + + bool + operator==(const QUICTransportParameterId &x) const + { + return this->_id == x._id; + } + + bool + operator==(uint16_t &x) const + { + return this->_id == x; + } + + operator uint16_t() const { return _id; }; + + QUICTransportParameterId() : _id(0){}; + QUICTransportParameterId(uint16_t id) : _id(id){}; + +private: + uint16_t _id = 0; +}; + +typedef struct _QUICTransportParameterValue { + _QUICTransportParameterValue(){}; + _QUICTransportParameterValue(const uint8_t *str) : data(str), len(str ? strlen(reinterpret_cast(str)) : 0){}; + _QUICTransportParameterValue(const uint8_t *_data, uint16_t _len) : data(_data), len(_len){}; + const uint8_t *data = nullptr; + uint16_t len = 0; +} QUICTransportParameterValue; + +class QUICTransportParameters +{ +public: + QUICTransportParameters(const uint8_t *buf) : _buf(buf){}; + QUICTransportParameterValue get(QUICTransportParameterId id) const; + void add(QUICTransportParameterId id, QUICTransportParameterValue value); + void store(uint8_t *buf, uint16_t *len) const; + +protected: + virtual std::ptrdiff_t _parameters_offset() const = 0; + virtual void _store(uint8_t *buf, uint16_t *len) const = 0; + const uint8_t *_buf; + Map _parameters; +}; + +class QUICTransportParametersInClientHello : public QUICTransportParameters +{ +public: + QUICTransportParametersInClientHello(QUICVersion negotiated_version, QUICVersion initial_version) + : QUICTransportParameters(nullptr), _negotiated_version(negotiated_version), _initial_version(initial_version){}; + QUICTransportParametersInClientHello(const uint8_t *buf) : QUICTransportParameters(buf){}; + QUICVersion negotiated_version() const; + QUICVersion initial_version() const; + +protected: + std::ptrdiff_t _parameters_offset() const override; + void _store(uint8_t *buf, uint16_t *len) const override; + +private: + QUICVersion _negotiated_version = 0; + QUICVersion _initial_version = 0; +}; + +class QUICTransportParametersInEncryptedExtensions : public QUICTransportParameters +{ +public: + QUICTransportParametersInEncryptedExtensions() : QUICTransportParameters(nullptr){}; + QUICTransportParametersInEncryptedExtensions(const uint8_t *buf) : QUICTransportParameters(buf){}; + const uint8_t *supported_versions(uint16_t *n) const; + void add_version(QUICVersion version); + +protected: + std::ptrdiff_t _parameters_offset() const override; + void _store(uint8_t *buf, uint16_t *len) const override; + + uint8_t _n_versions = 0; + QUICVersion _versions[256] = {}; +}; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc new file mode 100644 index 00000000000..0be3d0008b6 --- /dev/null +++ b/iocore/net/quic/QUICTypes.cc @@ -0,0 +1,140 @@ +/** @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 "QUICTypes.h" + +// TODO: Update version number +// Note: You need to update QUICTypes.h if you change the number of versions +const QUICVersion QUIC_SUPPORTED_VERSIONS[] = { + 0xff000004, // Prefix for drafts (0xff000000) + draft number +}; + +const QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; + +bool +QUICTypeUtil::hasLongHeader(const uint8_t *buf) +{ + return (buf[0] & 0x80) != 0; +} + +QUICConnectionId +QUICTypeUtil::read_QUICConnectionId(const uint8_t *buf, uint8_t len) +{ + return static_cast(read_nbytes_as_uint(buf, len)); +} + +QUICPacketNumber +QUICTypeUtil::read_QUICPacketNumber(const uint8_t *buf, uint8_t len) +{ + return static_cast(read_nbytes_as_uint(buf, len)); +} + +QUICVersion +QUICTypeUtil::read_QUICVersion(const uint8_t *buf) +{ + return static_cast(read_nbytes_as_uint(buf, 4)); +} + +QUICStreamId +QUICTypeUtil::read_QUICStreamId(const uint8_t *buf, uint8_t len) +{ + return static_cast(read_nbytes_as_uint(buf, len)); +} + +QUICOffset +QUICTypeUtil::read_QUICOffset(const uint8_t *buf, uint8_t len) +{ + return static_cast(read_nbytes_as_uint(buf, len)); +} + +QUICErrorCode +QUICTypeUtil::read_QUICErrorCode(const uint8_t *buf) +{ + return static_cast(read_nbytes_as_uint(buf, 4)); +} + +uint64_t +QUICTypeUtil::read_nbytes_as_uint(const uint8_t *buf, uint8_t n) +{ + uint64_t value = 0; + memcpy(&value, buf, n); + return be64toh(value << (64 - n * 8)); +} + +void +QUICTypeUtil::write_QUICConnectionId(QUICConnectionId connection_id, uint8_t n, uint8_t *buf, size_t *len) +{ + write_uint_as_nbytes(static_cast(connection_id), n, buf, len); +} + +void +QUICTypeUtil::write_QUICPacketNumber(QUICPacketNumber packet_number, uint8_t n, uint8_t *buf, size_t *len) +{ + write_uint_as_nbytes(static_cast(packet_number), n, buf, len); +} + +void +QUICTypeUtil::write_QUICVersion(QUICVersion version, uint8_t *buf, size_t *len) +{ + write_uint_as_nbytes(static_cast(version), 4, buf, len); +} + +void +QUICTypeUtil::write_QUICStreamId(QUICStreamId stream_id, uint8_t n, uint8_t *buf, size_t *len) +{ + write_uint_as_nbytes(static_cast(stream_id), n, buf, len); +} + +void +QUICTypeUtil::write_QUICOffset(QUICOffset offset, uint8_t n, uint8_t *buf, size_t *len) +{ + write_uint_as_nbytes(static_cast(offset), n, buf, len); +} + +void +QUICTypeUtil::write_QUICErrorCode(QUICErrorCode error_code, uint8_t *buf, size_t *len) +{ + write_uint_as_nbytes(static_cast(error_code), 4, buf, len); +} + +void +QUICTypeUtil::write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size_t *len) +{ + value = htobe64(value) >> (64 - n * 8); + memcpy(buf, reinterpret_cast(&value), n); + *len = n; +} + +void +fnv1a(const uint8_t *data, size_t len, uint8_t *hash) +{ + uint64_t h = 0xcbf29ce484222325ULL; + uint64_t prime = 0x100000001b3ULL; + size_t n; + + for (size_t i = 0; i < len; ++i) { + h ^= data[i]; + h *= prime; + } + return QUICTypeUtil::write_uint_as_nbytes(h, 8, hash, &n); +} diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h new file mode 100644 index 00000000000..d1f613bc196 --- /dev/null +++ b/iocore/net/quic/QUICTypes.h @@ -0,0 +1,179 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifdef __APPLE__ +#include +#define be64toh(x) OSSwapBigToHostInt64(x) +#define htobe64(x) OSSwapHostToBigInt64(x) +#else +#include +#endif +#include + +#include +#include + +// These magical defines should be removed when we implement seriously +#define MAGIC_NUMBER_0 0 +#define MAGIC_NUMBER_1 1 +#define MAGIC_NUMBER_TRUE true + +typedef uint64_t QUICPacketNumber; +typedef uint32_t QUICVersion; +typedef uint32_t QUICStreamId; +typedef uint64_t QUICOffset; + +extern const QUICVersion QUIC_SUPPORTED_VERSIONS[1]; +extern const QUICStreamId STREAM_ID_FOR_HANDSHAKE; + +enum class QUICPacketType : int { + VERSION_NEGOTIATION = 1, + CLIENT_INITIAL, + SERVER_STATELESS_RETRY, + SERVER_CLEARTEXT, + CLIENT_CLEARTEXT, + ZERO_RTT_PROTECTED, + ONE_RTT_PROTECTED_KEY_PHASE_0, + ONE_RTT_PROTECTED_KEY_PHASE_1, + PUBLIC_RESET, + UNINITIALIZED, +}; + +// To detect length of Packet Number +enum class QUICPacketShortHeaderType : int { + ONE = 1, + TWO, + THREE, + UNINITIALIZED, +}; + +enum class QUICFrameType : int { + PADDING = 0x00, + RST_STREAM, + CONNECTION_CLOSE, + GOAWAY, + MAX_DATA, + MAX_STREAM_DATA, + MAX_STREAM_ID, + PING, + BLOCKED, + STREAM_BLOCKED, + STREAM_ID_NEEDED, + NEW_CONNECTION_ID, + ACK = 0xA0, + STREAM = 0xC0, + UNKNOWN = 0x100, +}; + +enum class QUICVersionNegotiationStatus { + NOT_NEGOTIATED, // Haven't negotiated yet + NEGOTIATED, // Negotiated + REVALIDATED, // Revalidated in cryptographic handshake + FAILED, // Negotiation failed +}; + +enum class QUICKeyPhase : int { + PHASE_0 = 0, + PHASE_1, + PHASE_UNINITIALIZED, +}; + +enum class QUICErrorClass { + NONE, + AQPPLICATION_SPECIFIC, + HOST_LOCAL, + QUIC_TRANSPORT, + CRYPTOGRAPHIC, +}; + +enum class QUICErrorCode : uint32_t { + APPLICATION_SPECIFIC_ERROR = 0, + HOST_LOCAL_ERROR = 0x40000000, + QUIC_TRANSPORT_ERROR = 0x80000000, + QUIC_INTERNAL_ERROR = 0x80000001, + CRYPTOGRAPHIC_ERROR = 0xC0000000, + TLS_HANDSHAKE_FAILED = 0xC000001C, + // TODO Add error codes +}; + +struct QUICError { + QUICError(const QUICErrorClass error_class = QUICErrorClass::NONE, + const QUICErrorCode error_code = QUICErrorCode::APPLICATION_SPECIFIC_ERROR, const char *err_msg = nullptr) + { + cls = error_class; + code = error_code; + msg = err_msg; + }; + + QUICErrorClass cls; + QUICErrorCode code; + const char *msg; +}; + +class QUICConnectionId +{ +public: + explicit operator bool() const { return true; } + + operator uint64_t() const { return _id; }; + + QUICConnectionId() { this->randomize(); }; + QUICConnectionId(uint64_t id) : _id(id){}; + + void + randomize() + { + std::random_device rnd; + this->_id = (static_cast(rnd()) << 32) + rnd(); + }; + +private: + uint64_t _id; +}; + +class QUICTypeUtil +{ +public: + static bool hasLongHeader(const uint8_t *buf); + + static QUICConnectionId read_QUICConnectionId(const uint8_t *buf, uint8_t n); + static QUICPacketNumber read_QUICPacketNumber(const uint8_t *buf, uint8_t n); + static QUICVersion read_QUICVersion(const uint8_t *buf); + static QUICStreamId read_QUICStreamId(const uint8_t *buf, uint8_t n); + static QUICOffset read_QUICOffset(const uint8_t *buf, uint8_t n); + static QUICErrorCode read_QUICErrorCode(const uint8_t *buf); + + static void write_QUICConnectionId(QUICConnectionId connection_id, uint8_t n, uint8_t *buf, size_t *len); + static void write_QUICPacketNumber(QUICPacketNumber packet_number, uint8_t n, uint8_t *buf, size_t *len); + static void write_QUICVersion(QUICVersion version, uint8_t *buf, size_t *len); + static void write_QUICStreamId(QUICStreamId stream_id, uint8_t n, uint8_t *buf, size_t *len); + static void write_QUICOffset(QUICOffset offset, uint8_t n, uint8_t *buf, size_t *len); + static void write_QUICErrorCode(QUICErrorCode error_code, 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: +}; diff --git a/iocore/net/quic/QUICVersionNegotiator.cc b/iocore/net/quic/QUICVersionNegotiator.cc new file mode 100644 index 00000000000..6e6856334c7 --- /dev/null +++ b/iocore/net/quic/QUICVersionNegotiator.cc @@ -0,0 +1,63 @@ +/** @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 "QUICVersionNegotiator.h" + +QUICVersionNegotiator::QUICVersionNegotiator(QUICPacketFactory *packet_factory, QUICPacketTransmitter *tx) + : _packet_factory(packet_factory), _tx(tx){}; + +QUICVersionNegotiationStatus +QUICVersionNegotiator::status() +{ + return this->_status; +} + +QUICVersionNegotiationStatus +QUICVersionNegotiator::negotiate(const QUICPacket *initial_packet) +{ + if (this->_is_supported(initial_packet->version())) { + this->_status = QUICVersionNegotiationStatus::NEGOTIATED; + } else { + this->_tx->transmit_packet(this->_packet_factory->create_version_negotiation_packet(initial_packet)); + } + return this->_status; +} + +QUICVersionNegotiationStatus +QUICVersionNegotiator::revalidate(QUICVersion version) +{ + // TDOO revalidate the version + this->_status = QUICVersionNegotiationStatus::FAILED; + return _status; +} + +bool +QUICVersionNegotiator::_is_supported(QUICVersion version) +{ + for (auto v : QUIC_SUPPORTED_VERSIONS) { + if (v == version) { + return true; + } + } + return false; +} diff --git a/iocore/net/quic/QUICVersionNegotiator.h b/iocore/net/quic/QUICVersionNegotiator.h new file mode 100644 index 00000000000..8410d755b2d --- /dev/null +++ b/iocore/net/quic/QUICVersionNegotiator.h @@ -0,0 +1,47 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICTypes.h" +#include "QUICPacketTransmitter.h" + +/** + * @brief Abstruct QUIC Application Class + * @detail Every quic application must inherits this class + */ +class QUICVersionNegotiator +{ +public: + QUICVersionNegotiator(QUICPacketFactory *packet_factory, QUICPacketTransmitter *tx); + QUICVersionNegotiationStatus status(); + QUICVersionNegotiationStatus negotiate(const QUICPacket *initial_packet); + QUICVersionNegotiationStatus revalidate(QUICVersion version); + +private: + QUICPacketFactory *_packet_factory = nullptr; + QUICPacketTransmitter *_tx = nullptr; + QUICVersionNegotiationStatus _status = QUICVersionNegotiationStatus::NOT_NEGOTIATED; + + bool _is_supported(QUICVersion version); +}; diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am new file mode 100644 index 00000000000..1216cda8d55 --- /dev/null +++ b/iocore/net/quic/test/Makefile.am @@ -0,0 +1,368 @@ +# Makefile.am for the traffic/iocore/net hierarchy +# +# 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. + +TESTS = $(check_PROGRAMS) +check_PROGRAMS = \ + test_QUICPacket \ + test_QUICPacketFactory \ + test_QUICFrame \ + test_QUICFrameDispatcher \ + test_QUICStreamState \ + test_QUICStream \ + test_QUICTransportParameters \ + test_QUICCrypto \ + test_QUICLossDetector \ + test_QUICTypeUtil \ + test_QUICAckFrameCreator \ + test_QUICVersionNegotiator + + +AM_CPPFLAGS += \ + $(iocore_include_dirs) \ + -I$(abs_top_srcdir)/lib \ + -I$(abs_top_srcdir)/lib/records \ + -I$(abs_top_srcdir)/mgmt \ + -I$(abs_top_srcdir)/mgmt/utils \ + -I$(abs_top_srcdir)/proxy \ + -I$(abs_top_srcdir)/proxy/hdrs \ + -I$(abs_top_srcdir)/proxy/http \ + -I$(abs_top_srcdir)/proxy/logging \ + -I$(abs_top_srcdir)/proxy/shared \ + -I$(abs_top_srcdir)/tests/include \ + @OPENSSL_INCLUDES@ + +if OPENSSL_IS_BORINGSSL +QUICCrypto_impl = ../QUICCrypto_boringssl.cc +else +QUICCrypto_impl = ../QUICCrypto_openssl.cc +endif + +# +# test_QUICPacket +# +test_QUICPacket_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICPacket_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICPacket_SOURCES = \ + event_processor_main.cc \ + test_QUICPacket.cc \ + ../QUICPacket.cc \ + ../QUICCrypto.cc \ + $(QUICCrypto_impl) \ + ../QUICTypes.cc + +test_QUICPacket_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ + +# +# test_QUICPacketFactory +# +test_QUICPacketFactory_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICPacketFactory_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICPacketFactory_SOURCES = \ + event_processor_main.cc \ + test_QUICPacketFactory.cc \ + ../QUICPacket.cc \ + ../QUICCrypto.cc \ + $(QUICCrypto_impl) \ + ../QUICTypes.cc + +test_QUICPacketFactory_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ + +# +# test_QUICFrame +# +test_QUICFrame_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICFrame_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICFrame_SOURCES = \ + main.cc \ + test_QUICFrame.cc \ + ../QUICFrame.cc \ + ../QUICPacket.cc \ + ../QUICCrypto.cc \ + $(QUICCrypto_impl) \ + ../QUICTypes.cc + +test_QUICFrame_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a + +# +# test_QUICFrameDispatcher +# +test_QUICFrameDispatcher_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICFrameDispatcher_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICFrameDispatcher_SOURCES = \ + main.cc \ + test_QUICFrameDispatcher.cc \ + ../QUICFrameDispatcher.cc \ + ../QUICConnectionManager.cc \ + ../QUICStreamManager.cc \ + ../QUICFlowController.cc \ + ../QUICCongestionController.cc \ + ../QUICLossDetector.cc \ + ../QUICFrame.cc \ + ../QUICPacket.cc \ + ../QUICStream.cc \ + ../QUICStreamState.cc \ + ../QUICApplication.cc \ + ../QUICHandshake.cc \ + ../QUICTypes.cc \ + ../QUICEchoApp.cc \ + ../QUICDebugNames.cc \ + ../QUICCrypto.cc \ + $(QUICCrypto_impl) + +test_QUICFrameDispatcher_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ + + +# +# test_QUICStreamState +# +test_QUICStreamState_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICStreamState_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICStreamState_SOURCES = \ + main.cc \ + test_QUICStreamState.cc \ + ../QUICStreamState.cc + +test_QUICStreamState_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ + +# +# test_QUICStream +# +test_QUICStream_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICStream_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICStream_SOURCES = \ + event_processor_main.cc \ + test_QUICStream.cc \ + ../QUICStream.cc \ + ../QUICFrameDispatcher.cc \ + ../QUICConnectionManager.cc \ + ../QUICStreamManager.cc \ + ../QUICFlowController.cc \ + ../QUICCongestionController.cc + +test_QUICStream_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ + +# +# test_QUICTransportParameters +# +test_QUICTransportParameters_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICTransportParameters_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICTransportParameters_SOURCES = \ + main.cc \ + test_QUICTransportParameters.cc \ + ../QUICTransportParameters.cc \ + ../QUICTypes.cc + +test_QUICTransportParameters_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a + +# +# test_QUICCrypto +# +test_QUICCrypto_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICCrypto_LDFLAGS = \ + @AM_LDFLAGS@ \ + @OPENSSL_LDFLAGS@ + +test_QUICCrypto_LDADD = \ + @OPENSSL_LIBS@ \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a + +test_QUICCrypto_SOURCES = \ + main.cc \ + test_QUICCrypto.cc \ + ../QUICCrypto.cc \ + $(QUICCrypto_impl) \ + ../QUICCrypto.h + +# +# test_QUICLossDetector +# +test_QUICLossDetector_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICLossDetector_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICLossDetector_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ + +test_QUICLossDetector_SOURCES = \ + event_processor_main.cc \ + test_QUICLossDetector.cc \ + ../QUICLossDetector.cc \ + ../QUICTypes.cc \ + ../QUICPacket.cc \ + ../QUICCrypto.cc \ + $(QUICCrypto_impl) \ + ../QUICFrame.cc + +# +# test_QUICTypeUtil +# +test_QUICTypeUtil_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICTypeUtil_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICTypeUtil_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la + +test_QUICTypeUtil_SOURCES = \ + main.cc \ + test_QUICTypeUtil.cc \ + ../QUICTypes.cc + +# +# test_QUICAckFrameCreator +# +test_QUICAckFrameCreator_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICAckFrameCreator_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICAckFrameCreator_LDADD = \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/ts/libtsutil.la + +test_QUICAckFrameCreator_SOURCES = \ + main.cc \ + test_QUICAckFrameCreator.cc \ + ../QUICAckFrameCreator.cc \ + ../QUICTypes.cc \ + ../QUICFrame.cc \ + ../QUICPacket.cc \ + ../QUICCrypto.cc \ + $(QUICCrypto_impl) + +# +# test_QUICTypeUtil +# +test_QUICVersionNegotiator_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICVersionNegotiator_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICVersionNegotiator_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ + +test_QUICVersionNegotiator_SOURCES = \ + main.cc \ + test_QUICVersionNegotiator.cc \ + ../QUICTypes.cc \ + ../QUICPacket.cc \ + ../QUICCrypto.cc \ + $(QUICCrypto_impl) \ + ../QUICVersionNegotiator.cc + +include $(top_srcdir)/build/tidy.mk + +tidy-local: $(DIST_SOURCES) + $(CXX_Clang_Tidy) diff --git a/iocore/net/quic/test/event_processor_main.cc b/iocore/net/quic/test/event_processor_main.cc new file mode 100644 index 00000000000..fbfead65285 --- /dev/null +++ b/iocore/net/quic/test/event_processor_main.cc @@ -0,0 +1,53 @@ +/** @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. + */ + +// To make compile faster +// https://github.com/philsquared/Catch/blob/master/docs/slow-compiles.md +#define CATCH_CONFIG_MAIN +#include "catch.hpp" + +#include "I_EventSystem.h" +#include "ts/ink_string.h" +#include "ts/I_Layout.h" +#include "diags.i" + +#define TEST_THREADS 1 + +struct EventProcessorListener : Catch::TestEventListenerBase { + using TestEventListenerBase::TestEventListenerBase; // inherit constructor + + virtual void + testRunStarting(Catch::TestRunInfo const &testRunInfo) override + { + Layout::create(); + init_diags("", nullptr); + RecProcessInit(RECM_STAND_ALONE); + + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + eventProcessor.start(TEST_THREADS); + + Thread *main_thread = new EThread; + main_thread->set_specific(); + } +}; +CATCH_REGISTER_LISTENER(EventProcessorListener); diff --git a/iocore/net/quic/test/main.cc b/iocore/net/quic/test/main.cc new file mode 100644 index 00000000000..213dec81c72 --- /dev/null +++ b/iocore/net/quic/test/main.cc @@ -0,0 +1,27 @@ +/** @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. + */ + +// To make compile faster +// https://github.com/philsquared/Catch/blob/master/docs/slow-compiles.md +#define CATCH_CONFIG_MAIN +#include "catch.hpp" diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc new file mode 100644 index 00000000000..a5196879c9c --- /dev/null +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -0,0 +1,69 @@ +/** @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 "catch.hpp" + +#include "quic/QUICAckFrameCreator.h" + +TEST_CASE("QUICAckFrameCreator", "[quic]") +{ + QUICAckFrameCreator creator; + std::unique_ptr frame = {nullptr, nullptr}; + + // Initial state + frame = creator.create(); + CHECK(frame == nullptr); + + // One packet + creator.update(1, true); + frame = creator.create(); + CHECK(frame != nullptr); + CHECK(frame->num_blocks() == 0); + CHECK(frame->largest_acknowledged() == 1); + CHECK(frame->ack_block_section()->first_ack_block_length() == 1); + + frame = creator.create(); + CHECK(frame == nullptr); + + // Not sequential + creator.update(2, true); + creator.update(5, true); + creator.update(3, true); + creator.update(4, true); + frame = creator.create(); + CHECK(frame != nullptr); + CHECK(frame->num_blocks() == 0); + CHECK(frame->largest_acknowledged() == 5); + CHECK(frame->ack_block_section()->first_ack_block_length() == 4); + + // Loss + creator.update(6, true); + creator.update(7, true); + creator.update(10, true); + frame = creator.create(); + CHECK(frame != nullptr); + CHECK(frame->num_blocks() == 1); + CHECK(frame->largest_acknowledged() == 10); + CHECK(frame->ack_block_section()->first_ack_block_length() == 2); + CHECK(frame->ack_block_section()->begin()->gap() == 2); +} diff --git a/iocore/net/quic/test/test_QUICCrypto.cc b/iocore/net/quic/test/test_QUICCrypto.cc new file mode 100644 index 00000000000..f3c13c230d3 --- /dev/null +++ b/iocore/net/quic/test/test_QUICCrypto.cc @@ -0,0 +1,189 @@ +/** @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 "catch.hpp" + +#include +#include +#include + +#ifdef OPENSSL_IS_BORINGSSL +#include +#endif + +#include + +#include "QUICCrypto.h" + +const static uint32_t MAX_HANDSHAKE_MSG_LEN = 2048; + +static const char server_crt[] = "-----BEGIN CERTIFICATE-----\n" + "MIIDRjCCAi4CCQDoLSBwQxmcJTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJK\n" + "UDEOMAwGA1UECBMFVG9reW8xDzANBgNVBAcTBk1pbmF0bzEhMB8GA1UEChMYSW50\n" + "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTcw\n" + "MTE4MDEyMzA3WhcNMjcwMTE2MDEyMzA3WjBlMQswCQYDVQQGEwJKUDEOMAwGA1UE\n" + "CBMFVG9reW8xDzANBgNVBAcTBk1pbmF0bzEhMB8GA1UEChMYSW50ZXJuZXQgV2lk\n" + "Z2l0cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB\n" + "AQUAA4IBDwAwggEKAoIBAQC70j62KOWkuqNsDhl+7uqKFS6TMcJYLdYrH1YInwlY\n" + "htOMSMWx2hPSYYBKzVQpLvhe2LPbhLwcVJdq4aqQNjNpxrpxW/YIY5zxCRVgQsgf\n" + "KXiKgUR0G+F3MQHsm1YIqxQU2OeJldIZUBM2YMDp8h1CXTAvGaAZaXsqO9UvR2Zw\n" + "JZJ+GElYNlNwhdStqIM8v1JNFjfO3gWkVqTv+QM4fmpror2pp8CaDrueg4PrSY3Y\n" + "D/WG75rkmlrW26t0Q8fjkn+s/UiQ3V/IkP1+MfrJWH6RL2DGjBv2KfNAik42xWUi\n" + "KXzaNcDFN4hjqVG59O9bPnUDn1wPypY/TXB4iqSAlxupAgMBAAEwDQYJKoZIhvcN\n" + "AQELBQADggEBAKLc+P5YfusNYIkX3YE+gHBVpo95xnoVUcsGr/h1zanCkmsyKkNU\n" + "e2w9xsVnRLgpRfwrnwiaNP/k6cPYt5ePPCJjUfkO7Ql7DCcjLgEp8lrvxMmRIdSg\n" + "LPq+NdityxXYhfaZdGdXjnLLiq3zYL/8aYjjZ8YAZTuu6pBgfGvjcqYLV1ohimrP\n" + "8BW0BbnvedqTyL7tdKjdiWnHE5ObrxnphL2evoStskBr5CLYR4vX7+qp0oVSz2Ol\n" + "nBMV3wXyhHBY1tuT1SK7ajC/ZHrciZosACRV5PC6nKXi3shWOxt76SZV3HcMmFwX\n" + "NQYYTBOlb5U080adFSmP5/6NRzrKwZ3mD2s=\n" + "-----END CERTIFICATE-----\n"; + +static const char server_key[] = "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEpAIBAAKCAQEAu9I+tijlpLqjbA4Zfu7qihUukzHCWC3WKx9WCJ8JWIbTjEjF\n" + "sdoT0mGASs1UKS74Xtiz24S8HFSXauGqkDYzaca6cVv2CGOc8QkVYELIHyl4ioFE\n" + "dBvhdzEB7JtWCKsUFNjniZXSGVATNmDA6fIdQl0wLxmgGWl7KjvVL0dmcCWSfhhJ\n" + "WDZTcIXUraiDPL9STRY3zt4FpFak7/kDOH5qa6K9qafAmg67noOD60mN2A/1hu+a\n" + "5Jpa1turdEPH45J/rP1IkN1fyJD9fjH6yVh+kS9gxowb9inzQIpONsVlIil82jXA\n" + "xTeIY6lRufTvWz51A59cD8qWP01weIqkgJcbqQIDAQABAoIBADI3ShEF6jAavmq7\n" + "clGfqxF0DFnKaf2Nc79fx27SpnsGwTS2mDSu67HJ47UcJK5GIp2pLp04ZdrlOv6W\n" + "izW3aBOV0G9SePtRNrqzBQYRlNPQEKxnV1f7xFJLxgnulhgHNX1FaNI+PkgKQri9\n" + "MZba5rvBkoplPYrNyuJF0P+tBVRiISWDY00PlZ57pQDyOvXzUckAkxmjNzo+86ld\n" + "/NyO+nR45vVKSeIBT5tT67D8wRisZgO/7QKP5sbKYwa7AR4sTEYFwBaFi4Mr6v1T\n" + "kp0KxOFBI+MioFwyK7ZjkoKClrY/K0IPsKfn2vmi6jLpfkA+qCl1JsVhrfVO3KJc\n" + "PXXF4QECgYEA9339GQS2AWSuA/9ZgHFqTTOEEHujCkh9D4mKO4LRi5hKPN9NQKUU\n" + "KgaBXWTbr8FwOTXw6HMl0SaIOdc6VxdzViNvPCpu2Wn8hyTC5Mjs/BtXkXNcBQqs\n" + "tPm0JxgC6fpQAb+gU+zZ+QQNlUWH/CEiQFxxGNzBn9E3Xq2j0StdhPECgYEAwkci\n" + "GiQuM4KMDdwbs4RDlEZyvXxWwgHKPoXv/Uq7HXtuT1FGb/+Rf3BGimMf2Qqmppp8\n" + "MAZ+xk+eXhtqKZHsV2ifhUfuVZ6NPhT2WRyn6MozuHh3MK4l2KtOhxulcoX/2sDk\n" + "dLYclxhXZFuXvbLz2KpgMmPMGyzEQNHQaoTkojkCgYEAxb/wVGY0OybD+EO2su9s\n" + "PaVU94qielvzOU/vmJ9taTnUz5Co/Gcqlm2+Pe6RrnxEfCICjOk8pUJBhN3ZKq99\n" + "I62Keqt5CNUrxpvz8bQtzz7VmE1xkEG4P55pePcxlNzBwrPnmkdc3yCC7euxvR6I\n" + "bJ6wa2owd89Gi6r4gvBAeDECgYBpdiPU/P73h05v16RR9uKYgwWWRwDxn/chqaN1\n" + "ZDPe9ToUZJJQCfP5sgEY7mZDc7yzg/kWOPBoxp+5hjhDCKu7Z1fxCfMfF0qlAMwZ\n" + "46xieiFJaluJWX/B9nxSa3eMi6EwJrXdhV5Pxy7pk67zk0k7vIEr2XDa75o5dawl\n" + "pq5WQQKBgQC9xsRLtQjnDEdNEgCicTupa7BXmvc9tRb1mA5SeqjwzYuulrTyvn5Y\n" + "QOXYdz8aeZ+ZQ/cDeGA3jA6lekWnExkp9enHeqadyDWM7rvXi800E6gB/vrO7r/c\n" + "iE+fpXud6cwNw2XYsk6RBSQ8qhJoCpa+koPXfSJOZ9Y89NMbtq0w3Q==\n" + "-----END RSA PRIVATE KEY-----\n"; + +void +print_hex(const uint8_t *v, size_t len) +{ + for (size_t i = 0; i < len; i++) { + std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast(v[i]) << " "; + + if (i != 0 && (i + 1) % 32 == 0 && i != len - 1) { + std::cout << std::endl; + } + } + + std::cout << std::endl; + + return; +} + +TEST_CASE("QUICCrypto 1-RTT", "[quic]") +{ + // Client + SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); + QUICCrypto *client = new QUICCrypto(client_ssl_ctx, NET_VCONNECTION_OUT); + + // Server + SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); + BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); + SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); + BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); + SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); + QUICCrypto *server = new QUICCrypto(server_ssl_ctx, NET_VCONNECTION_IN); + + // Client Hello + uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t client_hello_len = 0; + CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0)); + std::cout << "Client Hello" << std::endl; + print_hex(client_hello, client_hello_len); + + // Server Hello + uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t server_hello_len = 0; + CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len)); + std::cout << "Server Hello" << std::endl; + print_hex(server_hello, server_hello_len); + + // Client Fnished + uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t client_finished_len = 0; + CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len)); + std::cout << "Client Finished" << std::endl; + print_hex(client_finished, client_finished_len); + + // Post Handshake Msg + uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t post_handshake_msg_len = 0; + CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, client_finished_len)); + std::cout << "Post Handshake Message" << std::endl; + print_hex(post_handshake_msg, post_handshake_msg_len); + + CHECK(client->setup_session()); + CHECK(server->setup_session()); + + // encrypt - decrypt + uint8_t original[] = { + 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + uint64_t pkt_num = 0x123456789; + uint8_t ad[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + + // client (encrypt) - server (decrypt) + std::cout << "Original Text" << std::endl; + print_hex(original, sizeof(original)); + + uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead + size_t cipher_len = 0; + CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), + QUICKeyPhase::PHASE_0)); + + std::cout << "Encrypted Text" << std::endl; + print_hex(cipher, cipher_len); + + uint8_t plain[128] = {0}; + size_t plain_len = 0; + CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); + + std::cout << "Decrypted Text" << std::endl; + print_hex(plain, plain_len); + + CHECK(sizeof(original) == (plain_len)); + CHECK(memcmp(original, plain, plain_len) == 0); + + // Teardown + delete client; + delete server; +} diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc new file mode 100644 index 00000000000..2fbc6a91c2d --- /dev/null +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -0,0 +1,607 @@ +/** @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 "catch.hpp" + +#include "quic/QUICFrame.h" + +TEST_CASE("QUICFrame Type", "[quic]") +{ + CHECK(QUICFrame::type(reinterpret_cast("\x00")) == QUICFrameType::PADDING); + CHECK(QUICFrame::type(reinterpret_cast("\x01")) == QUICFrameType::RST_STREAM); + CHECK(QUICFrame::type(reinterpret_cast("\x02")) == QUICFrameType::CONNECTION_CLOSE); + CHECK(QUICFrame::type(reinterpret_cast("\x03")) == QUICFrameType::GOAWAY); + CHECK(QUICFrame::type(reinterpret_cast("\x04")) == QUICFrameType::MAX_DATA); + CHECK(QUICFrame::type(reinterpret_cast("\x05")) == QUICFrameType::MAX_STREAM_DATA); + CHECK(QUICFrame::type(reinterpret_cast("\x06")) == QUICFrameType::MAX_STREAM_ID); + CHECK(QUICFrame::type(reinterpret_cast("\x07")) == QUICFrameType::PING); + CHECK(QUICFrame::type(reinterpret_cast("\x08")) == QUICFrameType::BLOCKED); + CHECK(QUICFrame::type(reinterpret_cast("\x09")) == QUICFrameType::STREAM_BLOCKED); + CHECK(QUICFrame::type(reinterpret_cast("\x0a")) == QUICFrameType::STREAM_ID_NEEDED); + CHECK(QUICFrame::type(reinterpret_cast("\x0b")) == QUICFrameType::NEW_CONNECTION_ID); + // Undefined ragne + CHECK(QUICFrame::type(reinterpret_cast("\x0c")) == QUICFrameType::UNKNOWN); + CHECK(QUICFrame::type(reinterpret_cast("\x9f")) == QUICFrameType::UNKNOWN); + // Range of ACK + CHECK(QUICFrame::type(reinterpret_cast("\xa0")) == QUICFrameType::ACK); + CHECK(QUICFrame::type(reinterpret_cast("\xbf")) == QUICFrameType::ACK); + // Range of STREAM + CHECK(QUICFrame::type(reinterpret_cast("\xc0")) == QUICFrameType::STREAM); + CHECK(QUICFrame::type(reinterpret_cast("\xff")) == QUICFrameType::STREAM); +} + +TEST_CASE("Construct QUICFrame", "[quic]") +{ + uint8_t payload[] = "foo"; + uint8_t buf[65536]; + size_t len; + + QUICStreamFrame frame1(payload, sizeof(payload), 0xffcc9966, 0xffddbb9977553311); + frame1.store(buf, &len); + CHECK(frame1.type() == QUICFrameType::STREAM); + CHECK(frame1.size() == 19); + CHECK(frame1.stream_id() == 0xffcc9966); + CHECK(frame1.offset() == 0xffddbb9977553311); + CHECK(frame1.data_length() == 4); + CHECK(memcmp(frame1.data(), "foo\0", 4) == 0); + CHECK(frame1.has_fin_flag() == false); +} + +TEST_CASE("Load STREAM Frame 1", "[quic]") +{ + uint8_t buf1[] = { + 0xC0, // 11FSSOOD + 0x01, // Stream ID + 0x01, 0x02, 0x03, 0x04, // Stream Data + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM); + CHECK(frame1->size() == 6); + std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(streamFrame1->stream_id() == 0x01); + CHECK(streamFrame1->offset() == 0x00); + CHECK(streamFrame1->data_length() == 4); + CHECK(memcmp(streamFrame1->data(), "\x01\x02\x03\x04", 4) == 0); + CHECK(streamFrame1->has_fin_flag() == false); +} + +TEST_CASE("Load STREAM Frame 2", "[quic]") +{ + uint8_t buf1[] = { + 0xC1, // 11FSSOOD + 0x01, // Stream ID + 0x00, 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM); + CHECK(frame1->size() == 9); + std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(streamFrame1->stream_id() == 0x01); + CHECK(streamFrame1->offset() == 0x00); + CHECK(streamFrame1->data_length() == 5); + CHECK(memcmp(streamFrame1->data(), "\x01\x02\x03\x04\x05", 5) == 0); + CHECK(streamFrame1->has_fin_flag() == false); +} + +TEST_CASE("Store STREAM Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + // 32bit stream id, 64bit offset + uint8_t expected[] = { + 0xDF, // 11FSSOOD + 0x00, 0x00, 0x00, 0x01, // Stream ID + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Offset + 0x00, 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + QUICStreamFrame streamFrame(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01, 0x00); + streamFrame.store(buf, &len); + CHECK(len == 20); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load Ack Frame 1", "[quic]") +{ + // 0 Ack Block, 0 Timestamp, 8 bit packet number length, 8 bit block length + uint8_t buf1[] = { + 0xA0, // 101NLLMM + 0x00, // NumTS + 0x12, // Largest Acknowledged + 0x34, 0x56, // Ack Delay + 0x00, // Ack Block Section + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::ACK); + CHECK(frame1->size() == 6); + std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(ackFrame1 != nullptr); + CHECK(ackFrame1->has_ack_blocks() == false); + CHECK(ackFrame1->num_timestamps() == 0); + CHECK(ackFrame1->largest_acknowledged() == 0x12); + CHECK(ackFrame1->ack_delay() == 0x3456); + + // TODO: 1 Ack Block, 0 Timestamp + // TODO: 1 Ack Block, 1 Timestamp +} + +TEST_CASE("Load Ack Frame 2", "[quic]") +{ + // 0 Ack Block, 0 Timestamp, 8 bit packet number length, 8 bit block length + uint8_t buf1[] = { + 0xAA, // 101NLLMM '0b10101010' { N: 0, LL: 10, MM:10 } + 0x00, // NumTS + 0x00, 0x00, 0x00, 0x01, // Largest Acknowledged + 0x01, 0x71, // Ack Delay + 0x00, 0x00, 0x00, 0x01, // ACK Block + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::ACK); + CHECK(frame1->size() == 12); + std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(ackFrame1 != nullptr); + CHECK(ackFrame1->has_ack_blocks() == false); + CHECK(ackFrame1->num_timestamps() == 0); + CHECK(ackFrame1->largest_acknowledged() == 0x01); + CHECK(ackFrame1->ack_delay() == 0x0171); + + // TODO: 1 Ack Block, 0 Timestamp + // TODO: 1 Ack Block, 1 Timestamp +} + +TEST_CASE("Store Ack Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + // 0 Ack Block, 0 Timestamp, 8 bit packet number length, 8 bit block length + uint8_t expected[] = { + 0xA2, // 101NLLMM + 0x00, // NumTS + 0x12, // Largest Acknowledged + 0x34, 0x56, // Ack Delay + 0x00, 0x00, 0x00, 0x00, // Ack Block Section + }; + QUICAckFrame ackFrame(0x12, 0x3456, 0); + ackFrame.store(buf, &len); + CHECK(len == 9); + CHECK(memcmp(buf, expected, len) == 0); + + // TODO: Add ack blocks and timestamps +} + +TEST_CASE("Load RST_STREAM Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x01, // Type + 0x80, 0x00, 0x00, 0x00, // Error Code + 0x12, 0x34, 0x56, 0x78, // Stream ID + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::RST_STREAM); + CHECK(frame1->size() == 17); + std::shared_ptr rstStreamFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(rstStreamFrame1 != nullptr); + CHECK(rstStreamFrame1->error_code() == QUICErrorCode::QUIC_TRANSPORT_ERROR); + CHECK(rstStreamFrame1->stream_id() == 0x12345678); + CHECK(rstStreamFrame1->final_offset() == 0x1122334455667788); +} + +TEST_CASE("Store RST_STREAM Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x01, // Type + 0x80, 0x00, 0x00, 0x00, // Error Code + 0x12, 0x34, 0x56, 0x78, // Stream ID + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset + }; + QUICRstStreamFrame rstStreamFrame(QUICErrorCode::QUIC_TRANSPORT_ERROR, 0x12345678, 0x1122334455667788); + rstStreamFrame.store(buf, &len); + CHECK(len == 17); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load Ping Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x07, // Type + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::PING); + CHECK(frame1->size() == 1); + std::shared_ptr pingStreamFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(pingStreamFrame1 != nullptr); +} + +TEST_CASE("Store Ping Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x07, // Type + }; + QUICPingFrame pingStreamFrame; + pingStreamFrame.store(buf, &len); + CHECK(len == 1); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load Padding Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x00, // Type + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::PADDING); + CHECK(frame1->size() == 1); + std::shared_ptr paddingFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(paddingFrame1 != nullptr); +} + +TEST_CASE("Store Padding Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x00, // Type + }; + QUICPaddingFrame paddingFrame; + paddingFrame.store(buf, &len); + CHECK(len == 1); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load Goaway Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x03, // Type + 0x12, 0x34, 0x56, 0x78, // Latest Client Stream ID + 0xAA, 0xBB, 0xCC, 0xDD, // Latest Server Stream ID + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::GOAWAY); + CHECK(frame1->size() == 9); + std::shared_ptr goawayFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(goawayFrame1 != nullptr); + CHECK(goawayFrame1->client_stream_id() == 0x12345678); + CHECK(goawayFrame1->server_stream_id() == 0xAABBCCDD); +} + +TEST_CASE("Store Goaway Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x03, // Type + 0x12, 0x34, 0x56, 0x78, // Latest Client Stream ID + 0xAA, 0xBB, 0xCC, 0xDD, // Latest Server Stream ID + }; + QUICGoawayFrame goawayFrame(0x12345678, 0xAABBCCDD); + goawayFrame.store(buf, &len); + CHECK(len == 9); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load ConnectionClose Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x02, // Type + 0x80, 0x00, 0x00, 0x00, // Error Code + 0x00, 0x05, // Reason Phrase Length + 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::CONNECTION_CLOSE); + CHECK(frame1->size() == 12); + std::shared_ptr connectionCloseFrame1 = + std::dynamic_pointer_cast(frame1); + CHECK(connectionCloseFrame1 != nullptr); + CHECK(connectionCloseFrame1->error_code() == QUICErrorCode::QUIC_TRANSPORT_ERROR); + CHECK(connectionCloseFrame1->reason_phrase_length() == 5); + CHECK(memcmp(connectionCloseFrame1->reason_phrase(), buf1 + 7, 5) == 0); +} + +TEST_CASE("Store ConnectionClose Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x02, // Type + 0x80, 0x00, 0x00, 0x00, // Error Code + 0x00, 0x05, // Reason Phrase Length + 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); + }; + QUICConnectionCloseFrame connectionCloseFrame(QUICErrorCode::QUIC_TRANSPORT_ERROR, 5, "ABCDE"); + connectionCloseFrame.store(buf, &len); + CHECK(len == 12); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load MaxData Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x04, // Type + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::MAX_DATA); + CHECK(frame1->size() == 9); + std::shared_ptr maxDataFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(maxDataFrame1 != nullptr); + CHECK(maxDataFrame1->maximum_data() == 0x1122334455667788ULL); +} + +TEST_CASE("Store MaxData Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x04, // Type + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data + }; + QUICMaxDataFrame maxDataFrame(0x1122334455667788); + maxDataFrame.store(buf, &len); + CHECK(len == 9); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load MaxStreamData Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x05, // Type + 0x01, 0x02, 0x03, 0x04, // Stream ID + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::MAX_STREAM_DATA); + CHECK(frame1->size() == 13); + std::shared_ptr maxStreamDataFrame1 = + std::dynamic_pointer_cast(frame1); + CHECK(maxStreamDataFrame1 != nullptr); + CHECK(maxStreamDataFrame1->stream_id() == 0x01020304); + CHECK(maxStreamDataFrame1->maximum_stream_data() == 0x1122334455667788ULL); +} + +TEST_CASE("Store MaxStreamData Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x05, // Type + 0x01, 0x02, 0x03, 0x04, // Stream ID + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data + }; + QUICMaxStreamDataFrame maxStreamDataFrame(0x01020304, 0x1122334455667788ULL); + maxStreamDataFrame.store(buf, &len); + CHECK(len == 13); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load MaxStreamId Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x06, // Type + 0x01, 0x02, 0x03, 0x04, // Stream ID + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::MAX_STREAM_ID); + CHECK(frame1->size() == 5); + std::shared_ptr maxStreamIdFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(maxStreamIdFrame1 != nullptr); + CHECK(maxStreamIdFrame1->maximum_stream_id() == 0x01020304); +} + +TEST_CASE("Store MaxStreamId Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x06, // Type + 0x01, 0x02, 0x03, 0x04, // Stream ID + }; + QUICMaxStreamIdFrame maxStreamIdFrame(0x01020304); + maxStreamIdFrame.store(buf, &len); + CHECK(len == 5); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load Blocked Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x08, // Type + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::BLOCKED); + CHECK(frame1->size() == 1); + std::shared_ptr blockedStreamFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(blockedStreamFrame1 != nullptr); +} + +TEST_CASE("Store Blocked Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x08, // Type + }; + QUICBlockedFrame blockedStreamFrame; + blockedStreamFrame.store(buf, &len); + CHECK(len == 1); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load StreamBlocked Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x09, // Type + 0x01, 0x02, 0x03, 0x04, // Stream ID + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM_BLOCKED); + CHECK(frame1->size() == 5); + std::shared_ptr streamBlockedFrame1 = + std::dynamic_pointer_cast(frame1); + CHECK(streamBlockedFrame1 != nullptr); + CHECK(streamBlockedFrame1->stream_id() == 0x01020304); +} + +TEST_CASE("Store StreamBlocked Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x09, // Type + 0x01, 0x02, 0x03, 0x04, // Stream ID + }; + QUICStreamBlockedFrame streamBlockedFrame(0x01020304); + streamBlockedFrame.store(buf, &len); + CHECK(len == 5); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load StreamIdNeeded Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x0a, // Type + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM_ID_NEEDED); + CHECK(frame1->size() == 1); + std::shared_ptr streamIdNeededFrame1 = + std::dynamic_pointer_cast(frame1); + CHECK(streamIdNeededFrame1 != nullptr); +} + +TEST_CASE("Store StreamIdNeeded Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x0a, // Type + }; + QUICStreamIdNeededFrame streamIdNeededStreamFrame; + streamIdNeededStreamFrame.store(buf, &len); + CHECK(len == 1); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load NewConnectionId Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x0b, // Type + 0x01, 0x02, // Sequence + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Connection ID + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::NEW_CONNECTION_ID); + CHECK(frame1->size() == 11); + std::shared_ptr newConnectionIdFrame1 = + std::dynamic_pointer_cast(frame1); + CHECK(newConnectionIdFrame1 != nullptr); + CHECK(newConnectionIdFrame1->sequence() == 0x0102); + CHECK(newConnectionIdFrame1->connection_id() == 0x1122334455667788ULL); +} + +TEST_CASE("Store NewConnectionId Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x0b, // Type + 0x01, 0x02, // Sequence + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Connection ID + }; + QUICNewConnectionIdFrame newConnectionIdFrame(0x0102, 0x1122334455667788ULL); + newConnectionIdFrame.store(buf, &len); + CHECK(len == 11); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("QUICFrameFactory Create Unknown Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x0f, // Type + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1 == nullptr); +} + +TEST_CASE("QUICFrameFactory Fast Create Frame", "[quic]") +{ + QUICFrameFactory factory; + + uint8_t buf1[] = { + 0x03, // Type + 0x12, 0x34, 0x56, 0x78, // Latest Client Stream ID + 0xAA, 0xBB, 0xCC, 0xDD, // Latest Server Stream ID + }; + uint8_t buf2[] = { + 0x03, // Type + 0x11, 0x22, 0x33, 0x44, // Latest Client Stream ID + 0x0A, 0x0B, 0x0C, 0x0D, // Latest Server Stream ID + }; + std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); + CHECK(frame1 != nullptr); + + std::shared_ptr goawayFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(goawayFrame1 != nullptr); + CHECK(goawayFrame1->client_stream_id() == 0x12345678); + CHECK(goawayFrame1->server_stream_id() == 0xAABBCCDD); + + std::shared_ptr frame2 = factory.fast_create(buf2, sizeof(buf2)); + CHECK(frame2 != nullptr); + std::shared_ptr goawayFrame2 = std::dynamic_pointer_cast(frame2); + CHECK(goawayFrame2 != nullptr); + CHECK(goawayFrame2->client_stream_id() == 0x11223344); + CHECK(goawayFrame2->server_stream_id() == 0x0A0B0C0D); + + CHECK(frame1 == frame2); +} + +TEST_CASE("QUICFrameFactory Fast Create Unknown Frame", "[quic]") +{ + QUICFrameFactory factory; + + uint8_t buf1[] = { + 0x0f, // Type + }; + std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); + CHECK(frame1 == nullptr); +} diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc new file mode 100644 index 00000000000..a406a45de6f --- /dev/null +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -0,0 +1,74 @@ +/** @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 "catch.hpp" + +#include "quic/QUICFrameDispatcher.h" +#include "quic/Mock.h" +#include + +TEST_CASE("QUICFrameHandler", "[quic]") +{ + uint8_t payload[] = {0x01}; + QUICStreamFrame streamFrame(payload, 1, 0x03, 0); + + auto connectionManager = std::make_shared(); + auto streamManager = std::make_shared(); + auto flowController = std::make_shared(); + auto congestionController = std::make_shared(); + auto lossDetector = std::make_shared(); + QUICFrameDispatcher quicFrameDispatcher(connectionManager, streamManager, flowController, congestionController, lossDetector); + + // Initial state + CHECK(connectionManager->getTotalFrameCount() == 0); + CHECK(streamManager->getTotalFrameCount() == 0); + CHECK(flowController->getTotalFrameCount() == 0); + CHECK(congestionController->getTotalFrameCount() == 0); + + // STREAM frame + uint8_t buf[4096] = {0}; + size_t len = 0; + streamFrame.store(buf, &len); + quicFrameDispatcher.receive_frames(buf, len); + CHECK(connectionManager->getTotalFrameCount() == 0); + CHECK(streamManager->getTotalFrameCount() == 1); + CHECK(flowController->getTotalFrameCount() == 1); + CHECK(congestionController->getTotalFrameCount() == 1); +} + +// Stubs +QUICApplication *QUICNetVConnection::get_application(QUICStreamId) +{ + return nullptr; +} + +QUICCrypto * +QUICNetVConnection::get_crypto() +{ + return nullptr; +} + +void QUICNetVConnection::close(QUICError) +{ + return; +} diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc new file mode 100644 index 00000000000..09b4800db52 --- /dev/null +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -0,0 +1,57 @@ +/** @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 "catch.hpp" + +#include "QUICLossDetector.h" +#include "QUICEvents.h" +#include "Mock.h" + +TEST_CASE("QUICLossDetector_Loss_in_Handshake", "[quic]") +{ + MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); + QUICLossDetector detector(tx); + + // Check initial state + CHECK(tx->_retransmit_count == 0); + + // Send SERVER_CLEARTEXT (Handshake message) + uint8_t raw[4] = {0}; + ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); + memcpy(payload.get(), raw, sizeof(raw)); + + std::unique_ptr packet = std::unique_ptr(new QUICPacket( + QUICPacketType::SERVER_CLEARTEXT, 0xffddbb9977553311ULL, 0x00000001, 0x00112233, std::move(payload), sizeof(raw), true)); + detector.on_packet_sent(std::move(packet)); + ink_hrtime_sleep(HRTIME_MSECONDS(1000)); + CHECK(tx->_retransmit_count > 0); + + // Receive ACK + std::shared_ptr frame = std::make_shared(0x01, 20, 0); + frame->ack_block_section()->add_ack_block({0, 1ULL}); + detector.handle_frame(frame); + ink_hrtime_sleep(HRTIME_MSECONDS(1500)); + int retransmit_count = tx->_retransmit_count; + ink_hrtime_sleep(HRTIME_MSECONDS(1500)); + CHECK(tx->_retransmit_count == retransmit_count); +} diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc new file mode 100644 index 00000000000..1dc3b707b63 --- /dev/null +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -0,0 +1,96 @@ +/** @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 "catch.hpp" + +#include "quic/QUICPacket.h" + +TEST_CASE("Loading Long Header Packet", "[quic]") +{ + uint8_t raw[] = {0x01, 0x02, 0x03, 0x04}; + ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); + memcpy(payload.get(), raw, sizeof(raw)); + + // Cleartext packet with a long header + QUICPacket packet1(QUICPacketType::CLIENT_CLEARTEXT, 0xffddbb9977553311ULL, 0xffcc9966, 0x00112233, std::move(payload), + sizeof(raw), true); + + uint8_t buf[65536]; + size_t len; + packet1.store(buf, &len); + + IOBufferBlock *block = new_IOBufferBlock(); + block->alloc(iobuffer_size_to_index(len)); + memcpy(block->end(), buf, len); + block->fill(len); + + const QUICPacket packet2(block); + + CHECK(packet2.type() == QUICPacketType::CLIENT_CLEARTEXT); + CHECK(packet2.connection_id() == 0xffddbb9977553311ULL); + CHECK(packet2.packet_number() == 0xffcc9966); + CHECK(packet2.version() == 0x00112233); + CHECK(packet2.size() == 29); + CHECK(packet2.payload_size() == sizeof(raw)); + CHECK(memcmp(packet2.payload(), raw, sizeof(raw)) == 0); +} + +TEST_CASE("Loading Short Header Packet", "[quic]") +{ + uint8_t raw[] = {0x01, 0x02, 0x03, 0x04}; + ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); + memcpy(payload.get(), raw, sizeof(raw)); + + uint8_t protected_raw[] = {0x04, 0x03, 0x02, 0x01, 0x00}; + ats_unique_buf protected_payload = ats_unique_malloc(sizeof(protected_raw)); + memcpy(protected_payload.get(), protected_raw, sizeof(protected_raw)); + + // Cleartext packet with a long header + QUICPacket packet1(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, 0xffcc9966, std::move(payload), sizeof(raw), true); + packet1.set_protected_payload(std::move(protected_payload), sizeof(protected_raw)); + + uint8_t buf[65536]; + size_t len; + packet1.store(buf, &len); + + IOBufferBlock *block = new_IOBufferBlock(); + block->alloc(iobuffer_size_to_index(len)); + memcpy(block->end(), buf, len); + block->fill(len); + + const QUICPacket packet2(block); + + CHECK(packet2.type() == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0); + CHECK(packet2.packet_number() == 0xffcc9966); + CHECK(packet2.size() == 10); + CHECK(packet2.payload_size() == sizeof(protected_raw)); + CHECK(memcmp(packet2.payload(), protected_raw, sizeof(protected_raw)) == 0); +} + +TEST_CASE("Loading Unknown Packet", "[quic]") +{ + const uint8_t buf[] = {0xff}; + QUICPacketHeader *header = QUICPacketHeader::load(buf, sizeof(buf)); + + CHECK(header->type() == QUICPacketType::UNINITIALIZED); +} diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc new file mode 100644 index 00000000000..48f6c5df71e --- /dev/null +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -0,0 +1,69 @@ +/** @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 "catch.hpp" + +#include "quic/QUICPacket.h" + +TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") +{ + QUICPacketFactory factory; + + const uint8_t client_initial_packet_data[] = { + 0x82, // Type + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection id + 0x00, 0x00, 0x00, 0x00, // Packet number + 0xaa, 0xbb, 0xcc, 0xdd, // Version + 0x00 // Payload + }; + + IOBufferBlock *block = new_IOBufferBlock(); + block->alloc(iobuffer_size_to_index(sizeof(client_initial_packet_data))); + memcpy(block->end(), client_initial_packet_data, sizeof(client_initial_packet_data)); + block->fill(sizeof(client_initial_packet_data)); + + QUICPacket client_initial_packet(block); + + std::unique_ptr packet = factory.create_version_negotiation_packet(&client_initial_packet); + CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); + CHECK(packet->connection_id() == client_initial_packet.connection_id()); + CHECK(packet->packet_number() == client_initial_packet.packet_number()); + CHECK(memcmp(packet->payload(), "\xff\x00\x00\x04", 4) == 0); +} + +TEST_CASE("QUICPacketFactory_Create_ServerCleartextPacket", "[quic]") +{ + QUICPacketFactory factory; + factory.set_version(0x11223344); + + uint8_t raw[] = {0xaa, 0xbb, 0xcc, 0xdd}; + ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); + memcpy(payload.get(), raw, sizeof(raw)); + + std::unique_ptr packet = factory.create_server_cleartext_packet(0x01020304, std::move(payload), sizeof(raw), true); + CHECK(packet->type() == QUICPacketType::SERVER_CLEARTEXT); + CHECK(packet->connection_id() == 0x01020304); + CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); + CHECK(packet->packet_number() == 0); + CHECK(packet->version() == 0x11223344); +} diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc new file mode 100644 index 00000000000..042f39d0764 --- /dev/null +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -0,0 +1,140 @@ +/** @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 "catch.hpp" + +#include "quic/QUICStream.h" +#include "quic/Mock.h" + +namespace +{ +// Test Data +uint8_t payload[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; +uint32_t stream_id = 0x03; + +std::shared_ptr frame_1 = std::make_shared(payload, 2, stream_id, 0); +std::shared_ptr frame_2 = std::make_shared(payload + 2, 2, stream_id, 2); +std::shared_ptr frame_3 = std::make_shared(payload + 4, 2, stream_id, 4); +std::shared_ptr frame_4 = std::make_shared(payload + 6, 2, stream_id, 6); +std::shared_ptr frame_5 = std::make_shared(payload + 8, 2, stream_id, 8); +std::shared_ptr frame_6 = std::make_shared(payload + 10, 2, stream_id, 10); +std::shared_ptr frame_7 = std::make_shared(payload + 12, 2, stream_id, 12); +std::shared_ptr frame_8 = std::make_shared(payload + 14, 2, stream_id, 14); + +TEST_CASE("QUICStream_assembling_byte_stream_1", "[quic]") +{ + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + IOBufferReader *reader = read_buffer->alloc_reader(); + + std::unique_ptr stream(new QUICStream()); + stream->init(nullptr, stream_id); + stream->do_io_read(nullptr, 0, read_buffer); + + stream->recv(frame_1); + stream->recv(frame_2); + stream->recv(frame_3); + stream->recv(frame_4); + stream->recv(frame_5); + stream->recv(frame_6); + stream->recv(frame_7); + stream->recv(frame_8); + + uint8_t buf[32]; + int64_t len = reader->read_avail(); + reader->read(buf, len); + + CHECK(len == 16); + CHECK(memcmp(buf, payload, len) == 0); +} + +TEST_CASE("QUICStream_assembling_byte_stream_2", "[quic]") +{ + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + IOBufferReader *reader = read_buffer->alloc_reader(); + + std::unique_ptr stream(new QUICStream()); + stream->init(nullptr, stream_id); + stream->do_io_read(nullptr, 0, read_buffer); + + stream->recv(frame_8); + stream->recv(frame_7); + stream->recv(frame_6); + stream->recv(frame_5); + stream->recv(frame_4); + stream->recv(frame_3); + stream->recv(frame_2); + stream->recv(frame_1); + + uint8_t buf[32]; + int64_t len = reader->read_avail(); + reader->read(buf, len); + + CHECK(len == 16); + CHECK(memcmp(buf, payload, len) == 0); +} + +TEST_CASE("QUICStream_assembling_byte_stream_3", "[quic]") +{ + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + IOBufferReader *reader = read_buffer->alloc_reader(); + + std::unique_ptr stream(new QUICStream()); + stream->init(nullptr, stream_id); + stream->do_io_read(nullptr, 0, read_buffer); + + stream->recv(frame_8); + stream->recv(frame_7); + stream->recv(frame_6); + stream->recv(frame_7); // duplicated frame + stream->recv(frame_5); + stream->recv(frame_3); + stream->recv(frame_1); + stream->recv(frame_2); + stream->recv(frame_4); + stream->recv(frame_5); // duplicated frame + + uint8_t buf[32]; + int64_t len = reader->read_avail(); + reader->read(buf, len); + + CHECK(len == 16); + CHECK(memcmp(buf, payload, len) == 0); +} +} + +// Stubs +QUICApplication *QUICNetVConnection::get_application(QUICStreamId) +{ + return nullptr; +} + +QUICCrypto * +QUICNetVConnection::get_crypto() +{ + return nullptr; +} + +void QUICNetVConnection::close(QUICError) +{ + return; +} diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc new file mode 100644 index 00000000000..353cffd3263 --- /dev/null +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -0,0 +1,47 @@ +/** @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 "catch.hpp" + +#include + +#include "quic/QUICFrame.h" +#include "quic/QUICStreamState.h" + +TEST_CASE("QUICStreamState_Update", "[quic]") +{ + QUICStreamState ss; + + std::shared_ptr streamFrame = + std::make_shared(reinterpret_cast("foo"), 4, 1, 0); + std::shared_ptr rstStreamFrame = + std::make_shared(QUICErrorCode::QUIC_TRANSPORT_ERROR, 0, 0); + + CHECK(ss.get() == QUICStreamState::State::idle); + + ss.update_with_received_frame(*streamFrame); + CHECK(ss.get() == QUICStreamState::State::open); + + ss.update_with_received_frame(*rstStreamFrame); + CHECK(ss.get() == QUICStreamState::State::closed); +} diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc new file mode 100644 index 00000000000..7999789b426 --- /dev/null +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -0,0 +1,164 @@ +/** @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 "catch.hpp" + +#include "QUICTransportParameters.h" + +TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") +{ + uint8_t buf[] = { + 0x01, 0x02, 0x03, 0x04, // negotiated version + 0x05, 0x06, 0x07, 0x08, // iinitial version + 0x00, 0x04, // number of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value + 0x00, 0x01, // parameter id + 0x00, 0x04, // length of value + 0x12, 0x34, 0x56, 0x78, // value + 0x00, 0x02, // parameter id + 0x00, 0x04, // length of value + 0x0a, 0x0b, 0x0c, 0x0d, // value + 0x00, 0x03, // parameter id + 0x00, 0x02, // length of value + 0xab, 0xcd, // value + }; + + QUICTransportParametersInClientHello params_in_ch(buf); + CHECK(params_in_ch.negotiated_version() == 0x01020304); + CHECK(params_in_ch.initial_version() == 0x05060708); + QUICTransportParameterValue value; + value = params_in_ch.get(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); + CHECK(value.len == 4); + CHECK(memcmp(value.data, "\x11\x22\x33\x44", 4) == 0); + value = params_in_ch.get(QUICTransportParameterId::INITIAL_MAX_DATA); + CHECK(value.len == 4); + CHECK(memcmp(value.data, "\x12\x34\x56\x78", 4) == 0); + value = params_in_ch.get(QUICTransportParameterId::INITIAL_MAX_STREAM_ID); + CHECK(value.len == 4); + CHECK(memcmp(value.data, "\x0a\x0b\x0c\x0d", 4) == 0); + value = params_in_ch.get(QUICTransportParameterId::IDLE_TIMEOUT); + CHECK(value.len == 2); + CHECK(memcmp(value.data, "\xab\xcd", 2) == 0); + value = params_in_ch.get(QUICTransportParameterId::MAX_PACKET_SIZE); + CHECK(value.len == 0); + CHECK(value.data == nullptr); +} + +TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") +{ + uint8_t buf[65536]; + uint16_t len; + + uint8_t expected[] = { + 0x01, 0x02, 0x03, 0x04, // negotiated version + 0x05, 0x06, 0x07, 0x08, // iinitial version + 0x00, 0x02, // number of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value + 0x00, 0x05, // parameter id + 0x00, 0x02, // length of value + 0xab, 0xcd, // value + }; + + QUICTransportParametersInClientHello params_in_ch(0x01020304, 0x05060708); + params_in_ch.add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, {reinterpret_cast("\x11\x22\x33\x44"), 4}); + params_in_ch.add(QUICTransportParameterId::MAX_PACKET_SIZE, {reinterpret_cast("\xab\xcd"), 2}); + params_in_ch.store(buf, &len); + CHECK(len == 24); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") +{ + uint8_t buf[] = { + 0x00, 0x01, // number of supported versions + 0x01, 0x02, 0x03, 0x04, // + 0x00, 0x04, // number of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value + 0x00, 0x01, // parameter id + 0x00, 0x04, // length of value + 0x12, 0x34, 0x56, 0x78, // value + 0x00, 0x02, // parameter id + 0x00, 0x04, // length of value + 0x0a, 0x0b, 0x0c, 0x0d, // value + 0x00, 0x03, // parameter id + 0x00, 0x02, // length of value + 0xab, 0xcd, // value + }; + + QUICTransportParametersInEncryptedExtensions params_in_ee(buf); + const uint8_t *versions; + uint16_t nversion; + versions = params_in_ee.supported_versions(&nversion); + CHECK(nversion == 1); + CHECK(memcmp(versions, "\x01\x02\x03\x04", 4) == 0); + QUICTransportParameterValue value; + value = params_in_ee.get(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); + CHECK(value.len == 4); + CHECK(memcmp(value.data, "\x11\x22\x33\x44", 4) == 0); + value = params_in_ee.get(QUICTransportParameterId::INITIAL_MAX_DATA); + CHECK(value.len == 4); + CHECK(memcmp(value.data, "\x12\x34\x56\x78", 4) == 0); + value = params_in_ee.get(QUICTransportParameterId::INITIAL_MAX_STREAM_ID); + CHECK(value.len == 4); + CHECK(memcmp(value.data, "\x0a\x0b\x0c\x0d", 4) == 0); + value = params_in_ee.get(QUICTransportParameterId::IDLE_TIMEOUT); + CHECK(value.len == 2); + CHECK(memcmp(value.data, "\xab\xcd", 2) == 0); + value = params_in_ee.get(QUICTransportParameterId::MAX_PACKET_SIZE); + CHECK(value.len == 0); + CHECK(value.data == nullptr); +} + +TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") +{ + uint8_t buf[65536]; + uint16_t len; + + uint8_t expected[] = { + 0x00, 0x02, // number of supported versions + 0x01, 0x02, 0x03, 0x04, // version 1 + 0x05, 0x06, 0x07, 0x08, // version 2 + 0x00, 0x02, // number of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value + 0x00, 0x05, // parameter id + 0x00, 0x02, // length of value + 0xab, 0xcd, // value + }; + + QUICTransportParametersInEncryptedExtensions params_in_ee; + params_in_ee.add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, {reinterpret_cast("\x11\x22\x33\x44"), 4}); + params_in_ee.add(QUICTransportParameterId::MAX_PACKET_SIZE, {reinterpret_cast("\xab\xcd"), 2}); + params_in_ee.add_version(0x01020304); + params_in_ee.add_version(0x05060708); + params_in_ee.store(buf, &len); + CHECK(len == 26); + CHECK(memcmp(buf, expected, len) == 0); +} diff --git a/iocore/net/quic/test/test_QUICTypeUtil.cc b/iocore/net/quic/test/test_QUICTypeUtil.cc new file mode 100644 index 00000000000..1bea4babf70 --- /dev/null +++ b/iocore/net/quic/test/test_QUICTypeUtil.cc @@ -0,0 +1,69 @@ +/** @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 "catch.hpp" + +#include "quic/QUICTypes.h" +#include + +TEST_CASE("QUICTypeUtil", "[quic]") +{ + uint8_t buf[8]; + size_t len; + + QUICTypeUtil::write_uint_as_nbytes(0xff, 1, buf, &len); + INFO("1 byte to 1 byte"); + CHECK(memcmp(buf, "\xff\x00\x00\x00\x00\x00\x00\x00", 1) == 0); + + QUICTypeUtil::write_uint_as_nbytes(0xff, 2, buf, &len); + INFO("1 byte to 2 byte"); + CHECK(memcmp(buf, "\x00\xff\x00\x00\x00\x00\x00\x00", 2) == 0); + + QUICTypeUtil::write_uint_as_nbytes(0xff, 4, buf, &len); + INFO("1 byte to 4 byte"); + CHECK(memcmp(buf, "\x00\x00\x00\xff\x00\x00\x00\x00", 4) == 0); + + QUICTypeUtil::write_uint_as_nbytes(0xff, 6, buf, &len); + INFO("1 byte to 6 byte"); + CHECK(memcmp(buf, "\x00\x00\x00\x00\x00\xff\x00\x00", 6) == 0); + + QUICTypeUtil::write_uint_as_nbytes(0xff, 8, buf, &len); + INFO("1 byte to 8 byte"); + CHECK(memcmp(buf, "\x00\x00\x00\x00\x00\x00\x00\xff", 8) == 0); + + QUICTypeUtil::write_uint_as_nbytes(0x11ff, 2, buf, &len); + INFO("2 byte to 2 byte"); + CHECK(memcmp(buf, "\x11\xff\x00\x00\x00\x00\x00\x00", 2) == 0); + + QUICTypeUtil::write_uint_as_nbytes(0x11ff, 4, buf, &len); + INFO("2 byte to 4 byte"); + CHECK(memcmp(buf, "\x00\x00\x11\xff\x00\x00\x00\x00", 4) == 0); + + QUICTypeUtil::write_uint_as_nbytes(0x11ff, 6, buf, &len); + INFO("2 byte to 6 byte"); + CHECK(memcmp(buf, "\x00\x00\x00\x00\x11\xff\x00\x00", 6) == 0); + + QUICTypeUtil::write_uint_as_nbytes(0x11ff, 8, buf, &len); + INFO("2 byte to 8 byte"); + CHECK(memcmp(buf, "\x00\x00\x00\x00\x00\x00\x11\xff", 8) == 0); +} diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc new file mode 100644 index 00000000000..3d63e01781a --- /dev/null +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -0,0 +1,47 @@ +/** @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 "catch.hpp" + +#include "quic/QUICVersionNegotiator.h" +#include "quic/Mock.h" + +TEST_CASE("QUICVersionNegotiator_Normal", "[quic]") +{ + QUICPacketFactory packet_factory; + QUICVersionNegotiator vn(&packet_factory, new MockQUICPacketTransmitter()); + + // Check initial state + CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); + + // Negotiate version + std::unique_ptr initial_packet = + packet_factory.create_client_initial_packet({}, QUIC_SUPPORTED_VERSIONS[0], ats_unique_malloc(0), 0); + vn.negotiate(initial_packet.get()); + CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); + + // Revalidate version + vn.revalidate(QUIC_SUPPORTED_VERSIONS[0]); + // FIXME Currently, revalidate() is not implemented yet + // CHECK(vn.status() == QUICVersionNegotiationStatus::REVALIDATED); +} diff --git a/lib/records/I_RecHttp.h b/lib/records/I_RecHttp.h index 75ddd6f2de6..8fa2c697728 100644 --- a/lib/records/I_RecHttp.h +++ b/lib/records/I_RecHttp.h @@ -231,7 +231,8 @@ struct HttpProxyPort { TRANSPORT_COMPRESSED, ///< Compressed HTTP. TRANSPORT_BLIND_TUNNEL, ///< Blind tunnel (no processing). TRANSPORT_SSL, ///< SSL connection. - TRANSPORT_PLUGIN /// < Protocol plugin connection + TRANSPORT_PLUGIN, /// < Protocol plugin connection + TRANSPORT_QUIC, ///< SSL connection. }; int m_fd; ///< Pre-opened file descriptor if present. @@ -272,6 +273,9 @@ struct HttpProxyPort { /// Check for SSL port. bool isSSL() const; + /// Check for QUIC port. + bool isQUIC() const; + /// Check for SSL port. bool isPlugin() const; @@ -298,6 +302,15 @@ struct HttpProxyPort { /// @return @c true if any global port is an SSL port. static bool hasSSL(); + /// Check for QUIC ports. + /// @return @c true if any port in @a ports is an QUIC port. + static bool hasQUIC(Group const &ports ///< Ports to check. + ); + + /// Check for QUIC ports. + /// @return @c true if any global port is an QUIC port. + static bool hasQUIC(); + /** Load all relevant configuration data. This is hardwired to look up the appropriate values in the @@ -389,6 +402,7 @@ struct HttpProxyPort { static const char *const OPT_TRANSPARENT_FULL; ///< Full transparency. static const char *const OPT_TRANSPARENT_PASSTHROUGH; ///< Pass-through non-HTTP. static const char *const OPT_SSL; ///< SSL (experimental) + static const char *const OPT_QUIC; ///< QUIC (experimental) static const char *const OPT_PLUGIN; ///< Protocol Plugin handle (experimental) static const char *const OPT_BLIND_TUNNEL; ///< Blind tunnel. static const char *const OPT_COMPRESSED; ///< Compressed. @@ -421,6 +435,11 @@ HttpProxyPort::isSSL() const return TRANSPORT_SSL == m_type; } inline bool +HttpProxyPort::isQUIC() const +{ + return TRANSPORT_QUIC == m_type; +} +inline bool HttpProxyPort::isPlugin() const { return TRANSPORT_PLUGIN == m_type; @@ -463,6 +482,11 @@ HttpProxyPort::hasSSL() { return self::hasSSL(m_global); } +inline bool +HttpProxyPort::hasQUIC() +{ + return self::hasQUIC(m_global); +} inline HttpProxyPort * HttpProxyPort::findHttp(uint16_t family) { diff --git a/lib/records/RecHttp.cc b/lib/records/RecHttp.cc index dc35bcefa11..d3024998937 100644 --- a/lib/records/RecHttp.cc +++ b/lib/records/RecHttp.cc @@ -130,6 +130,7 @@ const char *const HttpProxyPort::OPT_SSL = "ssl"; const char *const HttpProxyPort::OPT_PLUGIN = "plugin"; const char *const HttpProxyPort::OPT_BLIND_TUNNEL = "blind"; const char *const HttpProxyPort::OPT_COMPRESSED = "compressed"; +const char *const HttpProxyPort::OPT_QUIC = "quic"; // File local constants. namespace @@ -177,6 +178,18 @@ HttpProxyPort::hasSSL(Group const &ports) return zret; } +bool +HttpProxyPort::hasQUIC(Group const &ports) +{ + bool zret = false; + for (int i = 0, n = ports.length(); i < n && !zret; ++i) { + if (ports[i].isQUIC()) { + zret = true; + } + } + return zret; +} + HttpProxyPort * HttpProxyPort::findHttp(Group const &ports, uint16_t family) { @@ -344,6 +357,8 @@ HttpProxyPort::processOptions(const char *opts) af_set_p = true; } else if (0 == strcasecmp(OPT_SSL, item)) { m_type = TRANSPORT_SSL; + } else if (0 == strcasecmp(OPT_QUIC, item)) { + m_type = TRANSPORT_QUIC; } else if (0 == strcasecmp(OPT_PLUGIN, item)) { m_type = TRANSPORT_PLUGIN; } else if (0 == strcasecmp(OPT_TRANSPARENT_INBOUND, item)) { @@ -531,6 +546,8 @@ HttpProxyPort::print(char *out, size_t n) zret += snprintf(out + zret, n - zret, ":%s", OPT_BLIND_TUNNEL); } else if (TRANSPORT_SSL == m_type) { zret += snprintf(out + zret, n - zret, ":%s", OPT_SSL); + } else if (TRANSPORT_QUIC == m_type) { + zret += snprintf(out + zret, n - zret, ":%s", OPT_QUIC); } else if (TRANSPORT_PLUGIN == m_type) { zret += snprintf(out + zret, n - zret, ":%s", OPT_PLUGIN); } else if (TRANSPORT_COMPRESSED == m_type) { diff --git a/proxy/Main.cc b/proxy/Main.cc index d257a5e9310..2bf879628e2 100644 --- a/proxy/Main.cc +++ b/proxy/Main.cc @@ -91,6 +91,7 @@ extern "C" int plock(int); #include "I_Tasks.h" #include "InkAPIInternal.h" #include "HTTP2.h" +#include "HQ.h" #include @@ -1809,6 +1810,8 @@ main(int /* argc ATS_UNUSED */, const char **argv) // Initialize HTTP/2 Http2::init(); + // Initialize HTTP/QUIC + HQ::init(); if (!HttpProxyPort::loadValue(http_accept_port_descriptor)) { HttpProxyPort::loadConfig(); @@ -1829,6 +1832,8 @@ main(int /* argc ATS_UNUSED */, const char **argv) SSLConfigParams::load_ssl_file_cb = load_ssl_file_callback; sslNetProcessor.start(-1, stacksize); + quic_NetProcessor.start(-1, stacksize); + pmgmt->registerPluginCallbacks(global_config_cbs); cacheProcessor.afterInitCallbackSet(&CB_After_Cache_Init); diff --git a/proxy/Makefile.am b/proxy/Makefile.am index 0b5e394cc06..220f8d869f5 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -19,7 +19,7 @@ include $(top_srcdir)/build/tidy.mk # Note that hdrs is targeted from ../Makefile.am -SUBDIRS = congest http http2 logging config +SUBDIRS = congest http http2 hq logging config noinst_LIBRARIES = bin_PROGRAMS = \ traffic_server \ @@ -35,6 +35,7 @@ AM_CPPFLAGS += \ -I$(abs_top_srcdir)/lib/records \ -I$(abs_srcdir)/http \ -I$(abs_srcdir)/http2 \ + -I$(abs_srcdir)/hq \ -I$(abs_srcdir)/logging \ -I$(abs_srcdir)/http/remap \ -I$(abs_srcdir)/hdrs \ @@ -179,6 +180,7 @@ endif traffic_server_LDADD = \ http/libhttp.a \ http2/libhttp2.a \ + hq/libhq.a \ http/remap/libhttp_remap.a \ congest/libCongestionControl.a \ logging/liblogging.a \ @@ -202,6 +204,7 @@ endif traffic_server_LDADD += \ $(top_builddir)/iocore/net/libinknet.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ diff --git a/proxy/hq/HQ.cc b/proxy/hq/HQ.cc new file mode 100644 index 00000000000..1797a866770 --- /dev/null +++ b/proxy/hq/HQ.cc @@ -0,0 +1,32 @@ +/** @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 "HQ.h" + +RecRawStatBlock *quic_rsb; + +void +HQ::init() +{ + quic_rsb = RecAllocateRawStatBlock(static_cast(HQ_N_STATS)); +} diff --git a/proxy/hq/HQ.h b/proxy/hq/HQ.h new file mode 100644 index 00000000000..2d29e742c25 --- /dev/null +++ b/proxy/hq/HQ.h @@ -0,0 +1,44 @@ +/** @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. + */ + +#ifndef __HTTP_QUIC_H__ +#define __HTTP_QUIC_H__ + +#include "ts/ink_defs.h" +#include "I_RecDefs.h" +#include "I_RecProcess.h" + +extern RecRawStatBlock *hq_rsb; // Container for statistics. + +class HQ +{ +public: + static void init(); +}; + +// Statistics +enum { + HQ_N_STATS // Terminal counter, NOT A STAT INDEX. +}; + +#endif // __HTTP_QUIC_H__ diff --git a/proxy/hq/HQSessionAccept.cc b/proxy/hq/HQSessionAccept.cc new file mode 100644 index 00000000000..a98e44ec05a --- /dev/null +++ b/proxy/hq/HQSessionAccept.cc @@ -0,0 +1,85 @@ +/** @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 "HQSessionAccept.h" + +#include "P_Net.h" +#include "I_Machine.h" +#include "../IPAllow.h" + +HQSessionAccept::HQSessionAccept(const HttpSessionAccept::Options &_o) : SessionAccept(nullptr), options(_o) +{ + SET_HANDLER(&HQSessionAccept::mainEvent); +} + +HQSessionAccept::~HQSessionAccept() +{ +} + +bool +HQSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader *reader) +{ + sockaddr const *client_ip = netvc->get_remote_addr(); + const AclRecord *session_acl_record = testIpAllowPolicy(client_ip); + if (!session_acl_record) { + ip_port_text_buffer ipb; + Warning("QUIC client '%s' prohibited by ip-allow policy", ats_ip_ntop(client_ip, ipb, sizeof(ipb))); + return false; + } + netvc->attributes = this->options.transport_type; + + if (is_debug_tag_set("quic_seq")) { + ip_port_text_buffer ipb; + + Debug("quic_seq", "[HQSessionAccept:mainEvent %p] accepted connection from %s transport type = %d", netvc, + ats_ip_nptop(client_ip, ipb, sizeof(ipb)), netvc->attributes); + } + + ink_assert(false); + // Not implemented yet + + // HQClientSession *new_session = THREAD_ALLOC_INIT(quicClientSessionAllocator, this_ethread()); + // new_session->acl_record = session_acl_record; + // new_session->new_connection(netvc, iobuf, reader, false /* backdoor */); + // static_cast(netvc)->set_application(new_session); + + return true; +} + +int +HQSessionAccept::mainEvent(int event, void *data) +{ + NetVConnection *netvc; + ink_release_assert(event == NET_EVENT_ACCEPT || event == EVENT_ERROR); + ink_release_assert((event == NET_EVENT_ACCEPT) ? (data != nullptr) : (1)); + + if (event == NET_EVENT_ACCEPT) { + netvc = static_cast(data); + if (!this->accept(netvc, nullptr, nullptr)) { + netvc->do_io_close(); + } + return EVENT_CONT; + } + + return EVENT_CONT; +} diff --git a/proxy/hq/HQSessionAccept.h b/proxy/hq/HQSessionAccept.h new file mode 100644 index 00000000000..68fb584ec16 --- /dev/null +++ b/proxy/hq/HQSessionAccept.h @@ -0,0 +1,56 @@ +/** @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. + */ + +#ifndef __HTTP_QUIC_SESSION_ACCEPT_H__ +#define __HTTP_QUIC_SESSION_ACCEPT_H__ + +#include "ts/ink_platform.h" +#include "I_Net.h" + +// XXX HttpSessionAccept::Options needs to be refactored and separated from HttpSessionAccept so that +// it can generically apply to all protocol implementations. +#include "http/HttpSessionAccept.h" + +// HTTP/QUIC Session Accept. +// +// HTTP/QUIC needs to be explicitly enabled on a server port. The syntax is different for SSL and raw +// ports. The example below configures QUIC on port 443 (with TLS). +// +// CONFIG proxy.config.http.server_ports STRING 443:quic + +class HQSessionAccept : public SessionAccept { +public: + explicit HQSessionAccept(const HttpSessionAccept::Options &); + ~HQSessionAccept(); + + bool accept(NetVConnection *, MIOBuffer *, IOBufferReader *); + int mainEvent(int event, void *netvc); + +private: + HQSessionAccept(const HQSessionAccept &); + HQSessionAccept &operator=(const HQSessionAccept &); + + HttpSessionAccept::Options options; +}; + +#endif // __HTTP_QUIC_SESSION_ACCEPT_H__ diff --git a/proxy/hq/Makefile.am b/proxy/hq/Makefile.am new file mode 100644 index 00000000000..b188de4e899 --- /dev/null +++ b/proxy/hq/Makefile.am @@ -0,0 +1,43 @@ +# +# Makefile.am for HTTP over QUIC +# +# 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 $(top_srcdir)/build/tidy.mk + +AM_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(abs_top_srcdir)/proxy/api/ts \ + -I$(abs_top_srcdir)/lib \ + -I$(abs_top_srcdir)/lib/records \ + -I$(abs_top_srcdir)/mgmt \ + -I$(abs_top_srcdir)/mgmt/utils \ + -I$(abs_top_srcdir)/proxy \ + -I$(abs_top_srcdir)/proxy/http \ + -I$(abs_top_srcdir)/proxy/hdrs \ + -I$(abs_top_srcdir)/proxy/shared \ + -I$(abs_top_srcdir)/proxy/http/remap + +noinst_LIBRARIES = libhq.a + +libhq_a_SOURCES = \ + HQ.cc \ + HQSessionAccept.cc \ + HQSessionAccept.h + +tidy-local: $(libhq_a_SOURCES) \ + $(CXX_Clang_Tidy) diff --git a/proxy/http/HttpProxyServerMain.cc b/proxy/http/HttpProxyServerMain.cc index e88b6043458..9beb3ac29f3 100644 --- a/proxy/http/HttpProxyServerMain.cc +++ b/proxy/http/HttpProxyServerMain.cc @@ -39,6 +39,7 @@ #include "ProtocolProbeSessionAccept.h" #include "http2/Http2SessionAccept.h" #include "HttpConnectionCount.h" +#include "hq/HQSessionAccept.h" HttpSessionAccept *plugin_http_accept = nullptr; HttpSessionAccept *plugin_http_transparent_accept = nullptr; @@ -218,6 +219,10 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned ssl_plugin_acceptors.push(ssl); ssl->proxyPort = &port; acceptor._accept = ssl; + } else if (port.isQUIC()) { + // HTTP/QUIC + HQSessionAccept *hq = new HQSessionAccept(accept_opt); + acceptor._accept = hq; } else { acceptor._accept = probe; } @@ -286,7 +291,11 @@ start_HttpProxyServer() for (int i = 0, n = proxy_ports.length(); i < n; ++i) { HttpProxyAcceptor &acceptor = HttpProxyAcceptors[i]; HttpProxyPort &port = proxy_ports[i]; - if (port.isSSL()) { + if (port.isQUIC()) { + if (nullptr == quic_NetProcessor.main_accept(acceptor._accept, port.m_fd, acceptor._net_opt)) { + return; + } + } else if (port.isSSL()) { if (nullptr == sslNetProcessor.main_accept(acceptor._accept, port.m_fd, acceptor._net_opt)) { return; } diff --git a/proxy/http/Makefile.am b/proxy/http/Makefile.am index fc8ee91b890..0d9605a8e5c 100644 --- a/proxy/http/Makefile.am +++ b/proxy/http/Makefile.am @@ -31,7 +31,8 @@ AM_CPPFLAGS += \ -I$(abs_top_srcdir)/proxy/shared \ -I$(abs_top_srcdir)/proxy/http/remap \ -I$(abs_top_srcdir)/proxy/logging \ - -I$(abs_top_srcdir)/proxy/http2 + -I$(abs_top_srcdir)/proxy/http2 \ + -I$(abs_top_srcdir)/proxy/hq noinst_HEADERS = HttpProxyServerMain.h noinst_LIBRARIES = libhttp.a From 94f42e73042c77891bf1dabbd083d59978626c05 Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Tue, 8 Aug 2017 15:51:05 -0700 Subject: [PATCH 0002/1313] Updates to build on Fedora 26 and clang-format --- iocore/net/QUICNetProcessor.cc | 2 +- iocore/net/QUICNetVConnection.cc | 6 +++--- iocore/net/QUICPacketHandler.cc | 4 ++-- iocore/net/quic/Mock.h | 4 +--- iocore/net/quic/QUICFlowController.cc | 2 +- iocore/net/quic/QUICFrame.cc | 2 +- iocore/net/quic/QUICFrame.h | 4 ++-- iocore/net/quic/QUICFrameDispatcher.cc | 4 ++-- iocore/net/quic/QUICHandshake.cc | 2 +- iocore/net/quic/QUICStreamManager.cc | 2 +- proxy/hq/HQSessionAccept.h | 3 ++- 11 files changed, 17 insertions(+), 18 deletions(-) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 72fb4e14df9..40eb37e3575 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -114,7 +114,7 @@ QUICNetProcessor::main_accept(Continuation *cont, SOCKET fd, AcceptOptions const // char thr_name[MAX_THREAD_NAME_LENGTH]; NetAccept *na = createNetAccept(opt); - if (opt.accept_threads < 0) { + if (accept_threads < 0) { REC_ReadConfigInteger(accept_threads, "proxy.config.accept_threads"); } NET_INCREMENT_DYN_STAT(net_accepts_currently_open_stat); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 926568f4a77..1ff56e3f99a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -258,7 +258,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) if (error.cls != QUICErrorClass::NONE) { // TODO: Send error if needed - Debug(tag, "QUICError: cls=%u, code=0x%x", error.cls, error.code); + Debug(tag, "QUICError: cls=%u, code=0x%x", static_cast(error.cls), static_cast(error.code)); } if (this->_handshake_handler && this->_handshake_handler->is_completed()) { @@ -295,7 +295,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) if (error.cls != QUICErrorClass::NONE) { // TODO: Send error if needed - Debug(tag, "QUICError: cls=%u, code=0x%x", error.cls, error.code); + Debug(tag, "QUICError: cls=%u, code=0x%x", static_cast(error.cls), static_cast(error.code)); } return EVENT_CONT; @@ -413,7 +413,7 @@ QUICNetVConnection::_state_connection_established_process_packet(std::unique_ptr if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, packet->payload(), packet->payload_size(), packet->packet_number(), packet->header(), packet->header_size(), packet->key_phase())) { - Debug(tag, "Decrypt Packet, pkt_num: %llu, header_len: %hu, payload_len: %zu", packet->packet_number(), packet->header_size(), + Debug(tag, "Decrypt Packet, pkt_num: %lu, header_len: %hu, payload_len: %zu", packet->packet_number(), packet->header_size(), plain_txt_len); this->_recv_and_ack(plain_txt.get(), plain_txt_len, packet->packet_number()); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 88474296fdc..59ea5cc3207 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -67,7 +67,7 @@ QUICPacketHandler::acceptEvent(int event, void *data) UDPPacket *packet_r; ip_port_text_buffer ipb; while ((packet_r = queue->dequeue())) { - Debug("quic_sec", "received packet from %s, size=%lld", ats_ip_nptop(&packet_r->from.sa, ipb, sizeof(ipb)), + Debug("quic_sec", "received packet from %s, size=%ld", ats_ip_nptop(&packet_r->from.sa, ipb, sizeof(ipb)), packet_r->getPktLength()); this->_recv_packet(event, packet_r); } @@ -142,7 +142,7 @@ QUICPacketHandler::send_packet(const QUICPacket &packet, QUICNetVConnection *vc) // NOTE: p will be enqueued to udpOutQueue of UDPNetHandler ip_port_text_buffer ipb; - Debug("quic_sec", "send %s packet to %s, size=%lld", QUICDebugNames::packet_type(packet.type()), + Debug("quic_sec", "send %s packet to %s, size=%ld", QUICDebugNames::packet_type(packet.type()), ats_ip_nptop(&udpPkt->to.sa, ipb, sizeof(ipb)), udpPkt->getPktLength()); vc->get_udp_con()->send(this, udpPkt); } diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 094bce30be5..9483ce3b469 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -9,9 +9,7 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter { public: - MockQUICPacketTransmitter() : QUICPacketTransmitter() { - this->_mutex= new_ProxyMutex(); - }; + MockQUICPacketTransmitter() : QUICPacketTransmitter() { this->_mutex = new_ProxyMutex(); }; void transmit_packet(std::unique_ptr packet) override diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index b746aa2a726..273715a62e6 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -35,7 +35,7 @@ QUICFlowController::handle_frame(std::shared_ptr frame) case QUICFrameType::STREAM: break; default: - Debug(tag, "Unexpected frame type: %02x", frame->type()); + Debug(tag, "Unexpected frame type: %02x", static_cast(frame->type())); ink_assert(false); break; } diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 8ca581d97b1..d7495c76957 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -612,7 +612,7 @@ QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, con this->_ack_blocks = ack_block; if (this->_ack_blocks->size()) { if (this->_ack_blocks->size() == this->_index) { - this->_current_block = {0, 0ULL}; + this->_current_block = {static_cast(0), 0ULL}; } else { this->_current_block = this->_ack_blocks->at(this->_index); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index a4247802d63..2e87d4ff8e3 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -125,7 +125,7 @@ class QUICAckFrame : public QUICFrame // TODO Parse Ack Block } else { if (this->_ack_blocks->size() == this->_index) { - this->_current_block = {0, 0ULL}; + this->_current_block = {static_cast(0), 0ULL}; } else { this->_current_block = this->_ack_blocks->at(this->_index); } @@ -150,7 +150,7 @@ class QUICAckFrame : public QUICFrame uint8_t _index; const uint8_t *_buf; const std::vector *_ack_blocks = nullptr; - QUICAckFrame::AckBlock _current_block = {0, 0ULL}; + QUICAckFrame::AckBlock _current_block = {static_cast(0), 0ULL}; }; AckBlockSection(uint64_t first_ack_block_length); diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 2a79560371a..faf664a97a8 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -64,7 +64,7 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size) // TODO: check debug build if (frame->type() != QUICFrameType::PADDING) { - Debug(tag, "frame type %d, size %zu", frame->type(), frame->size()); + Debug(tag, "frame type %d, size %zu", static_cast(frame->type()), frame->size()); } // FIXME We should probably use a mapping table. All the objects has the common interface (QUICFrameHandler). @@ -138,7 +138,7 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size) } default: // Unknown frame - Debug(tag, "Unknown frame type: %02x", frame->type()); + Debug(tag, "Unknown frame type: %02x", static_cast(frame->type())); ink_assert(false); break; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index e4221ae1345..b1761b62152 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -30,7 +30,7 @@ #define I_WANNA_DUMP_THIS_BUF(buf, len) \ { \ int i, j; \ - fprintf(stderr, "len=%lld\n", len); \ + fprintf(stderr, "len=%ld\n", len); \ for (i = 0; i < len / 8; i++) { \ fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x ", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3], \ buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6], buf[i * 8 + 7]); \ diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index c5bb46efbf9..6499772d9c0 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -52,7 +52,7 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) this->_handle_stream_frame(std::dynamic_pointer_cast(frame)); break; default: - Debug(tag, "Unexpected frame type: %02x", frame->type()); + Debug(tag, "Unexpected frame type: %02x", static_cast(frame->type())); ink_assert(false); break; } diff --git a/proxy/hq/HQSessionAccept.h b/proxy/hq/HQSessionAccept.h index 68fb584ec16..16abc410449 100644 --- a/proxy/hq/HQSessionAccept.h +++ b/proxy/hq/HQSessionAccept.h @@ -38,7 +38,8 @@ // // CONFIG proxy.config.http.server_ports STRING 443:quic -class HQSessionAccept : public SessionAccept { +class HQSessionAccept : public SessionAccept +{ public: explicit HQSessionAccept(const HttpSessionAccept::Options &); ~HQSessionAccept(); From a080d20eff91423956bed23f4f57879cb1d8e1a4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 9 Aug 2017 10:26:37 +0900 Subject: [PATCH 0003/1313] Use cross-platform print format --- iocore/net/QUICNetVConnection.cc | 4 ++-- iocore/net/QUICPacketHandler.cc | 4 ++-- iocore/net/quic/QUICHandshake.cc | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 1ff56e3f99a..afb42261681 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -413,8 +413,8 @@ QUICNetVConnection::_state_connection_established_process_packet(std::unique_ptr if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, packet->payload(), packet->payload_size(), packet->packet_number(), packet->header(), packet->header_size(), packet->key_phase())) { - Debug(tag, "Decrypt Packet, pkt_num: %lu, header_len: %hu, payload_len: %zu", packet->packet_number(), packet->header_size(), - plain_txt_len); + Debug(tag, "Decrypt Packet, pkt_num: %" PRIu64 ", header_len: %hu, payload_len: %zu", packet->packet_number(), + packet->header_size(), plain_txt_len); this->_recv_and_ack(plain_txt.get(), plain_txt_len, packet->packet_number()); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 59ea5cc3207..47e050505b1 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -67,7 +67,7 @@ QUICPacketHandler::acceptEvent(int event, void *data) UDPPacket *packet_r; ip_port_text_buffer ipb; while ((packet_r = queue->dequeue())) { - Debug("quic_sec", "received packet from %s, size=%ld", ats_ip_nptop(&packet_r->from.sa, ipb, sizeof(ipb)), + Debug("quic_sec", "received packet from %s, size=%" PRId64, ats_ip_nptop(&packet_r->from.sa, ipb, sizeof(ipb)), packet_r->getPktLength()); this->_recv_packet(event, packet_r); } @@ -142,7 +142,7 @@ QUICPacketHandler::send_packet(const QUICPacket &packet, QUICNetVConnection *vc) // NOTE: p will be enqueued to udpOutQueue of UDPNetHandler ip_port_text_buffer ipb; - Debug("quic_sec", "send %s packet to %s, size=%ld", QUICDebugNames::packet_type(packet.type()), + Debug("quic_sec", "send %s packet to %s, size=%" PRId64, QUICDebugNames::packet_type(packet.type()), ats_ip_nptop(&udpPkt->to.sa, ipb, sizeof(ipb)), udpPkt->getPktLength()); vc->get_udp_con()->send(this, udpPkt); } diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index b1761b62152..f5b0753431a 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -30,7 +30,7 @@ #define I_WANNA_DUMP_THIS_BUF(buf, len) \ { \ int i, j; \ - fprintf(stderr, "len=%ld\n", len); \ + fprintf(stderr, "len=%" PRId64 "\n", len); \ for (i = 0; i < len / 8; i++) { \ fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x ", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3], \ buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6], buf[i * 8 + 7]); \ From 7052a17f4e884e013d6efc78167375a6e2787093 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 9 Aug 2017 15:20:35 +0900 Subject: [PATCH 0004/1313] Close QUIC Connection by inactivity timeout --- iocore/net/P_QUICNetVConnection.h | 30 +++++++++--- iocore/net/P_UnixNetVConnection.h | 15 +++--- iocore/net/QUICNetVConnection.cc | 75 +++++++++++++++++++++++++++-- iocore/net/quic/QUICEvents.h | 1 + iocore/net/quic/QUICLossDetector.cc | 14 +++++- iocore/net/quic/QUICLossDetector.h | 1 + 6 files changed, 114 insertions(+), 22 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e0bd7cc4223..09caae268e2 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -93,6 +93,15 @@ typedef enum { QUIC_HOOK_OP_LAST = QUIC_HOOK_OP_TERMINATE ///< End marker value. } QuicVConnOp; +enum class QUICConnectionState { + Open = 0, + Handshake, + Established, + TimeWait, + Closing, + Closed, +}; + ////////////////////////////////////////////////////////////////// // // class NetVConnection @@ -113,20 +122,23 @@ class QUICLossDetector; * * state_handshake() * | READ: - * | _state_handshake_process_initial_client_packet() - * | _state_handshake_process_client_cleartext_packet() - * | _state_handshake_process_zero_rtt_protected_packet() + * | _state_handshake_process_initial_client_packet() + * | _state_handshake_process_client_cleartext_packet() + * | _state_handshake_process_zero_rtt_protected_packet() * | WRITE: - * | _state_common_send_packet() + * | _state_common_send_packet() * v * state_connection_established() * | READ: - * | _state_connection_established_process_packet() + * | _state_connection_established_process_packet() * | WRITE: - * | _state_common_send_packet() + * | _state_common_send_packet() * v - * X - * + * state_connection_close() + * READ: + * Do nothing + * WRITE: + * _state_common_send_packet() **/ class QUICNetVConnection : public UnixNetVConnection, public QUICPacketTransmitter, public QUICFrameTransmitter { @@ -143,6 +155,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICPacketTransmitt int startEvent(int event, Event *e); int state_handshake(int event, Event *data); int state_connection_established(int event, Event *data); + int state_connection_closed(int event, Event *data); void start(SSL_CTX *); uint32_t maximum_quic_packet_size(); uint32_t minimum_quic_packet_size(); @@ -168,6 +181,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICPacketTransmitt QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; QUICAckFrameCreator _ack_frame_creator; + QUICConnectionState _state = QUICConnectionState::Open; uint32_t _pmtu = 1280; diff --git a/iocore/net/P_UnixNetVConnection.h b/iocore/net/P_UnixNetVConnection.h index c86a136ef16..91b8d2c5b0b 100644 --- a/iocore/net/P_UnixNetVConnection.h +++ b/iocore/net/P_UnixNetVConnection.h @@ -150,14 +150,14 @@ class UnixNetVConnection : public NetVConnection // called when handing an event from this NetVConnection,// // or the NetVConnection creation callback. // //////////////////////////////////////////////////////////// - void set_active_timeout(ink_hrtime timeout_in) override; - void set_inactivity_timeout(ink_hrtime timeout_in) override; - void cancel_active_timeout() override; - void cancel_inactivity_timeout() override; + virtual void set_active_timeout(ink_hrtime timeout_in) override; + virtual void set_inactivity_timeout(ink_hrtime timeout_in) override; + virtual void cancel_active_timeout() override; + virtual void cancel_inactivity_timeout() override; void set_action(Continuation *c) override; - void add_to_keep_alive_queue() override; - void remove_from_keep_alive_queue() override; - bool add_to_active_queue() override; + virtual void add_to_keep_alive_queue() override; + virtual void remove_from_keep_alive_queue() override; + virtual bool add_to_active_queue() override; virtual void remove_from_active_queue(); // The public interface is VIO::reenable() @@ -432,5 +432,6 @@ UnixNetVConnection::set_action(Continuation *c) void close_UnixNetVConnection(UnixNetVConnection *vc, EThread *t); void write_to_net(NetHandler *nh, UnixNetVConnection *vc, EThread *thread); void write_to_net_io(NetHandler *nh, UnixNetVConnection *vc, EThread *thread); +void net_activity(UnixNetVConnection *vc, EThread *thread); #endif diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index afb42261681..5eb413038c4 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -49,6 +49,7 @@ ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); QUICNetVConnection::QUICNetVConnection() : UnixNetVConnection() { + this->_state = QUICConnectionState::Handshake; SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_handshake); } @@ -99,16 +100,13 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) std::shared_ptr congestionController = std::make_shared(); this->_frame_dispatcher = new QUICFrameDispatcher(connectionManager, this->_stream_manager, flowController, congestionController, this->_loss_detector); - - // TODO set timeout from conf - this->set_active_timeout(0); - this->set_inactivity_timeout(2); } -// TODO: call free when close connection void QUICNetVConnection::free(EThread *t) { + Debug(tag, "Free connection: %p", this); + this->_udp_con = nullptr; this->_packet_handler = nullptr; @@ -215,6 +213,7 @@ QUICNetVConnection::close(QUICError error) this->transmit_frame(QUICFrameFactory::create_connection_close_frame(error.code, 0, "")); } +// TODO: Timeout by active_timeout / inactive_timeout int QUICNetVConnection::state_handshake(int event, Event *data) { @@ -231,6 +230,8 @@ QUICNetVConnection::state_handshake(int event, Event *data) switch (event) { case QUIC_EVENT_PACKET_READ_READY: { std::unique_ptr p = std::unique_ptr(this->_packet_recv_queue.dequeue()); + net_activity(this, this_ethread()); + switch (p->type()) { case QUICPacketType::CLIENT_INITIAL: error = this->_state_handshake_process_initial_client_packet(std::move(p)); @@ -263,7 +264,14 @@ QUICNetVConnection::state_handshake(int event, Event *data) if (this->_handshake_handler && this->_handshake_handler->is_completed()) { Debug(tag, "Enter state_connection_established"); + this->_state = QUICConnectionState::Established; SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); + + // TODO: switch waiting for a CONNECTION_CLOSE frame for first implementation + // TODO: read idle_timeout from Transport Prameters + ink_hrtime idle_timeout = HRTIME_SECONDS(3); + this->set_inactivity_timeout(idle_timeout); + this->add_to_active_queue(); } return EVENT_CONT; @@ -276,6 +284,8 @@ QUICNetVConnection::state_connection_established(int event, Event *data) switch (event) { case QUIC_EVENT_PACKET_READ_READY: { std::unique_ptr p = std::unique_ptr(this->_packet_recv_queue.dequeue()); + net_activity(this, this_ethread()); + switch (p->type()) { case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: @@ -291,6 +301,22 @@ QUICNetVConnection::state_connection_established(int event, Event *data) error = this->_state_common_send_packet(); break; } + + case EVENT_IMMEDIATE: { + // Start Implicit Shutdown. Because no network activity for the duration of the idle timeout. + this->remove_from_active_queue(); + + // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application + Debug(tag, "Enter state_connection_close"); + this->_state = QUICConnectionState::Closing; + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); + + this->close({QUICErrorClass::NONE, QUICErrorCode::QUIC_TRANSPORT_ERROR}); + + break; + } + default: + Debug(tag, "Unexpected event: %u", event); } if (error.cls != QUICErrorClass::NONE) { @@ -301,6 +327,43 @@ QUICNetVConnection::state_connection_established(int event, Event *data) return EVENT_CONT; } +int +QUICNetVConnection::state_connection_closed(int event, Event *data) +{ + switch (event) { + case QUIC_EVENT_PACKET_READ_READY: { + // TODO: send GOAWAY frame + break; + } + case QUIC_EVENT_PACKET_WRITE_READY: { + // TODO: Retransmit CONNECTION_CLOSE when Explicit Shutdown (Out of scope from first implementation) + // Inplicit Shutdown + if (this->_state == QUICConnectionState::Closing) { + this->_state_common_send_packet(); + this->_state = QUICConnectionState::Closed; + + this->next_inactivity_timeout_at = 0; + this->next_activity_timeout_at = 0; + + this->inactivity_timeout_in = 0; + this->active_timeout_in = 0; + + // TODO: Drop record from Connection-ID - QUICNetVConnection table in QUICPacketHandler + // Shutdown loss detector + this->_loss_detector->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); + + this->free(this_ethread()); + } + + break; + } + default: + Debug(tag, "Unexpected event: %u", event); + } + + return EVENT_DONE; +} + UDPConnection * QUICNetVConnection::get_udp_con() { @@ -437,6 +500,8 @@ QUICNetVConnection::_state_common_send_packet() this->_loss_detector->on_packet_sent(std::unique_ptr(packet)); } + net_activity(this, this_ethread()); + return QUICError(QUICErrorClass::NONE); } diff --git a/iocore/net/quic/QUICEvents.h b/iocore/net/quic/QUICEvents.h index 1a8a9b2d9c2..de27a7863b5 100644 --- a/iocore/net/quic/QUICEvents.h +++ b/iocore/net/quic/QUICEvents.h @@ -28,4 +28,5 @@ enum { QUIC_EVENT_PACKET_READ_READY = QUIC_EVENT_EVENTS_START, QUIC_EVENT_PACKET_WRITE_READY, + QUIC_EVENT_LD_SHUTDOWN, }; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 5ffc58f4621..4e2cdbf735b 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -53,9 +53,19 @@ int QUICLossDetector::event_handler(int event, Event *edata) { switch (event) { - case EVENT_INTERVAL: + case EVENT_INTERVAL: { this->_on_loss_detection_alarm(); break; + } + case QUIC_EVENT_LD_SHUTDOWN: { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + Debug("quic_loss_detector", "Shutdown"); + + if (this->_loss_detection_alarm) { + this->_loss_detection_alarm->cancel(); + } + break; + } default: break; } @@ -121,7 +131,7 @@ QUICLossDetector::on_packet_sent(std::unique_ptr packet) { bool is_handshake = false; QUICPacketType type = packet->type(); - if (type != QUICPacketType::ZERO_RTT_PROTECTED || type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 || + if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { is_handshake = true; } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 0a2b71cc996..7d6f325c155 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -100,6 +100,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _detect_lost_packets(QUICPacketNumber largest_acked); void _set_loss_detection_alarm(); void _on_loss_detection_alarm(); + std::set _determine_newly_acked_packets(const QUICAckFrame &ack_frame); void _retransmit_handshake_packets(); From 7ee8f3966b75092a5045fe0b9413368d20d17278 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 10 Aug 2017 11:57:18 +0900 Subject: [PATCH 0005/1313] Fix build warnings on Fedora 26 --- iocore/net/quic/QUICCongestionController.cc | 2 +- iocore/net/quic/QUICConnectionManager.cc | 2 +- iocore/net/quic/QUICLossDetector.cc | 6 +++--- iocore/net/quic/QUICPacket.cc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 79df5d855a1..2584c35d6c3 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -33,7 +33,7 @@ QUICCongestionController::handle_frame(std::shared_ptr frame) case QUICFrameType::ACK: break; default: - Debug(tag, "Unexpected frame type: %02x", frame->type()); + Debug(tag, "Unexpected frame type: %02x", static_cast(frame->type())); ink_assert(false); break; } diff --git a/iocore/net/quic/QUICConnectionManager.cc b/iocore/net/quic/QUICConnectionManager.cc index fc1240b3144..85654f24d20 100644 --- a/iocore/net/quic/QUICConnectionManager.cc +++ b/iocore/net/quic/QUICConnectionManager.cc @@ -35,7 +35,7 @@ QUICConnectionManager::handle_frame(std::shared_ptr frame) case QUICFrameType::PING: break; default: - Debug(tag, "Unexpected frame type: %02x", frame->type()); + Debug(tag, "Unexpected frame type: %02x", static_cast(frame->type())); ink_assert(false); break; } diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 4e2cdbf735b..f30d69a0075 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -34,7 +34,7 @@ QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter) : _transm this->_tlp_count = 0; this->_rto_count = 0; if (this->_time_loss_detection) { - this->_reordering_threshold = INFINITY; + this->_reordering_threshold = UINT32_MAX; this->_time_reordering_fraction = this->_TIME_REORDERING_FRACTION; } else { this->_reordering_threshold = this->_REORDERING_THRESHOLD; @@ -80,7 +80,7 @@ QUICLossDetector::handle_frame(std::shared_ptr frame) this->_on_ack_received(std::dynamic_pointer_cast(frame)); break; default: - Debug("quic_loss_detector", "Unexpected frame type: %02x", frame->type()); + Debug("quic_loss_detector", "Unexpected frame type: %02x", static_cast(frame->type())); ink_assert(false); break; } @@ -188,7 +188,7 @@ void QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - Debug("quic_loss_detector", "Packet number %llu has been acked", acked_packet_number); + Debug("quic_loss_detector", "Packet number %" PRIu64 " has been acked", acked_packet_number); this->_largest_acked_packet = acked_packet_number; // If a packet sent prior to RTO was acked, then the RTO // was spurious. Otherwise, inform congestion control. diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 135dd85ee94..8b41218cbdf 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -636,7 +636,7 @@ QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, packet->payload(), packet->payload_size(), packet->packet_number(), ad, ad_len, packet->key_phase())) { packet->set_protected_payload(std::move(cipher_txt), cipher_txt_len); - Debug("quic_packet_factory", "Encrypt Packet, pkt_num: %llu, header_len: %zu payload: %zu", packet->packet_number(), ad_len, + Debug("quic_packet_factory", "Encrypt Packet, pkt_num: %" PRIu64 ", header_len: %zu payload: %zu", packet->packet_number(), ad_len, cipher_txt_len); return packet; } else { From b51be170deb0cec505233b912e9b80c72d33913b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 10 Aug 2017 12:15:21 +0900 Subject: [PATCH 0006/1313] Fix a build error on Fedora 26 swap() in Vec.h was actually a global function, and it seems like the function confuses gcc 7.1.1 if we use unique_ptr in some situation. --- lib/ts/Vec.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/ts/Vec.h b/lib/ts/Vec.h index 00da28fa16b..ff7d815c8aa 100644 --- a/lib/ts/Vec.h +++ b/lib/ts/Vec.h @@ -149,7 +149,7 @@ class Vec int read(int fd); void qsort(bool (*lt)(C, C)); void qsort(bool (*lt)(const C &, const C &)); - void swap(C *p1, C *p2); + static void swap(C *p1, C *p2); private: void move_internal(Vec &v); @@ -950,9 +950,9 @@ Vec::read(int fd) return t; } -template +template inline void -swap(C *p1, C *p2) +Vec::swap(C *p1, C *p2) { C t = *p1; *p1 = *p2; @@ -979,15 +979,15 @@ qsort_Vec(C *left, C *right, bool (*lt)(C, C)) // find the median if (lt(*center, *left)) { // order left and center - swap(center, left); + Vec::swap(center, left); } if (lt(*(right - 1), *left)) { // order left and right - swap(right - 1, left); + Vec::swap(right - 1, left); } if (lt(*(right - 1), *center)) { // order right and center - swap((right - 1), center); + Vec::swap((right - 1), center); } - swap(center, right - 2); // stash the median one from the right for now + Vec::swap(center, right - 2); // stash the median one from the right for now median = *(right - 2); // the median of left, center and right values // now partition, pivoting on the median value @@ -1011,12 +1011,12 @@ qsort_Vec(C *left, C *right, bool (*lt)(C, C)) if (lt(*l, median)) { l++; } else { - swap(l, r - 1); + Vec::swap(l, r - 1); r--; } } - swap(l, right - 2); // restore median to its rightful place + Vec::swap(l, right - 2); // restore median to its rightful place // recurse for the littles (left segment) qsort_Vec(left, l, lt); @@ -1045,15 +1045,15 @@ qsort_VecRef(C *left, C *right, bool (*lt)(const C &, const C &), unsigned int * // find the median if (lt(*center, *left)) { // order left and center - swap(center, left); + Vec::swap(center, left); } if (lt(*(right - 1), *left)) { // order left and right - swap(right - 1, left); + Vec::swap(right - 1, left); } if (lt(*(right - 1), *center)) { // order right and center - swap((right - 1), center); + Vec::swap((right - 1), center); } - swap(center, right - 2); // stash the median one from the right for now + Vec::swap(center, right - 2); // stash the median one from the right for now median = *(right - 2); // the median of left, center and right values // now partition, pivoting on the median value @@ -1077,12 +1077,12 @@ qsort_VecRef(C *left, C *right, bool (*lt)(const C &, const C &), unsigned int * if (lt(*l, median)) { l++; } else { - swap(l, r - 1); + Vec::swap(l, r - 1); r--; } } - swap(l, right - 2); // restore median to its rightful place + Vec::swap(l, right - 2); // restore median to its rightful place // recurse for the littles (left segment) qsort_VecRef(left, l, lt, p_ctr); From 43a9f9ec1f639ef7dc9d9de6e37daf252d617bbd Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 10 Aug 2017 15:58:46 +0900 Subject: [PATCH 0007/1313] Fix an runtime error on Fedora 26 Make sure that all information are extracted from a packet before std::move release it when passing the infomation and the packet at the same time. --- iocore/net/quic/QUICLossDetector.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index f30d69a0075..4c1031471d8 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -135,8 +135,11 @@ QUICLossDetector::on_packet_sent(std::unique_ptr packet) type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { is_handshake = true; } - return this->_on_packet_sent(packet->packet_number(), packet->is_retransmittable(), is_handshake, packet->size(), - std::move(packet)); + + QUICPacketNumber packet_number = packet->packet_number(); + bool is_retransmittable = packet->is_retransmittable(); + size_t sent_bytes = packet->size(); + return this->_on_packet_sent(packet_number, is_retransmittable, is_handshake, sent_bytes, std::move(packet)); } void From fc797a0838dd8d6c62a9a068b1e8c730d98ac780 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 10 Aug 2017 16:11:46 +0900 Subject: [PATCH 0008/1313] Fix a runtime error on Fedora 26 operator[] of std::map try to create a value if the key doesn't exist, which we don't want to because it would be a shared_ptr. Use find() instead. --- iocore/net/quic/QUICStream.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 1e820952e51..f80ed0f7380 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -235,9 +235,10 @@ QUICStream::_write_to_read_vio(std::shared_ptr frame) void QUICStream::_reorder_data() { - while (auto frame = _request_stream_frame_buffer[this->_request_buffer_offset]) { - this->_request_stream_frame_buffer.erase(this->_request_buffer_offset); - this->_write_to_read_vio(frame); + auto frame = _request_stream_frame_buffer.find(this->_request_buffer_offset); + while (frame != this->_request_stream_frame_buffer.end()) { + this->_write_to_read_vio(frame->second); + frame = _request_stream_frame_buffer.find(this->_request_buffer_offset); } } From e8c6b978ed02ea96b80901f662a47a07d89c34ef Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 10 Aug 2017 15:34:56 +0900 Subject: [PATCH 0009/1313] Add QUICConfig and proxy.config.quic.no_activity_timeout_in Add QUICConfig class to load configs related to QUIC. "proxy.config.quic.no_activity_timeout_in" is also added. Default value is 30 seconds. --- iocore/net/QUICNetProcessor.cc | 6 +-- iocore/net/QUICNetVConnection.cc | 8 ++-- iocore/net/quic/Makefile.am | 1 + iocore/net/quic/QUICConfig.cc | 74 ++++++++++++++++++++++++++++++++ iocore/net/quic/QUICConfig.h | 51 ++++++++++++++++++++++ mgmt/RecordsConfig.cc | 8 ++++ 6 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 iocore/net/quic/QUICConfig.cc create mode 100644 iocore/net/quic/QUICConfig.h diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 40eb37e3575..7500ab1093b 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -24,6 +24,7 @@ #include "P_Net.h" #include "ts/I_Layout.h" #include "I_RecHttp.h" +#include "QUICConfig.h" // #include "P_QUICUtils.h" // @@ -52,10 +53,7 @@ QUICNetProcessor::start(int, size_t stacksize) { // This initialization order matters ... // QUICInitializeLibrary(); - // QUICConfig::startup(); - - // if (!QUICCertificateConfig::startup()) - // return -1; + QUICConfig::startup(); // Acquire a QUICConfigParams instance *after* we start QUIC up. // QUICConfig::scoped_config params; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5eb413038c4..9898712e0ee 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -36,6 +36,7 @@ #include "QUICEchoApp.h" #include "QUICDebugNames.h" #include "QUICEvents.h" +#include "QUICConfig.h" #define STATE_FROM_VIO(_x) ((NetState *)(((char *)(_x)) - STATE_VIO_OFFSET)) #define STATE_VIO_OFFSET ((uintptr_t) & ((NetState *)0)->vio) @@ -267,9 +268,10 @@ QUICNetVConnection::state_handshake(int event, Event *data) this->_state = QUICConnectionState::Established; SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); - // TODO: switch waiting for a CONNECTION_CLOSE frame for first implementation - // TODO: read idle_timeout from Transport Prameters - ink_hrtime idle_timeout = HRTIME_SECONDS(3); + QUICConfig::scoped_config params; + + // TODO: use idle_timeout from negotiated Transport Prameters + ink_hrtime idle_timeout = HRTIME_SECONDS(params->no_activity_timeout_in()); this->set_inactivity_timeout(idle_timeout); this->add_to_active_queue(); } diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index b0b799aecaa..714874c70cd 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -56,6 +56,7 @@ libquic_a_SOURCES = \ QUICCrypto.cc \ $(QUICCrypto_impl) \ QUICAckFrameCreator.cc \ + QUICConfig.cc \ QUICDebugNames.cc \ QUICApplication.cc \ QUICEchoApp.cc diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc new file mode 100644 index 00000000000..64b8e906628 --- /dev/null +++ b/iocore/net/quic/QUICConfig.cc @@ -0,0 +1,74 @@ +/** @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 "QUICConfig.h" + +#include + +int QUICConfig::_config_id = 0; + +// +// QUICConfigParams +// +void +QUICConfigParams::initialize() +{ + REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_in, "proxy.config.quic.no_activity_timeout_in"); +} + +uint32_t +QUICConfigParams::no_activity_timeout_in() const +{ + return this->_no_activity_timeout_in; +} + +// +// QUICConfig +// +void +QUICConfig::startup() +{ + reconfigure(); +} + +void +QUICConfig::reconfigure() +{ + QUICConfigParams *params; + params = new QUICConfigParams; + // re-read configuration + params->initialize(); + _config_id = configProcessor.set(_config_id, params); +} + +QUICConfigParams * +QUICConfig::acquire() +{ + return static_cast(configProcessor.get(_config_id)); +} + +void +QUICConfig::release(QUICConfigParams *params) +{ + configProcessor.release(_config_id, params); +} diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h new file mode 100644 index 00000000000..e4139bb8b65 --- /dev/null +++ b/iocore/net/quic/QUICConfig.h @@ -0,0 +1,51 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ProxyConfig.h" + +class QUICConfigParams : public ConfigInfo +{ +public: + void initialize(); + + uint32_t no_activity_timeout_in() const; + +private: + uint32_t _no_activity_timeout_in = 0; +}; + +class QUICConfig +{ +public: + static void startup(); + static void reconfigure(); + static QUICConfigParams *acquire(); + static void release(QUICConfigParams *params); + + using scoped_config = ConfigProcessor::scoped_config; + +private: + static int _config_id; +}; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 39bce056baf..f16fd2bf363 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1328,6 +1328,14 @@ static const RecordElement RecordsConfig[] = {RECT_CONFIG, "proxy.config.http2.active_timeout_in", RECD_INT, "900", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} , + //############ + //# + //# QUIC global configuration. + //# + //############ + {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_in", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + //# Add LOCAL Records Here {RECT_LOCAL, "proxy.local.incoming_ip_to_bind", RECD_STRING, nullptr, RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , From e95c8f38ca1d029a2218d16d4295a4e10200e2ac Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 14 Aug 2017 10:43:48 +0900 Subject: [PATCH 0010/1313] Print Connection ID on debug logs in QUICNetVConnection --- iocore/net/QUICNetVConnection.cc | 43 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 9898712e0ee..08477fe4f25 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -41,7 +41,8 @@ #define STATE_FROM_VIO(_x) ((NetState *)(((char *)(_x)) - STATE_VIO_OFFSET)) #define STATE_VIO_OFFSET ((uintptr_t) & ((NetState *)0)->vio) -const static char *tag = "quic_net"; +#define DebugQUICCon(fmt, ...) \ + Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) const static uint32_t MINIMUM_MTU = 1280; const static uint32_t MAX_PACKET_OVERHEAD = 25; // Max long header len(17) + FNV-1a hash len(8) @@ -106,7 +107,7 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) void QUICNetVConnection::free(EThread *t) { - Debug(tag, "Free connection: %p", this); + DebugQUICCon("Free connection"); this->_udp_con = nullptr; this->_packet_handler = nullptr; @@ -196,14 +197,14 @@ QUICNetVConnection::get_transmitter_mutex() void QUICNetVConnection::push_packet(std::unique_ptr packet) { - Debug(tag, "Type=%s Size=%u", QUICDebugNames::packet_type(packet->type()), packet->size()); + DebugQUICCon("Type=%s Size=%u", QUICDebugNames::packet_type(packet->type()), packet->size()); this->_packet_recv_queue.enqueue(const_cast(packet.release())); } void QUICNetVConnection::transmit_frame(std::unique_ptr frame) { - Debug(tag, "Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); + DebugQUICCon("Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); this->_frame_buffer.push(std::move(frame)); eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); } @@ -255,16 +256,16 @@ QUICNetVConnection::state_handshake(int event, Event *data) break; } default: - Debug(tag, "Unexpected event: %u", event); + DebugQUICCon("Unexpected event: %u", event); } if (error.cls != QUICErrorClass::NONE) { // TODO: Send error if needed - Debug(tag, "QUICError: cls=%u, code=0x%x", static_cast(error.cls), static_cast(error.code)); + DebugQUICCon("QUICError: cls=%u, code=0x%x", static_cast(error.cls), static_cast(error.code)); } if (this->_handshake_handler && this->_handshake_handler->is_completed()) { - Debug(tag, "Enter state_connection_established"); + DebugQUICCon("Enter state_connection_established"); this->_state = QUICConnectionState::Established; SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); @@ -309,7 +310,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) this->remove_from_active_queue(); // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application - Debug(tag, "Enter state_connection_close"); + DebugQUICCon("Enter state_connection_close"); this->_state = QUICConnectionState::Closing; SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); @@ -318,12 +319,12 @@ QUICNetVConnection::state_connection_established(int event, Event *data) break; } default: - Debug(tag, "Unexpected event: %u", event); + DebugQUICCon("Unexpected event: %u", event); } if (error.cls != QUICErrorClass::NONE) { // TODO: Send error if needed - Debug(tag, "QUICError: cls=%u, code=0x%x", static_cast(error.cls), static_cast(error.code)); + DebugQUICCon("QUICError: cls=%u, code=0x%x", static_cast(error.cls), static_cast(error.code)); } return EVENT_CONT; @@ -360,7 +361,7 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) break; } default: - Debug(tag, "Unexpected event: %u", event); + DebugQUICCon("Unexpected event: %u", event); } return EVENT_DONE; @@ -379,7 +380,7 @@ QUICNetVConnection::get_application(QUICStreamId stream_id) return static_cast(this->_handshake_handler); } else { if (!this->_application) { - Debug(tag, "setup quic application"); + DebugQUICCon("setup quic application"); // TODO: Instantiate negotiated application const uint8_t *application = this->_handshake_handler->negotiated_application_name(); if (memcmp(application, "hq", 2) == 0) { @@ -427,17 +428,17 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_p } if (packet->version()) { if (this->_version_negotiator->negotiate(packet.get()) == QUICVersionNegotiationStatus::NEGOTIATED) { - Debug(tag, "Version negotiation succeeded: %x", packet->version()); + DebugQUICCon("Version negotiation succeeded: %x", packet->version()); this->_packet_factory.set_version(packet->version()); // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing) if (packet->has_valid_fnv1a_hash()) { this->_handshake_handler = new QUICHandshake(new_ProxyMutex(), this); this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size()); } else { - Debug(tag, "Invalid FNV-1a hash value"); + DebugQUICCon("Invalid FNV-1a hash value"); } } else { - Debug(tag, "Version negotiation failed: %x", packet->version()); + DebugQUICCon("Version negotiation failed: %x", packet->version()); } } else { return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); @@ -454,7 +455,7 @@ QUICNetVConnection::_state_handshake_process_client_cleartext_packet(std::unique if (packet->has_valid_fnv1a_hash()) { this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); } else { - Debug(tag, "Invalid FNV-1a hash value"); + DebugQUICCon("Invalid FNV-1a hash value"); } return QUICError(QUICErrorClass::NONE); } @@ -478,14 +479,14 @@ QUICNetVConnection::_state_connection_established_process_packet(std::unique_ptr if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, packet->payload(), packet->payload_size(), packet->packet_number(), packet->header(), packet->header_size(), packet->key_phase())) { - Debug(tag, "Decrypt Packet, pkt_num: %" PRIu64 ", header_len: %hu, payload_len: %zu", packet->packet_number(), - packet->header_size(), plain_txt_len); + DebugQUICCon("Decrypt Packet, pkt_num: %" PRIu64 ", header_len: %hu, payload_len: %zu", packet->packet_number(), + packet->header_size(), plain_txt_len); this->_recv_and_ack(plain_txt.get(), plain_txt_len, packet->packet_number()); return QUICError(QUICErrorClass::NONE); } else { - Debug(tag, "CRYPTOGRAPHIC Error"); + DebugQUICCon("CRYPTOGRAPHIC Error"); return QUICError(QUICErrorClass::CRYPTOGRAPHIC); } @@ -543,7 +544,7 @@ QUICNetVConnection::_packetize_frames() buf = ats_unique_malloc(max_size); } size_t l = 0; - Debug(tag, "type=%s", QUICDebugNames::frame_type(frame->type())); + DebugQUICCon("type=%s", QUICDebugNames::frame_type(frame->type())); frame->store(buf.get() + len, &l); len += l; } @@ -576,7 +577,7 @@ std::unique_ptr QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type) { std::unique_ptr packet; - Debug(tag, "retransmittable %u", retransmittable); + DebugQUICCon("retransmittable %u", retransmittable); switch (type) { case QUICPacketType::SERVER_CLEARTEXT: From c4a8ea6adaf59b234f299f38935aa68362dc8617 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 14 Aug 2017 16:55:05 +0900 Subject: [PATCH 0011/1313] Handle CONNECTION_CLOSE frame on QUICNetVConnection Integrate QUICConnectionManager into QUICNetVConnection. --- iocore/net/P_QUICNetVConnection.h | 29 +++-- iocore/net/QUICNetVConnection.cc | 117 ++++++++++++------ iocore/net/quic/Makefile.am | 1 - iocore/net/quic/Mock.h | 87 ++++++------- ...ICConnectionManager.h => QUICConnection.h} | 14 +-- iocore/net/quic/QUICConnectionManager.cc | 42 ------- iocore/net/quic/QUICFrameDispatcher.cc | 11 +- iocore/net/quic/QUICFrameDispatcher.h | 6 +- iocore/net/quic/QUICFrameHandler.h | 1 + iocore/net/quic/QUICPacket.cc | 4 +- iocore/net/quic/test/Makefile.am | 2 - .../net/quic/test/test_QUICFrameDispatcher.cc | 8 +- 12 files changed, 162 insertions(+), 160 deletions(-) rename iocore/net/quic/{QUICConnectionManager.h => QUICConnection.h} (72%) delete mode 100644 iocore/net/quic/QUICConnectionManager.cc diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 09caae268e2..3bba2e87784 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -42,6 +42,7 @@ #include "ts/apidefs.h" #include "ts/List.h" +#include "quic/QUICConnection.h" #include "quic/QUICVersionNegotiator.h" #include "quic/QUICPacket.h" #include "quic/QUICFrame.h" @@ -52,10 +53,7 @@ #include "quic/QUICCrypto.h" #include "quic/QUICAckFrameCreator.h" #include "quic/QUICLossDetector.h" -#include "quic/QUICPacketTransmitter.h" -#include "quic/QUICFrameTransmitter.h" #include "quic/QUICStreamManager.h" -#include "quic/QUICConnectionManager.h" #include "quic/QUICFlowController.h" #include "quic/QUICCongestionController.h" @@ -134,13 +132,19 @@ class QUICLossDetector; * | WRITE: * | _state_common_send_packet() * v + * state_connection_closing() (If closing actively) + * | READ: + * | _state_connection_established_process_packet() + * | WRITE: + * | _state_common_send_packet() + * v * state_connection_close() * READ: * Do nothing * WRITE: * _state_common_send_packet() **/ -class QUICNetVConnection : public UnixNetVConnection, public QUICPacketTransmitter, public QUICFrameTransmitter +class QUICNetVConnection : public UnixNetVConnection, public QUICConnection { typedef UnixNetVConnection super; ///< Parent type. @@ -155,15 +159,12 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICPacketTransmitt int startEvent(int event, Event *e); int state_handshake(int event, Event *data); int state_connection_established(int event, Event *data); + int state_connection_closing(int event, Event *data); int state_connection_closed(int event, Event *data); void start(SSL_CTX *); uint32_t maximum_quic_packet_size(); uint32_t minimum_quic_packet_size(); - virtual void transmit_packet(std::unique_ptr packet) override; - virtual void retransmit_packet(const QUICPacket &packet) override; - virtual Ptr get_transmitter_mutex() override; void push_packet(std::unique_ptr packet); - virtual void transmit_frame(std::unique_ptr frame) override; void close(QUICError error); void free(EThread *t) override; @@ -174,6 +175,17 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICPacketTransmitt virtual void net_read_io(NetHandler *nh, EThread *lthread) override; virtual int64_t load_buffer_and_write(int64_t towrite, MIOBufferAccessor &buf, int64_t &total_written, int &needs) override; + // QUICConnection (QUICPacketTransmitter) + virtual void transmit_packet(std::unique_ptr packet) override; + virtual void retransmit_packet(const QUICPacket &packet) override; + virtual Ptr get_transmitter_mutex() override; + + // QUICConnection (QUICFrameTransmitter) + virtual void transmit_frame(std::unique_ptr frame) override; + + // QUICConnection (QUICFrameHandler) + void handle_frame(std::shared_ptr frame) override; + private: QUICConnectionId _quic_connection_id; UDPConnection *_udp_con = nullptr; @@ -209,6 +221,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICPacketTransmitt QUICError _state_handshake_process_client_cleartext_packet(std::unique_ptr packet); QUICError _state_handshake_process_zero_rtt_protected_packet(std::unique_ptr packet); QUICError _state_connection_established_process_packet(std::unique_ptr packet); + QUICError _state_common_receive_packet(); QUICError _state_common_send_packet(); Ptr _transmitter_mutex; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 08477fe4f25..da12ede3f5c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -97,11 +97,10 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) this->_stream_manager->init(this); this->_stream_manager->set_connection(this); // FIXME Want to remove; - std::shared_ptr connectionManager = std::make_shared(this); std::shared_ptr flowController = std::make_shared(); std::shared_ptr congestionController = std::make_shared(); this->_frame_dispatcher = - new QUICFrameDispatcher(connectionManager, this->_stream_manager, flowController, congestionController, this->_loss_detector); + new QUICFrameDispatcher(this, this->_stream_manager, flowController, congestionController, this->_loss_detector); } void @@ -212,7 +211,29 @@ QUICNetVConnection::transmit_frame(std::unique_ptrtransmit_frame(QUICFrameFactory::create_connection_close_frame(error.code, 0, "")); + if (this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closed) || + this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closing)) { + // do nothing + } else { + DebugQUICCon("Enter state_connection_closing"); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); + this->transmit_frame(QUICFrameFactory::create_connection_close_frame(error.code, 0, "")); + } +} + +void +QUICNetVConnection::handle_frame(std::shared_ptr frame) +{ + switch (frame->type()) { + case QUICFrameType::CONNECTION_CLOSE: + DebugQUICCon("Enter state_connection_closed"); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); + break; + default: + DebugQUICCon("Unexpected frame type: %02x", static_cast(frame->type())); + ink_assert(false); + break; + } } // TODO: Timeout by active_timeout / inactive_timeout @@ -286,18 +307,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) QUICError error; switch (event) { case QUIC_EVENT_PACKET_READ_READY: { - std::unique_ptr p = std::unique_ptr(this->_packet_recv_queue.dequeue()); - net_activity(this, this_ethread()); - - switch (p->type()) { - case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: - case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: - error = this->_state_connection_established_process_packet(std::move(p)); - break; - default: - error = QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); - break; - } + error = this->_state_common_receive_packet(); break; } case QUIC_EVENT_PACKET_WRITE_READY: { @@ -306,16 +316,11 @@ QUICNetVConnection::state_connection_established(int event, Event *data) } case EVENT_IMMEDIATE: { - // Start Implicit Shutdown. Because no network activity for the duration of the idle timeout. + // Start Implicit Shutdown. Because of no network activity for the duration of the idle timeout. this->remove_from_active_queue(); + this->close({}); // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application - DebugQUICCon("Enter state_connection_close"); - this->_state = QUICConnectionState::Closing; - SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); - - this->close({QUICErrorClass::NONE, QUICErrorCode::QUIC_TRANSPORT_ERROR}); - break; } default: @@ -330,6 +335,32 @@ QUICNetVConnection::state_connection_established(int event, Event *data) return EVENT_CONT; } +int +QUICNetVConnection::state_connection_closing(int event, Event *data) +{ + QUICError error; + switch (event) { + case QUIC_EVENT_PACKET_READ_READY: { + error = this->_state_common_receive_packet(); + break; + } + case QUIC_EVENT_PACKET_WRITE_READY: { + this->_state_common_send_packet(); + break; + } + default: + DebugQUICCon("Unexpected event: %u", event); + } + + // FIXME Enter closed state if CONNECTION_CLOSE was ACKed + if (true) { + DebugQUICCon("Enter state_connection_closed"); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); + } + + return EVENT_DONE; +} + int QUICNetVConnection::state_connection_closed(int event, Event *data) { @@ -339,24 +370,17 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) break; } case QUIC_EVENT_PACKET_WRITE_READY: { - // TODO: Retransmit CONNECTION_CLOSE when Explicit Shutdown (Out of scope from first implementation) - // Inplicit Shutdown - if (this->_state == QUICConnectionState::Closing) { - this->_state_common_send_packet(); - this->_state = QUICConnectionState::Closed; - - this->next_inactivity_timeout_at = 0; - this->next_activity_timeout_at = 0; + this->next_inactivity_timeout_at = 0; + this->next_activity_timeout_at = 0; - this->inactivity_timeout_in = 0; - this->active_timeout_in = 0; + this->inactivity_timeout_in = 0; + this->active_timeout_in = 0; - // TODO: Drop record from Connection-ID - QUICNetVConnection table in QUICPacketHandler - // Shutdown loss detector - this->_loss_detector->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); + // TODO: Drop record from Connection-ID - QUICNetVConnection table in QUICPacketHandler + // Shutdown loss detector + this->_loss_detector->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); - this->free(this_ethread()); - } + this->free(this_ethread()); break; } @@ -492,6 +516,25 @@ QUICNetVConnection::_state_connection_established_process_packet(std::unique_ptr } } +QUICError +QUICNetVConnection::_state_common_receive_packet() +{ + QUICError error; + std::unique_ptr p = std::unique_ptr(this->_packet_recv_queue.dequeue()); + net_activity(this, this_ethread()); + + switch (p->type()) { + case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: + case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: + error = this->_state_connection_established_process_packet(std::move(p)); + break; + default: + error = QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + break; + } + return error; +} + QUICError QUICNetVConnection::_state_common_send_packet() { diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 714874c70cd..21e1fcad2c2 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -45,7 +45,6 @@ libquic_a_SOURCES = \ QUICFrame.cc \ QUICFrameDispatcher.cc \ QUICVersionNegotiator.cc \ - QUICConnectionManager.cc \ QUICLossDetector.cc \ QUICStreamManager.cc \ QUICFlowController.cc \ diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 9483ce3b469..164b80880ef 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -1,4 +1,3 @@ -#include "QUICConnectionManager.h" #include "QUICStreamManager.h" #include "QUICFlowController.h" #include "QUICCongestionController.h" @@ -6,10 +5,10 @@ #include "QUICEvents.h" #include "QUICPacketTransmitter.h" -class MockQUICPacketTransmitter : public QUICPacketTransmitter +class MockQUICConnection : public QUICConnection { public: - MockQUICPacketTransmitter() : QUICPacketTransmitter() { this->_mutex = new_ProxyMutex(); }; + MockQUICConnection() : QUICConnection() { this->_mutex = new_ProxyMutex(); }; void transmit_packet(std::unique_ptr packet) override @@ -29,76 +28,78 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter return this->_mutex; } - int _transmit_count = 0; - int _retransmit_count = 0; - Ptr _mutex; -}; - -class MockQUICFrameTransmitter : public QUICFrameTransmitter -{ void - transmit_frame(std::unique_ptr frame) + transmit_frame(std::unique_ptr frame) override { } -}; - -class MockQUICLossDetector : public QUICLossDetector -{ -public: - MockQUICLossDetector() : QUICLossDetector(new MockQUICPacketTransmitter()) {} void - rcv_frame(std::shared_ptr) + handle_frame(std::shared_ptr f) override { } - void - on_packet_sent(std::unique_ptr packet) + int + getTotalFrameCount() { + return _totalFrameCount; } + + int _transmit_count = 0; + int _retransmit_count = 0; + Ptr _mutex; + int _totalFrameCount = 0; }; -class MockQUICConnectionManager : public QUICConnectionManager +class MockQUICPacketTransmitter : public QUICPacketTransmitter { public: - MockQUICConnectionManager() : QUICConnectionManager(new MockQUICFrameTransmitter()) {} + MockQUICPacketTransmitter() : QUICPacketTransmitter() { this->_mutex = new_ProxyMutex(); }; - // Override - virtual void - handle_frame(std::shared_ptr f) override + void + transmit_packet(std::unique_ptr packet) override { - ++_frameCount[static_cast(f->type())]; - ++_totalFrameCount; + ++_transmit_count; } - // for Test - int - getStreamFrameCount() + void + retransmit_packet(const QUICPacket &packet) override { - return _frameCount[static_cast(QUICFrameType::STREAM)]; + ++_retransmit_count; } - int - getAckFrameCount() + Ptr + get_transmitter_mutex() override { - return _frameCount[static_cast(QUICFrameType::ACK)]; + return this->_mutex; } - int - getPingFrameCount() + int _transmit_count = 0; + int _retransmit_count = 0; + Ptr _mutex; +}; + +class MockQUICFrameTransmitter : public QUICFrameTransmitter +{ + void + transmit_frame(std::unique_ptr frame) { - return _frameCount[static_cast(QUICFrameType::PING)]; } +}; - int - getTotalFrameCount() +class MockQUICLossDetector : public QUICLossDetector +{ +public: + MockQUICLossDetector() : QUICLossDetector(new MockQUICPacketTransmitter()) {} + + void + rcv_frame(std::shared_ptr) { - return _totalFrameCount; } -private: - int _totalFrameCount = 0; - int _frameCount[256] = {0}; + void + on_packet_sent(std::unique_ptr packet) + { + } }; class MockQUICStreamManager : public QUICStreamManager diff --git a/iocore/net/quic/QUICConnectionManager.h b/iocore/net/quic/QUICConnection.h similarity index 72% rename from iocore/net/quic/QUICConnectionManager.h rename to iocore/net/quic/QUICConnection.h index 3a677343a93..bf71ba84cc9 100644 --- a/iocore/net/quic/QUICConnectionManager.h +++ b/iocore/net/quic/QUICConnection.h @@ -23,18 +23,10 @@ #pragma once -#include -#include +#include "QUICPacketTransmitter.h" #include "QUICFrameTransmitter.h" +#include "QUICFrameHandler.h" -class QUICConnectionManager : public QUICFrameHandler +class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler { -public: - QUICConnectionManager(QUICFrameTransmitter *tx) : _tx(tx){}; - virtual void handle_frame(std::shared_ptr frame) override; - -private: - QUICFrameTransmitter *_tx = nullptr; - - void _handle_ping_frame(const QUICPingFrame *); }; diff --git a/iocore/net/quic/QUICConnectionManager.cc b/iocore/net/quic/QUICConnectionManager.cc deleted file mode 100644 index 85654f24d20..00000000000 --- a/iocore/net/quic/QUICConnectionManager.cc +++ /dev/null @@ -1,42 +0,0 @@ -/** @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 - -const static char *tag = "quic_connection_manager"; - -void -QUICConnectionManager::handle_frame(std::shared_ptr frame) -{ - switch (frame->type()) { - case QUICFrameType::CONNECTION_CLOSE: - case QUICFrameType::STREAM: - case QUICFrameType::GOAWAY: - case QUICFrameType::PING: - break; - default: - Debug(tag, "Unexpected frame type: %02x", static_cast(frame->type())); - ink_assert(false); - break; - } -} diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index faf664a97a8..724e04f1398 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -22,7 +22,7 @@ */ #include "QUICFrameDispatcher.h" -#include "QUICConnectionManager.h" +#include "QUICConnection.h" #include "QUICStreamManager.h" #include "QUICFlowController.h" #include "QUICCongestionController.h" @@ -34,13 +34,12 @@ const static char *tag = "quic_frame_handler"; // // Frame Dispatcher // -QUICFrameDispatcher::QUICFrameDispatcher(const std::shared_ptr cmgr, - const std::shared_ptr smgr, +QUICFrameDispatcher::QUICFrameDispatcher(QUICConnection *connection, const std::shared_ptr smgr, const std::shared_ptr fctlr, const std::shared_ptr cctlr, const std::shared_ptr ld) { - connectionManager = cmgr; + this->_connection = connection; streamManager = smgr; flowController = fctlr; congestionController = cctlr; @@ -79,12 +78,11 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size) break; } case QUICFrameType::CONNECTION_CLOSE: { - connectionManager->handle_frame(frame); + this->_connection->handle_frame(frame); should_send_ack = true; break; } case QUICFrameType::GOAWAY: { - connectionManager->handle_frame(frame); should_send_ack = true; break; } @@ -103,7 +101,6 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size) break; } case QUICFrameType::PING: { - connectionManager->handle_frame(frame); should_send_ack = true; break; } diff --git a/iocore/net/quic/QUICFrameDispatcher.h b/iocore/net/quic/QUICFrameDispatcher.h index c16316b01bb..2fd7f34ab05 100644 --- a/iocore/net/quic/QUICFrameDispatcher.h +++ b/iocore/net/quic/QUICFrameDispatcher.h @@ -25,16 +25,16 @@ #include "QUICFrame.h" +class QUICConnection; class QUICStreamManager; class QUICFlowController; -class QUICConnectionManager; class QUICCongestionController; class QUICLossDetector; class QUICFrameDispatcher { public: - QUICFrameDispatcher(const std::shared_ptr cmgr, const std::shared_ptr smgr, + QUICFrameDispatcher(QUICConnection *connection, const std::shared_ptr smgr, const std::shared_ptr fctlr, const std::shared_ptr cctlr, const std::shared_ptr ld); /* @@ -42,12 +42,12 @@ class QUICFrameDispatcher */ bool receive_frames(const uint8_t *payload, uint16_t size); - std::shared_ptr connectionManager = nullptr; std::shared_ptr streamManager = nullptr; std::shared_ptr flowController = nullptr; std::shared_ptr congestionController = nullptr; std::shared_ptr lossDetector = nullptr; private: + QUICConnection *_connection = nullptr; QUICFrameFactory _frame_factory; }; diff --git a/iocore/net/quic/QUICFrameHandler.h b/iocore/net/quic/QUICFrameHandler.h index 6a99bac4f53..d4554fe8bfe 100644 --- a/iocore/net/quic/QUICFrameHandler.h +++ b/iocore/net/quic/QUICFrameHandler.h @@ -27,5 +27,6 @@ class QUICFrameHandler { +public: virtual void handle_frame(std::shared_ptr frame) = 0; }; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 8b41218cbdf..cb450803edf 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -636,8 +636,8 @@ QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, packet->payload(), packet->payload_size(), packet->packet_number(), ad, ad_len, packet->key_phase())) { packet->set_protected_payload(std::move(cipher_txt), cipher_txt_len); - Debug("quic_packet_factory", "Encrypt Packet, pkt_num: %" PRIu64 ", header_len: %zu payload: %zu", packet->packet_number(), ad_len, - cipher_txt_len); + Debug("quic_packet_factory", "Encrypt Packet, pkt_num: %" PRIu64 ", header_len: %zu payload: %zu", packet->packet_number(), + ad_len, cipher_txt_len); return packet; } else { Debug("quic_packet_factory", "CRYPTOGRAPHIC Error"); diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 1216cda8d55..5837352cf98 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -143,7 +143,6 @@ test_QUICFrameDispatcher_SOURCES = \ main.cc \ test_QUICFrameDispatcher.cc \ ../QUICFrameDispatcher.cc \ - ../QUICConnectionManager.cc \ ../QUICStreamManager.cc \ ../QUICFlowController.cc \ ../QUICCongestionController.cc \ @@ -210,7 +209,6 @@ test_QUICStream_SOURCES = \ test_QUICStream.cc \ ../QUICStream.cc \ ../QUICFrameDispatcher.cc \ - ../QUICConnectionManager.cc \ ../QUICStreamManager.cc \ ../QUICFlowController.cc \ ../QUICCongestionController.cc diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index a406a45de6f..6f5f0528282 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -32,15 +32,15 @@ TEST_CASE("QUICFrameHandler", "[quic]") uint8_t payload[] = {0x01}; QUICStreamFrame streamFrame(payload, 1, 0x03, 0); - auto connectionManager = std::make_shared(); + auto connection = new MockQUICConnection(); auto streamManager = std::make_shared(); auto flowController = std::make_shared(); auto congestionController = std::make_shared(); auto lossDetector = std::make_shared(); - QUICFrameDispatcher quicFrameDispatcher(connectionManager, streamManager, flowController, congestionController, lossDetector); + QUICFrameDispatcher quicFrameDispatcher(connection, streamManager, flowController, congestionController, lossDetector); // Initial state - CHECK(connectionManager->getTotalFrameCount() == 0); + CHECK(connection->getTotalFrameCount() == 0); CHECK(streamManager->getTotalFrameCount() == 0); CHECK(flowController->getTotalFrameCount() == 0); CHECK(congestionController->getTotalFrameCount() == 0); @@ -50,7 +50,7 @@ TEST_CASE("QUICFrameHandler", "[quic]") size_t len = 0; streamFrame.store(buf, &len); quicFrameDispatcher.receive_frames(buf, len); - CHECK(connectionManager->getTotalFrameCount() == 0); + CHECK(connection->getTotalFrameCount() == 0); CHECK(streamManager->getTotalFrameCount() == 1); CHECK(flowController->getTotalFrameCount() == 1); CHECK(congestionController->getTotalFrameCount() == 1); From 52ba71ad38ed36af6a7290f0fa8f9a41adc256f4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 14 Aug 2017 16:59:25 +0900 Subject: [PATCH 0012/1313] Remove QUICConnectionState --- iocore/net/P_QUICNetVConnection.h | 10 ---------- iocore/net/QUICNetVConnection.cc | 2 -- 2 files changed, 12 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 3bba2e87784..67fb93b2e81 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -91,15 +91,6 @@ typedef enum { QUIC_HOOK_OP_LAST = QUIC_HOOK_OP_TERMINATE ///< End marker value. } QuicVConnOp; -enum class QUICConnectionState { - Open = 0, - Handshake, - Established, - TimeWait, - Closing, - Closed, -}; - ////////////////////////////////////////////////////////////////// // // class NetVConnection @@ -193,7 +184,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; QUICAckFrameCreator _ack_frame_creator; - QUICConnectionState _state = QUICConnectionState::Open; uint32_t _pmtu = 1280; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index da12ede3f5c..ca963fab658 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -51,7 +51,6 @@ ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); QUICNetVConnection::QUICNetVConnection() : UnixNetVConnection() { - this->_state = QUICConnectionState::Handshake; SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_handshake); } @@ -287,7 +286,6 @@ QUICNetVConnection::state_handshake(int event, Event *data) if (this->_handshake_handler && this->_handshake_handler->is_completed()) { DebugQUICCon("Enter state_connection_established"); - this->_state = QUICConnectionState::Established; SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); QUICConfig::scoped_config params; From e4d34d77238292453ee3358e7d4f0bd8f61c3dcb Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 14 Aug 2017 17:30:18 +0900 Subject: [PATCH 0013/1313] Remove dependency for NetVConnection To make it possible to run test without real network layer, QUIC related classes depend on QUICConnection abstraction layer instead of QUICNetVConnection. --- iocore/net/P_QUICNetVConnection.h | 9 +++++---- iocore/net/quic/Mock.h | 14 ++++++++++++++ iocore/net/quic/QUICApplication.cc | 4 ++-- iocore/net/quic/QUICApplication.h | 9 +++++---- iocore/net/quic/QUICConnection.h | 7 +++++++ iocore/net/quic/QUICEchoApp.cc | 3 +-- iocore/net/quic/QUICEchoApp.h | 3 +-- iocore/net/quic/QUICHandshake.cc | 18 +++++++----------- iocore/net/quic/QUICHandshake.h | 5 ++--- iocore/net/quic/QUICStreamManager.cc | 7 +++---- iocore/net/quic/QUICStreamManager.h | 7 +++---- .../net/quic/test/test_QUICFrameDispatcher.cc | 17 ----------------- iocore/net/quic/test/test_QUICStream.cc | 17 ----------------- 13 files changed, 50 insertions(+), 70 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 67fb93b2e81..3eea803a139 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -156,16 +156,17 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection uint32_t maximum_quic_packet_size(); uint32_t minimum_quic_packet_size(); void push_packet(std::unique_ptr packet); - void close(QUICError error); void free(EThread *t) override; UDPConnection *get_udp_con(); - QUICApplication *get_application(QUICStreamId stream_id); - QUICCrypto *get_crypto(); - virtual void net_read_io(NetHandler *nh, EThread *lthread) override; virtual int64_t load_buffer_and_write(int64_t towrite, MIOBufferAccessor &buf, int64_t &total_written, int &needs) override; + // QUICConnection + QUICApplication *get_application(QUICStreamId stream_id) override; + QUICCrypto *get_crypto() override; + void close(QUICError error) override; + // QUICConnection (QUICPacketTransmitter) virtual void transmit_packet(std::unique_ptr packet) override; virtual void retransmit_packet(const QUICPacket &packet) override; diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 164b80880ef..42b3c7b63fd 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -38,6 +38,20 @@ class MockQUICConnection : public QUICConnection { } + QUICApplication *get_application(QUICStreamId stream_id) override + { + return nullptr; + } + + QUICCrypto *get_crypto() override + { + return nullptr; + } + + void close(QUICError error) override + { + } + int getTotalFrameCount() { diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 343a6bed715..6acbfb7722d 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -81,9 +81,9 @@ QUICStreamIO::write_reenable() // // QUICApplication // -QUICApplication::QUICApplication(ProxyMutex *m, QUICNetVConnection *vc) : Continuation(m) +QUICApplication::QUICApplication(ProxyMutex *m, QUICConnection *qc) : Continuation(m) { - this->_client_vc = vc; + this->_client_qc = qc; } // @brief Bind stream and application diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index d876e6adbe7..cc075fe0a5f 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -23,10 +23,11 @@ #pragma once -#include "I_VConnection.h" +#include "../../eventsystem/I_EventSystem.h" +#include "../../eventsystem/I_IOBuffer.h" #include "QUICTypes.h" -class QUICNetVConnection; +class QUICConnection; class QUICStream; class QUICApplication; @@ -62,7 +63,7 @@ class QUICStreamIO class QUICApplication : public Continuation { public: - QUICApplication(ProxyMutex *m, QUICNetVConnection *vc); + QUICApplication(ProxyMutex *m, QUICConnection *qc); void set_stream(QUICStream *stream); bool is_stream_set(QUICStream *stream); @@ -72,7 +73,7 @@ class QUICApplication : public Continuation protected: QUICStreamIO *_find_stream_io(QUICStreamId id); - QUICNetVConnection *_client_vc = nullptr; + QUICConnection *_client_qc = nullptr; private: std::map _stream_map; diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index bf71ba84cc9..236842be646 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -27,6 +27,13 @@ #include "QUICFrameTransmitter.h" #include "QUICFrameHandler.h" +class QUICApplication; +class QUICCrypto; + class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler { +public: + virtual QUICApplication *get_application(QUICStreamId stream_id) = 0; + virtual QUICCrypto *get_crypto() = 0; + virtual void close(QUICError error) = 0; }; diff --git a/iocore/net/quic/QUICEchoApp.cc b/iocore/net/quic/QUICEchoApp.cc index 45bb4f9c8aa..4be18cc79f1 100644 --- a/iocore/net/quic/QUICEchoApp.cc +++ b/iocore/net/quic/QUICEchoApp.cc @@ -24,12 +24,11 @@ #include "QUICEchoApp.h" #include "P_Net.h" -#include "P_QUICNetVConnection.h" #include "QUICDebugNames.h" const static char *tag = "quic_echo_app"; -QUICEchoApp::QUICEchoApp(ProxyMutex *m, QUICNetVConnection *vc) : QUICApplication(m, vc) +QUICEchoApp::QUICEchoApp(ProxyMutex *m, QUICConnection *qc) : QUICApplication(m, qc) { SET_HANDLER(&QUICEchoApp::main_event_handler); } diff --git a/iocore/net/quic/QUICEchoApp.h b/iocore/net/quic/QUICEchoApp.h index a8310b70cbf..541da2906f3 100644 --- a/iocore/net/quic/QUICEchoApp.h +++ b/iocore/net/quic/QUICEchoApp.h @@ -24,7 +24,6 @@ #ifndef __QUIC_ECHOAPP__ #define __QUIC_ECHOAPP__ -#include "I_VConnection.h" #include "QUICApplication.h" /** @@ -35,7 +34,7 @@ class QUICEchoApp : public QUICApplication { public: - QUICEchoApp(ProxyMutex *m, QUICNetVConnection *vc); + QUICEchoApp(ProxyMutex *m, QUICConnection *qc); int main_event_handler(int event, Event *data); }; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index f5b0753431a..067a3c0e358 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -23,10 +23,6 @@ #include "QUICHandshake.h" -#include "P_Net.h" -#include "P_QUICNetVConnection.h" -#include "QUICApplication.h" - #define I_WANNA_DUMP_THIS_BUF(buf, len) \ { \ int i, j; \ @@ -52,7 +48,7 @@ const static int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size const static int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(ProxyMutex *m, QUICNetVConnection *vc) : QUICApplication(m, vc) +QUICHandshake::QUICHandshake(ProxyMutex *m, QUICConnection *qc) : QUICApplication(m, qc) { SET_HANDLER(&QUICHandshake::state_read_client_hello); } @@ -60,7 +56,7 @@ QUICHandshake::QUICHandshake(ProxyMutex *m, QUICNetVConnection *vc) : QUICApplic bool QUICHandshake::is_completed() { - QUICCrypto *crypto = this->_client_vc->get_crypto(); + QUICCrypto *crypto = this->_client_qc->get_crypto(); return crypto->is_handshake_finished(); } @@ -87,7 +83,7 @@ QUICHandshake::state_read_client_hello(int event, Event *data) } if (error.cls != QUICErrorClass::NONE) { - this->_client_vc->close(error); + this->_client_qc->close(error); Debug(tag, "Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); } @@ -111,7 +107,7 @@ QUICHandshake::state_read_client_finished(int event, Event *data) } if (error.cls != QUICErrorClass::NONE) { - this->_client_vc->close(error); + this->_client_qc->close(error); Debug(tag, "Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); } @@ -160,7 +156,7 @@ QUICHandshake::_process_client_hello() I_WANNA_DUMP_THIS_BUF(msg, msg_len); // <----- DEBUG ----- - QUICCrypto *crypto = this->_client_vc->get_crypto(); + QUICCrypto *crypto = this->_client_qc->get_crypto(); uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t server_hello_len = 0; @@ -204,7 +200,7 @@ QUICHandshake::_process_client_finished() I_WANNA_DUMP_THIS_BUF(msg, msg_len); // <----- DEBUG ----- - QUICCrypto *crypto = this->_client_vc->get_crypto(); + QUICCrypto *crypto = this->_client_qc->get_crypto(); uint8_t out[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t out_len = 0; @@ -236,7 +232,7 @@ QUICHandshake::_process_client_finished() QUICError QUICHandshake::_process_handshake_complete() { - QUICCrypto *crypto = this->_client_vc->get_crypto(); + QUICCrypto *crypto = this->_client_qc->get_crypto(); int r = crypto->setup_session(); if (r) { diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 28854ec13f5..cd2a359d7af 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -24,10 +24,9 @@ #ifndef __QUIC_HANDSHAKE__ #define __QUIC_HANDSHAKE__ -#include "I_VConnection.h" +#include "QUICConnection.h" #include "QUICApplication.h" -class QUICNetVConnection; /** * @class QUICHandshake @@ -49,7 +48,7 @@ class QUICNetVConnection; class QUICHandshake : public QUICApplication { public: - QUICHandshake(ProxyMutex *m, QUICNetVConnection *vc); + QUICHandshake(ProxyMutex *m, QUICConnection *qc); int state_read_client_hello(int event, Event *data); int state_read_client_finished(int event, Event *data); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 6499772d9c0..e9f058d8fd1 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -24,7 +24,6 @@ #include #include -#include const static char *tag = "quic_stream_manager"; @@ -39,9 +38,9 @@ QUICStreamManager::init(QUICFrameTransmitter *tx) } void -QUICStreamManager::set_connection(QUICNetVConnection *vc) +QUICStreamManager::set_connection(QUICConnection *qc) { - this->_vc = vc; + this->_qc = qc; } void @@ -62,7 +61,7 @@ void QUICStreamManager::_handle_stream_frame(std::shared_ptr frame) { QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); - QUICApplication *application = this->_vc->get_application(frame->stream_id()); + QUICApplication *application = this->_qc->get_application(frame->stream_id()); if (!application->is_stream_set(stream)) { application->set_stream(stream); diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 3daff59aa57..1b031664ddb 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -25,19 +25,18 @@ #include "QUICTypes.h" #include "QUICStream.h" +#include "QUICConnection.h" #include "QUICFrameHandler.h" #include "QUICFrame.h" #include "QUICFrameTransmitter.h" -class QUICNetVConnection; - class QUICStreamManager : public QUICFrameHandler { public: QUICStreamManager(){}; int init(QUICFrameTransmitter *tx); - void set_connection(QUICNetVConnection *vc); // FIXME Want to remove. + void set_connection(QUICConnection *qc); // FIXME Want to remove. virtual void handle_frame(std::shared_ptr) override; void send_frame(std::unique_ptr frame); @@ -47,7 +46,7 @@ class QUICStreamManager : public QUICFrameHandler QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICStream *_find_stream(QUICStreamId id); - QUICNetVConnection *_vc = nullptr; + QUICConnection *_qc = nullptr; QUICFrameTransmitter *_tx = nullptr; private: diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 6f5f0528282..53726a7103c 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -55,20 +55,3 @@ TEST_CASE("QUICFrameHandler", "[quic]") CHECK(flowController->getTotalFrameCount() == 1); CHECK(congestionController->getTotalFrameCount() == 1); } - -// Stubs -QUICApplication *QUICNetVConnection::get_application(QUICStreamId) -{ - return nullptr; -} - -QUICCrypto * -QUICNetVConnection::get_crypto() -{ - return nullptr; -} - -void QUICNetVConnection::close(QUICError) -{ - return; -} diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 042f39d0764..e31ddb982c6 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -121,20 +121,3 @@ TEST_CASE("QUICStream_assembling_byte_stream_3", "[quic]") CHECK(memcmp(buf, payload, len) == 0); } } - -// Stubs -QUICApplication *QUICNetVConnection::get_application(QUICStreamId) -{ - return nullptr; -} - -QUICCrypto * -QUICNetVConnection::get_crypto() -{ - return nullptr; -} - -void QUICNetVConnection::close(QUICError) -{ - return; -} From 08ef8e4d398e2084b28ac4e766dc34379b1b0720 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 14 Aug 2017 17:45:42 +0900 Subject: [PATCH 0014/1313] Add a test case for handling CONNECTION_CLOSE frames on FrameDispatcher --- iocore/net/quic/Mock.h | 3 +++ iocore/net/quic/test/test_QUICFrameDispatcher.cc | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 42b3c7b63fd..6f0b14fb9aa 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -36,6 +36,8 @@ class MockQUICConnection : public QUICConnection void handle_frame(std::shared_ptr f) override { + ++_frameCount[static_cast(f->type())]; + ++_totalFrameCount; } QUICApplication *get_application(QUICStreamId stream_id) override @@ -62,6 +64,7 @@ class MockQUICConnection : public QUICConnection int _retransmit_count = 0; Ptr _mutex; int _totalFrameCount = 0; + int _frameCount[256] = {0}; }; class MockQUICPacketTransmitter : public QUICPacketTransmitter diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 53726a7103c..dfb673748bf 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -54,4 +54,13 @@ TEST_CASE("QUICFrameHandler", "[quic]") CHECK(streamManager->getTotalFrameCount() == 1); CHECK(flowController->getTotalFrameCount() == 1); CHECK(congestionController->getTotalFrameCount() == 1); + + // CONNECTION_CLOSE frame + QUICConnectionCloseFrame connectionCloseFrame({}); + connectionCloseFrame.store(buf, &len); + quicFrameDispatcher.receive_frames(buf, len); + CHECK(connection->getTotalFrameCount() == 1); + CHECK(streamManager->getTotalFrameCount() == 1); + CHECK(flowController->getTotalFrameCount() == 1); + CHECK(congestionController->getTotalFrameCount() == 1); } From 85155fa607828380f9b55d2a7ebfbb1b32b1976c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 Aug 2017 09:23:32 +0900 Subject: [PATCH 0015/1313] Change QUICNetProcessor from struct to class --- iocore/net/P_QUICNetProcessor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h index 461afddd8f7..d6a57fa66a8 100644 --- a/iocore/net/P_QUICNetProcessor.h +++ b/iocore/net/P_QUICNetProcessor.h @@ -50,7 +50,7 @@ struct NetAccept; // class QUICNetProcessor // ////////////////////////////////////////////////////////////////// -struct QUICNetProcessor : public UnixNetProcessor { +class QUICNetProcessor : public UnixNetProcessor { public: QUICNetProcessor(); virtual ~QUICNetProcessor(); From 92741d4334cc3a8b4d87ae310f51c192597b4838 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 15 Aug 2017 09:52:55 +0900 Subject: [PATCH 0016/1313] Add draft-05(-pre) support - Change label prefix of Key Expansion - Change largest length of the Largest Acknowledged field of Ack frame - Change QUIC_SUPPORTED_VERSIONS --- iocore/net/quic/QUICCrypto.cc | 10 +++++----- iocore/net/quic/QUICFrame.cc | 10 +++------- iocore/net/quic/QUICTypes.cc | 6 ------ iocore/net/quic/QUICTypes.h | 8 +++++++- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- 5 files changed, 16 insertions(+), 20 deletions(-) diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 2707dfaa0a7..f3df0a6454b 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -36,11 +36,11 @@ constexpr static char tag[] = "quic_crypto"; constexpr static ts::StringView exporter_label_client_1_rtt("EXPORTER-QUIC client 1-RTT Secret", ts::StringView::literal); constexpr static ts::StringView exporter_label_server_1_rtt("EXPORTER-QUIC server 1-RTT Secret", ts::StringView::literal); -// [quic-tls draft-04] "TLS 1.3, " + Label -// constexpr static ts::StringView expand_label_client_1_rtt("TLS 1.3, QUIC client 1-RTT secret", ts::StringView::literal); -// constexpr static ts::StringView expand_label_server_1_rtt("TLS 1.3, QUIC server 1-RTT secret", ts::StringView::literal); -constexpr static ts::StringView expand_label_key("TLS 1.3, key", ts::StringView::literal); -constexpr static ts::StringView expand_label_iv("TLS 1.3, iv", ts::StringView::literal); +// [quic-tls draft-05] "tls13 " + Label +// constexpr static ts::StringView expand_label_client_1_rtt("tls13 QUIC client 1-RTT secret", ts::StringView::literal); +// constexpr static ts::StringView expand_label_server_1_rtt("tls13 QUIC server 1-RTT secret", ts::StringView::literal); +constexpr static ts::StringView expand_label_key("tls13 key", ts::StringView::literal); +constexpr static ts::StringView expand_label_iv("tls13 iv", ts::StringView::literal); // // QUICPacketProtection diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index d7495c76957..cf361998751 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -327,7 +327,7 @@ QUICAckFrame::store(uint8_t *buf, size_t *len) const QUICTypeUtil::write_uint_as_nbytes(this->_largest_acknowledged, 4, p, &n); } else { buf[0] += 0x03 << 2; - QUICTypeUtil::write_uint_as_nbytes(this->_largest_acknowledged, 6, p, &n); + QUICTypeUtil::write_uint_as_nbytes(this->_largest_acknowledged, 8, p, &n); } p += n; @@ -439,14 +439,10 @@ QUICAckFrame::_get_largest_acknowledged_length() const * 0 -> 1 byte * 1 -> 2 byte * 2 -> 4 byte - * 3 -> 6 byte + * 3 -> 8 byte */ int n = (this->_buf[0] & 0x0c) >> 2; - if (n == 0) { - return 1; - } else { - return n * 2; - } + return 0x01 << n; } size_t diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 0be3d0008b6..cf4500035d9 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -23,12 +23,6 @@ #include "QUICTypes.h" -// TODO: Update version number -// Note: You need to update QUICTypes.h if you change the number of versions -const QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff000004, // Prefix for drafts (0xff000000) + draft number -}; - const QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; bool diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index d1f613bc196..abff7218f4c 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -45,7 +45,13 @@ typedef uint32_t QUICVersion; typedef uint32_t QUICStreamId; typedef uint64_t QUICOffset; -extern const QUICVersion QUIC_SUPPORTED_VERSIONS[1]; +// TODO: Update version number +// Note: You also need to update tests for VersionNegotiationPacket, if you change the number of versions +// Prefix for drafts (0xff000000) + draft number +constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { + 0xff000005, +}; + extern const QUICStreamId STREAM_ID_FOR_HANDSHAKE; enum class QUICPacketType : int { diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 48f6c5df71e..31bdbd2d33a 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -48,7 +48,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); CHECK(packet->connection_id() == client_initial_packet.connection_id()); CHECK(packet->packet_number() == client_initial_packet.packet_number()); - CHECK(memcmp(packet->payload(), "\xff\x00\x00\x04", 4) == 0); + CHECK(memcmp(packet->payload(), "\xff\x00\x00\x05", 4) == 0); } TEST_CASE("QUICPacketFactory_Create_ServerCleartextPacket", "[quic]") From c6b05347e0616fe666dc6412a76f05291bce68a1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 Aug 2017 10:50:15 +0900 Subject: [PATCH 0017/1313] Allocate buffer for UDP packets with a size of PMTU --- iocore/net/P_QUICNetProcessor.h | 3 ++- iocore/net/P_QUICNetVConnection.h | 5 +++-- iocore/net/QUICNetVConnection.cc | 6 ++++++ iocore/net/QUICPacketHandler.cc | 9 ++++++--- iocore/net/quic/Mock.h | 27 ++++++++++++++++++++++++--- iocore/net/quic/QUICConnection.h | 7 +++++-- iocore/net/quic/QUICHandshake.h | 1 - iocore/net/quic/QUICStreamManager.h | 2 +- 8 files changed, 47 insertions(+), 13 deletions(-) diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h index d6a57fa66a8..f5a29065180 100644 --- a/iocore/net/P_QUICNetProcessor.h +++ b/iocore/net/P_QUICNetProcessor.h @@ -50,7 +50,8 @@ struct NetAccept; // class QUICNetProcessor // ////////////////////////////////////////////////////////////////// -class QUICNetProcessor : public UnixNetProcessor { +class QUICNetProcessor : public UnixNetProcessor +{ public: QUICNetProcessor(); virtual ~QUICNetProcessor(); diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 3eea803a139..1a143b9c36b 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -153,8 +153,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection int state_connection_closing(int event, Event *data); int state_connection_closed(int event, Event *data); void start(SSL_CTX *); - uint32_t maximum_quic_packet_size(); - uint32_t minimum_quic_packet_size(); void push_packet(std::unique_ptr packet); void free(EThread *t) override; @@ -165,6 +163,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // QUICConnection QUICApplication *get_application(QUICStreamId stream_id) override; QUICCrypto *get_crypto() override; + uint32_t maximum_quic_packet_size() override; + uint32_t minimum_quic_packet_size() override; + uint32_t pmtu() override; void close(QUICError error) override; // QUICConnection (QUICPacketTransmitter) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ca963fab658..421555ab12e 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -133,6 +133,12 @@ QUICNetVConnection::reenable(VIO *vio) return; } +uint32_t +QUICNetVConnection::pmtu() +{ + return this->_pmtu; +} + uint32_t QUICNetVConnection::minimum_quic_packet_size() { diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 47e050505b1..9286ada24be 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -135,10 +135,13 @@ QUICPacketHandler::send_packet(const QUICPacket &packet, QUICNetVConnection *vc) this->_connections.put(packet.connection_id(), vc); } - uint8_t udp_payload[65536]; size_t udp_len; - packet.store(udp_payload, &udp_len); - UDPPacket *udpPkt = new_UDPPacket(vc->con.addr, 0, reinterpret_cast(udp_payload), udp_len); + Ptr udp_payload(new_IOBufferBlock()); + udp_payload->alloc(iobuffer_size_to_index(vc->pmtu())); + packet.store(reinterpret_cast(udp_payload->end()), &udp_len); + udp_payload->fill(udp_len); + + UDPPacket *udpPkt = new_UDPPacket(vc->con.addr, 0, udp_payload); // NOTE: p will be enqueued to udpOutQueue of UDPNetHandler ip_port_text_buffer ipb; diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 6f0b14fb9aa..462df2ba1e0 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -40,17 +40,38 @@ class MockQUICConnection : public QUICConnection ++_totalFrameCount; } - QUICApplication *get_application(QUICStreamId stream_id) override + QUICApplication * + get_application(QUICStreamId stream_id) override { return nullptr; } - QUICCrypto *get_crypto() override + QUICCrypto * + get_crypto() override { return nullptr; } - void close(QUICError error) override + uint32_t + minimum_quic_packet_size() override + { + return 1200; + } + + uint32_t + maximum_quic_packet_size() override + { + return 1200; + } + + uint32_t + pmtu() override + { + return 1280; + } + + void + close(QUICError error) override { } diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 236842be646..22f373e922b 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -34,6 +34,9 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter { public: virtual QUICApplication *get_application(QUICStreamId stream_id) = 0; - virtual QUICCrypto *get_crypto() = 0; - virtual void close(QUICError error) = 0; + virtual QUICCrypto *get_crypto() = 0; + virtual uint32_t maximum_quic_packet_size() = 0; + virtual uint32_t minimum_quic_packet_size() = 0; + virtual uint32_t pmtu() = 0; + virtual void close(QUICError error) = 0; }; diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index cd2a359d7af..b364a930ffb 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -27,7 +27,6 @@ #include "QUICConnection.h" #include "QUICApplication.h" - /** * @class QUICHandshake * @brief Do handshake as a QUIC application diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 1b031664ddb..7ea2700dd58 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -46,7 +46,7 @@ class QUICStreamManager : public QUICFrameHandler QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICStream *_find_stream(QUICStreamId id); - QUICConnection *_qc = nullptr; + QUICConnection *_qc = nullptr; QUICFrameTransmitter *_tx = nullptr; private: From 58478550894828671231bb94b7584db4cbe26991 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 Aug 2017 10:55:55 +0900 Subject: [PATCH 0018/1313] Increase buffer sizes for UDP socket --- iocore/net/QUICNetProcessor.cc | 2 +- iocore/net/test_I_UDPNet.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 7500ab1093b..2eab6f830b1 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -136,7 +136,7 @@ QUICNetProcessor::main_accept(Continuation *cont, SOCKET fd, AcceptOptions const na->action_->server = &na->server; na->init_accept(); - udpNet.UDPBind((Continuation *)na, &na->server.accept_addr.sa, 1024000, 1024000); + udpNet.UDPBind((Continuation *)na, &na->server.accept_addr.sa, 1048576, 1048576); return na->action_.get(); } diff --git a/iocore/net/test_I_UDPNet.cc b/iocore/net/test_I_UDPNet.cc index b8358eef182..68d708c10ac 100644 --- a/iocore/net/test_I_UDPNet.cc +++ b/iocore/net/test_I_UDPNet.cc @@ -60,7 +60,7 @@ EchoServer::start() addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr.sin_port = htons(port); - udpNet.UDPBind(static_cast(this), reinterpret_cast(&addr), 1024000, 1024000); + udpNet.UDPBind(static_cast(this), reinterpret_cast(&addr), 1048576, 1048576); return true; } From b82fd38bb5408eefc6351780a88ed86940e28685 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 Aug 2017 12:27:10 +0900 Subject: [PATCH 0019/1313] Make TLS 1.3 support optional --- build/crypto.m4 | 28 ++++++++++++++++++++++++++++ cmd/traffic_layout/traffic_layout.cc | 1 + configure.ac | 16 +++------------- lib/ts/ink_config.h.in | 1 + 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/build/crypto.m4 b/build/crypto.m4 index 3a3b03b669f..dea1c59aaa3 100644 --- a/build/crypto.m4 +++ b/build/crypto.m4 @@ -230,3 +230,31 @@ AC_DEFUN([TS_CHECK_CRYPTO_DH_GET_2048_256], [ TS_ARG_ENABLE_VAR([use], [dh_get_2048_256]) AC_SUBST(use_dh_get_2048_256) ]) + +AC_DEFUN([TS_CHECK_CRYPTO_TLS13], [ + enable_tls13=yes + _tls13_saved_LIBS=$LIBS + TS_ADDTO(LIBS, [$OPENSSL_LIBS]) + AC_MSG_CHECKING([whether TLS 1.3 is supported]) + AC_LINK_IFELSE( + [ + AC_LANG_PROGRAM([[ +#include + ]], + [[ +#ifndef TLS1_3_VERSION +# error no TLS1_3 support +#endif + ]]) + ], + [ + AC_MSG_RESULT([yes]) + ], + [ + AC_MSG_RESULT([no]) + enable_tls13=no + ]) + LIBS=$_tls13_saved_LIBS + TS_ARG_ENABLE_VAR([use], [tls13]) + AC_SUBST(use_tls13) +]) diff --git a/cmd/traffic_layout/traffic_layout.cc b/cmd/traffic_layout/traffic_layout.cc index 82a33c8860a..e959c5435e7 100644 --- a/cmd/traffic_layout/traffic_layout.cc +++ b/cmd/traffic_layout/traffic_layout.cc @@ -108,6 +108,7 @@ produce_features(bool json) print_feature("TS_USE_CERT_CB", TS_USE_CERT_CB, json); print_feature("TS_USE_SET_RBIO", TS_USE_SET_RBIO, json); print_feature("TS_USE_TLS_ECKEY", TS_USE_TLS_ECKEY, json); + print_feature("TS_USE_TLS13", TS_USE_TLS13, json); print_feature("TS_USE_LINUX_NATIVE_AIO", TS_USE_LINUX_NATIVE_AIO, json); print_feature("TS_HAS_SO_PEERCRED", TS_HAS_SO_PEERCRED, json); print_feature("TS_USE_REMOTE_UNWINDING", TS_USE_REMOTE_UNWINDING, json); diff --git a/configure.ac b/configure.ac index 4e1692d550a..a0e80d631ae 100644 --- a/configure.ac +++ b/configure.ac @@ -1140,6 +1140,9 @@ TS_CHECK_CRYPTO_SET_RBIO # Check for DH_get_2048_256 TS_CHECK_CRYPTO_DH_GET_2048_256 +# Check for TLS 1.3 support +TS_CHECK_CRYPTO_TLS13 + saved_LIBS="$LIBS" TS_ADDTO([LIBS], ["$OPENSSL_LIBS"]) @@ -1174,19 +1177,6 @@ AC_CHECK_FUNC([EVP_MD_CTX_reset], [], AC_CHECK_FUNC([EVP_MD_CTX_free], [], [AC_DEFINE([EVP_MD_CTX_free], [EVP_MD_CTX_destroy], [Renamed in OpenSSL 1.1])]) -AC_MSG_CHECKING([for TLS 1.3 is supported]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[ - #ifndef TLS1_3_VERSION - # error no TLS1_3 support - #endif - ]]) - ], - [AC_MSG_RESULT([yes])], - [AC_ERROR(OpenSSL 1.1.1+ or BoringSSL is required); - AC_MSG_RESULT([no])]) - - AC_MSG_CHECKING([for OpenSSL is BoringSSL]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ diff --git a/lib/ts/ink_config.h.in b/lib/ts/ink_config.h.in index 79b2c00c395..1bb3875327a 100644 --- a/lib/ts/ink_config.h.in +++ b/lib/ts/ink_config.h.in @@ -75,6 +75,7 @@ #define TS_USE_SET_RBIO @use_set_rbio@ #define TS_USE_GET_DH_2048_256 @use_dh_get_2048_256@ #define TS_USE_TLS_ECKEY @use_tls_eckey@ +#define TS_USE_TLS13 @use_tls13@ #define TS_USE_LINUX_NATIVE_AIO @use_linux_native_aio@ #define TS_USE_REMOTE_UNWINDING @use_remote_unwinding@ #define TS_USE_SSLV3_CLIENT @use_sslv3_client@ From 49e6fc74cfe533e33ac39b4f7af44f30907cf464 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 Aug 2017 15:43:57 +0900 Subject: [PATCH 0020/1313] Build QUIC modules only if TLS 1.3 is available --- configure.ac | 9 +++++++++ iocore/net/Makefile.am | 18 ++++++++++++------ lib/ts/ink_config.h.in | 1 + proxy/Main.cc | 8 ++++++-- proxy/Makefile.am | 14 +++++++++++--- proxy/http/HttpProxyServerMain.cc | 14 ++++++++++---- 6 files changed, 49 insertions(+), 15 deletions(-) diff --git a/configure.ac b/configure.ac index a0e80d631ae..02a5de59cf0 100644 --- a/configure.ac +++ b/configure.ac @@ -1143,6 +1143,15 @@ TS_CHECK_CRYPTO_DH_GET_2048_256 # Check for TLS 1.3 support TS_CHECK_CRYPTO_TLS13 +# Check for QUIC support +enable_quic=no +AS_IF([test "x$enable_tls13" = "xyes"], [ + enable_quic=yes +]) +TS_ARG_ENABLE_VAR([use], [quic]) +AC_SUBST(use_quic) +AM_CONDITIONAL([ENABLE_QUIC], [test "x$enable_quic" = "xyes"]) + saved_LIBS="$LIBS" TS_ADDTO([LIBS], ["$OPENSSL_LIBS"]) diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am index 252a4c3aa8f..10ce90d21e0 100644 --- a/iocore/net/Makefile.am +++ b/iocore/net/Makefile.am @@ -16,7 +16,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +if ENABLE_QUIC SUBDIRS = quic +endif AM_CPPFLAGS += \ $(iocore_include_dirs) \ @@ -114,9 +116,6 @@ libinknet_a_SOURCES = \ P_UDPIOEvent.h \ P_UDPNet.h \ P_UDPPacket.h \ - P_QUICPacketHandler.h \ - P_QUICNetProcessor.h \ - P_QUICNetVConnection.h \ P_UnixCompletionUtil.h \ P_UnixNet.h \ P_UnixNetProcessor.h \ @@ -139,9 +138,6 @@ libinknet_a_SOURCES = \ OCSPStapling.cc \ Socks.cc \ UDPIOEvent.cc \ - QUICPacketHandler.cc \ - QUICNetProcessor.cc \ - QUICNetVConnection.cc \ UnixConnection.cc \ UnixNet.cc \ UnixNetAccept.cc \ @@ -152,6 +148,16 @@ libinknet_a_SOURCES = \ UnixUDPNet.cc \ SSLDynlock.cc +if ENABLE_QUIC +libinknet_a_SOURCES += \ + P_QUICPacketHandler.h \ + P_QUICNetProcessor.h \ + P_QUICNetVConnection.h \ + QUICPacketHandler.cc \ + QUICNetProcessor.cc \ + QUICNetVConnection.cc +endif + #test_UNUSED_SOURCES = \ # NetTest-http-server.c \ # test_I_Net.cc \ diff --git a/lib/ts/ink_config.h.in b/lib/ts/ink_config.h.in index 1bb3875327a..71506cc76ae 100644 --- a/lib/ts/ink_config.h.in +++ b/lib/ts/ink_config.h.in @@ -76,6 +76,7 @@ #define TS_USE_GET_DH_2048_256 @use_dh_get_2048_256@ #define TS_USE_TLS_ECKEY @use_tls_eckey@ #define TS_USE_TLS13 @use_tls13@ +#define TS_USE_QUIC @use_quic@ #define TS_USE_LINUX_NATIVE_AIO @use_linux_native_aio@ #define TS_USE_REMOTE_UNWINDING @use_remote_unwinding@ #define TS_USE_SSLV3_CLIENT @use_sslv3_client@ diff --git a/proxy/Main.cc b/proxy/Main.cc index 2bf879628e2..3557805dcbe 100644 --- a/proxy/Main.cc +++ b/proxy/Main.cc @@ -91,7 +91,9 @@ extern "C" int plock(int); #include "I_Tasks.h" #include "InkAPIInternal.h" #include "HTTP2.h" +#if TS_USE_QUIC == 1 #include "HQ.h" +#endif #include @@ -1810,8 +1812,10 @@ main(int /* argc ATS_UNUSED */, const char **argv) // Initialize HTTP/2 Http2::init(); +#if TS_USE_QUIC == 1 // Initialize HTTP/QUIC HQ::init(); +#endif if (!HttpProxyPort::loadValue(http_accept_port_descriptor)) { HttpProxyPort::loadConfig(); @@ -1831,9 +1835,9 @@ main(int /* argc ATS_UNUSED */, const char **argv) SSLConfigParams::init_ssl_ctx_cb = init_ssl_ctx_callback; SSLConfigParams::load_ssl_file_cb = load_ssl_file_callback; sslNetProcessor.start(-1, stacksize); - +#if TS_USE_QUIC == 1 quic_NetProcessor.start(-1, stacksize); - +#endif pmgmt->registerPluginCallbacks(global_config_cbs); cacheProcessor.afterInitCallbackSet(&CB_After_Cache_Init); diff --git a/proxy/Makefile.am b/proxy/Makefile.am index 220f8d869f5..7505dc0cc20 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -19,7 +19,11 @@ include $(top_srcdir)/build/tidy.mk # Note that hdrs is targeted from ../Makefile.am -SUBDIRS = congest http http2 hq logging config +SUBDIRS = congest http http2 logging config +if ENABLE_QUIC +SUBDIRS += hq +endif + noinst_LIBRARIES = bin_PROGRAMS = \ traffic_server \ @@ -180,7 +184,6 @@ endif traffic_server_LDADD = \ http/libhttp.a \ http2/libhttp2.a \ - hq/libhq.a \ http/remap/libhttp_remap.a \ congest/libCongestionControl.a \ logging/liblogging.a \ @@ -197,6 +200,12 @@ traffic_server_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/lib/bindings/libbindings.la +if ENABLE_QUIC +traffic_server_LDADD += \ + hq/libhq.a \ + $(top_builddir)/iocore/net/quic/libquic.a +endif + if BUILD_LUAJIT traffic_server_LDADD += \ $(top_builddir)/lib/luajit/src/libluajit.a @@ -204,7 +213,6 @@ endif traffic_server_LDADD += \ $(top_builddir)/iocore/net/libinknet.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ diff --git a/proxy/http/HttpProxyServerMain.cc b/proxy/http/HttpProxyServerMain.cc index 9beb3ac29f3..6e2771683fe 100644 --- a/proxy/http/HttpProxyServerMain.cc +++ b/proxy/http/HttpProxyServerMain.cc @@ -39,7 +39,9 @@ #include "ProtocolProbeSessionAccept.h" #include "http2/Http2SessionAccept.h" #include "HttpConnectionCount.h" +#if TS_USE_QUIC == 1 #include "hq/HQSessionAccept.h" +#endif HttpSessionAccept *plugin_http_accept = nullptr; HttpSessionAccept *plugin_http_transparent_accept = nullptr; @@ -219,10 +221,12 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned ssl_plugin_acceptors.push(ssl); ssl->proxyPort = &port; acceptor._accept = ssl; +#if TS_USE_QUIC == 1 } else if (port.isQUIC()) { // HTTP/QUIC HQSessionAccept *hq = new HQSessionAccept(accept_opt); acceptor._accept = hq; +#endif } else { acceptor._accept = probe; } @@ -291,14 +295,16 @@ start_HttpProxyServer() for (int i = 0, n = proxy_ports.length(); i < n; ++i) { HttpProxyAcceptor &acceptor = HttpProxyAcceptors[i]; HttpProxyPort &port = proxy_ports[i]; - if (port.isQUIC()) { - if (nullptr == quic_NetProcessor.main_accept(acceptor._accept, port.m_fd, acceptor._net_opt)) { + if (port.isSSL()) { + if (nullptr == sslNetProcessor.main_accept(acceptor._accept, port.m_fd, acceptor._net_opt)) { return; } - } else if (port.isSSL()) { - if (nullptr == sslNetProcessor.main_accept(acceptor._accept, port.m_fd, acceptor._net_opt)) { +#if TS_USE_QUIC == 1 + } else if (port.isQUIC()) { + if (nullptr == quic_NetProcessor.main_accept(acceptor._accept, port.m_fd, acceptor._net_opt)) { return; } +#endif } else if (!port.isPlugin()) { if (nullptr == netProcessor.main_accept(acceptor._accept, port.m_fd, acceptor._net_opt)) { return; From df6c99e3c0a86f512ed39764b580ae5acb878e70 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 Aug 2017 16:14:55 +0900 Subject: [PATCH 0021/1313] Add one more TS_USE_QUIC check --- iocore/net/P_Net.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/P_Net.h b/iocore/net/P_Net.h index 87456c49e84..0a7a502a3ea 100644 --- a/iocore/net/P_Net.h +++ b/iocore/net/P_Net.h @@ -109,9 +109,11 @@ 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" +#endif // #include "P_QUICCertLookup.h" #undef NET_SYSTEM_MODULE_VERSION From af8743532fc8f4429caffd75e8e887f1785f7e54 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 Aug 2017 16:34:55 +0900 Subject: [PATCH 0022/1313] Add AL header --- iocore/net/quic/Mock.h | 23 ++++++++++++++++++++++ iocore/net/quic/QUICStreamState.cc | 23 ++++++++++++++++++++++ iocore/net/quic/QUICTransportParameters.cc | 23 ++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 462df2ba1e0..6aab61155c1 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -1,3 +1,26 @@ +/** @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 "QUICStreamManager.h" #include "QUICFlowController.h" #include "QUICCongestionController.h" diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index dfe9f4dd13b..eb43130f282 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -1,3 +1,26 @@ +/** @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 "QUICStreamState.h" #include "ts/ink_assert.h" diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 4b483a22b40..c7fe73678a4 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -1,3 +1,26 @@ +/** @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 #include "QUICTransportParameters.h" From 39356833845830c0f6901af61dbacd3885cd5cc9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 Aug 2017 16:36:23 +0900 Subject: [PATCH 0023/1313] clang-format --- lib/records/I_RecHttp.h | 2 +- lib/ts/Vec.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/records/I_RecHttp.h b/lib/records/I_RecHttp.h index 8fa2c697728..066486ad119 100644 --- a/lib/records/I_RecHttp.h +++ b/lib/records/I_RecHttp.h @@ -305,7 +305,7 @@ struct HttpProxyPort { /// Check for QUIC ports. /// @return @c true if any port in @a ports is an QUIC port. static bool hasQUIC(Group const &ports ///< Ports to check. - ); + ); /// Check for QUIC ports. /// @return @c true if any global port is an QUIC port. diff --git a/lib/ts/Vec.h b/lib/ts/Vec.h index ff7d815c8aa..f599eadbe96 100644 --- a/lib/ts/Vec.h +++ b/lib/ts/Vec.h @@ -988,7 +988,7 @@ qsort_Vec(C *left, C *right, bool (*lt)(C, C)) Vec::swap((right - 1), center); } Vec::swap(center, right - 2); // stash the median one from the right for now - median = *(right - 2); // the median of left, center and right values + median = *(right - 2); // the median of left, center and right values // now partition, pivoting on the median value // l ptr is +1 b/c we already put the lowest of the incoming left, center @@ -1054,7 +1054,7 @@ qsort_VecRef(C *left, C *right, bool (*lt)(const C &, const C &), unsigned int * Vec::swap((right - 1), center); } Vec::swap(center, right - 2); // stash the median one from the right for now - median = *(right - 2); // the median of left, center and right values + median = *(right - 2); // the median of left, center and right values // now partition, pivoting on the median value // l ptr is +1 b/c we already put the lowest of the incoming left, center From e44f61e268b0af2921e96d398150e06001a3b9e4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 16 Aug 2017 11:05:56 +0900 Subject: [PATCH 0024/1313] Fix build issues on FreeBSD 11 --- iocore/net/quic/QUICTypes.h | 4 +++- proxy/Makefile.am | 12 +++++++++--- proxy/hq/Makefile.am | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index abff7218f4c..f01a4c7be41 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -23,10 +23,12 @@ #pragma once -#ifdef __APPLE__ +#if defined(darwin) #include #define be64toh(x) OSSwapBigToHostInt64(x) #define htobe64(x) OSSwapHostToBigInt64(x) +#elif defined(freebsd) +#include #else #include #endif diff --git a/proxy/Makefile.am b/proxy/Makefile.am index 7505dc0cc20..e2ee8221980 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -202,8 +202,7 @@ traffic_server_LDADD = \ if ENABLE_QUIC traffic_server_LDADD += \ - hq/libhq.a \ - $(top_builddir)/iocore/net/quic/libquic.a + hq/libhq.a endif if BUILD_LUAJIT @@ -212,7 +211,14 @@ traffic_server_LDADD += \ endif traffic_server_LDADD += \ - $(top_builddir)/iocore/net/libinknet.a \ + $(top_builddir)/iocore/net/libinknet.a + +if ENABLE_QUIC +traffic_server_LDADD += \ + $(top_builddir)/iocore/net/quic/libquic.a +endif + +traffic_server_LDADD += \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ diff --git a/proxy/hq/Makefile.am b/proxy/hq/Makefile.am index b188de4e899..dc545e1525c 100644 --- a/proxy/hq/Makefile.am +++ b/proxy/hq/Makefile.am @@ -19,7 +19,7 @@ include $(top_srcdir)/build/tidy.mk -AM_CPPFLAGS = \ +AM_CPPFLAGS += \ $(iocore_include_dirs) \ -I$(abs_top_srcdir)/proxy/api/ts \ -I$(abs_top_srcdir)/lib \ From 31ca4fa14c9d007f5a16645da4a01fb1040cb4b0 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 16 Aug 2017 15:56:00 +0900 Subject: [PATCH 0025/1313] Add MAX_DATA, MAX_STREAM_DATA, BLOCKED, and STREAM_BLOCKED frame factory --- iocore/net/quic/QUICFrame.cc | 32 ++++++++++++++++++++++++++++++++ iocore/net/quic/QUICFrame.h | 21 +++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index cf361998751..f0c0b5bbbf0 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1301,6 +1301,38 @@ QUICFrameFactory::create_connection_close_frame(QUICErrorCode error_code, uint16 return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); } +std::unique_ptr +QUICFrameFactory::create_max_data_frame(uint64_t maximum_data) +{ + QUICMaxDataFrame *frame = quicMaxDataFrameAllocator.alloc(); + new (frame) QUICMaxDataFrame(maximum_data); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_data_frame); +} + +std::unique_ptr +QUICFrameFactory::create_max_stream_data_frame(QUICStreamId stream_id, uint64_t maximum_data) +{ + QUICMaxStreamDataFrame *frame = quicMaxStreamDataFrameAllocator.alloc(); + new (frame) QUICMaxStreamDataFrame(stream_id, maximum_data); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); +} + +std::unique_ptr +QUICFrameFactory::create_blocked_frame() +{ + QUICBlockedFrame *frame = quicBlockedFrameAllocator.alloc(); + new (frame) QUICBlockedFrame(); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_blocked_frame); +} + +std::unique_ptr +QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id) +{ + QUICStreamBlockedFrame *frame = quicStreamBlockedFrameAllocator.alloc(); + new (frame) QUICStreamBlockedFrame(stream_id); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); +} + std::unique_ptr QUICFrameFactory::create_retransmission_frame(std::unique_ptr original_frame, const QUICPacket &original_packet) diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 2e87d4ff8e3..8be22bf22c8 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -603,6 +603,27 @@ class QUICFrameFactory static std::unique_ptr create_connection_close_frame( QUICErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase); + /* + * Creates a MAX_DATA frame. + */ + static std::unique_ptr create_max_data_frame(uint64_t maximum_data); + + /* + * Creates a MAX_STREAM_DATA frame. + */ + static std::unique_ptr create_max_stream_data_frame(QUICStreamId stream_id, + uint64_t maximum_stream_data); + + /* + * Creates a BLOCKED frame. + */ + static std::unique_ptr create_blocked_frame(); + + /* + * Creates a STREAM_BLOCKED frame. + */ + static std::unique_ptr create_stream_blocked_frame(QUICStreamId stream_id); + /* * Creates a retransmission frame, which is very special. * This retransmission frame will be used only for retransmission and it's not a standard frame type. From 985169147a952dfd67c5e790f2d39c00cae8459b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 17 Aug 2017 11:25:34 +0900 Subject: [PATCH 0026/1313] Make a check for TLS 1.3 support strict --- build/crypto.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/crypto.m4 b/build/crypto.m4 index dea1c59aaa3..d7b76965426 100644 --- a/build/crypto.m4 +++ b/build/crypto.m4 @@ -242,7 +242,7 @@ AC_DEFUN([TS_CHECK_CRYPTO_TLS13], [ #include ]], [[ -#ifndef TLS1_3_VERSION +#ifdef OPENSSL_NO_TLS1_3 # error no TLS1_3 support #endif ]]) From 6a633e6d13363316c4f8fdcd0467e8f91b0d74c4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 18 Aug 2017 14:45:02 +0900 Subject: [PATCH 0027/1313] Fix TLS 1.3 check Check for TLS1_3_VERSION was still needed for OpenSSL < 1.1.1 --- build/crypto.m4 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/crypto.m4 b/build/crypto.m4 index d7b76965426..0405671e580 100644 --- a/build/crypto.m4 +++ b/build/crypto.m4 @@ -242,6 +242,9 @@ AC_DEFUN([TS_CHECK_CRYPTO_TLS13], [ #include ]], [[ +#ifndef TLS1_3_VERSION +# error no TLS1_3 support +#endif #ifdef OPENSSL_NO_TLS1_3 # error no TLS1_3 support #endif From 8f7f0a8300e20b55c61f76acf355439710e1add4 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 18 Aug 2017 14:30:55 +0900 Subject: [PATCH 0028/1313] Add QUICDebugNames::error_class and QUICDebugNames::error_code --- iocore/net/quic/QUICDebugNames.cc | 40 +++++++++++++++++++++++++++++++ iocore/net/quic/QUICDebugNames.h | 3 +++ 2 files changed, 43 insertions(+) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 74f7a2a742f..b3c738cacac 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -90,6 +90,46 @@ QUICDebugNames::frame_type(QUICFrameType type) } } +const char * +QUICDebugNames::error_class(QUICErrorClass cls) +{ + switch (cls) { + case QUICErrorClass::NONE: + return "NONE"; + case QUICErrorClass::AQPPLICATION_SPECIFIC: + return "AQPPLICATION_SPECIFIC"; + case QUICErrorClass::HOST_LOCAL: + return "HOST_LOCAL"; + case QUICErrorClass::QUIC_TRANSPORT: + return "QUIC_TRANSPORT"; + case QUICErrorClass::CRYPTOGRAPHIC: + return "CRYPTOGRAPHIC"; + default: + return "UNKNOWN"; + } +} + +const char * +QUICDebugNames::error_code(QUICErrorCode code) +{ + switch (code) { + case QUICErrorCode::APPLICATION_SPECIFIC_ERROR: + return "APPLICATION_SPECIFIC_ERROR"; + case QUICErrorCode::HOST_LOCAL_ERROR: + return "HOST_LOCAL_ERROR"; + case QUICErrorCode::QUIC_TRANSPORT_ERROR: + return "QUIC_TRANSPORT_ERROR"; + case QUICErrorCode::QUIC_INTERNAL_ERROR: + return "QUIC_INTERNAL_ERROR"; + case QUICErrorCode::CRYPTOGRAPHIC_ERROR: + return "CRYPTOGRAPHIC_ERROR"; + case QUICErrorCode::TLS_HANDSHAKE_FAILED: + return "TLS_HANDSHAKE_FAILED"; + default: + return "UNKNOWN"; + } +} + const char * QUICDebugNames::vc_event(int event) { diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index a6fe7154ad0..fabd07607fe 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -30,6 +30,9 @@ class QUICDebugNames public: static const char *packet_type(QUICPacketType type); static const char *frame_type(QUICFrameType type); + static const char *error_class(QUICErrorClass cls); + static const char *error_code(QUICErrorCode code); + // TODO: move to somewhere static const char *vc_event(int event); }; From 8eaad3da7e604b97fe3dc9c34d3094aad3bed3b1 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 18 Aug 2017 14:32:45 +0900 Subject: [PATCH 0029/1313] Set IPV6_V6ONLY socket option --- iocore/net/UnixUDPNet.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iocore/net/UnixUDPNet.cc b/iocore/net/UnixUDPNet.cc index b925c0583b3..c6d4602dc5d 100644 --- a/iocore/net/UnixUDPNet.cc +++ b/iocore/net/UnixUDPNet.cc @@ -595,6 +595,10 @@ UDPNetProcessor::UDPBind(Continuation *cont, sockaddr const *addr, int send_bufs } } + if (ats_is_ip6(addr) && (res = safe_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, SOCKOPT_ON, sizeof(int))) < 0) { + goto Lerror; + } + if ((res = socketManager.ink_bind(fd, addr, ats_ip_size(addr))) < 0) { goto Lerror; } @@ -630,6 +634,8 @@ UDPNetProcessor::UDPBind(Continuation *cont, sockaddr const *addr, int send_bufs if (fd != NO_FD) { socketManager.close(fd); } + Debug("udpnet", "Error: %s (%d)", strerror(errno), errno); + cont->handleEvent(NET_EVENT_DATAGRAM_ERROR, nullptr); return ACTION_IO_ERROR; } From 5fe89243e0d21d4cf0a1c268cb85ec7840f0198a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 18 Aug 2017 14:35:57 +0900 Subject: [PATCH 0030/1313] Fix "Invalid argument" error on sending UDP packet --- iocore/net/UnixUDPNet.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/iocore/net/UnixUDPNet.cc b/iocore/net/UnixUDPNet.cc index c6d4602dc5d..ee2c591eebd 100644 --- a/iocore/net/UnixUDPNet.cc +++ b/iocore/net/UnixUDPNet.cc @@ -780,7 +780,7 @@ UDPQueue::SendUDPPacket(UDPPacketInternal *p, int32_t /* pktLen ATS_UNUSED */) msg.msg_flags = 0; #endif msg.msg_name = (caddr_t)&p->to.sa; - msg.msg_namelen = sizeof(p->to.sa); + msg.msg_namelen = ats_ip_size(p->to); iov_len = 0; for (IOBufferBlock *b = p->chain.get(); b != nullptr; b = b->next.get()) { @@ -798,6 +798,10 @@ UDPQueue::SendUDPPacket(UDPPacketInternal *p, int32_t /* pktLen ATS_UNUSED */) n = ::sendmsg(p->conn->getFd(), &msg, 0); if ((n >= 0) || ((n < 0) && (errno != EAGAIN))) { // send succeeded or some random error happened. + if (n < 0) { + Debug("udp-send", "Error: %s (%d)", strerror(errno), errno); + } + break; } if (errno == EAGAIN) { From 2ec9b809a898c083bad84abfff87e3dd99416c36 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 18 Aug 2017 14:38:11 +0900 Subject: [PATCH 0031/1313] Set sa_family when initialize QUICNetVConnection --- iocore/net/QUICPacketHandler.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 9286ada24be..2edb33881dd 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -115,6 +115,9 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) vc->set_context(NET_VCONNECTION_IN); vc->read.triggered = 1; vc->start(this->_ssl_ctx); + vc->options.ip_proto = NetVCOptions::USE_UDP; + vc->options.ip_family = udpPacket->from.sa.sa_family; + // TODO: Handle Connection ID of Client Cleartext / Non-Final Server Cleartext Packet this->_connections.put(qPkt->connection_id(), vc); } From 6ea3b7d6c2bd0dc32c88f90e841c6d7092ff12b7 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 18 Aug 2017 14:40:32 +0900 Subject: [PATCH 0032/1313] Fix max data size of STREAM frame --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 16 +++++++++++++--- iocore/net/quic/Mock.h | 14 +++++++++++++- iocore/net/quic/QUICFrameTransmitter.h | 1 + iocore/net/quic/QUICStream.cc | 10 ++++------ iocore/net/quic/QUICStream.h | 6 ++++-- iocore/net/quic/QUICStreamManager.cc | 2 +- iocore/net/quic/test/test_QUICStream.cc | 6 +++--- 8 files changed, 40 insertions(+), 16 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 1a143b9c36b..8f51030568d 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -165,6 +165,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICCrypto *get_crypto() override; uint32_t maximum_quic_packet_size() override; uint32_t minimum_quic_packet_size() override; + uint32_t maximum_stream_frame_data_size() override; uint32_t pmtu() override; void close(QUICError error) override; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 421555ab12e..b09e9307588 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -44,8 +44,9 @@ #define DebugQUICCon(fmt, ...) \ Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) -const static uint32_t MINIMUM_MTU = 1280; -const static uint32_t MAX_PACKET_OVERHEAD = 25; // Max long header len(17) + FNV-1a hash len(8) +const static uint32_t MINIMUM_MTU = 1280; +const static uint32_t MAX_PACKET_OVERHEAD = 25; // Max long header len(17) + FNV-1a hash len(8) +const static uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); @@ -159,6 +160,12 @@ QUICNetVConnection::maximum_quic_packet_size() } } +uint32_t +QUICNetVConnection::maximum_stream_frame_data_size() +{ + return this->maximum_quic_packet_size() - MAX_STREAM_FRAME_OVERHEAD - MAX_PACKET_OVERHEAD; +} + void QUICNetVConnection::transmit_packet(std::unique_ptr packet) { @@ -287,7 +294,8 @@ QUICNetVConnection::state_handshake(int event, Event *data) if (error.cls != QUICErrorClass::NONE) { // TODO: Send error if needed - DebugQUICCon("QUICError: cls=%u, code=0x%x", static_cast(error.cls), static_cast(error.code)); + DebugQUICCon("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error.cls), static_cast(error.cls), + QUICDebugNames::error_code(error.code), static_cast(error.code)); } if (this->_handshake_handler && this->_handshake_handler->is_completed()) { @@ -446,6 +454,8 @@ QUICError QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_ptr packet) { if (packet->size() < this->minimum_quic_packet_size()) { + DebugQUICCon("%" PRId32 ", %" PRId32, packet->size(), this->minimum_quic_packet_size()); + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); } diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 6aab61155c1..561feeb1a19 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -87,6 +87,12 @@ class MockQUICConnection : public QUICConnection return 1200; } + uint32_t + maximum_stream_frame_data_size() override + { + return 1160; + } + uint32_t pmtu() override { @@ -142,8 +148,14 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter class MockQUICFrameTransmitter : public QUICFrameTransmitter { void - transmit_frame(std::unique_ptr frame) + transmit_frame(std::unique_ptr frame) override + { + } + + uint32_t + maximum_stream_frame_data_size() override { + return 1160; } }; diff --git a/iocore/net/quic/QUICFrameTransmitter.h b/iocore/net/quic/QUICFrameTransmitter.h index 8612dafa5af..ce3c267bd95 100644 --- a/iocore/net/quic/QUICFrameTransmitter.h +++ b/iocore/net/quic/QUICFrameTransmitter.h @@ -34,4 +34,5 @@ class QUICFrameTransmitter * This sends QUIC_PACKET_WRITE_READY event. */ virtual void transmit_frame(std::unique_ptr frame) = 0; + virtual uint32_t maximum_stream_frame_data_size() = 0; }; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index f80ed0f7380..db25063f37b 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -30,11 +30,11 @@ const static char *tag = "quic_stream"; void -QUICStream::init(QUICStreamManager *manager, QUICStreamId id) +QUICStream::init(QUICStreamManager *manager, QUICConnection *qc, QUICStreamId id) { this->_streamManager = manager; - - this->_id = id; + this->_qc = qc; + this->_id = id; this->mutex = new_ProxyMutex(); } @@ -286,9 +286,7 @@ QUICStream::_send() IOBufferReader *reader = this->_write_vio.get_reader(); int64_t bytes_avail = reader->read_avail(); int64_t total_len = 0; - // TODO: refer maximum_quic_packet_size - // uint32_t max_size = this->client_vc->maximum_quic_packet_size() - MAX_STREAM_FRAME_HEADER_LEN(15) - MAX_PACKET_OVERHEAD(25); - uint32_t max_size = 1212; + uint32_t max_size = this->_qc->maximum_stream_frame_data_size(); while (total_len < bytes_avail) { int64_t data_len = reader->block_read_avail(); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 7cae47f9a52..aef9dcaf447 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -31,6 +31,7 @@ #include "QUICFrame.h" #include "QUICStreamState.h" +class QUICConnection; class QUICStreamState; class QUICStreamManager; @@ -44,7 +45,7 @@ class QUICStream : public VConnection QUICStream() : VConnection(nullptr) {} ~QUICStream() {} - void init(QUICStreamManager *manager, uint32_t id); + void init(QUICStreamManager *manager, QUICConnection *qc, uint32_t id); void start(); int main_event_handler(int event, void *data); @@ -94,5 +95,6 @@ class QUICStream : public VConnection // TODO: Consider to replace with ts/RbTree.h or other data structure std::map> _request_stream_frame_buffer; - QUICStreamManager *_streamManager; + QUICStreamManager *_streamManager = nullptr; + QUICConnection *_qc = nullptr; }; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index e9f058d8fd1..fe6be6e31d3 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -104,7 +104,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) if (!stream) { // TODO Free the stream somewhere stream = THREAD_ALLOC_INIT(quicStreamAllocator, this_ethread()); - stream->init(this, stream_id); + stream->init(this, this->_qc, stream_id); stream->start(); this->stream_list.push(stream); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index e31ddb982c6..d60867a5156 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -47,7 +47,7 @@ TEST_CASE("QUICStream_assembling_byte_stream_1", "[quic]") IOBufferReader *reader = read_buffer->alloc_reader(); std::unique_ptr stream(new QUICStream()); - stream->init(nullptr, stream_id); + stream->init(nullptr, nullptr, stream_id); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_1); @@ -73,7 +73,7 @@ TEST_CASE("QUICStream_assembling_byte_stream_2", "[quic]") IOBufferReader *reader = read_buffer->alloc_reader(); std::unique_ptr stream(new QUICStream()); - stream->init(nullptr, stream_id); + stream->init(nullptr, nullptr, stream_id); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -99,7 +99,7 @@ TEST_CASE("QUICStream_assembling_byte_stream_3", "[quic]") IOBufferReader *reader = read_buffer->alloc_reader(); std::unique_ptr stream(new QUICStream()); - stream->init(nullptr, stream_id); + stream->init(nullptr, nullptr, stream_id); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); From 71f40486164fdc29a86bd80f0a730e1d6ccbda6c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 18 Aug 2017 14:59:41 +0900 Subject: [PATCH 0033/1313] Exchange Transport Parameters This commit just enable to exhcange the parameters, and the parameters are not loded from configuration nor processed. --- iocore/net/P_QUICNetVConnection.h | 5 ++ iocore/net/P_QUICPacketHandler.h | 3 +- iocore/net/QUICNetProcessor.cc | 7 ++ iocore/net/QUICNetVConnection.cc | 27 +++++- iocore/net/quic/Makefile.am | 2 + iocore/net/quic/Mock.h | 88 +++++++++++++++++++ iocore/net/quic/QUICConnection.h | 15 ++-- iocore/net/quic/QUICCrypto.cc | 4 +- iocore/net/quic/QUICCrypto.h | 2 +- iocore/net/quic/QUICGlobals.cc | 3 + iocore/net/quic/QUICGlobals.h | 37 ++++++++ iocore/net/quic/QUICPacket.cc | 6 -- iocore/net/quic/QUICPacket.h | 4 - iocore/net/quic/QUICTransportParameters.cc | 60 +++++++++++-- iocore/net/quic/QUICTransportParameters.h | 28 ++++-- iocore/net/quic/QUICTypes.cc | 6 ++ iocore/net/quic/QUICTypes.h | 5 ++ iocore/net/quic/test/Makefile.am | 11 ++- iocore/net/quic/test/test_QUICCrypto.cc | 5 +- .../quic/test/test_QUICTransportParameters.cc | 4 +- 20 files changed, 285 insertions(+), 37 deletions(-) create mode 100644 iocore/net/quic/QUICGlobals.cc create mode 100644 iocore/net/quic/QUICGlobals.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 8f51030568d..dda0d7c42dc 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -167,6 +167,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection uint32_t minimum_quic_packet_size() override; uint32_t maximum_stream_frame_data_size() override; uint32_t pmtu() override; + void set_transport_parameters(std::unique_ptr tp) override; + const QUICTransportParameters &local_transport_parameters() override; void close(QUICError error) override; // QUICConnection (QUICPacketTransmitter) @@ -190,6 +192,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection uint32_t _pmtu = 1280; + std::unique_ptr _local_transport_parameters; + std::unique_ptr _remote_transport_parameters; + // TODO: use custom allocator and make them std::unique_ptr or std::shared_ptr // or make them just member variables. QUICVersionNegotiator *_version_negotiator = nullptr; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 4d21060854b..64463e4ef51 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -26,7 +26,8 @@ #include "ts/ink_platform.h" #include "P_Connection.h" #include "P_NetAccept.h" -#include "P_QUICNetVConnection.h" + +class QUICNetVConnection; struct QUICPacketHandler : public NetAccept { public: diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 2eab6f830b1..f635210bb64 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -24,7 +24,9 @@ #include "P_Net.h" #include "ts/I_Layout.h" #include "I_RecHttp.h" +#include "QUICGlobals.h" #include "QUICConfig.h" +#include "QUICTransportParameters.h" // #include "P_QUICUtils.h" // @@ -51,6 +53,7 @@ QUICNetProcessor::cleanup() int QUICNetProcessor::start(int, size_t stacksize) { + QUIC::init(); // This initialization order matters ... // QUICInitializeLibrary(); QUICConfig::startup(); @@ -65,6 +68,10 @@ QUICNetProcessor::start(int, size_t stacksize) this->_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(this->_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(this->_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_add_custom_ext(this->_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); SSLConfig::scoped_config params; SSLParseCertificateConfiguration(params, this->_ssl_ctx); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b09e9307588..4d2c7cb0fa2 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -88,7 +88,7 @@ void QUICNetVConnection::start(SSL_CTX *ssl_ctx) { this->_version_negotiator = new QUICVersionNegotiator(&this->_packet_factory, this); - this->_crypto = new QUICCrypto(ssl_ctx, this->netvc_context); + this->_crypto = new QUICCrypto(ssl_ctx, this); this->_packet_factory.set_crypto_module(this->_crypto); // FIXME Should these have to be shared_ptr? @@ -101,6 +101,19 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) std::shared_ptr congestionController = std::make_shared(); this->_frame_dispatcher = new QUICFrameDispatcher(this, this->_stream_manager, flowController, congestionController, this->_loss_detector); + + // FIXME Fill appropriate values + // MUSTs + QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(); + tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, {reinterpret_cast("\x00\x00\x00\x00"), 4}); + tp->add(QUICTransportParameterId::INITIAL_MAX_DATA, {reinterpret_cast("\x00\x00\x00\x00"), 4}); + tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, {reinterpret_cast("\x00\x00\x00\x00"), 4}); + tp->add(QUICTransportParameterId::IDLE_TIMEOUT, {reinterpret_cast("\x00\x00"), 2}); + tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); + // MAYs + // this->_local_transport_parameters.add(QUICTransportParameterId::TRUNCATE_CONNECTION_ID, {}); + // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); + this->_local_transport_parameters = std::unique_ptr(tp); } void @@ -140,6 +153,18 @@ QUICNetVConnection::pmtu() return this->_pmtu; } +void +QUICNetVConnection::set_transport_parameters(std::unique_ptr tp) +{ + this->_remote_transport_parameters = std::move(tp); +} + +const QUICTransportParameters & +QUICNetVConnection::local_transport_parameters() +{ + return *this->_local_transport_parameters; +} + uint32_t QUICNetVConnection::minimum_quic_packet_size() { diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 21e1fcad2c2..3316dc477b6 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -40,6 +40,7 @@ QUICCrypto_impl = QUICCrypto_openssl.cc endif libquic_a_SOURCES = \ + QUICGlobals.cc \ QUICTypes.cc \ QUICPacket.cc \ QUICFrame.cc \ @@ -54,6 +55,7 @@ libquic_a_SOURCES = \ QUICHandshake.cc \ QUICCrypto.cc \ $(QUICCrypto_impl) \ + QUICTransportParameters.cc \ QUICAckFrameCreator.cc \ QUICConfig.cc \ QUICDebugNames.cc \ diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 561feeb1a19..05d7af9bd97 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -28,6 +28,74 @@ #include "QUICEvents.h" #include "QUICPacketTransmitter.h" +class MockNetVConnection : public NetVConnection +{ +public: + MockNetVConnection(NetVConnectionContext_t context = NET_VCONNECTION_OUT) : NetVConnection() { netvc_context = context; } + VIO * + do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) + { + return nullptr; + }; + VIO * + do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) + { + return nullptr; + }; + void do_io_close(int lerrno = -1){}; + void do_io_shutdown(ShutdownHowTo_t howto){}; + void reenable(VIO *vio){}; + void reenable_re(VIO *vio){}; + void set_active_timeout(ink_hrtime timeout_in){}; + void set_inactivity_timeout(ink_hrtime timeout_in){}; + void cancel_active_timeout(){}; + void cancel_inactivity_timeout(){}; + void add_to_keep_alive_queue(){}; + void remove_from_keep_alive_queue(){}; + bool + add_to_active_queue() + { + return true; + }; + ink_hrtime + get_active_timeout() + { + return 0; + } + ink_hrtime + get_inactivity_timeout() + { + return 0; + } + void + apply_options() + { + } + SOCKET + get_socket() + { + return 0; + } + int + set_tcp_init_cwnd(int init_cwnd) + { + return 0; + } + int + set_tcp_congestion_control(int side) + { + return 0; + } + void set_local_addr(){}; + void set_remote_addr(){}; + + NetVConnectionContext_t + get_context() const + { + return netvc_context; + } +}; + class MockQUICConnection : public QUICConnection { public: @@ -99,6 +167,17 @@ class MockQUICConnection : public QUICConnection return 1280; } + void + set_transport_parameters(std::unique_ptr tp) override + { + } + + const QUICTransportParameters & + local_transport_parameters() override + { + return dummy_transport_parameters; + } + void close(QUICError error) override { @@ -115,6 +194,8 @@ class MockQUICConnection : public QUICConnection Ptr _mutex; int _totalFrameCount = 0; int _frameCount[256] = {0}; + + QUICTransportParametersInEncryptedExtensions dummy_transport_parameters; }; class MockQUICPacketTransmitter : public QUICPacketTransmitter @@ -303,3 +384,10 @@ class MockQUICFlowController : public QUICFlowController int _totalFrameCount = 0; int _frameCount[256] = {0}; }; + +void NetVConnection::cancel_OOB(){}; +Action * +NetVConnection::send_OOB(Continuation *, char *, int) +{ + return nullptr; +} diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 22f373e922b..4efb317b56e 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -26,6 +26,7 @@ #include "QUICPacketTransmitter.h" #include "QUICFrameTransmitter.h" #include "QUICFrameHandler.h" +#include "QUICTransportParameters.h" class QUICApplication; class QUICCrypto; @@ -33,10 +34,12 @@ class QUICCrypto; class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler { public: - virtual QUICApplication *get_application(QUICStreamId stream_id) = 0; - virtual QUICCrypto *get_crypto() = 0; - virtual uint32_t maximum_quic_packet_size() = 0; - virtual uint32_t minimum_quic_packet_size() = 0; - virtual uint32_t pmtu() = 0; - virtual void close(QUICError error) = 0; + virtual QUICApplication *get_application(QUICStreamId stream_id) = 0; + virtual QUICCrypto *get_crypto() = 0; + virtual uint32_t maximum_quic_packet_size() = 0; + virtual uint32_t minimum_quic_packet_size() = 0; + virtual uint32_t pmtu() = 0; + virtual void set_transport_parameters(std::unique_ptr tp) = 0; + virtual const QUICTransportParameters &local_transport_parameters() = 0; + virtual void close(QUICError error) = 0; }; diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index f3df0a6454b..8eb13854632 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -20,6 +20,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "QUICGlobals.h" #include "QUICCrypto.h" #include @@ -82,9 +83,10 @@ QUICPacketProtection::key_phase() const // // QUICCrypto // -QUICCrypto::QUICCrypto(SSL_CTX *ssl_ctx, NetVConnectionContext_t c) : _netvc_context(c) +QUICCrypto::QUICCrypto(SSL_CTX *ssl_ctx, NetVConnection *vc) : _netvc_context(vc->get_context()) { this->_ssl = SSL_new(ssl_ctx); + SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_vc_index, vc); if (this->_netvc_context == NET_VCONNECTION_IN) { SSL_set_accept_state(this->_ssl); } else if (this->_netvc_context == NET_VCONNECTION_OUT) { diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICCrypto.h index e018680ed7d..0c704b2e77a 100644 --- a/iocore/net/quic/QUICCrypto.h +++ b/iocore/net/quic/QUICCrypto.h @@ -66,7 +66,7 @@ class QUICPacketProtection class QUICCrypto { public: - QUICCrypto(SSL_CTX *, NetVConnectionContext_t); + QUICCrypto(SSL_CTX *, NetVConnection *); ~QUICCrypto(); bool handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len); diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc new file mode 100644 index 00000000000..68571b54e00 --- /dev/null +++ b/iocore/net/quic/QUICGlobals.cc @@ -0,0 +1,3 @@ +#include "QUICGlobals.h" + +int QUIC::ssl_quic_vc_index = -1; diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h new file mode 100644 index 00000000000..2dcdef34d19 --- /dev/null +++ b/iocore/net/quic/QUICGlobals.h @@ -0,0 +1,37 @@ +/** @file + * + * QUIC Globals + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +class QUIC +{ +public: + static void + init() + { + ssl_quic_vc_index = SSL_get_ex_new_index(0, (void *)"NetVC index", nullptr, nullptr, nullptr); + } + static int ssl_quic_vc_index; +}; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index cb450803edf..278daaedbf5 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -31,12 +31,6 @@ static const int OFFSET_PAYLOAD = 17; static const int LONGHEADER_LENGTH = 17; static const int FNV1A_HASH_LEN = 8; -ats_unique_buf -ats_unique_malloc(size_t size) -{ - return ats_unique_buf(reinterpret_cast(ats_malloc(size)), [](void *p) { ats_free(p); }); -} - const uint8_t * QUICPacketHeader::buf() { diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index e7192368fb5..32a087bc9b4 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -36,10 +36,6 @@ #define QUIC_FIELD_OFFSET_PACKET_NUMBER 4 #define QUIC_FIELD_OFFSET_PAYLOAD 5 -// TODO: move to lib/ts/ink_memory.h? -using ats_unique_buf = std::unique_ptr; -ats_unique_buf ats_unique_malloc(size_t size); - class QUICPacketHeader { public: diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index c7fe73678a4..fe0d0d8128c 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -22,13 +22,24 @@ */ #include +#include "QUICGlobals.h" #include "QUICTransportParameters.h" +#include "QUICConnection.h" +#include "../P_QUICNetVConnection.h" + +const static int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; + +QUICTransportParameters::QUICTransportParameters(const uint8_t *buf, size_t len) +{ + this->_buf = ats_unique_malloc(len); + memcpy(this->_buf.get(), buf, len); +} QUICTransportParameterValue QUICTransportParameters::get(QUICTransportParameterId tpid) const { QUICTransportParameterValue value; - const uint8_t *p = this->_buf + this->_parameters_offset(); + const uint8_t *p = this->_buf.get() + this->_parameters_offset(); uint16_t n = (p[0] << 8) + p[1]; p += 2; @@ -110,13 +121,13 @@ QUICTransportParametersInClientHello::_parameters_offset() const QUICVersion QUICTransportParametersInClientHello::negotiated_version() const { - return QUICTypeUtil::read_QUICVersion(this->_buf); + return QUICTypeUtil::read_QUICVersion(this->_buf.get()); } QUICVersion QUICTransportParametersInClientHello::initial_version() const { - return QUICTypeUtil::read_QUICVersion(this->_buf + sizeof(QUICVersion)); + return QUICTypeUtil::read_QUICVersion(this->_buf.get() + sizeof(QUICVersion)); } void @@ -138,8 +149,9 @@ QUICTransportParametersInEncryptedExtensions::_store(uint8_t *buf, uint16_t *len const uint8_t * QUICTransportParametersInEncryptedExtensions::supported_versions(uint16_t *n) const { - *n = (this->_buf[0] << 8) + this->_buf[1]; - return this->_buf + 2; + uint8_t *b = this->_buf.get(); + *n = (b[0] << 8) + b[1]; + return b + 2; } void @@ -151,5 +163,41 @@ QUICTransportParametersInEncryptedExtensions::add_version(QUICVersion version) std::ptrdiff_t QUICTransportParametersInEncryptedExtensions::_parameters_offset() const { - return 2 + 4 * ((this->_buf[0] << 8) + this->_buf[1]); + const uint8_t *b = this->_buf.get(); + return 2 + 4 * ((b[0] << 8) + b[1]); +} + +// +// QUICTransportParametersHandler +// + +int +QUICTransportParametersHandler::add(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char **out, size_t *outlen, + X509 *x, size_t chainidx, int *al, void *add_arg) +{ + QUICConnection *qc = + static_cast(static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_vc_index))); + *out = reinterpret_cast(ats_malloc(TRANSPORT_PARAMETERS_MAXIMUM_SIZE)); + qc->local_transport_parameters().store(const_cast(*out), reinterpret_cast(outlen)); + + return 1; +} + +void +QUICTransportParametersHandler::free(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *out, void *add_arg) +{ + ats_free(const_cast(out)); +} + +int +QUICTransportParametersHandler::parse(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *in, size_t inlen, + X509 *x, size_t chainidx, int *al, void *parse_arg) +{ + QUICConnection *qc = + static_cast(static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_vc_index))); + QUICTransportParametersInClientHello *tp = new QUICTransportParametersInClientHello(in, inlen); + std::unique_ptr utp = std::unique_ptr(tp); + qc->set_transport_parameters(std::move(utp)); + + return 1; } diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 244b33e2ec4..40373b41cdb 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -23,6 +23,7 @@ #pragma once +#include #include "QUICTypes.h" #include "ts/Map.h" #include @@ -73,15 +74,16 @@ typedef struct _QUICTransportParameterValue { class QUICTransportParameters { public: - QUICTransportParameters(const uint8_t *buf) : _buf(buf){}; + QUICTransportParameters(const uint8_t *buf, size_t len); QUICTransportParameterValue get(QUICTransportParameterId id) const; void add(QUICTransportParameterId id, QUICTransportParameterValue value); void store(uint8_t *buf, uint16_t *len) const; protected: + QUICTransportParameters(){}; virtual std::ptrdiff_t _parameters_offset() const = 0; virtual void _store(uint8_t *buf, uint16_t *len) const = 0; - const uint8_t *_buf; + ats_unique_buf _buf = {nullptr, [](void *p) { ats_free(p); }}; Map _parameters; }; @@ -89,8 +91,8 @@ class QUICTransportParametersInClientHello : public QUICTransportParameters { public: QUICTransportParametersInClientHello(QUICVersion negotiated_version, QUICVersion initial_version) - : QUICTransportParameters(nullptr), _negotiated_version(negotiated_version), _initial_version(initial_version){}; - QUICTransportParametersInClientHello(const uint8_t *buf) : QUICTransportParameters(buf){}; + : QUICTransportParameters(), _negotiated_version(negotiated_version), _initial_version(initial_version){}; + QUICTransportParametersInClientHello(const uint8_t *buf, size_t len) : QUICTransportParameters(buf, len){}; QUICVersion negotiated_version() const; QUICVersion initial_version() const; @@ -106,8 +108,8 @@ class QUICTransportParametersInClientHello : public QUICTransportParameters class QUICTransportParametersInEncryptedExtensions : public QUICTransportParameters { public: - QUICTransportParametersInEncryptedExtensions() : QUICTransportParameters(nullptr){}; - QUICTransportParametersInEncryptedExtensions(const uint8_t *buf) : QUICTransportParameters(buf){}; + QUICTransportParametersInEncryptedExtensions() : QUICTransportParameters(){}; + QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len) : QUICTransportParameters(buf, len){}; const uint8_t *supported_versions(uint16_t *n) const; void add_version(QUICVersion version); @@ -118,3 +120,17 @@ class QUICTransportParametersInEncryptedExtensions : public QUICTransportParamet uint8_t _n_versions = 0; QUICVersion _versions[256] = {}; }; + +class QUICTransportParametersHandler +{ +public: + static constexpr int TRANSPORT_PARAMETER_ID = 26; + + static int add(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char **out, size_t *outlen, X509 *x, + size_t chainidx, int *al, void *add_arg); + + static void free(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *out, void *add_arg); + + static int parse(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *in, size_t inlen, X509 *x, + size_t chainidx, int *al, void *parse_arg); +}; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index cf4500035d9..e77f71fbffb 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -23,6 +23,12 @@ #include "QUICTypes.h" +ats_unique_buf +ats_unique_malloc(size_t size) +{ + return ats_unique_buf(reinterpret_cast(ats_malloc(size)), [](void *p) { ats_free(p); }); +} + const QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; bool diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index f01a4c7be41..f6898d98162 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -36,12 +36,17 @@ #include #include +#include "ts/ink_memory.h" // These magical defines should be removed when we implement seriously #define MAGIC_NUMBER_0 0 #define MAGIC_NUMBER_1 1 #define MAGIC_NUMBER_TRUE true +// TODO: move to lib/ts/ink_memory.h? +using ats_unique_buf = std::unique_ptr; +ats_unique_buf ats_unique_malloc(size_t size); + typedef uint64_t QUICPacketNumber; typedef uint32_t QUICVersion; typedef uint32_t QUICStreamId; diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 5837352cf98..fc06666d99a 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -120,6 +120,7 @@ test_QUICFrame_LDFLAGS = \ test_QUICFrame_SOURCES = \ main.cc \ test_QUICFrame.cc \ + ../QUICGlobals.cc \ ../QUICFrame.cc \ ../QUICPacket.cc \ ../QUICCrypto.cc \ @@ -142,7 +143,9 @@ test_QUICFrameDispatcher_LDFLAGS = \ test_QUICFrameDispatcher_SOURCES = \ main.cc \ test_QUICFrameDispatcher.cc \ + ../QUICGlobals.cc \ ../QUICFrameDispatcher.cc \ + ../QUICTransportParameters.cc \ ../QUICStreamManager.cc \ ../QUICFlowController.cc \ ../QUICCongestionController.cc \ @@ -236,11 +239,13 @@ test_QUICTransportParameters_LDFLAGS = \ test_QUICTransportParameters_SOURCES = \ main.cc \ test_QUICTransportParameters.cc \ + ../QUICGlobals.cc \ ../QUICTransportParameters.cc \ ../QUICTypes.cc test_QUICTransportParameters_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a # @@ -256,6 +261,7 @@ test_QUICCrypto_LDFLAGS = \ test_QUICCrypto_LDADD = \ @OPENSSL_LIBS@ \ $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a test_QUICCrypto_SOURCES = \ @@ -263,7 +269,8 @@ test_QUICCrypto_SOURCES = \ test_QUICCrypto.cc \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ - ../QUICCrypto.h + ../QUICCrypto.h \ + ../QUICGlobals.cc # # test_QUICLossDetector @@ -329,6 +336,7 @@ test_QUICAckFrameCreator_SOURCES = \ main.cc \ test_QUICAckFrameCreator.cc \ ../QUICAckFrameCreator.cc \ + ../QUICGlobals.cc \ ../QUICTypes.cc \ ../QUICFrame.cc \ ../QUICPacket.cc \ @@ -354,6 +362,7 @@ test_QUICVersionNegotiator_LDADD = \ test_QUICVersionNegotiator_SOURCES = \ main.cc \ test_QUICVersionNegotiator.cc \ + ../QUICGlobals.cc \ ../QUICTypes.cc \ ../QUICPacket.cc \ ../QUICCrypto.cc \ diff --git a/iocore/net/quic/test/test_QUICCrypto.cc b/iocore/net/quic/test/test_QUICCrypto.cc index f3c13c230d3..58d84e9b30b 100644 --- a/iocore/net/quic/test/test_QUICCrypto.cc +++ b/iocore/net/quic/test/test_QUICCrypto.cc @@ -33,6 +33,7 @@ #include +#include "Mock.h" #include "QUICCrypto.h" const static uint32_t MAX_HANDSHAKE_MSG_LEN = 2048; @@ -108,7 +109,7 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - QUICCrypto *client = new QUICCrypto(client_ssl_ctx, NET_VCONNECTION_OUT); + QUICCrypto *client = new QUICCrypto(client_ssl_ctx, new MockNetVConnection(NET_VCONNECTION_OUT)); // Server SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); @@ -118,7 +119,7 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - QUICCrypto *server = new QUICCrypto(server_ssl_ctx, NET_VCONNECTION_IN); + QUICCrypto *server = new QUICCrypto(server_ssl_ctx, new MockNetVConnection(NET_VCONNECTION_IN)); // Client Hello uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index 7999789b426..864eee6d971 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -45,7 +45,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") 0xab, 0xcd, // value }; - QUICTransportParametersInClientHello params_in_ch(buf); + QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf)); CHECK(params_in_ch.negotiated_version() == 0x01020304); CHECK(params_in_ch.initial_version() == 0x05060708); QUICTransportParameterValue value; @@ -111,7 +111,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") 0xab, 0xcd, // value }; - QUICTransportParametersInEncryptedExtensions params_in_ee(buf); + QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf)); const uint8_t *versions; uint16_t nversion; versions = params_in_ee.supported_versions(&nversion); From 5adb4a1d0c9ec1c803353f5d2bd868390463aa7a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 18 Aug 2017 15:23:10 +0900 Subject: [PATCH 0034/1313] clang-format --- iocore/net/quic/Mock.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 05d7af9bd97..b22e2d0247f 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -72,10 +72,7 @@ class MockNetVConnection : public NetVConnection { } SOCKET - get_socket() - { - return 0; - } + get_socket() { return 0; } int set_tcp_init_cwnd(int init_cwnd) { From 8790f3df35de521add33e18021b45337a5603647 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 18 Aug 2017 15:24:02 +0900 Subject: [PATCH 0035/1313] Add AL header --- iocore/net/quic/QUICGlobals.cc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index 68571b54e00..ca6e1518e19 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -1,3 +1,26 @@ +/** @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 "QUICGlobals.h" int QUIC::ssl_quic_vc_index = -1; From e27a5b83238a9b3a2ae2d6849d7981349ab12216 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 18 Aug 2017 15:24:17 +0900 Subject: [PATCH 0036/1313] Fix build issue on Fedora 26 --- iocore/net/quic/QUICTypes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index f6898d98162..2dd92251d55 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -34,6 +34,7 @@ #endif #include +#include #include #include #include "ts/ink_memory.h" From 82a41a975057018651b588d4f05b5356004d9887 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 21 Aug 2017 11:46:49 +0900 Subject: [PATCH 0037/1313] Revalidate negotiated version (server side) --- iocore/net/QUICNetVConnection.cc | 30 +++++++++++++++++++ iocore/net/quic/QUICTypes.h | 13 ++++---- iocore/net/quic/QUICVersionNegotiator.cc | 19 +++++++++--- iocore/net/quic/QUICVersionNegotiator.h | 2 ++ .../quic/test/test_QUICVersionNegotiator.cc | 4 +-- 5 files changed, 56 insertions(+), 12 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 4d2c7cb0fa2..db7abf9ae10 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -157,6 +157,36 @@ void QUICNetVConnection::set_transport_parameters(std::unique_ptr tp) { this->_remote_transport_parameters = std::move(tp); + + const QUICTransportParametersInClientHello *tp_in_ch = + dynamic_cast(this->_remote_transport_parameters.get()); + if (tp_in_ch) { + // Version revalidation + QUICVersion version = tp_in_ch->negotiated_version(); + if (this->_version_negotiator->revalidate(version) != QUICVersionNegotiationStatus::REVALIDATED) { + this->close({QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_VERSION_NEGOTIATION_MISMATCH}); + return; + } + if (tp_in_ch->negotiated_version() != tp_in_ch->initial_version()) { + // FIXME Check initial_version + /* If the initial version is different from the negotiated_version, a + * stateless server MUST check that it would have sent a version + * negotiation packet if it had received a packet with the indicated + * initial_version. (Draft-04 7.3.4. Version Negotiation Validation) + */ + this->close({QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_VERSION_NEGOTIATION_MISMATCH}); + return; + } + DebugQUICCon("Version negotiation revalidated: %x", packet->version()); + return; + } + + const QUICTransportParametersInEncryptedExtensions *tp_in_ee = + dynamic_cast(this->_remote_transport_parameters.get()); + if (tp_in_ee) { + // TODO Add client side implementation + return; + } } const QUICTransportParameters & diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 2dd92251d55..c595abfb580 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -123,12 +123,13 @@ enum class QUICErrorClass { }; enum class QUICErrorCode : uint32_t { - APPLICATION_SPECIFIC_ERROR = 0, - HOST_LOCAL_ERROR = 0x40000000, - QUIC_TRANSPORT_ERROR = 0x80000000, - QUIC_INTERNAL_ERROR = 0x80000001, - CRYPTOGRAPHIC_ERROR = 0xC0000000, - TLS_HANDSHAKE_FAILED = 0xC000001C, + APPLICATION_SPECIFIC_ERROR = 0, + HOST_LOCAL_ERROR = 0x40000000, + QUIC_TRANSPORT_ERROR = 0x80000000, + QUIC_INTERNAL_ERROR = 0x80000001, + QUIC_VERSION_NEGOTIATION_MISMATCH = 0x80000037, + CRYPTOGRAPHIC_ERROR = 0xC0000000, + TLS_HANDSHAKE_FAILED = 0xC000001C, // TODO Add error codes }; diff --git a/iocore/net/quic/QUICVersionNegotiator.cc b/iocore/net/quic/QUICVersionNegotiator.cc index 6e6856334c7..d08ee1b8a8b 100644 --- a/iocore/net/quic/QUICVersionNegotiator.cc +++ b/iocore/net/quic/QUICVersionNegotiator.cc @@ -36,7 +36,8 @@ QUICVersionNegotiationStatus QUICVersionNegotiator::negotiate(const QUICPacket *initial_packet) { if (this->_is_supported(initial_packet->version())) { - this->_status = QUICVersionNegotiationStatus::NEGOTIATED; + this->_status = QUICVersionNegotiationStatus::NEGOTIATED; + this->_negotiated_version = initial_packet->version(); } else { this->_tx->transmit_packet(this->_packet_factory->create_version_negotiation_packet(initial_packet)); } @@ -46,9 +47,19 @@ QUICVersionNegotiator::negotiate(const QUICPacket *initial_packet) QUICVersionNegotiationStatus QUICVersionNegotiator::revalidate(QUICVersion version) { - // TDOO revalidate the version - this->_status = QUICVersionNegotiationStatus::FAILED; - return _status; + if (this->_negotiated_version == version) { + this->_status = QUICVersionNegotiationStatus::REVALIDATED; + } else { + this->_status = QUICVersionNegotiationStatus::FAILED; + this->_negotiated_version = 0; + } + return this->_status; +} + +QUICVersion +QUICVersionNegotiator::negotiated_version() +{ + return this->_negotiated_version; } bool diff --git a/iocore/net/quic/QUICVersionNegotiator.h b/iocore/net/quic/QUICVersionNegotiator.h index 8410d755b2d..fd376933a26 100644 --- a/iocore/net/quic/QUICVersionNegotiator.h +++ b/iocore/net/quic/QUICVersionNegotiator.h @@ -37,8 +37,10 @@ class QUICVersionNegotiator QUICVersionNegotiationStatus status(); QUICVersionNegotiationStatus negotiate(const QUICPacket *initial_packet); QUICVersionNegotiationStatus revalidate(QUICVersion version); + QUICVersion negotiated_version(); private: + QUICVersion _negotiated_version = 0; QUICPacketFactory *_packet_factory = nullptr; QUICPacketTransmitter *_tx = nullptr; QUICVersionNegotiationStatus _status = QUICVersionNegotiationStatus::NOT_NEGOTIATED; diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 3d63e01781a..da415505ec7 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -42,6 +42,6 @@ TEST_CASE("QUICVersionNegotiator_Normal", "[quic]") // Revalidate version vn.revalidate(QUIC_SUPPORTED_VERSIONS[0]); - // FIXME Currently, revalidate() is not implemented yet - // CHECK(vn.status() == QUICVersionNegotiationStatus::REVALIDATED); + CHECK(vn.status() == QUICVersionNegotiationStatus::REVALIDATED); + CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); } From 78330c7f962d47c4a9483098d2e804779f4d56f0 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 21 Aug 2017 11:51:00 +0900 Subject: [PATCH 0038/1313] Fix a compile error --- iocore/net/QUICNetVConnection.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index db7abf9ae10..52372a38a70 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -177,7 +177,7 @@ QUICNetVConnection::set_transport_parameters(std::unique_ptrclose({QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_VERSION_NEGOTIATION_MISMATCH}); return; } - DebugQUICCon("Version negotiation revalidated: %x", packet->version()); + DebugQUICCon("Version negotiation revalidated: %x", tp_in_ch->negotiated_version()); return; } From 51e8f5a08df023ad2e1f5d96046045ff0d679ce8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 22 Aug 2017 09:07:32 +0900 Subject: [PATCH 0039/1313] Remove get_crypto from QUICNetVConnection Crypto module should not be exported because it's too powerful to touch it from QUICApplications except QUICHandshake. --- iocore/net/P_QUICNetVConnection.h | 1 - iocore/net/QUICNetVConnection.cc | 8 +------- iocore/net/quic/Mock.h | 6 ------ iocore/net/quic/QUICConnection.h | 2 -- iocore/net/quic/QUICHandshake.cc | 10 +++++----- iocore/net/quic/QUICHandshake.h | 3 ++- 6 files changed, 8 insertions(+), 22 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index dda0d7c42dc..58d8a47b39f 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -162,7 +162,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // QUICConnection QUICApplication *get_application(QUICStreamId stream_id) override; - QUICCrypto *get_crypto() override; uint32_t maximum_quic_packet_size() override; uint32_t minimum_quic_packet_size() override; uint32_t maximum_stream_frame_data_size() override; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 52372a38a70..e32c7aa2fc4 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -483,12 +483,6 @@ QUICNetVConnection::get_application(QUICStreamId stream_id) return this->_application; } -QUICCrypto * -QUICNetVConnection::get_crypto() -{ - return this->_crypto; -} - void QUICNetVConnection::net_read_io(NetHandler *nh, EThread *lthread) { @@ -525,7 +519,7 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_p this->_packet_factory.set_version(packet->version()); // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing) if (packet->has_valid_fnv1a_hash()) { - this->_handshake_handler = new QUICHandshake(new_ProxyMutex(), this); + this->_handshake_handler = new QUICHandshake(new_ProxyMutex(), this, this->_crypto); this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size()); } else { DebugQUICCon("Invalid FNV-1a hash value"); diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index b22e2d0247f..d74bde36af2 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -134,12 +134,6 @@ class MockQUICConnection : public QUICConnection return nullptr; } - QUICCrypto * - get_crypto() override - { - return nullptr; - } - uint32_t minimum_quic_packet_size() override { diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 4efb317b56e..19eb48dd710 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -29,13 +29,11 @@ #include "QUICTransportParameters.h" class QUICApplication; -class QUICCrypto; class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler { public: virtual QUICApplication *get_application(QUICStreamId stream_id) = 0; - virtual QUICCrypto *get_crypto() = 0; virtual uint32_t maximum_quic_packet_size() = 0; virtual uint32_t minimum_quic_packet_size() = 0; virtual uint32_t pmtu() = 0; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 067a3c0e358..a77763a41c7 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -48,7 +48,7 @@ const static int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size const static int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(ProxyMutex *m, QUICConnection *qc) : QUICApplication(m, qc) +QUICHandshake::QUICHandshake(ProxyMutex *m, QUICConnection *qc, QUICCrypto *c) : QUICApplication(m, qc), _crypto(c) { SET_HANDLER(&QUICHandshake::state_read_client_hello); } @@ -56,7 +56,7 @@ QUICHandshake::QUICHandshake(ProxyMutex *m, QUICConnection *qc) : QUICApplicatio bool QUICHandshake::is_completed() { - QUICCrypto *crypto = this->_client_qc->get_crypto(); + QUICCrypto *crypto = this->_crypto; return crypto->is_handshake_finished(); } @@ -156,7 +156,7 @@ QUICHandshake::_process_client_hello() I_WANNA_DUMP_THIS_BUF(msg, msg_len); // <----- DEBUG ----- - QUICCrypto *crypto = this->_client_qc->get_crypto(); + QUICCrypto *crypto = this->_crypto; uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t server_hello_len = 0; @@ -200,7 +200,7 @@ QUICHandshake::_process_client_finished() I_WANNA_DUMP_THIS_BUF(msg, msg_len); // <----- DEBUG ----- - QUICCrypto *crypto = this->_client_qc->get_crypto(); + QUICCrypto *crypto = this->_crypto; uint8_t out[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t out_len = 0; @@ -232,7 +232,7 @@ QUICHandshake::_process_client_finished() QUICError QUICHandshake::_process_handshake_complete() { - QUICCrypto *crypto = this->_client_qc->get_crypto(); + QUICCrypto *crypto = this->_crypto; int r = crypto->setup_session(); if (r) { diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index b364a930ffb..99107c7848a 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -47,7 +47,7 @@ class QUICHandshake : public QUICApplication { public: - QUICHandshake(ProxyMutex *m, QUICConnection *qc); + QUICHandshake(ProxyMutex *m, QUICConnection *qc, QUICCrypto *c); int state_read_client_hello(int event, Event *data); int state_read_client_finished(int event, Event *data); @@ -58,6 +58,7 @@ class QUICHandshake : public QUICApplication const uint8_t *negotiated_application_name(); private: + QUICCrypto *_crypto = nullptr; QUICError _process_client_hello(); QUICError _process_client_finished(); QUICError _process_handshake_complete(); From 0f3003b2f0b524b53f382c41593021fd54f0895b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 22 Aug 2017 09:28:31 +0900 Subject: [PATCH 0040/1313] Create mutexes in QUICApplication constructor There's no need to create and pass it from QUICNetVConnection --- iocore/net/QUICNetVConnection.cc | 4 ++-- iocore/net/quic/QUICApplication.cc | 2 +- iocore/net/quic/QUICApplication.h | 2 +- iocore/net/quic/QUICEchoApp.cc | 2 +- iocore/net/quic/QUICEchoApp.h | 2 +- iocore/net/quic/QUICHandshake.cc | 2 +- iocore/net/quic/QUICHandshake.h | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e32c7aa2fc4..fc1aec3689f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -475,7 +475,7 @@ QUICNetVConnection::get_application(QUICStreamId stream_id) // TODO: Instantiate negotiated application const uint8_t *application = this->_handshake_handler->negotiated_application_name(); if (memcmp(application, "hq", 2) == 0) { - QUICEchoApp *echo_app = new QUICEchoApp(new_ProxyMutex(), this); + QUICEchoApp *echo_app = new QUICEchoApp(this); this->_application = echo_app; } } @@ -519,7 +519,7 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_p this->_packet_factory.set_version(packet->version()); // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing) if (packet->has_valid_fnv1a_hash()) { - this->_handshake_handler = new QUICHandshake(new_ProxyMutex(), this, this->_crypto); + this->_handshake_handler = new QUICHandshake(this, this->_crypto); this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size()); } else { DebugQUICCon("Invalid FNV-1a hash value"); diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 6acbfb7722d..30c2f3053a3 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -81,7 +81,7 @@ QUICStreamIO::write_reenable() // // QUICApplication // -QUICApplication::QUICApplication(ProxyMutex *m, QUICConnection *qc) : Continuation(m) +QUICApplication::QUICApplication(QUICConnection *qc) : Continuation(new_ProxyMutex()) { this->_client_qc = qc; } diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index cc075fe0a5f..3e2426e56b4 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -63,7 +63,7 @@ class QUICStreamIO class QUICApplication : public Continuation { public: - QUICApplication(ProxyMutex *m, QUICConnection *qc); + QUICApplication(QUICConnection *qc); void set_stream(QUICStream *stream); bool is_stream_set(QUICStream *stream); diff --git a/iocore/net/quic/QUICEchoApp.cc b/iocore/net/quic/QUICEchoApp.cc index 4be18cc79f1..936995afb85 100644 --- a/iocore/net/quic/QUICEchoApp.cc +++ b/iocore/net/quic/QUICEchoApp.cc @@ -28,7 +28,7 @@ const static char *tag = "quic_echo_app"; -QUICEchoApp::QUICEchoApp(ProxyMutex *m, QUICConnection *qc) : QUICApplication(m, qc) +QUICEchoApp::QUICEchoApp(QUICConnection *qc) : QUICApplication(qc) { SET_HANDLER(&QUICEchoApp::main_event_handler); } diff --git a/iocore/net/quic/QUICEchoApp.h b/iocore/net/quic/QUICEchoApp.h index 541da2906f3..82e1239201d 100644 --- a/iocore/net/quic/QUICEchoApp.h +++ b/iocore/net/quic/QUICEchoApp.h @@ -34,7 +34,7 @@ class QUICEchoApp : public QUICApplication { public: - QUICEchoApp(ProxyMutex *m, QUICConnection *qc); + QUICEchoApp(QUICConnection *qc); int main_event_handler(int event, Event *data); }; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index a77763a41c7..a81daa3ff47 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -48,7 +48,7 @@ const static int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size const static int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(ProxyMutex *m, QUICConnection *qc, QUICCrypto *c) : QUICApplication(m, qc), _crypto(c) +QUICHandshake::QUICHandshake(QUICConnection *qc, QUICCrypto *c) : QUICApplication(qc), _crypto(c) { SET_HANDLER(&QUICHandshake::state_read_client_hello); } diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 99107c7848a..6f01e8089ee 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -47,7 +47,7 @@ class QUICHandshake : public QUICApplication { public: - QUICHandshake(ProxyMutex *m, QUICConnection *qc, QUICCrypto *c); + QUICHandshake(QUICConnection *qc, QUICCrypto *c); int state_read_client_hello(int event, Event *data); int state_read_client_finished(int event, Event *data); From 8562c59545fd70e0c5ad5e6c57d7f073fac9ce03 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 22 Aug 2017 09:29:28 +0900 Subject: [PATCH 0041/1313] Use pragma once --- iocore/net/quic/QUICCrypto.h | 5 +---- iocore/net/quic/QUICEchoApp.h | 4 +--- iocore/net/quic/QUICHandshake.h | 5 +---- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICCrypto.h index 0c704b2e77a..f4c7fc9762a 100644 --- a/iocore/net/quic/QUICCrypto.h +++ b/iocore/net/quic/QUICCrypto.h @@ -21,8 +21,7 @@ * limitations under the License. */ -#ifndef __QUIC_CRYPTO__ -#define __QUIC_CRYPTO__ +#pragma once #include @@ -117,5 +116,3 @@ class QUICCrypto QUICPacketProtection *_server_pp = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; }; - -#endif // __QUIC_CRYPTO__ diff --git a/iocore/net/quic/QUICEchoApp.h b/iocore/net/quic/QUICEchoApp.h index 82e1239201d..8a61f908508 100644 --- a/iocore/net/quic/QUICEchoApp.h +++ b/iocore/net/quic/QUICEchoApp.h @@ -21,8 +21,7 @@ * limitations under the License. */ -#ifndef __QUIC_ECHOAPP__ -#define __QUIC_ECHOAPP__ +#pragma once #include "QUICApplication.h" @@ -38,4 +37,3 @@ class QUICEchoApp : public QUICApplication int main_event_handler(int event, Event *data); }; -#endif // __QUIC_HANDSHAKE__ diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 6f01e8089ee..64074a0a246 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -21,8 +21,7 @@ * limitations under the License. */ -#ifndef __QUIC_HANDSHAKE__ -#define __QUIC_HANDSHAKE__ +#pragma once #include "QUICConnection.h" #include "QUICApplication.h" @@ -63,5 +62,3 @@ class QUICHandshake : public QUICApplication QUICError _process_client_finished(); QUICError _process_handshake_complete(); }; - -#endif // __QUIC_HANDSHAKE__ From c485128a5ca56b2f4621b8511218a6d11b4751c1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 22 Aug 2017 12:00:10 +0900 Subject: [PATCH 0042/1313] Introduce QUICApplicaionMap class To keep QUICNetVConnection focused on connection, delegate streams and applications mapping to QUICApplicationMap. --- iocore/net/P_QUICNetVConnection.h | 6 ++-- iocore/net/QUICNetVConnection.cc | 41 +++++++++++++--------------- iocore/net/quic/Makefile.am | 1 + iocore/net/quic/Mock.h | 6 ---- iocore/net/quic/QUICConnection.h | 1 - iocore/net/quic/QUICStream.cc | 6 ++-- iocore/net/quic/QUICStream.h | 6 ++-- iocore/net/quic/QUICStreamManager.cc | 13 +++------ iocore/net/quic/QUICStreamManager.h | 9 +++--- iocore/net/quic/test/Makefile.am | 1 + 10 files changed, 39 insertions(+), 51 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 58d8a47b39f..9c007417369 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -56,6 +56,7 @@ #include "quic/QUICStreamManager.h" #include "quic/QUICFlowController.h" #include "quic/QUICCongestionController.h" +#include "quic/QUICApplicationMap.h" // These are included here because older OpenQUIC libraries don't have them. // Don't copy these defines, or use their values directly, they are merely @@ -161,7 +162,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection virtual int64_t load_buffer_and_write(int64_t towrite, MIOBufferAccessor &buf, int64_t &total_written, int &needs) override; // QUICConnection - QUICApplication *get_application(QUICStreamId stream_id) override; uint32_t maximum_quic_packet_size() override; uint32_t minimum_quic_packet_size() override; uint32_t maximum_stream_frame_data_size() override; @@ -188,6 +188,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; QUICAckFrameCreator _ack_frame_creator; + QUICApplicationMap _application_map; uint32_t _pmtu = 1280; @@ -198,7 +199,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // or make them just member variables. QUICVersionNegotiator *_version_negotiator = nullptr; QUICHandshake *_handshake_handler = nullptr; - QUICApplication *_application = nullptr; QUICCrypto *_crypto = nullptr; std::shared_ptr _loss_detector = nullptr; std::shared_ptr _stream_manager = nullptr; @@ -222,6 +222,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICError _state_common_send_packet(); Ptr _transmitter_mutex; + + QUICApplication *_create_application(); }; typedef int (QUICNetVConnection::*QUICNetVConnHandler)(int, void *); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index fc1aec3689f..926c1d2f11f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -94,8 +94,7 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) // FIXME Should these have to be shared_ptr? this->_loss_detector = std::make_shared(this); this->_stream_manager = std::make_shared(); - this->_stream_manager->init(this); - this->_stream_manager->set_connection(this); // FIXME Want to remove; + this->_stream_manager->init(this, &this->_application_map); std::shared_ptr flowController = std::make_shared(); std::shared_ptr congestionController = std::make_shared(); @@ -126,7 +125,6 @@ QUICNetVConnection::free(EThread *t) delete this->_version_negotiator; delete this->_handshake_handler; - delete this->_application; delete this->_crypto; delete this->_frame_dispatcher; // XXX _loss_detector and _stream_manager are std::shared_ptr @@ -354,6 +352,8 @@ QUICNetVConnection::state_handshake(int event, Event *data) } if (this->_handshake_handler && this->_handshake_handler->is_completed()) { + DebugQUICCon("setup quic application"); + this->_application_map.set_default(this->_create_application()); DebugQUICCon("Enter state_connection_established"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); @@ -464,25 +464,6 @@ QUICNetVConnection::get_udp_con() return this->_udp_con; } -QUICApplication * -QUICNetVConnection::get_application(QUICStreamId stream_id) -{ - if (stream_id == STREAM_ID_FOR_HANDSHAKE) { - return static_cast(this->_handshake_handler); - } else { - if (!this->_application) { - DebugQUICCon("setup quic application"); - // TODO: Instantiate negotiated application - const uint8_t *application = this->_handshake_handler->negotiated_application_name(); - if (memcmp(application, "hq", 2) == 0) { - QUICEchoApp *echo_app = new QUICEchoApp(this); - this->_application = echo_app; - } - } - } - return this->_application; -} - void QUICNetVConnection::net_read_io(NetHandler *nh, EThread *lthread) { @@ -519,7 +500,10 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_p this->_packet_factory.set_version(packet->version()); // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing) if (packet->has_valid_fnv1a_hash()) { + // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not this->_handshake_handler = new QUICHandshake(this, this->_crypto); + this->_application_map.set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); + this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size()); } else { DebugQUICCon("Invalid FNV-1a hash value"); @@ -702,3 +686,16 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi return packet; } + +QUICApplication * +QUICNetVConnection::_create_application() +{ + const uint8_t *application = this->_handshake_handler->negotiated_application_name(); + if (memcmp(application, "hq", 2) == 0) { + return new QUICEchoApp(this); + } else { + DebugQUICCon("Unknown application has been negotiated: %s", application); + ink_assert(false); + return nullptr; + } +} diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 3316dc477b6..9d0ae8d4701 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -60,6 +60,7 @@ libquic_a_SOURCES = \ QUICConfig.cc \ QUICDebugNames.cc \ QUICApplication.cc \ + QUICApplicationMap.cc \ QUICEchoApp.cc include $(top_srcdir)/build/tidy.mk diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index d74bde36af2..d208edb029b 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -128,12 +128,6 @@ class MockQUICConnection : public QUICConnection ++_totalFrameCount; } - QUICApplication * - get_application(QUICStreamId stream_id) override - { - return nullptr; - } - uint32_t minimum_quic_packet_size() override { diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 19eb48dd710..a90b73fa45a 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -33,7 +33,6 @@ class QUICApplication; class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler { public: - virtual QUICApplication *get_application(QUICStreamId stream_id) = 0; virtual uint32_t maximum_quic_packet_size() = 0; virtual uint32_t minimum_quic_packet_size() = 0; virtual uint32_t pmtu() = 0; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index db25063f37b..edd19ea2554 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -30,10 +30,10 @@ const static char *tag = "quic_stream"; void -QUICStream::init(QUICStreamManager *manager, QUICConnection *qc, QUICStreamId id) +QUICStream::init(QUICStreamManager *manager, QUICFrameTransmitter *tx, QUICStreamId id) { this->_streamManager = manager; - this->_qc = qc; + this->_tx = tx; this->_id = id; this->mutex = new_ProxyMutex(); @@ -286,7 +286,7 @@ QUICStream::_send() IOBufferReader *reader = this->_write_vio.get_reader(); int64_t bytes_avail = reader->read_avail(); int64_t total_len = 0; - uint32_t max_size = this->_qc->maximum_stream_frame_data_size(); + uint32_t max_size = this->_tx->maximum_stream_frame_data_size(); while (total_len < bytes_avail) { int64_t data_len = reader->block_read_avail(); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index aef9dcaf447..aeb5d65bd8e 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -31,7 +31,7 @@ #include "QUICFrame.h" #include "QUICStreamState.h" -class QUICConnection; +class QUICFrameTransmitter; class QUICStreamState; class QUICStreamManager; @@ -45,7 +45,7 @@ class QUICStream : public VConnection QUICStream() : VConnection(nullptr) {} ~QUICStream() {} - void init(QUICStreamManager *manager, QUICConnection *qc, uint32_t id); + void init(QUICStreamManager *manager, QUICFrameTransmitter *tx, uint32_t id); void start(); int main_event_handler(int event, void *data); @@ -96,5 +96,5 @@ class QUICStream : public VConnection std::map> _request_stream_frame_buffer; QUICStreamManager *_streamManager = nullptr; - QUICConnection *_qc = nullptr; + QUICFrameTransmitter *_tx = nullptr; }; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index fe6be6e31d3..19ef3e2c749 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -31,18 +31,13 @@ ClassAllocator quicStreamManagerAllocator("quicStreamManagerA ClassAllocator quicStreamAllocator("quicStreamAllocator"); int -QUICStreamManager::init(QUICFrameTransmitter *tx) +QUICStreamManager::init(QUICFrameTransmitter *tx, QUICApplicationMap *app_map) { this->_tx = tx; + this->_app_map = app_map; return 0; } -void -QUICStreamManager::set_connection(QUICConnection *qc) -{ - this->_qc = qc; -} - void QUICStreamManager::handle_frame(std::shared_ptr frame) { @@ -61,7 +56,7 @@ void QUICStreamManager::_handle_stream_frame(std::shared_ptr frame) { QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); - QUICApplication *application = this->_qc->get_application(frame->stream_id()); + QUICApplication *application = this->_app_map->get(frame->stream_id()); if (!application->is_stream_set(stream)) { application->set_stream(stream); @@ -104,7 +99,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) if (!stream) { // TODO Free the stream somewhere stream = THREAD_ALLOC_INIT(quicStreamAllocator, this_ethread()); - stream->init(this, this->_qc, stream_id); + stream->init(this, this->_tx, stream_id); stream->start(); this->stream_list.push(stream); diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 7ea2700dd58..08daaccba62 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -25,7 +25,7 @@ #include "QUICTypes.h" #include "QUICStream.h" -#include "QUICConnection.h" +#include "QUICApplicationMap.h" #include "QUICFrameHandler.h" #include "QUICFrame.h" #include "QUICFrameTransmitter.h" @@ -35,8 +35,7 @@ class QUICStreamManager : public QUICFrameHandler public: QUICStreamManager(){}; - int init(QUICFrameTransmitter *tx); - void set_connection(QUICConnection *qc); // FIXME Want to remove. + int init(QUICFrameTransmitter *tx, QUICApplicationMap *app_map); virtual void handle_frame(std::shared_ptr) override; void send_frame(std::unique_ptr frame); @@ -46,8 +45,8 @@ class QUICStreamManager : public QUICFrameHandler QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICStream *_find_stream(QUICStreamId id); - QUICConnection *_qc = nullptr; - QUICFrameTransmitter *_tx = nullptr; + QUICApplicationMap *_app_map = nullptr; + QUICFrameTransmitter *_tx = nullptr; private: void _handle_stream_frame(std::shared_ptr); diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index fc06666d99a..3d43c164607 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -147,6 +147,7 @@ test_QUICFrameDispatcher_SOURCES = \ ../QUICFrameDispatcher.cc \ ../QUICTransportParameters.cc \ ../QUICStreamManager.cc \ + ../QUICApplicationMap.cc \ ../QUICFlowController.cc \ ../QUICCongestionController.cc \ ../QUICLossDetector.cc \ From cd36a9eb52c220cd9d38947408d8d9c43fd43d87 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 22 Aug 2017 15:48:45 +0900 Subject: [PATCH 0043/1313] Add QUICApplicatioMap --- iocore/net/quic/QUICApplicationMap.cc | 47 +++++++++++++++++++++++++++ iocore/net/quic/QUICApplicationMap.h | 40 +++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 iocore/net/quic/QUICApplicationMap.cc create mode 100644 iocore/net/quic/QUICApplicationMap.h diff --git a/iocore/net/quic/QUICApplicationMap.cc b/iocore/net/quic/QUICApplicationMap.cc new file mode 100644 index 00000000000..ff95226930c --- /dev/null +++ b/iocore/net/quic/QUICApplicationMap.cc @@ -0,0 +1,47 @@ +/** @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 + +QUICApplication * +QUICApplicationMap::get(QUICStreamId id) +{ + auto it = this->_map.find(id); + if (it == this->_map.end()) { + return this->_default_app; + } else { + return it->second; + } +} + +void +QUICApplicationMap::set(QUICStreamId id, QUICApplication *app) +{ + this->_map[id] = app; +} + +void +QUICApplicationMap::set_default(QUICApplication *app) +{ + this->_default_app = app; +} diff --git a/iocore/net/quic/QUICApplicationMap.h b/iocore/net/quic/QUICApplicationMap.h new file mode 100644 index 00000000000..a657adf6e41 --- /dev/null +++ b/iocore/net/quic/QUICApplicationMap.h @@ -0,0 +1,40 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICTypes.h" +#include "QUICApplication.h" +#include + +class QUICApplicationMap +{ +public: + void set(QUICStreamId id, QUICApplication *app); + void set_default(QUICApplication *app); + QUICApplication *get(QUICStreamId id); + +private: + std::map _map; + QUICApplication *_default_app = nullptr; +}; From 6115406298e96219ab1a20e671094c52f5dea760 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 Aug 2017 08:34:07 +0900 Subject: [PATCH 0044/1313] Fix build error of test_QUICStream --- iocore/net/quic/test/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 3d43c164607..c09f670066b 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -215,6 +215,7 @@ test_QUICStream_SOURCES = \ ../QUICFrameDispatcher.cc \ ../QUICStreamManager.cc \ ../QUICFlowController.cc \ + ../QUICApplicationMap.cc \ ../QUICCongestionController.cc test_QUICStream_LDADD = \ From f98e16d6606509782ddb11dcf25797404aaccebd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 Aug 2017 08:40:53 +0900 Subject: [PATCH 0045/1313] Fix QUICTransportParameter - Make data of QUICTransportParameterValue std::unique_ptr - Change _parameters table to std::map - Fix binary format of TransportParameter --- iocore/net/QUICNetVConnection.cc | 31 +++- iocore/net/quic/QUICTransportParameters.cc | 113 +++++++++------ iocore/net/quic/QUICTransportParameters.h | 22 +-- .../quic/test/test_QUICTransportParameters.cc | 132 ++++++++++++------ 4 files changed, 195 insertions(+), 103 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 926c1d2f11f..7ae5251e952 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -104,10 +104,33 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) // FIXME Fill appropriate values // MUSTs QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(); - tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, {reinterpret_cast("\x00\x00\x00\x00"), 4}); - tp->add(QUICTransportParameterId::INITIAL_MAX_DATA, {reinterpret_cast("\x00\x00\x00\x00"), 4}); - tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, {reinterpret_cast("\x00\x00\x00\x00"), 4}); - tp->add(QUICTransportParameterId::IDLE_TIMEOUT, {reinterpret_cast("\x00\x00"), 2}); + + size_t max_stream_data_buf_len = 4; + ats_unique_buf max_stream_data_buf = ats_unique_malloc(max_stream_data_buf_len); + memcpy(max_stream_data_buf.get(), "\x00\x00\x00\x00", max_stream_data_buf_len); + tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, + std::unique_ptr( + new QUICTransportParameterValue(std::move(max_stream_data_buf), max_stream_data_buf_len))); + + size_t max_data_buf_len = 4; + ats_unique_buf max_data_buf = ats_unique_malloc(max_data_buf_len); + memcpy(max_data_buf.get(), "\x00\x00\x00\x00", max_data_buf_len); + tp->add(QUICTransportParameterId::INITIAL_MAX_DATA, + std::unique_ptr(new QUICTransportParameterValue(std::move(max_data_buf), max_data_buf_len))); + + uint16_t max_stream_id_buf_len = 4; + ats_unique_buf max_stream_id_buf = ats_unique_malloc(max_stream_id_buf_len); + memcpy(max_stream_id_buf.get(), "\x00\x00\x00\x00", max_stream_id_buf_len); + tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, + std::unique_ptr( + new QUICTransportParameterValue(std::move(max_stream_id_buf), max_stream_id_buf_len))); + + uint16_t idle_timeout_buf_len = 2; + ats_unique_buf idle_timeout_buf = ats_unique_malloc(idle_timeout_buf_len); + memcpy(idle_timeout_buf.get(), "\x00\x00", idle_timeout_buf_len); + tp->add(QUICTransportParameterId::IDLE_TIMEOUT, std::unique_ptr(new QUICTransportParameterValue( + std::move(idle_timeout_buf), idle_timeout_buf_len))); + tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); // MAYs // this->_local_transport_parameters.add(QUICTransportParameterId::TRUNCATE_CONNECTION_ID, {}); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index fe0d0d8128c..c8638c4988c 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -35,35 +35,59 @@ QUICTransportParameters::QUICTransportParameters(const uint8_t *buf, size_t len) memcpy(this->_buf.get(), buf, len); } -QUICTransportParameterValue -QUICTransportParameters::get(QUICTransportParameterId tpid) const +const uint8_t * +QUICTransportParameters::get(QUICTransportParameterId tpid, uint16_t &len) const { - QUICTransportParameterValue value; - const uint8_t *p = this->_buf.get() + this->_parameters_offset(); + if (this->_buf) { + const uint8_t *p = this->_buf.get() + this->_parameters_offset(); - uint16_t n = (p[0] << 8) + p[1]; - p += 2; - for (; n > 0; --n) { - uint16_t _id = (p[0] << 8) + p[1]; - p += 2; - uint16_t _value_len = (p[0] << 8) + p[1]; + uint16_t n = (p[0] << 8) + p[1]; p += 2; - if (tpid == _id) { - value.data = p; - value.len = _value_len; - return value; + for (; n > 0; --n) { + uint16_t _id = (p[0] << 8) + p[1]; + p += 2; + uint16_t _value_len = (p[0] << 8) + p[1]; + p += 2; + if (tpid == _id) { + len = _value_len; + return p; + } + p += _value_len; + } + } else { + auto p = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); + if (p != this->_parameters.end()) { + len = p->second->len; + return p->second->data.get(); } - p += _value_len; } - value.data = nullptr; - value.len = 0; - return value; + + len = 0; + return nullptr; +} + +uint32_t +QUICTransportParameters::initial_max_stream_data() const +{ + uint16_t len = 0; + const uint8_t *data = this->get(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, len); + + return static_cast(QUICTypeUtil::read_nbytes_as_uint(data, len)); +} + +uint32_t +QUICTransportParameters::initial_max_data() const +{ + uint16_t len = 0; + const uint8_t *data = this->get(QUICTransportParameterId::INITIAL_MAX_DATA, len); + + return static_cast(QUICTypeUtil::read_nbytes_as_uint(data, len)); } void -QUICTransportParameters::add(QUICTransportParameterId id, QUICTransportParameterValue value) +QUICTransportParameters::add(QUICTransportParameterId id, std::unique_ptr value) { - _parameters.put(id, value); + this->_parameters.insert(std::pair>(id, std::move(value))); } void @@ -71,32 +95,32 @@ QUICTransportParameters::store(uint8_t *buf, uint16_t *len) const { uint8_t *p = buf; - // Why Map::get() doesn't have const?? - QUICTransportParameters *me = const_cast(this); - // Write QUIC versions this->_store(p, len); p += *len; // Write parameters - Vec keys; - me->_parameters.get_keys(keys); - unsigned int n = keys.length(); - p[0] = (n & 0xff00) >> 8; - p[1] = n & 0xff; - p += 2; - for (unsigned int i = 0; i < n; ++i) { - QUICTransportParameterValue value; - p[0] = (keys[i] & 0xff00) >> 8; - p[1] = keys[i] & 0xff; + // XXX parameters_size will be written later + uint8_t *parameters_size = p; + p += sizeof(uint16_t); + + for (auto &it : this->_parameters) { + p[0] = (it.first & 0xff00) >> 8; + p[1] = it.first & 0xff; p += 2; - value = me->_parameters.get(keys[i]); - p[0] = (value.len & 0xff00) >> 8; - p[1] = value.len & 0xff; + const QUICTransportParameterValue *value = it.second.get(); + p[0] = (value->len & 0xff00) >> 8; + p[1] = value->len & 0xff; p += 2; - memcpy(p, value.data, value.len); - p += value.len; + memcpy(p, value->data.get(), value->len); + p += value->len; } + + ptrdiff_t n = p - parameters_size - sizeof(uint16_t); + + parameters_size[0] = (n & 0xff00) >> 8; + parameters_size[1] = n & 0xff; + *len = (p - buf); } @@ -136,9 +160,8 @@ QUICTransportParametersInEncryptedExtensions::_store(uint8_t *buf, uint16_t *len uint8_t *p = buf; size_t l; - p[0] = (this->_n_versions & 0xff00) >> 8; - p[1] = this->_n_versions & 0xff; - p += 2; + p[0] = this->_n_versions * sizeof(uint32_t); + ++p; for (int i = 0; i < this->_n_versions; ++i) { QUICTypeUtil::write_QUICVersion(this->_versions[i], p, &l); p += l; @@ -147,11 +170,11 @@ QUICTransportParametersInEncryptedExtensions::_store(uint8_t *buf, uint16_t *len } const uint8_t * -QUICTransportParametersInEncryptedExtensions::supported_versions(uint16_t *n) const +QUICTransportParametersInEncryptedExtensions::supported_versions_len(uint16_t *n) const { uint8_t *b = this->_buf.get(); - *n = (b[0] << 8) + b[1]; - return b + 2; + *n = b[0]; + return b + 1; } void @@ -164,7 +187,7 @@ std::ptrdiff_t QUICTransportParametersInEncryptedExtensions::_parameters_offset() const { const uint8_t *b = this->_buf.get(); - return 2 + 4 * ((b[0] << 8) + b[1]); + return sizeof(uint8_t) + b[0]; } // diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 40373b41cdb..57814de08fb 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -23,9 +23,11 @@ #pragma once +#include +// #include "ts/Map.h" + #include #include "QUICTypes.h" -#include "ts/Map.h" #include class QUICTransportParameterId @@ -65,9 +67,10 @@ class QUICTransportParameterId typedef struct _QUICTransportParameterValue { _QUICTransportParameterValue(){}; - _QUICTransportParameterValue(const uint8_t *str) : data(str), len(str ? strlen(reinterpret_cast(str)) : 0){}; - _QUICTransportParameterValue(const uint8_t *_data, uint16_t _len) : data(_data), len(_len){}; - const uint8_t *data = nullptr; + _QUICTransportParameterValue(ats_unique_buf str) + : data(std::move(str)), len(str ? strlen(reinterpret_cast(str.get())) : 0){}; + _QUICTransportParameterValue(ats_unique_buf _data, uint16_t _len) : data(std::move(_data)), len(_len){}; + ats_unique_buf data = {nullptr, [](void *p) { ats_free(p); }}; uint16_t len = 0; } QUICTransportParameterValue; @@ -75,8 +78,10 @@ class QUICTransportParameters { public: QUICTransportParameters(const uint8_t *buf, size_t len); - QUICTransportParameterValue get(QUICTransportParameterId id) const; - void add(QUICTransportParameterId id, QUICTransportParameterValue value); + const uint8_t *get(QUICTransportParameterId id, uint16_t &len) const; + uint32_t initial_max_stream_data() const; + uint32_t initial_max_data() const; + void add(QUICTransportParameterId id, std::unique_ptr value); void store(uint8_t *buf, uint16_t *len) const; protected: @@ -84,7 +89,8 @@ class QUICTransportParameters virtual std::ptrdiff_t _parameters_offset() const = 0; virtual void _store(uint8_t *buf, uint16_t *len) const = 0; ats_unique_buf _buf = {nullptr, [](void *p) { ats_free(p); }}; - Map _parameters; + + std::map> _parameters; }; class QUICTransportParametersInClientHello : public QUICTransportParameters @@ -110,7 +116,7 @@ class QUICTransportParametersInEncryptedExtensions : public QUICTransportParamet public: QUICTransportParametersInEncryptedExtensions() : QUICTransportParameters(){}; QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len) : QUICTransportParameters(buf, len){}; - const uint8_t *supported_versions(uint16_t *n) const; + const uint8_t *supported_versions_len(uint16_t *n) const; void add_version(QUICVersion version); protected: diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index 864eee6d971..4977db2fd3b 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -30,7 +30,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, // negotiated version 0x05, 0x06, 0x07, 0x08, // iinitial version - 0x00, 0x04, // number of parameters + 0x00, 0x1e, // size of parameters 0x00, 0x00, // parameter id 0x00, 0x04, // length of value 0x11, 0x22, 0x33, 0x44, // value @@ -48,22 +48,29 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf)); CHECK(params_in_ch.negotiated_version() == 0x01020304); CHECK(params_in_ch.initial_version() == 0x05060708); - QUICTransportParameterValue value; - value = params_in_ch.get(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); - CHECK(value.len == 4); - CHECK(memcmp(value.data, "\x11\x22\x33\x44", 4) == 0); - value = params_in_ch.get(QUICTransportParameterId::INITIAL_MAX_DATA); - CHECK(value.len == 4); - CHECK(memcmp(value.data, "\x12\x34\x56\x78", 4) == 0); - value = params_in_ch.get(QUICTransportParameterId::INITIAL_MAX_STREAM_ID); - CHECK(value.len == 4); - CHECK(memcmp(value.data, "\x0a\x0b\x0c\x0d", 4) == 0); - value = params_in_ch.get(QUICTransportParameterId::IDLE_TIMEOUT); - CHECK(value.len == 2); - CHECK(memcmp(value.data, "\xab\xcd", 2) == 0); - value = params_in_ch.get(QUICTransportParameterId::MAX_PACKET_SIZE); - CHECK(value.len == 0); - CHECK(value.data == nullptr); + + uint16_t len = 0; + const uint8_t *data = nullptr; + + data = params_in_ch.get(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); + + data = params_in_ch.get(QUICTransportParameterId::INITIAL_MAX_DATA, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); + + data = params_in_ch.get(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x0a\x0b\x0c\x0d", 4) == 0); + + data = params_in_ch.get(QUICTransportParameterId::IDLE_TIMEOUT, len); + CHECK(len == 2); + CHECK(memcmp(data, "\xab\xcd", 2) == 0); + + data = params_in_ch.get(QUICTransportParameterId::MAX_PACKET_SIZE, len); + CHECK(len == 0); + CHECK(data == nullptr); } TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") @@ -74,7 +81,7 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") uint8_t expected[] = { 0x01, 0x02, 0x03, 0x04, // negotiated version 0x05, 0x06, 0x07, 0x08, // iinitial version - 0x00, 0x02, // number of parameters + 0x00, 0x0e, // size of parameters 0x00, 0x00, // parameter id 0x00, 0x04, // length of value 0x11, 0x22, 0x33, 0x44, // value @@ -84,8 +91,21 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") }; QUICTransportParametersInClientHello params_in_ch(0x01020304, 0x05060708); - params_in_ch.add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, {reinterpret_cast("\x11\x22\x33\x44"), 4}); - params_in_ch.add(QUICTransportParameterId::MAX_PACKET_SIZE, {reinterpret_cast("\xab\xcd"), 2}); + + size_t max_stream_data_buf_len = 4; + ats_unique_buf max_stream_data_buf = ats_unique_malloc(max_stream_data_buf_len); + memcpy(max_stream_data_buf.get(), "\x11\x22\x33\x44", max_stream_data_buf_len); + params_in_ch.add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, + std::unique_ptr( + new QUICTransportParameterValue(std::move(max_stream_data_buf), max_stream_data_buf_len))); + + uint16_t max_packet_size_buf_len = 2; + ats_unique_buf max_packet_size_buf = ats_unique_malloc(max_packet_size_buf_len); + memcpy(max_packet_size_buf.get(), "\xab\xcd", max_packet_size_buf_len); + params_in_ch.add(QUICTransportParameterId::MAX_PACKET_SIZE, + std::unique_ptr( + new QUICTransportParameterValue(std::move(max_packet_size_buf), max_packet_size_buf_len))); + params_in_ch.store(buf, &len); CHECK(len == 24); CHECK(memcmp(buf, expected, len) == 0); @@ -94,9 +114,9 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") { uint8_t buf[] = { - 0x00, 0x01, // number of supported versions + 0x04, // size of supported versions 0x01, 0x02, 0x03, 0x04, // - 0x00, 0x04, // number of parameters + 0x00, 0x1e, // size of parameters 0x00, 0x00, // parameter id 0x00, 0x04, // length of value 0x11, 0x22, 0x33, 0x44, // value @@ -113,26 +133,33 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf)); const uint8_t *versions; - uint16_t nversion; - versions = params_in_ee.supported_versions(&nversion); - CHECK(nversion == 1); + uint16_t vlen; + versions = params_in_ee.supported_versions_len(&vlen); + CHECK(vlen == 4); CHECK(memcmp(versions, "\x01\x02\x03\x04", 4) == 0); - QUICTransportParameterValue value; - value = params_in_ee.get(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); - CHECK(value.len == 4); - CHECK(memcmp(value.data, "\x11\x22\x33\x44", 4) == 0); - value = params_in_ee.get(QUICTransportParameterId::INITIAL_MAX_DATA); - CHECK(value.len == 4); - CHECK(memcmp(value.data, "\x12\x34\x56\x78", 4) == 0); - value = params_in_ee.get(QUICTransportParameterId::INITIAL_MAX_STREAM_ID); - CHECK(value.len == 4); - CHECK(memcmp(value.data, "\x0a\x0b\x0c\x0d", 4) == 0); - value = params_in_ee.get(QUICTransportParameterId::IDLE_TIMEOUT); - CHECK(value.len == 2); - CHECK(memcmp(value.data, "\xab\xcd", 2) == 0); - value = params_in_ee.get(QUICTransportParameterId::MAX_PACKET_SIZE); - CHECK(value.len == 0); - CHECK(value.data == nullptr); + + uint16_t len = 0; + const uint8_t *data = nullptr; + + data = params_in_ee.get(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); + + data = params_in_ee.get(QUICTransportParameterId::INITIAL_MAX_DATA, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); + + data = params_in_ee.get(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x0a\x0b\x0c\x0d", 4) == 0); + + data = params_in_ee.get(QUICTransportParameterId::IDLE_TIMEOUT, len); + CHECK(len == 2); + CHECK(memcmp(data, "\xab\xcd", 2) == 0); + + data = params_in_ee.get(QUICTransportParameterId::MAX_PACKET_SIZE, len); + CHECK(len == 0); + CHECK(data == nullptr); } TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") @@ -141,10 +168,10 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") uint16_t len; uint8_t expected[] = { - 0x00, 0x02, // number of supported versions + 0x08, // size of supported versions 0x01, 0x02, 0x03, 0x04, // version 1 0x05, 0x06, 0x07, 0x08, // version 2 - 0x00, 0x02, // number of parameters + 0x00, 0x0e, // size of parameters 0x00, 0x00, // parameter id 0x00, 0x04, // length of value 0x11, 0x22, 0x33, 0x44, // value @@ -154,11 +181,24 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") }; QUICTransportParametersInEncryptedExtensions params_in_ee; - params_in_ee.add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, {reinterpret_cast("\x11\x22\x33\x44"), 4}); - params_in_ee.add(QUICTransportParameterId::MAX_PACKET_SIZE, {reinterpret_cast("\xab\xcd"), 2}); + + size_t max_stream_data_buf_len = 4; + ats_unique_buf max_stream_data_buf = ats_unique_malloc(max_stream_data_buf_len); + memcpy(max_stream_data_buf.get(), "\x11\x22\x33\x44", max_stream_data_buf_len); + params_in_ee.add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, + std::unique_ptr( + new QUICTransportParameterValue(std::move(max_stream_data_buf), max_stream_data_buf_len))); + + uint16_t max_packet_size_buf_len = 2; + ats_unique_buf max_packet_size_buf = ats_unique_malloc(max_packet_size_buf_len); + memcpy(max_packet_size_buf.get(), "\xab\xcd", max_packet_size_buf_len); + params_in_ee.add(QUICTransportParameterId::MAX_PACKET_SIZE, + std::unique_ptr( + new QUICTransportParameterValue(std::move(max_packet_size_buf), max_packet_size_buf_len))); + params_in_ee.add_version(0x01020304); params_in_ee.add_version(0x05060708); params_in_ee.store(buf, &len); - CHECK(len == 26); + CHECK(len == 25); CHECK(memcmp(buf, expected, len) == 0); } From a4657c59fb7d2c1315ca09ecb2b3145c7168c5f2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 Aug 2017 09:11:26 +0900 Subject: [PATCH 0046/1313] Load TransportParameters from QUICConfig --- iocore/net/QUICNetVConnection.cc | 18 +++++++++++------- iocore/net/quic/QUICConfig.cc | 18 ++++++++++++++++++ iocore/net/quic/QUICConfig.h | 9 ++++++++- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 7ae5251e952..d779a390813 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -101,33 +101,37 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) this->_frame_dispatcher = new QUICFrameDispatcher(this, this->_stream_manager, flowController, congestionController, this->_loss_detector); - // FIXME Fill appropriate values + QUICConfig::scoped_config params; + // MUSTs QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(); size_t max_stream_data_buf_len = 4; ats_unique_buf max_stream_data_buf = ats_unique_malloc(max_stream_data_buf_len); - memcpy(max_stream_data_buf.get(), "\x00\x00\x00\x00", max_stream_data_buf_len); + QUICTypeUtil::write_uint_as_nbytes(params->initial_max_stream_data(), max_stream_data_buf_len, max_stream_data_buf.get(), + &max_stream_data_buf_len); tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, std::unique_ptr( new QUICTransportParameterValue(std::move(max_stream_data_buf), max_stream_data_buf_len))); size_t max_data_buf_len = 4; ats_unique_buf max_data_buf = ats_unique_malloc(max_data_buf_len); - memcpy(max_data_buf.get(), "\x00\x00\x00\x00", max_data_buf_len); + QUICTypeUtil::write_uint_as_nbytes(params->initial_max_data(), max_data_buf_len, max_data_buf.get(), &max_data_buf_len); tp->add(QUICTransportParameterId::INITIAL_MAX_DATA, std::unique_ptr(new QUICTransportParameterValue(std::move(max_data_buf), max_data_buf_len))); - uint16_t max_stream_id_buf_len = 4; + size_t max_stream_id_buf_len = 4; ats_unique_buf max_stream_id_buf = ats_unique_malloc(max_stream_id_buf_len); - memcpy(max_stream_id_buf.get(), "\x00\x00\x00\x00", max_stream_id_buf_len); + QUICTypeUtil::write_uint_as_nbytes(params->initial_max_stream_id(), max_stream_id_buf_len, max_stream_id_buf.get(), + &max_stream_id_buf_len); tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, std::unique_ptr( new QUICTransportParameterValue(std::move(max_stream_id_buf), max_stream_id_buf_len))); - uint16_t idle_timeout_buf_len = 2; + size_t idle_timeout_buf_len = 2; ats_unique_buf idle_timeout_buf = ats_unique_malloc(idle_timeout_buf_len); - memcpy(idle_timeout_buf.get(), "\x00\x00", idle_timeout_buf_len); + QUICTypeUtil::write_uint_as_nbytes(params->no_activity_timeout_in(), idle_timeout_buf_len, idle_timeout_buf.get(), + &idle_timeout_buf_len); tp->add(QUICTransportParameterId::IDLE_TIMEOUT, std::unique_ptr(new QUICTransportParameterValue( std::move(idle_timeout_buf), idle_timeout_buf_len))); diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 64b8e906628..d97ef54188e 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -42,6 +42,24 @@ QUICConfigParams::no_activity_timeout_in() const return this->_no_activity_timeout_in; } +uint32_t +QUICConfigParams::initial_max_data() const +{ + return this->_initial_max_data; +} + +uint32_t +QUICConfigParams::initial_max_stream_data() const +{ + return this->_initial_max_stream_data; +} + +uint32_t +QUICConfigParams::initial_max_stream_id() const +{ + return this->_initial_max_stream_id; +} + // // QUICConfig // diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index e4139bb8b65..b9ac7c20768 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -31,9 +31,16 @@ class QUICConfigParams : public ConfigInfo void initialize(); uint32_t no_activity_timeout_in() const; + uint32_t initial_max_data() const; + uint32_t initial_max_stream_data() const; + uint32_t initial_max_stream_id() const; private: - uint32_t _no_activity_timeout_in = 0; + // FIXME Fill appropriate values + uint32_t _no_activity_timeout_in = 0; + uint32_t _initial_max_data = 100; // in units of 1024 octets + uint32_t _initial_max_stream_data = 2048; + uint32_t _initial_max_stream_id = 100; }; class QUICConfig From 28dd6829690dd5ee39c6bffbe9c92afd8fa594cc Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 23 Aug 2017 09:57:34 +0900 Subject: [PATCH 0047/1313] Cleanup FrameDispatcher --- iocore/net/P_QUICNetVConnection.h | 15 +-- iocore/net/QUICNetVConnection.cc | 29 ++++-- iocore/net/quic/Mock.h | 6 ++ iocore/net/quic/QUICCongestionController.cc | 6 ++ iocore/net/quic/QUICCongestionController.h | 1 + iocore/net/quic/QUICFlowController.cc | 6 ++ iocore/net/quic/QUICFlowController.h | 3 +- iocore/net/quic/QUICFrameDispatcher.cc | 95 +++---------------- iocore/net/quic/QUICFrameDispatcher.h | 18 +--- iocore/net/quic/QUICFrameHandler.h | 3 + iocore/net/quic/QUICLossDetector.cc | 6 ++ iocore/net/quic/QUICLossDetector.h | 1 + iocore/net/quic/QUICStreamManager.cc | 8 +- iocore/net/quic/QUICStreamManager.h | 5 +- iocore/net/quic/test/Makefile.am | 6 -- .../net/quic/test/test_QUICFrameDispatcher.cc | 15 ++- 16 files changed, 98 insertions(+), 125 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 9c007417369..d42c63d1090 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -179,6 +179,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection virtual void transmit_frame(std::unique_ptr frame) override; // QUICConnection (QUICFrameHandler) + std::vector interests() override; void handle_frame(std::shared_ptr frame) override; private: @@ -197,12 +198,14 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // TODO: use custom allocator and make them std::unique_ptr or std::shared_ptr // or make them just member variables. - QUICVersionNegotiator *_version_negotiator = nullptr; - QUICHandshake *_handshake_handler = nullptr; - QUICCrypto *_crypto = nullptr; - std::shared_ptr _loss_detector = nullptr; - std::shared_ptr _stream_manager = nullptr; - QUICFrameDispatcher *_frame_dispatcher = nullptr; + QUICVersionNegotiator *_version_negotiator = nullptr; + QUICHandshake *_handshake_handler = nullptr; + QUICCrypto *_crypto = nullptr; + QUICLossDetector *_loss_detector = nullptr; + QUICFrameDispatcher *_frame_dispatcher = nullptr; + QUICStreamManager *_stream_manager = nullptr; + QUICFlowController *_flow_controller = nullptr; + QUICCongestionController *_congestion_controller = nullptr; Queue _packet_recv_queue; Queue _packet_send_queue; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index d779a390813..d8412326ba3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -89,17 +89,21 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) { this->_version_negotiator = new QUICVersionNegotiator(&this->_packet_factory, this); this->_crypto = new QUICCrypto(ssl_ctx, this); + this->_frame_dispatcher = new QUICFrameDispatcher(); this->_packet_factory.set_crypto_module(this->_crypto); - // FIXME Should these have to be shared_ptr? - this->_loss_detector = std::make_shared(this); - this->_stream_manager = std::make_shared(); + // Create frame handlers + this->_stream_manager = new QUICStreamManager(); this->_stream_manager->init(this, &this->_application_map); + this->_flow_controller = new QUICFlowController(); + this->_congestion_controller = new QUICCongestionController(); + this->_loss_detector = new QUICLossDetector(this); - std::shared_ptr flowController = std::make_shared(); - std::shared_ptr congestionController = std::make_shared(); - this->_frame_dispatcher = - new QUICFrameDispatcher(this, this->_stream_manager, flowController, congestionController, this->_loss_detector); + this->_frame_dispatcher->add_handler(this); + this->_frame_dispatcher->add_handler(this->_stream_manager); + this->_frame_dispatcher->add_handler(this->_flow_controller); + this->_frame_dispatcher->add_handler(this->_congestion_controller); + this->_frame_dispatcher->add_handler(this->_loss_detector); QUICConfig::scoped_config params; @@ -153,8 +157,11 @@ QUICNetVConnection::free(EThread *t) delete this->_version_negotiator; delete this->_handshake_handler; delete this->_crypto; + delete this->_loss_detector; delete this->_frame_dispatcher; - // XXX _loss_detector and _stream_manager are std::shared_ptr + delete this->_stream_manager; + delete this->_flow_controller; + delete this->_congestion_controller; // TODO: clear member variables like `UnixNetVConnection::free(EThread *t)` this->mutex.clear(); @@ -313,6 +320,12 @@ QUICNetVConnection::close(QUICError error) } } +std::vector +QUICNetVConnection::interests() +{ + return {QUICFrameType::CONNECTION_CLOSE}; +} + void QUICNetVConnection::handle_frame(std::shared_ptr frame) { diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index d208edb029b..7848e5b6c47 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -121,6 +121,12 @@ class MockQUICConnection : public QUICConnection { } + std::vector + interests() override + { + return {QUICFrameType::CONNECTION_CLOSE}; + } + void handle_frame(std::shared_ptr f) override { diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 2584c35d6c3..f10ef19f415 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -25,6 +25,12 @@ const static char *tag = "quic_congestion_controller"; +std::vector +QUICCongestionController::interests() +{ + return {QUICFrameType::ACK, QUICFrameType::STREAM}; +} + void QUICCongestionController::handle_frame(std::shared_ptr frame) { diff --git a/iocore/net/quic/QUICCongestionController.h b/iocore/net/quic/QUICCongestionController.h index a579a4866af..9faab4c4c8b 100644 --- a/iocore/net/quic/QUICCongestionController.h +++ b/iocore/net/quic/QUICCongestionController.h @@ -30,6 +30,7 @@ class QUICCongestionController : public QUICFrameHandler { public: + virtual std::vector interests() override; virtual void handle_frame(std::shared_ptr) override; private: diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 273715a62e6..a1608677249 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -25,6 +25,12 @@ const static char *tag = "quic_flow_controller"; +std::vector +QUICFlowController::interests() +{ + return {QUICFrameType::MAX_DATA, QUICFrameType::MAX_STREAM_DATA, QUICFrameType::BLOCKED, QUICFrameType::STREAM}; +} + void QUICFlowController::handle_frame(std::shared_ptr frame) { diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index 6009d2cf51c..5ede6cdb8df 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -27,9 +27,10 @@ // TODO Implement flow controll // Flow controll will be required for the 2nd implementation draft -class QUICFlowController : QUICFrameHandler +class QUICFlowController : public QUICFrameHandler { public: + virtual std::vector interests() override; virtual void handle_frame(std::shared_ptr) override; private: diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 724e04f1398..e5ba11e0a90 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -34,16 +34,13 @@ const static char *tag = "quic_frame_handler"; // // Frame Dispatcher // -QUICFrameDispatcher::QUICFrameDispatcher(QUICConnection *connection, const std::shared_ptr smgr, - const std::shared_ptr fctlr, - const std::shared_ptr cctlr, - const std::shared_ptr ld) + +void +QUICFrameDispatcher::add_handler(QUICFrameHandler *handler) { - this->_connection = connection; - streamManager = smgr; - flowController = fctlr; - congestionController = cctlr; - lossDetector = ld; + for (QUICFrameType t : handler->interests()) { + this->_handlers[static_cast(t)].push_back(handler); + } } bool @@ -61,84 +58,18 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size) } cursor += frame->size(); + QUICFrameType type = frame->type(); + // TODO: check debug build - if (frame->type() != QUICFrameType::PADDING) { + if (type != QUICFrameType::PADDING) { Debug(tag, "frame type %d, size %zu", static_cast(frame->type()), frame->size()); } - // FIXME We should probably use a mapping table. All the objects has the common interface (QUICFrameHandler). - switch (frame->type()) { - case QUICFrameType::PADDING: { - // NOTE: do nothing - break; - } - case QUICFrameType::RST_STREAM: { - streamManager->handle_frame(frame); - should_send_ack = true; - break; - } - case QUICFrameType::CONNECTION_CLOSE: { - this->_connection->handle_frame(frame); - should_send_ack = true; - break; - } - case QUICFrameType::GOAWAY: { - should_send_ack = true; - break; - } - case QUICFrameType::MAX_DATA: { - flowController->handle_frame(frame); - should_send_ack = true; - break; - } - case QUICFrameType::MAX_STREAM_DATA: { - flowController->handle_frame(frame); - should_send_ack = true; - break; - } - case QUICFrameType::MAX_STREAM_ID: { - should_send_ack = true; - break; - } - case QUICFrameType::PING: { - should_send_ack = true; - break; - } - case QUICFrameType::BLOCKED: { - flowController->handle_frame(frame); - should_send_ack = true; - break; - } - case QUICFrameType::STREAM_BLOCKED: { - should_send_ack = true; - break; - } - case QUICFrameType::STREAM_ID_NEEDED: { - should_send_ack = true; - break; - } - case QUICFrameType::NEW_CONNECTION_ID: { - should_send_ack = true; - break; - } - case QUICFrameType::ACK: { - congestionController->handle_frame(frame); - this->lossDetector->handle_frame(frame); - break; - } - case QUICFrameType::STREAM: { - streamManager->handle_frame(frame); - flowController->handle_frame(frame); - congestionController->handle_frame(frame); - should_send_ack = true; - break; - } - default: - // Unknown frame - Debug(tag, "Unknown frame type: %02x", static_cast(frame->type())); - ink_assert(false); + should_send_ack |= (type != QUICFrameType::PADDING && type != QUICFrameType::ACK); - break; + std::vector handlers = this->_handlers[static_cast(type)]; + for (auto h : handlers) { + h->handle_frame(frame); } } return should_send_ack; diff --git a/iocore/net/quic/QUICFrameDispatcher.h b/iocore/net/quic/QUICFrameDispatcher.h index 2fd7f34ab05..b1865426274 100644 --- a/iocore/net/quic/QUICFrameDispatcher.h +++ b/iocore/net/quic/QUICFrameDispatcher.h @@ -24,30 +24,20 @@ #pragma once #include "QUICFrame.h" - -class QUICConnection; -class QUICStreamManager; -class QUICFlowController; -class QUICCongestionController; -class QUICLossDetector; +#include "QUICFrameHandler.h" +#include class QUICFrameDispatcher { public: - QUICFrameDispatcher(QUICConnection *connection, const std::shared_ptr smgr, - const std::shared_ptr fctlr, const std::shared_ptr cctlr, - const std::shared_ptr ld); /* * Returns true if ACK frame should be sent */ bool receive_frames(const uint8_t *payload, uint16_t size); - std::shared_ptr streamManager = nullptr; - std::shared_ptr flowController = nullptr; - std::shared_ptr congestionController = nullptr; - std::shared_ptr lossDetector = nullptr; + void add_handler(QUICFrameHandler *handler); private: - QUICConnection *_connection = nullptr; QUICFrameFactory _frame_factory; + std::vector _handlers[256]; }; diff --git a/iocore/net/quic/QUICFrameHandler.h b/iocore/net/quic/QUICFrameHandler.h index d4554fe8bfe..64b09d93ef8 100644 --- a/iocore/net/quic/QUICFrameHandler.h +++ b/iocore/net/quic/QUICFrameHandler.h @@ -23,10 +23,13 @@ #pragma once +#include #include class QUICFrameHandler { public: + virtual ~QUICFrameHandler(){}; + virtual std::vector interests() = 0; virtual void handle_frame(std::shared_ptr frame) = 0; }; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 4c1031471d8..4c6bd341b3c 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -72,6 +72,12 @@ QUICLossDetector::event_handler(int event, Event *edata) return EVENT_CONT; } +std::vector +QUICLossDetector::interests() +{ + return {QUICFrameType::ACK}; +} + void QUICLossDetector::handle_frame(std::shared_ptr frame) { diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 7d6f325c155..0b93b4649e5 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -45,6 +45,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler int event_handler(int event, Event *edata); + std::vector interests() override; virtual void handle_frame(std::shared_ptr) override; void on_packet_sent(std::unique_ptr packet); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 19ef3e2c749..9b08fd2b5c2 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -33,11 +33,17 @@ ClassAllocator quicStreamAllocator("quicStreamAllocator"); int QUICStreamManager::init(QUICFrameTransmitter *tx, QUICApplicationMap *app_map) { - this->_tx = tx; + this->_tx = tx; this->_app_map = app_map; return 0; } +std::vector +QUICStreamManager::interests() +{ + return {QUICFrameType::STREAM, QUICFrameType::RST_STREAM}; +} + void QUICStreamManager::handle_frame(std::shared_ptr frame) { diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 08daaccba62..ae80bcd8299 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -36,6 +36,7 @@ class QUICStreamManager : public QUICFrameHandler QUICStreamManager(){}; int init(QUICFrameTransmitter *tx, QUICApplicationMap *app_map); + virtual std::vector interests() override; virtual void handle_frame(std::shared_ptr) override; void send_frame(std::unique_ptr frame); @@ -45,8 +46,8 @@ class QUICStreamManager : public QUICFrameHandler QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICStream *_find_stream(QUICStreamId id); - QUICApplicationMap *_app_map = nullptr; - QUICFrameTransmitter *_tx = nullptr; + QUICApplicationMap *_app_map = nullptr; + QUICFrameTransmitter *_tx = nullptr; private: void _handle_stream_frame(std::shared_ptr); diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index c09f670066b..d58b46e607a 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -166,9 +166,6 @@ test_QUICFrameDispatcher_SOURCES = \ test_QUICFrameDispatcher_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ @LIBTCL@ \ @HWLOC_LIBS@ @@ -192,9 +189,6 @@ test_QUICStreamState_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ @LIBTCL@ \ @HWLOC_LIBS@ diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index dfb673748bf..35c60585df0 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -33,11 +33,16 @@ TEST_CASE("QUICFrameHandler", "[quic]") QUICStreamFrame streamFrame(payload, 1, 0x03, 0); auto connection = new MockQUICConnection(); - auto streamManager = std::make_shared(); - auto flowController = std::make_shared(); - auto congestionController = std::make_shared(); - auto lossDetector = std::make_shared(); - QUICFrameDispatcher quicFrameDispatcher(connection, streamManager, flowController, congestionController, lossDetector); + auto streamManager = new MockQUICStreamManager(); + auto flowController = new MockQUICFlowController(); + auto congestionController = new MockQUICCongestionController(); + auto lossDetector = new MockQUICLossDetector(); + QUICFrameDispatcher quicFrameDispatcher; + quicFrameDispatcher.add_handler(connection); + quicFrameDispatcher.add_handler(streamManager); + quicFrameDispatcher.add_handler(flowController); + quicFrameDispatcher.add_handler(congestionController); + quicFrameDispatcher.add_handler(lossDetector); // Initial state CHECK(connection->getTotalFrameCount() == 0); From a86fca03b73533a4bcdfc2f58e9bd17413791a9f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 Aug 2017 10:37:54 +0900 Subject: [PATCH 0048/1313] Cleanup QUICTransportParameterValue --- iocore/net/QUICNetVConnection.cc | 29 +++-------- iocore/net/quic/QUICTransportParameters.cc | 49 ++++++++++++++++--- iocore/net/quic/QUICTransportParameters.h | 21 +++++--- .../quic/test/test_QUICTransportParameters.cc | 44 +++++++---------- 4 files changed, 81 insertions(+), 62 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index d8412326ba3..3fc88e0b264 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -110,34 +110,19 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) // MUSTs QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(); - size_t max_stream_data_buf_len = 4; - ats_unique_buf max_stream_data_buf = ats_unique_malloc(max_stream_data_buf_len); - QUICTypeUtil::write_uint_as_nbytes(params->initial_max_stream_data(), max_stream_data_buf_len, max_stream_data_buf.get(), - &max_stream_data_buf_len); tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, std::unique_ptr( - new QUICTransportParameterValue(std::move(max_stream_data_buf), max_stream_data_buf_len))); - - size_t max_data_buf_len = 4; - ats_unique_buf max_data_buf = ats_unique_malloc(max_data_buf_len); - QUICTypeUtil::write_uint_as_nbytes(params->initial_max_data(), max_data_buf_len, max_data_buf.get(), &max_data_buf_len); - tp->add(QUICTransportParameterId::INITIAL_MAX_DATA, - std::unique_ptr(new QUICTransportParameterValue(std::move(max_data_buf), max_data_buf_len))); - - size_t max_stream_id_buf_len = 4; - ats_unique_buf max_stream_id_buf = ats_unique_malloc(max_stream_id_buf_len); - QUICTypeUtil::write_uint_as_nbytes(params->initial_max_stream_id(), max_stream_id_buf_len, max_stream_id_buf.get(), - &max_stream_id_buf_len); + new QUICTransportParameterValue(params->initial_max_stream_data(), sizeof(params->initial_max_stream_data())))); + + tp->add(QUICTransportParameterId::INITIAL_MAX_DATA, std::unique_ptr(new QUICTransportParameterValue( + params->initial_max_data(), sizeof(params->initial_max_data())))); + tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, std::unique_ptr( - new QUICTransportParameterValue(std::move(max_stream_id_buf), max_stream_id_buf_len))); + new QUICTransportParameterValue(params->initial_max_stream_id(), sizeof(params->initial_max_stream_id())))); - size_t idle_timeout_buf_len = 2; - ats_unique_buf idle_timeout_buf = ats_unique_malloc(idle_timeout_buf_len); - QUICTypeUtil::write_uint_as_nbytes(params->no_activity_timeout_in(), idle_timeout_buf_len, idle_timeout_buf.get(), - &idle_timeout_buf_len); tp->add(QUICTransportParameterId::IDLE_TIMEOUT, std::unique_ptr(new QUICTransportParameterValue( - std::move(idle_timeout_buf), idle_timeout_buf_len))); + params->no_activity_timeout_in(), sizeof(uint16_t)))); tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); // MAYs diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index c8638c4988c..7365084255e 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -29,6 +29,35 @@ const static int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; +// +// QUICTransportParameterValue +// +QUICTransportParameterValue::QUICTransportParameterValue(ats_unique_buf d, uint16_t l) : _data(std::move(d)), _len(l){}; + +QUICTransportParameterValue::QUICTransportParameterValue(uint64_t raw_data, uint16_t l) +{ + this->_data = ats_unique_malloc(l); + size_t len = 0; + QUICTypeUtil::write_uint_as_nbytes(raw_data, l, this->_data.get(), &len); + this->_len = len; +}; + +const uint8_t * +QUICTransportParameterValue::data() const +{ + return this->_data.get(); +} + +uint16_t +QUICTransportParameterValue::len() const +{ + return this->_len; +} + +// +// QUICTransportParameters +// + QUICTransportParameters::QUICTransportParameters(const uint8_t *buf, size_t len) { this->_buf = ats_unique_malloc(len); @@ -57,8 +86,8 @@ QUICTransportParameters::get(QUICTransportParameterId tpid, uint16_t &len) const } else { auto p = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); if (p != this->_parameters.end()) { - len = p->second->len; - return p->second->data.get(); + len = p->second->len(); + return p->second->data(); } } @@ -109,11 +138,11 @@ QUICTransportParameters::store(uint8_t *buf, uint16_t *len) const p[1] = it.first & 0xff; p += 2; const QUICTransportParameterValue *value = it.second.get(); - p[0] = (value->len & 0xff00) >> 8; - p[1] = value->len & 0xff; + p[0] = (value->len() & 0xff00) >> 8; + p[1] = value->len() & 0xff; p += 2; - memcpy(p, value->data.get(), value->len); - p += value->len; + memcpy(p, value->data(), value->len()); + p += value->len(); } ptrdiff_t n = p - parameters_size - sizeof(uint16_t); @@ -124,6 +153,10 @@ QUICTransportParameters::store(uint8_t *buf, uint16_t *len) const *len = (p - buf); } +// +// QUICTransportParametersInClientHello +// + void QUICTransportParametersInClientHello::_store(uint8_t *buf, uint16_t *len) const { @@ -154,6 +187,10 @@ QUICTransportParametersInClientHello::initial_version() const return QUICTypeUtil::read_QUICVersion(this->_buf.get() + sizeof(QUICVersion)); } +// +// QUICTransportParametersInEncryptedExtensions +// + void QUICTransportParametersInEncryptedExtensions::_store(uint8_t *buf, uint16_t *len) const { diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 57814de08fb..a32261f8000 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -65,14 +65,19 @@ class QUICTransportParameterId uint16_t _id = 0; }; -typedef struct _QUICTransportParameterValue { - _QUICTransportParameterValue(){}; - _QUICTransportParameterValue(ats_unique_buf str) - : data(std::move(str)), len(str ? strlen(reinterpret_cast(str.get())) : 0){}; - _QUICTransportParameterValue(ats_unique_buf _data, uint16_t _len) : data(std::move(_data)), len(_len){}; - ats_unique_buf data = {nullptr, [](void *p) { ats_free(p); }}; - uint16_t len = 0; -} QUICTransportParameterValue; +class QUICTransportParameterValue +{ +public: + QUICTransportParameterValue(ats_unique_buf d, uint16_t l); + QUICTransportParameterValue(uint64_t raw_data, uint16_t l); + + const uint8_t *data() const; + uint16_t len() const; + +private: + ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; + uint16_t _len = 0; +}; class QUICTransportParameters { diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index 4977db2fd3b..adf3daf57e6 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -92,19 +92,15 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") QUICTransportParametersInClientHello params_in_ch(0x01020304, 0x05060708); - size_t max_stream_data_buf_len = 4; - ats_unique_buf max_stream_data_buf = ats_unique_malloc(max_stream_data_buf_len); - memcpy(max_stream_data_buf.get(), "\x11\x22\x33\x44", max_stream_data_buf_len); - params_in_ch.add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, - std::unique_ptr( - new QUICTransportParameterValue(std::move(max_stream_data_buf), max_stream_data_buf_len))); - - uint16_t max_packet_size_buf_len = 2; - ats_unique_buf max_packet_size_buf = ats_unique_malloc(max_packet_size_buf_len); - memcpy(max_packet_size_buf.get(), "\xab\xcd", max_packet_size_buf_len); - params_in_ch.add(QUICTransportParameterId::MAX_PACKET_SIZE, - std::unique_ptr( - new QUICTransportParameterValue(std::move(max_packet_size_buf), max_packet_size_buf_len))); + uint32_t max_stream_data = 0x11223344; + params_in_ch.add( + QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, + std::unique_ptr(new QUICTransportParameterValue(max_stream_data, sizeof(max_stream_data)))); + + uint16_t max_packet_size = 0xabcd; + params_in_ch.add( + QUICTransportParameterId::MAX_PACKET_SIZE, + std::unique_ptr(new QUICTransportParameterValue(max_packet_size, sizeof(max_packet_size)))); params_in_ch.store(buf, &len); CHECK(len == 24); @@ -182,19 +178,15 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") QUICTransportParametersInEncryptedExtensions params_in_ee; - size_t max_stream_data_buf_len = 4; - ats_unique_buf max_stream_data_buf = ats_unique_malloc(max_stream_data_buf_len); - memcpy(max_stream_data_buf.get(), "\x11\x22\x33\x44", max_stream_data_buf_len); - params_in_ee.add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, - std::unique_ptr( - new QUICTransportParameterValue(std::move(max_stream_data_buf), max_stream_data_buf_len))); - - uint16_t max_packet_size_buf_len = 2; - ats_unique_buf max_packet_size_buf = ats_unique_malloc(max_packet_size_buf_len); - memcpy(max_packet_size_buf.get(), "\xab\xcd", max_packet_size_buf_len); - params_in_ee.add(QUICTransportParameterId::MAX_PACKET_SIZE, - std::unique_ptr( - new QUICTransportParameterValue(std::move(max_packet_size_buf), max_packet_size_buf_len))); + uint32_t max_stream_data = 0x11223344; + params_in_ee.add( + QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, + std::unique_ptr(new QUICTransportParameterValue(max_stream_data, sizeof(max_stream_data)))); + + uint16_t max_packet_size = 0xabcd; + params_in_ee.add( + QUICTransportParameterId::MAX_PACKET_SIZE, + std::unique_ptr(new QUICTransportParameterValue(max_packet_size, sizeof(max_packet_size)))); params_in_ee.add_version(0x01020304); params_in_ee.add_version(0x05060708); From 1d28d8c41ca04d8e97e8c49d5710dd1ee240ddba Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 Aug 2017 12:10:56 +0900 Subject: [PATCH 0049/1313] Rename _request/_response_buffer_offset to _recv/_send_offset --- iocore/net/quic/QUICStream.cc | 20 ++++++++++++-------- iocore/net/quic/QUICStream.h | 7 ++++--- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index edd19ea2554..8a10c57a5e2 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -229,16 +229,16 @@ QUICStream::_write_to_read_vio(std::shared_ptr frame) int bytes_added = this->_read_vio.buffer.writer()->write(frame->data(), frame->data_length()); this->_read_vio.nbytes += bytes_added; - this->_request_buffer_offset += frame->data_length(); + this->_recv_offset += frame->data_length(); } void QUICStream::_reorder_data() { - auto frame = _request_stream_frame_buffer.find(this->_request_buffer_offset); + auto frame = _request_stream_frame_buffer.find(this->_recv_offset); while (frame != this->_request_stream_frame_buffer.end()) { this->_write_to_read_vio(frame->second); - frame = _request_stream_frame_buffer.find(this->_request_buffer_offset); + frame = _request_stream_frame_buffer.find(this->_recv_offset); } } @@ -260,10 +260,14 @@ QUICStream::recv(std::shared_ptr frame) } this->_state.update_with_received_frame(*frame); - if (this->_request_buffer_offset > frame->offset()) { + if (frame->offset() > this->_recv_largest_offset) { + this->_recv_largest_offset = frame->offset(); + } + + if (this->_recv_offset > frame->offset()) { // Do nothing. Just ignore STREAM frame. return; - } else if (this->_request_buffer_offset == frame->offset()) { + } else if (this->_recv_offset == frame->offset()) { this->_write_to_read_vio(frame); this->_reorder_data(); } else { @@ -298,10 +302,10 @@ QUICStream::_send() len = data_len; } - std::unique_ptr frame = QUICFrameFactory::create_stream_frame( - reinterpret_cast(reader->start()), len, this->_id, this->_response_buffer_offset); + std::unique_ptr frame = + QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, this->_id, this->_send_offset); - this->_response_buffer_offset += len; + this->_send_offset += len; reader->consume(len); this->_write_vio.ndone += len; total_len += len; diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index aeb5d65bd8e..1992d215bd6 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -81,9 +81,10 @@ class QUICStream : public VConnection Event *_send_tracked_event(Event *event, int send_event, VIO *vio); - QUICStreamId _id = 0; - QUICOffset _request_buffer_offset = 0; - QUICOffset _response_buffer_offset = 0; + QUICStreamId _id = 0; + QUICOffset _recv_offset = 0; + QUICOffset _recv_largest_offset = 0; + QUICOffset _send_offset = 0; VIO _read_vio; VIO _write_vio; From 08f2639c08f722660317b95f0c6d9116cb01f5ac Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 Aug 2017 11:47:56 +0900 Subject: [PATCH 0050/1313] Add Flow Control support --- iocore/net/P_QUICNetVConnection.h | 5 +- iocore/net/QUICNetVConnection.cc | 9 +- iocore/net/quic/Mock.h | 10 ++ iocore/net/quic/QUICConnection.h | 1 + iocore/net/quic/QUICStream.cc | 128 ++++++++++++++++-- iocore/net/quic/QUICStream.h | 17 ++- iocore/net/quic/QUICStreamManager.cc | 164 ++++++++++++++++++++++-- iocore/net/quic/QUICStreamManager.h | 30 ++++- iocore/net/quic/QUICTypes.h | 71 +++++++++- iocore/net/quic/test/test_QUICStream.cc | 8 +- 10 files changed, 408 insertions(+), 35 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index d42c63d1090..b4e07deb665 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -168,6 +168,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection uint32_t pmtu() override; void set_transport_parameters(std::unique_ptr tp) override; const QUICTransportParameters &local_transport_parameters() override; + const QUICTransportParameters &remote_transport_parameters() override; void close(QUICError error) override; // QUICConnection (QUICPacketTransmitter) @@ -193,8 +194,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection uint32_t _pmtu = 1280; - std::unique_ptr _local_transport_parameters; - std::unique_ptr _remote_transport_parameters; + std::unique_ptr _local_transport_parameters = nullptr; + std::unique_ptr _remote_transport_parameters = nullptr; // TODO: use custom allocator and make them std::unique_ptr or std::shared_ptr // or make them just member variables. diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3fc88e0b264..7e92e602a55 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -94,7 +94,7 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) // Create frame handlers this->_stream_manager = new QUICStreamManager(); - this->_stream_manager->init(this, &this->_application_map); + this->_stream_manager->init(this, this, &this->_application_map); this->_flow_controller = new QUICFlowController(); this->_congestion_controller = new QUICCongestionController(); this->_loss_detector = new QUICLossDetector(this); @@ -174,6 +174,7 @@ void QUICNetVConnection::set_transport_parameters(std::unique_ptr tp) { this->_remote_transport_parameters = std::move(tp); + this->_stream_manager->init_flow_control_params(*this->_local_transport_parameters, *this->_remote_transport_parameters); const QUICTransportParametersInClientHello *tp_in_ch = dynamic_cast(this->_remote_transport_parameters.get()); @@ -212,6 +213,12 @@ QUICNetVConnection::local_transport_parameters() return *this->_local_transport_parameters; } +const QUICTransportParameters & +QUICNetVConnection::remote_transport_parameters() +{ + return *this->_remote_transport_parameters; +} + uint32_t QUICNetVConnection::minimum_quic_packet_size() { diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 7848e5b6c47..195b285634f 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -169,6 +169,12 @@ class MockQUICConnection : public QUICConnection return dummy_transport_parameters; } + const QUICTransportParameters & + remote_transport_parameters() override + { + return dummy_transport_parameters; + } + void close(QUICError error) override { @@ -285,6 +291,10 @@ class MockQUICStreamManager : public QUICStreamManager return _totalFrameCount; } + bool is_recv_avail_more_than(uint64_t /* size */) override { return true; } + + void send_frame(std::unique_ptr /* frame */) override { return; } + private: int _totalFrameCount = 0; int _frameCount[256] = {0}; diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index a90b73fa45a..9aad6875716 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -38,5 +38,6 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter virtual uint32_t pmtu() = 0; virtual void set_transport_parameters(std::unique_ptr tp) = 0; virtual const QUICTransportParameters &local_transport_parameters() = 0; + virtual const QUICTransportParameters &remote_transport_parameters() = 0; virtual void close(QUICError error) = 0; }; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 8a10c57a5e2..362337720c0 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -26,15 +26,21 @@ #include "I_Event.h" #include "QUICStreamManager.h" #include "QUICDebugNames.h" +#include "QUICConfig.h" const static char *tag = "quic_stream"; +constexpr uint64_t MAX_DATA_HEADSPACE = 10240; // in uints of octets +constexpr uint64_t MAX_STREAM_DATA_HEADSPACE = 1024; + void -QUICStream::init(QUICStreamManager *manager, QUICFrameTransmitter *tx, QUICStreamId id) +QUICStream::init(QUICStreamManager *manager, QUICFrameTransmitter *tx, QUICStreamId id, uint64_t recv_max_stream_data, + uint64_t send_max_stream_data) { this->_streamManager = manager; this->_tx = tx; this->_id = id; + init_flow_control_params(recv_max_stream_data, send_max_stream_data); this->mutex = new_ProxyMutex(); } @@ -45,6 +51,14 @@ QUICStream::start() SET_HANDLER(&QUICStream::main_event_handler); } +void +QUICStream::init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data) +{ + this->_recv_max_stream_data = recv_max_stream_data; + this->_recv_max_stream_data_deleta = recv_max_stream_data; + this->_send_max_stream_data = send_max_stream_data; +} + uint32_t QUICStream::id() { @@ -248,7 +262,7 @@ QUICStream::_reorder_data() * If the reordering or writting operation is heavy, split out them to read function, * which is called by application via do_io_read() or reenable(). */ -void +QUICError QUICStream::recv(std::shared_ptr frame) { ink_assert(_id == frame->stream_id()); @@ -256,17 +270,20 @@ QUICStream::recv(std::shared_ptr frame) if (!this->_state.is_allowed_to_receive(*frame)) { this->reset(); - return; + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); } this->_state.update_with_received_frame(*frame); - if (frame->offset() > this->_recv_largest_offset) { - this->_recv_largest_offset = frame->offset(); + // Flow Control + QUICError error = this->_recv_flow_control(frame->offset()); + if (error.cls != QUICErrorClass::NONE) { + return error; } + // Reordering if (this->_recv_offset > frame->offset()) { // Do nothing. Just ignore STREAM frame. - return; + return QUICError(QUICErrorClass::NONE); } else if (this->_recv_offset == frame->offset()) { this->_write_to_read_vio(frame); this->_reorder_data(); @@ -276,7 +293,71 @@ QUICStream::recv(std::shared_ptr frame) this->_request_stream_frame_buffer.insert(std::make_pair(frame->offset(), frame)); } - return; + return QUICError(QUICErrorClass::NONE); +} + +QUICError +QUICStream::recv(std::shared_ptr frame) +{ + this->_send_max_stream_data += frame->maximum_stream_data(); + return QUICError(QUICErrorClass::NONE); +} + +QUICError +QUICStream::recv(std::shared_ptr frame) +{ + this->_slide_recv_max_stream_data(); + return QUICError(QUICErrorClass::NONE); +} + +void +QUICStream::_slide_recv_max_stream_data() +{ + // TODO: How much should this be increased? + this->_recv_max_stream_data += this->_recv_max_stream_data_deleta; + this->_streamManager->send_frame(QUICFrameFactory::create_max_stream_data_frame(this->_id, this->_recv_max_stream_data)); +} + +QUICError +QUICStream::_recv_flow_control(uint64_t new_offset) +{ + if (this->_recv_largest_offset > new_offset) { + return QUICError(QUICErrorClass::NONE); + } + + uint64_t delta = new_offset - this->_recv_largest_offset; + + Debug("quic_flow_ctrl", "Con: %" PRIu64 "/%" PRIu64 " Stream: %" PRIu64 "/%" PRIu64, + (this->_streamManager->recv_total_offset() + delta) / 1024, this->_streamManager->recv_max_data(), new_offset, + this->_recv_max_stream_data); + + // Connection Level Flow Control + if (this->_id != STREAM_ID_FOR_HANDSHAKE) { + if (!this->_streamManager->is_recv_avail_more_than(delta)) { + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); + } + + if (!this->_streamManager->is_recv_avail_more_than(delta + MAX_DATA_HEADSPACE)) { + this->_streamManager->slide_recv_max_data(); + } + + this->_streamManager->add_recv_total_offset(delta); + } + + // Stream Level Flow Control + if (this->_recv_max_stream_data > 0) { + if (this->_recv_max_stream_data < new_offset) { + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); + } + + if (this->_recv_max_stream_data < new_offset + MAX_STREAM_DATA_HEADSPACE) { + this->_slide_recv_max_stream_data(); + } + } + + this->_recv_largest_offset = new_offset; + + return QUICError(QUICErrorClass::NONE); } /** @@ -302,6 +383,10 @@ QUICStream::_send() len = data_len; } + if (!this->_send_flow_control(len)) { + break; + } + std::unique_ptr frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, this->_id, this->_send_offset); @@ -315,12 +400,39 @@ QUICStream::_send() break; } this->_state.update_with_sent_frame(*frame); - this->_streamManager->send_frame(std::move(frame)); + this->_streamManager->send_stream_frame(std::move(frame)); } return; } +bool +QUICStream::_send_flow_control(uint64_t len) +{ + Debug("quic_flow_ctrl", "Con: %" PRIu64 "/%" PRIu64 " Stream: %" PRIu64 "/%" PRIu64, + (this->_streamManager->send_total_offset() + len) / 1024, this->_streamManager->send_max_data(), this->_send_offset + len, + this->_send_max_stream_data); + + // Stream Level Flow Control + // TODO: remove check of _send_max_stream_data when moved to Second Implementation completely + if (this->_send_max_stream_data > 0 && len > this->_send_max_stream_data) { + this->_streamManager->send_frame(QUICFrameFactory::create_stream_blocked_frame(this->_id)); + + return false; + } + + // Connection Level Flow Control + if (this->_id != STREAM_ID_FOR_HANDSHAKE) { + if (!this->_streamManager->is_send_avail_more_than(len)) { + this->_streamManager->send_frame(QUICFrameFactory::create_blocked_frame()); + + return false; + } + } + + return true; +} + void QUICStream::reset() { diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 1992d215bd6..6d35e6de7af 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -45,8 +45,10 @@ class QUICStream : public VConnection QUICStream() : VConnection(nullptr) {} ~QUICStream() {} - void init(QUICStreamManager *manager, QUICFrameTransmitter *tx, uint32_t id); + void init(QUICStreamManager *manager, QUICFrameTransmitter *tx, uint32_t id, uint64_t recv_max_stream_data = 0, + uint64_t send_max_stream_data = 0); void start(); + void init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data); int main_event_handler(int event, void *data); uint32_t id(); @@ -58,7 +60,10 @@ class QUICStream : public VConnection void do_io_shutdown(ShutdownHowTo_t howto) override; void reenable(VIO *vio) override; - void recv(std::shared_ptr frame); + QUICError recv(std::shared_ptr frame); + QUICError recv(std::shared_ptr frame); + QUICError recv(std::shared_ptr frame); + void reset(); bool is_read_ready(); @@ -81,11 +86,19 @@ class QUICStream : public VConnection Event *_send_tracked_event(Event *event, int send_event, VIO *vio); + void _slide_recv_max_stream_data(); + QUICError _recv_flow_control(uint64_t new_offset); + bool _send_flow_control(uint64_t len); + QUICStreamId _id = 0; QUICOffset _recv_offset = 0; QUICOffset _recv_largest_offset = 0; QUICOffset _send_offset = 0; + uint64_t _recv_max_stream_data = 0; + uint64_t _recv_max_stream_data_deleta = 0; + uint64_t _send_max_stream_data = 0; + VIO _read_vio; VIO _write_vio; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 9b08fd2b5c2..fab8deab3ee 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -21,9 +21,11 @@ * limitations under the License. */ -#include +#include "QUICStreamManager.h" -#include +#include "QUICApplication.h" +#include "QUICTransportParameters.h" +#include "QUICConnection.h" const static char *tag = "quic_stream_manager"; @@ -31,34 +33,112 @@ ClassAllocator quicStreamManagerAllocator("quicStreamManagerA ClassAllocator quicStreamAllocator("quicStreamAllocator"); int -QUICStreamManager::init(QUICFrameTransmitter *tx, QUICApplicationMap *app_map) +QUICStreamManager::init(QUICFrameTransmitter *tx, QUICConnection *qc, QUICApplicationMap *app_map) { this->_tx = tx; + this->_qc = qc; this->_app_map = app_map; + return 0; } std::vector QUICStreamManager::interests() { - return {QUICFrameType::STREAM, QUICFrameType::RST_STREAM}; + return {QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::MAX_DATA, QUICFrameType::MAX_STREAM_DATA, + QUICFrameType::BLOCKED}; +} + +void +QUICStreamManager::init_flow_control_params(const QUICTransportParameters &local_tp, const QUICTransportParameters &remote_tp) +{ + // Connection level + this->_recv_max_data = QUICMaximumData(local_tp.initial_max_data()); + this->_send_max_data = QUICMaximumData(remote_tp.initial_max_data()); + + // Setup a stream for Handshake + QUICStream *stream = this->_find_stream(STREAM_ID_FOR_HANDSHAKE); + stream->init_flow_control_params(local_tp.initial_max_stream_data(), remote_tp.initial_max_stream_data()); } void QUICStreamManager::handle_frame(std::shared_ptr frame) { + QUICError error = QUICError(QUICErrorClass::NONE); + switch (frame->type()) { + case QUICFrameType::MAX_DATA: { + error = this->_handle_max_data_frame(std::dynamic_pointer_cast(frame)); + break; + } + case QUICFrameType::BLOCKED: { + this->slide_recv_max_data(); + break; + } + case QUICFrameType::MAX_STREAM_DATA: { + error = this->_handle_max_stream_data_frame(std::dynamic_pointer_cast(frame)); + break; + } + case QUICFrameType::STREAM_BLOCKED: { + error = this->_handle_stream_blocked_frame(std::dynamic_pointer_cast(frame)); + break; + } case QUICFrameType::STREAM: - this->_handle_stream_frame(std::dynamic_pointer_cast(frame)); + error = this->_handle_stream_frame(std::dynamic_pointer_cast(frame)); break; default: Debug(tag, "Unexpected frame type: %02x", static_cast(frame->type())); ink_assert(false); break; } + + if (error.cls != QUICErrorClass::NONE) { + // TODO return error + } +} + +QUICError +QUICStreamManager::_handle_max_data_frame(std::shared_ptr frame) +{ + this->_send_max_data = frame->maximum_data(); + return QUICError(QUICErrorClass::NONE); } void +QUICStreamManager::slide_recv_max_data() +{ + // TODO: How much should this be increased? + this->_recv_max_data += this->_qc->local_transport_parameters().initial_max_data(); + this->send_frame(QUICFrameFactory::create_max_data_frame(this->_recv_max_data)); +} + +QUICError +QUICStreamManager::_handle_max_stream_data_frame(std::shared_ptr frame) +{ + QUICStream *stream = this->_find_stream(frame->stream_id()); + if (stream) { + stream->recv(frame); + } else { + // TODO: connection error? + } + + return QUICError(QUICErrorClass::NONE); +} + +QUICError +QUICStreamManager::_handle_stream_blocked_frame(std::shared_ptr frame) +{ + QUICStream *stream = this->_find_stream(frame->stream_id()); + if (stream) { + stream->recv(frame); + } else { + // TODO: connection error? + } + + return QUICError(QUICErrorClass::NONE); +} + +QUICError QUICStreamManager::_handle_stream_frame(std::shared_ptr frame) { QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); @@ -68,18 +148,34 @@ QUICStreamManager::_handle_stream_frame(std::shared_ptr f application->set_stream(stream); } - stream->recv(frame); + QUICError error = stream->recv(frame); + // FIXME: schedule VC_EVENT_READ_READY to application every single frame? // If application reading buffer continuously, do not schedule event. this_ethread()->schedule_imm(application, VC_EVENT_READ_READY, stream); - return; + return error; } /** * @brief Send stream frame */ void +QUICStreamManager::send_stream_frame(std::unique_ptr frame) +{ + // XXX The offset of sending frame is always largest offset by sending side + if (frame->stream_id() != STREAM_ID_FOR_HANDSHAKE) { + this->_send_total_offset += frame->size(); + } + this->_tx->transmit_frame(std::move(frame)); + + return; +} + +/** + * @brief Send frame + */ +void QUICStreamManager::send_frame(std::unique_ptr frame) { this->_tx->transmit_frame(std::move(frame)); @@ -87,6 +183,24 @@ QUICStreamManager::send_frame(std::unique_ptr f return; } +bool +QUICStreamManager::is_send_avail_more_than(uint64_t size) +{ + return this->_send_max_data > (this->_send_total_offset + size); +} + +bool +QUICStreamManager::is_recv_avail_more_than(uint64_t size) +{ + return this->_recv_max_data > (this->_recv_total_offset + size); +} + +void +QUICStreamManager::add_recv_total_offset(uint64_t delta) +{ + this->_recv_total_offset += delta; +} + QUICStream * QUICStreamManager::_find_stream(QUICStreamId id) { @@ -105,10 +219,44 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) if (!stream) { // TODO Free the stream somewhere stream = THREAD_ALLOC_INIT(quicStreamAllocator, this_ethread()); - stream->init(this, this->_tx, stream_id); + if (stream_id == STREAM_ID_FOR_HANDSHAKE) { + // XXX rece/send max_stream_data are going to be set by init_flow_control_params() + stream->init(this, this->_tx, stream_id); + } else { + const QUICTransportParameters &local_tp = this->_qc->local_transport_parameters(); + const QUICTransportParameters &remote_tp = this->_qc->remote_transport_parameters(); + + // TODO: check local_tp and remote_tp is initialized + stream->init(this, this->_tx, stream_id, local_tp.initial_max_stream_data(), remote_tp.initial_max_stream_data()); + } + stream->start(); this->stream_list.push(stream); } return stream; } + +uint64_t +QUICStreamManager::recv_max_data() const +{ + return this->_recv_max_data; +} + +uint64_t +QUICStreamManager::send_max_data() const +{ + return this->_send_max_data; +} + +uint64_t +QUICStreamManager::recv_total_offset() const +{ + return this->_recv_total_offset; +} + +uint64_t +QUICStreamManager::send_total_offset() const +{ + return this->_send_total_offset; +} diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index ae80bcd8299..6df6db38f13 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -30,25 +30,47 @@ #include "QUICFrame.h" #include "QUICFrameTransmitter.h" +class QUICTransportParameters; + class QUICStreamManager : public QUICFrameHandler { public: QUICStreamManager(){}; - int init(QUICFrameTransmitter *tx, QUICApplicationMap *app_map); + int init(QUICFrameTransmitter *tx, QUICConnection *qc, QUICApplicationMap *app_map); virtual std::vector interests() override; virtual void handle_frame(std::shared_ptr) override; - void send_frame(std::unique_ptr frame); + virtual void send_frame(std::unique_ptr frame); + void send_stream_frame(std::unique_ptr frame); + virtual bool is_send_avail_more_than(uint64_t size); + virtual bool is_recv_avail_more_than(uint64_t size); + void add_recv_total_offset(uint64_t delta); + void slide_recv_max_data(); + void init_flow_control_params(const QUICTransportParameters &local_tp, const QUICTransportParameters &remote_tp); + uint64_t recv_max_data() const; + uint64_t send_max_data() const; + uint64_t recv_total_offset() const; + uint64_t send_total_offset() const; DLL stream_list; private: QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICStream *_find_stream(QUICStreamId id); + QUICError _handle_max_data_frame(std::shared_ptr); + QUICError _handle_stream_frame(std::shared_ptr); + QUICError _handle_max_stream_data_frame(std::shared_ptr); + QUICError _handle_stream_blocked_frame(std::shared_ptr); QUICApplicationMap *_app_map = nullptr; QUICFrameTransmitter *_tx = nullptr; + QUICConnection *_qc = nullptr; -private: - void _handle_stream_frame(std::shared_ptr); + QUICMaximumData _recv_max_data = {0}; + QUICMaximumData _send_max_data = {0}; + + // TODO: Maximum Data is in units of 1024 octets, but those total offset are in units of octets. + // Add new uint16_t fields for remainder and treat those total offset in units of 1024 octets if needed + uint64_t _recv_total_offset = 0; + uint64_t _send_total_offset = 0; }; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index c595abfb580..83a05004dcc 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -122,14 +122,16 @@ enum class QUICErrorClass { CRYPTOGRAPHIC, }; +// TODO: fix for draft-05 enum class QUICErrorCode : uint32_t { - APPLICATION_SPECIFIC_ERROR = 0, - HOST_LOCAL_ERROR = 0x40000000, - QUIC_TRANSPORT_ERROR = 0x80000000, - QUIC_INTERNAL_ERROR = 0x80000001, - QUIC_VERSION_NEGOTIATION_MISMATCH = 0x80000037, - CRYPTOGRAPHIC_ERROR = 0xC0000000, - TLS_HANDSHAKE_FAILED = 0xC000001C, + APPLICATION_SPECIFIC_ERROR = 0, + HOST_LOCAL_ERROR = 0x40000000, + QUIC_TRANSPORT_ERROR = 0x80000000, + QUIC_INTERNAL_ERROR = 0x80000001, + QUIC_VERSION_NEGOTIATION_MISMATCH = 0x80000037, + QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA = 0x8000003b, + CRYPTOGRAPHIC_ERROR = 0xC0000000, + TLS_HANDSHAKE_FAILED = 0xC000001C, // TODO Add error codes }; @@ -168,6 +170,61 @@ class QUICConnectionId uint64_t _id; }; +class QUICMaximumData +{ +public: + QUICMaximumData(uint64_t d) : _data(d) {} + + bool + operator>(uint64_t r) const + { + return this->_data > (r / 1024); + } + + bool + operator<(uint64_t r) const + { + return this->_data < (r / 1024); + } + + bool + operator>=(uint64_t r) const + { + return this->_data >= (r / 1024); + } + + bool + operator<=(uint64_t r) const + { + return this->_data <= (r / 1024); + } + + bool + operator==(uint64_t r) const + { + return this->_data == (r / 1024); + } + + QUICMaximumData & + operator=(uint64_t d) + { + this->_data = d; + return *this; + } + + QUICMaximumData & + operator+=(uint64_t d) + { + this->_data += d; + return *this; + } + + operator uint64_t() const { return _data; } + +private: + uint64_t _data = 0; // in units of 1024 octets +}; + class QUICTypeUtil { public: diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index d60867a5156..e296621f4fa 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -41,13 +41,15 @@ std::shared_ptr frame_6 = std::make_shared(pay std::shared_ptr frame_7 = std::make_shared(payload + 12, 2, stream_id, 12); std::shared_ptr frame_8 = std::make_shared(payload + 14, 2, stream_id, 14); +MockQUICStreamManager *manager = new MockQUICStreamManager(); + TEST_CASE("QUICStream_assembling_byte_stream_1", "[quic]") { MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); std::unique_ptr stream(new QUICStream()); - stream->init(nullptr, nullptr, stream_id); + stream->init(manager, nullptr, stream_id, 1024, 1024); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_1); @@ -73,7 +75,7 @@ TEST_CASE("QUICStream_assembling_byte_stream_2", "[quic]") IOBufferReader *reader = read_buffer->alloc_reader(); std::unique_ptr stream(new QUICStream()); - stream->init(nullptr, nullptr, stream_id); + stream->init(manager, nullptr, stream_id); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -99,7 +101,7 @@ TEST_CASE("QUICStream_assembling_byte_stream_3", "[quic]") IOBufferReader *reader = read_buffer->alloc_reader(); std::unique_ptr stream(new QUICStream()); - stream->init(nullptr, nullptr, stream_id); + stream->init(manager, nullptr, stream_id); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); From 970d63786d0711ecf283f7d719a9b5f725c42caf Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 Aug 2017 14:58:04 +0900 Subject: [PATCH 0051/1313] Delete QUICFlowController class --- iocore/net/P_QUICNetVConnection.h | 2 - iocore/net/QUICNetVConnection.cc | 3 -- iocore/net/quic/Makefile.am | 1 - iocore/net/quic/Mock.h | 44 ----------------- iocore/net/quic/QUICFlowController.cc | 48 ------------------- iocore/net/quic/QUICFlowController.h | 37 -------------- iocore/net/quic/QUICFrameDispatcher.cc | 1 - iocore/net/quic/test/Makefile.am | 2 - .../net/quic/test/test_QUICFrameDispatcher.cc | 5 -- 9 files changed, 143 deletions(-) delete mode 100644 iocore/net/quic/QUICFlowController.cc delete mode 100644 iocore/net/quic/QUICFlowController.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index b4e07deb665..8e5586c4951 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -54,7 +54,6 @@ #include "quic/QUICAckFrameCreator.h" #include "quic/QUICLossDetector.h" #include "quic/QUICStreamManager.h" -#include "quic/QUICFlowController.h" #include "quic/QUICCongestionController.h" #include "quic/QUICApplicationMap.h" @@ -205,7 +204,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICLossDetector *_loss_detector = nullptr; QUICFrameDispatcher *_frame_dispatcher = nullptr; QUICStreamManager *_stream_manager = nullptr; - QUICFlowController *_flow_controller = nullptr; QUICCongestionController *_congestion_controller = nullptr; Queue _packet_recv_queue; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 7e92e602a55..e34f13cd006 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -95,13 +95,11 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) // Create frame handlers this->_stream_manager = new QUICStreamManager(); this->_stream_manager->init(this, this, &this->_application_map); - this->_flow_controller = new QUICFlowController(); this->_congestion_controller = new QUICCongestionController(); this->_loss_detector = new QUICLossDetector(this); this->_frame_dispatcher->add_handler(this); this->_frame_dispatcher->add_handler(this->_stream_manager); - this->_frame_dispatcher->add_handler(this->_flow_controller); this->_frame_dispatcher->add_handler(this->_congestion_controller); this->_frame_dispatcher->add_handler(this->_loss_detector); @@ -145,7 +143,6 @@ QUICNetVConnection::free(EThread *t) delete this->_loss_detector; delete this->_frame_dispatcher; delete this->_stream_manager; - delete this->_flow_controller; delete this->_congestion_controller; // TODO: clear member variables like `UnixNetVConnection::free(EThread *t)` diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 9d0ae8d4701..fda10cd8b1e 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -48,7 +48,6 @@ libquic_a_SOURCES = \ QUICVersionNegotiator.cc \ QUICLossDetector.cc \ QUICStreamManager.cc \ - QUICFlowController.cc \ QUICCongestionController.cc \ QUICStreamState.cc \ QUICStream.cc \ diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 195b285634f..b69795426ab 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -22,7 +22,6 @@ */ #include "QUICStreamManager.h" -#include "QUICFlowController.h" #include "QUICCongestionController.h" #include "QUICLossDetector.h" #include "QUICEvents.h" @@ -343,49 +342,6 @@ class MockQUICCongestionController : public QUICCongestionController int _frameCount[256] = {0}; }; -class MockQUICFlowController : public QUICFlowController -{ -public: - MockQUICFlowController() {} - - // Override - virtual void - handle_frame(std::shared_ptr f) override - { - ++_frameCount[static_cast(f->type())]; - ++_totalFrameCount; - } - - // for Test - int - getStreamFrameCount() - { - return _frameCount[static_cast(QUICFrameType::STREAM)]; - } - - int - getAckFrameCount() - { - return _frameCount[static_cast(QUICFrameType::ACK)]; - } - - int - getPingFrameCount() - { - return _frameCount[static_cast(QUICFrameType::PING)]; - } - - int - getTotalFrameCount() - { - return _totalFrameCount; - } - -private: - int _totalFrameCount = 0; - int _frameCount[256] = {0}; -}; - void NetVConnection::cancel_OOB(){}; Action * NetVConnection::send_OOB(Continuation *, char *, int) diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc deleted file mode 100644 index a1608677249..00000000000 --- a/iocore/net/quic/QUICFlowController.cc +++ /dev/null @@ -1,48 +0,0 @@ -/** @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 - -const static char *tag = "quic_flow_controller"; - -std::vector -QUICFlowController::interests() -{ - return {QUICFrameType::MAX_DATA, QUICFrameType::MAX_STREAM_DATA, QUICFrameType::BLOCKED, QUICFrameType::STREAM}; -} - -void -QUICFlowController::handle_frame(std::shared_ptr frame) -{ - switch (frame->type()) { - case QUICFrameType::MAX_DATA: - case QUICFrameType::MAX_STREAM_DATA: - case QUICFrameType::BLOCKED: - case QUICFrameType::STREAM: - break; - default: - Debug(tag, "Unexpected frame type: %02x", static_cast(frame->type())); - ink_assert(false); - break; - } -} diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h deleted file mode 100644 index 5ede6cdb8df..00000000000 --- a/iocore/net/quic/QUICFlowController.h +++ /dev/null @@ -1,37 +0,0 @@ -/** @file - * - * A brief file description - * - * @section license License - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -// TODO Implement flow controll -// Flow controll will be required for the 2nd implementation draft -class QUICFlowController : public QUICFrameHandler -{ -public: - virtual std::vector interests() override; - virtual void handle_frame(std::shared_ptr) override; - -private: -}; diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index e5ba11e0a90..0799f22e170 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -24,7 +24,6 @@ #include "QUICFrameDispatcher.h" #include "QUICConnection.h" #include "QUICStreamManager.h" -#include "QUICFlowController.h" #include "QUICCongestionController.h" #include "QUICLossDetector.h" #include "QUICEvents.h" diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index d58b46e607a..b51245a9e14 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -148,7 +148,6 @@ test_QUICFrameDispatcher_SOURCES = \ ../QUICTransportParameters.cc \ ../QUICStreamManager.cc \ ../QUICApplicationMap.cc \ - ../QUICFlowController.cc \ ../QUICCongestionController.cc \ ../QUICLossDetector.cc \ ../QUICFrame.cc \ @@ -208,7 +207,6 @@ test_QUICStream_SOURCES = \ ../QUICStream.cc \ ../QUICFrameDispatcher.cc \ ../QUICStreamManager.cc \ - ../QUICFlowController.cc \ ../QUICApplicationMap.cc \ ../QUICCongestionController.cc diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 35c60585df0..5b158192d07 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -34,20 +34,17 @@ TEST_CASE("QUICFrameHandler", "[quic]") auto connection = new MockQUICConnection(); auto streamManager = new MockQUICStreamManager(); - auto flowController = new MockQUICFlowController(); auto congestionController = new MockQUICCongestionController(); auto lossDetector = new MockQUICLossDetector(); QUICFrameDispatcher quicFrameDispatcher; quicFrameDispatcher.add_handler(connection); quicFrameDispatcher.add_handler(streamManager); - quicFrameDispatcher.add_handler(flowController); quicFrameDispatcher.add_handler(congestionController); quicFrameDispatcher.add_handler(lossDetector); // Initial state CHECK(connection->getTotalFrameCount() == 0); CHECK(streamManager->getTotalFrameCount() == 0); - CHECK(flowController->getTotalFrameCount() == 0); CHECK(congestionController->getTotalFrameCount() == 0); // STREAM frame @@ -57,7 +54,6 @@ TEST_CASE("QUICFrameHandler", "[quic]") quicFrameDispatcher.receive_frames(buf, len); CHECK(connection->getTotalFrameCount() == 0); CHECK(streamManager->getTotalFrameCount() == 1); - CHECK(flowController->getTotalFrameCount() == 1); CHECK(congestionController->getTotalFrameCount() == 1); // CONNECTION_CLOSE frame @@ -66,6 +62,5 @@ TEST_CASE("QUICFrameHandler", "[quic]") quicFrameDispatcher.receive_frames(buf, len); CHECK(connection->getTotalFrameCount() == 1); CHECK(streamManager->getTotalFrameCount() == 1); - CHECK(flowController->getTotalFrameCount() == 1); CHECK(congestionController->getTotalFrameCount() == 1); } From 5a5d53f384fe5ed5526676678e2bd44d9b4e0610 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 23 Aug 2017 16:00:40 +0900 Subject: [PATCH 0052/1313] Add support for ALPN on QUIC Since there's only one application layer protocol now, NextProtocolAccept is not introduced yet. --- iocore/net/P_QUICNetVConnection.h | 7 ++++++ iocore/net/P_QUICPacketHandler.h | 1 + iocore/net/QUICNetProcessor.cc | 1 + iocore/net/QUICNetVConnection.cc | 37 ++++++++++++++++++++++++++----- iocore/net/quic/QUICCrypto.cc | 6 +++++ iocore/net/quic/QUICCrypto.h | 3 +++ iocore/net/quic/QUICGlobals.cc | 21 ++++++++++++++++++ iocore/net/quic/QUICGlobals.h | 4 ++++ iocore/net/quic/QUICHandshake.cc | 7 +++--- iocore/net/quic/QUICHandshake.h | 2 +- lib/records/I_RecHttp.h | 1 + lib/records/RecHttp.cc | 19 +++++++++++++++- lib/ts/apidefs.h.in | 3 +++ lib/ts/ink_inet.cc | 1 + lib/ts/ink_inet.h | 1 + proxy/http/HttpProxyServerMain.cc | 7 ++++-- 16 files changed, 108 insertions(+), 13 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 8e5586c4951..a2e6cf35b49 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -104,6 +104,8 @@ typedef std::unique_ptr ats_uint8_t_unique_ptr; struct QUICPacketHandler; class QUICLossDetector; +class SSLNextProtocolSet; + /** * @class QUICNetVConnection * @brief A NetVConnection for a QUIC network socket @@ -160,6 +162,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection virtual void net_read_io(NetHandler *nh, EThread *lthread) override; virtual int64_t load_buffer_and_write(int64_t towrite, MIOBufferAccessor &buf, int64_t &total_written, int &needs) override; + SSLNextProtocolSet *next_protocol_set(); + void registerNextProtocolSet(SSLNextProtocolSet *s); + // QUICConnection uint32_t maximum_quic_packet_size() override; uint32_t minimum_quic_packet_size() override; @@ -193,6 +198,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection uint32_t _pmtu = 1280; + SSLNextProtocolSet *_next_protocol_set = nullptr; + std::unique_ptr _local_transport_parameters = nullptr; std::unique_ptr _remote_transport_parameters = nullptr; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 64463e4ef51..ce77b4ad216 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -28,6 +28,7 @@ #include "P_NetAccept.h" class QUICNetVConnection; +class QUICPacket; struct QUICPacketHandler : public NetAccept { public: diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index f635210bb64..291dfab9284 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -68,6 +68,7 @@ QUICNetProcessor::start(int, size_t stacksize) this->_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(this->_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(this->_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_alpn_select_cb(this->_ssl_ctx, QUIC::ssl_select_next_protocol, nullptr); SSL_CTX_add_custom_ext(this->_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, diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e34f13cd006..1d44f42ff44 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -33,6 +33,8 @@ #include "BIO_fastopen.h" #include "Log.h" +#include "P_SSLNextProtocolSet.h" + #include "QUICEchoApp.h" #include "QUICDebugNames.h" #include "QUICEvents.h" @@ -63,6 +65,11 @@ QUICNetVConnection::init(UDPConnection *udp_con, QUICPacketHandler *packet_handl this->_transmitter_mutex = new_ProxyMutex(); this->_packet_handler = packet_handler; this->_quic_connection_id.randomize(); + + // FIXME These should be done by HttpProxyServerMain + SSLNextProtocolSet *next_protocol_set = new SSLNextProtocolSet(); + next_protocol_set->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC, nullptr); + this->registerNextProtocolSet(next_protocol_set); } VIO * @@ -509,6 +516,18 @@ QUICNetVConnection::load_buffer_and_write(int64_t towrite, MIOBufferAccessor &bu return 0; } +void +QUICNetVConnection::registerNextProtocolSet(SSLNextProtocolSet *s) +{ + this->_next_protocol_set = s; +} + +SSLNextProtocolSet * +QUICNetVConnection::next_protocol_set() +{ + return this->_next_protocol_set; +} + QUICError QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_ptr packet) { @@ -719,12 +738,20 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi QUICApplication * QUICNetVConnection::_create_application() { - const uint8_t *application = this->_handshake_handler->negotiated_application_name(); - if (memcmp(application, "hq", 2) == 0) { - return new QUICEchoApp(this); + const uint8_t *app_name; + unsigned int app_name_len = 0; + this->_handshake_handler->negotiated_application_name(&app_name, &app_name_len); + if (app_name) { + DebugQUICCon("ALPN: %.*s", app_name_len, app_name); + if (memcmp(TS_ALPN_PROTOCOL_HTTP_QUIC, app_name, app_name_len) == 0) { + return new QUICEchoApp(this); + } else { + DebugQUICCon("Negotiated application is not available"); + ink_assert(false); + return nullptr; + } } else { - DebugQUICCon("Unknown application has been negotiated: %s", application); - ink_assert(false); + DebugQUICCon("Failed to negotiate application"); return nullptr; } } diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 8eb13854632..53b2799f2ae 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -242,6 +242,12 @@ QUICCrypto::update_server_keymaterial() // return 1; } +SSL * +QUICCrypto::ssl_handle() +{ + return this->_ssl; +} + bool QUICCrypto::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICCrypto.h index f4c7fc9762a..5617e61688a 100644 --- a/iocore/net/quic/QUICCrypto.h +++ b/iocore/net/quic/QUICCrypto.h @@ -78,6 +78,9 @@ class QUICCrypto int update_client_keymaterial(); int update_server_keymaterial(); + // FIXME SSL handle should not be exported + SSL *ssl_handle(); + private: int _export_secret(uint8_t *dst, size_t dst_len, const char *label, size_t label_len) const; int _export_client_keymaterial(size_t secret_len, size_t key_len, size_t iv_len); diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index ca6e1518e19..b8dd77dac7e 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -21,6 +21,27 @@ * limitations under the License. */ +#include #include "QUICGlobals.h" +#include "P_QUICNetVConnection.h" +#include "P_SSLNextProtocolSet.h" int QUIC::ssl_quic_vc_index = -1; + +int +QUIC::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen, + void *) +{ + const unsigned char *npn; + unsigned npnsz = 0; + QUICNetVConnection *qnvc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_vc_index)); + + qnvc->next_protocol_set()->advertiseProtocols(&npn, &npnsz); + if (SSL_select_next_proto((unsigned char **)out, outlen, npn, npnsz, in, inlen) == OPENSSL_NPN_NEGOTIATED) { + return SSL_TLSEXT_ERR_OK; + } + + *out = nullptr; + *outlen = 0; + return SSL_TLSEXT_ERR_NOACK; +} diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h index 2dcdef34d19..e1d2b4a873d 100644 --- a/iocore/net/quic/QUICGlobals.h +++ b/iocore/net/quic/QUICGlobals.h @@ -34,4 +34,8 @@ class QUIC ssl_quic_vc_index = SSL_get_ex_new_index(0, (void *)"NetVC index", nullptr, nullptr, nullptr); } static int ssl_quic_vc_index; + + // SSL callbacks + static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, + unsigned inlen, void *); }; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index a81daa3ff47..84261381b69 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -60,11 +60,10 @@ QUICHandshake::is_completed() return crypto->is_handshake_finished(); } -const uint8_t * -QUICHandshake::negotiated_application_name() +void +QUICHandshake::negotiated_application_name(const uint8_t **name, unsigned int *len) { - // TODO Use the protocol name negotiated on ALPN - return reinterpret_cast("hq"); + SSL_get0_alpn_selected(this->_crypto->ssl_handle(), name, len); } int diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 64074a0a246..3a501f0afc7 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -54,7 +54,7 @@ class QUICHandshake : public QUICApplication int state_complete(int event, void *data); int state_closed(int event, void *data); bool is_completed(); - const uint8_t *negotiated_application_name(); + void negotiated_application_name(const uint8_t **name, unsigned int *len); private: QUICCrypto *_crypto = nullptr; diff --git a/lib/records/I_RecHttp.h b/lib/records/I_RecHttp.h index 066486ad119..99e38ead09c 100644 --- a/lib/records/I_RecHttp.h +++ b/lib/records/I_RecHttp.h @@ -135,6 +135,7 @@ extern SessionProtocolSet HTTP_PROTOCOL_SET; extern SessionProtocolSet HTTP2_PROTOCOL_SET; extern SessionProtocolSet DEFAULT_NON_TLS_SESSION_PROTOCOL_SET; extern SessionProtocolSet DEFAULT_TLS_SESSION_PROTOCOL_SET; +extern SessionProtocolSet DEFAULT_QUIC_SESSION_PROTOCOL_SET; const char *RecNormalizeProtoTag(const char *tag); diff --git a/lib/records/RecHttp.cc b/lib/records/RecHttp.cc index d3024998937..b2b3f3a4264 100644 --- a/lib/records/RecHttp.cc +++ b/lib/records/RecHttp.cc @@ -40,6 +40,7 @@ const char *const TS_ALPN_PROTOCOL_HTTP_0_9 = IP_PROTO_TAG_HTTP_0_9.ptr(); const char *const TS_ALPN_PROTOCOL_HTTP_1_0 = IP_PROTO_TAG_HTTP_1_0.ptr(); const char *const TS_ALPN_PROTOCOL_HTTP_1_1 = IP_PROTO_TAG_HTTP_1_1.ptr(); const char *const TS_ALPN_PROTOCOL_HTTP_2_0 = IP_PROTO_TAG_HTTP_2_0.ptr(); +const char *const TS_ALPN_PROTOCOL_HTTP_QUIC = IP_PROTO_TAG_HTTP_QUIC.ptr(); const char *const TS_ALPN_PROTOCOL_GROUP_HTTP = "http"; const char *const TS_ALPN_PROTOCOL_GROUP_HTTP2 = "http2"; @@ -47,6 +48,7 @@ const char *const TS_ALPN_PROTOCOL_GROUP_HTTP2 = "http2"; const char *const TS_PROTO_TAG_HTTP_1_0 = TS_ALPN_PROTOCOL_HTTP_1_0; const char *const TS_PROTO_TAG_HTTP_1_1 = TS_ALPN_PROTOCOL_HTTP_1_1; const char *const TS_PROTO_TAG_HTTP_2_0 = TS_ALPN_PROTOCOL_HTTP_2_0; +const char *const TS_PROTO_TAG_HTTP_QUIC = TS_ALPN_PROTOCOL_HTTP_QUIC; const char *const TS_PROTO_TAG_TLS_1_3 = IP_PROTO_TAG_TLS_1_3.ptr(); const char *const TS_PROTO_TAG_TLS_1_2 = IP_PROTO_TAG_TLS_1_2.ptr(); const char *const TS_PROTO_TAG_TLS_1_1 = IP_PROTO_TAG_TLS_1_1.ptr(); @@ -63,12 +65,14 @@ int TS_ALPN_PROTOCOL_INDEX_HTTP_0_9 = SessionProtocolNameRegistry::INVALID; int TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = SessionProtocolNameRegistry::INVALID; int TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = SessionProtocolNameRegistry::INVALID; int TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = SessionProtocolNameRegistry::INVALID; +int TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC = SessionProtocolNameRegistry::INVALID; // Predefined protocol sets for ease of use. SessionProtocolSet HTTP_PROTOCOL_SET; SessionProtocolSet HTTP2_PROTOCOL_SET; SessionProtocolSet DEFAULT_NON_TLS_SESSION_PROTOCOL_SET; SessionProtocolSet DEFAULT_TLS_SESSION_PROTOCOL_SET; +SessionProtocolSet DEFAULT_QUIC_SESSION_PROTOCOL_SET; void RecHttpLoadIp(const char *value_name, IpAddr &ip4, IpAddr &ip6) @@ -432,7 +436,13 @@ HttpProxyPort::processOptions(const char *opts) // Set the default session protocols. if (!sp_set_p) { - m_session_protocol_preference = this->isSSL() ? DEFAULT_TLS_SESSION_PROTOCOL_SET : DEFAULT_NON_TLS_SESSION_PROTOCOL_SET; + if (this->isSSL()) { + m_session_protocol_preference = DEFAULT_TLS_SESSION_PROTOCOL_SET; + } else if (this->isQUIC()) { + m_session_protocol_preference = DEFAULT_QUIC_SESSION_PROTOCOL_SET; + } else { + m_session_protocol_preference = DEFAULT_NON_TLS_SESSION_PROTOCOL_SET; + } } return zret; @@ -587,6 +597,8 @@ HttpProxyPort::print(char *out, size_t n) sp_set.markOut(DEFAULT_NON_TLS_SESSION_PROTOCOL_SET); } else if (sp_set == DEFAULT_TLS_SESSION_PROTOCOL_SET && this->isSSL()) { sp_set.markOut(DEFAULT_TLS_SESSION_PROTOCOL_SET); + } else if (sp_set == DEFAULT_QUIC_SESSION_PROTOCOL_SET && this->isQUIC()) { + sp_set.markOut(DEFAULT_QUIC_SESSION_PROTOCOL_SET); } // pull out groups. @@ -644,6 +656,7 @@ ts_session_protocol_well_known_name_indices_init() TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_1_0); TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_1_1); TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_2_0); + TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_QUIC); // Now do the predefined protocol sets. HTTP_PROTOCOL_SET.markIn(TS_ALPN_PROTOCOL_INDEX_HTTP_0_9); @@ -652,6 +665,9 @@ ts_session_protocol_well_known_name_indices_init() HTTP2_PROTOCOL_SET.markIn(TS_ALPN_PROTOCOL_INDEX_HTTP_2_0); DEFAULT_TLS_SESSION_PROTOCOL_SET.markAllIn(); + DEFAULT_TLS_SESSION_PROTOCOL_SET.markOut(TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC); + + DEFAULT_QUIC_SESSION_PROTOCOL_SET.markIn(TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC); DEFAULT_NON_TLS_SESSION_PROTOCOL_SET = HTTP_PROTOCOL_SET; @@ -659,6 +675,7 @@ ts_session_protocol_well_known_name_indices_init() ink_hash_table_insert(TSProtoTags, TS_PROTO_TAG_HTTP_1_0, reinterpret_cast(const_cast(TS_PROTO_TAG_HTTP_1_0))); ink_hash_table_insert(TSProtoTags, TS_PROTO_TAG_HTTP_1_1, reinterpret_cast(const_cast(TS_PROTO_TAG_HTTP_1_1))); ink_hash_table_insert(TSProtoTags, TS_PROTO_TAG_HTTP_2_0, reinterpret_cast(const_cast(TS_PROTO_TAG_HTTP_2_0))); + ink_hash_table_insert(TSProtoTags, TS_PROTO_TAG_HTTP_QUIC, reinterpret_cast(const_cast(TS_PROTO_TAG_HTTP_QUIC))); ink_hash_table_insert(TSProtoTags, TS_PROTO_TAG_TLS_1_3, reinterpret_cast(const_cast(TS_PROTO_TAG_TLS_1_3))); ink_hash_table_insert(TSProtoTags, TS_PROTO_TAG_TLS_1_2, reinterpret_cast(const_cast(TS_PROTO_TAG_TLS_1_2))); ink_hash_table_insert(TSProtoTags, TS_PROTO_TAG_TLS_1_1, reinterpret_cast(const_cast(TS_PROTO_TAG_TLS_1_1))); diff --git a/lib/ts/apidefs.h.in b/lib/ts/apidefs.h.in index eb69a702311..79fc0f7feed 100644 --- a/lib/ts/apidefs.h.in +++ b/lib/ts/apidefs.h.in @@ -1161,11 +1161,13 @@ extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_0_9; extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_1_0; extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_1_1; extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_2_0; +extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_QUIC; extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_0_9; extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_1_0; extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_1_1; extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_2_0; +extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC; extern tsapi const char *const TS_ALPN_PROTOCOL_GROUP_HTTP; extern tsapi const char *const TS_ALPN_PROTOCOL_GROUP_HTTP2; @@ -1173,6 +1175,7 @@ extern tsapi const char *const TS_ALPN_PROTOCOL_GROUP_HTTP2; extern tsapi const char *const TS_PROTO_TAG_HTTP_1_0; extern tsapi const char *const TS_PROTO_TAG_HTTP_1_1; extern tsapi const char *const TS_PROTO_TAG_HTTP_2_0; +extern tsapi const char *const TS_PROTO_TAG_HTTP_QUIC; extern tsapi const char *const TS_PROTO_TAG_TLS_1_3; extern tsapi const char *const TS_PROTO_TAG_TLS_1_2; extern tsapi const char *const TS_PROTO_TAG_TLS_1_1; diff --git a/lib/ts/ink_inet.cc b/lib/ts/ink_inet.cc index 2e940c627fa..8247cb420c3 100644 --- a/lib/ts/ink_inet.cc +++ b/lib/ts/ink_inet.cc @@ -44,6 +44,7 @@ const ts::StringView IP_PROTO_TAG_HTTP_0_9("http/0.9", ts::StringView::literal); const ts::StringView IP_PROTO_TAG_HTTP_1_0("http/1.0", ts::StringView::literal); const ts::StringView IP_PROTO_TAG_HTTP_1_1("http/1.1", ts::StringView::literal); const ts::StringView IP_PROTO_TAG_HTTP_2_0("h2", ts::StringView::literal); // HTTP/2 over TLS +const ts::StringView IP_PROTO_TAG_HTTP_QUIC("hq-05", ts::StringView::literal); // HTTP over QUIC uint32_t ink_inet_addr(const char *s) diff --git a/lib/ts/ink_inet.h b/lib/ts/ink_inet.h index 2f0c757d719..bca32a066ce 100644 --- a/lib/ts/ink_inet.h +++ b/lib/ts/ink_inet.h @@ -58,6 +58,7 @@ extern const ts::StringView IP_PROTO_TAG_HTTP_0_9; extern const ts::StringView IP_PROTO_TAG_HTTP_1_0; extern const ts::StringView IP_PROTO_TAG_HTTP_1_1; extern const ts::StringView IP_PROTO_TAG_HTTP_2_0; +extern const ts::StringView IP_PROTO_TAG_HTTP_QUIC; struct IpAddr; // forward declare. diff --git a/proxy/http/HttpProxyServerMain.cc b/proxy/http/HttpProxyServerMain.cc index 6e2771683fe..1ee1b0f7313 100644 --- a/proxy/http/HttpProxyServerMain.cc +++ b/proxy/http/HttpProxyServerMain.cc @@ -224,8 +224,11 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned #if TS_USE_QUIC == 1 } else if (port.isQUIC()) { // HTTP/QUIC - HQSessionAccept *hq = new HQSessionAccept(accept_opt); - acceptor._accept = hq; + if (port.m_session_protocol_preference.contains(TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC)) { + HQSessionAccept *hq = new HQSessionAccept(accept_opt); + // FIXME hq should be registered to QUICNextProtocolAccept like SSL + acceptor._accept = hq; + } #endif } else { acceptor._accept = probe; From 6d538d4e4cb385325999150e67c0b1848aca6997 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 Aug 2017 16:05:01 +0900 Subject: [PATCH 0053/1313] Return QUICError from QUICFrameHandler::handle_frame() --- iocore/net/P_QUICNetVConnection.h | 4 +- iocore/net/QUICNetVConnection.cc | 65 +++++++++++-------- iocore/net/quic/Mock.h | 12 +++- iocore/net/quic/QUICCongestionController.cc | 6 +- iocore/net/quic/QUICCongestionController.h | 2 +- iocore/net/quic/QUICFrameDispatcher.cc | 18 +++-- iocore/net/quic/QUICFrameDispatcher.h | 2 +- iocore/net/quic/QUICFrameHandler.h | 4 +- iocore/net/quic/QUICLossDetector.cc | 6 +- iocore/net/quic/QUICLossDetector.h | 2 +- iocore/net/quic/QUICStreamManager.cc | 6 +- iocore/net/quic/QUICStreamManager.h | 2 +- .../net/quic/test/test_QUICFrameDispatcher.cc | 5 +- 13 files changed, 83 insertions(+), 51 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index a2e6cf35b49..6d70c00c5ae 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -185,7 +185,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // QUICConnection (QUICFrameHandler) std::vector interests() override; - void handle_frame(std::shared_ptr frame) override; + QUICError handle_frame(std::shared_ptr frame) override; private: QUICConnectionId _quic_connection_id; @@ -221,7 +221,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection std::unique_ptr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type = QUICPacketType::UNINITIALIZED); - void _recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_num); + QUICError _recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_numm); QUICError _state_handshake_process_initial_client_packet(std::unique_ptr packet); QUICError _state_handshake_process_client_cleartext_packet(std::unique_ptr packet); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 1d44f42ff44..f6343c32ebe 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -322,9 +322,11 @@ QUICNetVConnection::interests() return {QUICFrameType::CONNECTION_CLOSE}; } -void +QUICError QUICNetVConnection::handle_frame(std::shared_ptr frame) { + QUICError error = QUICError(QUICErrorClass::NONE); + switch (frame->type()) { case QUICFrameType::CONNECTION_CLOSE: DebugQUICCon("Enter state_connection_closed"); @@ -335,6 +337,8 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) ink_assert(false); break; } + + return error; } // TODO: Timeout by active_timeout / inactive_timeout @@ -542,26 +546,30 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_p if (packet->type() != QUICPacketType::CLIENT_INITIAL) { return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); } - if (packet->version()) { - if (this->_version_negotiator->negotiate(packet.get()) == QUICVersionNegotiationStatus::NEGOTIATED) { - DebugQUICCon("Version negotiation succeeded: %x", packet->version()); - this->_packet_factory.set_version(packet->version()); - // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing) - if (packet->has_valid_fnv1a_hash()) { - // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not - this->_handshake_handler = new QUICHandshake(this, this->_crypto); - this->_application_map.set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); - - this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size()); - } else { - DebugQUICCon("Invalid FNV-1a hash value"); - } - } else { - DebugQUICCon("Version negotiation failed: %x", packet->version()); - } - } else { + + if (!packet->version()) { return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); } + + if (this->_version_negotiator->negotiate(packet.get()) != QUICVersionNegotiationStatus::NEGOTIATED) { + DebugQUICCon("Version negotiation failed: %x", packet->version()); + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_VERSION_NEGOTIATION_MISMATCH); + } + + DebugQUICCon("Version negotiation succeeded: %x", packet->version()); + this->_packet_factory.set_version(packet->version()); + // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing) + if (!packet->has_valid_fnv1a_hash()) { + DebugQUICCon("Invalid FNV-1a hash value"); + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::CRYPTOGRAPHIC_ERROR); + } + + // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not + this->_handshake_handler = new QUICHandshake(this, this->_crypto); + this->_application_map.set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); + bool should_send_ack; + + return this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size(), should_send_ack); } return QUICError(QUICErrorClass::NONE); @@ -570,13 +578,16 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_p QUICError QUICNetVConnection::_state_handshake_process_client_cleartext_packet(std::unique_ptr packet) { + QUICError error = QUICError(QUICErrorClass::NONE); + // The payload of this packet contains STREAM frames and could contain PADDING and ACK frames if (packet->has_valid_fnv1a_hash()) { - this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); + error = this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); } else { DebugQUICCon("Invalid FNV-1a hash value"); + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::CRYPTOGRAPHIC_ERROR); } - return QUICError(QUICErrorClass::NONE); + return error; } QUICError @@ -601,9 +612,7 @@ QUICNetVConnection::_state_connection_established_process_packet(std::unique_ptr DebugQUICCon("Decrypt Packet, pkt_num: %" PRIu64 ", header_len: %hu, payload_len: %zu", packet->packet_number(), packet->header_size(), plain_txt_len); - this->_recv_and_ack(plain_txt.get(), plain_txt_len, packet->packet_number()); - - return QUICError(QUICErrorClass::NONE); + return this->_recv_and_ack(plain_txt.get(), plain_txt_len, packet->packet_number()); } else { DebugQUICCon("CRYPTOGRAPHIC Error"); @@ -699,16 +708,20 @@ QUICNetVConnection::_packetize_frames() } } -void +QUICError QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_num) { - bool should_send_ack = this->_frame_dispatcher->receive_frames(payload, size); + bool should_send_ack; + QUICError error = this->_frame_dispatcher->receive_frames(payload, size, should_send_ack); + this->_ack_frame_creator.update(packet_num, should_send_ack); std::unique_ptr ack_frame = this->_ack_frame_creator.create_if_needed(); if (ack_frame != nullptr) { this->transmit_frame(std::move(ack_frame)); eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); } + + return error; } std::unique_ptr diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index b69795426ab..6e72a74b0e2 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -126,11 +126,13 @@ class MockQUICConnection : public QUICConnection return {QUICFrameType::CONNECTION_CLOSE}; } - void + QUICError handle_frame(std::shared_ptr f) override { ++_frameCount[static_cast(f->type())]; ++_totalFrameCount; + + return QUICError(QUICErrorClass::NONE); } uint32_t @@ -258,11 +260,13 @@ class MockQUICStreamManager : public QUICStreamManager MockQUICStreamManager() : QUICStreamManager() {} // Override - virtual void + virtual QUICError handle_frame(std::shared_ptr f) override { ++_frameCount[static_cast(f->type())]; ++_totalFrameCount; + + return QUICError(QUICErrorClass::NONE); } // for Test @@ -305,11 +309,13 @@ class MockQUICCongestionController : public QUICCongestionController MockQUICCongestionController() : QUICCongestionController() {} // Override - virtual void + virtual QUICError handle_frame(std::shared_ptr f) override { ++_frameCount[static_cast(f->type())]; ++_totalFrameCount; + + return QUICError(QUICErrorClass::NONE); } // for Test diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index f10ef19f415..6da901c537a 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -31,9 +31,11 @@ QUICCongestionController::interests() return {QUICFrameType::ACK, QUICFrameType::STREAM}; } -void +QUICError QUICCongestionController::handle_frame(std::shared_ptr frame) { + QUICError error = QUICError(QUICErrorClass::NONE); + switch (frame->type()) { case QUICFrameType::STREAM: case QUICFrameType::ACK: @@ -43,4 +45,6 @@ QUICCongestionController::handle_frame(std::shared_ptr frame) ink_assert(false); break; } + + return error; } diff --git a/iocore/net/quic/QUICCongestionController.h b/iocore/net/quic/QUICCongestionController.h index 9faab4c4c8b..cf8191bce3b 100644 --- a/iocore/net/quic/QUICCongestionController.h +++ b/iocore/net/quic/QUICCongestionController.h @@ -31,7 +31,7 @@ class QUICCongestionController : public QUICFrameHandler { public: virtual std::vector interests() override; - virtual void handle_frame(std::shared_ptr) override; + virtual QUICError handle_frame(std::shared_ptr) override; private: }; diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 0799f22e170..3ac3f27af49 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -42,12 +42,13 @@ QUICFrameDispatcher::add_handler(QUICFrameHandler *handler) } } -bool -QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size) +QUICError +QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size, bool &should_send_ack) { std::shared_ptr frame(nullptr); - uint16_t cursor = 0; - bool should_send_ack = false; + uint16_t cursor = 0; + should_send_ack = false; + QUICError error = QUICError(QUICErrorClass::NONE); while (cursor < size) { frame = this->_frame_factory.fast_create(payload + cursor, size - cursor); @@ -68,8 +69,13 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size) std::vector handlers = this->_handlers[static_cast(type)]; for (auto h : handlers) { - h->handle_frame(frame); + error = h->handle_frame(frame); + // TODO: is there any case to continue this loop even if error? + if (error.cls != QUICErrorClass::NONE) { + return error; + } } } - return should_send_ack; + + return error; } diff --git a/iocore/net/quic/QUICFrameDispatcher.h b/iocore/net/quic/QUICFrameDispatcher.h index b1865426274..0c61f398800 100644 --- a/iocore/net/quic/QUICFrameDispatcher.h +++ b/iocore/net/quic/QUICFrameDispatcher.h @@ -33,7 +33,7 @@ class QUICFrameDispatcher /* * Returns true if ACK frame should be sent */ - bool receive_frames(const uint8_t *payload, uint16_t size); + QUICError receive_frames(const uint8_t *payload, uint16_t size, bool &should_send_ack); void add_handler(QUICFrameHandler *handler); diff --git a/iocore/net/quic/QUICFrameHandler.h b/iocore/net/quic/QUICFrameHandler.h index 64b09d93ef8..0f2a27ff6b0 100644 --- a/iocore/net/quic/QUICFrameHandler.h +++ b/iocore/net/quic/QUICFrameHandler.h @@ -30,6 +30,6 @@ class QUICFrameHandler { public: virtual ~QUICFrameHandler(){}; - virtual std::vector interests() = 0; - virtual void handle_frame(std::shared_ptr frame) = 0; + virtual std::vector interests() = 0; + virtual QUICError handle_frame(std::shared_ptr frame) = 0; }; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 4c6bd341b3c..12a7368525e 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -78,9 +78,11 @@ QUICLossDetector::interests() return {QUICFrameType::ACK}; } -void +QUICError QUICLossDetector::handle_frame(std::shared_ptr frame) { + QUICError error = QUICError(QUICErrorClass::NONE); + switch (frame->type()) { case QUICFrameType::ACK: this->_on_ack_received(std::dynamic_pointer_cast(frame)); @@ -90,6 +92,8 @@ QUICLossDetector::handle_frame(std::shared_ptr frame) ink_assert(false); break; } + + return error; } void diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 0b93b4649e5..56d9650cfc8 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -46,7 +46,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler int event_handler(int event, Event *edata); std::vector interests() override; - virtual void handle_frame(std::shared_ptr) override; + virtual QUICError handle_frame(std::shared_ptr) override; void on_packet_sent(std::unique_ptr packet); private: diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index fab8deab3ee..6015f397699 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -61,7 +61,7 @@ QUICStreamManager::init_flow_control_params(const QUICTransportParameters &local stream->init_flow_control_params(local_tp.initial_max_stream_data(), remote_tp.initial_max_stream_data()); } -void +QUICError QUICStreamManager::handle_frame(std::shared_ptr frame) { QUICError error = QUICError(QUICErrorClass::NONE); @@ -92,9 +92,7 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) break; } - if (error.cls != QUICErrorClass::NONE) { - // TODO return error - } + return error; } QUICError diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 6df6db38f13..4abea4ffed1 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -39,7 +39,7 @@ class QUICStreamManager : public QUICFrameHandler int init(QUICFrameTransmitter *tx, QUICConnection *qc, QUICApplicationMap *app_map); virtual std::vector interests() override; - virtual void handle_frame(std::shared_ptr) override; + virtual QUICError handle_frame(std::shared_ptr) override; virtual void send_frame(std::unique_ptr frame); void send_stream_frame(std::unique_ptr frame); virtual bool is_send_avail_more_than(uint64_t size); diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 5b158192d07..8573dce68af 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -51,7 +51,8 @@ TEST_CASE("QUICFrameHandler", "[quic]") uint8_t buf[4096] = {0}; size_t len = 0; streamFrame.store(buf, &len); - quicFrameDispatcher.receive_frames(buf, len); + bool should_send_ack; + quicFrameDispatcher.receive_frames(buf, len, should_send_ack); CHECK(connection->getTotalFrameCount() == 0); CHECK(streamManager->getTotalFrameCount() == 1); CHECK(congestionController->getTotalFrameCount() == 1); @@ -59,7 +60,7 @@ TEST_CASE("QUICFrameHandler", "[quic]") // CONNECTION_CLOSE frame QUICConnectionCloseFrame connectionCloseFrame({}); connectionCloseFrame.store(buf, &len); - quicFrameDispatcher.receive_frames(buf, len); + quicFrameDispatcher.receive_frames(buf, len, should_send_ack); CHECK(connection->getTotalFrameCount() == 1); CHECK(streamManager->getTotalFrameCount() == 1); CHECK(congestionController->getTotalFrameCount() == 1); From 0b589903df5f433fc44df2c408eb30428c13de99 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 Aug 2017 16:25:45 +0900 Subject: [PATCH 0054/1313] Remvoe duplicated mutex allocation --- iocore/net/QUICNetVConnection.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index f6343c32ebe..3ec81cb8d19 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -62,7 +62,6 @@ QUICNetVConnection::init(UDPConnection *udp_con, QUICPacketHandler *packet_handl { this->_transmitter_mutex = new_ProxyMutex(); this->_udp_con = udp_con; - this->_transmitter_mutex = new_ProxyMutex(); this->_packet_handler = packet_handler; this->_quic_connection_id.randomize(); From 075d829b405800c70061797725a5584d378f48ab Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 Aug 2017 16:35:10 +0900 Subject: [PATCH 0055/1313] Cleanup QUICStreamManager --- iocore/net/quic/QUICStream.cc | 2 +- iocore/net/quic/QUICStreamManager.cc | 18 +++++++++--------- iocore/net/quic/QUICStreamManager.h | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 362337720c0..f5594198450 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -400,7 +400,7 @@ QUICStream::_send() break; } this->_state.update_with_sent_frame(*frame); - this->_streamManager->send_stream_frame(std::move(frame)); + this->_streamManager->send_frame(std::move(frame)); } return; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 6015f397699..4ac3b9425a2 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -68,7 +68,7 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) switch (frame->type()) { case QUICFrameType::MAX_DATA: { - error = this->_handle_max_data_frame(std::dynamic_pointer_cast(frame)); + error = this->_handle_frame(std::dynamic_pointer_cast(frame)); break; } case QUICFrameType::BLOCKED: { @@ -76,15 +76,15 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) break; } case QUICFrameType::MAX_STREAM_DATA: { - error = this->_handle_max_stream_data_frame(std::dynamic_pointer_cast(frame)); + error = this->_handle_frame(std::dynamic_pointer_cast(frame)); break; } case QUICFrameType::STREAM_BLOCKED: { - error = this->_handle_stream_blocked_frame(std::dynamic_pointer_cast(frame)); + error = this->_handle_frame(std::dynamic_pointer_cast(frame)); break; } case QUICFrameType::STREAM: - error = this->_handle_stream_frame(std::dynamic_pointer_cast(frame)); + error = this->_handle_frame(std::dynamic_pointer_cast(frame)); break; default: Debug(tag, "Unexpected frame type: %02x", static_cast(frame->type())); @@ -96,7 +96,7 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) } QUICError -QUICStreamManager::_handle_max_data_frame(std::shared_ptr frame) +QUICStreamManager::_handle_frame(std::shared_ptr frame) { this->_send_max_data = frame->maximum_data(); return QUICError(QUICErrorClass::NONE); @@ -111,7 +111,7 @@ QUICStreamManager::slide_recv_max_data() } QUICError -QUICStreamManager::_handle_max_stream_data_frame(std::shared_ptr frame) +QUICStreamManager::_handle_frame(std::shared_ptr frame) { QUICStream *stream = this->_find_stream(frame->stream_id()); if (stream) { @@ -124,7 +124,7 @@ QUICStreamManager::_handle_max_stream_data_frame(std::shared_ptr frame) +QUICStreamManager::_handle_frame(std::shared_ptr frame) { QUICStream *stream = this->_find_stream(frame->stream_id()); if (stream) { @@ -137,7 +137,7 @@ QUICStreamManager::_handle_stream_blocked_frame(std::shared_ptr frame) +QUICStreamManager::_handle_frame(std::shared_ptr frame) { QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); QUICApplication *application = this->_app_map->get(frame->stream_id()); @@ -159,7 +159,7 @@ QUICStreamManager::_handle_stream_frame(std::shared_ptr f * @brief Send stream frame */ void -QUICStreamManager::send_stream_frame(std::unique_ptr frame) +QUICStreamManager::send_frame(std::unique_ptr frame) { // XXX The offset of sending frame is always largest offset by sending side if (frame->stream_id() != STREAM_ID_FOR_HANDSHAKE) { diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 4abea4ffed1..fbfc6e97ece 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -41,7 +41,7 @@ class QUICStreamManager : public QUICFrameHandler virtual std::vector interests() override; virtual QUICError handle_frame(std::shared_ptr) override; virtual void send_frame(std::unique_ptr frame); - void send_stream_frame(std::unique_ptr frame); + virtual void send_frame(std::unique_ptr frame); virtual bool is_send_avail_more_than(uint64_t size); virtual bool is_recv_avail_more_than(uint64_t size); void add_recv_total_offset(uint64_t delta); @@ -57,10 +57,10 @@ class QUICStreamManager : public QUICFrameHandler private: QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICStream *_find_stream(QUICStreamId id); - QUICError _handle_max_data_frame(std::shared_ptr); - QUICError _handle_stream_frame(std::shared_ptr); - QUICError _handle_max_stream_data_frame(std::shared_ptr); - QUICError _handle_stream_blocked_frame(std::shared_ptr); + QUICError _handle_frame(std::shared_ptr); + QUICError _handle_frame(std::shared_ptr); + QUICError _handle_frame(std::shared_ptr); + QUICError _handle_frame(std::shared_ptr); QUICApplicationMap *_app_map = nullptr; QUICFrameTransmitter *_tx = nullptr; From 1f8eeaee5364da3db3fe3e7cb130827321690d88 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 24 Aug 2017 14:39:47 +0900 Subject: [PATCH 0056/1313] Prevent retransmitting Handshake packets many many times --- iocore/net/quic/QUICLossDetector.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 12a7368525e..6d66a02399b 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -339,10 +339,17 @@ QUICLossDetector::_retransmit_handshake_packets() { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + std::set retransmitted_handshake_packets; + for (auto &info : this->_sent_packets) { if (!info.second->handshake) { break; } + retransmitted_handshake_packets.insert(info.first); this->_transmitter->retransmit_packet(*info.second->packet); } + + for (auto packet_number : retransmitted_handshake_packets) { + this->_sent_packets.erase(packet_number); + } } From ed4ff1b7ab89b0176d7559519d493377ecb5f949 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 24 Aug 2017 15:09:43 +0900 Subject: [PATCH 0057/1313] Set inactivity timeout before handshake start --- iocore/net/P_QUICNetVConnection.h | 4 +++ iocore/net/QUICNetVConnection.cc | 59 +++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 6d70c00c5ae..40a9a40d2a3 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -111,6 +111,9 @@ class SSLNextProtocolSet; * @brief A NetVConnection for a QUIC network socket * @detail * + * state_pre_handshake() + * | + * v * state_handshake() * | READ: * | _state_handshake_process_initial_client_packet() @@ -150,6 +153,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override; VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) override; int startEvent(int event, Event *e); + int state_pre_handshake(int event, Event *data); int state_handshake(int event, Event *data); int state_connection_established(int event, Event *data); int state_connection_closing(int event, Event *data); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3ec81cb8d19..25885790fae 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -54,9 +54,10 @@ ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); QUICNetVConnection::QUICNetVConnection() : UnixNetVConnection() { - SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_handshake); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_pre_handshake); } +// XXX This might be called on ET_UDP thread void QUICNetVConnection::init(UDPConnection *udp_con, QUICPacketHandler *packet_handler) { @@ -340,35 +341,53 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) return error; } -// TODO: Timeout by active_timeout / inactive_timeout +// XXX Setup QUICNetVConnection on regular EThread. +// QUICNetVConnection::init() and QUICNetVConnection::start() might be called on ET_UDP EThread. int -QUICNetVConnection::state_handshake(int event, Event *data) +QUICNetVConnection::state_pre_handshake(int event, Event *data) { - QUICError error; - - if (!thread) { - thread = this_ethread(); + if (!this->thread) { + this->thread = this_ethread(); } - if (!nh) { - nh = get_NetHandler(this_ethread()); + if (!this->nh) { + this->nh = get_NetHandler(this_ethread()); } + // FIXME: Should be accept_no_activity_timeout? + QUICConfig::scoped_config params; + + this->set_inactivity_timeout(HRTIME_SECONDS(params->no_activity_timeout_in())); + this->add_to_active_queue(); + + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_handshake); + return this->handleEvent(event, data); +} + +// TODO: Timeout by active_timeout +int +QUICNetVConnection::state_handshake(int event, Event *data) +{ + QUICError error; + switch (event) { case QUIC_EVENT_PACKET_READ_READY: { std::unique_ptr p = std::unique_ptr(this->_packet_recv_queue.dequeue()); net_activity(this, this_ethread()); switch (p->type()) { - case QUICPacketType::CLIENT_INITIAL: + case QUICPacketType::CLIENT_INITIAL: { error = this->_state_handshake_process_initial_client_packet(std::move(p)); break; - case QUICPacketType::CLIENT_CLEARTEXT: + } + case QUICPacketType::CLIENT_CLEARTEXT: { error = this->_state_handshake_process_client_cleartext_packet(std::move(p)); break; - case QUICPacketType::ZERO_RTT_PROTECTED: + } + case QUICPacketType::ZERO_RTT_PROTECTED: { error = this->_state_handshake_process_zero_rtt_protected_packet(std::move(p)); break; + } default: error = QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); break; @@ -380,6 +399,15 @@ QUICNetVConnection::state_handshake(int event, Event *data) error = this->_state_common_send_packet(); break; } + case EVENT_IMMEDIATE: { + // Start Implicit Shutdown. Because of no network activity for the duration of the idle timeout. + this->remove_from_active_queue(); + this->close({}); + + // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application + break; + } + default: DebugQUICCon("Unexpected event: %u", event); } @@ -395,13 +423,6 @@ QUICNetVConnection::state_handshake(int event, Event *data) this->_application_map.set_default(this->_create_application()); DebugQUICCon("Enter state_connection_established"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); - - QUICConfig::scoped_config params; - - // TODO: use idle_timeout from negotiated Transport Prameters - ink_hrtime idle_timeout = HRTIME_SECONDS(params->no_activity_timeout_in()); - this->set_inactivity_timeout(idle_timeout); - this->add_to_active_queue(); } return EVENT_CONT; From f52efea24b10c8fbbf641cd5784eccbacf14107c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 24 Aug 2017 16:01:12 +0900 Subject: [PATCH 0058/1313] Fix alarm duration of QUICLossDetector - Fix cut & paste code from pseudocode for SetLossDetectionAlarm - Use ink_hrtime type --- iocore/net/quic/QUICLossDetector.cc | 8 ++++---- iocore/net/quic/QUICLossDetector.h | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 6d66a02399b..430d504e8e6 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -273,7 +273,7 @@ QUICLossDetector::_update_rtt(uint32_t latest_rtt) void QUICLossDetector::_set_loss_detection_alarm() { - uint32_t alarm_duration; + ink_hrtime alarm_duration; if (!this->_retransmittable_outstanding && this->_loss_detection_alarm) { this->_loss_detection_alarm->cancel(); this->_loss_detection_alarm = nullptr; @@ -288,7 +288,7 @@ QUICLossDetector::_set_loss_detection_alarm() alarm_duration = 2 * this->_smoothed_rtt; } alarm_duration = max(alarm_duration, this->_MIN_TLP_TIMEOUT); - alarm_duration = alarm_duration * (2 ^ this->_handshake_count); + alarm_duration = alarm_duration * (1 << this->_handshake_count); Debug("quic_loss_detection", "Handshake retransmission alarm will be set"); } else if (this->_loss_time != 0) { // Early retransmit timer or time loss detection. @@ -307,7 +307,7 @@ QUICLossDetector::_set_loss_detection_alarm() // RTO alarm alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar; alarm_duration = max(alarm_duration, this->_MIN_RTO_TIMEOUT); - alarm_duration = alarm_duration * (2 ^ this->_rto_count); + alarm_duration = alarm_duration * (1 << this->_rto_count); Debug("quic_loss_detection", "RTO alarm will be set"); } @@ -315,7 +315,7 @@ QUICLossDetector::_set_loss_detection_alarm() this->_loss_detection_alarm->cancel(); } this->_loss_detection_alarm = eventProcessor.schedule_in(this, alarm_duration); - Debug("quic_loss_detection", "Loss detection alarm has been set to %u", alarm_duration); + Debug("quic_loss_detection", "Loss detection alarm has been set to %" PRId64, alarm_duration); } std::set diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 56d9650cfc8..df29ac9eb1e 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -67,10 +67,10 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler uint32_t _MAX_TLPS = 2; uint32_t _REORDERING_THRESHOLD = 3; double _TIME_REORDERING_FRACTION = 1 / 8; - uint32_t _MIN_TLP_TIMEOUT = HRTIME_MSECONDS(10); - uint32_t _MIN_RTO_TIMEOUT = HRTIME_MSECONDS(200); - uint32_t _DELAYED_ACK_TIMEOUT = HRTIME_MSECONDS(25); - uint32_t _DEFAULT_INITIAL_RTT = HRTIME_MSECONDS(100); + ink_hrtime _MIN_TLP_TIMEOUT = HRTIME_MSECONDS(10); + ink_hrtime _MIN_RTO_TIMEOUT = HRTIME_MSECONDS(200); + ink_hrtime _DELAYED_ACK_TIMEOUT = HRTIME_MSECONDS(25); + ink_hrtime _DEFAULT_INITIAL_RTT = HRTIME_MSECONDS(100); // 3.2.2. Variables of interest Action *_loss_detection_alarm; @@ -81,12 +81,12 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler uint32_t _largest_sent_packet; uint32_t _largest_acked_packet; uint32_t _time_of_last_sent_packet; - uint32_t _latest_rtt; - uint32_t _smoothed_rtt; + ink_hrtime _latest_rtt; + ink_hrtime _smoothed_rtt; uint32_t _rttvar; uint32_t _reordering_threshold; double _time_reordering_fraction; - uint32_t _loss_time; + ink_hrtime _loss_time; std::map> _sent_packets; uint32_t _handshake_outstanding = 0; From c6da89c43342b91e30617982907faf248c6da2e6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 25 Aug 2017 11:06:03 +0900 Subject: [PATCH 0059/1313] Fix handshake_outstanding count --- iocore/net/quic/QUICLossDetector.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 430d504e8e6..c406b9b52fd 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -351,5 +351,6 @@ QUICLossDetector::_retransmit_handshake_packets() for (auto packet_number : retransmitted_handshake_packets) { this->_sent_packets.erase(packet_number); + --this->_handshake_outstanding; } } From 1acd290179f3ad0f963ba6410e6cf8d50b271f62 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 25 Aug 2017 11:14:30 +0900 Subject: [PATCH 0060/1313] Refactor handshake As per 7.2 Cryptographic and Transport Handshake, crypto module, transport parameter, negotiated version, negotiated application are provided from Handshake. --- iocore/net/P_QUICNetVConnection.h | 10 +- iocore/net/QUICNetVConnection.cc | 126 ++++---------------- iocore/net/quic/Mock.h | 7 -- iocore/net/quic/QUICApplication.h | 1 + iocore/net/quic/QUICConnection.h | 14 +-- iocore/net/quic/QUICCrypto.cc | 5 +- iocore/net/quic/QUICCrypto.h | 5 +- iocore/net/quic/QUICFrame.h | 1 - iocore/net/quic/QUICGlobals.cc | 9 +- iocore/net/quic/QUICGlobals.h | 6 +- iocore/net/quic/QUICHandshake.cc | 131 ++++++++++++++++++++- iocore/net/quic/QUICHandshake.h | 32 ++++- iocore/net/quic/QUICStream.h | 1 - iocore/net/quic/QUICStreamManager.cc | 26 ++-- iocore/net/quic/QUICStreamManager.h | 13 +- iocore/net/quic/QUICTransportParameters.cc | 14 +-- iocore/net/quic/QUICTransportParameters.h | 2 - iocore/net/quic/QUICTypes.h | 4 - iocore/net/quic/QUICVersionNegotiator.cc | 19 ++- iocore/net/quic/QUICVersionNegotiator.h | 8 +- 20 files changed, 241 insertions(+), 193 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 40a9a40d2a3..785f30bb6ae 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -166,7 +166,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection virtual void net_read_io(NetHandler *nh, EThread *lthread) override; virtual int64_t load_buffer_and_write(int64_t towrite, MIOBufferAccessor &buf, int64_t &total_written, int &needs) override; - SSLNextProtocolSet *next_protocol_set(); + // QUICNetVConnection void registerNextProtocolSet(SSLNextProtocolSet *s); // QUICConnection @@ -174,9 +174,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection uint32_t minimum_quic_packet_size() override; uint32_t maximum_stream_frame_data_size() override; uint32_t pmtu() override; - void set_transport_parameters(std::unique_ptr tp) override; - const QUICTransportParameters &local_transport_parameters() override; - const QUICTransportParameters &remote_transport_parameters() override; + NetVConnectionContext_t direction() override; + SSLNextProtocolSet *next_protocol_set() override; void close(QUICError error) override; // QUICConnection (QUICPacketTransmitter) @@ -204,9 +203,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection SSLNextProtocolSet *_next_protocol_set = nullptr; - std::unique_ptr _local_transport_parameters = nullptr; - std::unique_ptr _remote_transport_parameters = nullptr; - // TODO: use custom allocator and make them std::unique_ptr or std::shared_ptr // or make them just member variables. QUICVersionNegotiator *_version_negotiator = nullptr; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 25885790fae..75b16f913d3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -94,14 +94,16 @@ QUICNetVConnection::startEvent(int /*event ATS_UNUSED */, Event *e) void QUICNetVConnection::start(SSL_CTX *ssl_ctx) { - this->_version_negotiator = new QUICVersionNegotiator(&this->_packet_factory, this); - this->_crypto = new QUICCrypto(ssl_ctx, this); - this->_frame_dispatcher = new QUICFrameDispatcher(); + // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not + this->_handshake_handler = new QUICHandshake(this, ssl_ctx); + this->_application_map.set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); + + this->_crypto = this->_handshake_handler->crypto_module(); + this->_frame_dispatcher = new QUICFrameDispatcher(); this->_packet_factory.set_crypto_module(this->_crypto); // Create frame handlers - this->_stream_manager = new QUICStreamManager(); - this->_stream_manager->init(this, this, &this->_application_map); + this->_stream_manager = new QUICStreamManager(this, &this->_application_map); this->_congestion_controller = new QUICCongestionController(); this->_loss_detector = new QUICLossDetector(this); @@ -109,31 +111,6 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) this->_frame_dispatcher->add_handler(this->_stream_manager); this->_frame_dispatcher->add_handler(this->_congestion_controller); this->_frame_dispatcher->add_handler(this->_loss_detector); - - QUICConfig::scoped_config params; - - // MUSTs - QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(); - - tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, - std::unique_ptr( - new QUICTransportParameterValue(params->initial_max_stream_data(), sizeof(params->initial_max_stream_data())))); - - tp->add(QUICTransportParameterId::INITIAL_MAX_DATA, std::unique_ptr(new QUICTransportParameterValue( - params->initial_max_data(), sizeof(params->initial_max_data())))); - - tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, - std::unique_ptr( - new QUICTransportParameterValue(params->initial_max_stream_id(), sizeof(params->initial_max_stream_id())))); - - tp->add(QUICTransportParameterId::IDLE_TIMEOUT, std::unique_ptr(new QUICTransportParameterValue( - params->no_activity_timeout_in(), sizeof(uint16_t)))); - - tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); - // MAYs - // this->_local_transport_parameters.add(QUICTransportParameterId::TRUNCATE_CONNECTION_ID, {}); - // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); - this->_local_transport_parameters = std::unique_ptr(tp); } void @@ -174,53 +151,10 @@ QUICNetVConnection::pmtu() return this->_pmtu; } -void -QUICNetVConnection::set_transport_parameters(std::unique_ptr tp) -{ - this->_remote_transport_parameters = std::move(tp); - this->_stream_manager->init_flow_control_params(*this->_local_transport_parameters, *this->_remote_transport_parameters); - - const QUICTransportParametersInClientHello *tp_in_ch = - dynamic_cast(this->_remote_transport_parameters.get()); - if (tp_in_ch) { - // Version revalidation - QUICVersion version = tp_in_ch->negotiated_version(); - if (this->_version_negotiator->revalidate(version) != QUICVersionNegotiationStatus::REVALIDATED) { - this->close({QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_VERSION_NEGOTIATION_MISMATCH}); - return; - } - if (tp_in_ch->negotiated_version() != tp_in_ch->initial_version()) { - // FIXME Check initial_version - /* If the initial version is different from the negotiated_version, a - * stateless server MUST check that it would have sent a version - * negotiation packet if it had received a packet with the indicated - * initial_version. (Draft-04 7.3.4. Version Negotiation Validation) - */ - this->close({QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_VERSION_NEGOTIATION_MISMATCH}); - return; - } - DebugQUICCon("Version negotiation revalidated: %x", tp_in_ch->negotiated_version()); - return; - } - - const QUICTransportParametersInEncryptedExtensions *tp_in_ee = - dynamic_cast(this->_remote_transport_parameters.get()); - if (tp_in_ee) { - // TODO Add client side implementation - return; - } -} - -const QUICTransportParameters & -QUICNetVConnection::local_transport_parameters() +NetVConnectionContext_t +QUICNetVConnection::direction() { - return *this->_local_transport_parameters; -} - -const QUICTransportParameters & -QUICNetVConnection::remote_transport_parameters() -{ - return *this->_remote_transport_parameters; + return this->netvc_context; } uint32_t @@ -419,8 +353,10 @@ QUICNetVConnection::state_handshake(int event, Event *data) } if (this->_handshake_handler && this->_handshake_handler->is_completed()) { - DebugQUICCon("setup quic application"); this->_application_map.set_default(this->_create_application()); + this->_stream_manager->init_flow_control_params(this->_handshake_handler->local_transport_parameters(), + this->_handshake_handler->remote_transport_parameters()); + DebugQUICCon("Enter state_connection_established"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); } @@ -557,42 +493,22 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_p { if (packet->size() < this->minimum_quic_packet_size()) { DebugQUICCon("%" PRId32 ", %" PRId32, packet->size(), this->minimum_quic_packet_size()); - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); } - // Negotiate version - if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) { - if (packet->type() != QUICPacketType::CLIENT_INITIAL) { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); - } - - if (!packet->version()) { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); - } - - if (this->_version_negotiator->negotiate(packet.get()) != QUICVersionNegotiationStatus::NEGOTIATED) { - DebugQUICCon("Version negotiation failed: %x", packet->version()); - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_VERSION_NEGOTIATION_MISMATCH); - } - - DebugQUICCon("Version negotiation succeeded: %x", packet->version()); - this->_packet_factory.set_version(packet->version()); + // Start handshake + QUICError error = this->_handshake_handler->start(packet.get(), &this->_packet_factory); + if (this->_handshake_handler->is_version_negotiated()) { // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing) - if (!packet->has_valid_fnv1a_hash()) { + if (packet->has_valid_fnv1a_hash()) { + bool should_send_ack; + this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size(), should_send_ack); + } else { DebugQUICCon("Invalid FNV-1a hash value"); return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::CRYPTOGRAPHIC_ERROR); } - - // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not - this->_handshake_handler = new QUICHandshake(this, this->_crypto); - this->_application_map.set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); - bool should_send_ack; - - return this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size(), should_send_ack); } - - return QUICError(QUICErrorClass::NONE); + return error; } QUICError diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 6e72a74b0e2..842a6c7dd79 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -96,7 +96,6 @@ class MockQUICConnection : public QUICConnection { public: MockQUICConnection() : QUICConnection() { this->_mutex = new_ProxyMutex(); }; - void transmit_packet(std::unique_ptr packet) override { @@ -200,7 +199,6 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter { public: MockQUICPacketTransmitter() : QUICPacketTransmitter() { this->_mutex = new_ProxyMutex(); }; - void transmit_packet(std::unique_ptr packet) override { @@ -242,7 +240,6 @@ class MockQUICLossDetector : public QUICLossDetector { public: MockQUICLossDetector() : QUICLossDetector(new MockQUICPacketTransmitter()) {} - void rcv_frame(std::shared_ptr) { @@ -258,7 +255,6 @@ class MockQUICStreamManager : public QUICStreamManager { public: MockQUICStreamManager() : QUICStreamManager() {} - // Override virtual QUICError handle_frame(std::shared_ptr f) override @@ -295,9 +291,7 @@ class MockQUICStreamManager : public QUICStreamManager } bool is_recv_avail_more_than(uint64_t /* size */) override { return true; } - void send_frame(std::unique_ptr /* frame */) override { return; } - private: int _totalFrameCount = 0; int _frameCount[256] = {0}; @@ -307,7 +301,6 @@ class MockQUICCongestionController : public QUICCongestionController { public: MockQUICCongestionController() : QUICCongestionController() {} - // Override virtual QUICError handle_frame(std::shared_ptr f) override diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 3e2426e56b4..39c19741a82 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -64,6 +64,7 @@ class QUICApplication : public Continuation { public: QUICApplication(QUICConnection *qc); + virtual ~QUICApplication(){}; void set_stream(QUICStream *stream); bool is_stream_set(QUICStream *stream); diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 9aad6875716..0e571ed97c9 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -29,15 +29,15 @@ #include "QUICTransportParameters.h" class QUICApplication; +class SSLNextProtocolSet; class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler { public: - virtual uint32_t maximum_quic_packet_size() = 0; - virtual uint32_t minimum_quic_packet_size() = 0; - virtual uint32_t pmtu() = 0; - virtual void set_transport_parameters(std::unique_ptr tp) = 0; - virtual const QUICTransportParameters &local_transport_parameters() = 0; - virtual const QUICTransportParameters &remote_transport_parameters() = 0; - virtual void close(QUICError error) = 0; + virtual uint32_t maximum_quic_packet_size() = 0; + virtual uint32_t minimum_quic_packet_size() = 0; + virtual uint32_t pmtu() = 0; + virtual NetVConnectionContext_t direction() = 0; + virtual SSLNextProtocolSet *next_protocol_set() = 0; + virtual void close(QUICError error) = 0; }; diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 53b2799f2ae..02872e7c33a 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -83,10 +83,8 @@ QUICPacketProtection::key_phase() const // // QUICCrypto // -QUICCrypto::QUICCrypto(SSL_CTX *ssl_ctx, NetVConnection *vc) : _netvc_context(vc->get_context()) +QUICCrypto::QUICCrypto(SSL *ssl, NetVConnectionContext_t nvc_ctx) : _ssl(ssl), _netvc_context(nvc_ctx) { - this->_ssl = SSL_new(ssl_ctx); - SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_vc_index, vc); if (this->_netvc_context == NET_VCONNECTION_IN) { SSL_set_accept_state(this->_ssl); } else if (this->_netvc_context == NET_VCONNECTION_OUT) { @@ -101,7 +99,6 @@ QUICCrypto::QUICCrypto(SSL_CTX *ssl_ctx, NetVConnection *vc) : _netvc_context(vc QUICCrypto::~QUICCrypto() { - SSL_free(this->_ssl); delete this->_client_pp; delete this->_server_pp; } diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICCrypto.h index 5617e61688a..1eb24ac9882 100644 --- a/iocore/net/quic/QUICCrypto.h +++ b/iocore/net/quic/QUICCrypto.h @@ -38,7 +38,6 @@ struct KeyMaterial { KeyMaterial(size_t secret_len, size_t key_len, size_t iv_len) : secret_len(secret_len), key_len(key_len), iv_len(iv_len) {} - uint8_t secret[EVP_MAX_MD_SIZE] = {0}; uint8_t key[EVP_MAX_KEY_LENGTH] = {0}; uint8_t iv[EVP_MAX_IV_LENGTH] = {0}; @@ -65,8 +64,8 @@ class QUICPacketProtection class QUICCrypto { public: - QUICCrypto(SSL_CTX *, NetVConnection *); - ~QUICCrypto(); + QUICCrypto(SSL *, NetVConnectionContext_t); + virtual ~QUICCrypto(); bool handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len); bool is_handshake_finished() const; diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 8be22bf22c8..79e21b4e149 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -116,7 +116,6 @@ class QUICAckFrame : public QUICFrame const QUICAckFrame::AckBlock &operator*() const { return this->_current_block; }; const QUICAckFrame::AckBlock *operator->() const { return &this->_current_block; }; - const QUICAckFrame::AckBlock &operator++() { ++(this->_index); diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index b8dd77dac7e..cdad89b168e 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -26,17 +26,18 @@ #include "P_QUICNetVConnection.h" #include "P_SSLNextProtocolSet.h" -int QUIC::ssl_quic_vc_index = -1; +int QUIC::ssl_quic_qc_index = -1; +int QUIC::ssl_quic_hs_index = -1; int QUIC::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen, void *) { const unsigned char *npn; - unsigned npnsz = 0; - QUICNetVConnection *qnvc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_vc_index)); + unsigned npnsz = 0; + QUICConnection *qc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); - qnvc->next_protocol_set()->advertiseProtocols(&npn, &npnsz); + qc->next_protocol_set()->advertiseProtocols(&npn, &npnsz); if (SSL_select_next_proto((unsigned char **)out, outlen, npn, npnsz, in, inlen) == OPENSSL_NPN_NEGOTIATED) { return SSL_TLSEXT_ERR_OK; } diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h index e1d2b4a873d..1af0f733a37 100644 --- a/iocore/net/quic/QUICGlobals.h +++ b/iocore/net/quic/QUICGlobals.h @@ -31,9 +31,11 @@ class QUIC static void init() { - ssl_quic_vc_index = SSL_get_ex_new_index(0, (void *)"NetVC index", nullptr, nullptr, nullptr); + ssl_quic_qc_index = SSL_get_ex_new_index(0, (void *)"QUICConnection index", nullptr, nullptr, nullptr); + ssl_quic_hs_index = SSL_get_ex_new_index(0, (void *)"QUICHandshake index", nullptr, nullptr, nullptr); } - static int ssl_quic_vc_index; + static int ssl_quic_qc_index; + static int ssl_quic_hs_index; // SSL callbacks static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 84261381b69..9e8fdfd685b 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -21,7 +21,11 @@ * limitations under the License. */ +#include "QUICGlobals.h" #include "QUICHandshake.h" +#include "QUICVersionNegotiator.h" +#include "QUICConfig.h" +#include "P_SSLNextProtocolSet.h" #define I_WANNA_DUMP_THIS_BUF(buf, len) \ { \ @@ -48,16 +52,69 @@ const static int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size const static int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(QUICConnection *qc, QUICCrypto *c) : QUICApplication(qc), _crypto(c) +QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICApplication(qc) { + this->_ssl = SSL_new(ssl_ctx); + SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc); + SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_hs_index, this); + this->_crypto = new QUICCrypto(this->_ssl, qc->direction()); + this->_version_negotiator = new QUICVersionNegotiator(); + + this->_load_local_transport_parameters(); + SET_HANDLER(&QUICHandshake::state_read_client_hello); } +QUICHandshake::~QUICHandshake() +{ + SSL_free(this->_ssl); +} + +QUICError +QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory) +{ + // Negotiate version + if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) { + if (initial_packet->type() != QUICPacketType::CLIENT_INITIAL) { + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + } + if (initial_packet->version()) { + if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { + Debug(tag, "Version negotiation succeeded: %x", initial_packet->version()); + packet_factory->set_version(this->_version_negotiator->negotiated_version()); + } else { + this->_client_qc->transmit_packet(packet_factory->create_version_negotiation_packet(initial_packet)); + Debug(tag, "Version negotiation failed: %x", initial_packet->version()); + } + } else { + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + } + } + return QUICError(QUICErrorClass::NONE); +} + +bool +QUICHandshake::is_version_negotiated() +{ + return (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED); +} + bool QUICHandshake::is_completed() { - QUICCrypto *crypto = this->_crypto; - return crypto->is_handshake_finished(); + return this->_crypto->is_handshake_finished(); +} + +QUICVersion +QUICHandshake::negotiated_version() +{ + return this->_version_negotiator->negotiated_version(); +} + +QUICCrypto * +QUICHandshake::crypto_module() +{ + return this->_crypto; } void @@ -66,6 +123,45 @@ QUICHandshake::negotiated_application_name(const uint8_t **name, unsigned int *l SSL_get0_alpn_selected(this->_crypto->ssl_handle(), name, len); } +void +QUICHandshake::set_transport_parameters(std::shared_ptr tp) +{ + this->_remote_transport_parameters = tp; + + const QUICTransportParametersInClientHello *tp_in_ch = + dynamic_cast(this->_remote_transport_parameters.get()); + if (tp_in_ch) { + // Version revalidation + if (this->_version_negotiator->revalidate(tp_in_ch) != QUICVersionNegotiationStatus::REVALIDATED) { + this->_client_qc->close({QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_VERSION_NEGOTIATION_MISMATCH}); + Debug(tag, "Enter state_closed"); + SET_HANDLER(&QUICHandshake::state_closed); + return; + } + Debug(tag, "Version negotiation revalidated: %x", tp_in_ch->negotiated_version()); + return; + } + + const QUICTransportParametersInEncryptedExtensions *tp_in_ee = + dynamic_cast(this->_remote_transport_parameters.get()); + if (tp_in_ee) { + // TODO Add client side implementation + return; + } +} + +std::shared_ptr +QUICHandshake::local_transport_parameters() +{ + return this->_local_transport_parameters; +} + +std::shared_ptr +QUICHandshake::remote_transport_parameters() +{ + return this->_remote_transport_parameters; +} + int QUICHandshake::state_read_client_hello(int event, Event *data) { @@ -136,6 +232,35 @@ QUICHandshake::state_closed(int event, void *data) return EVENT_CONT; } +void +QUICHandshake::_load_local_transport_parameters() +{ + QUICConfig::scoped_config params; + + // MUSTs + QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(); + + tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, + std::unique_ptr( + new QUICTransportParameterValue(params->initial_max_stream_data(), sizeof(params->initial_max_stream_data())))); + + tp->add(QUICTransportParameterId::INITIAL_MAX_DATA, std::unique_ptr(new QUICTransportParameterValue( + params->initial_max_data(), sizeof(params->initial_max_data())))); + + tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, + std::unique_ptr( + new QUICTransportParameterValue(params->initial_max_stream_id(), sizeof(params->initial_max_stream_id())))); + + tp->add(QUICTransportParameterId::IDLE_TIMEOUT, std::unique_ptr(new QUICTransportParameterValue( + params->no_activity_timeout_in(), sizeof(uint16_t)))); + + tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); + // MAYs + // this->_local_transport_parameters.add(QUICTransportParameterId::TRUNCATE_CONNECTION_ID, {}); + // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); + this->_local_transport_parameters = std::unique_ptr(tp); +} + QUICError QUICHandshake::_process_client_hello() { diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 3a501f0afc7..61baa4a2738 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -43,21 +43,47 @@ * v * state_closed() */ + +class QUICVersionNegotiator; +class SSLNextProtocolSet; + class QUICHandshake : public QUICApplication { public: - QUICHandshake(QUICConnection *qc, QUICCrypto *c); + QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx); + ~QUICHandshake(); + + QUICError start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); + // States int state_read_client_hello(int event, Event *data); int state_read_client_finished(int event, Event *data); int state_address_validation(int event, void *data); int state_complete(int event, void *data); int state_closed(int event, void *data); - bool is_completed(); + + // Getters + QUICCrypto *crypto_module(); + QUICVersion negotiated_version(); void negotiated_application_name(const uint8_t **name, unsigned int *len); + std::shared_ptr local_transport_parameters(); + std::shared_ptr remote_transport_parameters(); + + bool is_version_negotiated(); + bool is_completed(); + + void set_transport_parameters(std::shared_ptr tp); private: - QUICCrypto *_crypto = nullptr; + SSL *_ssl = nullptr; + QUICCrypto *_crypto = nullptr; + std::shared_ptr _local_transport_parameters = nullptr; + std::shared_ptr _remote_transport_parameters = nullptr; + + QUICVersionNegotiator *_version_negotiator = nullptr; + + void _load_local_transport_parameters(); + QUICError _process_client_hello(); QUICError _process_client_finished(); QUICError _process_handshake_complete(); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 6d35e6de7af..dfcb2c66c36 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -44,7 +44,6 @@ class QUICStream : public VConnection public: QUICStream() : VConnection(nullptr) {} ~QUICStream() {} - void init(QUICStreamManager *manager, QUICFrameTransmitter *tx, uint32_t id, uint64_t recv_max_stream_data = 0, uint64_t send_max_stream_data = 0); void start(); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 4ac3b9425a2..0fdb9685335 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -32,14 +32,8 @@ const static char *tag = "quic_stream_manager"; ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); ClassAllocator quicStreamAllocator("quicStreamAllocator"); -int -QUICStreamManager::init(QUICFrameTransmitter *tx, QUICConnection *qc, QUICApplicationMap *app_map) +QUICStreamManager::QUICStreamManager(QUICFrameTransmitter *tx, QUICApplicationMap *app_map) : _tx(tx), _app_map(app_map) { - this->_tx = tx; - this->_qc = qc; - this->_app_map = app_map; - - return 0; } std::vector @@ -50,15 +44,19 @@ QUICStreamManager::interests() } void -QUICStreamManager::init_flow_control_params(const QUICTransportParameters &local_tp, const QUICTransportParameters &remote_tp) +QUICStreamManager::init_flow_control_params(std::shared_ptr local_tp, + std::shared_ptr remote_tp) { + this->_local_tp = local_tp; + this->_remote_tp = remote_tp; + // Connection level - this->_recv_max_data = QUICMaximumData(local_tp.initial_max_data()); - this->_send_max_data = QUICMaximumData(remote_tp.initial_max_data()); + this->_recv_max_data = QUICMaximumData(local_tp->initial_max_data()); + this->_send_max_data = QUICMaximumData(remote_tp->initial_max_data()); // Setup a stream for Handshake QUICStream *stream = this->_find_stream(STREAM_ID_FOR_HANDSHAKE); - stream->init_flow_control_params(local_tp.initial_max_stream_data(), remote_tp.initial_max_stream_data()); + stream->init_flow_control_params(local_tp->initial_max_stream_data(), remote_tp->initial_max_stream_data()); } QUICError @@ -106,7 +104,7 @@ void QUICStreamManager::slide_recv_max_data() { // TODO: How much should this be increased? - this->_recv_max_data += this->_qc->local_transport_parameters().initial_max_data(); + this->_recv_max_data += this->_local_tp->initial_max_data(); this->send_frame(QUICFrameFactory::create_max_data_frame(this->_recv_max_data)); } @@ -221,8 +219,8 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) // XXX rece/send max_stream_data are going to be set by init_flow_control_params() stream->init(this, this->_tx, stream_id); } else { - const QUICTransportParameters &local_tp = this->_qc->local_transport_parameters(); - const QUICTransportParameters &remote_tp = this->_qc->remote_transport_parameters(); + const QUICTransportParameters &local_tp = *this->_local_tp; + const QUICTransportParameters &remote_tp = *this->_remote_tp; // TODO: check local_tp and remote_tp is initialized stream->init(this, this->_tx, stream_id, local_tp.initial_max_stream_data(), remote_tp.initial_max_stream_data()); diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index fbfc6e97ece..17b44b4f349 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -36,8 +36,7 @@ class QUICStreamManager : public QUICFrameHandler { public: QUICStreamManager(){}; - - int init(QUICFrameTransmitter *tx, QUICConnection *qc, QUICApplicationMap *app_map); + QUICStreamManager(QUICFrameTransmitter *tx, QUICApplicationMap *app_map); virtual std::vector interests() override; virtual QUICError handle_frame(std::shared_ptr) override; virtual void send_frame(std::unique_ptr frame); @@ -46,7 +45,8 @@ class QUICStreamManager : public QUICFrameHandler virtual bool is_recv_avail_more_than(uint64_t size); void add_recv_total_offset(uint64_t delta); void slide_recv_max_data(); - void init_flow_control_params(const QUICTransportParameters &local_tp, const QUICTransportParameters &remote_tp); + void init_flow_control_params(std::shared_ptr local_tp, + std::shared_ptr remote_tp); uint64_t recv_max_data() const; uint64_t send_max_data() const; uint64_t recv_total_offset() const; @@ -62,9 +62,10 @@ class QUICStreamManager : public QUICFrameHandler QUICError _handle_frame(std::shared_ptr); QUICError _handle_frame(std::shared_ptr); - QUICApplicationMap *_app_map = nullptr; - QUICFrameTransmitter *_tx = nullptr; - QUICConnection *_qc = nullptr; + QUICFrameTransmitter *_tx = nullptr; + QUICApplicationMap *_app_map = nullptr; + std::shared_ptr _local_tp = nullptr; + std::shared_ptr _remote_tp = nullptr; QUICMaximumData _recv_max_data = {0}; QUICMaximumData _send_max_data = {0}; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 7365084255e..53894c835ac 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -235,10 +235,9 @@ int QUICTransportParametersHandler::add(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char **out, size_t *outlen, X509 *x, size_t chainidx, int *al, void *add_arg) { - QUICConnection *qc = - static_cast(static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_vc_index))); - *out = reinterpret_cast(ats_malloc(TRANSPORT_PARAMETERS_MAXIMUM_SIZE)); - qc->local_transport_parameters().store(const_cast(*out), reinterpret_cast(outlen)); + QUICHandshake *hs = static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_hs_index)); + *out = reinterpret_cast(ats_malloc(TRANSPORT_PARAMETERS_MAXIMUM_SIZE)); + hs->local_transport_parameters()->store(const_cast(*out), reinterpret_cast(outlen)); return 1; } @@ -253,11 +252,8 @@ int QUICTransportParametersHandler::parse(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *in, size_t inlen, X509 *x, size_t chainidx, int *al, void *parse_arg) { - QUICConnection *qc = - static_cast(static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_vc_index))); - QUICTransportParametersInClientHello *tp = new QUICTransportParametersInClientHello(in, inlen); - std::unique_ptr utp = std::unique_ptr(tp); - qc->set_transport_parameters(std::move(utp)); + QUICHandshake *hs = static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_hs_index)); + hs->set_transport_parameters(std::make_shared(in, inlen)); return 1; } diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index a32261f8000..a84aba8807e 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -43,7 +43,6 @@ class QUICTransportParameterId }; explicit operator bool() const { return true; } - bool operator==(const QUICTransportParameterId &x) const { @@ -57,7 +56,6 @@ class QUICTransportParameterId } operator uint16_t() const { return _id; }; - QUICTransportParameterId() : _id(0){}; QUICTransportParameterId(uint16_t id) : _id(id){}; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 83a05004dcc..aabf1d9e5db 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -153,9 +153,7 @@ class QUICConnectionId { public: explicit operator bool() const { return true; } - operator uint64_t() const { return _id; }; - QUICConnectionId() { this->randomize(); }; QUICConnectionId(uint64_t id) : _id(id){}; @@ -174,7 +172,6 @@ class QUICMaximumData { public: QUICMaximumData(uint64_t d) : _data(d) {} - bool operator>(uint64_t r) const { @@ -220,7 +217,6 @@ class QUICMaximumData } operator uint64_t() const { return _data; } - private: uint64_t _data = 0; // in units of 1024 octets }; diff --git a/iocore/net/quic/QUICVersionNegotiator.cc b/iocore/net/quic/QUICVersionNegotiator.cc index d08ee1b8a8b..aa91c0c9847 100644 --- a/iocore/net/quic/QUICVersionNegotiator.cc +++ b/iocore/net/quic/QUICVersionNegotiator.cc @@ -22,9 +22,7 @@ */ #include "QUICVersionNegotiator.h" - -QUICVersionNegotiator::QUICVersionNegotiator(QUICPacketFactory *packet_factory, QUICPacketTransmitter *tx) - : _packet_factory(packet_factory), _tx(tx){}; +#include "QUICTransportParameters.h" QUICVersionNegotiationStatus QUICVersionNegotiator::status() @@ -38,16 +36,25 @@ QUICVersionNegotiator::negotiate(const QUICPacket *initial_packet) if (this->_is_supported(initial_packet->version())) { this->_status = QUICVersionNegotiationStatus::NEGOTIATED; this->_negotiated_version = initial_packet->version(); - } else { - this->_tx->transmit_packet(this->_packet_factory->create_version_negotiation_packet(initial_packet)); } return this->_status; } QUICVersionNegotiationStatus -QUICVersionNegotiator::revalidate(QUICVersion version) +QUICVersionNegotiator::revalidate(const QUICTransportParametersInClientHello *tp) { + QUICVersion version = tp->negotiated_version(); if (this->_negotiated_version == version) { + if (tp->negotiated_version() != tp->initial_version()) { + // FIXME Check initial_version + /* If the initial version is different from the negotiated_version, a + * stateless server MUST check that it would have sent a version + * negotiation packet if it had received a packet with the indicated + * initial_version. (Draft-04 7.3.4. Version Negotiation Validation) + */ + this->_status = QUICVersionNegotiationStatus::FAILED; + this->_negotiated_version = 0; + } this->_status = QUICVersionNegotiationStatus::REVALIDATED; } else { this->_status = QUICVersionNegotiationStatus::FAILED; diff --git a/iocore/net/quic/QUICVersionNegotiator.h b/iocore/net/quic/QUICVersionNegotiator.h index fd376933a26..6b7e075643f 100644 --- a/iocore/net/quic/QUICVersionNegotiator.h +++ b/iocore/net/quic/QUICVersionNegotiator.h @@ -24,7 +24,8 @@ #pragma once #include "QUICTypes.h" -#include "QUICPacketTransmitter.h" +#include "QUICPacket.h" +#include "QUICTransportParameters.h" /** * @brief Abstruct QUIC Application Class @@ -33,16 +34,13 @@ class QUICVersionNegotiator { public: - QUICVersionNegotiator(QUICPacketFactory *packet_factory, QUICPacketTransmitter *tx); QUICVersionNegotiationStatus status(); QUICVersionNegotiationStatus negotiate(const QUICPacket *initial_packet); - QUICVersionNegotiationStatus revalidate(QUICVersion version); + QUICVersionNegotiationStatus revalidate(const QUICTransportParametersInClientHello *tp); QUICVersion negotiated_version(); private: QUICVersion _negotiated_version = 0; - QUICPacketFactory *_packet_factory = nullptr; - QUICPacketTransmitter *_tx = nullptr; QUICVersionNegotiationStatus _status = QUICVersionNegotiationStatus::NOT_NEGOTIATED; bool _is_supported(QUICVersion version); From 996ab43b7632823249fd38ead7d401f0dfc7080b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 25 Aug 2017 12:08:42 +0900 Subject: [PATCH 0061/1313] Fix tests --- iocore/net/quic/Mock.h | 20 +++---- iocore/net/quic/QUICGlobals.cc | 2 +- iocore/net/quic/QUICTransportParameters.cc | 12 +++- iocore/net/quic/test/Makefile.am | 55 ++++++++++++++++--- iocore/net/quic/test/test_QUICCrypto.cc | 4 +- .../quic/test/test_QUICVersionNegotiator.cc | 5 +- 6 files changed, 72 insertions(+), 26 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 842a6c7dd79..4956b557d72 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -95,7 +95,7 @@ class MockNetVConnection : public NetVConnection class MockQUICConnection : public QUICConnection { public: - MockQUICConnection() : QUICConnection() { this->_mutex = new_ProxyMutex(); }; + MockQUICConnection(NetVConnectionContext_t context = NET_VCONNECTION_OUT) : QUICConnection(), _direction(context) { this->_mutex = new_ProxyMutex(); }; void transmit_packet(std::unique_ptr packet) override { @@ -158,21 +158,16 @@ class MockQUICConnection : public QUICConnection return 1280; } - void - set_transport_parameters(std::unique_ptr tp) override - { - } - - const QUICTransportParameters & - local_transport_parameters() override + NetVConnectionContext_t + direction() override { - return dummy_transport_parameters; + return _direction; } - const QUICTransportParameters & - remote_transport_parameters() override + SSLNextProtocolSet * + next_protocol_set() override { - return dummy_transport_parameters; + return nullptr; } void @@ -193,6 +188,7 @@ class MockQUICConnection : public QUICConnection int _frameCount[256] = {0}; QUICTransportParametersInEncryptedExtensions dummy_transport_parameters; + NetVConnectionContext_t _direction; }; class MockQUICPacketTransmitter : public QUICPacketTransmitter diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index cdad89b168e..ca45f67a054 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -23,7 +23,7 @@ #include #include "QUICGlobals.h" -#include "P_QUICNetVConnection.h" +#include "QUICConnection.h" #include "P_SSLNextProtocolSet.h" int QUIC::ssl_quic_qc_index = -1; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 53894c835ac..2acb5c16938 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -178,13 +178,21 @@ QUICTransportParametersInClientHello::_parameters_offset() const QUICVersion QUICTransportParametersInClientHello::negotiated_version() const { - return QUICTypeUtil::read_QUICVersion(this->_buf.get()); + if (this->_buf) { + return QUICTypeUtil::read_QUICVersion(this->_buf.get()); + } else { + return this->_negotiated_version; + } } QUICVersion QUICTransportParametersInClientHello::initial_version() const { - return QUICTypeUtil::read_QUICVersion(this->_buf.get() + sizeof(QUICVersion)); + if (this->_buf) { + return QUICTypeUtil::read_QUICVersion(this->_buf.get() + sizeof(QUICVersion)); + } else { + return this->_initial_version; + } } // diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index b51245a9e14..65f473cfa31 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -125,7 +125,8 @@ test_QUICFrame_SOURCES = \ ../QUICPacket.cc \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ - ../QUICTypes.cc + ../QUICTypes.cc \ + ../../SSLNextProtocolSet.cc test_QUICFrame_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -144,6 +145,8 @@ test_QUICFrameDispatcher_SOURCES = \ main.cc \ test_QUICFrameDispatcher.cc \ ../QUICGlobals.cc \ + ../QUICConfig.cc \ + ../QUICVersionNegotiator.cc \ ../QUICFrameDispatcher.cc \ ../QUICTransportParameters.cc \ ../QUICStreamManager.cc \ @@ -160,11 +163,15 @@ test_QUICFrameDispatcher_SOURCES = \ ../QUICEchoApp.cc \ ../QUICDebugNames.cc \ ../QUICCrypto.cc \ - $(QUICCrypto_impl) + $(QUICCrypto_impl) \ + ../../SSLNextProtocolSet.cc test_QUICFrameDispatcher_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ @LIBTCL@ \ @HWLOC_LIBS@ @@ -208,7 +215,8 @@ test_QUICStream_SOURCES = \ ../QUICFrameDispatcher.cc \ ../QUICStreamManager.cc \ ../QUICApplicationMap.cc \ - ../QUICCongestionController.cc + ../QUICCongestionController.cc \ + ../../SSLNextProtocolSet.cc test_QUICStream_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -234,12 +242,29 @@ test_QUICTransportParameters_SOURCES = \ main.cc \ test_QUICTransportParameters.cc \ ../QUICGlobals.cc \ + ../QUICConfig.cc \ + ../QUICApplication.cc \ + ../QUICApplicationMap.cc \ + ../QUICHandshake.cc \ + ../QUICVersionNegotiator.cc \ + ../QUICCrypto.cc \ + $(QUICCrypto_impl) \ + ../QUICStream.cc \ + ../QUICStreamState.cc \ + ../QUICStreamManager.cc \ + ../QUICPacket.cc \ + ../QUICFrame.cc \ + ../QUICDebugNames.cc \ ../QUICTransportParameters.cc \ - ../QUICTypes.cc + ../QUICTypes.cc \ + ../../SSLNextProtocolSet.cc test_QUICTransportParameters_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a # @@ -264,7 +289,8 @@ test_QUICCrypto_SOURCES = \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICCrypto.h \ - ../QUICGlobals.cc + ../QUICGlobals.cc \ + ../../SSLNextProtocolSet.cc # # test_QUICLossDetector @@ -335,7 +361,8 @@ test_QUICAckFrameCreator_SOURCES = \ ../QUICFrame.cc \ ../QUICPacket.cc \ ../QUICCrypto.cc \ - $(QUICCrypto_impl) + $(QUICCrypto_impl) \ + ../../SSLNextProtocolSet.cc # # test_QUICTypeUtil @@ -349,6 +376,9 @@ test_QUICVersionNegotiator_LDFLAGS = \ test_QUICVersionNegotiator_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ @LIBTCL@ \ @HWLOC_LIBS@ @@ -361,7 +391,18 @@ test_QUICVersionNegotiator_SOURCES = \ ../QUICPacket.cc \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ - ../QUICVersionNegotiator.cc + ../QUICApplication.cc \ + ../QUICApplicationMap.cc \ + ../QUICHandshake.cc \ + ../QUICStream.cc \ + ../QUICStreamState.cc \ + ../QUICStreamManager.cc \ + ../QUICFrame.cc \ + ../QUICDebugNames.cc \ + ../QUICVersionNegotiator.cc \ + ../QUICTransportParameters.cc \ + ../QUICConfig.cc \ + ../../SSLNextProtocolSet.cc include $(top_srcdir)/build/tidy.mk diff --git a/iocore/net/quic/test/test_QUICCrypto.cc b/iocore/net/quic/test/test_QUICCrypto.cc index 58d84e9b30b..e97b83af8fc 100644 --- a/iocore/net/quic/test/test_QUICCrypto.cc +++ b/iocore/net/quic/test/test_QUICCrypto.cc @@ -109,7 +109,7 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - QUICCrypto *client = new QUICCrypto(client_ssl_ctx, new MockNetVConnection(NET_VCONNECTION_OUT)); + QUICCrypto *client = new QUICCrypto(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); // Server SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); @@ -119,7 +119,7 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - QUICCrypto *server = new QUICCrypto(server_ssl_ctx, new MockNetVConnection(NET_VCONNECTION_IN)); + QUICCrypto *server = new QUICCrypto(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); // Client Hello uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index da415505ec7..1191efdf415 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -29,7 +29,7 @@ TEST_CASE("QUICVersionNegotiator_Normal", "[quic]") { QUICPacketFactory packet_factory; - QUICVersionNegotiator vn(&packet_factory, new MockQUICPacketTransmitter()); + QUICVersionNegotiator vn; // Check initial state CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); @@ -41,7 +41,8 @@ TEST_CASE("QUICVersionNegotiator_Normal", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); // Revalidate version - vn.revalidate(QUIC_SUPPORTED_VERSIONS[0]); + QUICTransportParametersInClientHello tp(QUIC_SUPPORTED_VERSIONS[0], QUIC_SUPPORTED_VERSIONS[0]); + vn.revalidate(&tp); CHECK(vn.status() == QUICVersionNegotiationStatus::REVALIDATED); CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); } From 8e231ee8dc6a4ff04e88c4b19156c2c82042e4b1 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 25 Aug 2017 13:52:21 +0900 Subject: [PATCH 0062/1313] Modernize typedef and remove unused aliases --- iocore/net/P_QUICNetVConnection.h | 6 +----- iocore/net/quic/QUICFrame.h | 2 +- iocore/net/quic/QUICTypes.h | 8 ++++---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 785f30bb6ae..bfb96afd4ee 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -99,8 +99,6 @@ typedef enum { // ////////////////////////////////////////////////////////////////// -typedef std::unique_ptr ats_uint8_t_unique_ptr; - struct QUICPacketHandler; class QUICLossDetector; @@ -142,7 +140,7 @@ class SSLNextProtocolSet; **/ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection { - typedef UnixNetVConnection super; ///< Parent type. + using super = UnixNetVConnection; ///< Parent type. public: QUICNetVConnection(); @@ -235,6 +233,4 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICApplication *_create_application(); }; -typedef int (QUICNetVConnection::*QUICNetVConnHandler)(int, void *); - extern ClassAllocator quicNetVCAllocator; diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 79e21b4e149..8feb1750dd3 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -428,7 +428,7 @@ class QUICNewConnectionIdFrame : public QUICFrame QUICConnectionId _connection_id = 0; }; -typedef void (*QUICFrameDeleterFunc)(QUICFrame *p); +using QUICFrameDeleterFunc = void (*)(QUICFrame *p); // // Retransmission Frame diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index aabf1d9e5db..e709ddcdb29 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -48,10 +48,10 @@ using ats_unique_buf = std::unique_ptr; ats_unique_buf ats_unique_malloc(size_t size); -typedef uint64_t QUICPacketNumber; -typedef uint32_t QUICVersion; -typedef uint32_t QUICStreamId; -typedef uint64_t QUICOffset; +using QUICPacketNumber = uint64_t; +using QUICVersion = uint32_t; +using QUICStreamId = uint32_t; +using QUICOffset = uint64_t; // TODO: Update version number // Note: You also need to update tests for VersionNegotiationPacket, if you change the number of versions From 13e1e43c4c2ae8f70878fbbc64fc65188b8981f6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 25 Aug 2017 14:10:34 +0900 Subject: [PATCH 0063/1313] Ran clan-tody with performance-unnecessary-value-param --- iocore/net/quic/QUICHandshake.cc | 4 +++- iocore/net/quic/QUICLossDetector.cc | 2 +- iocore/net/quic/QUICLossDetector.h | 2 +- iocore/net/quic/QUICStream.cc | 6 +++--- iocore/net/quic/QUICStream.h | 6 +++--- iocore/net/quic/QUICStreamManager.cc | 12 ++++++------ iocore/net/quic/QUICStreamManager.h | 12 ++++++------ 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 9e8fdfd685b..521467bb957 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -23,6 +23,8 @@ #include "QUICGlobals.h" #include "QUICHandshake.h" + +#include #include "QUICVersionNegotiator.h" #include "QUICConfig.h" #include "P_SSLNextProtocolSet.h" @@ -126,7 +128,7 @@ QUICHandshake::negotiated_application_name(const uint8_t **name, unsigned int *l void QUICHandshake::set_transport_parameters(std::shared_ptr tp) { - this->_remote_transport_parameters = tp; + this->_remote_transport_parameters = std::move(tp); const QUICTransportParametersInClientHello *tp_in_ch = dynamic_cast(this->_remote_transport_parameters.get()); diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index c406b9b52fd..3687884c89e 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -174,7 +174,7 @@ QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_retran } void -QUICLossDetector::_on_ack_received(std::shared_ptr ack_frame) +QUICLossDetector::_on_ack_received(const std::shared_ptr& ack_frame) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); // If the largest acked is newly acked, update the RTT. diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index df29ac9eb1e..49d0333810b 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -95,7 +95,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _on_packet_sent(QUICPacketNumber packet_number, bool is_retransmittable, bool is_handshake, size_t sent_bytes, std::unique_ptr packet); - void _on_ack_received(std::shared_ptr ack_frame); + void _on_ack_received(const std::shared_ptr& ack_frame); void _on_packet_acked(QUICPacketNumber acked_packet_number); void _update_rtt(uint32_t latest_rtt); void _detect_lost_packets(QUICPacketNumber largest_acked); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index f5594198450..c7e4626f51e 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -237,7 +237,7 @@ QUICStream::_signal_write_event(bool direct) } void -QUICStream::_write_to_read_vio(std::shared_ptr frame) +QUICStream::_write_to_read_vio(const std::shared_ptr& frame) { SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); @@ -297,14 +297,14 @@ QUICStream::recv(std::shared_ptr frame) } QUICError -QUICStream::recv(std::shared_ptr frame) +QUICStream::recv(const std::shared_ptr& frame) { this->_send_max_stream_data += frame->maximum_stream_data(); return QUICError(QUICErrorClass::NONE); } QUICError -QUICStream::recv(std::shared_ptr frame) +QUICStream::recv(const std::shared_ptr& frame) { this->_slide_recv_max_stream_data(); return QUICError(QUICErrorClass::NONE); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index dfcb2c66c36..8d54eda3527 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -60,8 +60,8 @@ class QUICStream : public VConnection void reenable(VIO *vio) override; QUICError recv(std::shared_ptr frame); - QUICError recv(std::shared_ptr frame); - QUICError recv(std::shared_ptr frame); + QUICError recv(const std::shared_ptr& frame); + QUICError recv(const std::shared_ptr& frame); void reset(); @@ -74,7 +74,7 @@ class QUICStream : public VConnection void _send(); - void _write_to_read_vio(std::shared_ptr); + void _write_to_read_vio(const std::shared_ptr&); void _reorder_data(); // NOTE: Those are called update_read_request/update_write_request in Http2Stream // void _read_from_net(uint64_t read_len, bool direct); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 0fdb9685335..d9a8610fd63 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -44,8 +44,8 @@ QUICStreamManager::interests() } void -QUICStreamManager::init_flow_control_params(std::shared_ptr local_tp, - std::shared_ptr remote_tp) +QUICStreamManager::init_flow_control_params(const std::shared_ptr& local_tp, + const std::shared_ptr& remote_tp) { this->_local_tp = local_tp; this->_remote_tp = remote_tp; @@ -94,7 +94,7 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) } QUICError -QUICStreamManager::_handle_frame(std::shared_ptr frame) +QUICStreamManager::_handle_frame(const std::shared_ptr& frame) { this->_send_max_data = frame->maximum_data(); return QUICError(QUICErrorClass::NONE); @@ -109,7 +109,7 @@ QUICStreamManager::slide_recv_max_data() } QUICError -QUICStreamManager::_handle_frame(std::shared_ptr frame) +QUICStreamManager::_handle_frame(const std::shared_ptr& frame) { QUICStream *stream = this->_find_stream(frame->stream_id()); if (stream) { @@ -122,7 +122,7 @@ QUICStreamManager::_handle_frame(std::shared_ptr f } QUICError -QUICStreamManager::_handle_frame(std::shared_ptr frame) +QUICStreamManager::_handle_frame(const std::shared_ptr& frame) { QUICStream *stream = this->_find_stream(frame->stream_id()); if (stream) { @@ -135,7 +135,7 @@ QUICStreamManager::_handle_frame(std::shared_ptr f } QUICError -QUICStreamManager::_handle_frame(std::shared_ptr frame) +QUICStreamManager::_handle_frame(const std::shared_ptr& frame) { QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); QUICApplication *application = this->_app_map->get(frame->stream_id()); diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 17b44b4f349..b01dbdd5b8e 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -45,8 +45,8 @@ class QUICStreamManager : public QUICFrameHandler virtual bool is_recv_avail_more_than(uint64_t size); void add_recv_total_offset(uint64_t delta); void slide_recv_max_data(); - void init_flow_control_params(std::shared_ptr local_tp, - std::shared_ptr remote_tp); + void init_flow_control_params(const std::shared_ptr& local_tp, + const std::shared_ptr& remote_tp); uint64_t recv_max_data() const; uint64_t send_max_data() const; uint64_t recv_total_offset() const; @@ -57,10 +57,10 @@ class QUICStreamManager : public QUICFrameHandler private: QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICStream *_find_stream(QUICStreamId id); - QUICError _handle_frame(std::shared_ptr); - QUICError _handle_frame(std::shared_ptr); - QUICError _handle_frame(std::shared_ptr); - QUICError _handle_frame(std::shared_ptr); + QUICError _handle_frame(const std::shared_ptr&); + QUICError _handle_frame(const std::shared_ptr&); + QUICError _handle_frame(const std::shared_ptr&); + QUICError _handle_frame(const std::shared_ptr&); QUICFrameTransmitter *_tx = nullptr; QUICApplicationMap *_app_map = nullptr; From a281282714390a0367b34786aca2b78b49c52471 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 25 Aug 2017 15:06:39 +0900 Subject: [PATCH 0064/1313] Ran clang-format --- iocore/net/quic/Mock.h | 6 +++- iocore/net/quic/QUICLossDetector.cc | 2 +- iocore/net/quic/QUICLossDetector.h | 2 +- iocore/net/quic/QUICStream.cc | 6 ++-- iocore/net/quic/QUICStream.h | 6 ++-- iocore/net/quic/QUICStreamManager.cc | 12 ++++---- iocore/net/quic/QUICStreamManager.h | 12 ++++---- iocore/net/quic/QUICTypes.h | 1 + lib/records/RecHttp.cc | 46 ++++++++++++++-------------- lib/ts/ink_inet.cc | 2 +- proxy/http/HttpProxyServerMain.cc | 2 +- 11 files changed, 51 insertions(+), 46 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 4956b557d72..dad5f631d7d 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -95,7 +95,10 @@ class MockNetVConnection : public NetVConnection class MockQUICConnection : public QUICConnection { public: - MockQUICConnection(NetVConnectionContext_t context = NET_VCONNECTION_OUT) : QUICConnection(), _direction(context) { this->_mutex = new_ProxyMutex(); }; + MockQUICConnection(NetVConnectionContext_t context = NET_VCONNECTION_OUT) : QUICConnection(), _direction(context) + { + this->_mutex = new_ProxyMutex(); + }; void transmit_packet(std::unique_ptr packet) override { @@ -288,6 +291,7 @@ class MockQUICStreamManager : public QUICStreamManager bool is_recv_avail_more_than(uint64_t /* size */) override { return true; } void send_frame(std::unique_ptr /* frame */) override { return; } + private: int _totalFrameCount = 0; int _frameCount[256] = {0}; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 3687884c89e..bec3c6ff252 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -174,7 +174,7 @@ QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_retran } void -QUICLossDetector::_on_ack_received(const std::shared_ptr& ack_frame) +QUICLossDetector::_on_ack_received(const std::shared_ptr &ack_frame) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); // If the largest acked is newly acked, update the RTT. diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 49d0333810b..44e87a5e1e0 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -95,7 +95,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _on_packet_sent(QUICPacketNumber packet_number, bool is_retransmittable, bool is_handshake, size_t sent_bytes, std::unique_ptr packet); - void _on_ack_received(const std::shared_ptr& ack_frame); + void _on_ack_received(const std::shared_ptr &ack_frame); void _on_packet_acked(QUICPacketNumber acked_packet_number); void _update_rtt(uint32_t latest_rtt); void _detect_lost_packets(QUICPacketNumber largest_acked); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index c7e4626f51e..509471d530b 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -237,7 +237,7 @@ QUICStream::_signal_write_event(bool direct) } void -QUICStream::_write_to_read_vio(const std::shared_ptr& frame) +QUICStream::_write_to_read_vio(const std::shared_ptr &frame) { SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); @@ -297,14 +297,14 @@ QUICStream::recv(std::shared_ptr frame) } QUICError -QUICStream::recv(const std::shared_ptr& frame) +QUICStream::recv(const std::shared_ptr &frame) { this->_send_max_stream_data += frame->maximum_stream_data(); return QUICError(QUICErrorClass::NONE); } QUICError -QUICStream::recv(const std::shared_ptr& frame) +QUICStream::recv(const std::shared_ptr &frame) { this->_slide_recv_max_stream_data(); return QUICError(QUICErrorClass::NONE); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 8d54eda3527..b2110d58469 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -60,8 +60,8 @@ class QUICStream : public VConnection void reenable(VIO *vio) override; QUICError recv(std::shared_ptr frame); - QUICError recv(const std::shared_ptr& frame); - QUICError recv(const std::shared_ptr& frame); + QUICError recv(const std::shared_ptr &frame); + QUICError recv(const std::shared_ptr &frame); void reset(); @@ -74,7 +74,7 @@ class QUICStream : public VConnection void _send(); - void _write_to_read_vio(const std::shared_ptr&); + void _write_to_read_vio(const std::shared_ptr &); void _reorder_data(); // NOTE: Those are called update_read_request/update_write_request in Http2Stream // void _read_from_net(uint64_t read_len, bool direct); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index d9a8610fd63..c2aa2a6019f 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -44,8 +44,8 @@ QUICStreamManager::interests() } void -QUICStreamManager::init_flow_control_params(const std::shared_ptr& local_tp, - const std::shared_ptr& remote_tp) +QUICStreamManager::init_flow_control_params(const std::shared_ptr &local_tp, + const std::shared_ptr &remote_tp) { this->_local_tp = local_tp; this->_remote_tp = remote_tp; @@ -94,7 +94,7 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) } QUICError -QUICStreamManager::_handle_frame(const std::shared_ptr& frame) +QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { this->_send_max_data = frame->maximum_data(); return QUICError(QUICErrorClass::NONE); @@ -109,7 +109,7 @@ QUICStreamManager::slide_recv_max_data() } QUICError -QUICStreamManager::_handle_frame(const std::shared_ptr& frame) +QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { QUICStream *stream = this->_find_stream(frame->stream_id()); if (stream) { @@ -122,7 +122,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr& frame) +QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { QUICStream *stream = this->_find_stream(frame->stream_id()); if (stream) { @@ -135,7 +135,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr& frame) +QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); QUICApplication *application = this->_app_map->get(frame->stream_id()); diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index b01dbdd5b8e..88997b57cd5 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -45,8 +45,8 @@ class QUICStreamManager : public QUICFrameHandler virtual bool is_recv_avail_more_than(uint64_t size); void add_recv_total_offset(uint64_t delta); void slide_recv_max_data(); - void init_flow_control_params(const std::shared_ptr& local_tp, - const std::shared_ptr& remote_tp); + void init_flow_control_params(const std::shared_ptr &local_tp, + const std::shared_ptr &remote_tp); uint64_t recv_max_data() const; uint64_t send_max_data() const; uint64_t recv_total_offset() const; @@ -57,10 +57,10 @@ class QUICStreamManager : public QUICFrameHandler private: QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICStream *_find_stream(QUICStreamId id); - QUICError _handle_frame(const std::shared_ptr&); - QUICError _handle_frame(const std::shared_ptr&); - QUICError _handle_frame(const std::shared_ptr&); - QUICError _handle_frame(const std::shared_ptr&); + QUICError _handle_frame(const std::shared_ptr &); + QUICError _handle_frame(const std::shared_ptr &); + QUICError _handle_frame(const std::shared_ptr &); + QUICError _handle_frame(const std::shared_ptr &); QUICFrameTransmitter *_tx = nullptr; QUICApplicationMap *_app_map = nullptr; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index e709ddcdb29..5c3f9c27e9b 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -217,6 +217,7 @@ class QUICMaximumData } operator uint64_t() const { return _data; } + private: uint64_t _data = 0; // in units of 1024 octets }; diff --git a/lib/records/RecHttp.cc b/lib/records/RecHttp.cc index b2b3f3a4264..225db9402d1 100644 --- a/lib/records/RecHttp.cc +++ b/lib/records/RecHttp.cc @@ -36,35 +36,35 @@ SessionProtocolNameRegistry globalSessionProtocolNameRegistry; These are also used for NPN setup. */ -const char *const TS_ALPN_PROTOCOL_HTTP_0_9 = IP_PROTO_TAG_HTTP_0_9.ptr(); -const char *const TS_ALPN_PROTOCOL_HTTP_1_0 = IP_PROTO_TAG_HTTP_1_0.ptr(); -const char *const TS_ALPN_PROTOCOL_HTTP_1_1 = IP_PROTO_TAG_HTTP_1_1.ptr(); -const char *const TS_ALPN_PROTOCOL_HTTP_2_0 = IP_PROTO_TAG_HTTP_2_0.ptr(); +const char *const TS_ALPN_PROTOCOL_HTTP_0_9 = IP_PROTO_TAG_HTTP_0_9.ptr(); +const char *const TS_ALPN_PROTOCOL_HTTP_1_0 = IP_PROTO_TAG_HTTP_1_0.ptr(); +const char *const TS_ALPN_PROTOCOL_HTTP_1_1 = IP_PROTO_TAG_HTTP_1_1.ptr(); +const char *const TS_ALPN_PROTOCOL_HTTP_2_0 = IP_PROTO_TAG_HTTP_2_0.ptr(); const char *const TS_ALPN_PROTOCOL_HTTP_QUIC = IP_PROTO_TAG_HTTP_QUIC.ptr(); const char *const TS_ALPN_PROTOCOL_GROUP_HTTP = "http"; const char *const TS_ALPN_PROTOCOL_GROUP_HTTP2 = "http2"; -const char *const TS_PROTO_TAG_HTTP_1_0 = TS_ALPN_PROTOCOL_HTTP_1_0; -const char *const TS_PROTO_TAG_HTTP_1_1 = TS_ALPN_PROTOCOL_HTTP_1_1; -const char *const TS_PROTO_TAG_HTTP_2_0 = TS_ALPN_PROTOCOL_HTTP_2_0; +const char *const TS_PROTO_TAG_HTTP_1_0 = TS_ALPN_PROTOCOL_HTTP_1_0; +const char *const TS_PROTO_TAG_HTTP_1_1 = TS_ALPN_PROTOCOL_HTTP_1_1; +const char *const TS_PROTO_TAG_HTTP_2_0 = TS_ALPN_PROTOCOL_HTTP_2_0; const char *const TS_PROTO_TAG_HTTP_QUIC = TS_ALPN_PROTOCOL_HTTP_QUIC; -const char *const TS_PROTO_TAG_TLS_1_3 = IP_PROTO_TAG_TLS_1_3.ptr(); -const char *const TS_PROTO_TAG_TLS_1_2 = IP_PROTO_TAG_TLS_1_2.ptr(); -const char *const TS_PROTO_TAG_TLS_1_1 = IP_PROTO_TAG_TLS_1_1.ptr(); -const char *const TS_PROTO_TAG_TLS_1_0 = IP_PROTO_TAG_TLS_1_0.ptr(); -const char *const TS_PROTO_TAG_TCP = IP_PROTO_TAG_TCP.ptr(); -const char *const TS_PROTO_TAG_UDP = IP_PROTO_TAG_UDP.ptr(); -const char *const TS_PROTO_TAG_IPV4 = IP_PROTO_TAG_IPV4.ptr(); -const char *const TS_PROTO_TAG_IPV6 = IP_PROTO_TAG_IPV6.ptr(); +const char *const TS_PROTO_TAG_TLS_1_3 = IP_PROTO_TAG_TLS_1_3.ptr(); +const char *const TS_PROTO_TAG_TLS_1_2 = IP_PROTO_TAG_TLS_1_2.ptr(); +const char *const TS_PROTO_TAG_TLS_1_1 = IP_PROTO_TAG_TLS_1_1.ptr(); +const char *const TS_PROTO_TAG_TLS_1_0 = IP_PROTO_TAG_TLS_1_0.ptr(); +const char *const TS_PROTO_TAG_TCP = IP_PROTO_TAG_TCP.ptr(); +const char *const TS_PROTO_TAG_UDP = IP_PROTO_TAG_UDP.ptr(); +const char *const TS_PROTO_TAG_IPV4 = IP_PROTO_TAG_IPV4.ptr(); +const char *const TS_PROTO_TAG_IPV6 = IP_PROTO_TAG_IPV6.ptr(); InkHashTable *TSProtoTags; // Precomputed indices for ease of use. -int TS_ALPN_PROTOCOL_INDEX_HTTP_0_9 = SessionProtocolNameRegistry::INVALID; -int TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = SessionProtocolNameRegistry::INVALID; -int TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = SessionProtocolNameRegistry::INVALID; -int TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = SessionProtocolNameRegistry::INVALID; +int TS_ALPN_PROTOCOL_INDEX_HTTP_0_9 = SessionProtocolNameRegistry::INVALID; +int TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = SessionProtocolNameRegistry::INVALID; +int TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = SessionProtocolNameRegistry::INVALID; +int TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = SessionProtocolNameRegistry::INVALID; int TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC = SessionProtocolNameRegistry::INVALID; // Predefined protocol sets for ease of use. @@ -652,10 +652,10 @@ void ts_session_protocol_well_known_name_indices_init() { // register all the well known protocols and get the indices set. - TS_ALPN_PROTOCOL_INDEX_HTTP_0_9 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_0_9); - TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_1_0); - TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_1_1); - TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_2_0); + TS_ALPN_PROTOCOL_INDEX_HTTP_0_9 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_0_9); + TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_1_0); + TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_1_1); + TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_2_0); TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_QUIC); // Now do the predefined protocol sets. diff --git a/lib/ts/ink_inet.cc b/lib/ts/ink_inet.cc index 8247cb420c3..39b66c79fc8 100644 --- a/lib/ts/ink_inet.cc +++ b/lib/ts/ink_inet.cc @@ -43,7 +43,7 @@ const ts::StringView IP_PROTO_TAG_TLS_1_3("tls/1.3", ts::StringView::literal); const ts::StringView IP_PROTO_TAG_HTTP_0_9("http/0.9", ts::StringView::literal); const ts::StringView IP_PROTO_TAG_HTTP_1_0("http/1.0", ts::StringView::literal); const ts::StringView IP_PROTO_TAG_HTTP_1_1("http/1.1", ts::StringView::literal); -const ts::StringView IP_PROTO_TAG_HTTP_2_0("h2", ts::StringView::literal); // HTTP/2 over TLS +const ts::StringView IP_PROTO_TAG_HTTP_2_0("h2", ts::StringView::literal); // HTTP/2 over TLS const ts::StringView IP_PROTO_TAG_HTTP_QUIC("hq-05", ts::StringView::literal); // HTTP over QUIC uint32_t diff --git a/proxy/http/HttpProxyServerMain.cc b/proxy/http/HttpProxyServerMain.cc index 1ee1b0f7313..acde3396155 100644 --- a/proxy/http/HttpProxyServerMain.cc +++ b/proxy/http/HttpProxyServerMain.cc @@ -227,7 +227,7 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned if (port.m_session_protocol_preference.contains(TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC)) { HQSessionAccept *hq = new HQSessionAccept(accept_opt); // FIXME hq should be registered to QUICNextProtocolAccept like SSL - acceptor._accept = hq; + acceptor._accept = hq; } #endif } else { From 30f32d1735719592382e358f4215b8dce785fb51 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 25 Aug 2017 15:08:54 +0900 Subject: [PATCH 0065/1313] Use constant expressions --- iocore/net/QUICNetVConnection.cc | 6 +- iocore/net/quic/QUICAckFrameCreator.h | 2 +- iocore/net/quic/QUICApplication.cc | 2 +- iocore/net/quic/QUICCongestionController.cc | 2 +- iocore/net/quic/QUICCrypto_boringssl.cc | 2 +- iocore/net/quic/QUICCrypto_openssl.cc | 2 +- iocore/net/quic/QUICEchoApp.cc | 2 +- iocore/net/quic/QUICFrameDispatcher.cc | 2 +- iocore/net/quic/QUICHandshake.cc | 6 +- iocore/net/quic/QUICPacket.cc | 12 +-- iocore/net/quic/QUICStream.cc | 6 +- iocore/net/quic/QUICStreamManager.cc | 2 +- iocore/net/quic/QUICTransportParameters.cc | 2 +- iocore/net/quic/test/test_QUICCrypto.cc | 100 ++++++++++---------- 14 files changed, 74 insertions(+), 74 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 75b16f913d3..99e63da177a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -46,9 +46,9 @@ #define DebugQUICCon(fmt, ...) \ Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) -const static uint32_t MINIMUM_MTU = 1280; -const static uint32_t MAX_PACKET_OVERHEAD = 25; // Max long header len(17) + FNV-1a hash len(8) -const static uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; +static constexpr uint32_t MINIMUM_MTU = 1280; +static constexpr uint32_t MAX_PACKET_OVERHEAD = 25; // Max long header len(17) + FNV-1a hash len(8) +static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 8b940a4431c..7251747a375 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -30,7 +30,7 @@ class QUICAckFrameCreator { public: - static const int MAXIMUM_PACKET_COUNT = 256; + static constexpr int MAXIMUM_PACKET_COUNT = 256; QUICAckFrameCreator(){}; /* diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 30c2f3053a3..3bd0d20152e 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -26,7 +26,7 @@ #include "ts/MemView.h" #include "QUICStream.h" -const static char *tag = "quic_app"; +static constexpr char tag[] = "quic_app"; // // QUICStreamIO diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 6da901c537a..19939fe5bdf 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -23,7 +23,7 @@ #include -const static char *tag = "quic_congestion_controller"; +static constexpr char tag[] = "quic_congestion_controller"; std::vector QUICCongestionController::interests() diff --git a/iocore/net/quic/QUICCrypto_boringssl.cc b/iocore/net/quic/QUICCrypto_boringssl.cc index bd4a0c02d04..6b50b6b6414 100644 --- a/iocore/net/quic/QUICCrypto_boringssl.cc +++ b/iocore/net/quic/QUICCrypto_boringssl.cc @@ -29,7 +29,7 @@ #include #include -const static char tag[] = "quic_crypto"; +static constexpr char tag[] = "quic_crypto"; const EVP_AEAD * QUICCrypto::_get_evp_aead(const SSL_CIPHER *cipher) const diff --git a/iocore/net/quic/QUICCrypto_openssl.cc b/iocore/net/quic/QUICCrypto_openssl.cc index d0a6f2d3fc8..511db00ecc6 100644 --- a/iocore/net/quic/QUICCrypto_openssl.cc +++ b/iocore/net/quic/QUICCrypto_openssl.cc @@ -28,7 +28,7 @@ #include #include -const static char tag[] = "quic_crypto"; +static constexpr char tag[] = "quic_crypto"; const EVP_CIPHER * QUICCrypto::_get_evp_aead(const SSL_CIPHER *cipher) const diff --git a/iocore/net/quic/QUICEchoApp.cc b/iocore/net/quic/QUICEchoApp.cc index 936995afb85..5fcc4c6fe10 100644 --- a/iocore/net/quic/QUICEchoApp.cc +++ b/iocore/net/quic/QUICEchoApp.cc @@ -26,7 +26,7 @@ #include "P_Net.h" #include "QUICDebugNames.h" -const static char *tag = "quic_echo_app"; +static constexpr char tag[] = "quic_echo_app"; QUICEchoApp::QUICEchoApp(QUICConnection *qc) : QUICApplication(qc) { diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 3ac3f27af49..eff5890600f 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -28,7 +28,7 @@ #include "QUICLossDetector.h" #include "QUICEvents.h" -const static char *tag = "quic_frame_handler"; +static constexpr char tag[] = "quic_frame_handler"; // // Frame Dispatcher diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 521467bb957..18beda7cb58 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -49,10 +49,10 @@ } \ } -const static char *tag = "quic_handshake"; -const static int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; +static constexpr char tag[] = "quic_handshake"; +static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size -const static int MAX_HANDSHAKE_MSG_LEN = 65527; +static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527; QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICApplication(qc) { diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 278daaedbf5..db503844898 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -24,12 +24,12 @@ #include #include "QUICPacket.h" -static const int OFFSET_CONNECTION_ID = 1; -static const int OFFSET_PACKET_NUMBER = 9; -static const int OFFSET_VERSION = 13; -static const int OFFSET_PAYLOAD = 17; -static const int LONGHEADER_LENGTH = 17; -static const int FNV1A_HASH_LEN = 8; +static constexpr int OFFSET_CONNECTION_ID = 1; +static constexpr int OFFSET_PACKET_NUMBER = 9; +static constexpr int OFFSET_VERSION = 13; +static constexpr int OFFSET_PAYLOAD = 17; +static constexpr int LONGHEADER_LENGTH = 17; +static constexpr int FNV1A_HASH_LEN = 8; const uint8_t * QUICPacketHeader::buf() diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 509471d530b..e77375f9b3e 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -28,10 +28,10 @@ #include "QUICDebugNames.h" #include "QUICConfig.h" -const static char *tag = "quic_stream"; +static constexpr char tag[] = "quic_stream"; -constexpr uint64_t MAX_DATA_HEADSPACE = 10240; // in uints of octets -constexpr uint64_t MAX_STREAM_DATA_HEADSPACE = 1024; +static constexpr uint64_t MAX_DATA_HEADSPACE = 10240; // in uints of octets +static constexpr uint64_t MAX_STREAM_DATA_HEADSPACE = 1024; void QUICStream::init(QUICStreamManager *manager, QUICFrameTransmitter *tx, QUICStreamId id, uint64_t recv_max_stream_data, diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index c2aa2a6019f..c1aed64caa0 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -27,7 +27,7 @@ #include "QUICTransportParameters.h" #include "QUICConnection.h" -const static char *tag = "quic_stream_manager"; +static constexpr char tag[] = "quic_stream_manager"; ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); ClassAllocator quicStreamAllocator("quicStreamAllocator"); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 2acb5c16938..3bbe21795c2 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -27,7 +27,7 @@ #include "QUICConnection.h" #include "../P_QUICNetVConnection.h" -const static int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; +static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; // // QUICTransportParameterValue diff --git a/iocore/net/quic/test/test_QUICCrypto.cc b/iocore/net/quic/test/test_QUICCrypto.cc index e97b83af8fc..2d2f471822b 100644 --- a/iocore/net/quic/test/test_QUICCrypto.cc +++ b/iocore/net/quic/test/test_QUICCrypto.cc @@ -36,56 +36,56 @@ #include "Mock.h" #include "QUICCrypto.h" -const static uint32_t MAX_HANDSHAKE_MSG_LEN = 2048; - -static const char server_crt[] = "-----BEGIN CERTIFICATE-----\n" - "MIIDRjCCAi4CCQDoLSBwQxmcJTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJK\n" - "UDEOMAwGA1UECBMFVG9reW8xDzANBgNVBAcTBk1pbmF0bzEhMB8GA1UEChMYSW50\n" - "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTcw\n" - "MTE4MDEyMzA3WhcNMjcwMTE2MDEyMzA3WjBlMQswCQYDVQQGEwJKUDEOMAwGA1UE\n" - "CBMFVG9reW8xDzANBgNVBAcTBk1pbmF0bzEhMB8GA1UEChMYSW50ZXJuZXQgV2lk\n" - "Z2l0cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB\n" - "AQUAA4IBDwAwggEKAoIBAQC70j62KOWkuqNsDhl+7uqKFS6TMcJYLdYrH1YInwlY\n" - "htOMSMWx2hPSYYBKzVQpLvhe2LPbhLwcVJdq4aqQNjNpxrpxW/YIY5zxCRVgQsgf\n" - "KXiKgUR0G+F3MQHsm1YIqxQU2OeJldIZUBM2YMDp8h1CXTAvGaAZaXsqO9UvR2Zw\n" - "JZJ+GElYNlNwhdStqIM8v1JNFjfO3gWkVqTv+QM4fmpror2pp8CaDrueg4PrSY3Y\n" - "D/WG75rkmlrW26t0Q8fjkn+s/UiQ3V/IkP1+MfrJWH6RL2DGjBv2KfNAik42xWUi\n" - "KXzaNcDFN4hjqVG59O9bPnUDn1wPypY/TXB4iqSAlxupAgMBAAEwDQYJKoZIhvcN\n" - "AQELBQADggEBAKLc+P5YfusNYIkX3YE+gHBVpo95xnoVUcsGr/h1zanCkmsyKkNU\n" - "e2w9xsVnRLgpRfwrnwiaNP/k6cPYt5ePPCJjUfkO7Ql7DCcjLgEp8lrvxMmRIdSg\n" - "LPq+NdityxXYhfaZdGdXjnLLiq3zYL/8aYjjZ8YAZTuu6pBgfGvjcqYLV1ohimrP\n" - "8BW0BbnvedqTyL7tdKjdiWnHE5ObrxnphL2evoStskBr5CLYR4vX7+qp0oVSz2Ol\n" - "nBMV3wXyhHBY1tuT1SK7ajC/ZHrciZosACRV5PC6nKXi3shWOxt76SZV3HcMmFwX\n" - "NQYYTBOlb5U080adFSmP5/6NRzrKwZ3mD2s=\n" - "-----END CERTIFICATE-----\n"; - -static const char server_key[] = "-----BEGIN RSA PRIVATE KEY-----\n" - "MIIEpAIBAAKCAQEAu9I+tijlpLqjbA4Zfu7qihUukzHCWC3WKx9WCJ8JWIbTjEjF\n" - "sdoT0mGASs1UKS74Xtiz24S8HFSXauGqkDYzaca6cVv2CGOc8QkVYELIHyl4ioFE\n" - "dBvhdzEB7JtWCKsUFNjniZXSGVATNmDA6fIdQl0wLxmgGWl7KjvVL0dmcCWSfhhJ\n" - "WDZTcIXUraiDPL9STRY3zt4FpFak7/kDOH5qa6K9qafAmg67noOD60mN2A/1hu+a\n" - "5Jpa1turdEPH45J/rP1IkN1fyJD9fjH6yVh+kS9gxowb9inzQIpONsVlIil82jXA\n" - "xTeIY6lRufTvWz51A59cD8qWP01weIqkgJcbqQIDAQABAoIBADI3ShEF6jAavmq7\n" - "clGfqxF0DFnKaf2Nc79fx27SpnsGwTS2mDSu67HJ47UcJK5GIp2pLp04ZdrlOv6W\n" - "izW3aBOV0G9SePtRNrqzBQYRlNPQEKxnV1f7xFJLxgnulhgHNX1FaNI+PkgKQri9\n" - "MZba5rvBkoplPYrNyuJF0P+tBVRiISWDY00PlZ57pQDyOvXzUckAkxmjNzo+86ld\n" - "/NyO+nR45vVKSeIBT5tT67D8wRisZgO/7QKP5sbKYwa7AR4sTEYFwBaFi4Mr6v1T\n" - "kp0KxOFBI+MioFwyK7ZjkoKClrY/K0IPsKfn2vmi6jLpfkA+qCl1JsVhrfVO3KJc\n" - "PXXF4QECgYEA9339GQS2AWSuA/9ZgHFqTTOEEHujCkh9D4mKO4LRi5hKPN9NQKUU\n" - "KgaBXWTbr8FwOTXw6HMl0SaIOdc6VxdzViNvPCpu2Wn8hyTC5Mjs/BtXkXNcBQqs\n" - "tPm0JxgC6fpQAb+gU+zZ+QQNlUWH/CEiQFxxGNzBn9E3Xq2j0StdhPECgYEAwkci\n" - "GiQuM4KMDdwbs4RDlEZyvXxWwgHKPoXv/Uq7HXtuT1FGb/+Rf3BGimMf2Qqmppp8\n" - "MAZ+xk+eXhtqKZHsV2ifhUfuVZ6NPhT2WRyn6MozuHh3MK4l2KtOhxulcoX/2sDk\n" - "dLYclxhXZFuXvbLz2KpgMmPMGyzEQNHQaoTkojkCgYEAxb/wVGY0OybD+EO2su9s\n" - "PaVU94qielvzOU/vmJ9taTnUz5Co/Gcqlm2+Pe6RrnxEfCICjOk8pUJBhN3ZKq99\n" - "I62Keqt5CNUrxpvz8bQtzz7VmE1xkEG4P55pePcxlNzBwrPnmkdc3yCC7euxvR6I\n" - "bJ6wa2owd89Gi6r4gvBAeDECgYBpdiPU/P73h05v16RR9uKYgwWWRwDxn/chqaN1\n" - "ZDPe9ToUZJJQCfP5sgEY7mZDc7yzg/kWOPBoxp+5hjhDCKu7Z1fxCfMfF0qlAMwZ\n" - "46xieiFJaluJWX/B9nxSa3eMi6EwJrXdhV5Pxy7pk67zk0k7vIEr2XDa75o5dawl\n" - "pq5WQQKBgQC9xsRLtQjnDEdNEgCicTupa7BXmvc9tRb1mA5SeqjwzYuulrTyvn5Y\n" - "QOXYdz8aeZ+ZQ/cDeGA3jA6lekWnExkp9enHeqadyDWM7rvXi800E6gB/vrO7r/c\n" - "iE+fpXud6cwNw2XYsk6RBSQ8qhJoCpa+koPXfSJOZ9Y89NMbtq0w3Q==\n" - "-----END RSA PRIVATE KEY-----\n"; +static constexpr uint32_t MAX_HANDSHAKE_MSG_LEN = 2048; + +static constexpr char server_crt[] = "-----BEGIN CERTIFICATE-----\n" + "MIIDRjCCAi4CCQDoLSBwQxmcJTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJK\n" + "UDEOMAwGA1UECBMFVG9reW8xDzANBgNVBAcTBk1pbmF0bzEhMB8GA1UEChMYSW50\n" + "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTcw\n" + "MTE4MDEyMzA3WhcNMjcwMTE2MDEyMzA3WjBlMQswCQYDVQQGEwJKUDEOMAwGA1UE\n" + "CBMFVG9reW8xDzANBgNVBAcTBk1pbmF0bzEhMB8GA1UEChMYSW50ZXJuZXQgV2lk\n" + "Z2l0cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB\n" + "AQUAA4IBDwAwggEKAoIBAQC70j62KOWkuqNsDhl+7uqKFS6TMcJYLdYrH1YInwlY\n" + "htOMSMWx2hPSYYBKzVQpLvhe2LPbhLwcVJdq4aqQNjNpxrpxW/YIY5zxCRVgQsgf\n" + "KXiKgUR0G+F3MQHsm1YIqxQU2OeJldIZUBM2YMDp8h1CXTAvGaAZaXsqO9UvR2Zw\n" + "JZJ+GElYNlNwhdStqIM8v1JNFjfO3gWkVqTv+QM4fmpror2pp8CaDrueg4PrSY3Y\n" + "D/WG75rkmlrW26t0Q8fjkn+s/UiQ3V/IkP1+MfrJWH6RL2DGjBv2KfNAik42xWUi\n" + "KXzaNcDFN4hjqVG59O9bPnUDn1wPypY/TXB4iqSAlxupAgMBAAEwDQYJKoZIhvcN\n" + "AQELBQADggEBAKLc+P5YfusNYIkX3YE+gHBVpo95xnoVUcsGr/h1zanCkmsyKkNU\n" + "e2w9xsVnRLgpRfwrnwiaNP/k6cPYt5ePPCJjUfkO7Ql7DCcjLgEp8lrvxMmRIdSg\n" + "LPq+NdityxXYhfaZdGdXjnLLiq3zYL/8aYjjZ8YAZTuu6pBgfGvjcqYLV1ohimrP\n" + "8BW0BbnvedqTyL7tdKjdiWnHE5ObrxnphL2evoStskBr5CLYR4vX7+qp0oVSz2Ol\n" + "nBMV3wXyhHBY1tuT1SK7ajC/ZHrciZosACRV5PC6nKXi3shWOxt76SZV3HcMmFwX\n" + "NQYYTBOlb5U080adFSmP5/6NRzrKwZ3mD2s=\n" + "-----END CERTIFICATE-----\n"; + +static constexpr char server_key[] = "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEpAIBAAKCAQEAu9I+tijlpLqjbA4Zfu7qihUukzHCWC3WKx9WCJ8JWIbTjEjF\n" + "sdoT0mGASs1UKS74Xtiz24S8HFSXauGqkDYzaca6cVv2CGOc8QkVYELIHyl4ioFE\n" + "dBvhdzEB7JtWCKsUFNjniZXSGVATNmDA6fIdQl0wLxmgGWl7KjvVL0dmcCWSfhhJ\n" + "WDZTcIXUraiDPL9STRY3zt4FpFak7/kDOH5qa6K9qafAmg67noOD60mN2A/1hu+a\n" + "5Jpa1turdEPH45J/rP1IkN1fyJD9fjH6yVh+kS9gxowb9inzQIpONsVlIil82jXA\n" + "xTeIY6lRufTvWz51A59cD8qWP01weIqkgJcbqQIDAQABAoIBADI3ShEF6jAavmq7\n" + "clGfqxF0DFnKaf2Nc79fx27SpnsGwTS2mDSu67HJ47UcJK5GIp2pLp04ZdrlOv6W\n" + "izW3aBOV0G9SePtRNrqzBQYRlNPQEKxnV1f7xFJLxgnulhgHNX1FaNI+PkgKQri9\n" + "MZba5rvBkoplPYrNyuJF0P+tBVRiISWDY00PlZ57pQDyOvXzUckAkxmjNzo+86ld\n" + "/NyO+nR45vVKSeIBT5tT67D8wRisZgO/7QKP5sbKYwa7AR4sTEYFwBaFi4Mr6v1T\n" + "kp0KxOFBI+MioFwyK7ZjkoKClrY/K0IPsKfn2vmi6jLpfkA+qCl1JsVhrfVO3KJc\n" + "PXXF4QECgYEA9339GQS2AWSuA/9ZgHFqTTOEEHujCkh9D4mKO4LRi5hKPN9NQKUU\n" + "KgaBXWTbr8FwOTXw6HMl0SaIOdc6VxdzViNvPCpu2Wn8hyTC5Mjs/BtXkXNcBQqs\n" + "tPm0JxgC6fpQAb+gU+zZ+QQNlUWH/CEiQFxxGNzBn9E3Xq2j0StdhPECgYEAwkci\n" + "GiQuM4KMDdwbs4RDlEZyvXxWwgHKPoXv/Uq7HXtuT1FGb/+Rf3BGimMf2Qqmppp8\n" + "MAZ+xk+eXhtqKZHsV2ifhUfuVZ6NPhT2WRyn6MozuHh3MK4l2KtOhxulcoX/2sDk\n" + "dLYclxhXZFuXvbLz2KpgMmPMGyzEQNHQaoTkojkCgYEAxb/wVGY0OybD+EO2su9s\n" + "PaVU94qielvzOU/vmJ9taTnUz5Co/Gcqlm2+Pe6RrnxEfCICjOk8pUJBhN3ZKq99\n" + "I62Keqt5CNUrxpvz8bQtzz7VmE1xkEG4P55pePcxlNzBwrPnmkdc3yCC7euxvR6I\n" + "bJ6wa2owd89Gi6r4gvBAeDECgYBpdiPU/P73h05v16RR9uKYgwWWRwDxn/chqaN1\n" + "ZDPe9ToUZJJQCfP5sgEY7mZDc7yzg/kWOPBoxp+5hjhDCKu7Z1fxCfMfF0qlAMwZ\n" + "46xieiFJaluJWX/B9nxSa3eMi6EwJrXdhV5Pxy7pk67zk0k7vIEr2XDa75o5dawl\n" + "pq5WQQKBgQC9xsRLtQjnDEdNEgCicTupa7BXmvc9tRb1mA5SeqjwzYuulrTyvn5Y\n" + "QOXYdz8aeZ+ZQ/cDeGA3jA6lekWnExkp9enHeqadyDWM7rvXi800E6gB/vrO7r/c\n" + "iE+fpXud6cwNw2XYsk6RBSQ8qhJoCpa+koPXfSJOZ9Y89NMbtq0w3Q==\n" + "-----END RSA PRIVATE KEY-----\n"; void print_hex(const uint8_t *v, size_t len) From 0472c9dccae114c68e7642a7390eaceabec46cc1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 25 Aug 2017 17:32:06 +0900 Subject: [PATCH 0066/1313] Fix transport parameter parser --- iocore/net/quic/QUICTransportParameters.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 3bbe21795c2..97e04270693 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -72,16 +72,19 @@ QUICTransportParameters::get(QUICTransportParameterId tpid, uint16_t &len) const uint16_t n = (p[0] << 8) + p[1]; p += 2; - for (; n > 0; --n) { + while (n > 0) { uint16_t _id = (p[0] << 8) + p[1]; p += 2; + n -= 2; uint16_t _value_len = (p[0] << 8) + p[1]; p += 2; + n -= 2; if (tpid == _id) { len = _value_len; return p; } p += _value_len; + n -= _value_len; } } else { auto p = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); From 6f1f8ae58ec06c64b674be0e84025c122ac2847e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 25 Aug 2017 17:32:34 +0900 Subject: [PATCH 0067/1313] Print transport parameters --- iocore/net/quic/QUICDebugNames.cc | 21 +++++++++++++++++ iocore/net/quic/QUICDebugNames.h | 2 ++ iocore/net/quic/QUICTransportParameters.cc | 27 ++++++++++++++++++++++ iocore/net/quic/QUICTransportParameters.h | 6 ++--- 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index b3c738cacac..dae5885cf51 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -156,3 +156,24 @@ QUICDebugNames::vc_event(int event) return "UNKNOWN"; } } + +const char * +QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) +{ + switch (id) { + case QUICTransportParameterId::INITIAL_MAX_STREAM_DATA: + return "INITIAL_MAX_STREAM_DATA"; + case QUICTransportParameterId::INITIAL_MAX_DATA: + return "INITIAL_MAX_DATA"; + case QUICTransportParameterId::INITIAL_MAX_STREAM_ID: + return "INITIAL_MAX_STREAM_ID"; + case QUICTransportParameterId::IDLE_TIMEOUT: + return "IDLE_TIMEOUT"; + case QUICTransportParameterId::TRUNCATE_CONNECTION_ID: + return "TRUNCATE_CONNECTION_ID"; + case QUICTransportParameterId::MAX_PACKET_SIZE: + return "MAX_PACKET_SIZE"; + default: + return "UNKNOWN"; + } +} diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index fabd07607fe..20fcc717313 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -24,6 +24,7 @@ #pragma once #include "QUICTypes.h" +#include "QUICTransportParameters.h" class QUICDebugNames { @@ -32,6 +33,7 @@ class QUICDebugNames static const char *frame_type(QUICFrameType type); static const char *error_class(QUICErrorClass cls); static const char *error_code(QUICErrorCode code); + static const char *transport_parameter_id(QUICTransportParameterId id); // TODO: move to somewhere static const char *vc_event(int event); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 97e04270693..c3ce09c125d 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -22,9 +22,11 @@ */ #include +#include "ts/Diags.h" #include "QUICGlobals.h" #include "QUICTransportParameters.h" #include "QUICConnection.h" +#include "QUICDebugNames.h" #include "../P_QUICNetVConnection.h" static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; @@ -160,6 +162,31 @@ QUICTransportParameters::store(uint8_t *buf, uint16_t *len) const // QUICTransportParametersInClientHello // +QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const uint8_t *buf, size_t len) : QUICTransportParameters(buf, len) +{ + // Print all parameters + const uint8_t *p = this->_buf.get() + this->_parameters_offset(); + uint16_t n = (p[0] << 8) + p[1]; + p += 2; + while (n > 0) { + uint16_t _id = (p[0] << 8) + p[1]; + p += 2; + n -= 2; + uint16_t _value_len = (p[0] << 8) + p[1]; + p += 2; + n -= 2; + if (_value_len == 0) { + Debug("quic_handsahke", "%s: (no value)", QUICDebugNames::transport_parameter_id(_id)); + } else if (_value_len <= 8) { + Debug("quic_handsahke", "%s: 0x%" PRIx64 " (%" PRIu64 ")", QUICDebugNames::transport_parameter_id(_id), QUICTypeUtil::read_nbytes_as_uint(p, _value_len), QUICTypeUtil::read_nbytes_as_uint(p, _value_len)); + } else { + Debug("quic_handsahke", "%s: (long data)", QUICDebugNames::transport_parameter_id(_id)); + } + p += _value_len; + n -= _value_len; + } +} + void QUICTransportParametersInClientHello::_store(uint8_t *buf, uint16_t *len) const { diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index a84aba8807e..c5239f26e66 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -99,9 +99,9 @@ class QUICTransportParameters class QUICTransportParametersInClientHello : public QUICTransportParameters { public: - QUICTransportParametersInClientHello(QUICVersion negotiated_version, QUICVersion initial_version) - : QUICTransportParameters(), _negotiated_version(negotiated_version), _initial_version(initial_version){}; - QUICTransportParametersInClientHello(const uint8_t *buf, size_t len) : QUICTransportParameters(buf, len){}; + QUICTransportParametersInClientHello(QUICVersion negotiated_version, QUICVersion initial_version) : QUICTransportParameters(), _negotiated_version(negotiated_version), _initial_version(initial_version) +{}; + QUICTransportParametersInClientHello(const uint8_t *buf, size_t len); QUICVersion negotiated_version() const; QUICVersion initial_version() const; From b9570de8dabe46f8a0f7b8fa8eae5e219d1827a2 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 28 Aug 2017 15:49:24 +0900 Subject: [PATCH 0068/1313] Allocate QUICPacket with a class allocator --- iocore/net/P_QUICNetVConnection.h | 16 +++--- iocore/net/QUICNetVConnection.cc | 27 +++++----- iocore/net/QUICPacketHandler.cc | 4 +- iocore/net/quic/Mock.h | 6 +-- iocore/net/quic/QUICLossDetector.cc | 4 +- iocore/net/quic/QUICLossDetector.h | 6 +-- iocore/net/quic/QUICPacket.cc | 50 +++++++++++-------- iocore/net/quic/QUICPacket.h | 40 ++++++++++++--- iocore/net/quic/QUICPacketTransmitter.h | 2 +- iocore/net/quic/QUICTransportParameters.cc | 8 +-- iocore/net/quic/QUICTransportParameters.h | 4 +- iocore/net/quic/test/test_QUICLossDetector.cc | 6 ++- .../net/quic/test/test_QUICPacketFactory.cc | 5 +- .../quic/test/test_QUICVersionNegotiator.cc | 2 +- 14 files changed, 109 insertions(+), 71 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index bfb96afd4ee..b370cc5edb0 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -157,7 +157,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection int state_connection_closing(int event, Event *data); int state_connection_closed(int event, Event *data); void start(SSL_CTX *); - void push_packet(std::unique_ptr packet); + void push_packet(std::unique_ptr packet); void free(EThread *t) override; UDPConnection *get_udp_con(); @@ -177,7 +177,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void close(QUICError error) override; // QUICConnection (QUICPacketTransmitter) - virtual void transmit_packet(std::unique_ptr packet) override; + virtual void transmit_packet(std::unique_ptr packet) override; virtual void retransmit_packet(const QUICPacket &packet) override; virtual Ptr get_transmitter_mutex() override; @@ -216,15 +216,15 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection std::queue> _frame_buffer; void _packetize_frames(); - std::unique_ptr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, - QUICPacketType type = QUICPacketType::UNINITIALIZED); + std::unique_ptr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, + QUICPacketType type = QUICPacketType::UNINITIALIZED); QUICError _recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_numm); - QUICError _state_handshake_process_initial_client_packet(std::unique_ptr packet); - QUICError _state_handshake_process_client_cleartext_packet(std::unique_ptr packet); - QUICError _state_handshake_process_zero_rtt_protected_packet(std::unique_ptr packet); - QUICError _state_connection_established_process_packet(std::unique_ptr packet); + QUICError _state_handshake_process_initial_client_packet(std::unique_ptr packet); + QUICError _state_handshake_process_client_cleartext_packet(std::unique_ptr packet); + QUICError _state_handshake_process_zero_rtt_protected_packet(std::unique_ptr packet); + QUICError _state_connection_established_process_packet(std::unique_ptr packet); QUICError _state_common_receive_packet(); QUICError _state_common_send_packet(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 99e63da177a..8bb06017688 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -184,7 +184,7 @@ QUICNetVConnection::maximum_stream_frame_data_size() } void -QUICNetVConnection::transmit_packet(std::unique_ptr packet) +QUICNetVConnection::transmit_packet(std::unique_ptr packet) { // TODO Remove const_cast this->_packet_send_queue.enqueue(const_cast(packet.release())); @@ -223,7 +223,7 @@ QUICNetVConnection::get_transmitter_mutex() } void -QUICNetVConnection::push_packet(std::unique_ptr packet) +QUICNetVConnection::push_packet(std::unique_ptr packet) { DebugQUICCon("Type=%s Size=%u", QUICDebugNames::packet_type(packet->type()), packet->size()); this->_packet_recv_queue.enqueue(const_cast(packet.release())); @@ -306,7 +306,8 @@ QUICNetVConnection::state_handshake(int event, Event *data) switch (event) { case QUIC_EVENT_PACKET_READ_READY: { - std::unique_ptr p = std::unique_ptr(this->_packet_recv_queue.dequeue()); + std::unique_ptr p = + std::unique_ptr(this->_packet_recv_queue.dequeue(), &QUICPacketDeleter::delete_packet); net_activity(this, this_ethread()); switch (p->type()) { @@ -489,7 +490,7 @@ QUICNetVConnection::next_protocol_set() } QUICError -QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_ptr packet) +QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_ptr packet) { if (packet->size() < this->minimum_quic_packet_size()) { DebugQUICCon("%" PRId32 ", %" PRId32, packet->size(), this->minimum_quic_packet_size()); @@ -512,7 +513,7 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_p } QUICError -QUICNetVConnection::_state_handshake_process_client_cleartext_packet(std::unique_ptr packet) +QUICNetVConnection::_state_handshake_process_client_cleartext_packet(std::unique_ptr packet) { QUICError error = QUICError(QUICErrorClass::NONE); @@ -527,7 +528,7 @@ QUICNetVConnection::_state_handshake_process_client_cleartext_packet(std::unique } QUICError -QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(std::unique_ptr packet) +QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(std::unique_ptr packet) { // TODO: Decrypt the packet // decrypt(payload, p); @@ -536,7 +537,7 @@ QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(std::uniq } QUICError -QUICNetVConnection::_state_connection_established_process_packet(std::unique_ptr packet) +QUICNetVConnection::_state_connection_established_process_packet(std::unique_ptr packet) { // TODO: fix size size_t max_plain_txt_len = 2048; @@ -560,7 +561,8 @@ QUICError QUICNetVConnection::_state_common_receive_packet() { QUICError error; - std::unique_ptr p = std::unique_ptr(this->_packet_recv_queue.dequeue()); + std::unique_ptr p = + std::unique_ptr(this->_packet_recv_queue.dequeue(), &QUICPacketDeleter::delete_packet); net_activity(this, this_ethread()); switch (p->type()) { @@ -580,10 +582,11 @@ QUICNetVConnection::_state_common_send_packet() { this->_packetize_frames(); - const QUICPacket *packet; + QUICPacket *packet; while ((packet = this->_packet_send_queue.dequeue()) != nullptr) { this->_packet_handler->send_packet(*packet, this); - this->_loss_detector->on_packet_sent(std::unique_ptr(packet)); + this->_loss_detector->on_packet_sent( + std::unique_ptr(packet, &QUICPacketDeleter::delete_packet)); } net_activity(this, this_ethread()); @@ -660,10 +663,10 @@ QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPac return error; } -std::unique_ptr +std::unique_ptr QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type) { - std::unique_ptr packet; + std::unique_ptr packet(nullptr, &QUICPacketDeleter::delete_null_packet); DebugQUICCon("retransmittable %u", retransmittable); switch (type) { diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 2edb33881dd..0a7278c08df 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -96,8 +96,8 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) { IOBufferBlock *block = udpPacket->getIOBlockChain(); - std::unique_ptr qPkt = std::unique_ptr(QUICPacketFactory::create(block)); - QUICNetVConnection *vc = this->_connections.get(qPkt->connection_id()); + std::unique_ptr qPkt = QUICPacketFactory::create(block); + QUICNetVConnection *vc = this->_connections.get(qPkt->connection_id()); if (!vc) { // Unknown Connection ID diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index dad5f631d7d..54ee271b8ac 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -100,7 +100,7 @@ class MockQUICConnection : public QUICConnection this->_mutex = new_ProxyMutex(); }; void - transmit_packet(std::unique_ptr packet) override + transmit_packet(std::unique_ptr packet) override { ++_transmit_count; } @@ -199,7 +199,7 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter public: MockQUICPacketTransmitter() : QUICPacketTransmitter() { this->_mutex = new_ProxyMutex(); }; void - transmit_packet(std::unique_ptr packet) override + transmit_packet(std::unique_ptr packet) override { ++_transmit_count; } @@ -245,7 +245,7 @@ class MockQUICLossDetector : public QUICLossDetector } void - on_packet_sent(std::unique_ptr packet) + on_packet_sent(std::unique_ptr packet) { } }; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index bec3c6ff252..cd8fefd0a0e 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -137,7 +137,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num } void -QUICLossDetector::on_packet_sent(std::unique_ptr packet) +QUICLossDetector::on_packet_sent(std::unique_ptr packet) { bool is_handshake = false; QUICPacketType type = packet->type(); @@ -154,7 +154,7 @@ QUICLossDetector::on_packet_sent(std::unique_ptr packet) void QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_retransmittable, bool is_handshake, size_t sent_bytes, - std::unique_ptr packet) + std::unique_ptr packet) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); this->_largest_sent_packet = packet_number; diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 44e87a5e1e0..b12a293cac8 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -47,7 +47,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler std::vector interests() override; virtual QUICError handle_frame(std::shared_ptr) override; - void on_packet_sent(std::unique_ptr packet); + void on_packet_sent(std::unique_ptr packet); private: struct PacketInfo { @@ -56,7 +56,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler bool retransmittable; bool handshake; size_t bytes; - std::unique_ptr packet; + std::unique_ptr packet; }; bool _time_loss_detection = false; @@ -94,7 +94,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _decrement_packet_count(QUICPacketNumber packet_number); void _on_packet_sent(QUICPacketNumber packet_number, bool is_retransmittable, bool is_handshake, size_t sent_bytes, - std::unique_ptr packet); + std::unique_ptr packet); void _on_ack_received(const std::shared_ptr &ack_frame); void _on_packet_acked(QUICPacketNumber acked_packet_number); void _update_rtt(uint32_t latest_rtt); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index db503844898..0e037f4739c 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -24,6 +24,8 @@ #include #include "QUICPacket.h" +ClassAllocator quicPacketAllocator("quicPacketAllocator"); + static constexpr int OFFSET_CONNECTION_ID = 1; static constexpr int OFFSET_PACKET_NUMBER = 9; static constexpr int OFFSET_VERSION = 13; @@ -571,14 +573,15 @@ QUICPacket::set_protected_payload(ats_unique_buf cipher_txt, size_t cipher_txt_l this->_protected_payload_size = cipher_txt_len; } -QUICPacket * +std::unique_ptr QUICPacketFactory::create(IOBufferBlock *block) { - // TODO: Use custom allocator - return new QUICPacket(block); + QUICPacket *packet = quicPacketAllocator.alloc(); + new (packet) QUICPacket(block); + return std::unique_ptr(packet, &QUICPacketDeleter::delete_packet); } -std::unique_ptr +std::unique_ptr QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_sent_by_client) { size_t len = sizeof(QUICVersion) * countof(QUIC_SUPPORTED_VERSIONS); @@ -591,31 +594,32 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se p += n; } - // TODO: Use custom allocator - return std::unique_ptr(new QUICPacket(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), - packet_sent_by_client->packet_number(), packet_sent_by_client->version(), - std::move(versions), len, false)); + QUICPacket *packet = quicPacketAllocator.alloc(); + new (packet) + QUICPacket(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), packet_sent_by_client->packet_number(), + packet_sent_by_client->version(), std::move(versions), len, false); + return std::unique_ptr(packet, QUICPacketDeleter::delete_packet); } -std::unique_ptr +std::unique_ptr QUICPacketFactory::create_server_cleartext_packet(QUICConnectionId connection_id, ats_unique_buf payload, size_t len, bool retransmittable) { - // TODO: Use custom allocator - return std::unique_ptr(new QUICPacket(QUICPacketType::SERVER_CLEARTEXT, connection_id, - this->_packet_number_generator.next(), this->_version, std::move(payload), len, - retransmittable)); + QUICPacket *p = quicPacketAllocator.alloc(); + new (p) QUICPacket(QUICPacketType::SERVER_CLEARTEXT, connection_id, this->_packet_number_generator.next(), this->_version, + std::move(payload), len, retransmittable); + return std::unique_ptr(p, &QUICPacketDeleter::delete_packet); } -std::unique_ptr +std::unique_ptr QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id, ats_unique_buf payload, size_t len, bool retransmittable) { // TODO Key phase should be picked up from QUICCrypto, probably - // TODO Use class allocator - auto packet = - std::unique_ptr(new QUICPacket(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, connection_id, - this->_packet_number_generator.next(), std::move(payload), len, retransmittable)); + QUICPacket *p = quicPacketAllocator.alloc(); + new (p) QUICPacket(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, connection_id, this->_packet_number_generator.next(), + std::move(payload), len, retransmittable); + auto packet = std::unique_ptr(p, &QUICPacketDeleter::delete_packet); // TODO: use pmtu of UnixNetVConnection size_t max_cipher_txt_len = 2048; @@ -635,16 +639,18 @@ QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id return packet; } else { Debug("quic_packet_factory", "CRYPTOGRAPHIC Error"); - return nullptr; + return std::unique_ptr(nullptr, &QUICPacketDeleter::delete_null_packet); } } -std::unique_ptr +std::unique_ptr QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, QUICVersion version, ats_unique_buf payload, size_t len) { - return std::unique_ptr(new QUICPacket(QUICPacketType::CLIENT_INITIAL, connection_id, - this->_packet_number_generator.next(), version, std::move(payload), len, true)); + QUICPacket *packet = quicPacketAllocator.alloc(); + new (packet) QUICPacket(QUICPacketType::CLIENT_INITIAL, connection_id, this->_packet_number_generator.next(), version, + std::move(payload), len, true); + return std::unique_ptr(packet, &QUICPacketDeleter::delete_packet); } void diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 32a087bc9b4..dd2c2160be6 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -121,6 +121,7 @@ class QUICPacketShortHeader : public QUICPacketHeader class QUICPacket { public: + QUICPacket(){}; QUICPacket(IOBufferBlock *block); QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICVersion version, ats_unique_buf payload, size_t len, bool retransmittable); @@ -164,17 +165,40 @@ class QUICPacketNumberGenerator QUICPacketNumber _current = 0; }; +using QUICPacketDeleterFunc = void (*)(QUICPacket *p); + +extern ClassAllocator quicPacketAllocator; + +class QUICPacketDeleter +{ +public: + // TODO Probably these methods should call destructor + static void + delete_null_packet(QUICPacket *packet) + { + } + + static void + delete_packet(QUICPacket *packet) + { + quicPacketAllocator.free(packet); + } +}; + class QUICPacketFactory { public: - static QUICPacket *create(IOBufferBlock *block); - std::unique_ptr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client); - std::unique_ptr create_server_cleartext_packet(QUICConnectionId connection_id, ats_unique_buf payload, size_t len, - bool retransmittable); - std::unique_ptr create_server_protected_packet(QUICConnectionId connection_id, ats_unique_buf payload, size_t len, - bool retransmittable); - std::unique_ptr create_client_initial_packet(QUICConnectionId connection_id, QUICVersion version, - ats_unique_buf payload, size_t len); + static std::unique_ptr create(IOBufferBlock *block); + std::unique_ptr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client); + std::unique_ptr create_server_cleartext_packet(QUICConnectionId connection_id, + ats_unique_buf payload, size_t len, + bool retransmittable); + std::unique_ptr create_server_protected_packet(QUICConnectionId connection_id, + ats_unique_buf payload, size_t len, + bool retransmittable); + std::unique_ptr create_client_initial_packet(QUICConnectionId connection_id, + QUICVersion version, ats_unique_buf payload, + size_t len); void set_version(QUICVersion negotiated_version); void set_crypto_module(QUICCrypto *crypto); diff --git a/iocore/net/quic/QUICPacketTransmitter.h b/iocore/net/quic/QUICPacketTransmitter.h index d8b8a41cb08..67c8fa590b0 100644 --- a/iocore/net/quic/QUICPacketTransmitter.h +++ b/iocore/net/quic/QUICPacketTransmitter.h @@ -33,7 +33,7 @@ class QUICPacketTransmitter * * This sends QUIC_PACKET_WRITE_READY event. */ - virtual void transmit_packet(std::unique_ptr packet) = 0; + virtual void transmit_packet(std::unique_ptr packet) = 0; /* * Enqueue a packet for retransmission diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index c3ce09c125d..50c149faadf 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -162,11 +162,12 @@ QUICTransportParameters::store(uint8_t *buf, uint16_t *len) const // QUICTransportParametersInClientHello // -QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const uint8_t *buf, size_t len) : QUICTransportParameters(buf, len) +QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const uint8_t *buf, size_t len) + : QUICTransportParameters(buf, len) { // Print all parameters const uint8_t *p = this->_buf.get() + this->_parameters_offset(); - uint16_t n = (p[0] << 8) + p[1]; + uint16_t n = (p[0] << 8) + p[1]; p += 2; while (n > 0) { uint16_t _id = (p[0] << 8) + p[1]; @@ -178,7 +179,8 @@ QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const if (_value_len == 0) { Debug("quic_handsahke", "%s: (no value)", QUICDebugNames::transport_parameter_id(_id)); } else if (_value_len <= 8) { - Debug("quic_handsahke", "%s: 0x%" PRIx64 " (%" PRIu64 ")", QUICDebugNames::transport_parameter_id(_id), QUICTypeUtil::read_nbytes_as_uint(p, _value_len), QUICTypeUtil::read_nbytes_as_uint(p, _value_len)); + Debug("quic_handsahke", "%s: 0x%" PRIx64 " (%" PRIu64 ")", QUICDebugNames::transport_parameter_id(_id), + QUICTypeUtil::read_nbytes_as_uint(p, _value_len), QUICTypeUtil::read_nbytes_as_uint(p, _value_len)); } else { Debug("quic_handsahke", "%s: (long data)", QUICDebugNames::transport_parameter_id(_id)); } diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index c5239f26e66..87d8af66c32 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -99,8 +99,8 @@ class QUICTransportParameters class QUICTransportParametersInClientHello : public QUICTransportParameters { public: - QUICTransportParametersInClientHello(QUICVersion negotiated_version, QUICVersion initial_version) : QUICTransportParameters(), _negotiated_version(negotiated_version), _initial_version(initial_version) -{}; + QUICTransportParametersInClientHello(QUICVersion negotiated_version, QUICVersion initial_version) + : QUICTransportParameters(), _negotiated_version(negotiated_version), _initial_version(initial_version){}; QUICTransportParametersInClientHello(const uint8_t *buf, size_t len); QUICVersion negotiated_version() const; QUICVersion initial_version() const; diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 09b4800db52..b23e15656b2 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -40,8 +40,10 @@ TEST_CASE("QUICLossDetector_Loss_in_Handshake", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - std::unique_ptr packet = std::unique_ptr(new QUICPacket( - QUICPacketType::SERVER_CLEARTEXT, 0xffddbb9977553311ULL, 0x00000001, 0x00112233, std::move(payload), sizeof(raw), true)); + std::unique_ptr packet = std::unique_ptr( + new QUICPacket(QUICPacketType::SERVER_CLEARTEXT, 0xffddbb9977553311ULL, 0x00000001, 0x00112233, std::move(payload), sizeof(raw), + true), + [](QUICPacket *p) { delete p; }); detector.on_packet_sent(std::move(packet)); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); CHECK(tx->_retransmit_count > 0); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 31bdbd2d33a..51850ffbfde 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -44,7 +44,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") QUICPacket client_initial_packet(block); - std::unique_ptr packet = factory.create_version_negotiation_packet(&client_initial_packet); + std::unique_ptr packet = factory.create_version_negotiation_packet(&client_initial_packet); CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); CHECK(packet->connection_id() == client_initial_packet.connection_id()); CHECK(packet->packet_number() == client_initial_packet.packet_number()); @@ -60,7 +60,8 @@ TEST_CASE("QUICPacketFactory_Create_ServerCleartextPacket", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - std::unique_ptr packet = factory.create_server_cleartext_packet(0x01020304, std::move(payload), sizeof(raw), true); + std::unique_ptr packet = + factory.create_server_cleartext_packet(0x01020304, std::move(payload), sizeof(raw), true); CHECK(packet->type() == QUICPacketType::SERVER_CLEARTEXT); CHECK(packet->connection_id() == 0x01020304); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 1191efdf415..9de0bdb74ff 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -35,7 +35,7 @@ TEST_CASE("QUICVersionNegotiator_Normal", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); // Negotiate version - std::unique_ptr initial_packet = + std::unique_ptr initial_packet = packet_factory.create_client_initial_packet({}, QUIC_SUPPORTED_VERSIONS[0], ats_unique_malloc(0), 0); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); From ca6ab0c896348e65d9a8c8c2422312a3c023be0a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 28 Aug 2017 16:26:37 +0900 Subject: [PATCH 0069/1313] Allocate QUICPacketHeader with class allocators --- iocore/net/quic/QUICPacket.cc | 31 ++++++++++++++++++++++++++----- iocore/net/quic/QUICPacket.h | 5 +++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 0e037f4739c..683fd48ff6c 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -25,6 +25,8 @@ #include "QUICPacket.h" ClassAllocator quicPacketAllocator("quicPacketAllocator"); +ClassAllocator quicPacketLongHeaderAllocator("quicPacketLongHeaderAllocator"); +ClassAllocator quicPacketShortHeaderAllocator("quicPacketShortHeaderAllocator"); static constexpr int OFFSET_CONNECTION_ID = 1; static constexpr int OFFSET_PACKET_NUMBER = 9; @@ -43,9 +45,13 @@ QUICPacketHeader * QUICPacketHeader::load(const uint8_t *buf, size_t len) { if (QUICTypeUtil::hasLongHeader(buf)) { - return new QUICPacketLongHeader(buf, len); + QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); + new (long_header) QUICPacketLongHeader(buf, len); + return long_header; } else { - return new QUICPacketShortHeader(buf, len); + QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); + new (short_header) QUICPacketShortHeader(buf, len); + return short_header; } } @@ -53,20 +59,26 @@ QUICPacketHeader * QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICVersion version, ats_unique_buf payload, size_t len) { - return new QUICPacketLongHeader(type, connection_id, packet_number, version, std::move(payload), len); + QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); + new (long_header) QUICPacketLongHeader(type, connection_id, packet_number, version, std::move(payload), len); + return long_header; } QUICPacketHeader * QUICPacketHeader::build(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len) { - return new QUICPacketShortHeader(type, packet_number, std::move(payload), len); + QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); + new (short_header) QUICPacketShortHeader(type, packet_number, std::move(payload), len); + return short_header; } QUICPacketHeader * QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len) { - return new QUICPacketShortHeader(type, connection_id, packet_number, std::move(payload), len); + QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); + new (short_header) QUICPacketShortHeader(type, connection_id, packet_number, std::move(payload), len); + return short_header; } // QUICPacketLongHeader @@ -456,6 +468,15 @@ QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUIC this->_is_retransmittable = retransmittable; } +QUICPacket::~QUICPacket() +{ + if (this->_header->has_version()) { + quicPacketLongHeaderAllocator.free(static_cast(this->_header)); + } else { + quicPacketShortHeaderAllocator.free(static_cast(this->_header)); + } +} + /** * When packet is "Short Header Packet", QUICPacket::type() will return 1-RTT Protected (key phase 0) * or 1-RTT Protected (key phase 1) diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index dd2c2160be6..224f7e6f41b 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -78,6 +78,7 @@ class QUICPacketHeader class QUICPacketLongHeader : public QUICPacketHeader { public: + QUICPacketLongHeader() : QUICPacketHeader(){}; QUICPacketLongHeader(const uint8_t *buf, size_t len) : QUICPacketHeader(buf, len) {} QUICPacketLongHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICVersion version, ats_unique_buf buf, size_t len); @@ -97,6 +98,7 @@ class QUICPacketLongHeader : public QUICPacketHeader class QUICPacketShortHeader : public QUICPacketHeader { public: + QUICPacketShortHeader() : QUICPacketHeader(){}; QUICPacketShortHeader(const uint8_t *buf, size_t len) : QUICPacketHeader(buf, len) {} QUICPacketShortHeader(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf buf, size_t len); QUICPacketShortHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf buf, @@ -128,6 +130,7 @@ class QUICPacket QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len, bool retransmittable); QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len, bool retransmittabl); + ~QUICPacket(); void set_protected_payload(ats_unique_buf cipher_txt, size_t cipher_txt_len); QUICPacketType type() const; @@ -168,6 +171,8 @@ class QUICPacketNumberGenerator using QUICPacketDeleterFunc = void (*)(QUICPacket *p); extern ClassAllocator quicPacketAllocator; +extern ClassAllocator quicPacketLongHeaderAllocator; +extern ClassAllocator quicPacketShortHeaderAllocator; class QUICPacketDeleter { From 407dd1b98156af1010893aa75d428cd70e6b27a8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 29 Aug 2017 09:59:19 +0900 Subject: [PATCH 0070/1313] Fix a runtime error on Fedora 26 --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index b370cc5edb0..f256d78dd9d 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -195,7 +195,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; QUICAckFrameCreator _ack_frame_creator; - QUICApplicationMap _application_map; + QUICApplicationMap *_application_map = nullptr; uint32_t _pmtu = 1280; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8bb06017688..2b772b7c5ff 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -96,14 +96,15 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) { // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not this->_handshake_handler = new QUICHandshake(this, ssl_ctx); - this->_application_map.set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); + this->_application_map = new QUICApplicationMap(); + this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); this->_crypto = this->_handshake_handler->crypto_module(); this->_frame_dispatcher = new QUICFrameDispatcher(); this->_packet_factory.set_crypto_module(this->_crypto); // Create frame handlers - this->_stream_manager = new QUICStreamManager(this, &this->_application_map); + this->_stream_manager = new QUICStreamManager(this, this->_application_map); this->_congestion_controller = new QUICCongestionController(); this->_loss_detector = new QUICLossDetector(this); @@ -123,6 +124,7 @@ QUICNetVConnection::free(EThread *t) delete this->_version_negotiator; delete this->_handshake_handler; + delete this->_application_map; delete this->_crypto; delete this->_loss_detector; delete this->_frame_dispatcher; @@ -354,7 +356,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) } if (this->_handshake_handler && this->_handshake_handler->is_completed()) { - this->_application_map.set_default(this->_create_application()); + this->_application_map->set_default(this->_create_application()); this->_stream_manager->init_flow_control_params(this->_handshake_handler->local_transport_parameters(), this->_handshake_handler->remote_transport_parameters()); From c90703cc4c3be3c5b7790265cd09c584c30b1be0 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 1 Sep 2017 09:49:23 +0800 Subject: [PATCH 0071/1313] fix the compiler error with gcc 4.9 --- iocore/net/quic/QUICFrame.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 8feb1750dd3..11fcf033aca 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -429,6 +429,7 @@ class QUICNewConnectionIdFrame : public QUICFrame }; using QUICFrameDeleterFunc = void (*)(QUICFrame *p); +using QUICFramePtr = std::unique_ptr; // // Retransmission Frame @@ -444,7 +445,7 @@ class QUICRetransmissionFrame : public QUICFrame QUICPacketType packet_type() const; private: - std::unique_ptr _frame = std::unique_ptr(nullptr, nullptr); + std::unique_ptr _frame = QUICFramePtr(nullptr, nullptr); ats_unique_buf _data = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); size_t _size; QUICPacketType _packet_type; From b8a2a62bc83e17ec4721e50e65fdfb84c179755a Mon Sep 17 00:00:00 2001 From: Oknet Xu Date: Mon, 28 Aug 2017 10:56:16 +0800 Subject: [PATCH 0072/1313] Resign server.pem for autests to 10 years --- tests/gold_tests/h2/ssl/server.pem | 20 ++++++++++---------- tests/gold_tests/remap/ssl/server.pem | 20 ++++++++++---------- tests/gold_tests/tls/ssl/server.pem | 20 ++++++++++---------- tests/gold_tests/tls_hooks/ssl/server.pem | 20 ++++++++++---------- tests/tools/microServer/ssl/server.pem | 20 ++++++++++---------- 5 files changed, 50 insertions(+), 50 deletions(-) diff --git a/tests/gold_tests/h2/ssl/server.pem b/tests/gold_tests/h2/ssl/server.pem index a1de94fa776..3584a2ec119 100644 --- a/tests/gold_tests/h2/ssl/server.pem +++ b/tests/gold_tests/h2/ssl/server.pem @@ -14,19 +14,19 @@ lORoveLvotl4HOruSsMCQQCAx9dV9JUSFoyc1CWILp/FgUH/se4cjQCThGO0DoQQ vGTYmntY7j9WRJ9esQrjdD6Clw8zM/45GIBNwnXzqo7Z -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIICszCCAhwCCQCRJsJJ+mTsdDANBgkqhkiG9w0BAQsFADCBnTELMAkGA1UEBhMC -VVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFpZ24xDjAMBgNVBAoMBVlh -aG9vMQ0wCwYDVQQLDARFZGdlMSgwJgYDVQQDDB9qdWljZXByb2R1Y2UuY29ycC5u +MIICszCCAhwCCQCl0Y79KkYjpzANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAklMMRIwEAYDVQQHEwlDaGFtcGFpZ24xDjAMBgNVBAoTBVlh +aG9vMQ0wCwYDVQQLEwRFZGdlMSgwJgYDVQQDEx9qdWljZXByb2R1Y2UuY29ycC5u ZTEueWFob28uY29tMSQwIgYJKoZIhvcNAQkBFhVwZXJzaWEuYXppekB5YWhvby5j -b20wHhcNMTYwODI1MjI1NzIxWhcNMTcwODI1MjI1NzIxWjCBnTELMAkGA1UEBhMC -VVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFpZ24xDjAMBgNVBAoMBVlh -aG9vMQ0wCwYDVQQLDARFZGdlMSgwJgYDVQQDDB9qdWljZXByb2R1Y2UuY29ycC5u +b20wHhcNMTcwODI4MDI1MjI5WhcNMjcwODI2MDI1MjI5WjCBnTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAklMMRIwEAYDVQQHEwlDaGFtcGFpZ24xDjAMBgNVBAoTBVlh +aG9vMQ0wCwYDVQQLEwRFZGdlMSgwJgYDVQQDEx9qdWljZXByb2R1Y2UuY29ycC5u ZTEueWFob28uY29tMSQwIgYJKoZIhvcNAQkBFhVwZXJzaWEuYXppekB5YWhvby5j b20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYwc6JQX45GZmMDEjwxYT11 uVvuBBInfpYJeU8WIXHrKcX5LUSRcBikiKnlfSnMNRohsu6TElQACc60wQ7Q8KDE lBSsS1FaHzCIl1t1AkXRmz/1H65JSBvrV/6Z1NC+Gp58EbH7Gul8ByC1xaJm5ID1 -Dd++kOPlY5ZI9ZcFS7HLAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAXSVfZ5p1TkhW -QiYq9nfQlBnX2NVaf8ymA8edQR0qH/QBv4/52bNNXC7V/V+ev9LCho2iRMeYYyXB -yo1wBAGR83lS9cF/tOABcYrxjdP54Sfkyh5fomcg8SV7zap6C8mhbV8r3EujbKCx -igH3fMX5F/eRwNCzaMMyQsXaxTJ3trk= +Dd++kOPlY5ZI9ZcFS7HLAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAASZbz+d+DdI+ +ypesJrlBRosXh0w8sIjkUSSdT/OuKEVzfH/dRcb4VZDW/W2gmm0VEqSN2xYYVpW3 +hUsW2J+kByqFqX6selREwo8ui8kkyBJVo0y/MCrGM0C3qw1cSaiKoa5OqlOyO3hb +ZC9IIyWmpBxRmJFfIwS6MoTpe0/ZTJQ= -----END CERTIFICATE----- diff --git a/tests/gold_tests/remap/ssl/server.pem b/tests/gold_tests/remap/ssl/server.pem index a1de94fa776..58b9b9715b7 100644 --- a/tests/gold_tests/remap/ssl/server.pem +++ b/tests/gold_tests/remap/ssl/server.pem @@ -14,19 +14,19 @@ lORoveLvotl4HOruSsMCQQCAx9dV9JUSFoyc1CWILp/FgUH/se4cjQCThGO0DoQQ vGTYmntY7j9WRJ9esQrjdD6Clw8zM/45GIBNwnXzqo7Z -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIICszCCAhwCCQCRJsJJ+mTsdDANBgkqhkiG9w0BAQsFADCBnTELMAkGA1UEBhMC -VVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFpZ24xDjAMBgNVBAoMBVlh -aG9vMQ0wCwYDVQQLDARFZGdlMSgwJgYDVQQDDB9qdWljZXByb2R1Y2UuY29ycC5u +MIICszCCAhwCCQD4jSkztmlO1TANBgkqhkiG9w0BAQsFADCBnTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAklMMRIwEAYDVQQHEwlDaGFtcGFpZ24xDjAMBgNVBAoTBVlh +aG9vMQ0wCwYDVQQLEwRFZGdlMSgwJgYDVQQDEx9qdWljZXByb2R1Y2UuY29ycC5u ZTEueWFob28uY29tMSQwIgYJKoZIhvcNAQkBFhVwZXJzaWEuYXppekB5YWhvby5j -b20wHhcNMTYwODI1MjI1NzIxWhcNMTcwODI1MjI1NzIxWjCBnTELMAkGA1UEBhMC -VVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFpZ24xDjAMBgNVBAoMBVlh -aG9vMQ0wCwYDVQQLDARFZGdlMSgwJgYDVQQDDB9qdWljZXByb2R1Y2UuY29ycC5u +b20wHhcNMTcwODI4MDM0NDQ1WhcNMjcwODI2MDM0NDQ1WjCBnTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAklMMRIwEAYDVQQHEwlDaGFtcGFpZ24xDjAMBgNVBAoTBVlh +aG9vMQ0wCwYDVQQLEwRFZGdlMSgwJgYDVQQDEx9qdWljZXByb2R1Y2UuY29ycC5u ZTEueWFob28uY29tMSQwIgYJKoZIhvcNAQkBFhVwZXJzaWEuYXppekB5YWhvby5j b20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYwc6JQX45GZmMDEjwxYT11 uVvuBBInfpYJeU8WIXHrKcX5LUSRcBikiKnlfSnMNRohsu6TElQACc60wQ7Q8KDE lBSsS1FaHzCIl1t1AkXRmz/1H65JSBvrV/6Z1NC+Gp58EbH7Gul8ByC1xaJm5ID1 -Dd++kOPlY5ZI9ZcFS7HLAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAXSVfZ5p1TkhW -QiYq9nfQlBnX2NVaf8ymA8edQR0qH/QBv4/52bNNXC7V/V+ev9LCho2iRMeYYyXB -yo1wBAGR83lS9cF/tOABcYrxjdP54Sfkyh5fomcg8SV7zap6C8mhbV8r3EujbKCx -igH3fMX5F/eRwNCzaMMyQsXaxTJ3trk= +Dd++kOPlY5ZI9ZcFS7HLAgMBAAEwDQYJKoZIhvcNAQELBQADgYEATX7975NdhIbJ +glda+sXI9a86GgOpiuKO+vKubRJQZA+UlPf2vHEONjC2+7Y1aZvZYaKYL74vxGky +zkgp6ANSPl45lqD632x0e1Z7vzW5TkqK1JB2/xH2WgDcQZmP0FuQHzVNs4GjghDr +HCp1+sQDhfPB4aLmLFeyN0TkhdH1N3M= -----END CERTIFICATE----- diff --git a/tests/gold_tests/tls/ssl/server.pem b/tests/gold_tests/tls/ssl/server.pem index a1de94fa776..58b9b9715b7 100644 --- a/tests/gold_tests/tls/ssl/server.pem +++ b/tests/gold_tests/tls/ssl/server.pem @@ -14,19 +14,19 @@ lORoveLvotl4HOruSsMCQQCAx9dV9JUSFoyc1CWILp/FgUH/se4cjQCThGO0DoQQ vGTYmntY7j9WRJ9esQrjdD6Clw8zM/45GIBNwnXzqo7Z -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIICszCCAhwCCQCRJsJJ+mTsdDANBgkqhkiG9w0BAQsFADCBnTELMAkGA1UEBhMC -VVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFpZ24xDjAMBgNVBAoMBVlh -aG9vMQ0wCwYDVQQLDARFZGdlMSgwJgYDVQQDDB9qdWljZXByb2R1Y2UuY29ycC5u +MIICszCCAhwCCQD4jSkztmlO1TANBgkqhkiG9w0BAQsFADCBnTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAklMMRIwEAYDVQQHEwlDaGFtcGFpZ24xDjAMBgNVBAoTBVlh +aG9vMQ0wCwYDVQQLEwRFZGdlMSgwJgYDVQQDEx9qdWljZXByb2R1Y2UuY29ycC5u ZTEueWFob28uY29tMSQwIgYJKoZIhvcNAQkBFhVwZXJzaWEuYXppekB5YWhvby5j -b20wHhcNMTYwODI1MjI1NzIxWhcNMTcwODI1MjI1NzIxWjCBnTELMAkGA1UEBhMC -VVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFpZ24xDjAMBgNVBAoMBVlh -aG9vMQ0wCwYDVQQLDARFZGdlMSgwJgYDVQQDDB9qdWljZXByb2R1Y2UuY29ycC5u +b20wHhcNMTcwODI4MDM0NDQ1WhcNMjcwODI2MDM0NDQ1WjCBnTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAklMMRIwEAYDVQQHEwlDaGFtcGFpZ24xDjAMBgNVBAoTBVlh +aG9vMQ0wCwYDVQQLEwRFZGdlMSgwJgYDVQQDEx9qdWljZXByb2R1Y2UuY29ycC5u ZTEueWFob28uY29tMSQwIgYJKoZIhvcNAQkBFhVwZXJzaWEuYXppekB5YWhvby5j b20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYwc6JQX45GZmMDEjwxYT11 uVvuBBInfpYJeU8WIXHrKcX5LUSRcBikiKnlfSnMNRohsu6TElQACc60wQ7Q8KDE lBSsS1FaHzCIl1t1AkXRmz/1H65JSBvrV/6Z1NC+Gp58EbH7Gul8ByC1xaJm5ID1 -Dd++kOPlY5ZI9ZcFS7HLAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAXSVfZ5p1TkhW -QiYq9nfQlBnX2NVaf8ymA8edQR0qH/QBv4/52bNNXC7V/V+ev9LCho2iRMeYYyXB -yo1wBAGR83lS9cF/tOABcYrxjdP54Sfkyh5fomcg8SV7zap6C8mhbV8r3EujbKCx -igH3fMX5F/eRwNCzaMMyQsXaxTJ3trk= +Dd++kOPlY5ZI9ZcFS7HLAgMBAAEwDQYJKoZIhvcNAQELBQADgYEATX7975NdhIbJ +glda+sXI9a86GgOpiuKO+vKubRJQZA+UlPf2vHEONjC2+7Y1aZvZYaKYL74vxGky +zkgp6ANSPl45lqD632x0e1Z7vzW5TkqK1JB2/xH2WgDcQZmP0FuQHzVNs4GjghDr +HCp1+sQDhfPB4aLmLFeyN0TkhdH1N3M= -----END CERTIFICATE----- diff --git a/tests/gold_tests/tls_hooks/ssl/server.pem b/tests/gold_tests/tls_hooks/ssl/server.pem index a1de94fa776..58b9b9715b7 100644 --- a/tests/gold_tests/tls_hooks/ssl/server.pem +++ b/tests/gold_tests/tls_hooks/ssl/server.pem @@ -14,19 +14,19 @@ lORoveLvotl4HOruSsMCQQCAx9dV9JUSFoyc1CWILp/FgUH/se4cjQCThGO0DoQQ vGTYmntY7j9WRJ9esQrjdD6Clw8zM/45GIBNwnXzqo7Z -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIICszCCAhwCCQCRJsJJ+mTsdDANBgkqhkiG9w0BAQsFADCBnTELMAkGA1UEBhMC -VVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFpZ24xDjAMBgNVBAoMBVlh -aG9vMQ0wCwYDVQQLDARFZGdlMSgwJgYDVQQDDB9qdWljZXByb2R1Y2UuY29ycC5u +MIICszCCAhwCCQD4jSkztmlO1TANBgkqhkiG9w0BAQsFADCBnTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAklMMRIwEAYDVQQHEwlDaGFtcGFpZ24xDjAMBgNVBAoTBVlh +aG9vMQ0wCwYDVQQLEwRFZGdlMSgwJgYDVQQDEx9qdWljZXByb2R1Y2UuY29ycC5u ZTEueWFob28uY29tMSQwIgYJKoZIhvcNAQkBFhVwZXJzaWEuYXppekB5YWhvby5j -b20wHhcNMTYwODI1MjI1NzIxWhcNMTcwODI1MjI1NzIxWjCBnTELMAkGA1UEBhMC -VVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFpZ24xDjAMBgNVBAoMBVlh -aG9vMQ0wCwYDVQQLDARFZGdlMSgwJgYDVQQDDB9qdWljZXByb2R1Y2UuY29ycC5u +b20wHhcNMTcwODI4MDM0NDQ1WhcNMjcwODI2MDM0NDQ1WjCBnTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAklMMRIwEAYDVQQHEwlDaGFtcGFpZ24xDjAMBgNVBAoTBVlh +aG9vMQ0wCwYDVQQLEwRFZGdlMSgwJgYDVQQDEx9qdWljZXByb2R1Y2UuY29ycC5u ZTEueWFob28uY29tMSQwIgYJKoZIhvcNAQkBFhVwZXJzaWEuYXppekB5YWhvby5j b20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYwc6JQX45GZmMDEjwxYT11 uVvuBBInfpYJeU8WIXHrKcX5LUSRcBikiKnlfSnMNRohsu6TElQACc60wQ7Q8KDE lBSsS1FaHzCIl1t1AkXRmz/1H65JSBvrV/6Z1NC+Gp58EbH7Gul8ByC1xaJm5ID1 -Dd++kOPlY5ZI9ZcFS7HLAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAXSVfZ5p1TkhW -QiYq9nfQlBnX2NVaf8ymA8edQR0qH/QBv4/52bNNXC7V/V+ev9LCho2iRMeYYyXB -yo1wBAGR83lS9cF/tOABcYrxjdP54Sfkyh5fomcg8SV7zap6C8mhbV8r3EujbKCx -igH3fMX5F/eRwNCzaMMyQsXaxTJ3trk= +Dd++kOPlY5ZI9ZcFS7HLAgMBAAEwDQYJKoZIhvcNAQELBQADgYEATX7975NdhIbJ +glda+sXI9a86GgOpiuKO+vKubRJQZA+UlPf2vHEONjC2+7Y1aZvZYaKYL74vxGky +zkgp6ANSPl45lqD632x0e1Z7vzW5TkqK1JB2/xH2WgDcQZmP0FuQHzVNs4GjghDr +HCp1+sQDhfPB4aLmLFeyN0TkhdH1N3M= -----END CERTIFICATE----- diff --git a/tests/tools/microServer/ssl/server.pem b/tests/tools/microServer/ssl/server.pem index a1de94fa776..58b9b9715b7 100644 --- a/tests/tools/microServer/ssl/server.pem +++ b/tests/tools/microServer/ssl/server.pem @@ -14,19 +14,19 @@ lORoveLvotl4HOruSsMCQQCAx9dV9JUSFoyc1CWILp/FgUH/se4cjQCThGO0DoQQ vGTYmntY7j9WRJ9esQrjdD6Clw8zM/45GIBNwnXzqo7Z -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIICszCCAhwCCQCRJsJJ+mTsdDANBgkqhkiG9w0BAQsFADCBnTELMAkGA1UEBhMC -VVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFpZ24xDjAMBgNVBAoMBVlh -aG9vMQ0wCwYDVQQLDARFZGdlMSgwJgYDVQQDDB9qdWljZXByb2R1Y2UuY29ycC5u +MIICszCCAhwCCQD4jSkztmlO1TANBgkqhkiG9w0BAQsFADCBnTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAklMMRIwEAYDVQQHEwlDaGFtcGFpZ24xDjAMBgNVBAoTBVlh +aG9vMQ0wCwYDVQQLEwRFZGdlMSgwJgYDVQQDEx9qdWljZXByb2R1Y2UuY29ycC5u ZTEueWFob28uY29tMSQwIgYJKoZIhvcNAQkBFhVwZXJzaWEuYXppekB5YWhvby5j -b20wHhcNMTYwODI1MjI1NzIxWhcNMTcwODI1MjI1NzIxWjCBnTELMAkGA1UEBhMC -VVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFpZ24xDjAMBgNVBAoMBVlh -aG9vMQ0wCwYDVQQLDARFZGdlMSgwJgYDVQQDDB9qdWljZXByb2R1Y2UuY29ycC5u +b20wHhcNMTcwODI4MDM0NDQ1WhcNMjcwODI2MDM0NDQ1WjCBnTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAklMMRIwEAYDVQQHEwlDaGFtcGFpZ24xDjAMBgNVBAoTBVlh +aG9vMQ0wCwYDVQQLEwRFZGdlMSgwJgYDVQQDEx9qdWljZXByb2R1Y2UuY29ycC5u ZTEueWFob28uY29tMSQwIgYJKoZIhvcNAQkBFhVwZXJzaWEuYXppekB5YWhvby5j b20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYwc6JQX45GZmMDEjwxYT11 uVvuBBInfpYJeU8WIXHrKcX5LUSRcBikiKnlfSnMNRohsu6TElQACc60wQ7Q8KDE lBSsS1FaHzCIl1t1AkXRmz/1H65JSBvrV/6Z1NC+Gp58EbH7Gul8ByC1xaJm5ID1 -Dd++kOPlY5ZI9ZcFS7HLAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAXSVfZ5p1TkhW -QiYq9nfQlBnX2NVaf8ymA8edQR0qH/QBv4/52bNNXC7V/V+ev9LCho2iRMeYYyXB -yo1wBAGR83lS9cF/tOABcYrxjdP54Sfkyh5fomcg8SV7zap6C8mhbV8r3EujbKCx -igH3fMX5F/eRwNCzaMMyQsXaxTJ3trk= +Dd++kOPlY5ZI9ZcFS7HLAgMBAAEwDQYJKoZIhvcNAQELBQADgYEATX7975NdhIbJ +glda+sXI9a86GgOpiuKO+vKubRJQZA+UlPf2vHEONjC2+7Y1aZvZYaKYL74vxGky +zkgp6ANSPl45lqD632x0e1Z7vzW5TkqK1JB2/xH2WgDcQZmP0FuQHzVNs4GjghDr +HCp1+sQDhfPB4aLmLFeyN0TkhdH1N3M= -----END CERTIFICATE----- From 5f46f5c50a8093536fc242da03b82f46c3035fc6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 30 Aug 2017 11:38:47 +0900 Subject: [PATCH 0073/1313] Update stream state after sending / receiving frames --- iocore/net/quic/QUICFrame.cc | 20 ++- iocore/net/quic/QUICFrame.h | 12 +- iocore/net/quic/QUICStream.cc | 2 +- iocore/net/quic/QUICStreamState.cc | 126 ++++++++++++++++++- iocore/net/quic/test/test_QUICStreamState.cc | 119 ++++++++++++++++-- 5 files changed, 256 insertions(+), 23 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index f0c0b5bbbf0..e99eda61f47 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -70,12 +70,13 @@ QUICFrame::reset(const uint8_t *buf, size_t len) // STREAM Frame // -QUICStreamFrame::QUICStreamFrame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset) +QUICStreamFrame::QUICStreamFrame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last) { this->_data = data; this->_data_len = data_len; this->_stream_id = stream_id; this->_offset = offset; + this->_fin = last; } QUICFrameType @@ -108,6 +109,11 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, bool include_length_field) con buf[0] = static_cast(QUICFrameType::STREAM); *len = 1; + // "F" of "11FSSOOD" + if (this->has_fin_flag()) { + buf[0] += (0x01 << 5); + } + // "SS" of "11FSSOOD" // use 32 bit length for now buf[0] += (0x03 << 3); @@ -1278,10 +1284,10 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) } std::unique_ptr -QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset) +QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last) { QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(data, data_len, stream_id, offset); + new (frame) QUICStreamFrame(data, data_len, stream_id, offset, last); return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_frame); } @@ -1333,6 +1339,14 @@ QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id) return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); } +std::unique_ptr +QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICErrorCode error_code, QUICOffset final_offset) +{ + QUICRstStreamFrame *frame = quicRstStreamFrameAllocator.alloc(); + new (frame) QUICRstStreamFrame(error_code, stream_id, final_offset); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_rst_stream_frame); +} + std::unique_ptr QUICFrameFactory::create_retransmission_frame(std::unique_ptr original_frame, const QUICPacket &original_packet) diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 11fcf033aca..0272a82d484 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -58,7 +58,7 @@ class QUICStreamFrame : public QUICFrame public: QUICStreamFrame() : QUICFrame() {} QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamFrame(const uint8_t *buf, size_t len, QUICStreamId streamid, QUICOffset offset); + QUICStreamFrame(const uint8_t *buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -589,7 +589,8 @@ class QUICFrameFactory * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ static std::unique_ptr create_stream_frame(const uint8_t *data, size_t data_len, - QUICStreamId stream_id, QUICOffset offset); + QUICStreamId stream_id, QUICOffset offset, + bool last = false); /* * Creates a ACK frame. * You shouldn't call this directly but through QUICAckFrameCreator because QUICAckFrameCreator manages packet numbers that we @@ -624,6 +625,13 @@ class QUICFrameFactory */ static std::unique_ptr create_stream_blocked_frame(QUICStreamId stream_id); + /* + * Creates a RST_STREAM frame. + */ + static std::unique_ptr create_rst_stream_frame(QUICStreamId stream_id, + QUICErrorCode error_code, + QUICOffset final_offset); + /* * Creates a retransmission frame, which is very special. * This retransmission frame will be used only for retransmission and it's not a standard frame type. diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index e77375f9b3e..79fd4e8c910 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -396,7 +396,7 @@ QUICStream::_send() total_len += len; if (!this->_state.is_allowed_to_send(*frame)) { - // FIXME: What should we do? + Debug(tag, "Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); break; } this->_state.update_with_sent_frame(*frame); diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index eb43130f282..2f78c3c7652 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -33,12 +33,52 @@ QUICStreamState::get() const bool QUICStreamState::is_allowed_to_send(const QUICFrame &frame) const { + switch (this->_state) { + case State::idle: + break; + case State::open: + break; + case State::half_closed_local: + if (frame.type() == QUICFrameType::STREAM) { + return false; + } + break; + case State::half_closed_remote: + break; + case State::closed: + // Once a stream reaches this state, no frames can be sent that mention the stream + if (frame.type() == QUICFrameType::STREAM) { + return false; + } else if (frame.type() == QUICFrameType::RST_STREAM) { + return false; + } else if (frame.type() == QUICFrameType::MAX_STREAM_DATA) { + return false; + } + break; + case State::illegal: + return false; + } return true; } bool QUICStreamState::is_allowed_to_receive(const QUICFrame &frame) const { + switch (this->_state) { + case State::idle: + break; + case State::open: + break; + case State::half_closed_local: + break; + case State::half_closed_remote: + break; + case State::closed: + // Reordering might cause frames to be received after closing + break; + case State::illegal: + return false; + } return true; } @@ -47,18 +87,46 @@ QUICStreamState::update_with_received_frame(const QUICFrame &frame) { switch (this->_state) { case State::idle: - this->_set_state(State::open); - // fall through - case State::open: { - if (frame.type() == QUICFrameType::STREAM && dynamic_cast(frame).has_fin_flag()) { + if (frame.type() == QUICFrameType::STREAM) { + if (static_cast(frame).has_fin_flag()) { + this->_set_state(State::half_closed_remote); + } else { + this->_set_state(State::open); + } + } else if (frame.type() == QUICFrameType::RST_STREAM) { this->_set_state(State::half_closed_remote); + } else if (frame.type() == QUICFrameType::MAX_STREAM_DATA || frame.type() == QUICFrameType::STREAM_BLOCKED) { + this->_set_state(State::open); + } else { + this->_set_state(State::illegal); + } + break; + case State::open: + if (frame.type() == QUICFrameType::STREAM) { + if (static_cast(frame).has_fin_flag()) { + this->_set_state(State::half_closed_remote); + } } else if (frame.type() == QUICFrameType::RST_STREAM) { - this->_set_state(State::closed); + this->_set_state(State::half_closed_remote); + } else { + this->_set_state(State::illegal); } - } break; + break; case State::half_closed_local: + if (frame.type() == QUICFrameType::STREAM) { + if (static_cast(frame).has_fin_flag()) { + this->_set_state(State::closed); + } + } else if (frame.type() == QUICFrameType::RST_STREAM) { + this->_set_state(State::closed); + } else { + this->_set_state(State::illegal); + } + break; case State::half_closed_remote: + break; case State::closed: + break; case State::illegal: // Once we get illegal state, no way to recover it break; @@ -70,6 +138,52 @@ QUICStreamState::update_with_received_frame(const QUICFrame &frame) void QUICStreamState::update_with_sent_frame(const QUICFrame &frame) { + switch (this->_state) { + case State::idle: + if (frame.type() == QUICFrameType::STREAM) { + if (static_cast(frame).has_fin_flag()) { + this->_set_state(State::half_closed_local); + } else { + this->_set_state(State::open); + } + } else if (frame.type() == QUICFrameType::RST_STREAM) { + this->_set_state(State::half_closed_local); + } else { + this->_set_state(State::illegal); + } + break; + case State::open: + if (frame.type() == QUICFrameType::STREAM) { + if (static_cast(frame).has_fin_flag()) { + this->_set_state(State::half_closed_local); + } + } else if (frame.type() == QUICFrameType::RST_STREAM) { + this->_set_state(State::half_closed_local); + } else { + this->_set_state(State::illegal); + } + break; + case State::half_closed_local: + break; + case State::half_closed_remote: + if (frame.type() == QUICFrameType::STREAM) { + if (static_cast(frame).has_fin_flag()) { + this->_set_state(State::closed); + } + } else if (frame.type() == QUICFrameType::RST_STREAM) { + this->_set_state(State::closed); + } else { + this->_set_state(State::illegal); + } + break; + case State::closed: + break; + case State::illegal: + // Once we get illegal state, no way to recover it + break; + default: + break; + } } void diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index 353cffd3263..a771f66b5c2 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -28,20 +28,117 @@ #include "quic/QUICFrame.h" #include "quic/QUICStreamState.h" -TEST_CASE("QUICStreamState_Update", "[quic]") +TEST_CASE("QUICStreamState_Idle", "[quic]") { - QUICStreamState ss; + auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::QUIC_TRANSPORT_ERROR, 0); + auto max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(0, 0); + auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0); - std::shared_ptr streamFrame = - std::make_shared(reinterpret_cast("foo"), 4, 1, 0); - std::shared_ptr rstStreamFrame = - std::make_shared(QUICErrorCode::QUIC_TRANSPORT_ERROR, 0, 0); + // Case1. Send STREAM + QUICStreamState ss1; + ss1.update_with_sent_frame(*stream_frame); + CHECK(ss1.get() == QUICStreamState::State::open); - CHECK(ss.get() == QUICStreamState::State::idle); + // Case2. Send RST_STREAM + QUICStreamState ss2; + ss2.update_with_sent_frame(*rst_stream_frame); + CHECK(ss2.get() == QUICStreamState::State::half_closed_local); - ss.update_with_received_frame(*streamFrame); - CHECK(ss.get() == QUICStreamState::State::open); + // Case3. Recv STREAM + QUICStreamState ss3; + ss3.update_with_received_frame(*stream_frame); + CHECK(ss3.get() == QUICStreamState::State::open); - ss.update_with_received_frame(*rstStreamFrame); - CHECK(ss.get() == QUICStreamState::State::closed); + // Case4. Recv RST_STREAM + QUICStreamState ss4; + ss4.update_with_received_frame(*rst_stream_frame); + CHECK(ss4.get() == QUICStreamState::State::half_closed_remote); + + // Case5. Recv MAX_STREAM_DATA + QUICStreamState ss5; + ss5.update_with_received_frame(*max_stream_data_frame); + CHECK(ss5.get() == QUICStreamState::State::open); + + // Case6. Recv STREAM_BLOCKED + QUICStreamState ss6; + ss6.update_with_received_frame(*stream_blocked_frame); + CHECK(ss6.get() == QUICStreamState::State::open); +} + +TEST_CASE("QUICStreamState_Open", "[quic]") +{ + auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); + auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::QUIC_TRANSPORT_ERROR, 0); + + // Case1. Send FIN in a STREAM + QUICStreamState ss1; + ss1.update_with_sent_frame(*stream_frame); // OPEN + CHECK(ss1.get() == QUICStreamState::State::open); + ss1.update_with_sent_frame(*stream_frame_with_fin); + CHECK(ss1.get() == QUICStreamState::State::half_closed_local); + + // Case2. Send RST_STREAM + QUICStreamState ss2; + ss2.update_with_sent_frame(*stream_frame); // OPEN + CHECK(ss2.get() == QUICStreamState::State::open); + ss2.update_with_sent_frame(*rst_stream_frame); + CHECK(ss2.get() == QUICStreamState::State::half_closed_local); + + // Case3. Recv FIN in a STREAM + QUICStreamState ss3; + ss3.update_with_received_frame(*stream_frame); // OPEN + CHECK(ss3.get() == QUICStreamState::State::open); + ss3.update_with_received_frame(*stream_frame_with_fin); + CHECK(ss3.get() == QUICStreamState::State::half_closed_remote); + + // Case4. Recv RST_STREAM + QUICStreamState ss4; + ss4.update_with_received_frame(*stream_frame); // OPEN + CHECK(ss4.get() == QUICStreamState::State::open); + ss4.update_with_received_frame(*rst_stream_frame); + CHECK(ss4.get() == QUICStreamState::State::half_closed_remote); +} + +TEST_CASE("QUICStreamState_Half_Closed_Remote", "[quic]") +{ + auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); + auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::QUIC_TRANSPORT_ERROR, 0); + + // Case1. Send FIN in a STREAM + QUICStreamState ss1; + ss1.update_with_received_frame(*stream_frame_with_fin); // HALF CLOSED REMOTE + CHECK(ss1.get() == QUICStreamState::State::half_closed_remote); + ss1.update_with_sent_frame(*stream_frame_with_fin); + CHECK(ss1.get() == QUICStreamState::State::closed); + + // Case2. Send RST + QUICStreamState ss2; + ss2.update_with_received_frame(*stream_frame_with_fin); // HALF CLOSED REMOTE + CHECK(ss2.get() == QUICStreamState::State::half_closed_remote); + ss2.update_with_sent_frame(*rst_stream_frame); + CHECK(ss2.get() == QUICStreamState::State::closed); +} + +TEST_CASE("QUICStreamState_Half_Closed_Local", "[quic]") +{ + auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); + auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::QUIC_TRANSPORT_ERROR, 0); + + // Case1. Recv FIN in a STREAM + QUICStreamState ss1; + ss1.update_with_sent_frame(*stream_frame_with_fin); // HALF CLOSED LOCAL + CHECK(ss1.get() == QUICStreamState::State::half_closed_local); + ss1.update_with_received_frame(*stream_frame_with_fin); + CHECK(ss1.get() == QUICStreamState::State::closed); + + // Case2. Recv RST + QUICStreamState ss2; + ss2.update_with_sent_frame(*stream_frame_with_fin); // HALF CLOSED LOCAL + CHECK(ss2.get() == QUICStreamState::State::half_closed_local); + ss2.update_with_received_frame(*rst_stream_frame); + CHECK(ss2.get() == QUICStreamState::State::closed); } From 08c398d158c6877f98fa0c981cc955536800dfd4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 30 Aug 2017 11:41:22 +0900 Subject: [PATCH 0074/1313] Propagate errors --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICStreamManager.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2b772b7c5ff..5d85ac302b6 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -505,7 +505,7 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_p // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing) if (packet->has_valid_fnv1a_hash()) { bool should_send_ack; - this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size(), should_send_ack); + error = this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size(), should_send_ack); } else { DebugQUICCon("Invalid FNV-1a hash value"); return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::CRYPTOGRAPHIC_ERROR); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index c1aed64caa0..6b62ebd1cf0 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -113,7 +113,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr_find_stream(frame->stream_id()); if (stream) { - stream->recv(frame); + return stream->recv(frame); } else { // TODO: connection error? } @@ -126,7 +126,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr_find_stream(frame->stream_id()); if (stream) { - stream->recv(frame); + return stream->recv(frame); } else { // TODO: connection error? } From d1cbe218accf9647e018c8a5a86ff3a93861c88e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 30 Aug 2017 12:41:47 +0900 Subject: [PATCH 0075/1313] Improve debug logs --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICDebugNames.cc | 21 +++++++++++++++++++++ iocore/net/quic/QUICDebugNames.h | 2 ++ iocore/net/quic/QUICFrameDispatcher.cc | 3 ++- iocore/net/quic/QUICStream.cc | 10 ++++++---- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5d85ac302b6..0effe5f47f5 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -296,6 +296,7 @@ QUICNetVConnection::state_pre_handshake(int event, Event *data) this->set_inactivity_timeout(HRTIME_SECONDS(params->no_activity_timeout_in())); this->add_to_active_queue(); + DebugQUICCon("Enter state_handshake"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_handshake); return this->handleEvent(event, data); } @@ -669,7 +670,6 @@ std::unique_ptr QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type) { std::unique_ptr packet(nullptr, &QUICPacketDeleter::delete_null_packet); - DebugQUICCon("retransmittable %u", retransmittable); switch (type) { case QUICPacketType::SERVER_CLEARTEXT: diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index dae5885cf51..66b686617de 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -177,3 +177,24 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) return "UNKNOWN"; } } + +const char * +QUICDebugNames::stream_state(QUICStreamState state) +{ + switch (state.get()) { + case QUICStreamState::State::idle: + return "IDLE"; + case QUICStreamState::State::open: + return "OPEN"; + case QUICStreamState::State::half_closed_remote: + return "HC_REMOTE"; + case QUICStreamState::State::half_closed_local: + return "HC_LOCAL"; + case QUICStreamState::State::closed: + return "CLOSED"; + case QUICStreamState::State::illegal: + return "ILLEGAL"; + default: + return "UNKNOWN"; + } +} diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index 20fcc717313..79702c6acf6 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -25,6 +25,7 @@ #include "QUICTypes.h" #include "QUICTransportParameters.h" +#include "QUICStreamState.h" class QUICDebugNames { @@ -34,6 +35,7 @@ class QUICDebugNames static const char *error_class(QUICErrorClass cls); static const char *error_code(QUICErrorCode code); static const char *transport_parameter_id(QUICTransportParameterId id); + static const char *stream_state(QUICStreamState state); // TODO: move to somewhere static const char *vc_event(int event); diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index eff5890600f..5b87cd11f2c 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -27,6 +27,7 @@ #include "QUICCongestionController.h" #include "QUICLossDetector.h" #include "QUICEvents.h" +#include "QUICDebugNames.h" static constexpr char tag[] = "quic_frame_handler"; @@ -62,7 +63,7 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size, bool // TODO: check debug build if (type != QUICFrameType::PADDING) { - Debug(tag, "frame type %d, size %zu", static_cast(frame->type()), frame->size()); + Debug(tag, "Received %s frame, size %zu", QUICDebugNames::frame_type(frame->type()), frame->size()); } should_send_ack |= (type != QUICFrameType::PADDING && type != QUICFrameType::ACK); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 79fd4e8c910..42db2039658 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -28,7 +28,8 @@ #include "QUICDebugNames.h" #include "QUICConfig.h" -static constexpr char tag[] = "quic_stream"; +#define DebugQUICStream(fmt, ...) \ + Debug("quic_stream", "[%" PRIx64 "] [%s] " fmt, static_cast(this->_id), QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) static constexpr uint64_t MAX_DATA_HEADSPACE = 10240; // in uints of octets static constexpr uint64_t MAX_STREAM_DATA_HEADSPACE = 1024; @@ -43,6 +44,7 @@ QUICStream::init(QUICStreamManager *manager, QUICFrameTransmitter *tx, QUICStrea init_flow_control_params(recv_max_stream_data, send_max_stream_data); this->mutex = new_ProxyMutex(); + DebugQUICStream("Initialized"); } void @@ -68,7 +70,7 @@ QUICStream::id() int QUICStream::main_event_handler(int event, void *data) { - Debug(tag, "%s", QUICDebugNames::vc_event(event)); + DebugQUICStream("%s", QUICDebugNames::vc_event(event)); switch (event) { case VC_EVENT_READ_READY: @@ -94,7 +96,7 @@ QUICStream::main_event_handler(int event, void *data) break; } default: - Debug(tag, "unknown event"); + DebugQUICStream("unknown event"); ink_assert(false); } @@ -396,7 +398,7 @@ QUICStream::_send() total_len += len; if (!this->_state.is_allowed_to_send(*frame)) { - Debug(tag, "Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); + DebugQUICStream("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); break; } this->_state.update_with_sent_frame(*frame); From 05de7b0180622c53527e5656a601ee3c1bd4e4d5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 30 Aug 2017 14:16:15 +0900 Subject: [PATCH 0076/1313] Fix trivial things --- iocore/net/quic/QUICStream.cc | 43 ++++++++++++++++++----------------- iocore/net/quic/QUICStream.h | 12 +++++----- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 42db2039658..c7f4615e0b7 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -28,8 +28,9 @@ #include "QUICDebugNames.h" #include "QUICConfig.h" -#define DebugQUICStream(fmt, ...) \ - Debug("quic_stream", "[%" PRIx64 "] [%s] " fmt, static_cast(this->_id), QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) +#define DebugQUICStream(fmt, ...) \ + Debug("quic_stream", "[%" PRIx64 "] [%s] " fmt, static_cast(this->_id), QUICDebugNames::stream_state(this->_state), \ + ##__VA_ARGS__) static constexpr uint64_t MAX_DATA_HEADSPACE = 10240; // in uints of octets static constexpr uint64_t MAX_STREAM_DATA_HEADSPACE = 1024; @@ -38,9 +39,9 @@ void QUICStream::init(QUICStreamManager *manager, QUICFrameTransmitter *tx, QUICStreamId id, uint64_t recv_max_stream_data, uint64_t send_max_stream_data) { - this->_streamManager = manager; - this->_tx = tx; - this->_id = id; + this->_stream_manager = manager; + this->_tx = tx; + this->_id = id; init_flow_control_params(recv_max_stream_data, send_max_stream_data); this->mutex = new_ProxyMutex(); @@ -56,12 +57,12 @@ QUICStream::start() void QUICStream::init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data) { - this->_recv_max_stream_data = recv_max_stream_data; - this->_recv_max_stream_data_deleta = recv_max_stream_data; - this->_send_max_stream_data = send_max_stream_data; + this->_recv_max_stream_data = recv_max_stream_data; + this->_recv_max_stream_data_delta = recv_max_stream_data; + this->_send_max_stream_data = send_max_stream_data; } -uint32_t +QUICStreamId QUICStream::id() { return this->_id; @@ -316,8 +317,8 @@ void QUICStream::_slide_recv_max_stream_data() { // TODO: How much should this be increased? - this->_recv_max_stream_data += this->_recv_max_stream_data_deleta; - this->_streamManager->send_frame(QUICFrameFactory::create_max_stream_data_frame(this->_id, this->_recv_max_stream_data)); + this->_recv_max_stream_data += this->_recv_max_stream_data_delta; + this->_stream_manager->send_frame(QUICFrameFactory::create_max_stream_data_frame(this->_id, this->_recv_max_stream_data)); } QUICError @@ -330,20 +331,20 @@ QUICStream::_recv_flow_control(uint64_t new_offset) uint64_t delta = new_offset - this->_recv_largest_offset; Debug("quic_flow_ctrl", "Con: %" PRIu64 "/%" PRIu64 " Stream: %" PRIu64 "/%" PRIu64, - (this->_streamManager->recv_total_offset() + delta) / 1024, this->_streamManager->recv_max_data(), new_offset, + (this->_stream_manager->recv_total_offset() + delta) / 1024, this->_stream_manager->recv_max_data(), new_offset, this->_recv_max_stream_data); // Connection Level Flow Control if (this->_id != STREAM_ID_FOR_HANDSHAKE) { - if (!this->_streamManager->is_recv_avail_more_than(delta)) { + if (!this->_stream_manager->is_recv_avail_more_than(delta)) { return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); } - if (!this->_streamManager->is_recv_avail_more_than(delta + MAX_DATA_HEADSPACE)) { - this->_streamManager->slide_recv_max_data(); + if (!this->_stream_manager->is_recv_avail_more_than(delta + MAX_DATA_HEADSPACE)) { + this->_stream_manager->slide_recv_max_data(); } - this->_streamManager->add_recv_total_offset(delta); + this->_stream_manager->add_recv_total_offset(delta); } // Stream Level Flow Control @@ -402,7 +403,7 @@ QUICStream::_send() break; } this->_state.update_with_sent_frame(*frame); - this->_streamManager->send_frame(std::move(frame)); + this->_stream_manager->send_frame(std::move(frame)); } return; @@ -412,21 +413,21 @@ bool QUICStream::_send_flow_control(uint64_t len) { Debug("quic_flow_ctrl", "Con: %" PRIu64 "/%" PRIu64 " Stream: %" PRIu64 "/%" PRIu64, - (this->_streamManager->send_total_offset() + len) / 1024, this->_streamManager->send_max_data(), this->_send_offset + len, + (this->_stream_manager->send_total_offset() + len) / 1024, this->_stream_manager->send_max_data(), this->_send_offset + len, this->_send_max_stream_data); // Stream Level Flow Control // TODO: remove check of _send_max_stream_data when moved to Second Implementation completely if (this->_send_max_stream_data > 0 && len > this->_send_max_stream_data) { - this->_streamManager->send_frame(QUICFrameFactory::create_stream_blocked_frame(this->_id)); + this->_stream_manager->send_frame(QUICFrameFactory::create_stream_blocked_frame(this->_id)); return false; } // Connection Level Flow Control if (this->_id != STREAM_ID_FOR_HANDSHAKE) { - if (!this->_streamManager->is_send_avail_more_than(len)) { - this->_streamManager->send_frame(QUICFrameFactory::create_blocked_frame()); + if (!this->_stream_manager->is_send_avail_more_than(len)) { + this->_stream_manager->send_frame(QUICFrameFactory::create_blocked_frame()); return false; } diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index b2110d58469..e3c6d9cb899 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -50,7 +50,7 @@ class QUICStream : public VConnection void init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data); int main_event_handler(int event, void *data); - uint32_t id(); + QUICStreamId id(); // Implement VConnection interface. VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) override; @@ -94,9 +94,9 @@ class QUICStream : public VConnection QUICOffset _recv_largest_offset = 0; QUICOffset _send_offset = 0; - uint64_t _recv_max_stream_data = 0; - uint64_t _recv_max_stream_data_deleta = 0; - uint64_t _send_max_stream_data = 0; + uint64_t _recv_max_stream_data = 0; + uint64_t _recv_max_stream_data_delta = 0; + uint64_t _send_max_stream_data = 0; VIO _read_vio; VIO _write_vio; @@ -108,6 +108,6 @@ class QUICStream : public VConnection // TODO: Consider to replace with ts/RbTree.h or other data structure std::map> _request_stream_frame_buffer; - QUICStreamManager *_streamManager = nullptr; - QUICFrameTransmitter *_tx = nullptr; + QUICStreamManager *_stream_manager = nullptr; + QUICFrameTransmitter *_tx = nullptr; }; From f0f998cc16f6e4e4368ff8244430e906fc0b81f4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Sep 2017 16:45:19 +0900 Subject: [PATCH 0077/1313] Reimplement flow control with QUICFlowController --- .gitignore | 1 + iocore/net/P_QUICNetVConnection.h | 18 +- iocore/net/QUICNetVConnection.cc | 83 +++++- iocore/net/quic/Makefile.am | 1 + iocore/net/quic/Mock.h | 7 +- iocore/net/quic/QUICFlowController.cc | 122 +++++++++ iocore/net/quic/QUICFlowController.h | 106 ++++++++ iocore/net/quic/QUICStream.cc | 168 +++++------- iocore/net/quic/QUICStream.h | 29 +- iocore/net/quic/QUICStreamManager.cc | 99 +++---- iocore/net/quic/QUICStreamManager.h | 14 +- iocore/net/quic/test/Makefile.am | 35 ++- .../net/quic/test/test_QUICFlowController.cc | 252 ++++++++++++++++++ iocore/net/quic/test/test_QUICStream.cc | 9 +- 14 files changed, 731 insertions(+), 213 deletions(-) create mode 100644 iocore/net/quic/QUICFlowController.cc create mode 100644 iocore/net/quic/QUICFlowController.h create mode 100644 iocore/net/quic/test/test_QUICFlowController.cc diff --git a/.gitignore b/.gitignore index a5a618f9733..e68e278aa25 100644 --- a/.gitignore +++ b/.gitignore @@ -99,6 +99,7 @@ iocore/net/quic/test/test_QUICLossDetector iocore/net/quic/test/test_QUICTypeUtil iocore/net/quic/test/test_QUICAckFrameCreator iocore/net/quic/test/test_QUICVersionNegotiator +iocore/net/quic/test/test_QUICFlowController iocore/net/quic/ts_quic_client iocore/aio/test_AIO iocore/eventsystem/test_Buffer diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index f256d78dd9d..8ee7cdfd93c 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -203,13 +203,15 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // TODO: use custom allocator and make them std::unique_ptr or std::shared_ptr // or make them just member variables. - QUICVersionNegotiator *_version_negotiator = nullptr; - QUICHandshake *_handshake_handler = nullptr; - QUICCrypto *_crypto = nullptr; - QUICLossDetector *_loss_detector = nullptr; - QUICFrameDispatcher *_frame_dispatcher = nullptr; - QUICStreamManager *_stream_manager = nullptr; - QUICCongestionController *_congestion_controller = nullptr; + QUICVersionNegotiator *_version_negotiator = nullptr; + QUICHandshake *_handshake_handler = nullptr; + QUICCrypto *_crypto = nullptr; + QUICLossDetector *_loss_detector = nullptr; + QUICFrameDispatcher *_frame_dispatcher = nullptr; + QUICStreamManager *_stream_manager = nullptr; + QUICCongestionController *_congestion_controller = nullptr; + QUICRemoteFlowController *_remote_flow_controller = nullptr; + QUICLocalFlowController *_local_flow_controller = nullptr; Queue _packet_recv_queue; Queue _packet_send_queue; @@ -231,6 +233,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection Ptr _transmitter_mutex; QUICApplication *_create_application(); + void _init_flow_control_params(const std::shared_ptr &local_tp, + const std::shared_ptr &remote_tp); }; extern ClassAllocator quicNetVCAllocator; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 0effe5f47f5..f5a15ba039b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -104,14 +104,19 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) this->_packet_factory.set_crypto_module(this->_crypto); // Create frame handlers - this->_stream_manager = new QUICStreamManager(this, this->_application_map); - this->_congestion_controller = new QUICCongestionController(); - this->_loss_detector = new QUICLossDetector(this); + this->_stream_manager = new QUICStreamManager(this, this->_application_map); + this->_congestion_controller = new QUICCongestionController(); + this->_loss_detector = new QUICLossDetector(this); + this->_remote_flow_controller = new QUICRemoteConnectionFlowController(0, this); + this->_local_flow_controller = new QUICLocalConnectionFlowController(0, this); this->_frame_dispatcher->add_handler(this); this->_frame_dispatcher->add_handler(this->_stream_manager); this->_frame_dispatcher->add_handler(this->_congestion_controller); this->_frame_dispatcher->add_handler(this->_loss_detector); + + this->_init_flow_control_params(this->_handshake_handler->local_transport_parameters(), + this->_handshake_handler->remote_transport_parameters()); } void @@ -255,7 +260,7 @@ QUICNetVConnection::close(QUICError error) std::vector QUICNetVConnection::interests() { - return {QUICFrameType::CONNECTION_CLOSE}; + return {QUICFrameType::CONNECTION_CLOSE, QUICFrameType::BLOCKED, QUICFrameType::MAX_DATA}; } QUICError @@ -264,6 +269,15 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) QUICError error = QUICError(QUICErrorClass::NONE); switch (frame->type()) { + case QUICFrameType::MAX_DATA: + this->_remote_flow_controller->forward_limit(std::static_pointer_cast(frame)->maximum_data()); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, + static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); + break; + case QUICFrameType::BLOCKED: + // BLOCKED frame is for debugging. Nothing to do here. + break; case QUICFrameType::CONNECTION_CLOSE: DebugQUICCon("Enter state_connection_closed"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); @@ -358,8 +372,8 @@ QUICNetVConnection::state_handshake(int event, Event *data) if (this->_handshake_handler && this->_handshake_handler->is_completed()) { this->_application_map->set_default(this->_create_application()); - this->_stream_manager->init_flow_control_params(this->_handshake_handler->local_transport_parameters(), - this->_handshake_handler->remote_transport_parameters()); + this->_init_flow_control_params(this->_handshake_handler->local_transport_parameters(), + this->_handshake_handler->remote_transport_parameters()); DebugQUICCon("Enter state_connection_established"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); @@ -507,6 +521,16 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_p if (packet->has_valid_fnv1a_hash()) { bool should_send_ack; error = this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size(), should_send_ack); + if (error.cls != QUICErrorClass::NONE) { + return error; + } + error = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, + static_cast(this->_quic_connection_id), this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); + if (error.cls != QUICErrorClass::NONE) { + return error; + } } else { DebugQUICCon("Invalid FNV-1a hash value"); return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::CRYPTOGRAPHIC_ERROR); @@ -586,6 +610,13 @@ QUICNetVConnection::_state_common_send_packet() this->_packetize_frames(); QUICPacket *packet; + QUICError error = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, + static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); + if (error.cls != QUICErrorClass::NONE) { + return error; + } while ((packet = this->_packet_send_queue.dequeue()) != nullptr) { this->_packet_handler->send_packet(*packet, this); this->_loss_detector->on_packet_sent( @@ -654,7 +685,21 @@ QUICError QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_num) { bool should_send_ack; - QUICError error = this->_frame_dispatcher->receive_frames(payload, size, should_send_ack); + + QUICError error; + + error = this->_frame_dispatcher->receive_frames(payload, size, should_send_ack); + if (error.cls != QUICErrorClass::NONE) { + return error; + } + + error = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), + this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); + if (error.cls != QUICErrorClass::NONE) { + return error; + } + // this->_local_flow_controller->forward_limit(); this->_ack_frame_creator.update(packet_num, should_send_ack); std::unique_ptr ack_frame = this->_ack_frame_creator.create_if_needed(); @@ -709,3 +754,27 @@ QUICNetVConnection::_create_application() return nullptr; } } + +void +QUICNetVConnection::_init_flow_control_params(const std::shared_ptr &local_tp, + const std::shared_ptr &remote_tp) +{ + this->_stream_manager->init_flow_control_params(local_tp, remote_tp); + + uint32_t local_initial_max_data = 0; + uint32_t remote_initial_max_data = 0; + if (local_tp) { + local_initial_max_data = local_tp->initial_max_data(); + } + if (remote_tp) { + remote_initial_max_data = remote_tp->initial_max_data(); + } + + this->_local_flow_controller->forward_limit(local_initial_max_data); + this->_remote_flow_controller->forward_limit(remote_initial_max_data); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), + this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, + static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); +} diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index fda10cd8b1e..40d76384e8d 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -49,6 +49,7 @@ libquic_a_SOURCES = \ QUICLossDetector.cc \ QUICStreamManager.cc \ QUICCongestionController.cc \ + QUICFlowController.cc \ QUICStreamState.cc \ QUICStream.cc \ QUICHandshake.cc \ diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 54ee271b8ac..dd538e2d587 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -223,16 +223,20 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter class MockQUICFrameTransmitter : public QUICFrameTransmitter { +public: void transmit_frame(std::unique_ptr frame) override { + ++frameCount[static_cast(frame->type())]; } uint32_t maximum_stream_frame_data_size() override { - return 1160; + return 1200; } + + int frameCount[256] = {0}; }; class MockQUICLossDetector : public QUICLossDetector @@ -289,7 +293,6 @@ class MockQUICStreamManager : public QUICStreamManager return _totalFrameCount; } - bool is_recv_avail_more_than(uint64_t /* size */) override { return true; } void send_frame(std::unique_ptr /* frame */) override { return; } private: diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc new file mode 100644 index 00000000000..ec277e56234 --- /dev/null +++ b/iocore/net/quic/QUICFlowController.cc @@ -0,0 +1,122 @@ +/** @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 "QUICFlowController.h" +#include "QUICFrame.h" +#include "QUICFrameTransmitter.h" + +QUICOffset +QUICFlowController::current_offset() +{ + return this->_offset; +} + +QUICOffset +QUICFlowController::current_limit() +{ + return this->_limit; +} + +QUICError +QUICFlowController::update(QUICOffset offset) +{ + if (this->_offset <= offset) { + // Assume flow control is not initialized if the limit was 0 + if (this->_limit != 0 && offset > this->_limit) { + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); + } + this->_offset = offset; + } + + return QUICError(QUICErrorClass::NONE); +} + +void +QUICFlowController::forward_limit(QUICOffset limit) +{ + // MAX_(STREAM_)DATA might be unorderd due to delay + // Just ignore if the size was smaller than the last one + if (this->_limit > limit) { + return; + } + this->_limit = limit; +} + +void +QUICFlowController::set_threshold(uint64_t threshold) +{ + this->_threshold = threshold; +} + +QUICError +QUICRemoteFlowController::update(QUICOffset offset) +{ + QUICError error = QUICFlowController::update(offset); + + // Assume flow control is not initialized if the limit was 0 + if (this->_limit == 0) { + return error; + } + + // Send BLOCKED(_STREAM) frame + if (offset > this->_limit) { + this->_tx->transmit_frame(this->_create_frame()); + } + + return error; +} + +void +QUICLocalFlowController::forward_limit(QUICOffset offset) +{ + QUICFlowController::forward_limit(offset); + + // Send MAX_(STREAM_)DATA frame + if (this->_limit - this->_offset <= this->_threshold) { + this->_tx->transmit_frame(this->_create_frame()); + } +} + +std::unique_ptr +QUICRemoteConnectionFlowController::_create_frame() +{ + return QUICFrameFactory::create_blocked_frame(); +} + +std::unique_ptr +QUICLocalConnectionFlowController::_create_frame() +{ + return QUICFrameFactory::create_max_data_frame(this->_limit); +} + +std::unique_ptr +QUICRemoteStreamFlowController::_create_frame() +{ + return QUICFrameFactory::create_stream_blocked_frame(this->_stream_id); +} + +std::unique_ptr +QUICLocalStreamFlowController::_create_frame() +{ + return QUICFrameFactory::create_max_stream_data_frame(this->_stream_id, this->_limit); +} diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h new file mode 100644 index 00000000000..d9b9eff925a --- /dev/null +++ b/iocore/net/quic/QUICFlowController.h @@ -0,0 +1,106 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICTypes.h" +#include "QUICFrame.h" + +class QUICFrameTransmitter; + +class QUICFlowController +{ +public: + QUICOffset current_offset(); + QUICOffset current_limit(); + virtual QUICError update(QUICOffset offset); + virtual void forward_limit(QUICOffset limit); + void set_threshold(uint64_t threshold); + +protected: + QUICFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : _limit(initial_limit), _tx(tx) {} + virtual std::unique_ptr _create_frame() = 0; + + QUICOffset _offset = 0; + QUICOffset _limit = 0; + QUICOffset _threshold = 1024; + QUICFrameTransmitter *_tx = nullptr; +}; + +class QUICRemoteFlowController : public QUICFlowController +{ +public: + QUICRemoteFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICFlowController(initial_limit, tx) {} + QUICError update(QUICOffset offset) override; +}; + +class QUICLocalFlowController : public QUICFlowController +{ +public: + QUICLocalFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICFlowController(initial_limit, tx) {} + void forward_limit(QUICOffset limit) override; +}; + +class QUICRemoteConnectionFlowController : public QUICRemoteFlowController +{ +public: + QUICRemoteConnectionFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICRemoteFlowController(initial_limit, tx) + { + } + std::unique_ptr _create_frame() override; +}; + +class QUICLocalConnectionFlowController : public QUICLocalFlowController +{ +public: + QUICLocalConnectionFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICLocalFlowController(initial_limit, tx) + { + } + std::unique_ptr _create_frame() override; +}; + +class QUICRemoteStreamFlowController : public QUICRemoteFlowController +{ +public: + QUICRemoteStreamFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx, QUICStreamId stream_id) + : QUICRemoteFlowController(initial_limit, tx), _stream_id(stream_id) + { + } + std::unique_ptr _create_frame() override; + +private: + QUICStreamId _stream_id = 0; +}; + +class QUICLocalStreamFlowController : public QUICLocalFlowController +{ +public: + QUICLocalStreamFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx, QUICStreamId stream_id) + : QUICLocalFlowController(initial_limit, tx), _stream_id(stream_id) + { + } + std::unique_ptr _create_frame() override; + +private: + QUICStreamId _stream_id = 0; +}; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index c7f4615e0b7..f03dd8ad7eb 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -28,23 +28,21 @@ #include "QUICDebugNames.h" #include "QUICConfig.h" -#define DebugQUICStream(fmt, ...) \ - Debug("quic_stream", "[%" PRIx64 "] [%s] " fmt, static_cast(this->_id), QUICDebugNames::stream_state(this->_state), \ - ##__VA_ARGS__) - -static constexpr uint64_t MAX_DATA_HEADSPACE = 10240; // in uints of octets -static constexpr uint64_t MAX_STREAM_DATA_HEADSPACE = 1024; +#define DebugQUICStream(fmt, ...) \ + Debug("quic_stream", "[%" PRIx32 "] [%s] " fmt, this->_id, QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) void QUICStream::init(QUICStreamManager *manager, QUICFrameTransmitter *tx, QUICStreamId id, uint64_t recv_max_stream_data, uint64_t send_max_stream_data) { - this->_stream_manager = manager; - this->_tx = tx; - this->_id = id; - init_flow_control_params(recv_max_stream_data, send_max_stream_data); + this->mutex = new_ProxyMutex(); + this->_stream_manager = manager; + this->_tx = tx; + this->_id = id; + this->_remote_flow_controller = new QUICRemoteStreamFlowController(send_max_stream_data, _tx, _id); + this->_local_flow_controller = new QUICLocalStreamFlowController(recv_max_stream_data, _tx, _id); + this->init_flow_control_params(recv_max_stream_data, send_max_stream_data); - this->mutex = new_ProxyMutex(); DebugQUICStream("Initialized"); } @@ -57,9 +55,15 @@ QUICStream::start() void QUICStream::init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data) { - this->_recv_max_stream_data = recv_max_stream_data; - this->_recv_max_stream_data_delta = recv_max_stream_data; - this->_send_max_stream_data = send_max_stream_data; + this->_flow_control_buffer_size = recv_max_stream_data; + this->_local_flow_controller->forward_limit(recv_max_stream_data); + this->_remote_flow_controller->forward_limit(send_max_stream_data); + Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [LOCAL] %" PRIu64 "/%" PRIu64, this->_id, + QUICDebugNames::stream_state(this->_state), this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); + Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [REMOTE] %" PRIu64 "/%" PRIu64, this->_id, + QUICDebugNames::stream_state(this->_state), this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); } QUICStreamId @@ -72,6 +76,7 @@ int QUICStream::main_event_handler(int event, void *data) { DebugQUICStream("%s", QUICDebugNames::vc_event(event)); + QUICError error; switch (event) { case VC_EVENT_READ_READY: @@ -83,7 +88,7 @@ QUICStream::main_event_handler(int event, void *data) } case VC_EVENT_WRITE_READY: case VC_EVENT_WRITE_COMPLETE: { - this->_send(); + error = this->_send(); this->_signal_write_event(true); this->_write_event = nullptr; @@ -101,6 +106,12 @@ QUICStream::main_event_handler(int event, void *data) ink_assert(false); } + if (error.cls != QUICErrorClass::NONE) { + // TODO Send error if needed + DebugQUICStream("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error.cls), static_cast(error.cls), + QUICDebugNames::error_code(error.code), static_cast(error.code)); + } + return EVENT_CONT; } @@ -247,6 +258,10 @@ QUICStream::_write_to_read_vio(const std::shared_ptr &fra int bytes_added = this->_read_vio.buffer.writer()->write(frame->data(), frame->data_length()); this->_read_vio.nbytes += bytes_added; this->_recv_offset += frame->data_length(); + this->_local_flow_controller->forward_limit(frame->offset() + this->_flow_control_buffer_size); + Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [LOCAL] %" PRIu64 "/%" PRIu64, this->_id, + QUICDebugNames::stream_state(this->_state), this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); } void @@ -266,24 +281,28 @@ QUICStream::_reorder_data() * which is called by application via do_io_read() or reenable(). */ QUICError -QUICStream::recv(std::shared_ptr frame) +QUICStream::recv(const std::shared_ptr frame) { ink_assert(_id == frame->stream_id()); ink_assert(this->_read_vio.op == VIO::READ); + // Check stream state - Do this first before accept the frame if (!this->_state.is_allowed_to_receive(*frame)) { this->reset(); return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); } this->_state.update_with_received_frame(*frame); - // Flow Control - QUICError error = this->_recv_flow_control(frame->offset()); + // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit + QUICError error = this->_local_flow_controller->update(frame->offset() + frame->data_length()); + Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [LOCAL] %" PRIu64 "/%" PRIu64, this->_id, + QUICDebugNames::stream_state(this->_state), this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); if (error.cls != QUICErrorClass::NONE) { return error; } - // Reordering + // Reordering - Some frames may be delayed or be dropped if (this->_recv_offset > frame->offset()) { // Do nothing. Just ignore STREAM frame. return QUICError(QUICErrorClass::NONE); @@ -300,77 +319,31 @@ QUICStream::recv(std::shared_ptr frame) } QUICError -QUICStream::recv(const std::shared_ptr &frame) +QUICStream::recv(const std::shared_ptr frame) { - this->_send_max_stream_data += frame->maximum_stream_data(); + this->_remote_flow_controller->forward_limit(frame->maximum_stream_data()); + Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [REMOTE] %" PRIu64 "/%" PRIu64, this->_id, + QUICDebugNames::stream_state(this->_state), this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); return QUICError(QUICErrorClass::NONE); } QUICError -QUICStream::recv(const std::shared_ptr &frame) -{ - this->_slide_recv_max_stream_data(); - return QUICError(QUICErrorClass::NONE); -} - -void -QUICStream::_slide_recv_max_stream_data() -{ - // TODO: How much should this be increased? - this->_recv_max_stream_data += this->_recv_max_stream_data_delta; - this->_stream_manager->send_frame(QUICFrameFactory::create_max_stream_data_frame(this->_id, this->_recv_max_stream_data)); -} - -QUICError -QUICStream::_recv_flow_control(uint64_t new_offset) +QUICStream::recv(const std::shared_ptr frame) { - if (this->_recv_largest_offset > new_offset) { - return QUICError(QUICErrorClass::NONE); - } - - uint64_t delta = new_offset - this->_recv_largest_offset; - - Debug("quic_flow_ctrl", "Con: %" PRIu64 "/%" PRIu64 " Stream: %" PRIu64 "/%" PRIu64, - (this->_stream_manager->recv_total_offset() + delta) / 1024, this->_stream_manager->recv_max_data(), new_offset, - this->_recv_max_stream_data); - - // Connection Level Flow Control - if (this->_id != STREAM_ID_FOR_HANDSHAKE) { - if (!this->_stream_manager->is_recv_avail_more_than(delta)) { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); - } - - if (!this->_stream_manager->is_recv_avail_more_than(delta + MAX_DATA_HEADSPACE)) { - this->_stream_manager->slide_recv_max_data(); - } - - this->_stream_manager->add_recv_total_offset(delta); - } - - // Stream Level Flow Control - if (this->_recv_max_stream_data > 0) { - if (this->_recv_max_stream_data < new_offset) { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); - } - - if (this->_recv_max_stream_data < new_offset + MAX_STREAM_DATA_HEADSPACE) { - this->_slide_recv_max_stream_data(); - } - } - - this->_recv_largest_offset = new_offset; - + // STREAM_BLOCKED frames are for debugging. Nothing to do here. return QUICError(QUICErrorClass::NONE); } /** * @brief Send STREAM DATA from _response_buffer */ -void +QUICError QUICStream::_send() { SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); + QUICError error; IOBufferReader *reader = this->_write_vio.get_reader(); int64_t bytes_avail = reader->read_avail(); int64_t total_len = 0; @@ -386,7 +359,11 @@ QUICStream::_send() len = data_len; } - if (!this->_send_flow_control(len)) { + QUICError error = this->_remote_flow_controller->update(this->_send_offset + len); + Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [REMOTE] %" PRIu64 "/%" PRIu64, this->_id, + QUICDebugNames::stream_state(this->_state), this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); + if (error.cls != QUICErrorClass::NONE) { break; } @@ -406,34 +383,7 @@ QUICStream::_send() this->_stream_manager->send_frame(std::move(frame)); } - return; -} - -bool -QUICStream::_send_flow_control(uint64_t len) -{ - Debug("quic_flow_ctrl", "Con: %" PRIu64 "/%" PRIu64 " Stream: %" PRIu64 "/%" PRIu64, - (this->_stream_manager->send_total_offset() + len) / 1024, this->_stream_manager->send_max_data(), this->_send_offset + len, - this->_send_max_stream_data); - - // Stream Level Flow Control - // TODO: remove check of _send_max_stream_data when moved to Second Implementation completely - if (this->_send_max_stream_data > 0 && len > this->_send_max_stream_data) { - this->_stream_manager->send_frame(QUICFrameFactory::create_stream_blocked_frame(this->_id)); - - return false; - } - - // Connection Level Flow Control - if (this->_id != STREAM_ID_FOR_HANDSHAKE) { - if (!this->_stream_manager->is_send_avail_more_than(len)) { - this->_stream_manager->send_frame(QUICFrameFactory::create_blocked_frame()); - - return false; - } - } - - return true; + return error; } void @@ -447,3 +397,15 @@ QUICStream::is_read_ready() { return this->_read_vio.nbytes > 0; } + +QUICOffset +QUICStream::largest_offset_received() +{ + return this->_local_flow_controller->current_offset(); +} + +QUICOffset +QUICStream::largest_offset_sent() +{ + return this->_remote_flow_controller->current_offset(); +} diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index e3c6d9cb899..2f28c90a677 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -30,6 +30,7 @@ #include "QUICFrame.h" #include "QUICStreamState.h" +#include "QUICFlowController.h" class QUICFrameTransmitter; class QUICStreamState; @@ -59,20 +60,23 @@ class QUICStream : public VConnection void do_io_shutdown(ShutdownHowTo_t howto) override; void reenable(VIO *vio) override; - QUICError recv(std::shared_ptr frame); - QUICError recv(const std::shared_ptr &frame); - QUICError recv(const std::shared_ptr &frame); + QUICError recv(const std::shared_ptr frame); + QUICError recv(const std::shared_ptr frame); + QUICError recv(const std::shared_ptr frame); void reset(); bool is_read_ready(); + QUICOffset largest_offset_received(); + QUICOffset largest_offset_sent(); + LINK(QUICStream, link); private: QUICStreamState _state; - void _send(); + QUICError _send(); void _write_to_read_vio(const std::shared_ptr &); void _reorder_data(); @@ -85,18 +89,13 @@ class QUICStream : public VConnection Event *_send_tracked_event(Event *event, int send_event, VIO *vio); - void _slide_recv_max_stream_data(); - QUICError _recv_flow_control(uint64_t new_offset); - bool _send_flow_control(uint64_t len); - - QUICStreamId _id = 0; - QUICOffset _recv_offset = 0; - QUICOffset _recv_largest_offset = 0; - QUICOffset _send_offset = 0; + QUICStreamId _id = 0; + QUICOffset _recv_offset = 0; + QUICOffset _send_offset = 0; - uint64_t _recv_max_stream_data = 0; - uint64_t _recv_max_stream_data_delta = 0; - uint64_t _send_max_stream_data = 0; + QUICRemoteStreamFlowController *_remote_flow_controller; + QUICLocalStreamFlowController *_local_flow_controller; + uint64_t _flow_control_buffer_size = 1024; VIO _read_vio; VIO _write_vio; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 6b62ebd1cf0..035da95e204 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -39,8 +39,9 @@ QUICStreamManager::QUICStreamManager(QUICFrameTransmitter *tx, QUICApplicationMa std::vector QUICStreamManager::interests() { - return {QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::MAX_DATA, QUICFrameType::MAX_STREAM_DATA, - QUICFrameType::BLOCKED}; + return { + QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::MAX_STREAM_DATA, + }; } void @@ -50,13 +51,19 @@ QUICStreamManager::init_flow_control_params(const std::shared_ptr_local_tp = local_tp; this->_remote_tp = remote_tp; - // Connection level - this->_recv_max_data = QUICMaximumData(local_tp->initial_max_data()); - this->_send_max_data = QUICMaximumData(remote_tp->initial_max_data()); - // Setup a stream for Handshake QUICStream *stream = this->_find_stream(STREAM_ID_FOR_HANDSHAKE); - stream->init_flow_control_params(local_tp->initial_max_stream_data(), remote_tp->initial_max_stream_data()); + if (stream) { + uint32_t local_initial_max_stream_data = 0; + uint32_t remote_initial_max_stream_data = 0; + if (this->_local_tp) { + local_initial_max_stream_data = local_tp->initial_max_stream_data(); + } + if (this->_remote_tp) { + remote_initial_max_stream_data = remote_tp->initial_max_stream_data(); + } + stream->init_flow_control_params(local_initial_max_stream_data, remote_initial_max_stream_data); + } } QUICError @@ -65,19 +72,12 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) QUICError error = QUICError(QUICErrorClass::NONE); switch (frame->type()) { - case QUICFrameType::MAX_DATA: { - error = this->_handle_frame(std::dynamic_pointer_cast(frame)); - break; - } - case QUICFrameType::BLOCKED: { - this->slide_recv_max_data(); - break; - } case QUICFrameType::MAX_STREAM_DATA: { error = this->_handle_frame(std::dynamic_pointer_cast(frame)); break; } case QUICFrameType::STREAM_BLOCKED: { + // STREAM_BLOCKED frame is for debugging. Just propagate to streams error = this->_handle_frame(std::dynamic_pointer_cast(frame)); break; } @@ -93,21 +93,6 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) return error; } -QUICError -QUICStreamManager::_handle_frame(const std::shared_ptr &frame) -{ - this->_send_max_data = frame->maximum_data(); - return QUICError(QUICErrorClass::NONE); -} - -void -QUICStreamManager::slide_recv_max_data() -{ - // TODO: How much should this be increased? - this->_recv_max_data += this->_local_tp->initial_max_data(); - this->send_frame(QUICFrameFactory::create_max_data_frame(this->_recv_max_data)); -} - QUICError QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { @@ -159,9 +144,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr &f void QUICStreamManager::send_frame(std::unique_ptr frame) { - // XXX The offset of sending frame is always largest offset by sending side if (frame->stream_id() != STREAM_ID_FOR_HANDSHAKE) { - this->_send_total_offset += frame->size(); } this->_tx->transmit_frame(std::move(frame)); @@ -179,24 +162,6 @@ QUICStreamManager::send_frame(std::unique_ptr f return; } -bool -QUICStreamManager::is_send_avail_more_than(uint64_t size) -{ - return this->_send_max_data > (this->_send_total_offset + size); -} - -bool -QUICStreamManager::is_recv_avail_more_than(uint64_t size) -{ - return this->_recv_max_data > (this->_recv_total_offset + size); -} - -void -QUICStreamManager::add_recv_total_offset(uint64_t delta) -{ - this->_recv_total_offset += delta; -} - QUICStream * QUICStreamManager::_find_stream(QUICStreamId id) { @@ -217,7 +182,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) stream = THREAD_ALLOC_INIT(quicStreamAllocator, this_ethread()); if (stream_id == STREAM_ID_FOR_HANDSHAKE) { // XXX rece/send max_stream_data are going to be set by init_flow_control_params() - stream->init(this, this->_tx, stream_id); + stream->init(this, this->_tx, stream_id, this->_local_tp->initial_max_stream_data()); } else { const QUICTransportParameters &local_tp = *this->_local_tp; const QUICTransportParameters &remote_tp = *this->_remote_tp; @@ -234,25 +199,29 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) } uint64_t -QUICStreamManager::recv_max_data() const +QUICStreamManager::total_offset_received() const { - return this->_recv_max_data; -} + uint64_t total_offset_received = 0; -uint64_t -QUICStreamManager::send_max_data() const -{ - return this->_send_max_data; + // FIXME Iterating all (open + closed) streams is expensive + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + if (s->id() != 0) { + total_offset_received += s->largest_offset_received(); + } + } + return total_offset_received; } uint64_t -QUICStreamManager::recv_total_offset() const +QUICStreamManager::total_offset_sent() const { - return this->_recv_total_offset; -} + uint64_t total_offset_sent = 0; -uint64_t -QUICStreamManager::send_total_offset() const -{ - return this->_send_total_offset; + // FIXME Iterating all (open + closed) streams is expensive + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + if (s->id() != 0) { + total_offset_sent += s->largest_offset_sent(); + } + } + return this->_total_offset_sent; } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 88997b57cd5..605496f7c01 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -41,16 +41,10 @@ class QUICStreamManager : public QUICFrameHandler virtual QUICError handle_frame(std::shared_ptr) override; virtual void send_frame(std::unique_ptr frame); virtual void send_frame(std::unique_ptr frame); - virtual bool is_send_avail_more_than(uint64_t size); - virtual bool is_recv_avail_more_than(uint64_t size); - void add_recv_total_offset(uint64_t delta); - void slide_recv_max_data(); void init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); - uint64_t recv_max_data() const; - uint64_t send_max_data() const; - uint64_t recv_total_offset() const; - uint64_t send_total_offset() const; + uint64_t total_offset_received() const; + uint64_t total_offset_sent() const; DLL stream_list; @@ -72,6 +66,6 @@ class QUICStreamManager : public QUICFrameHandler // TODO: Maximum Data is in units of 1024 octets, but those total offset are in units of octets. // Add new uint16_t fields for remainder and treat those total offset in units of 1024 octets if needed - uint64_t _recv_total_offset = 0; - uint64_t _send_total_offset = 0; + uint64_t _total_offset_received = 0; + uint64_t _total_offset_sent = 0; }; diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 65f473cfa31..dc6e12fc034 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -29,7 +29,8 @@ check_PROGRAMS = \ test_QUICLossDetector \ test_QUICTypeUtil \ test_QUICAckFrameCreator \ - test_QUICVersionNegotiator + test_QUICVersionNegotiator \ + test_QUICFlowController AM_CPPFLAGS += \ @@ -152,6 +153,7 @@ test_QUICFrameDispatcher_SOURCES = \ ../QUICStreamManager.cc \ ../QUICApplicationMap.cc \ ../QUICCongestionController.cc \ + ../QUICFlowController.cc \ ../QUICLossDetector.cc \ ../QUICFrame.cc \ ../QUICPacket.cc \ @@ -252,6 +254,7 @@ test_QUICTransportParameters_SOURCES = \ ../QUICStream.cc \ ../QUICStreamState.cc \ ../QUICStreamManager.cc \ + ../QUICFlowController.cc \ ../QUICPacket.cc \ ../QUICFrame.cc \ ../QUICDebugNames.cc \ @@ -397,6 +400,7 @@ test_QUICVersionNegotiator_SOURCES = \ ../QUICStream.cc \ ../QUICStreamState.cc \ ../QUICStreamManager.cc \ + ../QUICFlowController.cc \ ../QUICFrame.cc \ ../QUICDebugNames.cc \ ../QUICVersionNegotiator.cc \ @@ -404,6 +408,35 @@ test_QUICVersionNegotiator_SOURCES = \ ../QUICConfig.cc \ ../../SSLNextProtocolSet.cc +# +# test_QUICFlowController +# +test_QUICFlowController_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICFlowController_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICFlowController_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ + +test_QUICFlowController_SOURCES = \ + main.cc \ + test_QUICFlowController.cc \ + ../QUICFlowController.cc \ + ../QUICTypes.cc \ + ../QUICPacket.cc \ + ../QUICCrypto.cc \ + $(QUICCrypto_impl) \ + ../QUICFrame.cc + include $(top_srcdir)/build/tidy.mk tidy-local: $(DIST_SOURCES) diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc new file mode 100644 index 00000000000..660cad64f5f --- /dev/null +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -0,0 +1,252 @@ +/** @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 "catch.hpp" + +#include "quic/QUICFlowController.h" +#include "quic/Mock.h" +#include + +TEST_CASE("QUICFlowController_Local_Connection", "[quic]") +{ + QUICError error; + MockQUICFrameTransmitter tx; + QUICLocalConnectionFlowController fc(1024, &tx); + + // Check initial state + CHECK(fc.current_offset() == 0); + CHECK(fc.current_limit() == 1024); + + error = fc.update(256); + CHECK(fc.current_offset() == 256); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + error = fc.update(512); + CHECK(fc.current_offset() == 512); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + // Retransmit + error = fc.update(512); + CHECK(fc.current_offset() == 512); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + error = fc.update(1024); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + // Delay + error = fc.update(512); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + // Exceed limit + error = fc.update(1280); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(error.code == QUICErrorCode::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); + + // MAX_STREAM_DATA + CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_DATA)] == 0); + fc.forward_limit(2048); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 2048); + CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_DATA)] == 1); + + error = fc.update(1280); + CHECK(fc.current_offset() == 1280); + CHECK(fc.current_limit() == 2048); + CHECK(error.cls == QUICErrorClass::NONE); +} + +TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") +{ + QUICError error; + MockQUICFrameTransmitter tx; + QUICRemoteConnectionFlowController fc(1024, &tx); + + // Check initial state + CHECK(fc.current_offset() == 0); + CHECK(fc.current_limit() == 1024); + + error = fc.update(256); + CHECK(fc.current_offset() == 256); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + error = fc.update(512); + CHECK(fc.current_offset() == 512); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + // Retransmit + error = fc.update(512); + CHECK(fc.current_offset() == 512); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + error = fc.update(1024); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + // Delay + error = fc.update(512); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + // Exceed limit + CHECK(tx.frameCount[static_cast(QUICFrameType::BLOCKED)] == 0); + error = fc.update(1280); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls != QUICErrorClass::NONE); + CHECK(tx.frameCount[static_cast(QUICFrameType::BLOCKED)] == 1); + + // MAX_STREAM_DATA + fc.forward_limit(2048); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 2048); + + error = fc.update(1280); + CHECK(fc.current_offset() == 1280); + CHECK(fc.current_limit() == 2048); + CHECK(error.cls == QUICErrorClass::NONE); +} + +TEST_CASE("QUICFlowController_Local_Stream", "[quic]") +{ + QUICError error; + MockQUICFrameTransmitter tx; + QUICLocalStreamFlowController fc(1024, &tx, 0); + + // Check initial state + CHECK(fc.current_offset() == 0); + CHECK(fc.current_limit() == 1024); + + error = fc.update(256); + CHECK(fc.current_offset() == 256); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + error = fc.update(512); + CHECK(fc.current_offset() == 512); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + // Retransmit + error = fc.update(512); + CHECK(fc.current_offset() == 512); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + error = fc.update(1024); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + // Delay + error = fc.update(512); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + // Exceed limit + error = fc.update(1280); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(error.code == QUICErrorCode::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); + + // MAX_STREAM_DATA + CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_STREAM_DATA)] == 0); + fc.forward_limit(2048); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 2048); + CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_STREAM_DATA)] == 1); + + error = fc.update(1280); + CHECK(fc.current_offset() == 1280); + CHECK(fc.current_limit() == 2048); + CHECK(error.cls == QUICErrorClass::NONE); +} + +TEST_CASE("QUICFlowController_Remote_Stream", "[quic]") +{ + QUICError error; + MockQUICFrameTransmitter tx; + QUICRemoteStreamFlowController fc(1024, &tx, 0); + + // Check initial state + CHECK(fc.current_offset() == 0); + CHECK(fc.current_limit() == 1024); + + error = fc.update(256); + CHECK(fc.current_offset() == 256); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + error = fc.update(512); + CHECK(fc.current_offset() == 512); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + // Retransmit + error = fc.update(512); + CHECK(fc.current_offset() == 512); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + error = fc.update(1024); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + // Delay + error = fc.update(512); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls == QUICErrorClass::NONE); + + // Exceed limit + CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM_BLOCKED)] == 0); + error = fc.update(1280); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(error.cls != QUICErrorClass::NONE); + CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM_BLOCKED)] == 1); + + // MAX_STREAM_DATA + fc.forward_limit(2048); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 2048); + + error = fc.update(1280); + CHECK(fc.current_offset() == 1280); + CHECK(fc.current_limit() == 2048); + CHECK(error.cls == QUICErrorClass::NONE); +} diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index e296621f4fa..99563bc8d72 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -47,9 +47,10 @@ TEST_CASE("QUICStream_assembling_byte_stream_1", "[quic]") { MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); + MockQUICFrameTransmitter tx; std::unique_ptr stream(new QUICStream()); - stream->init(manager, nullptr, stream_id, 1024, 1024); + stream->init(manager, &tx, stream_id, 1024, 1024); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_1); @@ -73,9 +74,10 @@ TEST_CASE("QUICStream_assembling_byte_stream_2", "[quic]") { MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); + MockQUICFrameTransmitter tx; std::unique_ptr stream(new QUICStream()); - stream->init(manager, nullptr, stream_id); + stream->init(manager, &tx, stream_id); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -99,9 +101,10 @@ TEST_CASE("QUICStream_assembling_byte_stream_3", "[quic]") { MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); + MockQUICFrameTransmitter tx; std::unique_ptr stream(new QUICStream()); - stream->init(manager, nullptr, stream_id); + stream->init(manager, &tx, stream_id); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); From c20192b930196249719fc0922254ecd88bc8457c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Sep 2017 11:22:20 +0900 Subject: [PATCH 0078/1313] Add tests for QUICStreamManager --- .gitignore | 1 + iocore/net/quic/Mock.h | 8 +++ iocore/net/quic/QUICFrame.cc | 6 +- iocore/net/quic/QUICStreamManager.cc | 36 ++++++++-- iocore/net/quic/QUICStreamManager.h | 15 ++--- iocore/net/quic/test/Makefile.am | 31 +++++++++ .../net/quic/test/test_QUICStreamManager.cc | 66 +++++++++++++++++++ 7 files changed, 149 insertions(+), 14 deletions(-) create mode 100644 iocore/net/quic/test/test_QUICStreamManager.cc diff --git a/.gitignore b/.gitignore index e68e278aa25..9f94fa6229e 100644 --- a/.gitignore +++ b/.gitignore @@ -93,6 +93,7 @@ iocore/net/quic/test/test_QUICPacket iocore/net/quic/test/test_QUICPacketFactory iocore/net/quic/test/test_QUICStream iocore/net/quic/test/test_QUICStreamState +iocore/net/quic/test/test_QUICStreamManager iocore/net/quic/test/test_QUICTransportParameters iocore/net/quic/test/test_QUICCrypto iocore/net/quic/test/test_QUICLossDetector diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index dd538e2d587..270b83b1344 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -21,6 +21,7 @@ * limitations under the License. */ +#include "QUICApplication.h" #include "QUICStreamManager.h" #include "QUICCongestionController.h" #include "QUICLossDetector.h" @@ -344,9 +345,16 @@ class MockQUICCongestionController : public QUICCongestionController int _frameCount[256] = {0}; }; +class MockQUICApplication : public QUICApplication +{ +public: + MockQUICApplication() : QUICApplication(new MockQUICConnection) {} +}; + void NetVConnection::cancel_OOB(){}; Action * NetVConnection::send_OOB(Continuation *, char *, int) { return nullptr; } + diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index e99eda61f47..e64b37b0381 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -691,7 +691,11 @@ QUICRstStreamFrame::error_code() const QUICStreamId QUICRstStreamFrame::stream_id() const { - return QUICTypeUtil::read_QUICStreamId(this->_buf + 5, 4); + if (this->_buf) { + return QUICTypeUtil::read_QUICStreamId(this->_buf + 5, 4); + } else { + return this->_stream_id; + } } QUICOffset diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 035da95e204..8db20cab1de 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -84,6 +84,9 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) case QUICFrameType::STREAM: error = this->_handle_frame(std::dynamic_pointer_cast(frame)); break; + case QUICFrameType::RST_STREAM: + error = this->_handle_frame(std::dynamic_pointer_cast(frame)); + break; default: Debug(tag, "Unexpected frame type: %02x", static_cast(frame->type())); ink_assert(false); @@ -96,7 +99,7 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) QUICError QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { - QUICStream *stream = this->_find_stream(frame->stream_id()); + QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); if (stream) { return stream->recv(frame); } else { @@ -109,7 +112,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { - QUICStream *stream = this->_find_stream(frame->stream_id()); + QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); if (stream) { return stream->recv(frame); } else { @@ -138,6 +141,19 @@ QUICStreamManager::_handle_frame(const std::shared_ptr &f return error; } +QUICError +QUICStreamManager::_handle_frame(const std::shared_ptr &frame) +{ + QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); + if (stream) { + // TODO Reset the stream + } else { + // TODO: connection error? + } + + return QUICError(QUICErrorClass::NONE); +} + /** * @brief Send stream frame */ @@ -206,7 +222,7 @@ QUICStreamManager::total_offset_received() const // FIXME Iterating all (open + closed) streams is expensive for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { if (s->id() != 0) { - total_offset_received += s->largest_offset_received(); + total_offset_received += s->largest_offset_received() / 1024; } } return total_offset_received; @@ -220,8 +236,18 @@ QUICStreamManager::total_offset_sent() const // FIXME Iterating all (open + closed) streams is expensive for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { if (s->id() != 0) { - total_offset_sent += s->largest_offset_sent(); + total_offset_sent += s->largest_offset_sent() / 1024; } } - return this->_total_offset_sent; + return total_offset_sent; +} + +uint32_t +QUICStreamManager::stream_count() const +{ + uint32_t count = 0; + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + ++count; + } + return count; } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 605496f7c01..70af4643de9 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -37,22 +37,26 @@ class QUICStreamManager : public QUICFrameHandler public: QUICStreamManager(){}; QUICStreamManager(QUICFrameTransmitter *tx, QUICApplicationMap *app_map); - virtual std::vector interests() override; - virtual QUICError handle_frame(std::shared_ptr) override; + virtual void send_frame(std::unique_ptr frame); virtual void send_frame(std::unique_ptr frame); void init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); uint64_t total_offset_received() const; uint64_t total_offset_sent() const; + uint32_t stream_count() const; DLL stream_list; + // QUICFrameHandler + virtual std::vector interests() override; + virtual QUICError handle_frame(std::shared_ptr) override; + private: QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICStream *_find_stream(QUICStreamId id); - QUICError _handle_frame(const std::shared_ptr &); QUICError _handle_frame(const std::shared_ptr &); + QUICError _handle_frame(const std::shared_ptr &); QUICError _handle_frame(const std::shared_ptr &); QUICError _handle_frame(const std::shared_ptr &); @@ -63,9 +67,4 @@ class QUICStreamManager : public QUICFrameHandler QUICMaximumData _recv_max_data = {0}; QUICMaximumData _send_max_data = {0}; - - // TODO: Maximum Data is in units of 1024 octets, but those total offset are in units of octets. - // Add new uint16_t fields for remainder and treat those total offset in units of 1024 octets if needed - uint64_t _total_offset_received = 0; - uint64_t _total_offset_sent = 0; }; diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index dc6e12fc034..a958fe80dd2 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -24,6 +24,7 @@ check_PROGRAMS = \ test_QUICFrameDispatcher \ test_QUICStreamState \ test_QUICStream \ + test_QUICStreamManager \ test_QUICTransportParameters \ test_QUICCrypto \ test_QUICLossDetector \ @@ -231,6 +232,36 @@ test_QUICStream_LDADD = \ @LIBTCL@ \ @HWLOC_LIBS@ +# +# test_QUICStreamManager +# +test_QUICStreamManager_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICStreamManager_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICStreamManager_SOURCES = \ + event_processor_main.cc \ + test_QUICStreamManager.cc \ + ../QUICStream.cc \ + ../QUICFrameDispatcher.cc \ + ../QUICStreamManager.cc \ + ../QUICApplicationMap.cc \ + ../QUICCongestionController.cc \ + ../../SSLNextProtocolSet.cc + +test_QUICStreamManager_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ + # # test_QUICTransportParameters # diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc new file mode 100644 index 00000000000..752859b3096 --- /dev/null +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -0,0 +1,66 @@ +/** @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 "catch.hpp" + +#include + +#include "quic/QUICStreamManager.h" +#include "quic/QUICFrame.h" +#include "quic/Mock.h" + +TEST_CASE("QUICStreamManager_NewStream", "[quic]") +{ + MockQUICFrameTransmitter tx; + QUICApplicationMap app_map; + MockQUICApplication mock_app; + app_map.set_default(&mock_app); + QUICStreamManager sm(&tx, &app_map); + std::shared_ptr local_tp = std::make_shared(); + std::shared_ptr remote_tp = std::make_shared(static_cast(0), static_cast(0)); + sm.init_flow_control_params(local_tp, remote_tp); + + // STREAM frames create new streams + std::shared_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 0); + std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 1, 0); + CHECK(sm.stream_count() == 0); + sm.handle_frame(stream_frame_0); + CHECK(sm.stream_count() == 1); + sm.handle_frame(stream_frame_1); + CHECK(sm.stream_count() == 2); + + // RST_STREAM frames create new streams + std::shared_ptr rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(2, QUICErrorCode::QUIC_INTERNAL_ERROR, 0); + sm.handle_frame(rst_stream_frame); + CHECK(sm.stream_count() == 3); + + // MAX_STREAM_DATA frames create new streams + std::shared_ptr max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(3, 0); + sm.handle_frame(max_stream_data_frame); + CHECK(sm.stream_count() == 4); + + // STREAM_BLOCKED frames create new streams + std::shared_ptr stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(4); + sm.handle_frame(stream_blocked_frame); + CHECK(sm.stream_count() == 5); +} From 22dfdfb3cf243377bf0ed864eee88ccb16b19a5e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Sep 2017 17:40:32 +0900 Subject: [PATCH 0079/1313] Add tests for QUICStreamManager (total_offset_sent/received) --- iocore/net/quic/Mock.h | 22 ++++++- iocore/net/quic/QUICApplication.cc | 2 +- iocore/net/quic/QUICApplication.h | 2 +- iocore/net/quic/QUICStreamManager.h | 3 - .../net/quic/test/test_QUICStreamManager.cc | 66 +++++++++++++++++++ 5 files changed, 89 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 270b83b1344..46bb03d7d4a 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -348,7 +348,27 @@ class MockQUICCongestionController : public QUICCongestionController class MockQUICApplication : public QUICApplication { public: - MockQUICApplication() : QUICApplication(new MockQUICConnection) {} + MockQUICApplication() : QUICApplication(new MockQUICConnection) { + SET_HANDLER(&MockQUICApplication::main_event_handler); + } + + int + main_event_handler(int event, Event *data) + { + if (event == 12345) { + QUICStreamIO *stream_io = static_cast(data->cookie); + stream_io->write_reenable(); + } + return EVENT_CONT; + } + + void + send(const uint8_t *data, size_t size, QUICStreamId stream_id) + { + QUICStreamIO *stream_io = this->_find_stream_io(stream_id); + stream_io->write(data, size); + eventProcessor.schedule_imm(this, ET_CALL, 12345, stream_io); + } }; void NetVConnection::cancel_OOB(){}; diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 3bd0d20152e..455459a328f 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -56,7 +56,7 @@ QUICStreamIO::read(uint8_t *buf, int64_t len) } int64_t -QUICStreamIO::write(uint8_t *buf, int64_t len) +QUICStreamIO::write(const uint8_t *buf, int64_t len) { SCOPED_MUTEX_LOCK(lock, this->_write_vio->mutex, this_ethread()); diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 39c19741a82..25df608d907 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -41,7 +41,7 @@ class QUICStreamIO int64_t read_avail(); int64_t read(uint8_t *buf, int64_t len); - int64_t write(uint8_t *buf, int64_t len); + int64_t write(const uint8_t *buf, int64_t len); void read_reenable(); void write_reenable(); diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 70af4643de9..fd6412a8f0f 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -64,7 +64,4 @@ class QUICStreamManager : public QUICFrameHandler QUICApplicationMap *_app_map = nullptr; std::shared_ptr _local_tp = nullptr; std::shared_ptr _remote_tp = nullptr; - - QUICMaximumData _recv_max_data = {0}; - QUICMaximumData _send_max_data = {0}; }; diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 752859b3096..55f3a29516e 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -64,3 +64,69 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") sm.handle_frame(stream_blocked_frame); CHECK(sm.stream_count() == 5); } + +TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") +{ + MockQUICFrameTransmitter tx; + QUICApplicationMap app_map; + MockQUICApplication mock_app; + app_map.set_default(&mock_app); + QUICStreamManager sm(&tx, &app_map); + std::shared_ptr local_tp = std::make_shared(); + local_tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, std::unique_ptr(new QUICTransportParameterValue(4096, 4))); + std::shared_ptr remote_tp = std::make_shared(static_cast(0), static_cast(0)); + sm.init_flow_control_params(local_tp, remote_tp); + uint8_t data[1024] = {0}; + + // Create a stream with STREAM_BLOCKED (== noop) + std::shared_ptr stream_blocked_frame_0 = QUICFrameFactory::create_stream_blocked_frame(0); + std::shared_ptr stream_blocked_frame_1 = QUICFrameFactory::create_stream_blocked_frame(1); + sm.handle_frame(stream_blocked_frame_0); + sm.handle_frame(stream_blocked_frame_1); + CHECK(sm.stream_count() == 2); + CHECK(sm.total_offset_received() == 0); + + // Stream 0 shoud be out of flow control + std::shared_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(data, 1024, 0, 0); + sm.handle_frame(stream_frame_0); + CHECK(sm.total_offset_received() == 0); + + // total_offset should be a integer in unit of 1024 octets + std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); + sm.handle_frame(stream_frame_1); + CHECK(sm.total_offset_received() == 1); +} + +TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") +{ + MockQUICFrameTransmitter tx; + QUICApplicationMap app_map; + MockQUICApplication mock_app; + app_map.set_default(&mock_app); + QUICStreamManager sm(&tx, &app_map); + std::shared_ptr local_tp = std::make_shared(); + local_tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, std::unique_ptr(new QUICTransportParameterValue(4096, 4))); + std::shared_ptr remote_tp = std::make_shared(static_cast(0), static_cast(0)); + sm.init_flow_control_params(local_tp, remote_tp); + uint8_t data[1024] = {0}; + + // Create a stream with STREAM_BLOCKED (== noop) + std::shared_ptr stream_frame_0_r = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 0); + std::shared_ptr stream_frame_1_r = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 1, 0); + sm.handle_frame(stream_frame_0_r); + sm.handle_frame(stream_frame_1_r); + CHECK(sm.stream_count() == 2); + CHECK(sm.total_offset_sent() == 0); + + // Stream 0 shoud be out of flow control + std::unique_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(data, 1024, 0, 0); + mock_app.send(data, 1024, 0); + sleep(2); + CHECK(sm.total_offset_sent() == 0); + + // total_offset should be a integer in unit of 1024 octets + std::unique_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); + mock_app.send(data, 1024, 1); + sleep(2); + CHECK(sm.total_offset_sent() == 1); +} From de466e93b69b0be8d2439d7b4313a05460692e65 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Sep 2017 17:43:09 +0900 Subject: [PATCH 0080/1313] clang-format --- iocore/net/quic/Mock.h | 5 +--- .../net/quic/test/test_QUICStreamManager.cc | 27 ++++++++++++------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 46bb03d7d4a..a9c4bf95c5d 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -348,9 +348,7 @@ class MockQUICCongestionController : public QUICCongestionController class MockQUICApplication : public QUICApplication { public: - MockQUICApplication() : QUICApplication(new MockQUICConnection) { - SET_HANDLER(&MockQUICApplication::main_event_handler); - } + MockQUICApplication() : QUICApplication(new MockQUICConnection) { SET_HANDLER(&MockQUICApplication::main_event_handler); } int main_event_handler(int event, Event *data) @@ -377,4 +375,3 @@ NetVConnection::send_OOB(Continuation *, char *, int) { return nullptr; } - diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 55f3a29516e..fdf4c515856 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -37,12 +37,15 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") app_map.set_default(&mock_app); QUICStreamManager sm(&tx, &app_map); std::shared_ptr local_tp = std::make_shared(); - std::shared_ptr remote_tp = std::make_shared(static_cast(0), static_cast(0)); + std::shared_ptr remote_tp = + std::make_shared(static_cast(0), static_cast(0)); sm.init_flow_control_params(local_tp, remote_tp); // STREAM frames create new streams - std::shared_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 0); - std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 1, 0); + std::shared_ptr stream_frame_0 = + QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 0); + std::shared_ptr stream_frame_1 = + QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 1, 0); CHECK(sm.stream_count() == 0); sm.handle_frame(stream_frame_0); CHECK(sm.stream_count() == 1); @@ -73,8 +76,10 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") app_map.set_default(&mock_app); QUICStreamManager sm(&tx, &app_map); std::shared_ptr local_tp = std::make_shared(); - local_tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, std::unique_ptr(new QUICTransportParameterValue(4096, 4))); - std::shared_ptr remote_tp = std::make_shared(static_cast(0), static_cast(0)); + local_tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, + std::unique_ptr(new QUICTransportParameterValue(4096, 4))); + std::shared_ptr remote_tp = + std::make_shared(static_cast(0), static_cast(0)); sm.init_flow_control_params(local_tp, remote_tp); uint8_t data[1024] = {0}; @@ -105,14 +110,18 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") app_map.set_default(&mock_app); QUICStreamManager sm(&tx, &app_map); std::shared_ptr local_tp = std::make_shared(); - local_tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, std::unique_ptr(new QUICTransportParameterValue(4096, 4))); - std::shared_ptr remote_tp = std::make_shared(static_cast(0), static_cast(0)); + local_tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, + std::unique_ptr(new QUICTransportParameterValue(4096, 4))); + std::shared_ptr remote_tp = + std::make_shared(static_cast(0), static_cast(0)); sm.init_flow_control_params(local_tp, remote_tp); uint8_t data[1024] = {0}; // Create a stream with STREAM_BLOCKED (== noop) - std::shared_ptr stream_frame_0_r = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 0); - std::shared_ptr stream_frame_1_r = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 1, 0); + std::shared_ptr stream_frame_0_r = + QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 0); + std::shared_ptr stream_frame_1_r = + QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 1, 0); sm.handle_frame(stream_frame_0_r); sm.handle_frame(stream_frame_1_r); CHECK(sm.stream_count() == 2); From 9af58ef1f308ea6481a2878770c4b9c5b210e50e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Sep 2017 09:27:03 +0900 Subject: [PATCH 0081/1313] Add packet number encoder and decoder --- iocore/net/quic/QUICPacket.cc | 54 +++++++++++++++++++++++++ iocore/net/quic/QUICPacket.h | 4 ++ iocore/net/quic/test/test_QUICPacket.cc | 39 ++++++++++++++++++ 3 files changed, 97 insertions(+) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 683fd48ff6c..d00924995d4 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -594,6 +594,57 @@ QUICPacket::set_protected_payload(ats_unique_buf cipher_txt, size_t cipher_txt_l this->_protected_payload_size = cipher_txt_len; } +uint8_t +QUICPacket::calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base) +{ + ink_assert(num > base); + + uint64_t d = (num - base) * 2; + uint8_t len = 0; + + if (d > 0xFFFF) { + len = 4; + } else if (d > 0xFF) { + len = 2; + } else { + len = 1; + } + + return len; +} + +bool +QUICPacket::encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len) +{ + ink_assert(len == 1 || len == 2 || len == 4); + + uint64_t mask = (1ULL << (len * 8)) - 1; + dst = src & mask; + return true; +} + +bool +QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, QUICPacketNumber base) +{ + ink_assert(len == 1 || len == 2 || len == 4); + + QUICPacketNumber expected = base + 1; + + uint64_t p = 1ULL << (len * 8); + QUICPacketNumber masked = base & (~(p - 1)); + dst = masked + src; + + if (dst >= expected) { + return true; + } + + dst += p; + return true; +} + +// +// QUICPacketFactory +// std::unique_ptr QUICPacketFactory::create(IOBufferBlock *block) { @@ -687,6 +738,9 @@ QUICPacketFactory::set_crypto_module(QUICCrypto *crypto) this->_crypto = crypto; } +// +// QUICPacketNumberGenerator +// QUICPacketNumber QUICPacketNumberGenerator::next() { diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 224f7e6f41b..02ecf6640c4 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -147,6 +147,10 @@ class QUICPacket void store_header(uint8_t *buf, size_t *len) const; bool has_valid_fnv1a_hash() const; QUICKeyPhase key_phase() 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_num); + LINK(QUICPacket, link); private: diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 1dc3b707b63..82a663272bd 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -94,3 +94,42 @@ TEST_CASE("Loading Unknown Packet", "[quic]") CHECK(header->type() == QUICPacketType::UNINITIALIZED); } + +TEST_CASE("Encoded Packet Number Length", "[quic]") +{ + QUICPacketNumber base = 0x6afa2f; + + CHECK(QUICPacket::calc_packet_number_len(0x6b4264, base) == 2); + CHECK(QUICPacket::calc_packet_number_len(0x6bc107, base) == 4); +} + +TEST_CASE("Encoding Packet Number", "[quic]") +{ + QUICPacketNumber dst = 0; + QUICPacketNumber src = 0xaa831f94; + + QUICPacket::encode_packet_number(dst, src, 2); + CHECK(dst == 0x1f94); +} + +TEST_CASE("Decoding Packet Number 1", "[quic]") +{ + QUICPacketNumber dst = 0; + QUICPacketNumber src = 0x1f94; + size_t len = 2; + QUICPacketNumber base = 0xaa82f30e; + + QUICPacket::decode_packet_number(dst, src, len, base); + CHECK(dst == 0xaa831f94); +} + +TEST_CASE("Decoding Packet Number 2", "[quic]") +{ + QUICPacketNumber dst = 0; + QUICPacketNumber src = 0xf1; + size_t len = 1; + QUICPacketNumber base = 0x18bf54f0; + + QUICPacket::decode_packet_number(dst, src, len, base); + CHECK(dst == 0x18bf54f1); +} From 4e471619c2b0d8a505beb1d7aaac148bc90da87d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Sep 2017 15:52:46 +0900 Subject: [PATCH 0082/1313] Encode/Decode packet number --- iocore/net/P_QUICNetVConnection.h | 7 +- iocore/net/P_QUICPacketHandler.h | 1 + iocore/net/QUICNetVConnection.cc | 30 ++- iocore/net/QUICPacketHandler.cc | 36 ++- iocore/net/quic/Mock.h | 12 + iocore/net/quic/QUICConnection.h | 14 +- iocore/net/quic/QUICHandshake.cc | 3 +- iocore/net/quic/QUICLossDetector.cc | 6 + iocore/net/quic/QUICLossDetector.h | 1 + iocore/net/quic/QUICPacket.cc | 220 ++++++++++-------- iocore/net/quic/QUICPacket.h | 73 +++--- iocore/net/quic/QUICTypes.cc | 1 + iocore/net/quic/test/test_QUICLossDetector.cc | 4 +- iocore/net/quic/test/test_QUICPacket.cc | 10 +- .../net/quic/test/test_QUICPacketFactory.cc | 6 +- .../quic/test/test_QUICVersionNegotiator.cc | 2 +- 16 files changed, 265 insertions(+), 161 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 8ee7cdfd93c..02606ea5b64 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -175,6 +175,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection NetVConnectionContext_t direction() override; SSLNextProtocolSet *next_protocol_set() override; void close(QUICError error) override; + QUICPacketNumber largest_received_packet_number() override; + QUICPacketNumber largest_acked_packet_number() override; // QUICConnection (QUICPacketTransmitter) virtual void transmit_packet(std::unique_ptr packet) override; @@ -190,8 +192,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection private: QUICConnectionId _quic_connection_id; - UDPConnection *_udp_con = nullptr; - QUICPacketHandler *_packet_handler = nullptr; + QUICPacketNumber _largest_received_packet_number = 0; + UDPConnection *_udp_con = nullptr; + QUICPacketHandler *_packet_handler = nullptr; QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; QUICAckFrameCreator _ack_frame_creator; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index ce77b4ad216..c40f255ee28 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -43,6 +43,7 @@ struct QUICPacketHandler : public NetAccept { private: void _recv_packet(int event, UDPPacket *udpPacket); + bool _read_connection_id(QUICConnectionId &cid, IOBufferBlock *block); Map _connections; SSL_CTX *_ssl_ctx; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index f5a15ba039b..8cf57631614 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -232,7 +232,8 @@ QUICNetVConnection::get_transmitter_mutex() void QUICNetVConnection::push_packet(std::unique_ptr packet) { - DebugQUICCon("Type=%s Size=%u", QUICDebugNames::packet_type(packet->type()), packet->size()); + DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), + packet->size()); this->_packet_recv_queue.enqueue(const_cast(packet.release())); } @@ -506,6 +507,18 @@ QUICNetVConnection::next_protocol_set() return this->_next_protocol_set; } +QUICPacketNumber +QUICNetVConnection::largest_received_packet_number() +{ + return this->_largest_received_packet_number; +} + +QUICPacketNumber +QUICNetVConnection::largest_acked_packet_number() +{ + return this->_loss_detector->largest_acked_packet_number(); +} + QUICError QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_ptr packet) { @@ -684,6 +697,10 @@ QUICNetVConnection::_packetize_frames() QUICError QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_num) { + if (packet_num > this->_largest_received_packet_number) { + this->_largest_received_packet_number = packet_num; + } + bool should_send_ack; QUICError error; @@ -718,15 +735,16 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi switch (type) { case QUICPacketType::SERVER_CLEARTEXT: - packet = this->_packet_factory.create_server_cleartext_packet(this->_quic_connection_id, std::move(buf), len, retransmittable); + packet = this->_packet_factory.create_server_cleartext_packet(this->_quic_connection_id, this->largest_acked_packet_number(), + std::move(buf), len, retransmittable); break; default: if (this->_handshake_handler && this->_handshake_handler->is_completed()) { - packet = - this->_packet_factory.create_server_protected_packet(this->_quic_connection_id, std::move(buf), len, retransmittable); + packet = this->_packet_factory.create_server_protected_packet(this->_quic_connection_id, this->largest_acked_packet_number(), + std::move(buf), len, retransmittable); } else { - packet = - this->_packet_factory.create_server_cleartext_packet(this->_quic_connection_id, std::move(buf), len, retransmittable); + packet = this->_packet_factory.create_server_cleartext_packet(this->_quic_connection_id, this->largest_acked_packet_number(), + std::move(buf), len, retransmittable); } break; } diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 0a7278c08df..0531aeb20dc 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -91,13 +91,42 @@ QUICPacketHandler::init_accept(EThread *t = nullptr) SET_HANDLER(&QUICPacketHandler::acceptEvent); } +// TODO: Integrate with QUICPacketHeader::connection_id() +bool +QUICPacketHandler::_read_connection_id(QUICConnectionId &cid, IOBufferBlock *block) +{ + const uint8_t *buf = reinterpret_cast(block->buf()); + const uint8_t cid_offset = 1; + const uint8_t cid_len = 8; + + if (QUICTypeUtil::hasLongHeader(buf)) { + cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); + } else { + if (buf[0] & 0x40) { + cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); + } else { + return false; + } + } + + return true; +} + void QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) { IOBufferBlock *block = udpPacket->getIOBlockChain(); - std::unique_ptr qPkt = QUICPacketFactory::create(block); - QUICNetVConnection *vc = this->_connections.get(qPkt->connection_id()); + QUICConnectionId cid; + bool res = this->_read_connection_id(cid, block); + + QUICNetVConnection *vc = nullptr; + if (res) { + vc = this->_connections.get(cid); + } else { + // TODO: find vc from five tuples + ink_assert(false); + } if (!vc) { // Unknown Connection ID @@ -119,9 +148,10 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) vc->options.ip_family = udpPacket->from.sa.sa_family; // TODO: Handle Connection ID of Client Cleartext / Non-Final Server Cleartext Packet - this->_connections.put(qPkt->connection_id(), vc); + this->_connections.put(cid, vc); } + std::unique_ptr qPkt = QUICPacketFactory::create(block, vc->largest_received_packet_number()); vc->push_packet(std::move(qPkt)); // send to EThread diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index a9c4bf95c5d..ddf056d5109 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -162,6 +162,18 @@ class MockQUICConnection : public QUICConnection return 1280; } + QUICPacketNumber + largest_received_packet_number() override + { + return 0; + } + + QUICPacketNumber + largest_acked_packet_number() override + { + return 0; + } + NetVConnectionContext_t direction() override { diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 0e571ed97c9..8113ade1291 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -34,10 +34,12 @@ class SSLNextProtocolSet; class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler { public: - virtual uint32_t maximum_quic_packet_size() = 0; - virtual uint32_t minimum_quic_packet_size() = 0; - virtual uint32_t pmtu() = 0; - virtual NetVConnectionContext_t direction() = 0; - virtual SSLNextProtocolSet *next_protocol_set() = 0; - virtual void close(QUICError error) = 0; + virtual uint32_t maximum_quic_packet_size() = 0; + virtual uint32_t minimum_quic_packet_size() = 0; + virtual uint32_t pmtu() = 0; + virtual NetVConnectionContext_t direction() = 0; + virtual SSLNextProtocolSet *next_protocol_set() = 0; + virtual void close(QUICError error) = 0; + virtual QUICPacketNumber largest_received_packet_number() = 0; + virtual QUICPacketNumber largest_acked_packet_number() = 0; }; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 18beda7cb58..85455fcacb9 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -85,7 +85,8 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet Debug(tag, "Version negotiation succeeded: %x", initial_packet->version()); packet_factory->set_version(this->_version_negotiator->negotiated_version()); } else { - this->_client_qc->transmit_packet(packet_factory->create_version_negotiation_packet(initial_packet)); + this->_client_qc->transmit_packet( + packet_factory->create_version_negotiation_packet(initial_packet, _client_qc->largest_acked_packet_number())); Debug(tag, "Version negotiation failed: %x", initial_packet->version()); } } else { diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index cd8fefd0a0e..feb48aa9e18 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -96,6 +96,12 @@ QUICLossDetector::handle_frame(std::shared_ptr frame) return error; } +QUICPacketNumber +QUICLossDetector::largest_acked_packet_number() +{ + return this->_largest_acked_packet; +} + void QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_number) { diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index b12a293cac8..82bfa9b857c 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -48,6 +48,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler std::vector interests() override; virtual QUICError handle_frame(std::shared_ptr) override; void on_packet_sent(std::unique_ptr packet); + QUICPacketNumber largest_acked_packet_number(); private: struct PacketInfo { diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index d00924995d4..3ef847fab97 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -35,6 +35,9 @@ static constexpr int OFFSET_PAYLOAD = 17; static constexpr int LONGHEADER_LENGTH = 17; static constexpr int FNV1A_HASH_LEN = 8; +// +// QUICPacketHeader +// const uint8_t * QUICPacketHeader::buf() { @@ -42,58 +45,61 @@ QUICPacketHeader::buf() } QUICPacketHeader * -QUICPacketHeader::load(const uint8_t *buf, size_t len) +QUICPacketHeader::load(const uint8_t *buf, size_t len, QUICPacketNumber base) { if (QUICTypeUtil::hasLongHeader(buf)) { QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); - new (long_header) QUICPacketLongHeader(buf, len); + new (long_header) QUICPacketLongHeader(buf, len, base); return long_header; } else { QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); - new (short_header) QUICPacketShortHeader(buf, len); + new (short_header) QUICPacketShortHeader(buf, len, base); return short_header; } } QUICPacketHeader * -QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICVersion version, - ats_unique_buf payload, size_t len) +QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len) { QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); - new (long_header) QUICPacketLongHeader(type, connection_id, packet_number, version, std::move(payload), len); + new (long_header) QUICPacketLongHeader(type, connection_id, packet_number, base_packet_number, version, std::move(payload), len); return long_header; } QUICPacketHeader * -QUICPacketHeader::build(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len) +QUICPacketHeader::build(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, + ats_unique_buf payload, size_t len) { QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); - new (short_header) QUICPacketShortHeader(type, packet_number, std::move(payload), len); + new (short_header) QUICPacketShortHeader(type, packet_number, base_packet_number, std::move(payload), len); return short_header; } QUICPacketHeader * -QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, - size_t len) +QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len) { QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); - new (short_header) QUICPacketShortHeader(type, connection_id, packet_number, std::move(payload), len); + new (short_header) QUICPacketShortHeader(type, connection_id, packet_number, base_packet_number, std::move(payload), len); return short_header; } +// // QUICPacketLongHeader - +// QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICVersion version, ats_unique_buf buf, size_t len) + QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len) { - this->_type = type; - this->_has_connection_id = true; - this->_connection_id = connection_id; - this->_packet_number = packet_number; - this->_has_version = true; - this->_version = version; - this->_payload = std::move(buf); - this->_payload_len = len; + this->_type = type; + this->_has_connection_id = true; + this->_connection_id = connection_id; + this->_packet_number = packet_number; + this->_base_packet_number = base_packet_number; + this->_has_version = true; + this->_version = version; + this->_payload = std::move(buf); + this->_payload_len = len; } QUICPacketType @@ -125,7 +131,12 @@ QUICPacketNumber QUICPacketLongHeader::packet_number() const { if (this->_buf) { - return QUICTypeUtil::read_QUICPacketNumber(this->_buf + OFFSET_PACKET_NUMBER, 4); + const uint8_t packet_number_len = 4; + QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf + OFFSET_PACKET_NUMBER, packet_number_len); + QUICPacketNumber dst = 0; + QUICPacket::decode_packet_number(dst, src, packet_number_len, this->_base_packet_number); + + return dst; } else { return this->_packet_number; } @@ -191,21 +202,30 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const *len += 1; QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, buf + *len, &n); *len += n; - QUICTypeUtil::write_QUICPacketNumber(this->_packet_number, 4, buf + *len, &n); + + QUICPacketNumber dst = 0; + size_t dst_len = 4; + QUICPacket::encode_packet_number(dst, this->_packet_number, dst_len); + QUICTypeUtil::write_QUICPacketNumber(dst, dst_len, buf + *len, &n); *len += n; + QUICTypeUtil::write_QUICVersion(this->_version, buf + *len, &n); *len += n; } +// // QUICPacketShortHeader - -QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf buf, size_t len) +// +QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len) { - this->_type = type; - this->_has_key_phase = true; - this->_packet_number = packet_number; - this->_payload = std::move(buf); - this->_payload_len = len; + this->_type = type; + this->_has_key_phase = true; + this->_packet_number = packet_number; + this->_base_packet_number = base_packet_number; + this->_packet_number_type = this->_discover_packet_number_type(packet_number, base_packet_number); + this->_payload = std::move(buf); + this->_payload_len = len; if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0) { this->_key_phase = QUICKeyPhase::PHASE_0; @@ -215,26 +235,20 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICPacketNumb ink_assert(false); this->_key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; } - - if (packet_number <= 0xFF) { - this->_packet_number_type = QUICPacketShortHeaderType::ONE; - } else if (packet_number <= 0xFFFF) { - this->_packet_number_type = QUICPacketShortHeaderType::TWO; - } else { - this->_packet_number_type = QUICPacketShortHeaderType::THREE; - } } QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - ats_unique_buf buf, size_t len) -{ - this->_type = type; - this->_has_key_phase = true; - this->_has_connection_id = true; - this->_connection_id = connection_id; - this->_packet_number = packet_number; - this->_payload = std::move(buf); - this->_payload_len = len; + QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len) +{ + this->_type = type; + this->_has_key_phase = true; + this->_has_connection_id = true; + this->_connection_id = connection_id; + this->_packet_number = packet_number; + this->_base_packet_number = base_packet_number; + this->_packet_number_type = this->_discover_packet_number_type(packet_number, base_packet_number); + this->_payload = std::move(buf); + this->_payload_len = len; if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0) { this->_key_phase = QUICKeyPhase::PHASE_0; @@ -244,14 +258,6 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICConnection ink_assert(false); this->_key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; } - - if (packet_number <= 0xFF) { - this->_packet_number_type = QUICPacketShortHeaderType::ONE; - } else if (packet_number <= 0xFFFF) { - this->_packet_number_type = QUICPacketShortHeaderType::TWO; - } else { - this->_packet_number_type = QUICPacketShortHeaderType::THREE; - } } QUICPacketType @@ -287,13 +293,17 @@ QUICPacketNumber QUICPacketShortHeader::packet_number() const { if (this->_buf) { - int n = this->_packet_numberLen(); + int n = this->_packet_number_len(); int offset = 1; if (this->has_connection_id()) { offset = OFFSET_PACKET_NUMBER; } - return QUICTypeUtil::read_QUICPacketNumber(this->_buf + offset, n); + QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf + offset, n); + QUICPacketNumber dst = 0; + QUICPacket::decode_packet_number(dst, src, n, this->_base_packet_number); + + return dst; } else { return this->_packet_number; } @@ -312,7 +322,7 @@ QUICPacketShortHeader::version() const } int -QUICPacketShortHeader::_packet_numberLen() const +QUICPacketShortHeader::_packet_number_len() const { QUICPacketShortHeaderType type; if (this->_buf) { @@ -334,6 +344,20 @@ QUICPacketShortHeader::_packet_numberLen() const } } +QUICPacketShortHeaderType +QUICPacketShortHeader::_discover_packet_number_type(QUICPacketNumber packet_number, QUICPacketNumber base_packet_number) const +{ + uint64_t d = (packet_number - base_packet_number) * 2; + + if (d > 0xFFFF) { + return QUICPacketShortHeaderType::THREE; + } else if (d > 0xFF) { + return QUICPacketShortHeaderType::TWO; + } else { + return QUICPacketShortHeaderType::ONE; + } +} + bool QUICPacketShortHeader::has_connection_id() const { @@ -385,7 +409,7 @@ QUICPacketShortHeader::length() const if (this->has_connection_id()) { len += 8; } - len += this->_packet_numberLen(); + len += this->_packet_number_len(); return len; } @@ -408,34 +432,30 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, buf + *len, &n); *len += n; } - switch (this->_packet_number_type) { - case QUICPacketShortHeaderType::ONE: - QUICTypeUtil::write_QUICPacketNumber(this->_packet_number, 1, buf + *len, &n); - break; - case QUICPacketShortHeaderType::TWO: - QUICTypeUtil::write_QUICPacketNumber(this->_packet_number, 2, buf + *len, &n); - break; - case QUICPacketShortHeaderType::THREE: - QUICTypeUtil::write_QUICPacketNumber(this->_packet_number, 4, buf + *len, &n); - break; - default: - ink_release_assert(0); - } + + 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; } +// // QUICPacket - -QUICPacket::QUICPacket(IOBufferBlock *block) : _block(block) +// +QUICPacket::QUICPacket(IOBufferBlock *block, QUICPacketNumber base_packet_number) : _block(block) { - this->_size = block->size(); - this->_header = QUICPacketHeader::load(reinterpret_cast(this->_block->buf()), this->_block->size()); + this->_size = block->size(); + this->_header = + QUICPacketHeader::load(reinterpret_cast(this->_block->buf()), this->_block->size(), base_packet_number); } -QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICVersion version, - ats_unique_buf payload, size_t len, bool retransmittable) +QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len, + bool retransmittable) { - this->_header = QUICPacketHeader::build(type, connection_id, packet_number, version, std::move(payload), len); + this->_header = QUICPacketHeader::build(type, connection_id, packet_number, base_packet_number, version, std::move(payload), len); this->_size = this->_header->length() + len; if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { @@ -444,10 +464,10 @@ QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUIC this->_is_retransmittable = retransmittable; } -QUICPacket::QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len, - bool retransmittable) +QUICPacket::QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, + ats_unique_buf payload, size_t len, bool retransmittable) { - this->_header = QUICPacketHeader::build(type, packet_number, std::move(payload), len); + this->_header = QUICPacketHeader::build(type, packet_number, base_packet_number, std::move(payload), len); this->_size = this->_header->length() + len; if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { @@ -456,10 +476,10 @@ QUICPacket::QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, ats_ this->_is_retransmittable = retransmittable; } -QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, - size_t len, bool retransmittable) +QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - this->_header = QUICPacketHeader::build(type, connection_id, packet_number, std::move(payload), len); + this->_header = QUICPacketHeader::build(type, connection_id, packet_number, base_packet_number, std::move(payload), len); this->_size = this->_header->length() + len; if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { @@ -646,15 +666,15 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si // QUICPacketFactory // std::unique_ptr -QUICPacketFactory::create(IOBufferBlock *block) +QUICPacketFactory::create(IOBufferBlock *block, QUICPacketNumber base_packet_number) { QUICPacket *packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(block); + new (packet) QUICPacket(block, base_packet_number); return std::unique_ptr(packet, &QUICPacketDeleter::delete_packet); } std::unique_ptr -QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_sent_by_client) +QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number) { size_t len = sizeof(QUICVersion) * countof(QUIC_SUPPORTED_VERSIONS); ats_unique_buf versions(reinterpret_cast(ats_malloc(len)), [](void *p) { ats_free(p); }); @@ -669,28 +689,28 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se QUICPacket *packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), packet_sent_by_client->packet_number(), - packet_sent_by_client->version(), std::move(versions), len, false); + base_packet_number, packet_sent_by_client->version(), std::move(versions), len, false); return std::unique_ptr(packet, QUICPacketDeleter::delete_packet); } std::unique_ptr -QUICPacketFactory::create_server_cleartext_packet(QUICConnectionId connection_id, ats_unique_buf payload, size_t len, - bool retransmittable) +QUICPacketFactory::create_server_cleartext_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, + ats_unique_buf payload, size_t len, bool retransmittable) { QUICPacket *p = quicPacketAllocator.alloc(); - new (p) QUICPacket(QUICPacketType::SERVER_CLEARTEXT, connection_id, this->_packet_number_generator.next(), this->_version, - std::move(payload), len, retransmittable); + new (p) QUICPacket(QUICPacketType::SERVER_CLEARTEXT, connection_id, this->_packet_number_generator.next(), base_packet_number, + this->_version, std::move(payload), len, retransmittable); return std::unique_ptr(p, &QUICPacketDeleter::delete_packet); } std::unique_ptr -QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id, ats_unique_buf payload, size_t len, - bool retransmittable) +QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, + ats_unique_buf payload, size_t len, bool retransmittable) { // TODO Key phase should be picked up from QUICCrypto, probably QUICPacket *p = quicPacketAllocator.alloc(); new (p) QUICPacket(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, connection_id, this->_packet_number_generator.next(), - std::move(payload), len, retransmittable); + base_packet_number, std::move(payload), len, retransmittable); auto packet = std::unique_ptr(p, &QUICPacketDeleter::delete_packet); // TODO: use pmtu of UnixNetVConnection @@ -716,12 +736,12 @@ QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id } std::unique_ptr -QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, QUICVersion version, ats_unique_buf payload, - size_t len) +QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, + QUICVersion version, ats_unique_buf payload, size_t len) { QUICPacket *packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(QUICPacketType::CLIENT_INITIAL, connection_id, this->_packet_number_generator.next(), version, - std::move(payload), len, true); + new (packet) QUICPacket(QUICPacketType::CLIENT_INITIAL, connection_id, this->_packet_number_generator.next(), base_packet_number, + version, std::move(payload), len, true); return std::unique_ptr(packet, &QUICPacketDeleter::delete_packet); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 02ecf6640c4..326a348c287 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -39,7 +39,7 @@ class QUICPacketHeader { public: - QUICPacketHeader(const uint8_t *buf, size_t len) : _buf(buf) {} + QUICPacketHeader(const uint8_t *buf, size_t len, QUICPacketNumber base) : _buf(buf), _base_packet_number(base) {} const uint8_t *buf(); virtual QUICPacketType type() const = 0; virtual QUICConnectionId connection_id() const = 0; @@ -49,12 +49,13 @@ class QUICPacketHeader virtual QUICKeyPhase key_phase() const = 0; virtual uint16_t length() const = 0; virtual void store(uint8_t *buf, size_t *len) const = 0; - static QUICPacketHeader *load(const uint8_t *buf, size_t len); - static QUICPacketHeader *build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICVersion version, ats_unique_buf payload, size_t len); - static QUICPacketHeader *build(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len); + static QUICPacketHeader *load(const uint8_t *buf, size_t len, QUICPacketNumber base); static QUICPacketHeader *build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); + static QUICPacketHeader *build(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len); + static QUICPacketHeader *build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len); virtual bool has_key_phase() const = 0; virtual bool has_connection_id() const = 0; virtual bool has_version() const = 0; @@ -62,26 +63,27 @@ class QUICPacketHeader protected: QUICPacketHeader(){}; - const uint8_t *_buf = nullptr; - ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); - QUICPacketType _type = QUICPacketType::UNINITIALIZED; - QUICKeyPhase _key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; - QUICConnectionId _connection_id = 0; - QUICPacketNumber _packet_number = 0; - QUICVersion _version = 0; - size_t _payload_len = 0; - bool _has_key_phase = false; - bool _has_connection_id = false; - bool _has_version = false; + const uint8_t *_buf = nullptr; + ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); + QUICPacketType _type = QUICPacketType::UNINITIALIZED; + QUICKeyPhase _key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; + QUICConnectionId _connection_id = 0; + QUICPacketNumber _packet_number = 0; + QUICPacketNumber _base_packet_number = 0; + QUICVersion _version = 0; + size_t _payload_len = 0; + bool _has_key_phase = false; + bool _has_connection_id = false; + bool _has_version = false; }; class QUICPacketLongHeader : public QUICPacketHeader { public: QUICPacketLongHeader() : QUICPacketHeader(){}; - QUICPacketLongHeader(const uint8_t *buf, size_t len) : QUICPacketHeader(buf, len) {} - QUICPacketLongHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICVersion version, - ats_unique_buf buf, size_t len); + QUICPacketLongHeader(const uint8_t *buf, size_t len, QUICPacketNumber base) : QUICPacketHeader(buf, len, base) {} + QUICPacketLongHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len); QUICPacketType type() const; QUICConnectionId connection_id() const; QUICPacketNumber packet_number() const; @@ -99,10 +101,11 @@ class QUICPacketShortHeader : public QUICPacketHeader { public: QUICPacketShortHeader() : QUICPacketHeader(){}; - QUICPacketShortHeader(const uint8_t *buf, size_t len) : QUICPacketHeader(buf, len) {} - QUICPacketShortHeader(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf buf, size_t len); - QUICPacketShortHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf buf, - size_t len); + QUICPacketShortHeader(const uint8_t *buf, size_t len, QUICPacketNumber base) : QUICPacketHeader(buf, len, base) {} + QUICPacketShortHeader(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, + ats_unique_buf buf, size_t len); + QUICPacketShortHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len); QUICPacketType type() const; QUICConnectionId connection_id() const; QUICPacketNumber packet_number() const; @@ -116,7 +119,8 @@ class QUICPacketShortHeader : public QUICPacketHeader void store(uint8_t *buf, size_t *len) const; private: - int _packet_numberLen() const; + QUICPacketShortHeaderType _discover_packet_number_type(QUICPacketNumber packet_number, QUICPacketNumber base_packet_number) const; + int _packet_number_len() const; QUICPacketShortHeaderType _packet_number_type = QUICPacketShortHeaderType::UNINITIALIZED; }; @@ -124,12 +128,13 @@ class QUICPacket { public: QUICPacket(){}; - QUICPacket(IOBufferBlock *block); - QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICVersion version, - ats_unique_buf payload, size_t len, bool retransmittable); - QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len, bool retransmittable); - QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, - size_t len, bool retransmittabl); + QUICPacket(IOBufferBlock *block, QUICPacketNumber base_packet_number); + QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len, bool retransmittable); + QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, + size_t len, bool retransmittable); + QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittabl); ~QUICPacket(); void set_protected_payload(ats_unique_buf cipher_txt, size_t cipher_txt_len); @@ -197,15 +202,19 @@ class QUICPacketDeleter class QUICPacketFactory { public: - static std::unique_ptr create(IOBufferBlock *block); - std::unique_ptr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client); + static std::unique_ptr create(IOBufferBlock *block, QUICPacketNumber base_packet_number); + std::unique_ptr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, + QUICPacketNumber base_packet_number); std::unique_ptr create_server_cleartext_packet(QUICConnectionId connection_id, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); std::unique_ptr create_server_protected_packet(QUICConnectionId connection_id, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); std::unique_ptr create_client_initial_packet(QUICConnectionId connection_id, + QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); void set_version(QUICVersion negotiated_version); diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index e77f71fbffb..f0cca15b501 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -40,6 +40,7 @@ QUICTypeUtil::hasLongHeader(const uint8_t *buf) QUICConnectionId QUICTypeUtil::read_QUICConnectionId(const uint8_t *buf, uint8_t len) { + // Should be QUICConnectionId(read_nbytes_as_uint(buf, len)); return static_cast(read_nbytes_as_uint(buf, len)); } diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index b23e15656b2..e77670d6112 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -41,8 +41,8 @@ TEST_CASE("QUICLossDetector_Loss_in_Handshake", "[quic]") memcpy(payload.get(), raw, sizeof(raw)); std::unique_ptr packet = std::unique_ptr( - new QUICPacket(QUICPacketType::SERVER_CLEARTEXT, 0xffddbb9977553311ULL, 0x00000001, 0x00112233, std::move(payload), sizeof(raw), - true), + new QUICPacket(QUICPacketType::SERVER_CLEARTEXT, 0xffddbb9977553311ULL, 0x00000001, 0, 0x00112233, std::move(payload), + sizeof(raw), true), [](QUICPacket *p) { delete p; }); detector.on_packet_sent(std::move(packet)); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 82a663272bd..a987004d603 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -32,7 +32,7 @@ TEST_CASE("Loading Long Header Packet", "[quic]") memcpy(payload.get(), raw, sizeof(raw)); // Cleartext packet with a long header - QUICPacket packet1(QUICPacketType::CLIENT_CLEARTEXT, 0xffddbb9977553311ULL, 0xffcc9966, 0x00112233, std::move(payload), + QUICPacket packet1(QUICPacketType::CLIENT_CLEARTEXT, 0xffddbb9977553311ULL, 0xffcc9966, 0, 0x00112233, std::move(payload), sizeof(raw), true); uint8_t buf[65536]; @@ -44,7 +44,7 @@ TEST_CASE("Loading Long Header Packet", "[quic]") memcpy(block->end(), buf, len); block->fill(len); - const QUICPacket packet2(block); + const QUICPacket packet2(block, 0); CHECK(packet2.type() == QUICPacketType::CLIENT_CLEARTEXT); CHECK(packet2.connection_id() == 0xffddbb9977553311ULL); @@ -66,7 +66,7 @@ TEST_CASE("Loading Short Header Packet", "[quic]") memcpy(protected_payload.get(), protected_raw, sizeof(protected_raw)); // Cleartext packet with a long header - QUICPacket packet1(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, 0xffcc9966, std::move(payload), sizeof(raw), true); + QUICPacket packet1(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, 0xffcc9966, 0, std::move(payload), sizeof(raw), true); packet1.set_protected_payload(std::move(protected_payload), sizeof(protected_raw)); uint8_t buf[65536]; @@ -78,7 +78,7 @@ TEST_CASE("Loading Short Header Packet", "[quic]") memcpy(block->end(), buf, len); block->fill(len); - const QUICPacket packet2(block); + const QUICPacket packet2(block, 0); CHECK(packet2.type() == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0); CHECK(packet2.packet_number() == 0xffcc9966); @@ -90,7 +90,7 @@ TEST_CASE("Loading Short Header Packet", "[quic]") TEST_CASE("Loading Unknown Packet", "[quic]") { const uint8_t buf[] = {0xff}; - QUICPacketHeader *header = QUICPacketHeader::load(buf, sizeof(buf)); + QUICPacketHeader *header = QUICPacketHeader::load(buf, sizeof(buf), 0); CHECK(header->type() == QUICPacketType::UNINITIALIZED); } diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 51850ffbfde..b92144b7409 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -42,9 +42,9 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") memcpy(block->end(), client_initial_packet_data, sizeof(client_initial_packet_data)); block->fill(sizeof(client_initial_packet_data)); - QUICPacket client_initial_packet(block); + QUICPacket client_initial_packet(block, 0); - std::unique_ptr packet = factory.create_version_negotiation_packet(&client_initial_packet); + std::unique_ptr packet = factory.create_version_negotiation_packet(&client_initial_packet, 0); CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); CHECK(packet->connection_id() == client_initial_packet.connection_id()); CHECK(packet->packet_number() == client_initial_packet.packet_number()); @@ -61,7 +61,7 @@ TEST_CASE("QUICPacketFactory_Create_ServerCleartextPacket", "[quic]") memcpy(payload.get(), raw, sizeof(raw)); std::unique_ptr packet = - factory.create_server_cleartext_packet(0x01020304, std::move(payload), sizeof(raw), true); + factory.create_server_cleartext_packet(0x01020304, 0, std::move(payload), sizeof(raw), true); CHECK(packet->type() == QUICPacketType::SERVER_CLEARTEXT); CHECK(packet->connection_id() == 0x01020304); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 9de0bdb74ff..1802c63ac05 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -36,7 +36,7 @@ TEST_CASE("QUICVersionNegotiator_Normal", "[quic]") // Negotiate version std::unique_ptr initial_packet = - packet_factory.create_client_initial_packet({}, QUIC_SUPPORTED_VERSIONS[0], ats_unique_malloc(0), 0); + packet_factory.create_client_initial_packet({}, 0, QUIC_SUPPORTED_VERSIONS[0], ats_unique_malloc(0), 0); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); From 368e54b8df5acd4c5eff21a7d29a7fec643bc04f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 5 Sep 2017 16:24:08 +0900 Subject: [PATCH 0083/1313] Schedule QUIC_EVENT_PACKET_WRITE_READY only if it's not scheduled --- iocore/net/P_QUICNetVConnection.h | 2 ++ iocore/net/QUICNetVConnection.cc | 13 ++++++++++--- iocore/net/quic/QUICFrameTransmitter.h | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 02606ea5b64..393701760d7 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -220,6 +220,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection Queue _packet_send_queue; std::queue> _frame_buffer; + Event *_packet_write_ready = nullptr; + void _packetize_frames(); std::unique_ptr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type = QUICPacketType::UNINITIALIZED); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8cf57631614..083dfa0e5d3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -195,7 +195,9 @@ QUICNetVConnection::transmit_packet(std::unique_ptr_packet_send_queue.enqueue(const_cast(packet.release())); - eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + if (!this->_packet_write_ready) { + this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + } } void @@ -242,7 +244,9 @@ QUICNetVConnection::transmit_frame(std::unique_ptrtype()), frame->size()); this->_frame_buffer.push(std::move(frame)); - eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + if (!this->_packet_write_ready) { + this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + } } void @@ -350,6 +354,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) } case QUIC_EVENT_PACKET_WRITE_READY: { error = this->_state_common_send_packet(); + this->_packet_write_ready = nullptr; break; } case EVENT_IMMEDIATE: { @@ -394,6 +399,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) } case QUIC_EVENT_PACKET_WRITE_READY: { error = this->_state_common_send_packet(); + this->_packet_write_ready = nullptr; break; } @@ -428,6 +434,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) } case QUIC_EVENT_PACKET_WRITE_READY: { this->_state_common_send_packet(); + this->_packet_write_ready = nullptr; break; } default: @@ -452,6 +459,7 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) break; } case QUIC_EVENT_PACKET_WRITE_READY: { + this->_packet_write_ready = nullptr; this->next_inactivity_timeout_at = 0; this->next_activity_timeout_at = 0; @@ -722,7 +730,6 @@ QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPac std::unique_ptr ack_frame = this->_ack_frame_creator.create_if_needed(); if (ack_frame != nullptr) { this->transmit_frame(std::move(ack_frame)); - eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); } return error; diff --git a/iocore/net/quic/QUICFrameTransmitter.h b/iocore/net/quic/QUICFrameTransmitter.h index ce3c267bd95..bbf478a4a60 100644 --- a/iocore/net/quic/QUICFrameTransmitter.h +++ b/iocore/net/quic/QUICFrameTransmitter.h @@ -31,7 +31,7 @@ class QUICFrameTransmitter /* * Enqueue a frame for transmission * - * This sends QUIC_PACKET_WRITE_READY event. + * This schedules QUIC_PACKET_WRITE_READY event. */ virtual void transmit_frame(std::unique_ptr frame) = 0; virtual uint32_t maximum_stream_frame_data_size() = 0; From 913767ae488c7f2414545adc22bcc5fd003edba4 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Sep 2017 16:32:32 +0900 Subject: [PATCH 0084/1313] Randomize initial value for packet number --- iocore/net/quic/QUICPacket.cc | 14 ++++++++++++++ iocore/net/quic/QUICPacket.h | 3 ++- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 3ef847fab97..bfae22b58d6 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -761,6 +761,20 @@ QUICPacketFactory::set_crypto_module(QUICCrypto *crypto) // // QUICPacketNumberGenerator // +QUICPacketNumberGenerator::QUICPacketNumberGenerator() +{ + this->randomize(); +} + +QUICPacketNumber +QUICPacketNumberGenerator::randomize() +{ + std::random_device rnd; + this->_current = rnd() & 0x7FFFFFFF; + + return this->_current; +} + QUICPacketNumber QUICPacketNumberGenerator::next() { diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 326a348c287..147f13d7475 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -170,7 +170,8 @@ class QUICPacket class QUICPacketNumberGenerator { public: - QUICPacketNumberGenerator(QUICPacketNumber initial_number = 0) : _current(initial_number){}; + QUICPacketNumberGenerator(); + QUICPacketNumber randomize(); QUICPacketNumber next(); private: diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index b92144b7409..ab989aea06b 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -65,6 +65,6 @@ TEST_CASE("QUICPacketFactory_Create_ServerCleartextPacket", "[quic]") CHECK(packet->type() == QUICPacketType::SERVER_CLEARTEXT); CHECK(packet->connection_id() == 0x01020304); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); - CHECK(packet->packet_number() == 0); + CHECK((packet->packet_number() & 0xFFFFFFFF80000000) == 0); CHECK(packet->version() == 0x11223344); } From c193d323b0dc8e883a0f5d182319bf5e831b7f3c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Sep 2017 10:46:40 +0900 Subject: [PATCH 0085/1313] Prevent triggering READ_READY event on every frame --- iocore/net/QUICNetVConnection.cc | 6 +++--- iocore/net/quic/QUICApplication.cc | 4 +++- iocore/net/quic/QUICStream.cc | 6 +++--- iocore/net/quic/QUICStream.h | 2 +- iocore/net/quic/QUICStreamManager.cc | 11 ++++++----- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 083dfa0e5d3..d6b233c55b5 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -353,7 +353,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) break; } case QUIC_EVENT_PACKET_WRITE_READY: { - error = this->_state_common_send_packet(); + error = this->_state_common_send_packet(); this->_packet_write_ready = nullptr; break; } @@ -398,7 +398,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) break; } case QUIC_EVENT_PACKET_WRITE_READY: { - error = this->_state_common_send_packet(); + error = this->_state_common_send_packet(); this->_packet_write_ready = nullptr; break; } @@ -459,7 +459,7 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) break; } case QUIC_EVENT_PACKET_WRITE_READY: { - this->_packet_write_ready = nullptr; + this->_packet_write_ready = nullptr; this->next_inactivity_timeout_at = 0; this->next_activity_timeout_at = 0; diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 455459a328f..b65b89c3191 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -52,7 +52,9 @@ QUICStreamIO::read_avail() int64_t QUICStreamIO::read(uint8_t *buf, int64_t len) { - return this->_read_buffer_reader->read(const_cast(buf), len); + int64_t read_len = this->_read_buffer_reader->read(const_cast(buf), len); + this->_read_vio->ndone += read_len; + return read_len; } int64_t diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index f03dd8ad7eb..c16d0dd34db 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -392,10 +392,10 @@ QUICStream::reset() // TODO: Create a RST_STREAM frame and pass it to Stream Manager } -bool -QUICStream::is_read_ready() +size_t +QUICStream::nbytes_to_read() { - return this->_read_vio.nbytes > 0; + return this->_read_vio.ntodo(); } QUICOffset diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 2f28c90a677..0c3e73bcdbc 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -66,7 +66,7 @@ class QUICStream : public VConnection void reset(); - bool is_read_ready(); + size_t nbytes_to_read(); QUICOffset largest_offset_received(); QUICOffset largest_offset_sent(); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 8db20cab1de..6125cf9b58f 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -132,11 +132,12 @@ QUICStreamManager::_handle_frame(const std::shared_ptr &f application->set_stream(stream); } - QUICError error = stream->recv(frame); - - // FIXME: schedule VC_EVENT_READ_READY to application every single frame? - // If application reading buffer continuously, do not schedule event. - this_ethread()->schedule_imm(application, VC_EVENT_READ_READY, stream); + size_t nbytes_to_read = stream->nbytes_to_read(); + QUICError error = stream->recv(frame); + // Prevent trigger read events multiple times + if (nbytes_to_read == 0) { + this_ethread()->schedule_imm(application, VC_EVENT_READ_READY, stream); + } return error; } From 6d8eee58fb8abdff2e796c0f1a9f12ba64ec37f6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 6 Sep 2017 16:35:15 +0900 Subject: [PATCH 0086/1313] Rename buffer for received STREAM frame --- iocore/net/quic/QUICStream.cc | 10 +++++----- iocore/net/quic/QUICStream.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index c16d0dd34db..0ca060d20d7 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -267,10 +267,10 @@ QUICStream::_write_to_read_vio(const std::shared_ptr &fra void QUICStream::_reorder_data() { - auto frame = _request_stream_frame_buffer.find(this->_recv_offset); - while (frame != this->_request_stream_frame_buffer.end()) { + auto frame = _received_stream_frame_buffer.find(this->_recv_offset); + while (frame != this->_received_stream_frame_buffer.end()) { this->_write_to_read_vio(frame->second); - frame = _request_stream_frame_buffer.find(this->_recv_offset); + frame = _received_stream_frame_buffer.find(this->_recv_offset); } } @@ -310,9 +310,9 @@ QUICStream::recv(const std::shared_ptr frame) this->_write_to_read_vio(frame); this->_reorder_data(); } else { - // NOTE: push fragments in _request_stream_frame_buffer temporally. + // NOTE: push fragments in _received_stream_frame_buffer temporally. // They will be reordered when missing data is filled and offset is matched. - this->_request_stream_frame_buffer.insert(std::make_pair(frame->offset(), frame)); + this->_received_stream_frame_buffer.insert(std::make_pair(frame->offset(), frame)); } return QUICError(QUICErrorClass::NONE); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 0c3e73bcdbc..ff7bb145dc1 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -105,7 +105,7 @@ class QUICStream : public VConnection // Fragments of received STREAM frame (offset is unmatched) // TODO: Consider to replace with ts/RbTree.h or other data structure - std::map> _request_stream_frame_buffer; + std::map> _received_stream_frame_buffer; QUICStreamManager *_stream_manager = nullptr; QUICFrameTransmitter *_tx = nullptr; From 27fca42498de9d55d54dd53ca07d6f5858f5fca4 Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 6 Sep 2017 10:59:41 +0800 Subject: [PATCH 0087/1313] support stateless retry token in transport parameters --- iocore/net/P_QUICNetVConnection.h | 2 ++ iocore/net/QUICNetVConnection.cc | 5 +++- iocore/net/quic/QUICHandshake.cc | 5 +++- iocore/net/quic/QUICHandshake.h | 4 ++- iocore/net/quic/QUICTransportParameters.cc | 15 ++++++++++ iocore/net/quic/QUICTransportParameters.h | 2 ++ iocore/net/quic/QUICTypes.h | 23 +++++++++++++++ .../quic/test/test_QUICTransportParameters.cc | 28 ++++++++++++------- 8 files changed, 71 insertions(+), 13 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 393701760d7..1216f43c2ab 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -240,6 +240,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICApplication *_create_application(); void _init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); + + QUICStatelessToken _token; }; extern ClassAllocator quicNetVCAllocator; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index d6b233c55b5..fce4ad8253d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -49,6 +49,7 @@ static constexpr uint32_t MINIMUM_MTU = 1280; static constexpr uint32_t MAX_PACKET_OVERHEAD = 25; // Max long header len(17) + FNV-1a hash len(8) static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; +static constexpr char STATELESS_RETRY_TOKEN_KEY[] = "stateless_token_retry_key"; ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); @@ -95,7 +96,9 @@ void QUICNetVConnection::start(SSL_CTX *ssl_ctx) { // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not - this->_handshake_handler = new QUICHandshake(this, ssl_ctx); + this->_token.gen_token(STATELESS_RETRY_TOKEN_KEY, _quic_connection_id ^ id); + + this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_token.get()); this->_application_map = new QUICApplicationMap(); this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 85455fcacb9..ef82f7527fe 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -54,7 +54,7 @@ static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICApplication(qc) +QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, INK_MD5 token) : QUICApplication(qc), _token(token) { this->_ssl = SSL_new(ssl_ctx); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc); @@ -257,6 +257,9 @@ QUICHandshake::_load_local_transport_parameters() tp->add(QUICTransportParameterId::IDLE_TIMEOUT, std::unique_ptr(new QUICTransportParameterValue( params->no_activity_timeout_in(), sizeof(uint16_t)))); + tp->add(QUICTransportParameterId::STATELESS_RETRY_TOKEN, + std::unique_ptr(new QUICTransportParameterValue(this->_token.u64, 16))); + tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); // MAYs // this->_local_transport_parameters.add(QUICTransportParameterId::TRUNCATE_CONNECTION_ID, {}); diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 61baa4a2738..e8866d6c4bc 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -50,7 +50,7 @@ class SSLNextProtocolSet; class QUICHandshake : public QUICApplication { public: - QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx); + QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, INK_MD5 token); ~QUICHandshake(); QUICError start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); @@ -87,4 +87,6 @@ class QUICHandshake : public QUICApplication QUICError _process_client_hello(); QUICError _process_client_finished(); QUICError _process_handshake_complete(); + + INK_MD5 _token; }; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 50c149faadf..2debfac9ffb 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -44,6 +44,21 @@ QUICTransportParameterValue::QUICTransportParameterValue(uint64_t raw_data, uint this->_len = len; }; +QUICTransportParameterValue::QUICTransportParameterValue(uint64_t raw_data[2], uint16_t l) +{ + this->_data = ats_unique_malloc(l); + size_t len = 0; + if (l > 8) { + QUICTypeUtil::write_uint_as_nbytes(raw_data[0], 8, this->_data.get(), &len); + this->_len += len; + QUICTypeUtil::write_uint_as_nbytes(raw_data[1], l - 8, this->_data.get() + 8, &len); + this->_len += len; + } else { + QUICTypeUtil::write_uint_as_nbytes(raw_data[0], l, this->_data.get(), &len); + this->_len += len; + } +} + const uint8_t * QUICTransportParameterValue::data() const { diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 87d8af66c32..63923b07dd9 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -40,6 +40,7 @@ class QUICTransportParameterId IDLE_TIMEOUT, TRUNCATE_CONNECTION_ID, MAX_PACKET_SIZE, + STATELESS_RETRY_TOKEN, }; explicit operator bool() const { return true; } @@ -68,6 +69,7 @@ class QUICTransportParameterValue public: QUICTransportParameterValue(ats_unique_buf d, uint16_t l); QUICTransportParameterValue(uint64_t raw_data, uint16_t l); + QUICTransportParameterValue(uint64_t raw_data[2], uint16_t l); const uint8_t *data() const; uint16_t len() const; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 5c3f9c27e9b..cd2f21b44a4 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -37,6 +37,7 @@ #include #include #include +#include "ts/INK_MD5.h" #include "ts/ink_memory.h" // These magical defines should be removed when we implement seriously @@ -149,6 +150,28 @@ struct QUICError { const char *msg; }; +class QUICStatelessToken +{ +public: + void + gen_token(const char *key, uint64_t data) + { + MD5Context ctx; + ctx.update(key, strlen(key)); + ctx.update(reinterpret_cast(&data), 8); + ctx.finalize(_md5); + } + + const INK_MD5 + get() const + { + return _md5; + } + +private: + INK_MD5 _md5; +}; + class QUICConnectionId { public: diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index adf3daf57e6..b65e406cdb9 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -79,15 +79,19 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") uint16_t len; uint8_t expected[] = { - 0x01, 0x02, 0x03, 0x04, // negotiated version - 0x05, 0x06, 0x07, 0x08, // iinitial version - 0x00, 0x0e, // size of parameters - 0x00, 0x00, // parameter id - 0x00, 0x04, // length of value - 0x11, 0x22, 0x33, 0x44, // value - 0x00, 0x05, // parameter id - 0x00, 0x02, // length of value - 0xab, 0xcd, // value + 0x01, 0x02, 0x03, 0x04, // negotiated version + 0x05, 0x06, 0x07, 0x08, // iinitial version + 0x00, 0x22, // size of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value + 0x00, 0x05, // parameter id + 0x00, 0x02, // length of value + 0xab, 0xcd, // value + 0x00, 0x06, // parameter id + 0x00, 0x10, // length of value + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // value + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // value }; QUICTransportParametersInClientHello params_in_ch(0x01020304, 0x05060708); @@ -102,8 +106,12 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") QUICTransportParameterId::MAX_PACKET_SIZE, std::unique_ptr(new QUICTransportParameterValue(max_packet_size, sizeof(max_packet_size)))); + uint64_t stateless_retry_token[2] = {0x0011223344556677, 0x0011223344556677}; + params_in_ch.add(QUICTransportParameterId::STATELESS_RETRY_TOKEN, + std::unique_ptr(new QUICTransportParameterValue(stateless_retry_token, 16))); + params_in_ch.store(buf, &len); - CHECK(len == 24); + CHECK(len == 44); CHECK(memcmp(buf, expected, len) == 0); } From d62137c4ba9b715484dd7c0284440b9510e30474 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 11 Sep 2017 11:06:58 +0900 Subject: [PATCH 0088/1313] Append PADDING frame randomly Minimum QUIC packet size applies only Cilent Initial Packet --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 21 ++++++++++++--------- iocore/net/quic/QUICConnection.h | 17 +++++++++++++++-- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 1216f43c2ab..61d16e28ceb 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -191,6 +191,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICError handle_frame(std::shared_ptr frame) override; private: + std::random_device _rnd; QUICConnectionId _quic_connection_id; QUICPacketNumber _largest_received_packet_number = 0; UDPConnection *_udp_con = nullptr; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index fce4ad8253d..c9654a3539b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -46,10 +46,10 @@ #define DebugQUICCon(fmt, ...) \ Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) -static constexpr uint32_t MINIMUM_MTU = 1280; -static constexpr uint32_t MAX_PACKET_OVERHEAD = 25; // Max long header len(17) + FNV-1a hash len(8) -static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; -static constexpr char STATELESS_RETRY_TOKEN_KEY[] = "stateless_token_retry_key"; +static constexpr uint32_t MAX_PACKET_OVERHEAD = 25; // Max long header len(17) + FNV-1a hash len(8) +static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; +static constexpr uint32_t MINIMUM_INITIAL_CLIENT_PACKET_SIZE = 1200; +static constexpr char STATELESS_RETRY_TOKEN_KEY[] = "stateless_token_retry_key"; ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); @@ -170,10 +170,13 @@ QUICNetVConnection::direction() uint32_t QUICNetVConnection::minimum_quic_packet_size() { - if (this->options.ip_family == PF_INET6) { - return MINIMUM_MTU - 48; + if (netvc_context == NET_VCONNECTION_OUT) { + // FIXME Only the first packet need to be 1200 bytes at least + return MINIMUM_INITIAL_CLIENT_PACKET_SIZE; } else { - return MINIMUM_MTU - 28; + // FIXME This size should be configurable and should have some randomness + // This is just for providing protection against packet analysis for protected packets + return 32 + (this->_rnd() & 0x3f); // 32 to 96 } } @@ -533,8 +536,8 @@ QUICNetVConnection::largest_acked_packet_number() QUICError QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_ptr packet) { - if (packet->size() < this->minimum_quic_packet_size()) { - DebugQUICCon("%" PRId32 ", %" PRId32, packet->size(), this->minimum_quic_packet_size()); + if (packet->size() < MINIMUM_INITIAL_CLIENT_PACKET_SIZE) { + DebugQUICCon("Packet size is smaller than the minimum initial client packet size"); return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); } diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 8113ade1291..69dfea6d300 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -34,8 +34,21 @@ class SSLNextProtocolSet; class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler { public: - virtual uint32_t maximum_quic_packet_size() = 0; - virtual uint32_t minimum_quic_packet_size() = 0; + /* + * Retruns the maximum packet size at the time called + * + * The size depends on PMTU. + */ + virtual uint32_t maximum_quic_packet_size() = 0; + + /* + * Returns the mimimum packet size at the time called + * + * If the connection is an outgoing connection and you have not sent Client Initial packet, + * this return the minimum size for it, which is 1200. + */ + virtual uint32_t minimum_quic_packet_size() = 0; + virtual uint32_t pmtu() = 0; virtual NetVConnectionContext_t direction() = 0; virtual SSLNextProtocolSet *next_protocol_set() = 0; From c1a88370301c7174a3f7fbcb25fccb1376a2921a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 11 Sep 2017 11:08:50 +0900 Subject: [PATCH 0089/1313] [draft-05] Increase the maximum lenght of ACK Block Length to 64 bits --- iocore/net/quic/QUICFrame.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index e64b37b0381..847eb62ba11 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -467,14 +467,10 @@ QUICAckFrame::_get_ack_block_length() const * 0 -> 1 byte * 1 -> 2 byte * 2 -> 4 byte - * 3 -> 6 byte + * 3 -> 8 byte */ int n = this->_buf[0] & 0x03; - if (n == 0) { - return 1; - } else { - return n * 2; - } + return 0x01 << n; } size_t From 2f2ca3b2620e1672b21bdd102acf28c5b1a92948 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 11 Sep 2017 11:13:53 +0900 Subject: [PATCH 0090/1313] Rename truncate_connection_id to omit_connection_id --- iocore/net/quic/QUICDebugNames.cc | 4 ++-- iocore/net/quic/QUICHandshake.cc | 2 +- iocore/net/quic/QUICTransportParameters.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 66b686617de..0599294e6d3 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -169,8 +169,8 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) return "INITIAL_MAX_STREAM_ID"; case QUICTransportParameterId::IDLE_TIMEOUT: return "IDLE_TIMEOUT"; - case QUICTransportParameterId::TRUNCATE_CONNECTION_ID: - return "TRUNCATE_CONNECTION_ID"; + case QUICTransportParameterId::OMIT_CONNECTION_ID: + return "OMIT_CONNECTION_ID"; case QUICTransportParameterId::MAX_PACKET_SIZE: return "MAX_PACKET_SIZE"; default: diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index ef82f7527fe..4c948352d4c 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -262,7 +262,7 @@ QUICHandshake::_load_local_transport_parameters() tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); // MAYs - // this->_local_transport_parameters.add(QUICTransportParameterId::TRUNCATE_CONNECTION_ID, {}); + // this->_local_transport_parameters.add(QUICTransportParameterId::OMIT_CONNECTION_ID, {}); // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); this->_local_transport_parameters = std::unique_ptr(tp); } diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 63923b07dd9..06adaf4ac10 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -38,7 +38,7 @@ class QUICTransportParameterId INITIAL_MAX_DATA, INITIAL_MAX_STREAM_ID, IDLE_TIMEOUT, - TRUNCATE_CONNECTION_ID, + OMIT_CONNECTION_ID, MAX_PACKET_SIZE, STATELESS_RETRY_TOKEN, }; From 6160455655b2c2aef934fe081cedb7f3f1a8d057 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 11 Sep 2017 11:29:28 +0900 Subject: [PATCH 0091/1313] [draft-05] Remove GOAWAY frame --- iocore/net/quic/QUICFrame.cc | 61 -------------------------- iocore/net/quic/QUICFrame.h | 28 ------------ iocore/net/quic/test/test_QUICFrame.cc | 57 +++++------------------- 3 files changed, 11 insertions(+), 135 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 847eb62ba11..c6394fbd1db 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -28,7 +28,6 @@ ClassAllocator quicAckFrameAllocator("quicAckFrameAllocator"); ClassAllocator quicPaddingFrameAllocator("quicPaddingFrameAllocator"); ClassAllocator quicRstStreamFrameAllocator("quicRstStreamFrameAllocator"); ClassAllocator quicConnectionCloseFrameAllocator("quicConnectionCloseFrameAllocator"); -ClassAllocator quicGoawayFrameAllocator("quicGoawayAllocator"); ClassAllocator quicMaxDataFrameAllocator("quicMaxDataFrameAllocator"); ClassAllocator quicMaxStreamDataFrameAllocator("quicMaxStreamDataFrameAllocator"); ClassAllocator quicMaxStreamIdFrameAllocator("quicMaxStreamDataIdAllocator"); @@ -744,62 +743,6 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len) const *len = 1; } -// -// GOAWAY frame -// - -QUICGoawayFrame::QUICGoawayFrame(QUICStreamId client_stream_id, QUICStreamId server_stream_id) -{ - this->_client_stream_id = client_stream_id; - this->_server_stream_id = server_stream_id; -} - -QUICFrameType -QUICGoawayFrame::type() const -{ - return QUICFrameType::GOAWAY; -} - -size_t -QUICGoawayFrame::size() const -{ - return 9; -} - -void -QUICGoawayFrame::store(uint8_t *buf, size_t *len) const -{ - size_t n; - uint8_t *p = buf; - *p = 0x03; - ++p; - QUICTypeUtil::write_QUICStreamId(this->_client_stream_id, 4, p, &n); - p += n; - QUICTypeUtil::write_QUICStreamId(this->_server_stream_id, 4, p, &n); - p += n; - *len = p - buf; -} - -QUICStreamId -QUICGoawayFrame::client_stream_id() const -{ - if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + 1, 4); - } else { - return this->_client_stream_id; - } -} - -QUICStreamId -QUICGoawayFrame::server_stream_id() const -{ - if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + 5, 4); - } else { - return this->_server_stream_id; - } -} - // // CONNECTION_CLOSE frame // @@ -1220,10 +1163,6 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicConnectionCloseFrameAllocator.alloc(); new (frame) QUICConnectionCloseFrame(buf, len); return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); - case QUICFrameType::GOAWAY: - frame = quicGoawayFrameAllocator.alloc(); - new (frame) QUICGoawayFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_goaway_frame); case QUICFrameType::MAX_DATA: frame = quicMaxDataFrameAllocator.alloc(); new (frame) QUICMaxDataFrame(buf, len); diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 0272a82d484..d39ab69227d 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -259,27 +259,6 @@ class QUICPaddingFrame : public QUICFrame virtual void store(uint8_t *buf, size_t *len) const override; }; -// -// GOAWAY -// - -class QUICGoawayFrame : public QUICFrame -{ -public: - QUICGoawayFrame() : QUICFrame() {} - QUICGoawayFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICGoawayFrame(QUICStreamId client_stream_id, QUICStreamId server_stream_id); - virtual QUICFrameType type() const override; - virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; - QUICStreamId client_stream_id() const; - QUICStreamId server_stream_id() const; - -private: - QUICStreamId _client_stream_id = 0; - QUICStreamId _server_stream_id = 0; -}; - // // CONNECTION_CLOSE // @@ -456,7 +435,6 @@ extern ClassAllocator quicAckFrameAllocator; extern ClassAllocator quicPaddingFrameAllocator; extern ClassAllocator quicRstStreamFrameAllocator; extern ClassAllocator quicConnectionCloseFrameAllocator; -extern ClassAllocator quicGoawayFrameAllocator; extern ClassAllocator quicMaxDataFrameAllocator; extern ClassAllocator quicMaxStreamDataFrameAllocator; extern ClassAllocator quicMaxStreamIdFrameAllocator; @@ -506,12 +484,6 @@ class QUICFrameDeleter quicConnectionCloseFrameAllocator.free(static_cast(frame)); } - static void - delete_goaway_frame(QUICFrame *frame) - { - quicGoawayFrameAllocator.free(static_cast(frame)); - } - static void delete_max_data_frame(QUICFrame *frame) { diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 2fbc6a91c2d..6091cd0c4a1 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -279,38 +279,6 @@ TEST_CASE("Store Padding Frame", "[quic]") CHECK(memcmp(buf, expected, len) == 0); } -TEST_CASE("Load Goaway Frame", "[quic]") -{ - uint8_t buf1[] = { - 0x03, // Type - 0x12, 0x34, 0x56, 0x78, // Latest Client Stream ID - 0xAA, 0xBB, 0xCC, 0xDD, // Latest Server Stream ID - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::GOAWAY); - CHECK(frame1->size() == 9); - std::shared_ptr goawayFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(goawayFrame1 != nullptr); - CHECK(goawayFrame1->client_stream_id() == 0x12345678); - CHECK(goawayFrame1->server_stream_id() == 0xAABBCCDD); -} - -TEST_CASE("Store Goaway Frame", "[quic]") -{ - uint8_t buf[65535]; - size_t len; - - uint8_t expected[] = { - 0x03, // Type - 0x12, 0x34, 0x56, 0x78, // Latest Client Stream ID - 0xAA, 0xBB, 0xCC, 0xDD, // Latest Server Stream ID - }; - QUICGoawayFrame goawayFrame(0x12345678, 0xAABBCCDD); - goawayFrame.store(buf, &len); - CHECK(len == 9); - CHECK(memcmp(buf, expected, len) == 0); -} - TEST_CASE("Load ConnectionClose Frame", "[quic]") { uint8_t buf1[] = { @@ -568,29 +536,26 @@ TEST_CASE("QUICFrameFactory Fast Create Frame", "[quic]") QUICFrameFactory factory; uint8_t buf1[] = { - 0x03, // Type - 0x12, 0x34, 0x56, 0x78, // Latest Client Stream ID - 0xAA, 0xBB, 0xCC, 0xDD, // Latest Server Stream ID + 0x06, // Type + 0x01, 0x02, 0x03, 0x04, // Stream Data }; uint8_t buf2[] = { - 0x03, // Type - 0x11, 0x22, 0x33, 0x44, // Latest Client Stream ID - 0x0A, 0x0B, 0x0C, 0x0D, // Latest Server Stream ID + 0x06, // Type + 0x05, 0x06, 0x07, 0x08, // Stream Data }; std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); CHECK(frame1 != nullptr); - std::shared_ptr goawayFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(goawayFrame1 != nullptr); - CHECK(goawayFrame1->client_stream_id() == 0x12345678); - CHECK(goawayFrame1->server_stream_id() == 0xAABBCCDD); + std::shared_ptr max_stream_id_frame1 = std::dynamic_pointer_cast(frame1); + CHECK(max_stream_id_frame1 != nullptr); + CHECK(max_stream_id_frame1->maximum_stream_id() == 0x01020304); std::shared_ptr frame2 = factory.fast_create(buf2, sizeof(buf2)); CHECK(frame2 != nullptr); - std::shared_ptr goawayFrame2 = std::dynamic_pointer_cast(frame2); - CHECK(goawayFrame2 != nullptr); - CHECK(goawayFrame2->client_stream_id() == 0x11223344); - CHECK(goawayFrame2->server_stream_id() == 0x0A0B0C0D); + + std::shared_ptr max_stream_id_frame2 = std::dynamic_pointer_cast(frame2); + CHECK(max_stream_id_frame2 != nullptr); + CHECK(max_stream_id_frame2->maximum_stream_id() == 0x05060708); CHECK(frame1 == frame2); } From e98590b5d7934360ffef3c6f9b5918969e746fa4 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 11 Sep 2017 11:43:12 +0900 Subject: [PATCH 0092/1313] [draft-05] Remove GOAWAY frame from QUICFrameType --- iocore/net/quic/QUICDebugNames.cc | 2 -- iocore/net/quic/QUICTypes.h | 3 +-- iocore/net/quic/test/test_QUICFrame.cc | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 0599294e6d3..d580be78d48 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -62,8 +62,6 @@ QUICDebugNames::frame_type(QUICFrameType type) return "RST_STREAM"; case QUICFrameType::CONNECTION_CLOSE: return "CONNECTION_CLOSE"; - case QUICFrameType::GOAWAY: - return "GOAWAY"; case QUICFrameType::MAX_DATA: return "MAX_DATA"; case QUICFrameType::MAX_STREAM_DATA: diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index cd2f21b44a4..926bd2a1c70 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -88,8 +88,7 @@ enum class QUICFrameType : int { PADDING = 0x00, RST_STREAM, CONNECTION_CLOSE, - GOAWAY, - MAX_DATA, + MAX_DATA = 0x04, MAX_STREAM_DATA, MAX_STREAM_ID, PING, diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 6091cd0c4a1..79409935469 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -30,7 +30,6 @@ TEST_CASE("QUICFrame Type", "[quic]") CHECK(QUICFrame::type(reinterpret_cast("\x00")) == QUICFrameType::PADDING); CHECK(QUICFrame::type(reinterpret_cast("\x01")) == QUICFrameType::RST_STREAM); CHECK(QUICFrame::type(reinterpret_cast("\x02")) == QUICFrameType::CONNECTION_CLOSE); - CHECK(QUICFrame::type(reinterpret_cast("\x03")) == QUICFrameType::GOAWAY); CHECK(QUICFrame::type(reinterpret_cast("\x04")) == QUICFrameType::MAX_DATA); CHECK(QUICFrame::type(reinterpret_cast("\x05")) == QUICFrameType::MAX_STREAM_DATA); CHECK(QUICFrame::type(reinterpret_cast("\x06")) == QUICFrameType::MAX_STREAM_ID); From c445c53e159472ae894825d7f1628b877d534612 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 11 Sep 2017 11:51:37 +0900 Subject: [PATCH 0093/1313] Fix RST_STREAM frame format --- iocore/net/quic/QUICFrame.cc | 18 +++++++++++++----- iocore/net/quic/test/test_QUICFrame.cc | 4 ++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index c6394fbd1db..3ab7a528f82 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -667,10 +667,10 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len) const uint8_t *p = buf; *p = 0x01; ++p; - QUICTypeUtil::write_QUICErrorCode(this->_error_code, p, &n); - p += n; QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n); p += n; + QUICTypeUtil::write_QUICErrorCode(this->_error_code, p, &n); + p += n; QUICTypeUtil::write_QUICOffset(this->_final_offset, 8, p, &n); p += n; @@ -680,14 +680,18 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len) const QUICErrorCode QUICRstStreamFrame::error_code() const { - return QUICTypeUtil::read_QUICErrorCode(this->_buf + 1); + if (this->_buf) { + return QUICTypeUtil::read_QUICErrorCode(this->_buf + 5); + } else { + return this->_error_code; + } } QUICStreamId QUICRstStreamFrame::stream_id() const { if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + 5, 4); + return QUICTypeUtil::read_QUICStreamId(this->_buf + 1, 4); } else { return this->_stream_id; } @@ -696,7 +700,11 @@ QUICRstStreamFrame::stream_id() const QUICOffset QUICRstStreamFrame::final_offset() const { - return QUICTypeUtil::read_QUICOffset(this->_buf + 9, 8); + if (this->_buf) { + return QUICTypeUtil::read_QUICOffset(this->_buf + 9, 8); + } else { + return this->_final_offset; + } } // diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 79409935469..809f2e7db90 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -195,8 +195,8 @@ TEST_CASE("Load RST_STREAM Frame", "[quic]") { uint8_t buf1[] = { 0x01, // Type - 0x80, 0x00, 0x00, 0x00, // Error Code 0x12, 0x34, 0x56, 0x78, // Stream ID + 0x80, 0x00, 0x00, 0x00, // Error Code 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); @@ -216,8 +216,8 @@ TEST_CASE("Store RST_STREAM Frame", "[quic]") uint8_t expected[] = { 0x01, // Type - 0x80, 0x00, 0x00, 0x00, // Error Code 0x12, 0x34, 0x56, 0x78, // Stream ID + 0x80, 0x00, 0x00, 0x00, // Error Code 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset }; QUICRstStreamFrame rstStreamFrame(QUICErrorCode::QUIC_TRANSPORT_ERROR, 0x12345678, 0x1122334455667788); From 533f8bbe94884e46521e5af45d6da7b6dc4f2de5 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 9 Sep 2017 20:38:46 +0800 Subject: [PATCH 0094/1313] initialize the quic stream after allocator.alloc --- iocore/net/quic/QUICStreamManager.cc | 2 +- .../net/quic/test/test_QUICStreamManager.cc | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 6125cf9b58f..a5daa620612 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -196,7 +196,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) QUICStream *stream = this->_find_stream(stream_id); if (!stream) { // TODO Free the stream somewhere - stream = THREAD_ALLOC_INIT(quicStreamAllocator, this_ethread()); + stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream(); if (stream_id == STREAM_ID_FOR_HANDSHAKE) { // XXX rece/send max_stream_data are going to be set by init_flow_control_params() stream->init(this, this->_tx, stream_id, this->_local_tp->initial_max_stream_data()); diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index fdf4c515856..450fbe48c40 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -68,6 +68,26 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") CHECK(sm.stream_count() == 5); } +TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") +{ + MockQUICFrameTransmitter tx; + QUICApplicationMap app_map; + MockQUICApplication mock_app; + app_map.set_default(&mock_app); + QUICStreamManager sm(&tx, &app_map); + std::shared_ptr local_tp = std::make_shared(); + std::shared_ptr remote_tp = + std::make_shared(static_cast(0), static_cast(0)); + sm.init_flow_control_params(local_tp, remote_tp); + + // STREAM frames create new streams + std::shared_ptr stream_frame_0 = + QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 7); + + sm.handle_frame(stream_frame_0); + CHECK("succeed"); +} + TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") { MockQUICFrameTransmitter tx; From 58bd89f66df87e359816085a12a49cce4150bba9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 11 Sep 2017 15:11:15 +0900 Subject: [PATCH 0095/1313] [draft-05] Add STOP_SENDING frame --- iocore/net/quic/QUICFrame.cc | 72 +++++++++++++++++++++++++- iocore/net/quic/QUICFrame.h | 34 ++++++++++++ iocore/net/quic/QUICTypes.h | 2 + iocore/net/quic/test/test_QUICFrame.cc | 37 ++++++++++++- 4 files changed, 143 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 3ab7a528f82..c8f22291c13 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -36,6 +36,7 @@ ClassAllocator quicBlockedFrameAllocator("quicBlockedFrameAllo ClassAllocator quicStreamBlockedFrameAllocator("quicStreamBlockedFrameAllocator"); ClassAllocator quicStreamIdNeededFrameAllocator("quicStreamIdNeededFrameAllocator"); ClassAllocator quicNewConnectionIdFrameAllocator("quicNewConnectionIdFrameAllocator"); +ClassAllocator quicStopSendingFrameAllocator("quicStopSendingFrameAllocator"); ClassAllocator quicRetransmissionFrameAllocator("quicRetransmissionFrameAllocator"); QUICFrameType @@ -44,6 +45,7 @@ QUICFrame::type() const return QUICFrame::type(this->_buf); } +// XXX QUICFrameType: 0x03 (GOAWAY frame) is removed QUICFrameType QUICFrame::type(const uint8_t *buf) { @@ -51,7 +53,7 @@ QUICFrame::type(const uint8_t *buf) return QUICFrameType::STREAM; } else if (buf[0] >= static_cast(QUICFrameType::ACK)) { return QUICFrameType::ACK; - } else if (static_cast(QUICFrameType::NEW_CONNECTION_ID) < buf[0] && buf[0] < static_cast(QUICFrameType::ACK)) { + } else if (buf[0] > static_cast(QUICFrameType::STOP_SENDING) || buf[0] == 0x03) { return QUICFrameType::UNKNOWN; } else { return static_cast(buf[0]); @@ -1108,6 +1110,62 @@ QUICNewConnectionIdFrame::connection_id() const } } +// +// STOP_SENDING frame +// + +QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICErrorCode error_code) + : _stream_id(stream_id), _error_code(error_code) +{ +} + +QUICFrameType +QUICStopSendingFrame::type() const +{ + return QUICFrameType::STOP_SENDING; +} + +size_t +QUICStopSendingFrame::size() const +{ + return 9; +} + +void +QUICStopSendingFrame::store(uint8_t *buf, size_t *len) const +{ + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::STOP_SENDING); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n); + p += n; + QUICTypeUtil::write_QUICErrorCode(this->_error_code, p, &n); + p += n; + + *len = p - buf; +} + +QUICErrorCode +QUICStopSendingFrame::error_code() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICErrorCode(this->_buf + 5); + } else { + return this->_error_code; + } +} + +QUICStreamId +QUICStopSendingFrame::stream_id() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICStreamId(this->_buf + 1, 4); + } else { + return this->_stream_id; + } +} + // // QUICRetransmissionFrame // @@ -1203,6 +1261,10 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicNewConnectionIdFrameAllocator.alloc(); new (frame) QUICNewConnectionIdFrame(buf, len); return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_connection_id_frame); + case QUICFrameType::STOP_SENDING: + frame = quicStopSendingFrameAllocator.alloc(); + new (frame) QUICStopSendingFrame(buf, len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_stop_sending_frame); default: // Unknown frame return std::unique_ptr(nullptr, &QUICFrameDeleter::delete_null_frame); @@ -1294,6 +1356,14 @@ QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICErrorCode return std::unique_ptr(frame, &QUICFrameDeleter::delete_rst_stream_frame); } +std::unique_ptr +QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICErrorCode error_code) +{ + QUICStopSendingFrame *frame = quicStopSendingFrameAllocator.alloc(); + new (frame) QUICStopSendingFrame(stream_id, error_code); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_stop_sending_frame); +} + std::unique_ptr QUICFrameFactory::create_retransmission_frame(std::unique_ptr original_frame, const QUICPacket &original_packet) diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index d39ab69227d..e696961e8f1 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -407,6 +407,27 @@ class QUICNewConnectionIdFrame : public QUICFrame QUICConnectionId _connection_id = 0; }; +// +// STOP_SENDING +// + +class QUICStopSendingFrame : public QUICFrame +{ +public: + QUICStopSendingFrame() : QUICFrame() {} + QUICStopSendingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICStopSendingFrame(QUICStreamId stream_id, QUICErrorCode error_code); + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + QUICStreamId stream_id() const; + QUICErrorCode error_code() const; + +private: + QUICStreamId _stream_id = 0; + QUICErrorCode _error_code; +}; + using QUICFrameDeleterFunc = void (*)(QUICFrame *p); using QUICFramePtr = std::unique_ptr; @@ -443,6 +464,7 @@ extern ClassAllocator quicBlockedFrameAllocator; extern ClassAllocator quicStreamBlockedFrameAllocator; extern ClassAllocator quicStreamIdNeededFrameAllocator; extern ClassAllocator quicNewConnectionIdFrameAllocator; +extern ClassAllocator quicStopSendingFrameAllocator; extern ClassAllocator quicRetransmissionFrameAllocator; class QUICFrameDeleter @@ -532,6 +554,12 @@ class QUICFrameDeleter quicNewConnectionIdFrameAllocator.free(static_cast(frame)); } + static void + delete_stop_sending_frame(QUICFrame *frame) + { + quicStopSendingFrameAllocator.free(static_cast(frame)); + } + static void delete_retransmission_frame(QUICFrame *frame) { @@ -604,6 +632,12 @@ class QUICFrameFactory QUICErrorCode error_code, QUICOffset final_offset); + /* + * Creates a STOP_SENDING frame. + */ + static std::unique_ptr create_stop_sending_frame(QUICStreamId stream_id, + QUICErrorCode error_code); + /* * Creates a retransmission frame, which is very special. * This retransmission frame will be used only for retransmission and it's not a standard frame type. diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 926bd2a1c70..787f74e448c 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -84,6 +84,7 @@ enum class QUICPacketShortHeaderType : int { UNINITIALIZED, }; +// XXX If you add or remove QUICFrameType, you might also need to change QUICFrame::type(const uint8_t *) enum class QUICFrameType : int { PADDING = 0x00, RST_STREAM, @@ -96,6 +97,7 @@ enum class QUICFrameType : int { STREAM_BLOCKED, STREAM_ID_NEEDED, NEW_CONNECTION_ID, + STOP_SENDING, ACK = 0xA0, STREAM = 0xC0, UNKNOWN = 0x100, diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 809f2e7db90..3ebd29a5bbc 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -38,8 +38,10 @@ TEST_CASE("QUICFrame Type", "[quic]") CHECK(QUICFrame::type(reinterpret_cast("\x09")) == QUICFrameType::STREAM_BLOCKED); CHECK(QUICFrame::type(reinterpret_cast("\x0a")) == QUICFrameType::STREAM_ID_NEEDED); CHECK(QUICFrame::type(reinterpret_cast("\x0b")) == QUICFrameType::NEW_CONNECTION_ID); + CHECK(QUICFrame::type(reinterpret_cast("\x0c")) == QUICFrameType::STOP_SENDING); // Undefined ragne - CHECK(QUICFrame::type(reinterpret_cast("\x0c")) == QUICFrameType::UNKNOWN); + CHECK(QUICFrame::type(reinterpret_cast("\x03")) == QUICFrameType::UNKNOWN); + CHECK(QUICFrame::type(reinterpret_cast("\x0d")) == QUICFrameType::UNKNOWN); CHECK(QUICFrame::type(reinterpret_cast("\x9f")) == QUICFrameType::UNKNOWN); // Range of ACK CHECK(QUICFrame::type(reinterpret_cast("\xa0")) == QUICFrameType::ACK); @@ -521,6 +523,39 @@ TEST_CASE("Store NewConnectionId Frame", "[quic]") CHECK(memcmp(buf, expected, len) == 0); } +TEST_CASE("Load STOP_SENDING Frame", "[quic]") +{ + uint8_t buf[] = { + 0x0c, // Type + 0x12, 0x34, 0x56, 0x78, // Stream ID + 0x80, 0x00, 0x00, 0x00, // Error Code + }; + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::STOP_SENDING); + CHECK(frame->size() == 9); + + std::shared_ptr stop_sending_frame = std::dynamic_pointer_cast(frame); + CHECK(stop_sending_frame != nullptr); + CHECK(stop_sending_frame->stream_id() == 0x12345678); + CHECK(stop_sending_frame->error_code() == QUICErrorCode::QUIC_TRANSPORT_ERROR); +} + +TEST_CASE("Store STOP_SENDING Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected[] = { + 0x0c, // Type + 0x12, 0x34, 0x56, 0x78, // Stream ID + 0x80, 0x00, 0x00, 0x00, // Error Code + }; + QUICStopSendingFrame stop_sending_frame(0x12345678, QUICErrorCode::QUIC_TRANSPORT_ERROR); + stop_sending_frame.store(buf, &len); + CHECK(len == 9); + CHECK(memcmp(buf, expected, len) == 0); +} + TEST_CASE("QUICFrameFactory Create Unknown Frame", "[quic]") { uint8_t buf1[] = { From fd62dfc9f51d708ddb4e901057ee2c0e405ec1b2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 11 Sep 2017 15:47:21 +0900 Subject: [PATCH 0096/1313] Cleanup QUICFrame - Replace hard-coded QUICFrameType - Reorder arguments of QUICRstFrame constructor - Use write_QUICStreamId() --- iocore/net/quic/QUICFrame.cc | 32 +++++++++++++------------- iocore/net/quic/QUICFrame.h | 4 ++-- iocore/net/quic/test/test_QUICFrame.cc | 14 +++++------ 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index c8f22291c13..6a07641e532 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -645,8 +645,8 @@ QUICAckFrame::TimestampSection::store(uint8_t *buf, size_t *len) const // RST_STREAM frame // -QUICRstStreamFrame::QUICRstStreamFrame(QUICErrorCode error_code, QUICStreamId stream_id, QUICOffset final_offset) - : _error_code(error_code), _stream_id(stream_id), _final_offset(final_offset) +QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICErrorCode error_code, QUICOffset final_offset) + : _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset) { } @@ -667,7 +667,7 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len) const { size_t n; uint8_t *p = buf; - *p = 0x01; + *p = static_cast(QUICFrameType::RST_STREAM); ++p; QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n); p += n; @@ -727,7 +727,7 @@ QUICPingFrame::size() const void QUICPingFrame::store(uint8_t *buf, size_t *len) const { - buf[0] = 0x07; + buf[0] = static_cast(QUICFrameType::PING); *len = 1; } @@ -749,7 +749,7 @@ QUICPaddingFrame::size() const void QUICPaddingFrame::store(uint8_t *buf, size_t *len) const { - buf[0] = 0x00; + buf[0] = static_cast(QUICFrameType::PADDING); *len = 1; } @@ -782,7 +782,7 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len) const { size_t n; uint8_t *p = buf; - *p = 0x02; + *p = static_cast(QUICFrameType::CONNECTION_CLOSE); ++p; QUICTypeUtil::write_QUICErrorCode(this->_error_code, p, &n); p += n; @@ -849,7 +849,7 @@ QUICMaxDataFrame::store(uint8_t *buf, size_t *len) const { size_t n; uint8_t *p = buf; - *p = 0x04; + *p = static_cast(QUICFrameType::MAX_DATA); ++p; QUICTypeUtil::write_uint_as_nbytes(this->_maximum_data, 8, p, &n); p += n; @@ -893,9 +893,9 @@ QUICMaxStreamDataFrame::store(uint8_t *buf, size_t *len) const { size_t n; uint8_t *p = buf; - *p = 0x05; + *p = static_cast(QUICFrameType::MAX_STREAM_DATA); ++p; - QUICTypeUtil::write_uint_as_nbytes(this->_stream_id, 4, p, &n); + QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n); p += n; QUICTypeUtil::write_uint_as_nbytes(this->_maximum_stream_data, 8, p, &n); p += n; @@ -948,7 +948,7 @@ QUICMaxStreamIdFrame::store(uint8_t *buf, size_t *len) const { size_t n; uint8_t *p = buf; - *p = 0x06; + *p = static_cast(QUICFrameType::MAX_STREAM_ID); ++p; QUICTypeUtil::write_uint_as_nbytes(this->_maximum_stream_id, 4, p, &n); p += n; @@ -984,7 +984,7 @@ QUICBlockedFrame::size() const void QUICBlockedFrame::store(uint8_t *buf, size_t *len) const { - buf[0] = 0x08; + buf[0] = static_cast(QUICFrameType::BLOCKED); *len = 1; } @@ -1013,9 +1013,9 @@ QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len) const { size_t n; uint8_t *p = buf; - *p = 0x09; + *p = static_cast(QUICFrameType::STREAM_BLOCKED); ++p; - QUICTypeUtil::write_uint_as_nbytes(this->_stream_id, 4, p, &n); + QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n); p += n; *len = p - buf; @@ -1049,7 +1049,7 @@ QUICStreamIdNeededFrame::size() const void QUICStreamIdNeededFrame::store(uint8_t *buf, size_t *len) const { - buf[0] = 0x0a; + buf[0] = static_cast(QUICFrameType::STREAM_ID_NEEDED); *len = 1; } @@ -1080,7 +1080,7 @@ QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len) const { size_t n; uint8_t *p = buf; - *p = 0x0b; + *p = static_cast(QUICFrameType::NEW_CONNECTION_ID); ++p; QUICTypeUtil::write_uint_as_nbytes(this->_sequence, 2, p, &n); p += n; @@ -1352,7 +1352,7 @@ std::unique_ptr QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICErrorCode error_code, QUICOffset final_offset) { QUICRstStreamFrame *frame = quicRstStreamFrameAllocator.alloc(); - new (frame) QUICRstStreamFrame(error_code, stream_id, final_offset); + new (frame) QUICRstStreamFrame(stream_id, error_code, final_offset); return std::unique_ptr(frame, &QUICFrameDeleter::delete_rst_stream_frame); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index e696961e8f1..bf65848ef84 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -219,7 +219,7 @@ class QUICRstStreamFrame : public QUICFrame public: QUICRstStreamFrame() : QUICFrame() {} QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICRstStreamFrame(QUICErrorCode error_code, QUICStreamId stream_id, QUICOffset final_offset); + QUICRstStreamFrame(QUICStreamId stream_id, QUICErrorCode error_code, QUICOffset final_offset); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -228,8 +228,8 @@ class QUICRstStreamFrame : public QUICFrame QUICOffset final_offset() const; private: + QUICStreamId _stream_id = 0; QUICErrorCode _error_code; - QUICStreamId _stream_id = 0; QUICOffset _final_offset = 0; }; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 3ebd29a5bbc..aa082d6d080 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -204,11 +204,11 @@ TEST_CASE("Load RST_STREAM Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::RST_STREAM); CHECK(frame1->size() == 17); - std::shared_ptr rstStreamFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(rstStreamFrame1 != nullptr); - CHECK(rstStreamFrame1->error_code() == QUICErrorCode::QUIC_TRANSPORT_ERROR); - CHECK(rstStreamFrame1->stream_id() == 0x12345678); - CHECK(rstStreamFrame1->final_offset() == 0x1122334455667788); + std::shared_ptr rst_stream_frame1 = std::dynamic_pointer_cast(frame1); + CHECK(rst_stream_frame1 != nullptr); + CHECK(rst_stream_frame1->error_code() == QUICErrorCode::QUIC_TRANSPORT_ERROR); + CHECK(rst_stream_frame1->stream_id() == 0x12345678); + CHECK(rst_stream_frame1->final_offset() == 0x1122334455667788); } TEST_CASE("Store RST_STREAM Frame", "[quic]") @@ -222,8 +222,8 @@ TEST_CASE("Store RST_STREAM Frame", "[quic]") 0x80, 0x00, 0x00, 0x00, // Error Code 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset }; - QUICRstStreamFrame rstStreamFrame(QUICErrorCode::QUIC_TRANSPORT_ERROR, 0x12345678, 0x1122334455667788); - rstStreamFrame.store(buf, &len); + QUICRstStreamFrame rst_stream_frame(0x12345678, QUICErrorCode::QUIC_TRANSPORT_ERROR, 0x1122334455667788); + rst_stream_frame.store(buf, &len); CHECK(len == 17); CHECK(memcmp(buf, expected, len) == 0); } From 5241e33e39f690f0a7e42acdaf55f2372ae7337b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 11 Sep 2017 16:55:46 +0900 Subject: [PATCH 0097/1313] [draft-05] Fix error codes --- iocore/net/QUICNetVConnection.cc | 6 ++-- iocore/net/quic/QUICDebugNames.cc | 32 ++++++++++++++++--- iocore/net/quic/QUICFlowController.cc | 2 +- iocore/net/quic/QUICHandshake.cc | 6 ++-- iocore/net/quic/QUICStream.cc | 2 +- iocore/net/quic/QUICTypes.h | 28 ++++++++++------ .../net/quic/test/test_QUICFlowController.cc | 4 +-- iocore/net/quic/test/test_QUICFrame.cc | 12 +++---- .../net/quic/test/test_QUICStreamManager.cc | 2 +- iocore/net/quic/test/test_QUICStreamState.cc | 8 ++--- 10 files changed, 68 insertions(+), 34 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index c9654a3539b..3babca66ed8 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -352,7 +352,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) break; } default: - error = QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + error = QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); break; } @@ -538,7 +538,7 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_p { if (packet->size() < MINIMUM_INITIAL_CLIENT_PACKET_SIZE) { DebugQUICCon("Packet size is smaller than the minimum initial client packet size"); - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); } // Start handshake @@ -625,7 +625,7 @@ QUICNetVConnection::_state_common_receive_packet() error = this->_state_connection_established_process_packet(std::move(p)); break; default: - error = QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + error = QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); break; } return error; diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index d580be78d48..2f79b9219c9 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -115,15 +115,39 @@ QUICDebugNames::error_code(QUICErrorCode code) return "APPLICATION_SPECIFIC_ERROR"; case QUICErrorCode::HOST_LOCAL_ERROR: return "HOST_LOCAL_ERROR"; - case QUICErrorCode::QUIC_TRANSPORT_ERROR: - return "QUIC_TRANSPORT_ERROR"; - case QUICErrorCode::QUIC_INTERNAL_ERROR: - return "QUIC_INTERNAL_ERROR"; + case QUICErrorCode::NO_ERROR: + return "NO_ERROR"; + case QUICErrorCode::INTERNAL_ERROR: + return "INTERNAL_ERROR"; + case QUICErrorCode::CANCELLED: + return "CANCELLED"; + case QUICErrorCode::FLOW_CONTROL_ERROR: + return "FLOW_CONTROL_ERROR"; + case QUICErrorCode::STREAM_ID_ERROR: + return "STREAM_ID_ERROR"; + case QUICErrorCode::STREAM_STATE_ERROR: + return "STREAM_STATE_ERROR"; + case QUICErrorCode::FINAL_OFFSET_ERROR: + return "FINAL_OFFSET_ERROR"; + case QUICErrorCode::FRAME_FORMAT_ERROR: + return "FRAME_FORMAT_ERROR"; + case QUICErrorCode::TRANSPORT_PARAMETER_ERROR: + return "TRANSPORT_PARAMETER_ERROR"; + case QUICErrorCode::VERSION_NEGOTIATION_ERROR: + return "VERSION_NEGOTIATION_ERROR"; + case QUICErrorCode::PROTOCOL_VIOLATION: + return "PROTOCOL_VIOLATION"; + case QUICErrorCode::QUIC_RECEIVED_RST: + return "QUIC_RECEIVED_RST"; case QUICErrorCode::CRYPTOGRAPHIC_ERROR: return "CRYPTOGRAPHIC_ERROR"; case QUICErrorCode::TLS_HANDSHAKE_FAILED: return "TLS_HANDSHAKE_FAILED"; default: + if ((static_cast(code) & 0xFFFFFF00) == static_cast(QUICErrorCode::FRAME_ERROR)) { + // TODO: Add frame type + return "FRAME_ERROR"; + } return "UNKNOWN"; } } diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index ec277e56234..77a615d72ac 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -43,7 +43,7 @@ QUICFlowController::update(QUICOffset offset) if (this->_offset <= offset) { // Assume flow control is not initialized if the limit was 0 if (this->_limit != 0 && offset > this->_limit) { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FLOW_CONTROL_ERROR); } this->_offset = offset; } diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 4c948352d4c..9a2584dd8e9 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -78,7 +78,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet // Negotiate version if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) { if (initial_packet->type() != QUICPacketType::CLIENT_INITIAL) { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); } if (initial_packet->version()) { if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { @@ -90,7 +90,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet Debug(tag, "Version negotiation failed: %x", initial_packet->version()); } } else { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); } } return QUICError(QUICErrorClass::NONE); @@ -136,7 +136,7 @@ QUICHandshake::set_transport_parameters(std::shared_ptr if (tp_in_ch) { // Version revalidation if (this->_version_negotiator->revalidate(tp_in_ch) != QUICVersionNegotiationStatus::REVALIDATED) { - this->_client_qc->close({QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_VERSION_NEGOTIATION_MISMATCH}); + this->_client_qc->close({QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::VERSION_NEGOTIATION_ERROR}); Debug(tag, "Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); return; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 0ca060d20d7..b98614815ec 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -289,7 +289,7 @@ QUICStream::recv(const std::shared_ptr frame) // Check stream state - Do this first before accept the frame if (!this->_state.is_allowed_to_receive(*frame)) { this->reset(); - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::QUIC_INTERNAL_ERROR); + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); } this->_state.update_with_received_frame(*frame); diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 787f74e448c..2d0a0950dc1 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -124,16 +124,26 @@ enum class QUICErrorClass { CRYPTOGRAPHIC, }; -// TODO: fix for draft-05 enum class QUICErrorCode : uint32_t { - APPLICATION_SPECIFIC_ERROR = 0, - HOST_LOCAL_ERROR = 0x40000000, - QUIC_TRANSPORT_ERROR = 0x80000000, - QUIC_INTERNAL_ERROR = 0x80000001, - QUIC_VERSION_NEGOTIATION_MISMATCH = 0x80000037, - QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA = 0x8000003b, - CRYPTOGRAPHIC_ERROR = 0xC0000000, - TLS_HANDSHAKE_FAILED = 0xC000001C, + APPLICATION_SPECIFIC_ERROR = 0, + HOST_LOCAL_ERROR = 0x40000000, + NO_ERROR = 0x80000000, + INTERNAL_ERROR, + CANCELLED, + FLOW_CONTROL_ERROR, + STREAM_ID_ERROR, + STREAM_STATE_ERROR, + FINAL_OFFSET_ERROR, + FRAME_FORMAT_ERROR, + TRANSPORT_PARAMETER_ERROR, + VERSION_NEGOTIATION_ERROR, + PROTOCOL_VIOLATION = 0x8000000A, + QUIC_RECEIVED_RST = 0x80000035, + FRAME_ERROR = 0x80000100, + CRYPTOGRAPHIC_ERROR = 0xC0000000, + TLS_HANDSHAKE_FAILED = 0xC000001C, + TLS_FATAL_ALERT_GENERATED, + TLS_FATAL_ALERT_RECEIVED, // TODO Add error codes }; diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index 660cad64f5f..9c7996bafe3 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -68,7 +68,7 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") error = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.code == QUICErrorCode::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); + CHECK(error.code == QUICErrorCode::FLOW_CONTROL_ERROR); // MAX_STREAM_DATA CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_DATA)] == 0); @@ -180,7 +180,7 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]") error = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.code == QUICErrorCode::QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA); + CHECK(error.code == QUICErrorCode::FLOW_CONTROL_ERROR); // MAX_STREAM_DATA CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_STREAM_DATA)] == 0); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index aa082d6d080..207664d2936 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -206,7 +206,7 @@ TEST_CASE("Load RST_STREAM Frame", "[quic]") CHECK(frame1->size() == 17); std::shared_ptr rst_stream_frame1 = std::dynamic_pointer_cast(frame1); CHECK(rst_stream_frame1 != nullptr); - CHECK(rst_stream_frame1->error_code() == QUICErrorCode::QUIC_TRANSPORT_ERROR); + CHECK(rst_stream_frame1->error_code() == QUICErrorCode::NO_ERROR); CHECK(rst_stream_frame1->stream_id() == 0x12345678); CHECK(rst_stream_frame1->final_offset() == 0x1122334455667788); } @@ -222,7 +222,7 @@ TEST_CASE("Store RST_STREAM Frame", "[quic]") 0x80, 0x00, 0x00, 0x00, // Error Code 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset }; - QUICRstStreamFrame rst_stream_frame(0x12345678, QUICErrorCode::QUIC_TRANSPORT_ERROR, 0x1122334455667788); + QUICRstStreamFrame rst_stream_frame(0x12345678, QUICErrorCode::NO_ERROR, 0x1122334455667788); rst_stream_frame.store(buf, &len); CHECK(len == 17); CHECK(memcmp(buf, expected, len) == 0); @@ -294,7 +294,7 @@ TEST_CASE("Load ConnectionClose Frame", "[quic]") std::shared_ptr connectionCloseFrame1 = std::dynamic_pointer_cast(frame1); CHECK(connectionCloseFrame1 != nullptr); - CHECK(connectionCloseFrame1->error_code() == QUICErrorCode::QUIC_TRANSPORT_ERROR); + CHECK(connectionCloseFrame1->error_code() == QUICErrorCode::NO_ERROR); CHECK(connectionCloseFrame1->reason_phrase_length() == 5); CHECK(memcmp(connectionCloseFrame1->reason_phrase(), buf1 + 7, 5) == 0); } @@ -310,7 +310,7 @@ TEST_CASE("Store ConnectionClose Frame", "[quic]") 0x00, 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; - QUICConnectionCloseFrame connectionCloseFrame(QUICErrorCode::QUIC_TRANSPORT_ERROR, 5, "ABCDE"); + QUICConnectionCloseFrame connectionCloseFrame(QUICErrorCode::NO_ERROR, 5, "ABCDE"); connectionCloseFrame.store(buf, &len); CHECK(len == 12); CHECK(memcmp(buf, expected, len) == 0); @@ -537,7 +537,7 @@ TEST_CASE("Load STOP_SENDING Frame", "[quic]") std::shared_ptr stop_sending_frame = std::dynamic_pointer_cast(frame); CHECK(stop_sending_frame != nullptr); CHECK(stop_sending_frame->stream_id() == 0x12345678); - CHECK(stop_sending_frame->error_code() == QUICErrorCode::QUIC_TRANSPORT_ERROR); + CHECK(stop_sending_frame->error_code() == QUICErrorCode::NO_ERROR); } TEST_CASE("Store STOP_SENDING Frame", "[quic]") @@ -550,7 +550,7 @@ TEST_CASE("Store STOP_SENDING Frame", "[quic]") 0x12, 0x34, 0x56, 0x78, // Stream ID 0x80, 0x00, 0x00, 0x00, // Error Code }; - QUICStopSendingFrame stop_sending_frame(0x12345678, QUICErrorCode::QUIC_TRANSPORT_ERROR); + QUICStopSendingFrame stop_sending_frame(0x12345678, QUICErrorCode::NO_ERROR); stop_sending_frame.store(buf, &len); CHECK(len == 9); CHECK(memcmp(buf, expected, len) == 0); diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 450fbe48c40..63ed88ccbd6 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -53,7 +53,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") CHECK(sm.stream_count() == 2); // RST_STREAM frames create new streams - std::shared_ptr rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(2, QUICErrorCode::QUIC_INTERNAL_ERROR, 0); + std::shared_ptr rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(2, QUICErrorCode::INTERNAL_ERROR, 0); sm.handle_frame(rst_stream_frame); CHECK(sm.stream_count() == 3); diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index a771f66b5c2..ec304342142 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -31,7 +31,7 @@ TEST_CASE("QUICStreamState_Idle", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::QUIC_TRANSPORT_ERROR, 0); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::NO_ERROR, 0); auto max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(0, 0); auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0); @@ -70,7 +70,7 @@ TEST_CASE("QUICStreamState_Open", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::QUIC_TRANSPORT_ERROR, 0); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::NO_ERROR, 0); // Case1. Send FIN in a STREAM QUICStreamState ss1; @@ -105,7 +105,7 @@ TEST_CASE("QUICStreamState_Half_Closed_Remote", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::QUIC_TRANSPORT_ERROR, 0); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::NO_ERROR, 0); // Case1. Send FIN in a STREAM QUICStreamState ss1; @@ -126,7 +126,7 @@ TEST_CASE("QUICStreamState_Half_Closed_Local", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::QUIC_TRANSPORT_ERROR, 0); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::NO_ERROR, 0); // Case1. Recv FIN in a STREAM QUICStreamState ss1; From 5442415d17b4062a9cf5b64db62a103d6ff559a9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 12 Sep 2017 09:56:37 +0900 Subject: [PATCH 0098/1313] [draft-05] Fix QUICLossDetector to follow pseudocode of draft-05 --- iocore/net/quic/QUICLossDetector.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index feb48aa9e18..fb72bc2dfb6 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -45,6 +45,7 @@ QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter) : _transm this->_rttvar = 0; this->_largest_sent_before_rto = 0; this->_time_of_last_sent_packet = 0; + this->_largest_sent_packet = 0; SET_HANDLER(&QUICLossDetector::event_handler); } @@ -183,6 +184,7 @@ void QUICLossDetector::_on_ack_received(const std::shared_ptr &ack_frame) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + this->_largest_acked_packet = ack_frame->largest_acknowledged(); // If the largest acked is newly acked, update the RTT. auto pi = this->_sent_packets.find(ack_frame->largest_acknowledged()); if (pi != this->_sent_packets.end()) { @@ -208,7 +210,6 @@ QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); Debug("quic_loss_detector", "Packet number %" PRIu64 " has been acked", acked_packet_number); - this->_largest_acked_packet = acked_packet_number; // If a packet sent prior to RTO was acked, then the RTO // was spurious. Otherwise, inform congestion control. if (this->_rto_count > 0 && acked_packet_number > this->_largest_sent_before_rto) { From 34c9253dc403af84ed3938414f26bfaa05cc5d0b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 12 Sep 2017 11:21:35 +0900 Subject: [PATCH 0099/1313] Add create_stateless_reset_packet --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICDebugNames.cc | 4 +- iocore/net/quic/QUICHandshake.cc | 4 +- iocore/net/quic/QUICHandshake.h | 4 +- iocore/net/quic/QUICPacket.cc | 45 ++++++++++++++++--- iocore/net/quic/QUICPacket.h | 4 ++ iocore/net/quic/QUICTransportParameters.cc | 2 +- iocore/net/quic/QUICTransportParameters.h | 2 +- iocore/net/quic/QUICTypes.h | 14 ++++-- .../net/quic/test/test_QUICPacketFactory.cc | 28 ++++++++++++ 10 files changed, 90 insertions(+), 19 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3babca66ed8..9cb85fa0c62 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -98,7 +98,7 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not this->_token.gen_token(STATELESS_RETRY_TOKEN_KEY, _quic_connection_id ^ id); - this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_token.get()); + this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_token); this->_application_map = new QUICApplicationMap(); this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 2f79b9219c9..a6b359e8c96 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -44,8 +44,8 @@ QUICDebugNames::packet_type(QUICPacketType type) return "ONE_RTT_PROTECTED_KEY_PHASE_0"; case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: return "ONE_RTT_PROTECTED_KEY_PHASE_1"; - case QUICPacketType::PUBLIC_RESET: - return "PUBLIC_RESET"; + case QUICPacketType::STATELESS_RESET: + return "STATELESS_RESET"; case QUICPacketType::UNINITIALIZED: default: return "UNKNOWN"; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 9a2584dd8e9..daa47aaf270 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -54,7 +54,7 @@ static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, INK_MD5 token) : QUICApplication(qc), _token(token) +QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessToken token) : QUICApplication(qc), _token(token) { this->_ssl = SSL_new(ssl_ctx); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc); @@ -258,7 +258,7 @@ QUICHandshake::_load_local_transport_parameters() params->no_activity_timeout_in(), sizeof(uint16_t)))); tp->add(QUICTransportParameterId::STATELESS_RETRY_TOKEN, - std::unique_ptr(new QUICTransportParameterValue(this->_token.u64, 16))); + std::unique_ptr(new QUICTransportParameterValue(this->_token.get_u64(), 16))); tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); // MAYs diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index e8866d6c4bc..5d0060a40e1 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -50,7 +50,7 @@ class SSLNextProtocolSet; class QUICHandshake : public QUICApplication { public: - QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, INK_MD5 token); + QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessToken token); ~QUICHandshake(); QUICError start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); @@ -88,5 +88,5 @@ class QUICHandshake : public QUICApplication QUICError _process_client_finished(); QUICError _process_handshake_complete(); - INK_MD5 _token; + QUICStatelessToken _token; }; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index bfae22b58d6..97e62c66218 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -254,6 +254,8 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICConnection this->_key_phase = QUICKeyPhase::PHASE_0; } else if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { this->_key_phase = QUICKeyPhase::PHASE_1; + } else if (type == QUICPacketType::STATELESS_RESET) { + this->_key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; } else { ink_assert(false); this->_key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; @@ -273,8 +275,7 @@ QUICPacketShortHeader::type() const return QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1; } default: - ink_assert(false); - return QUICPacketType::UNINITIALIZED; + return QUICPacketType::STATELESS_RESET; } } @@ -488,6 +489,25 @@ QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUIC this->_is_retransmittable = retransmittable; } +QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token) +{ + const uint8_t *token = stateless_reset_token.get_u8(); + QUICPacketNumber fake_packet_number = token[0]; + QUICPacketNumber fake_base_packet_number = token[0]; + ats_unique_buf fake_payload = ats_unique_malloc(15 + 8); + memcpy(fake_payload.get(), token + 1, 15); + // Append random bytes + std::random_device rnd; + for (int i = 15; i < 23; ++i) { + fake_payload.get()[i] = rnd() & 0xFF; + } + + this->_header = + QUICPacketHeader::build(type, connection_id, fake_packet_number, fake_base_packet_number, std::move(fake_payload), 15 + 8); + this->_size = this->_header->length() + 15 + 8; + this->_is_retransmittable = false; +} + QUICPacket::~QUICPacket() { if (this->_header->has_version()) { @@ -559,8 +579,10 @@ uint16_t QUICPacket::payload_size() const { // FIXME Protected packets may / may not contain something at the end - if (this->type() != QUICPacketType::ZERO_RTT_PROTECTED && this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && - this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { + if (this->type() == QUICPacketType::STATELESS_RESET) { + return this->_size - this->_header->length(); + } else if (this->type() != QUICPacketType::ZERO_RTT_PROTECTED && this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && + this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { return this->_size - this->_header->length() - FNV1A_HASH_LEN; } else { return this->_size - this->_header->length(); @@ -579,8 +601,11 @@ QUICPacket::store(uint8_t *buf, size_t *len) const this->_header->store(buf, len); ink_assert(this->size() >= *len); - if (this->type() != QUICPacketType::ZERO_RTT_PROTECTED && this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && - this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { + if (this->type() == QUICPacketType::STATELESS_RESET) { + memcpy(buf + *len, this->payload(), this->payload_size()); + *len += this->payload_size(); + } else if (this->type() != QUICPacketType::ZERO_RTT_PROTECTED && this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && + this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { memcpy(buf + *len, this->payload(), this->payload_size()); *len += this->payload_size(); @@ -745,6 +770,14 @@ QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, return std::unique_ptr(packet, &QUICPacketDeleter::delete_packet); } +std::unique_ptr +QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token) +{ + QUICPacket *packet = quicPacketAllocator.alloc(); + new (packet) QUICPacket(QUICPacketType::STATELESS_RESET, connection_id, stateless_reset_token); + return std::unique_ptr(packet, &QUICPacketDeleter::delete_packet); +} + void QUICPacketFactory::set_version(QUICVersion negotiated_version) { diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 147f13d7475..e0e9c7a14fb 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -56,6 +56,7 @@ class QUICPacketHeader ats_unique_buf payload, size_t len); static QUICPacketHeader *build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len); + static QUICPacketHeader *build(QUICPacketType, QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token); virtual bool has_key_phase() const = 0; virtual bool has_connection_id() const = 0; virtual bool has_version() const = 0; @@ -135,6 +136,7 @@ class QUICPacket size_t len, bool retransmittable); QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittabl); + QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token); ~QUICPacket(); void set_protected_payload(ats_unique_buf cipher_txt, size_t cipher_txt_len); @@ -218,6 +220,8 @@ class QUICPacketFactory QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); + std::unique_ptr create_stateless_reset_packet(QUICConnectionId connection_id, + QUICStatelessToken stateless_reset_token); void set_version(QUICVersion negotiated_version); void set_crypto_module(QUICCrypto *crypto); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 2debfac9ffb..2ca71760b0b 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -44,7 +44,7 @@ QUICTransportParameterValue::QUICTransportParameterValue(uint64_t raw_data, uint this->_len = len; }; -QUICTransportParameterValue::QUICTransportParameterValue(uint64_t raw_data[2], uint16_t l) +QUICTransportParameterValue::QUICTransportParameterValue(const uint64_t raw_data[2], uint16_t l) { this->_data = ats_unique_malloc(l); size_t len = 0; diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 06adaf4ac10..ba53a156786 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -69,7 +69,7 @@ class QUICTransportParameterValue public: QUICTransportParameterValue(ats_unique_buf d, uint16_t l); QUICTransportParameterValue(uint64_t raw_data, uint16_t l); - QUICTransportParameterValue(uint64_t raw_data[2], uint16_t l); + QUICTransportParameterValue(const uint64_t raw_data[2], uint16_t l); const uint8_t *data() const; uint16_t len() const; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 2d0a0950dc1..2f3fc2f837d 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -72,7 +72,7 @@ enum class QUICPacketType : int { ZERO_RTT_PROTECTED, ONE_RTT_PROTECTED_KEY_PHASE_0, ONE_RTT_PROTECTED_KEY_PHASE_1, - PUBLIC_RESET, + STATELESS_RESET, UNINITIALIZED, }; @@ -173,10 +173,16 @@ class QUICStatelessToken ctx.finalize(_md5); } - const INK_MD5 - get() const + const uint8_t * + get_u8() const { - return _md5; + return _md5.u8; + } + + const uint64_t * + get_u64() const + { + return _md5.u64; } private: diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index ab989aea06b..88079db73ee 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -68,3 +68,31 @@ TEST_CASE("QUICPacketFactory_Create_ServerCleartextPacket", "[quic]") CHECK((packet->packet_number() & 0xFFFFFFFF80000000) == 0); CHECK(packet->version() == 0x11223344); } + +TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") +{ + QUICPacketFactory factory; + QUICStatelessToken token; + token.gen_token("test", 12345); + uint8_t expected_output[] = { + 0x41, // 0CK0001 + 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, // Connection ID + 0x40, 0x01, 0x57, 0x55, 0x21, + 0x9c, 0x24, 0x24, // Token + 0xc7, 0x9f, 0x79, 0xa2, 0x72, + 0xcb, 0x55, 0xe6 + // Random data + }; + uint8_t output[1024]; + size_t out_len = 0; + + std::unique_ptr packet = factory.create_stateless_reset_packet(0x01020304, token); + CHECK(packet->type() == QUICPacketType::STATELESS_RESET); + CHECK(packet->connection_id() == 0x01020304); + CHECK(packet->packet_number() == token.get_u8()[0]); + CHECK(memcmp(packet->payload(), token.get_u8() + 1, 15) == 0); + packet->store(output, &out_len); + CHECK(memcmp(output, expected_output, 25) == 0); + CHECK(out_len > 25); // Check existence of random bytes at the end +} From a46bcab6c6949a7d4685f03dbff912b603574ecf Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 12 Sep 2017 14:50:33 +0900 Subject: [PATCH 0100/1313] Send stateless reset packet if the client id doesn't seem valid anymore --- iocore/net/P_QUICPacketHandler.h | 1 + iocore/net/QUICNetVConnection.cc | 3 +-- iocore/net/QUICPacketHandler.cc | 26 +++++++++++++++---- iocore/net/quic/QUICPacket.h | 4 +-- iocore/net/quic/QUICTypes.h | 5 ++-- .../net/quic/test/test_QUICPacketFactory.cc | 13 ++++------ 6 files changed, 33 insertions(+), 19 deletions(-) diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index c40f255ee28..6b29b6aa1cc 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -40,6 +40,7 @@ struct QUICPacketHandler : public NetAccept { virtual int acceptEvent(int event, void *e) override; void init_accept(EThread *t) override; void send_packet(const QUICPacket &packet, QUICNetVConnection *vc); + void send_packet(const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu); private: void _recv_packet(int event, UDPPacket *udpPacket); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 9cb85fa0c62..bbc5547f908 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -49,7 +49,6 @@ static constexpr uint32_t MAX_PACKET_OVERHEAD = 25; // Max long header len(17) + FNV-1a hash len(8) static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; static constexpr uint32_t MINIMUM_INITIAL_CLIENT_PACKET_SIZE = 1200; -static constexpr char STATELESS_RETRY_TOKEN_KEY[] = "stateless_token_retry_key"; ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); @@ -96,7 +95,7 @@ void QUICNetVConnection::start(SSL_CTX *ssl_ctx) { // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not - this->_token.gen_token(STATELESS_RETRY_TOKEN_KEY, _quic_connection_id ^ id); + this->_token.gen_token(_quic_connection_id ^ id); this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_token); this->_application_map = new QUICApplicationMap(); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 0531aeb20dc..39df7ce3d1b 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -129,9 +129,19 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) } if (!vc) { - // Unknown Connection ID Connection con; con.setRemote(&udpPacket->from.sa); + + // Send stateless reset if the packet is not a initial packet + if (!QUICTypeUtil::hasLongHeader(reinterpret_cast(block->buf()))) { + QUICStatelessToken token; + token.gen_token(cid); + auto packet = QUICPacketFactory::create_stateless_reset_packet(cid, token); + this->send_packet(*packet, udpPacket->getConnection(), con.addr, 1200); + return; + } + + // Create a new NetVConnection vc = static_cast(getNetProcessor()->allocate_vc(((UnixUDPConnection *)udpPacket->getConnection())->ethread)); vc->init(udpPacket->getConnection(), this); @@ -147,7 +157,6 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) vc->options.ip_proto = NetVCOptions::USE_UDP; vc->options.ip_family = udpPacket->from.sa.sa_family; - // TODO: Handle Connection ID of Client Cleartext / Non-Final Server Cleartext Packet this->_connections.put(cid, vc); } @@ -168,17 +177,24 @@ QUICPacketHandler::send_packet(const QUICPacket &packet, QUICNetVConnection *vc) this->_connections.put(packet.connection_id(), vc); } + this->send_packet(packet, vc->get_udp_con(), vc->con.addr, vc->pmtu()); +} + +void +QUICPacketHandler::send_packet(const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu) +{ size_t udp_len; Ptr udp_payload(new_IOBufferBlock()); - udp_payload->alloc(iobuffer_size_to_index(vc->pmtu())); + udp_payload->alloc(iobuffer_size_to_index(pmtu)); packet.store(reinterpret_cast(udp_payload->end()), &udp_len); udp_payload->fill(udp_len); - UDPPacket *udpPkt = new_UDPPacket(vc->con.addr, 0, udp_payload); + UDPPacket *udpPkt = new_UDPPacket(addr, 0, udp_payload); // NOTE: p will be enqueued to udpOutQueue of UDPNetHandler ip_port_text_buffer ipb; Debug("quic_sec", "send %s packet to %s, size=%" PRId64, QUICDebugNames::packet_type(packet.type()), ats_ip_nptop(&udpPkt->to.sa, ipb, sizeof(ipb)), udpPkt->getPktLength()); - vc->get_udp_con()->send(this, udpPkt); + + udp_con->send(this, udpPkt); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index e0e9c7a14fb..56d78874559 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -220,8 +220,8 @@ class QUICPacketFactory QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); - std::unique_ptr create_stateless_reset_packet(QUICConnectionId connection_id, - QUICStatelessToken stateless_reset_token); + static std::unique_ptr create_stateless_reset_packet(QUICConnectionId connection_id, + QUICStatelessToken stateless_reset_token); void set_version(QUICVersion negotiated_version); void set_crypto_module(QUICCrypto *crypto); diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 2f3fc2f837d..5c7a2e875e7 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -165,10 +165,11 @@ class QUICStatelessToken { public: void - gen_token(const char *key, uint64_t data) + gen_token(uint64_t data) { + static constexpr char STATELESS_RETRY_TOKEN_KEY[] = "stateless_token_retry_key"; MD5Context ctx; - ctx.update(key, strlen(key)); + ctx.update(STATELESS_RETRY_TOKEN_KEY, strlen(STATELESS_RETRY_TOKEN_KEY)); ctx.update(reinterpret_cast(&data), 8); ctx.finalize(_md5); } diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 88079db73ee..02d2b64ea63 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -73,15 +73,12 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") { QUICPacketFactory factory; QUICStatelessToken token; - token.gen_token("test", 12345); + token.gen_token(12345); uint8_t expected_output[] = { - 0x41, // 0CK0001 - 0x00, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x03, 0x04, // Connection ID - 0x40, 0x01, 0x57, 0x55, 0x21, - 0x9c, 0x24, 0x24, // Token - 0xc7, 0x9f, 0x79, 0xa2, 0x72, - 0xcb, 0x55, 0xe6 + 0x41, // 0CK0001 + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, // Connection ID + 0xa1, 0x45, 0x7b, 0x7e, 0x8f, 0x85, 0x0b, 0x14, // Token + 0xd2, 0x43, 0xa1, 0xaf, 0x7c, 0xe2, 0x91, 0x50, // Random data }; uint8_t output[1024]; From 2786a2c23a3250df3be41f16b92ac0fdce4420ac Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 12 Sep 2017 16:11:53 +0900 Subject: [PATCH 0101/1313] Remove send_frame from QUICStreamManager Since QUICStreamManager::send_frame does nothing, QUICStreams pass frames to QUICFrameTransmitter directly --- iocore/net/quic/Mock.h | 2 -- iocore/net/quic/QUICStream.cc | 6 ++---- iocore/net/quic/QUICStream.h | 3 +-- iocore/net/quic/QUICStreamManager.cc | 28 ++----------------------- iocore/net/quic/QUICStreamManager.h | 2 -- iocore/net/quic/test/test_QUICStream.cc | 8 +++---- 6 files changed, 8 insertions(+), 41 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index ddf056d5109..af8b7ff50b6 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -306,8 +306,6 @@ class MockQUICStreamManager : public QUICStreamManager return _totalFrameCount; } - void send_frame(std::unique_ptr /* frame */) override { return; } - private: int _totalFrameCount = 0; int _frameCount[256] = {0}; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index b98614815ec..91033fefe7a 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -32,11 +32,9 @@ Debug("quic_stream", "[%" PRIx32 "] [%s] " fmt, this->_id, QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) void -QUICStream::init(QUICStreamManager *manager, QUICFrameTransmitter *tx, QUICStreamId id, uint64_t recv_max_stream_data, - uint64_t send_max_stream_data) +QUICStream::init(QUICFrameTransmitter *tx, QUICStreamId id, uint64_t recv_max_stream_data, uint64_t send_max_stream_data) { this->mutex = new_ProxyMutex(); - this->_stream_manager = manager; this->_tx = tx; this->_id = id; this->_remote_flow_controller = new QUICRemoteStreamFlowController(send_max_stream_data, _tx, _id); @@ -380,7 +378,7 @@ QUICStream::_send() break; } this->_state.update_with_sent_frame(*frame); - this->_stream_manager->send_frame(std::move(frame)); + this->_tx->transmit_frame(std::move(frame)); } return error; diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index ff7bb145dc1..1a1fe71f7d9 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -45,8 +45,7 @@ class QUICStream : public VConnection public: QUICStream() : VConnection(nullptr) {} ~QUICStream() {} - void init(QUICStreamManager *manager, QUICFrameTransmitter *tx, uint32_t id, uint64_t recv_max_stream_data = 0, - uint64_t send_max_stream_data = 0); + void init(QUICFrameTransmitter *tx, uint32_t id, uint64_t recv_max_stream_data = 0, uint64_t send_max_stream_data = 0); void start(); void init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data); int main_event_handler(int event, void *data); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index a5daa620612..ca789e53c7b 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -155,30 +155,6 @@ QUICStreamManager::_handle_frame(const std::shared_ptr return QUICError(QUICErrorClass::NONE); } -/** - * @brief Send stream frame - */ -void -QUICStreamManager::send_frame(std::unique_ptr frame) -{ - if (frame->stream_id() != STREAM_ID_FOR_HANDSHAKE) { - } - this->_tx->transmit_frame(std::move(frame)); - - return; -} - -/** - * @brief Send frame - */ -void -QUICStreamManager::send_frame(std::unique_ptr frame) -{ - this->_tx->transmit_frame(std::move(frame)); - - return; -} - QUICStream * QUICStreamManager::_find_stream(QUICStreamId id) { @@ -199,13 +175,13 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream(); if (stream_id == STREAM_ID_FOR_HANDSHAKE) { // XXX rece/send max_stream_data are going to be set by init_flow_control_params() - stream->init(this, this->_tx, stream_id, this->_local_tp->initial_max_stream_data()); + stream->init(this->_tx, stream_id, this->_local_tp->initial_max_stream_data()); } else { const QUICTransportParameters &local_tp = *this->_local_tp; const QUICTransportParameters &remote_tp = *this->_remote_tp; // TODO: check local_tp and remote_tp is initialized - stream->init(this, this->_tx, stream_id, local_tp.initial_max_stream_data(), remote_tp.initial_max_stream_data()); + stream->init(this->_tx, stream_id, local_tp.initial_max_stream_data(), remote_tp.initial_max_stream_data()); } stream->start(); diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index fd6412a8f0f..40753d4e9eb 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -38,8 +38,6 @@ class QUICStreamManager : public QUICFrameHandler QUICStreamManager(){}; QUICStreamManager(QUICFrameTransmitter *tx, QUICApplicationMap *app_map); - virtual void send_frame(std::unique_ptr frame); - virtual void send_frame(std::unique_ptr frame); void init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); uint64_t total_offset_received() const; diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 99563bc8d72..545d3530bc4 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -41,8 +41,6 @@ std::shared_ptr frame_6 = std::make_shared(pay std::shared_ptr frame_7 = std::make_shared(payload + 12, 2, stream_id, 12); std::shared_ptr frame_8 = std::make_shared(payload + 14, 2, stream_id, 14); -MockQUICStreamManager *manager = new MockQUICStreamManager(); - TEST_CASE("QUICStream_assembling_byte_stream_1", "[quic]") { MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); @@ -50,7 +48,7 @@ TEST_CASE("QUICStream_assembling_byte_stream_1", "[quic]") MockQUICFrameTransmitter tx; std::unique_ptr stream(new QUICStream()); - stream->init(manager, &tx, stream_id, 1024, 1024); + stream->init(&tx, stream_id, 1024, 1024); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_1); @@ -77,7 +75,7 @@ TEST_CASE("QUICStream_assembling_byte_stream_2", "[quic]") MockQUICFrameTransmitter tx; std::unique_ptr stream(new QUICStream()); - stream->init(manager, &tx, stream_id); + stream->init(&tx, stream_id); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -104,7 +102,7 @@ TEST_CASE("QUICStream_assembling_byte_stream_3", "[quic]") MockQUICFrameTransmitter tx; std::unique_ptr stream(new QUICStream()); - stream->init(manager, &tx, stream_id); + stream->init(&tx, stream_id); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); From b3c97064c70832f7c59f63c984266c14dd235a6f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 12 Sep 2017 16:42:35 +0900 Subject: [PATCH 0102/1313] Change default error_code to QUICErrorCode::NO_ERROR --- iocore/net/quic/QUICTypes.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 5c7a2e875e7..819408e0d46 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -148,8 +148,8 @@ enum class QUICErrorCode : uint32_t { }; struct QUICError { - QUICError(const QUICErrorClass error_class = QUICErrorClass::NONE, - const QUICErrorCode error_code = QUICErrorCode::APPLICATION_SPECIFIC_ERROR, const char *err_msg = nullptr) + QUICError(const QUICErrorClass error_class = QUICErrorClass::NONE, const QUICErrorCode error_code = QUICErrorCode::NO_ERROR, + const char *err_msg = nullptr) { cls = error_class; code = error_code; From 3bfc675a3b530903b4d75647a5c2cb32b2368471 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 12 Sep 2017 16:47:24 +0900 Subject: [PATCH 0103/1313] Schedule QUIC_EVENT_SHUTDOWN when change state to state_connection_closed --- iocore/net/QUICNetVConnection.cc | 8 +++----- iocore/net/quic/QUICEvents.h | 2 ++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index bbc5547f908..e34e05548b4 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -291,6 +291,7 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) case QUICFrameType::CONNECTION_CLOSE: DebugQUICCon("Enter state_connection_closed"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); + this_ethread()->schedule_imm(this, QUIC_EVENT_SHUTDOWN, nullptr); break; default: DebugQUICCon("Unexpected frame type: %02x", static_cast(frame->type())); @@ -450,6 +451,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) if (true) { DebugQUICCon("Enter state_connection_closed"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); + this_ethread()->schedule_imm(this, QUIC_EVENT_SHUTDOWN, nullptr); } return EVENT_DONE; @@ -459,11 +461,7 @@ int QUICNetVConnection::state_connection_closed(int event, Event *data) { switch (event) { - case QUIC_EVENT_PACKET_READ_READY: { - // TODO: send GOAWAY frame - break; - } - case QUIC_EVENT_PACKET_WRITE_READY: { + case QUIC_EVENT_SHUTDOWN: { this->_packet_write_ready = nullptr; this->next_inactivity_timeout_at = 0; this->next_activity_timeout_at = 0; diff --git a/iocore/net/quic/QUICEvents.h b/iocore/net/quic/QUICEvents.h index de27a7863b5..b3273ce43cb 100644 --- a/iocore/net/quic/QUICEvents.h +++ b/iocore/net/quic/QUICEvents.h @@ -23,10 +23,12 @@ #pragma once +#include "I_EventSystem.h" #include "I_Event.h" enum { QUIC_EVENT_PACKET_READ_READY = QUIC_EVENT_EVENTS_START, QUIC_EVENT_PACKET_WRITE_READY, + QUIC_EVENT_SHUTDOWN, QUIC_EVENT_LD_SHUTDOWN, }; From 0952de777ffd7b54b62c364dc0be5c65518aeb20 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 12 Sep 2017 16:52:44 +0900 Subject: [PATCH 0104/1313] Add QUICDebugNames::quic_event(int) --- iocore/net/QUICNetVConnection.cc | 8 ++++---- iocore/net/quic/QUICDebugNames.cc | 17 +++++++++++++++++ iocore/net/quic/QUICDebugNames.h | 2 ++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e34e05548b4..b0df002a162 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -373,7 +373,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) } default: - DebugQUICCon("Unexpected event: %u", event); + DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); } if (error.cls != QUICErrorClass::NONE) { @@ -418,7 +418,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) break; } default: - DebugQUICCon("Unexpected event: %u", event); + DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); } if (error.cls != QUICErrorClass::NONE) { @@ -444,7 +444,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) break; } default: - DebugQUICCon("Unexpected event: %u", event); + DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); } // FIXME Enter closed state if CONNECTION_CLOSE was ACKed @@ -478,7 +478,7 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) break; } default: - DebugQUICCon("Unexpected event: %u", event); + DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); } return EVENT_DONE; diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index a6b359e8c96..5526d2dea6a 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -152,6 +152,23 @@ QUICDebugNames::error_code(QUICErrorCode code) } } +const char * +QUICDebugNames::quic_event(int event) +{ + switch (event) { + case QUIC_EVENT_PACKET_READ_READY: + return "QUIC_EVENT_PACKET_READ_READY"; + case QUIC_EVENT_PACKET_WRITE_READY: + return "QUIC_EVENT_PACKET_WRITE_READY"; + case QUIC_EVENT_SHUTDOWN: + return "QUIC_EVENT_SHUTDOWN"; + case QUIC_EVENT_LD_SHUTDOWN: + return "QUIC_EVENT_LD_SHUTDOWN"; + default: + return "UNKNOWN"; + } +} + const char * QUICDebugNames::vc_event(int event) { diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index 79702c6acf6..7b406d4716e 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -24,6 +24,7 @@ #pragma once #include "QUICTypes.h" +#include "QUICEvents.h" #include "QUICTransportParameters.h" #include "QUICStreamState.h" @@ -36,6 +37,7 @@ class QUICDebugNames static const char *error_code(QUICErrorCode code); static const char *transport_parameter_id(QUICTransportParameterId id); static const char *stream_state(QUICStreamState state); + static const char *quic_event(int event); // TODO: move to somewhere static const char *vc_event(int event); From 27899d856fef2cfedf62eb9deec0e7b8a41348df Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 12 Sep 2017 17:36:08 +0900 Subject: [PATCH 0105/1313] Add support for MAX_STREAM_ID frame and initial_max_stream_id transport parameter --- iocore/net/quic/QUICStreamManager.cc | 64 ++++++++++++++----- iocore/net/quic/QUICStreamManager.h | 4 ++ .../net/quic/test/test_QUICStreamManager.cc | 6 ++ 3 files changed, 57 insertions(+), 17 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index ca789e53c7b..24f8fb8aea5 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -40,7 +40,7 @@ std::vector QUICStreamManager::interests() { return { - QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::MAX_STREAM_DATA, + QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::MAX_STREAM_DATA, QUICFrameType::MAX_STREAM_ID, }; } @@ -64,6 +64,25 @@ QUICStreamManager::init_flow_control_params(const std::shared_ptrinit_flow_control_params(local_initial_max_stream_data, remote_initial_max_stream_data); } + + uint16_t len; + const uint8_t *tp_value; + if (this->_local_tp) { + tp_value = this->_local_tp->get(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, len); + this->_local_maximum_stream_id = QUICTypeUtil::read_QUICStreamId(tp_value, len); + } + if (this->_remote_tp) { + tp_value = this->_remote_tp->get(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, len); + this->_remote_maximum_stream_id = QUICTypeUtil::read_QUICStreamId(tp_value, len); + } +} + +void +QUICStreamManager::set_max_stream_id(QUICStreamId id) +{ + if (this->_local_maximum_stream_id <= id) { + this->_local_maximum_stream_id = id; + } } QUICError @@ -72,20 +91,21 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) QUICError error = QUICError(QUICErrorClass::NONE); switch (frame->type()) { - case QUICFrameType::MAX_STREAM_DATA: { - error = this->_handle_frame(std::dynamic_pointer_cast(frame)); + case QUICFrameType::MAX_STREAM_DATA: + error = this->_handle_frame(std::static_pointer_cast(frame)); break; - } - case QUICFrameType::STREAM_BLOCKED: { + case QUICFrameType::STREAM_BLOCKED: // STREAM_BLOCKED frame is for debugging. Just propagate to streams - error = this->_handle_frame(std::dynamic_pointer_cast(frame)); + error = this->_handle_frame(std::static_pointer_cast(frame)); break; - } case QUICFrameType::STREAM: - error = this->_handle_frame(std::dynamic_pointer_cast(frame)); + error = this->_handle_frame(std::static_pointer_cast(frame)); break; case QUICFrameType::RST_STREAM: - error = this->_handle_frame(std::dynamic_pointer_cast(frame)); + error = this->_handle_frame(std::static_pointer_cast(frame)); + break; + case QUICFrameType::MAX_STREAM_ID: + error = this->_handle_frame(std::static_pointer_cast(frame)); break; default: Debug(tag, "Unexpected frame type: %02x", static_cast(frame->type())); @@ -103,10 +123,8 @@ QUICStreamManager::_handle_frame(const std::shared_ptrrecv(frame); } else { - // TODO: connection error? + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR); } - - return QUICError(QUICErrorClass::NONE); } QUICError @@ -116,16 +134,18 @@ QUICStreamManager::_handle_frame(const std::shared_ptrrecv(frame); } else { - // TODO: connection error? + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR); } - - return QUICError(QUICErrorClass::NONE); } QUICError QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { - QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); + QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); + if (!stream) { + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR); + } + QUICApplication *application = this->_app_map->get(frame->stream_id()); if (!application->is_stream_set(stream)) { @@ -148,10 +168,16 @@ QUICStreamManager::_handle_frame(const std::shared_ptr QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); if (stream) { // TODO Reset the stream + return QUICError(QUICErrorClass::NONE); } else { - // TODO: connection error? + return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR); } +} +QUICError +QUICStreamManager::_handle_frame(const std::shared_ptr &frame) +{ + this->_remote_maximum_stream_id = frame->maximum_stream_id(); return QUICError(QUICErrorClass::NONE); } @@ -171,6 +197,10 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) { QUICStream *stream = this->_find_stream(stream_id); if (!stream) { + if ((stream_id > this->_local_maximum_stream_id && this->_local_maximum_stream_id != 0) || + (stream_id > this->_remote_maximum_stream_id && this->_remote_maximum_stream_id != 0)) { + return nullptr; + } // TODO Free the stream somewhere stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream(); if (stream_id == STREAM_ID_FOR_HANDSHAKE) { diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 40753d4e9eb..3fa81efcab3 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -40,6 +40,7 @@ class QUICStreamManager : public QUICFrameHandler void init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); + void set_max_stream_id(QUICStreamId id); uint64_t total_offset_received() const; uint64_t total_offset_sent() const; uint32_t stream_count() const; @@ -57,9 +58,12 @@ class QUICStreamManager : public QUICFrameHandler QUICError _handle_frame(const std::shared_ptr &); QUICError _handle_frame(const std::shared_ptr &); QUICError _handle_frame(const std::shared_ptr &); + QUICError _handle_frame(const std::shared_ptr &); QUICFrameTransmitter *_tx = nullptr; QUICApplicationMap *_app_map = nullptr; std::shared_ptr _local_tp = nullptr; std::shared_ptr _remote_tp = nullptr; + QUICStreamId _local_maximum_stream_id = 0; + QUICStreamId _remote_maximum_stream_id = 0; }; diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 63ed88ccbd6..eb7b77d7177 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -66,6 +66,12 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") std::shared_ptr stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(4); sm.handle_frame(stream_blocked_frame); CHECK(sm.stream_count() == 5); + + // Set local maximum stream id + sm.set_max_stream_id(4); + std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_blocked_frame(5); + sm.handle_frame(stream_blocked_frame_x); + CHECK(sm.stream_count() == 5); } TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") From 581151aaf5c55e9c47fcfc3f99ed0cd9b458aa84 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 13 Sep 2017 11:12:25 +0900 Subject: [PATCH 0106/1313] Use shortest stream id length --- iocore/net/quic/QUICFrame.cc | 15 ++++++-- iocore/net/quic/test/test_QUICFrame.cc | 49 +++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 6a07641e532..4baa5510e0e 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -116,9 +116,18 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, bool include_length_field) con } // "SS" of "11FSSOOD" - // use 32 bit length for now - buf[0] += (0x03 << 3); - QUICTypeUtil::write_QUICStreamId(this->stream_id(), 4, buf + *len, &n); + uint8_t stream_id_width = 0; + if (this->_stream_id > 0xFFFFFF) { + stream_id_width = 4; + } else if (this->_stream_id > 0xFFFF) { + stream_id_width = 3; + } else if (this->_stream_id > 0xFF) { + stream_id_width = 2; + } else { + stream_id_width = 1; + } + buf[0] += ((stream_id_width - 1) << 3); + QUICTypeUtil::write_QUICStreamId(this->stream_id(), stream_id_width, buf + *len, &n); *len += n; // "OO" of "11FSSOOD" diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 207664d2936..c630007c682 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -110,18 +110,57 @@ TEST_CASE("Store STREAM Frame", "[quic]") uint8_t buf[65535]; size_t len; + // 8bit stream id, 64bit offset + uint8_t expected1[] = { + 0xC7, // 11FSSOOD + 0x01, // Stream ID + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Offset + 0x00, 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + QUICStreamFrame streamFrame1(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01, 0x00); + streamFrame1.store(buf, &len); + CHECK(len == 17); + CHECK(memcmp(buf, expected1, len) == 0); + + // 16bit stream id, 64bit offset + uint8_t expected2[] = { + 0xCF, // 11FSSOOD + 0x01, 0x00, // Stream ID + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Offset + 0x00, 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + QUICStreamFrame streamFrame2(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x0100, 0x00); + streamFrame2.store(buf, &len); + CHECK(len == 18); + CHECK(memcmp(buf, expected2, len) == 0); + + // 24bit stream id, 64bit offset + uint8_t expected3[] = { + 0xD7, // 11FSSOOD + 0x01, 0x00, 0x00, // Stream ID + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Offset + 0x00, 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + QUICStreamFrame streamFrame3(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x010000, 0x00); + streamFrame3.store(buf, &len); + CHECK(len == 19); + CHECK(memcmp(buf, expected3, len) == 0); + // 32bit stream id, 64bit offset - uint8_t expected[] = { + uint8_t expected4[] = { 0xDF, // 11FSSOOD - 0x00, 0x00, 0x00, 0x01, // Stream ID + 0x01, 0x00, 0x00, 0x00, // Stream ID 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Offset 0x00, 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - QUICStreamFrame streamFrame(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01, 0x00); - streamFrame.store(buf, &len); + QUICStreamFrame streamFrame4(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01000000, 0x00); + streamFrame4.store(buf, &len); CHECK(len == 20); - CHECK(memcmp(buf, expected, len) == 0); + CHECK(memcmp(buf, expected4, len) == 0); } TEST_CASE("Load Ack Frame 1", "[quic]") From 2110b5ba4c611520b9f1a735088de11a493c2675 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 13 Sep 2017 14:39:07 +0900 Subject: [PATCH 0107/1313] Use the shortest offset length --- iocore/net/quic/QUICFrame.cc | 27 ++++++--- iocore/net/quic/test/test_QUICFrame.cc | 78 +++++++++++++++++++------- 2 files changed, 76 insertions(+), 29 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 4baa5510e0e..e73fd9d8ea9 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -118,22 +118,31 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, bool include_length_field) con // "SS" of "11FSSOOD" uint8_t stream_id_width = 0; if (this->_stream_id > 0xFFFFFF) { - stream_id_width = 4; - } else if (this->_stream_id > 0xFFFF) { stream_id_width = 3; - } else if (this->_stream_id > 0xFF) { + } else if (this->_stream_id > 0xFFFF) { stream_id_width = 2; - } else { + } else if (this->_stream_id > 0xFF) { stream_id_width = 1; + } else { + stream_id_width = 0; } - buf[0] += ((stream_id_width - 1) << 3); - QUICTypeUtil::write_QUICStreamId(this->stream_id(), stream_id_width, buf + *len, &n); + buf[0] += (stream_id_width << 3); + QUICTypeUtil::write_QUICStreamId(this->stream_id(), stream_id_width + 1, buf + *len, &n); *len += n; // "OO" of "11FSSOOD" - // use 64 bit length for now - buf[0] += (0x03 << 1); - QUICTypeUtil::write_QUICOffset(this->offset(), 8, buf + *len, &n); + uint8_t offset_width = 0; + if (this->offset() > 0xFFFFFFFF) { + offset_width = 3; + } else if (this->offset() > 0xFFFF) { + offset_width = 2; + } else if (this->offset() > 0x00) { + offset_width = 1; + } else { + offset_width = 0; + } + buf[0] += (offset_width << 1); + QUICTypeUtil::write_QUICOffset(this->offset(), offset_width ? 1 << offset_width : 0, buf + *len, &n); *len += n; // "D" of "11FSSOOD" diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index c630007c682..6540147dac7 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -110,57 +110,95 @@ TEST_CASE("Store STREAM Frame", "[quic]") uint8_t buf[65535]; size_t len; - // 8bit stream id, 64bit offset + // 8bit stream id, 0bit offset uint8_t expected1[] = { + 0xC1, // 11FSSOOD + 0x01, // Stream ID + 0x00, 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + QUICStreamFrame streamFrame1(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01, 0x00); + streamFrame1.store(buf, &len); + CHECK(len == 9); + CHECK(memcmp(buf, expected1, len) == 0); + + // 8bit stream id, 16bit offset + uint8_t expected2[] = { + 0xC3, // 11FSSOOD + 0x01, // Stream ID + 0x00, 0x01, // Offset + 0x00, 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + QUICStreamFrame streamFrame2(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01, 0x01); + streamFrame2.store(buf, &len); + CHECK(len == 11); + CHECK(memcmp(buf, expected2, len) == 0); + + // 8bit stream id, 32bit offset + uint8_t expected3[] = { + 0xC5, // 11FSSOOD + 0x01, // Stream ID + 0x00, 0x01, 0x00, 0x00, // Offset + 0x00, 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + QUICStreamFrame streamFrame3(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01, 0x010000); + streamFrame3.store(buf, &len); + CHECK(len == 13); + CHECK(memcmp(buf, expected3, len) == 0); + + // 8bit stream id, 64bit offset + uint8_t expected4[] = { 0xC7, // 11FSSOOD 0x01, // Stream ID - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Offset + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset 0x00, 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - QUICStreamFrame streamFrame1(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01, 0x00); - streamFrame1.store(buf, &len); + QUICStreamFrame streamFrame4(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01, 0x0100000000); + streamFrame4.store(buf, &len); CHECK(len == 17); - CHECK(memcmp(buf, expected1, len) == 0); + CHECK(memcmp(buf, expected4, len) == 0); // 16bit stream id, 64bit offset - uint8_t expected2[] = { + uint8_t expected5[] = { 0xCF, // 11FSSOOD 0x01, 0x00, // Stream ID - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Offset + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset 0x00, 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - QUICStreamFrame streamFrame2(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x0100, 0x00); - streamFrame2.store(buf, &len); + QUICStreamFrame streamFrame5(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x0100, 0x0100000000); + streamFrame5.store(buf, &len); CHECK(len == 18); - CHECK(memcmp(buf, expected2, len) == 0); + CHECK(memcmp(buf, expected5, len) == 0); // 24bit stream id, 64bit offset - uint8_t expected3[] = { + uint8_t expected6[] = { 0xD7, // 11FSSOOD 0x01, 0x00, 0x00, // Stream ID - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Offset + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset 0x00, 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - QUICStreamFrame streamFrame3(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x010000, 0x00); - streamFrame3.store(buf, &len); + QUICStreamFrame streamFrame6(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x010000, 0x0100000000); + streamFrame6.store(buf, &len); CHECK(len == 19); - CHECK(memcmp(buf, expected3, len) == 0); + CHECK(memcmp(buf, expected6, len) == 0); // 32bit stream id, 64bit offset - uint8_t expected4[] = { + uint8_t expected7[] = { 0xDF, // 11FSSOOD 0x01, 0x00, 0x00, 0x00, // Stream ID - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Offset + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset 0x00, 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - QUICStreamFrame streamFrame4(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01000000, 0x00); - streamFrame4.store(buf, &len); + QUICStreamFrame streamFrame7(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01000000, 0x0100000000); + streamFrame7.store(buf, &len); CHECK(len == 20); - CHECK(memcmp(buf, expected4, len) == 0); + CHECK(memcmp(buf, expected7, len) == 0); } TEST_CASE("Load Ack Frame 1", "[quic]") From 0a56b5af456a7f0c8ed15b38fa21c87345291699 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 15 Sep 2017 08:57:46 +0800 Subject: [PATCH 0108/1313] remove the useless frame since we already written it in vio --- iocore/net/quic/QUICStream.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 91033fefe7a..e6568742d0b 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -268,6 +268,7 @@ QUICStream::_reorder_data() auto frame = _received_stream_frame_buffer.find(this->_recv_offset); while (frame != this->_received_stream_frame_buffer.end()) { this->_write_to_read_vio(frame->second); + this->_received_stream_frame_buffer.erase(frame); frame = _received_stream_frame_buffer.find(this->_recv_offset); } } From 0ee430e9666ac63b6595d5952a129e3046ee892c Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 12 Sep 2017 20:32:22 +0800 Subject: [PATCH 0109/1313] correct the calc of the forward_limit --- iocore/net/quic/QUICStream.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index e6568742d0b..ebc01783021 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -256,7 +256,7 @@ QUICStream::_write_to_read_vio(const std::shared_ptr &fra int bytes_added = this->_read_vio.buffer.writer()->write(frame->data(), frame->data_length()); this->_read_vio.nbytes += bytes_added; this->_recv_offset += frame->data_length(); - this->_local_flow_controller->forward_limit(frame->offset() + this->_flow_control_buffer_size); + this->_local_flow_controller->forward_limit(this->_recv_offset + this->_flow_control_buffer_size); Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [LOCAL] %" PRIu64 "/%" PRIu64, this->_id, QUICDebugNames::stream_state(this->_state), this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); From f973bccd4b5b55f61104ada6e231495672756acb Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Sep 2017 10:56:46 +0900 Subject: [PATCH 0110/1313] Rename _frame_buffer of QUICNetVConnection to _frame_send_queue --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 61d16e28ceb..01b689c3dd5 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -219,7 +219,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection Queue _packet_recv_queue; Queue _packet_send_queue; - std::queue> _frame_buffer; + std::queue _frame_send_queue; Event *_packet_write_ready = nullptr; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b0df002a162..8f25ca9600f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -248,7 +248,7 @@ void QUICNetVConnection::transmit_frame(std::unique_ptr frame) { DebugQUICCon("Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); - this->_frame_buffer.push(std::move(frame)); + this->_frame_send_queue.push(std::move(frame)); if (!this->_packet_write_ready) { this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); } @@ -666,9 +666,9 @@ QUICNetVConnection::_packetize_frames() QUICPacketType previous_packet_type = QUICPacketType::UNINITIALIZED; QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; - while (this->_frame_buffer.size() > 0) { - frame = std::move(this->_frame_buffer.front()); - this->_frame_buffer.pop(); + while (this->_frame_send_queue.size() > 0) { + frame = std::move(this->_frame_send_queue.front()); + this->_frame_send_queue.pop(); QUICRetransmissionFrame *rf = dynamic_cast(frame.get()); previous_packet_type = current_packet_type; if (rf) { From 47078f9aa1c62e9b7e80fb2fe2d95aeb5b1fa139 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Sep 2017 11:25:11 +0900 Subject: [PATCH 0111/1313] Acquire a lock before _frame_send_queue operation --- iocore/net/P_QUICNetVConnection.h | 5 +++-- iocore/net/QUICNetVConnection.cc | 20 +++++++++++++------- iocore/net/quic/QUICLossDetector.cc | 2 +- iocore/net/quic/QUICPacketTransmitter.h | 2 +- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 01b689c3dd5..b29d2d642ef 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -181,7 +181,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // QUICConnection (QUICPacketTransmitter) virtual void transmit_packet(std::unique_ptr packet) override; virtual void retransmit_packet(const QUICPacket &packet) override; - virtual Ptr get_transmitter_mutex() override; + virtual Ptr get_packet_transmitter_mutex() override; // QUICConnection (QUICFrameTransmitter) virtual void transmit_frame(std::unique_ptr frame) override; @@ -236,7 +236,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICError _state_common_receive_packet(); QUICError _state_common_send_packet(); - Ptr _transmitter_mutex; + Ptr _packet_transmitter_mutex; + Ptr _frame_transmitter_mutex; QUICApplication *_create_application(); void _init_flow_control_params(const std::shared_ptr &local_tp, diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8f25ca9600f..aefd28cbc93 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -61,9 +61,10 @@ QUICNetVConnection::QUICNetVConnection() : UnixNetVConnection() void QUICNetVConnection::init(UDPConnection *udp_con, QUICPacketHandler *packet_handler) { - this->_transmitter_mutex = new_ProxyMutex(); - this->_udp_con = udp_con; - this->_packet_handler = packet_handler; + this->_packet_transmitter_mutex = new_ProxyMutex(); + this->_frame_transmitter_mutex = new_ProxyMutex(); + this->_udp_con = udp_con; + this->_packet_handler = packet_handler; this->_quic_connection_id.randomize(); // FIXME These should be done by HttpProxyServerMain @@ -231,9 +232,9 @@ QUICNetVConnection::retransmit_packet(const QUICPacket &packet) } Ptr -QUICNetVConnection::get_transmitter_mutex() +QUICNetVConnection::get_packet_transmitter_mutex() { - return this->_transmitter_mutex; + return this->_packet_transmitter_mutex; } void @@ -248,6 +249,8 @@ void QUICNetVConnection::transmit_frame(std::unique_ptr frame) { DebugQUICCon("Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); + + SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); this->_frame_send_queue.push(std::move(frame)); if (!this->_packet_write_ready) { this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); @@ -641,6 +644,8 @@ QUICNetVConnection::_state_common_send_packet() if (error.cls != QUICErrorClass::NONE) { return error; } + + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->get_packet_transmitter_mutex().get(), this_ethread()); while ((packet = this->_packet_send_queue.dequeue()) != nullptr) { this->_packet_handler->send_packet(*packet, this); this->_loss_detector->on_packet_sent( @@ -666,6 +671,7 @@ QUICNetVConnection::_packetize_frames() QUICPacketType previous_packet_type = QUICPacketType::UNINITIALIZED; QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; + SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); while (this->_frame_send_queue.size() > 0) { frame = std::move(this->_frame_send_queue.front()); this->_frame_send_queue.pop(); @@ -678,7 +684,7 @@ QUICNetVConnection::_packetize_frames() } if (len + frame->size() + MAX_PACKET_OVERHEAD > max_size || (previous_packet_type != current_packet_type && len > 0)) { ink_assert(len > 0); - SCOPED_MUTEX_LOCK(transmitter_lock, this->get_transmitter_mutex().get(), this_ethread()); + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->get_packet_transmitter_mutex().get(), this_ethread()); this->transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, previous_packet_type)); len = 0; } @@ -700,7 +706,7 @@ QUICNetVConnection::_packetize_frames() memset(buf.get() + len, 0, min_size - len); len += min_size - len; } - SCOPED_MUTEX_LOCK(transmitter_lock, this->get_transmitter_mutex().get(), this_ethread()); + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->get_packet_transmitter_mutex().get(), this_ethread()); this->transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, current_packet_type)); } } diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index fb72bc2dfb6..46ded5acd0c 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -344,7 +344,7 @@ QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame) void QUICLossDetector::_retransmit_handshake_packets() { - SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_transmitter_mutex().get(), this_ethread()); + SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); std::set retransmitted_handshake_packets; diff --git a/iocore/net/quic/QUICPacketTransmitter.h b/iocore/net/quic/QUICPacketTransmitter.h index 67c8fa590b0..6aaef383320 100644 --- a/iocore/net/quic/QUICPacketTransmitter.h +++ b/iocore/net/quic/QUICPacketTransmitter.h @@ -46,5 +46,5 @@ class QUICPacketTransmitter * Returns a mutex for transmitter interfaces. * You have to acquire a lock with this mutex before calling any methods provieded by QUICPacketTransmitter */ - virtual Ptr get_transmitter_mutex() = 0; + virtual Ptr get_packet_transmitter_mutex() = 0; }; From 1eb074fa2a96ded10371cee3e7ad991b17659887 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Sep 2017 12:28:53 +0900 Subject: [PATCH 0112/1313] Clear tracked event in the begnning of the event procedure - Clear tracked event in the begnning of the event procedure - Add interal version of transmit_frame() and transmit_packet() The methods from QUICPacketTransmitter and QUICFrameTransmitter could be called from QUICApplication. In that cases, PACKET_WRITE_READY event should be scheduled (if there're no tracked event). OTOH, internally called enqueue and dequeue frames or packets should not schedule event. So this change separate the methods for internal and external, and clear tracked event in the beggining. --- iocore/net/P_QUICNetVConnection.h | 3 ++ iocore/net/QUICNetVConnection.cc | 47 ++++++++++++++++++++++--------- iocore/net/quic/QUICPacket.h | 1 + 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index b29d2d642ef..9bb2b1ae11f 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -223,6 +223,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection Event *_packet_write_ready = nullptr; + void _transmit_packet(QUICPacketPtr); + void _transmit_frame(QUICFramePtr); + void _packetize_frames(); std::unique_ptr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type = QUICPacketType::UNINITIALIZED); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index aefd28cbc93..56246df1070 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -197,10 +197,19 @@ QUICNetVConnection::maximum_stream_frame_data_size() } void -QUICNetVConnection::transmit_packet(std::unique_ptr packet) +QUICNetVConnection::_transmit_packet(QUICPacketPtr packet) { + DebugQUICCon("Packet Type=%s Size=%hu", QUICDebugNames::packet_type(packet->type()), packet->size()); + + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); // TODO Remove const_cast this->_packet_send_queue.enqueue(const_cast(packet.release())); +} + +void +QUICNetVConnection::transmit_packet(std::unique_ptr packet) +{ + this->_transmit_packet(std::move(packet)); if (!this->_packet_write_ready) { this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); } @@ -246,13 +255,20 @@ QUICNetVConnection::push_packet(std::unique_ptr frame) +QUICNetVConnection::_transmit_frame(QUICFramePtr frame) { - DebugQUICCon("Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); + DebugQUICCon("Frame Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); this->_frame_send_queue.push(std::move(frame)); +} + +void +QUICNetVConnection::transmit_frame(std::unique_ptr frame) +{ + this->_transmit_frame(std::move(frame)); if (!this->_packet_write_ready) { + DebugQUICCon("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); } } @@ -362,8 +378,10 @@ QUICNetVConnection::state_handshake(int event, Event *data) break; } case QUIC_EVENT_PACKET_WRITE_READY: { - error = this->_state_common_send_packet(); - this->_packet_write_ready = nullptr; + if (this->_packet_write_ready == data) { + this->_packet_write_ready = nullptr; + } + error = this->_state_common_send_packet(); break; } case EVENT_IMMEDIATE: { @@ -407,11 +425,12 @@ QUICNetVConnection::state_connection_established(int event, Event *data) break; } case QUIC_EVENT_PACKET_WRITE_READY: { - error = this->_state_common_send_packet(); - this->_packet_write_ready = nullptr; + if (this->_packet_write_ready == data) { + this->_packet_write_ready = nullptr; + } + error = this->_state_common_send_packet(); break; } - case EVENT_IMMEDIATE: { // Start Implicit Shutdown. Because of no network activity for the duration of the idle timeout. this->remove_from_active_queue(); @@ -442,8 +461,10 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) break; } case QUIC_EVENT_PACKET_WRITE_READY: { + if (this->_packet_write_ready == data) { + this->_packet_write_ready = nullptr; + } this->_state_common_send_packet(); - this->_packet_write_ready = nullptr; break; } default: @@ -645,7 +666,7 @@ QUICNetVConnection::_state_common_send_packet() return error; } - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->get_packet_transmitter_mutex().get(), this_ethread()); + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); while ((packet = this->_packet_send_queue.dequeue()) != nullptr) { this->_packet_handler->send_packet(*packet, this); this->_loss_detector->on_packet_sent( @@ -684,8 +705,7 @@ QUICNetVConnection::_packetize_frames() } if (len + frame->size() + MAX_PACKET_OVERHEAD > max_size || (previous_packet_type != current_packet_type && len > 0)) { ink_assert(len > 0); - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->get_packet_transmitter_mutex().get(), this_ethread()); - this->transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, previous_packet_type)); + this->_transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, previous_packet_type)); len = 0; } retransmittable = retransmittable || (frame->type() != QUICFrameType::ACK && frame->type() != QUICFrameType::PADDING); @@ -706,8 +726,7 @@ QUICNetVConnection::_packetize_frames() memset(buf.get() + len, 0, min_size - len); len += min_size - len; } - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->get_packet_transmitter_mutex().get(), this_ethread()); - this->transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, current_packet_type)); + this->_transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, current_packet_type)); } } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 56d78874559..9f577e942d3 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -181,6 +181,7 @@ class QUICPacketNumberGenerator }; using QUICPacketDeleterFunc = void (*)(QUICPacket *p); +using QUICPacketPtr = std::unique_ptr; extern ClassAllocator quicPacketAllocator; extern ClassAllocator quicPacketLongHeaderAllocator; From 62bae4c01dd345f2b018d7dada932d3fbfc11b4c Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 18 Sep 2017 12:04:02 +0800 Subject: [PATCH 0113/1313] fix the complie error with test_QUICStreamManager --- iocore/net/quic/Mock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index af8b7ff50b6..66f8f56ebad 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -113,7 +113,7 @@ class MockQUICConnection : public QUICConnection } Ptr - get_transmitter_mutex() override + get_packet_transmitter_mutex() override { return this->_mutex; } @@ -224,7 +224,7 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter } Ptr - get_transmitter_mutex() override + get_packet_transmitter_mutex() override { return this->_mutex; } From 0d3bd625dd84405fb0ac42ebd5e3d37715f59b33 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 18 Sep 2017 15:50:23 +0800 Subject: [PATCH 0114/1313] move state change in _write_to_read_vio --- iocore/net/quic/QUICStream.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index ebc01783021..72ab230e229 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -260,6 +260,8 @@ QUICStream::_write_to_read_vio(const std::shared_ptr &fra Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [LOCAL] %" PRIu64 "/%" PRIu64, this->_id, QUICDebugNames::stream_state(this->_state), this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); + + this->_state.update_with_received_frame(*frame); } void @@ -290,7 +292,6 @@ QUICStream::recv(const std::shared_ptr frame) this->reset(); return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); } - this->_state.update_with_received_frame(*frame); // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit QUICError error = this->_local_flow_controller->update(frame->offset() + frame->data_length()); From 53afc1ece0adfaff27a30e8b6189b0ce9ec08fa9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 22 Sep 2017 10:47:12 +0900 Subject: [PATCH 0115/1313] Add simple multi-streamed application Also add HQClientSession and HQClientTransaction to connect to HttpSM from QUICSimpleApp. HQClientTransaction convert HTTP/0.9 GETs to HTTP/1.1. This will be changed to HTTP over QUIC eventually. --- iocore/net/P_QUICNetVConnection.h | 2 + iocore/net/P_UnixNetVConnection.h | 4 +- iocore/net/QUICNetVConnection.cc | 9 +- iocore/net/UnixNetVConnection.cc | 1 - iocore/net/quic/Makefile.am | 6 +- iocore/net/quic/QUICApplication.cc | 17 ++ iocore/net/quic/QUICApplication.h | 2 + iocore/net/quic/QUICSimpleApp.cc | 92 ++++++++++ iocore/net/quic/QUICSimpleApp.h | 46 +++++ iocore/net/quic/QUICStream.h | 1 + proxy/hq/HQClientSession.cc | 131 ++++++++++++++ proxy/hq/HQClientSession.h | 58 ++++++ proxy/hq/HQClientTransaction.cc | 271 +++++++++++++++++++++++++++++ proxy/hq/HQClientTransaction.h | 67 +++++++ proxy/hq/Makefile.am | 3 +- 15 files changed, 701 insertions(+), 9 deletions(-) create mode 100644 iocore/net/quic/QUICSimpleApp.cc create mode 100644 iocore/net/quic/QUICSimpleApp.h create mode 100644 proxy/hq/HQClientSession.cc create mode 100644 proxy/hq/HQClientSession.h create mode 100644 proxy/hq/HQClientTransaction.cc create mode 100644 proxy/hq/HQClientTransaction.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 9bb2b1ae11f..ae11bf2ca38 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -147,9 +147,11 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void init(UDPConnection *, QUICPacketHandler *); + // UnixNetVConnection void reenable(VIO *vio) override; VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override; VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) override; + int startEvent(int event, Event *e); int state_pre_handshake(int event, Event *data); int state_handshake(int event, Event *data); diff --git a/iocore/net/P_UnixNetVConnection.h b/iocore/net/P_UnixNetVConnection.h index 91b8d2c5b0b..be3fbd06518 100644 --- a/iocore/net/P_UnixNetVConnection.h +++ b/iocore/net/P_UnixNetVConnection.h @@ -281,8 +281,8 @@ class UnixNetVConnection : public NetVConnection ink_hrtime get_inactivity_timeout() override; ink_hrtime get_active_timeout() override; - void set_local_addr() override; - void set_remote_addr() override; + virtual void set_local_addr() override; + virtual void set_remote_addr() override; int set_tcp_init_cwnd(int init_cwnd) override; int set_tcp_congestion_control(int side) override; void apply_options() override; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 56246df1070..978ea1025c7 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -36,6 +36,7 @@ #include "P_SSLNextProtocolSet.h" #include "QUICEchoApp.h" +#include "QUICSimpleApp.h" #include "QUICDebugNames.h" #include "QUICEvents.h" #include "QUICConfig.h" @@ -76,13 +77,15 @@ QUICNetVConnection::init(UDPConnection *udp_con, QUICPacketHandler *packet_handl VIO * QUICNetVConnection::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) { - return super::do_io_read(c, nbytes, buf); + ink_assert(false); + return nullptr; } VIO * QUICNetVConnection::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) { - return super::do_io_write(c, nbytes, buf, owner); + ink_assert(false); + return nullptr; } int @@ -796,7 +799,7 @@ QUICNetVConnection::_create_application() if (app_name) { DebugQUICCon("ALPN: %.*s", app_name_len, app_name); if (memcmp(TS_ALPN_PROTOCOL_HTTP_QUIC, app_name, app_name_len) == 0) { - return new QUICEchoApp(this); + return new QUICSimpleApp(this, this); } else { DebugQUICCon("Negotiated application is not available"); ink_assert(false); diff --git a/iocore/net/UnixNetVConnection.cc b/iocore/net/UnixNetVConnection.cc index c974667f490..8b0f7408348 100644 --- a/iocore/net/UnixNetVConnection.cc +++ b/iocore/net/UnixNetVConnection.cc @@ -33,7 +33,6 @@ // Global ClassAllocator netVCAllocator("netVCAllocator"); - // // Reschedule a UnixNetVConnection by moving it // onto or off of the ready_list diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 40d76384e8d..34463d704cf 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -26,9 +26,10 @@ AM_CPPFLAGS += \ -I$(abs_top_srcdir)/proxy/hdrs \ -I$(abs_top_srcdir)/proxy/shared \ -I$(abs_top_srcdir)/proxy/logging \ + -I$(abs_top_srcdir)/proxy/http \ + -I$(abs_top_srcdir)/proxy/hq \ -I$(abs_top_srcdir)/mgmt \ -I$(abs_top_srcdir)/mgmt/utils \ - -I$(abs_top_srcdir)/proxy/http \ @OPENSSL_INCLUDES@ noinst_LIBRARIES = libquic.a @@ -61,7 +62,8 @@ libquic_a_SOURCES = \ QUICDebugNames.cc \ QUICApplication.cc \ QUICApplicationMap.cc \ - QUICEchoApp.cc + QUICEchoApp.cc \ + QUICSimpleApp.cc include $(top_srcdir)/build/tidy.mk diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index b65b89c3191..dbb832bc830 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -68,6 +68,17 @@ QUICStreamIO::write(const uint8_t *buf, int64_t len) return bytes_add; } +int64_t +QUICStreamIO::write(IOBufferReader *r, int64_t alen, int64_t offset) +{ + SCOPED_MUTEX_LOCK(lock, this->_write_vio->mutex, this_ethread()); + + int64_t bytes_add = this->_write_buffer->write(r, alen, offset); + this->_write_vio->nbytes += bytes_add; + + return bytes_add; +} + void QUICStreamIO::read_reenable() { @@ -80,6 +91,12 @@ QUICStreamIO::write_reenable() return this->_write_vio->reenable(); } +IOBufferReader * +QUICStreamIO::get_read_buffer_reader() +{ + return this->_read_buffer_reader; +} + // // QUICApplication // diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 25df608d907..1d6a3de5185 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -42,8 +42,10 @@ class QUICStreamIO int64_t read_avail(); int64_t read(uint8_t *buf, int64_t len); int64_t write(const uint8_t *buf, int64_t len); + int64_t write(IOBufferReader *r, int64_t len = INT64_MAX, int64_t offset = 0); void read_reenable(); void write_reenable(); + IOBufferReader *get_read_buffer_reader(); private: MIOBuffer *_read_buffer = nullptr; diff --git a/iocore/net/quic/QUICSimpleApp.cc b/iocore/net/quic/QUICSimpleApp.cc new file mode 100644 index 00000000000..82dc21d65af --- /dev/null +++ b/iocore/net/quic/QUICSimpleApp.cc @@ -0,0 +1,92 @@ +/** @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 "QUICSimpleApp.h" + +#include "P_Net.h" +#include "QUICDebugNames.h" + +#include "HQClientSession.h" +#include "HQClientTransaction.h" +#include "../IPAllow.h" + +static constexpr char tag[] = "quic_simple_app"; + +QUICSimpleApp::QUICSimpleApp(QUICNetVConnection *client_vc, QUICConnection *qc) : QUICApplication(qc) +{ + // FIXME: initialize on HQSessionAccept + sockaddr const *client_ip = client_vc->get_remote_addr(); + const AclRecord *session_acl_record = SessionAccept::testIpAllowPolicy(client_ip); + + this->_client_session = new HQClientSession(client_vc); + this->_client_session->acl_record = session_acl_record; + + SET_HANDLER(&QUICSimpleApp::main_event_handler); +} + +QUICSimpleApp::~QUICSimpleApp() +{ + delete this->_client_session; +} + +int +QUICSimpleApp::main_event_handler(int event, Event *data) +{ + Debug(tag, "%s", QUICDebugNames::vc_event(event)); + + QUICStream *stream = reinterpret_cast(data->cookie); + QUICStreamIO *stream_io = this->_find_stream_io(stream->id()); + if (stream_io == nullptr) { + Debug(tag, "Unknown Stream, id: %d", stream->id()); + return -1; + } + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + if (stream_io->read_avail()) { + HQClientTransaction *trans = new HQClientTransaction(this->_client_session, stream_io); + trans->new_transaction(); + } else { + Debug(tag, "No MSG"); + } + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + // Nothing to do + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + ink_assert(false); + break; + } + default: + break; + } + + return EVENT_CONT; +} diff --git a/iocore/net/quic/QUICSimpleApp.h b/iocore/net/quic/QUICSimpleApp.h new file mode 100644 index 00000000000..c658133d597 --- /dev/null +++ b/iocore/net/quic/QUICSimpleApp.h @@ -0,0 +1,46 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICApplication.h" + +class QUICNetVConnection; +class HQClientSession; + +/** + * @brief A simple multi-streamed application. + * @detail Response to simple HTTP/0.9 GETs + * + */ +class QUICSimpleApp : public QUICApplication +{ +public: + QUICSimpleApp(QUICNetVConnection *client_vc, QUICConnection *qc); + ~QUICSimpleApp(); + + int main_event_handler(int event, Event *data); + +private: + HQClientSession *_client_session = nullptr; +}; diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 1a1fe71f7d9..77731a650fb 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -32,6 +32,7 @@ #include "QUICStreamState.h" #include "QUICFlowController.h" +class QUICNetVConnection; class QUICFrameTransmitter; class QUICStreamState; class QUICStreamManager; diff --git a/proxy/hq/HQClientSession.cc b/proxy/hq/HQClientSession.cc new file mode 100644 index 00000000000..e38d08610d4 --- /dev/null +++ b/proxy/hq/HQClientSession.cc @@ -0,0 +1,131 @@ +/** @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 "HQClientSession.h" + +HQClientSession::HQClientSession(NetVConnection *vc) : _client_vc(vc) +{ +} + +HQClientSession::~HQClientSession() +{ + this->_client_vc = nullptr; + for (HQClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { + delete t; + } +} + +VIO * +HQClientSession::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + ink_assert(false); + return nullptr; +} + +VIO * +HQClientSession::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +{ + ink_assert(false); + return nullptr; +} + +void +HQClientSession::do_io_close(int lerrno) +{ + ink_assert(false); + return; +} + +void +HQClientSession::do_io_shutdown(ShutdownHowTo_t howto) +{ + ink_assert(false); + return; +} + +void +HQClientSession::reenable(VIO *vio) +{ + ink_assert(false); + return; +} + +void +HQClientSession::destroy() +{ + ink_assert(false); + return; +} + +void +HQClientSession::start() +{ + ink_assert(false); + return; +} + +void +HQClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader, bool backdoor) +{ + ink_assert(false); + return; +} + +NetVConnection * +HQClientSession::get_netvc() const +{ + return this->_client_vc; +} + +void +HQClientSession::release_netvc() +{ + ink_assert(false); + return; +} + +int +HQClientSession::get_transact_count() const +{ + return 0; +} + +const char * +HQClientSession::get_protocol_string() const +{ + return "hq"; +} + +void +HQClientSession::release(ProxyClientTransaction *trans) +{ + ink_assert(false); + return; +} + +void +HQClientSession::add_transaction(HQClientTransaction *trans) +{ + this->_transaction_list.enqueue(trans); + return; +} diff --git a/proxy/hq/HQClientSession.h b/proxy/hq/HQClientSession.h new file mode 100644 index 00000000000..b3a4ce4b886 --- /dev/null +++ b/proxy/hq/HQClientSession.h @@ -0,0 +1,58 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include "ProxyClientSession.h" +#include "HQClientTransaction.h" + +class HQClientSession : public ProxyClientSession +{ +public: + HQClientSession(NetVConnection *vc); + ~HQClientSession(); + + // Implement VConnection interface + VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) override; + VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; + void do_io_close(int lerrno = -1) override; + void do_io_shutdown(ShutdownHowTo_t howto) override; + void reenable(VIO *vio) override; + + // Implement ProxyClienSession interface + void start() override; + void destroy() override; + void new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader, bool backdoor) override; + NetVConnection *get_netvc() const override; + void release_netvc() override; + int get_transact_count() const override; + const char *get_protocol_string() const override; + void release(ProxyClientTransaction *trans) override; + + // HQClientSession specific methods + void add_transaction(HQClientTransaction *); + +private: + NetVConnection *_client_vc = nullptr; + Queue _transaction_list; +}; diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc new file mode 100644 index 00000000000..e217ce2f662 --- /dev/null +++ b/proxy/hq/HQClientTransaction.cc @@ -0,0 +1,271 @@ +/** @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 "HQClientTransaction.h" + +#include "QUICDebugNames.h" + +#include "HQClientSession.h" +#include "HttpSM.h" + +static void +dump_io_buffer(IOBufferReader *reader) +{ + IOBufferReader *debug_reader = reader->clone(); + uint8_t msg[1024] = {0}; + int64_t msg_len = 1024; + int64_t read_len = debug_reader->read(msg, msg_len); + Debug("hq_trans", "len=%" PRId64 "\n%s\n", read_len, msg); +} + +HQClientTransaction::HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) + +{ + this->mutex = new_ProxyMutex(); + this->parent = session; // trans.set_parent(); + this->sm_reader = this->_read_vio_buf.alloc_reader(); + static_cast(this->parent)->add_transaction(this); + + SET_HANDLER(&HQClientTransaction::main_event_handler); +} + +void +HQClientTransaction::set_active_timeout(ink_hrtime timeout_in) +{ + if (parent) { + parent->set_active_timeout(timeout_in); + } +} + +void +HQClientTransaction::set_inactivity_timeout(ink_hrtime timeout_in) +{ + if (parent) { + parent->set_inactivity_timeout(timeout_in); + } +} + +void +HQClientTransaction::cancel_inactivity_timeout() +{ + if (parent) { + parent->cancel_inactivity_timeout(); + } +} + +void +HQClientTransaction::release(IOBufferReader *r) +{ + super::release(r); + this->current_reader = nullptr; +} + +bool +HQClientTransaction::allow_half_open() const +{ + return false; +} + +int +HQClientTransaction::main_event_handler(int event, void *edata) +{ + Debug("hq_trans", "%s", QUICDebugNames::vc_event(event)); + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + if (edata == this->_read_event) { + this->_read_event = nullptr; + } + if (this->_stream_io->read_avail()) { + this->_read_request(); + } + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + if (edata == this->_write_event) { + this->_write_event = nullptr; + } + if (this->_write_vio.get_reader()->read_avail()) { + this->_write_response(); + } + break; + } + default: + Debug("hq_trans", "Unknown event %d", event); + ink_assert(false); + } + + return EVENT_CONT; +} + +void +HQClientTransaction::reenable(VIO *vio) +{ + if (vio->op == VIO::READ) { + SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); + + if (this->_read_vio.nbytes > 0) { + int event = (this->_read_vio.ntodo() == 0) ? VC_EVENT_READ_COMPLETE : VC_EVENT_READ_READY; + + if (this->_read_event == nullptr) { + this->_read_event = this_ethread()->schedule_imm_local(this, event); + } + } + } else if (vio->op == VIO::WRITE) { + SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); + + if (this->_write_vio.nbytes > 0) { + int event = (this->_write_vio.ntodo() == 0) ? VC_EVENT_WRITE_COMPLETE : VC_EVENT_WRITE_READY; + + if (this->_write_event == nullptr) { + this->_write_event = this_ethread()->schedule_imm_local(this, event); + } + } + } +} + +VIO * +HQClientTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + if (buf) { + this->_read_vio.buffer.writer_for(buf); + } else { + this->_read_vio.buffer.clear(); + } + + this->_read_vio.mutex = c ? c->mutex : this->mutex; + this->_read_vio._cont = c; + this->_read_vio.nbytes = nbytes; + this->_read_vio.ndone = 0; + this->_read_vio.vc_server = this; + this->_read_vio.op = VIO::READ; + + this->_read_vio.reenable(); + + return &this->_read_vio; +} + +VIO * +HQClientTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +{ + if (buf) { + this->_write_vio.buffer.reader_for(buf); + } else { + this->_write_vio.buffer.clear(); + } + + this->_write_vio.mutex = c ? c->mutex : this->mutex; + this->_write_vio._cont = c; + this->_write_vio.nbytes = nbytes; + this->_write_vio.ndone = 0; + this->_write_vio.vc_server = this; + this->_write_vio.op = VIO::WRITE; + + this->_write_vio.reenable(); + + return &this->_write_vio; +} + +void +HQClientTransaction::do_io_close(int lerrno) +{ + parent->do_io_close(lerrno); +} + +void +HQClientTransaction::destroy() +{ + current_reader = nullptr; +} + +void +HQClientTransaction::do_io_shutdown(ShutdownHowTo_t howto) +{ + if (parent) { + parent->do_io_shutdown(howto); + } +} + +// Convert HTTP/0.9 to HTTP/1.1 +void +HQClientTransaction::_read_request() +{ + IOBufferReader *client_vio_reader = this->_stream_io->get_read_buffer_reader(); + int64_t bytes_avail = client_vio_reader->read_avail(); + + // Copy only "GET /path/" + // Check CRLF or LF + int n = 2; + if (bytes_avail > 2 && client_vio_reader->start()[bytes_avail - 2] != '\r') { + n = 1; + } + + MIOBuffer *writer = this->_read_vio.get_writer(); + writer->write(client_vio_reader, bytes_avail - n); + + // FIXME: Get hostname from SNI? + const char version[] = " HTTP/1.1\r\nHost: localhost\r\n\r\n"; + writer->write(version, sizeof(version)); + + dump_io_buffer(this->sm_reader); + + this->_read_vio._cont->handleEvent(VC_EVENT_READ_READY, &this->_read_vio); +} + +// FIXME: already defined somewhere? +static constexpr char http_1_1_version[] = "HTTP/1.1"; + +// Convert HTTP/1.1 to HTTP/0.9 +void +HQClientTransaction::_write_response() +{ + IOBufferReader *reader = this->_write_vio.get_reader(); + + if (memcmp(reader->start(), http_1_1_version, sizeof(http_1_1_version)) == 0) { + // Skip HTTP/1.1 response headers + IOBufferBlock *headers = reader->get_current_block(); + int64_t headers_size = headers->read_avail(); + reader->consume(headers_size); + } + + // Write HTTP/1.1 response body + int64_t bytes_avail = reader->read_avail(); + int64_t total_written = 0; + while (total_written < bytes_avail) { + int64_t bytes_written = this->_stream_io->write(reader, bytes_avail); + reader->consume(bytes_written); + this->_write_vio.ndone += bytes_written; + total_written += bytes_written; + } + + this->_stream_io->write_reenable(); +} + +void +HQClientTransaction::transaction_done() +{ + // TODO: set FIN flag + return; +} diff --git a/proxy/hq/HQClientTransaction.h b/proxy/hq/HQClientTransaction.h new file mode 100644 index 00000000000..fc56a5e1ab5 --- /dev/null +++ b/proxy/hq/HQClientTransaction.h @@ -0,0 +1,67 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include "ProxyClientTransaction.h" + +class QUICStreamIO; +class HQClientSession; + +class HQClientTransaction : public ProxyClientTransaction +{ +public: + using super = ProxyClientTransaction; + + HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io); + + // Implement VConnection interface. + VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; + VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; + void do_io_close(int lerrno = -1) override; + + // Implement ProxyClienTransaction interface + void set_active_timeout(ink_hrtime timeout_in) override; + void set_inactivity_timeout(ink_hrtime timeout_in) override; + void cancel_inactivity_timeout() override; + void transaction_done() override; + bool allow_half_open() const override; + void destroy() override; + void do_io_shutdown(ShutdownHowTo_t howto) override; + void reenable(VIO *vio) override; + void release(IOBufferReader *r) override; + + // HQClientTransaction specific methods + int main_event_handler(int event, void *edata); + +private: + void _read_request(); + void _write_response(); + + MIOBuffer _read_vio_buf = CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX; + VIO _read_vio; + VIO _write_vio; + QUICStreamIO *_stream_io = nullptr; + Event *_read_event = nullptr; + Event *_write_event = nullptr; +}; diff --git a/proxy/hq/Makefile.am b/proxy/hq/Makefile.am index dc545e1525c..da9e2ff4e78 100644 --- a/proxy/hq/Makefile.am +++ b/proxy/hq/Makefile.am @@ -37,7 +37,8 @@ noinst_LIBRARIES = libhq.a libhq_a_SOURCES = \ HQ.cc \ HQSessionAccept.cc \ - HQSessionAccept.h + HQClientSession.cc \ + HQClientTransaction.cc tidy-local: $(libhq_a_SOURCES) \ $(CXX_Clang_Tidy) From 7d6097e360430a2494e154b55c9e9f77b949f6ce Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 22 Sep 2017 14:51:37 +0900 Subject: [PATCH 0116/1313] Skip HTTP/1.1 response headers --- proxy/hq/HQClientTransaction.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index e217ce2f662..3284c40685e 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -243,7 +243,7 @@ HQClientTransaction::_write_response() { IOBufferReader *reader = this->_write_vio.get_reader(); - if (memcmp(reader->start(), http_1_1_version, sizeof(http_1_1_version)) == 0) { + if (memcmp(reader->start(), http_1_1_version, sizeof(http_1_1_version) - 1) == 0) { // Skip HTTP/1.1 response headers IOBufferBlock *headers = reader->get_current_block(); int64_t headers_size = headers->read_avail(); From 57011b159de89cb5aca24c09a3428c0a66c8cf24 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 22 Sep 2017 15:29:09 +0900 Subject: [PATCH 0117/1313] Set FIN flag on final STREAM frame --- iocore/net/quic/QUICApplication.cc | 8 +++++++- iocore/net/quic/QUICApplication.h | 3 +++ iocore/net/quic/QUICStream.cc | 16 +++++++++++++--- iocore/net/quic/QUICStream.h | 2 ++ proxy/hq/HQClientTransaction.cc | 8 +++++++- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index dbb832bc830..1ba29dd3cac 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -31,7 +31,7 @@ static constexpr char tag[] = "quic_app"; // // QUICStreamIO // -QUICStreamIO::QUICStreamIO(QUICApplication *app, QUICStream *stream) +QUICStreamIO::QUICStreamIO(QUICApplication *app, QUICStream *stream) : _stream(stream) { this->_read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); this->_write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); @@ -97,6 +97,12 @@ QUICStreamIO::get_read_buffer_reader() return this->_read_buffer_reader; } +void +QUICStreamIO::set_fin() +{ + return this->_stream->set_fin(); +} + // // QUICApplication // diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 1d6a3de5185..8a20fc3d09f 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -46,8 +46,11 @@ class QUICStreamIO void read_reenable(); void write_reenable(); IOBufferReader *get_read_buffer_reader(); + void set_fin(); private: + QUICStream *_stream = nullptr; + MIOBuffer *_read_buffer = nullptr; MIOBuffer *_write_buffer = nullptr; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 72ab230e229..4ecb1253d66 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -351,12 +351,16 @@ QUICStream::_send() while (total_len < bytes_avail) { int64_t data_len = reader->block_read_avail(); - size_t len = 0; + int64_t len = 0; + bool fin = false; if (data_len > max_size) { len = max_size; } else { len = data_len; + if (total_len + len >= bytes_avail) { + fin = this->_fin; + } } QUICError error = this->_remote_flow_controller->update(this->_send_offset + len); @@ -367,8 +371,8 @@ QUICStream::_send() break; } - std::unique_ptr frame = - QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, this->_id, this->_send_offset); + std::unique_ptr frame = QUICFrameFactory::create_stream_frame( + reinterpret_cast(reader->start()), len, this->_id, this->_send_offset, fin); this->_send_offset += len; reader->consume(len); @@ -392,6 +396,12 @@ QUICStream::reset() // TODO: Create a RST_STREAM frame and pass it to Stream Manager } +void +QUICStream::set_fin() +{ + this->_fin = true; +} + size_t QUICStream::nbytes_to_read() { diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 77731a650fb..0b06b649475 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -65,6 +65,7 @@ class QUICStream : public VConnection QUICError recv(const std::shared_ptr frame); void reset(); + void set_fin(); size_t nbytes_to_read(); @@ -89,6 +90,7 @@ class QUICStream : public VConnection Event *_send_tracked_event(Event *event, int send_event, VIO *vio); + bool _fin; QUICStreamId _id = 0; QUICOffset _recv_offset = 0; QUICOffset _send_offset = 0; diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 3284c40685e..cd894e9aae3 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -248,6 +248,7 @@ HQClientTransaction::_write_response() IOBufferBlock *headers = reader->get_current_block(); int64_t headers_size = headers->read_avail(); reader->consume(headers_size); + this->_write_vio.ndone += headers_size; } // Write HTTP/1.1 response body @@ -260,12 +261,17 @@ HQClientTransaction::_write_response() total_written += bytes_written; } + // NOTE: When Chunked Transfer Coding is supported, check ChunkedState of ChunkedHandler + // is CHUNK_READ_DONE and set FIN flag + if (this->_write_vio.ntodo() == 0) { + this->_stream_io->set_fin(); + } this->_stream_io->write_reenable(); } void HQClientTransaction::transaction_done() { - // TODO: set FIN flag + // TODO: start closing transaction return; } From e601615b20dc73978acc2452d38d9b4c8169e1eb Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 22 Sep 2017 16:24:34 +0900 Subject: [PATCH 0118/1313] Rename QUICStream::set_fin() to QUICStream::shutdown() --- iocore/net/quic/QUICApplication.cc | 4 ++-- iocore/net/quic/QUICApplication.h | 2 +- iocore/net/quic/QUICStream.cc | 2 +- iocore/net/quic/QUICStream.h | 2 +- proxy/hq/HQClientTransaction.cc | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 1ba29dd3cac..61c1429edb2 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -98,9 +98,9 @@ QUICStreamIO::get_read_buffer_reader() } void -QUICStreamIO::set_fin() +QUICStreamIO::shutdown() { - return this->_stream->set_fin(); + return this->_stream->shutdown(); } // diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 8a20fc3d09f..20059d798bc 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -46,7 +46,7 @@ class QUICStreamIO void read_reenable(); void write_reenable(); IOBufferReader *get_read_buffer_reader(); - void set_fin(); + void shutdown(); private: QUICStream *_stream = nullptr; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 4ecb1253d66..3b982897cc6 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -397,7 +397,7 @@ QUICStream::reset() } void -QUICStream::set_fin() +QUICStream::shutdown() { this->_fin = true; } diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 0b06b649475..d8b476c74d8 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -65,7 +65,7 @@ class QUICStream : public VConnection QUICError recv(const std::shared_ptr frame); void reset(); - void set_fin(); + void shutdown(); size_t nbytes_to_read(); diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index cd894e9aae3..92d8d362c11 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -264,7 +264,7 @@ HQClientTransaction::_write_response() // NOTE: When Chunked Transfer Coding is supported, check ChunkedState of ChunkedHandler // is CHUNK_READ_DONE and set FIN flag if (this->_write_vio.ntodo() == 0) { - this->_stream_io->set_fin(); + this->_stream_io->shutdown(); } this->_stream_io->write_reenable(); } From 5575369ad6f09f3b3f24a4b9c422f77d37341302 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 26 Sep 2017 11:53:42 +0900 Subject: [PATCH 0119/1313] Delegate creating QUIC application to SessionAccept --- iocore/net/Makefile.am | 2 + iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/P_QUICNextProtocolAccept.h | 61 +++++++++++++++ iocore/net/P_QUICPacketHandler.h | 1 + iocore/net/QUICNetVConnection.cc | 41 +++------- iocore/net/QUICNextProtocolAccept.cc | 103 ++++++++++++++++++++++++++ iocore/net/QUICPacketHandler.cc | 1 + iocore/net/quic/Makefile.am | 4 +- iocore/net/quic/Mock.h | 95 +++++++++++++----------- iocore/net/quic/QUICConnection.h | 3 + iocore/net/quic/QUICSimpleApp.cc | 6 +- iocore/net/quic/QUICSimpleApp.h | 2 +- iocore/net/quic/QUICStreamManager.cc | 6 ++ iocore/net/quic/QUICStreamManager.h | 2 + proxy/hq/HQClientSession.cc | 3 +- proxy/hq/HQSessionAccept.cc | 9 +-- proxy/hq/Makefile.am | 3 +- proxy/http/HttpProxyServerMain.cc | 10 ++- 18 files changed, 262 insertions(+), 92 deletions(-) create mode 100644 iocore/net/P_QUICNextProtocolAccept.h create mode 100644 iocore/net/QUICNextProtocolAccept.cc diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am index 10ce90d21e0..faad241ab90 100644 --- a/iocore/net/Makefile.am +++ b/iocore/net/Makefile.am @@ -107,6 +107,7 @@ libinknet_a_SOURCES = \ P_SSLNetProcessor.h \ P_SSLNetVConnection.h \ P_SSLNextProtocolAccept.h \ + P_QUICNextProtocolAccept.h \ P_SSLNextProtocolSet.h \ P_SSLUtils.h \ P_SSLClientUtils.h \ @@ -132,6 +133,7 @@ libinknet_a_SOURCES = \ SSLNetProcessor.cc \ SSLNetVConnection.cc \ SSLNextProtocolAccept.cc \ + QUICNextProtocolAccept.cc \ SSLNextProtocolSet.cc \ SSLUtils.cc \ SSLClientUtils.cc \ diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index ae11bf2ca38..6ce31942146 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -173,6 +173,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection uint32_t maximum_quic_packet_size() override; uint32_t minimum_quic_packet_size() override; uint32_t maximum_stream_frame_data_size() override; + QUICStreamManager *stream_manager() override; uint32_t pmtu() override; NetVConnectionContext_t direction() override; SSLNextProtocolSet *next_protocol_set() override; @@ -244,7 +245,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection Ptr _packet_transmitter_mutex; Ptr _frame_transmitter_mutex; - QUICApplication *_create_application(); void _init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); diff --git a/iocore/net/P_QUICNextProtocolAccept.h b/iocore/net/P_QUICNextProtocolAccept.h new file mode 100644 index 00000000000..5b03652b0ae --- /dev/null +++ b/iocore/net/P_QUICNextProtocolAccept.h @@ -0,0 +1,61 @@ +/** @file + + QUICNextProtocolAccept + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include "P_QUICNetVConnection.h" +#include "P_SSLNextProtocolSet.h" +#include "I_IOBuffer.h" + +class QUICNextProtocolAccept : public SessionAccept +{ +public: + QUICNextProtocolAccept(); + ~QUICNextProtocolAccept(); + + bool accept(NetVConnection *, MIOBuffer *, IOBufferReader *); + + // Register handler as an endpoint for the specified protocol. Neither + // handler nor protocol are copied, so the caller must guarantee their + // lifetime is at least as long as that of the acceptor. + bool registerEndpoint(const char *protocol, Continuation *handler); + + // Unregister the handler. Returns false if this protocol is not registered + // or if it is not registered for the specified handler. + bool unregisterEndpoint(const char *protocol, Continuation *handler); + + SLINK(QUICNextProtocolAccept, link); + SSLNextProtocolSet *getProtoSet(); + SSLNextProtocolSet *cloneProtoSet(); + + // noncopyable + QUICNextProtocolAccept(const QUICNextProtocolAccept &) = delete; // disabled + QUICNextProtocolAccept &operator=(const QUICNextProtocolAccept &) = delete; // disabled + +private: + int mainEvent(int event, void *netvc); + + SSLNextProtocolSet protoset; + + friend struct QUICNextProtocolTrampoline; +}; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 6b29b6aa1cc..e1ea3fbae29 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -26,6 +26,7 @@ #include "ts/ink_platform.h" #include "P_Connection.h" #include "P_NetAccept.h" +#include "quic/QUICTypes.h" class QUICNetVConnection; class QUICPacket; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 978ea1025c7..87e749a0679 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -35,8 +35,6 @@ #include "P_SSLNextProtocolSet.h" -#include "QUICEchoApp.h" -#include "QUICSimpleApp.h" #include "QUICDebugNames.h" #include "QUICEvents.h" #include "QUICConfig.h" @@ -67,11 +65,6 @@ QUICNetVConnection::init(UDPConnection *udp_con, QUICPacketHandler *packet_handl this->_udp_con = udp_con; this->_packet_handler = packet_handler; this->_quic_connection_id.randomize(); - - // FIXME These should be done by HttpProxyServerMain - SSLNextProtocolSet *next_protocol_set = new SSLNextProtocolSet(); - next_protocol_set->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC, nullptr); - this->registerNextProtocolSet(next_protocol_set); } VIO * @@ -199,6 +192,12 @@ QUICNetVConnection::maximum_stream_frame_data_size() return this->maximum_quic_packet_size() - MAX_STREAM_FRAME_OVERHEAD - MAX_PACKET_OVERHEAD; } +QUICStreamManager * +QUICNetVConnection::stream_manager() +{ + return this->_stream_manager; +} + void QUICNetVConnection::_transmit_packet(QUICPacketPtr packet) { @@ -407,12 +406,17 @@ QUICNetVConnection::state_handshake(int event, Event *data) } if (this->_handshake_handler && this->_handshake_handler->is_completed()) { - this->_application_map->set_default(this->_create_application()); this->_init_flow_control_params(this->_handshake_handler->local_transport_parameters(), this->_handshake_handler->remote_transport_parameters()); DebugQUICCon("Enter state_connection_established"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); + + const uint8_t *app_name; + unsigned int app_name_len = 0; + this->_handshake_handler->negotiated_application_name(&app_name, &app_name_len); + Continuation *endpoint = this->_next_protocol_set->findEndpoint(app_name, app_name_len); + endpoint->handleEvent(NET_EVENT_ACCEPT, this); } return EVENT_CONT; @@ -790,27 +794,6 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi return packet; } -QUICApplication * -QUICNetVConnection::_create_application() -{ - const uint8_t *app_name; - unsigned int app_name_len = 0; - this->_handshake_handler->negotiated_application_name(&app_name, &app_name_len); - if (app_name) { - DebugQUICCon("ALPN: %.*s", app_name_len, app_name); - if (memcmp(TS_ALPN_PROTOCOL_HTTP_QUIC, app_name, app_name_len) == 0) { - return new QUICSimpleApp(this, this); - } else { - DebugQUICCon("Negotiated application is not available"); - ink_assert(false); - return nullptr; - } - } else { - DebugQUICCon("Failed to negotiate application"); - return nullptr; - } -} - void QUICNetVConnection::_init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp) diff --git a/iocore/net/QUICNextProtocolAccept.cc b/iocore/net/QUICNextProtocolAccept.cc new file mode 100644 index 00000000000..bdd89ed5922 --- /dev/null +++ b/iocore/net/QUICNextProtocolAccept.cc @@ -0,0 +1,103 @@ +/** @file + + QUICNextProtocolAccept + + @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 "P_QUICNextProtocolAccept.h" + +static QUICNetVConnection * +quic_netvc_cast(int event, void *edata) +{ + union { + VIO *vio; + NetVConnection *vc; + } ptr; + + switch (event) { + case NET_EVENT_ACCEPT: + ptr.vc = static_cast(edata); + return dynamic_cast(ptr.vc); + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_ERROR: + ptr.vio = static_cast(edata); + return dynamic_cast(ptr.vio->vc_server); + default: + return nullptr; + } +} + +int +QUICNextProtocolAccept::mainEvent(int event, void *edata) +{ + QUICNetVConnection *netvc = quic_netvc_cast(event, edata); + + Debug("quic", "[QUICNextProtocolAccept:mainEvent] event %d netvc %p", event, netvc); + switch (event) { + case NET_EVENT_ACCEPT: + ink_release_assert(netvc != nullptr); + netvc->registerNextProtocolSet(&this->protoset); + return EVENT_CONT; + default: + netvc->do_io_close(); + return EVENT_DONE; + } +} + +bool +QUICNextProtocolAccept::accept(NetVConnection *, MIOBuffer *, IOBufferReader *) +{ + ink_release_assert(0); + return false; +} + +bool +QUICNextProtocolAccept::registerEndpoint(const char *protocol, Continuation *handler) +{ + return this->protoset.registerEndpoint(protocol, handler); +} + +bool +QUICNextProtocolAccept::unregisterEndpoint(const char *protocol, Continuation *handler) +{ + return this->protoset.unregisterEndpoint(protocol, handler); +} + +QUICNextProtocolAccept::QUICNextProtocolAccept() : SessionAccept(nullptr) +{ + SET_HANDLER(&QUICNextProtocolAccept::mainEvent); +} + +SSLNextProtocolSet * +QUICNextProtocolAccept::getProtoSet() +{ + return &this->protoset; +} + +SSLNextProtocolSet * +QUICNextProtocolAccept::cloneProtoSet() +{ + return this->protoset.clone(); +} + +QUICNextProtocolAccept::~QUICNextProtocolAccept() +{ +} diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 39df7ce3d1b..3558221ce98 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -158,6 +158,7 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) vc->options.ip_family = udpPacket->from.sa.sa_family; this->_connections.put(cid, vc); + this->action_->continuation->handleEvent(NET_EVENT_ACCEPT, vc); } std::unique_ptr qPkt = QUICPacketFactory::create(block, vc->largest_received_packet_number()); diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 34463d704cf..90ba2fe480a 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -61,9 +61,7 @@ libquic_a_SOURCES = \ QUICConfig.cc \ QUICDebugNames.cc \ QUICApplication.cc \ - QUICApplicationMap.cc \ - QUICEchoApp.cc \ - QUICSimpleApp.cc + QUICApplicationMap.cc include $(top_srcdir)/build/tidy.mk diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 66f8f56ebad..af097ce5394 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -28,6 +28,50 @@ #include "QUICEvents.h" #include "QUICPacketTransmitter.h" +class MockQUICStreamManager : public QUICStreamManager +{ +public: + MockQUICStreamManager() : QUICStreamManager() {} + // Override + virtual QUICError + handle_frame(std::shared_ptr f) override + { + ++_frameCount[static_cast(f->type())]; + ++_totalFrameCount; + + return QUICError(QUICErrorClass::NONE); + } + + // for Test + int + getStreamFrameCount() + { + return _frameCount[static_cast(QUICFrameType::STREAM)]; + } + + int + getAckFrameCount() + { + return _frameCount[static_cast(QUICFrameType::ACK)]; + } + + int + getPingFrameCount() + { + return _frameCount[static_cast(QUICFrameType::PING)]; + } + + int + getTotalFrameCount() + { + return _totalFrameCount; + } + +private: + int _totalFrameCount = 0; + int _frameCount[256] = {0}; +}; + class MockNetVConnection : public NetVConnection { public: @@ -197,11 +241,18 @@ class MockQUICConnection : public QUICConnection return _totalFrameCount; } + QUICStreamManager * + stream_manager() override + { + return &_stream_manager; + } + int _transmit_count = 0; int _retransmit_count = 0; Ptr _mutex; int _totalFrameCount = 0; int _frameCount[256] = {0}; + MockQUICStreamManager _stream_manager; QUICTransportParametersInEncryptedExtensions dummy_transport_parameters; NetVConnectionContext_t _direction; @@ -267,50 +318,6 @@ class MockQUICLossDetector : public QUICLossDetector } }; -class MockQUICStreamManager : public QUICStreamManager -{ -public: - MockQUICStreamManager() : QUICStreamManager() {} - // Override - virtual QUICError - handle_frame(std::shared_ptr f) override - { - ++_frameCount[static_cast(f->type())]; - ++_totalFrameCount; - - return QUICError(QUICErrorClass::NONE); - } - - // for Test - int - getStreamFrameCount() - { - return _frameCount[static_cast(QUICFrameType::STREAM)]; - } - - int - getAckFrameCount() - { - return _frameCount[static_cast(QUICFrameType::ACK)]; - } - - int - getPingFrameCount() - { - return _frameCount[static_cast(QUICFrameType::PING)]; - } - - int - getTotalFrameCount() - { - return _totalFrameCount; - } - -private: - int _totalFrameCount = 0; - int _frameCount[256] = {0}; -}; - class MockQUICCongestionController : public QUICCongestionController { public: diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 69dfea6d300..690181907b3 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -29,6 +29,7 @@ #include "QUICTransportParameters.h" class QUICApplication; +class QUICStreamManager; class SSLNextProtocolSet; class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler @@ -49,6 +50,8 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter */ virtual uint32_t minimum_quic_packet_size() = 0; + virtual QUICStreamManager *stream_manager() = 0; + virtual uint32_t pmtu() = 0; virtual NetVConnectionContext_t direction() = 0; virtual SSLNextProtocolSet *next_protocol_set() = 0; diff --git a/iocore/net/quic/QUICSimpleApp.cc b/iocore/net/quic/QUICSimpleApp.cc index 82dc21d65af..f7424d15882 100644 --- a/iocore/net/quic/QUICSimpleApp.cc +++ b/iocore/net/quic/QUICSimpleApp.cc @@ -32,14 +32,16 @@ static constexpr char tag[] = "quic_simple_app"; -QUICSimpleApp::QUICSimpleApp(QUICNetVConnection *client_vc, QUICConnection *qc) : QUICApplication(qc) +QUICSimpleApp::QUICSimpleApp(QUICNetVConnection *client_vc) : QUICApplication(client_vc) { - // FIXME: initialize on HQSessionAccept sockaddr const *client_ip = client_vc->get_remote_addr(); const AclRecord *session_acl_record = SessionAccept::testIpAllowPolicy(client_ip); this->_client_session = new HQClientSession(client_vc); this->_client_session->acl_record = session_acl_record; + this->_client_session->new_connection(client_vc, nullptr, nullptr, false); + + this->_client_qc->stream_manager()->set_default_application(this); SET_HANDLER(&QUICSimpleApp::main_event_handler); } diff --git a/iocore/net/quic/QUICSimpleApp.h b/iocore/net/quic/QUICSimpleApp.h index c658133d597..12804eb6554 100644 --- a/iocore/net/quic/QUICSimpleApp.h +++ b/iocore/net/quic/QUICSimpleApp.h @@ -36,7 +36,7 @@ class HQClientSession; class QUICSimpleApp : public QUICApplication { public: - QUICSimpleApp(QUICNetVConnection *client_vc, QUICConnection *qc); + QUICSimpleApp(QUICNetVConnection *client_vc); ~QUICSimpleApp(); int main_event_handler(int event, Event *data); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 24f8fb8aea5..d79245c721a 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -258,3 +258,9 @@ QUICStreamManager::stream_count() const } return count; } + +void +QUICStreamManager::set_default_application(QUICApplication *app) +{ + this->_app_map->set_default(app); +} diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 3fa81efcab3..284a93d6a2b 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -45,6 +45,8 @@ class QUICStreamManager : public QUICFrameHandler uint64_t total_offset_sent() const; uint32_t stream_count() const; + void set_default_application(QUICApplication *app); + DLL stream_list; // QUICFrameHandler diff --git a/proxy/hq/HQClientSession.cc b/proxy/hq/HQClientSession.cc index e38d08610d4..27d19619630 100644 --- a/proxy/hq/HQClientSession.cc +++ b/proxy/hq/HQClientSession.cc @@ -87,7 +87,8 @@ HQClientSession::start() void HQClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader, bool backdoor) { - ink_assert(false); + this->con_id = ProxyClientSession::next_connection_id(); + return; } diff --git a/proxy/hq/HQSessionAccept.cc b/proxy/hq/HQSessionAccept.cc index a98e44ec05a..a0533981816 100644 --- a/proxy/hq/HQSessionAccept.cc +++ b/proxy/hq/HQSessionAccept.cc @@ -26,6 +26,7 @@ #include "P_Net.h" #include "I_Machine.h" #include "../IPAllow.h" +#include "QUICSimpleApp.h" HQSessionAccept::HQSessionAccept(const HttpSessionAccept::Options &_o) : SessionAccept(nullptr), options(_o) { @@ -55,13 +56,7 @@ HQSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader ats_ip_nptop(client_ip, ipb, sizeof(ipb)), netvc->attributes); } - ink_assert(false); - // Not implemented yet - - // HQClientSession *new_session = THREAD_ALLOC_INIT(quicClientSessionAllocator, this_ethread()); - // new_session->acl_record = session_acl_record; - // new_session->new_connection(netvc, iobuf, reader, false /* backdoor */); - // static_cast(netvc)->set_application(new_session); + new QUICSimpleApp(static_cast(netvc)); return true; } diff --git a/proxy/hq/Makefile.am b/proxy/hq/Makefile.am index da9e2ff4e78..955b0929534 100644 --- a/proxy/hq/Makefile.am +++ b/proxy/hq/Makefile.am @@ -38,7 +38,8 @@ libhq_a_SOURCES = \ HQ.cc \ HQSessionAccept.cc \ HQClientSession.cc \ - HQClientTransaction.cc + HQClientTransaction.cc \ + $(abs_top_srcdir)/iocore/net/quic/QUICSimpleApp.cc tidy-local: $(libhq_a_SOURCES) \ $(CXX_Clang_Tidy) diff --git a/proxy/http/HttpProxyServerMain.cc b/proxy/http/HttpProxyServerMain.cc index acde3396155..36d8fe71f7f 100644 --- a/proxy/http/HttpProxyServerMain.cc +++ b/proxy/http/HttpProxyServerMain.cc @@ -40,6 +40,7 @@ #include "http2/Http2SessionAccept.h" #include "HttpConnectionCount.h" #if TS_USE_QUIC == 1 +#include "P_QUICNextProtocolAccept.h" #include "hq/HQSessionAccept.h" #endif @@ -223,12 +224,15 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned acceptor._accept = ssl; #if TS_USE_QUIC == 1 } else if (port.isQUIC()) { + QUICNextProtocolAccept *quic = new QUICNextProtocolAccept(); + // HTTP/QUIC if (port.m_session_protocol_preference.contains(TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC)) { - HQSessionAccept *hq = new HQSessionAccept(accept_opt); - // FIXME hq should be registered to QUICNextProtocolAccept like SSL - acceptor._accept = hq; + quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC, new HQSessionAccept(accept_opt)); } + + quic->proxyPort = &port; + acceptor._accept = quic; #endif } else { acceptor._accept = probe; From f0548d651a252600eabeea49ecba99dca6883efc Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 27 Sep 2017 16:53:48 +0900 Subject: [PATCH 0120/1313] Add _stream_frame_send_queue for remote flow control `_frame_send_queue` of QUICNetVConnection is the queue for any type of frame except STREAM frame. The flow contorl doesn't blcok frames in this queue. `_stream_frame_send_queue` of QUICNetVConnection is the queue for STREAM frame except Stream 0. --- iocore/net/P_QUICNetVConnection.h | 9 +- iocore/net/QUICNetVConnection.cc | 130 +++++++++++++----- iocore/net/quic/Mock.h | 1 + iocore/net/quic/QUICFlowController.cc | 22 ++- iocore/net/quic/QUICFlowController.h | 4 + iocore/net/quic/QUICFrame.h | 1 + iocore/net/quic/QUICStreamManager.cc | 15 +- iocore/net/quic/QUICStreamManager.h | 3 + iocore/net/quic/QUICTypes.cc | 2 - iocore/net/quic/QUICTypes.h | 3 +- .../net/quic/test/test_QUICStreamManager.cc | 5 +- 11 files changed, 143 insertions(+), 52 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 6ce31942146..c80ef55bba3 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -187,7 +187,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection virtual Ptr get_packet_transmitter_mutex() override; // QUICConnection (QUICFrameTransmitter) - virtual void transmit_frame(std::unique_ptr frame) override; + virtual void transmit_frame(QUICFramePtr frame) override; // QUICConnection (QUICFrameHandler) std::vector interests() override; @@ -222,13 +222,20 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection Queue _packet_recv_queue; Queue _packet_send_queue; + // `_frame_send_queue` is the queue for any type of frame except STREAM frame. + // The flow contorl doesn't blcok frames in this queue. + // `_stream_frame_send_queue` is the queue for STREAM frame. std::queue _frame_send_queue; + std::queue _stream_frame_send_queue; Event *_packet_write_ready = nullptr; void _transmit_packet(QUICPacketPtr); void _transmit_frame(QUICFramePtr); + bool _is_send_frame_avail_more_than(uint32_t size); + void _store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, + QUICFramePtr frame); void _packetize_frames(); std::unique_ptr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type = QUICPacketType::UNINITIALIZED); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 87e749a0679..3795121db40 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -262,11 +262,22 @@ QUICNetVConnection::_transmit_frame(QUICFramePtr frame) DebugQUICCon("Frame Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); - this->_frame_send_queue.push(std::move(frame)); + + if (frame->type() == QUICFrameType::STREAM) { + QUICStreamFrame &stream_frame = static_cast(*frame); + // XXX: Stream 0 is exempt from the connection-level flow control window. + if (stream_frame.stream_id() == STREAM_ID_FOR_HANDSHAKE) { + this->_frame_send_queue.push(std::move(frame)); + } else { + this->_stream_frame_send_queue.push(std::move(frame)); + } + } else { + this->_frame_send_queue.push(std::move(frame)); + } } void -QUICNetVConnection::transmit_frame(std::unique_ptr frame) +QUICNetVConnection::transmit_frame(QUICFramePtr frame) { this->_transmit_frame(std::move(frame)); if (!this->_packet_write_ready) { @@ -305,6 +316,11 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); + + if (!this->_packet_write_ready) { + this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + } + break; case QUICFrameType::BLOCKED: // BLOCKED frame is for debugging. Nothing to do here. @@ -665,13 +681,6 @@ QUICNetVConnection::_state_common_send_packet() this->_packetize_frames(); QUICPacket *packet; - QUICError error = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, - static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); - if (error.cls != QUICErrorClass::NONE) { - return error; - } SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); while ((packet = this->_packet_send_queue.dequeue()) != nullptr) { @@ -685,49 +694,98 @@ QUICNetVConnection::_state_common_send_packet() return QUICError(QUICErrorClass::NONE); } +// Schedule sending BLOCKED frame when offset exceed the limit +bool +QUICNetVConnection::_is_send_frame_avail_more_than(uint32_t size) +{ + QUICError error = this->_remote_flow_controller->update((this->_stream_manager->total_offset_sent() + size) / 1024); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, + static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); + + if (error.cls != QUICErrorClass::NONE) { + // Flow Contoroller blocked sending STREAM frame + return false; + } + + return true; +} + +// Store frame data to buffer for packet. When remaining buffer is too small to store frame data or packet type is different from +// previous one, build packet and transmit it. After that, allocate new buffer. void -QUICNetVConnection::_packetize_frames() +QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, + QUICFramePtr frame) { uint32_t max_size = this->maximum_quic_packet_size(); - uint32_t min_size = this->minimum_quic_packet_size(); - ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); + + QUICPacketType previous_packet_type = current_packet_type; + QUICRetransmissionFrame *rf = dynamic_cast(frame.get()); + if (rf) { + current_packet_type = rf->packet_type(); + } else { + current_packet_type = QUICPacketType::UNINITIALIZED; + } + + if (len + frame->size() + MAX_PACKET_OVERHEAD > max_size || (previous_packet_type != current_packet_type && len > 0)) { + ink_assert(len > 0); + this->_transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, previous_packet_type)); + retransmittable = false; + len = 0; + } + + retransmittable = retransmittable || (frame->type() != QUICFrameType::ACK && frame->type() != QUICFrameType::PADDING); + + if (buf == nullptr) { + buf = ats_unique_malloc(max_size); + } + + size_t l = 0; + DebugQUICCon("type=%s", QUICDebugNames::frame_type(frame->type())); + frame->store(buf.get() + len, &l); + len += l; + + return; +} + +// 1. Dequeue frame from _stream_frame_send_queue and _frame_send_queue +// 2. Put frames into buffer as many as possible +// 3. Build packet with the buffer +// 4. Enqueue the packet via transmit_packet +void +QUICNetVConnection::_packetize_frames() +{ size_t len = 0; + ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); + QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; - // Put frames into buf as many as possible - std::unique_ptr frame(nullptr, nullptr); - bool retransmittable = false; - QUICPacketType previous_packet_type = QUICPacketType::UNINITIALIZED; - QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; + QUICFramePtr frame(nullptr, nullptr); + bool retransmittable = false; SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); + while (this->_frame_send_queue.size() > 0) { frame = std::move(this->_frame_send_queue.front()); this->_frame_send_queue.pop(); - QUICRetransmissionFrame *rf = dynamic_cast(frame.get()); - previous_packet_type = current_packet_type; - if (rf) { - current_packet_type = rf->packet_type(); - } else { - current_packet_type = QUICPacketType::UNINITIALIZED; - } - if (len + frame->size() + MAX_PACKET_OVERHEAD > max_size || (previous_packet_type != current_packet_type && len > 0)) { - ink_assert(len > 0); - this->_transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, previous_packet_type)); - len = 0; - } - retransmittable = retransmittable || (frame->type() != QUICFrameType::ACK && frame->type() != QUICFrameType::PADDING); + this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + } - if (buf == nullptr) { - buf = ats_unique_malloc(max_size); + while (this->_stream_frame_send_queue.size() > 0) { + const QUICFramePtr &f = this->_stream_frame_send_queue.front(); + uint32_t frame_size = f->size(); + if (!this->_is_send_frame_avail_more_than(frame_size)) { + break; } - size_t l = 0; - DebugQUICCon("type=%s", QUICDebugNames::frame_type(frame->type())); - frame->store(buf.get() + len, &l); - len += l; + + frame = std::move(this->_stream_frame_send_queue.front()); + this->_stream_frame_send_queue.pop(); + this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + this->_stream_manager->add_total_offset_sent(frame_size); } if (len != 0) { // Pad with PADDING frames + uint32_t min_size = this->minimum_quic_packet_size(); if (min_size > len) { // FIXME QUICNetVConnection should not know the actual type value of PADDING frame memset(buf.get() + len, 0, min_size - len); diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index af097ce5394..20cb7320a1d 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -382,6 +382,7 @@ class MockQUICApplication : public QUICApplication { QUICStreamIO *stream_io = this->_find_stream_io(stream_id); stream_io->write(data, size); + eventProcessor.schedule_imm(this, ET_CALL, 12345, stream_io); } }; diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 77a615d72ac..43e223a7a28 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -25,6 +25,9 @@ #include "QUICFrame.h" #include "QUICFrameTransmitter.h" +// +// QUICFlowController +// QUICOffset QUICFlowController::current_offset() { @@ -68,6 +71,16 @@ QUICFlowController::set_threshold(uint64_t threshold) this->_threshold = threshold; } +// +// QUICRemoteFlowController +// +void +QUICRemoteFlowController::forward_limit(QUICOffset offset) +{ + QUICFlowController::forward_limit(offset); + this->_blocked = false; +} + QUICError QUICRemoteFlowController::update(QUICOffset offset) { @@ -79,13 +92,17 @@ QUICRemoteFlowController::update(QUICOffset offset) } // Send BLOCKED(_STREAM) frame - if (offset > this->_limit) { + if (!this->_blocked && offset > this->_limit) { this->_tx->transmit_frame(this->_create_frame()); + this->_blocked = true; } return error; } +// +// QUICLocalFlowController +// void QUICLocalFlowController::forward_limit(QUICOffset offset) { @@ -97,6 +114,9 @@ QUICLocalFlowController::forward_limit(QUICOffset offset) } } +// +// QUIC[Remote|Local][Connection|Stream]FlowController +// std::unique_ptr QUICRemoteConnectionFlowController::_create_frame() { diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index d9b9eff925a..d3181b23b70 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -52,6 +52,10 @@ class QUICRemoteFlowController : public QUICFlowController public: QUICRemoteFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICFlowController(initial_limit, tx) {} QUICError update(QUICOffset offset) override; + void forward_limit(QUICOffset limit) override; + +private: + bool _blocked = false; }; class QUICLocalFlowController : public QUICFlowController diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index bf65848ef84..28117923332 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -430,6 +430,7 @@ class QUICStopSendingFrame : public QUICFrame using QUICFrameDeleterFunc = void (*)(QUICFrame *p); using QUICFramePtr = std::unique_ptr; +using QUICStreamFramePtr = std::unique_ptr; // // Retransmission Frame diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index d79245c721a..ba322ffdba7 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -238,15 +238,14 @@ QUICStreamManager::total_offset_received() const uint64_t QUICStreamManager::total_offset_sent() const { - uint64_t total_offset_sent = 0; + return this->_total_offset_sent; +} - // FIXME Iterating all (open + closed) streams is expensive - for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { - if (s->id() != 0) { - total_offset_sent += s->largest_offset_sent() / 1024; - } - } - return total_offset_sent; +void +QUICStreamManager::add_total_offset_sent(uint32_t sent_byte) +{ + // FIXME: use atomic increment + this->_total_offset_sent += sent_byte; } uint32_t diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 284a93d6a2b..2f664caef46 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -43,6 +43,8 @@ class QUICStreamManager : public QUICFrameHandler void set_max_stream_id(QUICStreamId id); uint64_t total_offset_received() const; uint64_t total_offset_sent() const; + void add_total_offset_sent(uint32_t sent_byte); + uint32_t stream_count() const; void set_default_application(QUICApplication *app); @@ -68,4 +70,5 @@ class QUICStreamManager : public QUICFrameHandler std::shared_ptr _remote_tp = nullptr; QUICStreamId _local_maximum_stream_id = 0; QUICStreamId _remote_maximum_stream_id = 0; + uint64_t _total_offset_sent = 0; }; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index f0cca15b501..c4d327ec68c 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -29,8 +29,6 @@ ats_unique_malloc(size_t size) return ats_unique_buf(reinterpret_cast(ats_malloc(size)), [](void *p) { ats_free(p); }); } -const QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; - bool QUICTypeUtil::hasLongHeader(const uint8_t *buf) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 819408e0d46..f3773c3c045 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -60,8 +60,7 @@ using QUICOffset = uint64_t; constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { 0xff000005, }; - -extern const QUICStreamId STREAM_ID_FOR_HANDSHAKE; +constexpr QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; enum class QUICPacketType : int { VERSION_NEGOTIATION = 1, diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index eb7b77d7177..6b7390cc321 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -159,9 +159,10 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") sleep(2); CHECK(sm.total_offset_sent() == 0); - // total_offset should be a integer in unit of 1024 octets + // total_offset should be a integer in unit of octets std::unique_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); mock_app.send(data, 1024, 1); + sm.add_total_offset_sent(1024); sleep(2); - CHECK(sm.total_offset_sent() == 1); + CHECK(sm.total_offset_sent() == 1024); } From 1418c4f569f87fff9e938fc8554c93286c3b25cb Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 27 Sep 2017 17:00:21 +0900 Subject: [PATCH 0121/1313] Restart sending after received MAX_STREAM_DATA --- iocore/net/quic/QUICStream.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 3b982897cc6..bf4b2a9f82a 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -325,6 +325,9 @@ QUICStream::recv(const std::shared_ptr frame) Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [REMOTE] %" PRIu64 "/%" PRIu64, this->_id, QUICDebugNames::stream_state(this->_state), this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); + + this->reenable(&this->_write_vio); + return QUICError(QUICErrorClass::NONE); } From 230216c7cd4fbbc971271cd04d47098a29a3a7c0 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 28 Sep 2017 10:36:24 +0900 Subject: [PATCH 0122/1313] Call set_parent() to set host_res_style when start HQClientTransaction --- proxy/hq/HQClientTransaction.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 92d8d362c11..4cb6283ba65 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -41,8 +41,8 @@ dump_io_buffer(IOBufferReader *reader) HQClientTransaction::HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) { - this->mutex = new_ProxyMutex(); - this->parent = session; // trans.set_parent(); + this->mutex = new_ProxyMutex(); + this->set_parent(session); this->sm_reader = this->_read_vio_buf.alloc_reader(); static_cast(this->parent)->add_transaction(this); From 294d36f83ca407c84a136e0ab777fff336fd24b3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 28 Sep 2017 11:10:23 +0900 Subject: [PATCH 0123/1313] Fix Makefile.am QUIC related sources were build even if QUIC is not enabled --- iocore/net/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am index faad241ab90..dcebadf8c1f 100644 --- a/iocore/net/Makefile.am +++ b/iocore/net/Makefile.am @@ -107,7 +107,6 @@ libinknet_a_SOURCES = \ P_SSLNetProcessor.h \ P_SSLNetVConnection.h \ P_SSLNextProtocolAccept.h \ - P_QUICNextProtocolAccept.h \ P_SSLNextProtocolSet.h \ P_SSLUtils.h \ P_SSLClientUtils.h \ @@ -133,7 +132,6 @@ libinknet_a_SOURCES = \ SSLNetProcessor.cc \ SSLNetVConnection.cc \ SSLNextProtocolAccept.cc \ - QUICNextProtocolAccept.cc \ SSLNextProtocolSet.cc \ SSLUtils.cc \ SSLClientUtils.cc \ @@ -155,9 +153,11 @@ libinknet_a_SOURCES += \ P_QUICPacketHandler.h \ P_QUICNetProcessor.h \ P_QUICNetVConnection.h \ + P_QUICNextProtocolAccept.h \ QUICPacketHandler.cc \ QUICNetProcessor.cc \ - QUICNetVConnection.cc + QUICNetVConnection.cc \ + QUICNextProtocolAccept.cc endif #test_UNUSED_SOURCES = \ From 9b4f995d10c98e7c58784248f327b02031f91df6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 28 Sep 2017 11:22:01 +0900 Subject: [PATCH 0124/1313] Move QUICSimpleApp under proxy/hq/ --- proxy/hq/Makefile.am | 2 +- {iocore/net/quic => proxy/hq}/QUICSimpleApp.cc | 0 {iocore/net/quic => proxy/hq}/QUICSimpleApp.h | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename {iocore/net/quic => proxy/hq}/QUICSimpleApp.cc (100%) rename {iocore/net/quic => proxy/hq}/QUICSimpleApp.h (100%) diff --git a/proxy/hq/Makefile.am b/proxy/hq/Makefile.am index 955b0929534..dd962ab6d52 100644 --- a/proxy/hq/Makefile.am +++ b/proxy/hq/Makefile.am @@ -39,7 +39,7 @@ libhq_a_SOURCES = \ HQSessionAccept.cc \ HQClientSession.cc \ HQClientTransaction.cc \ - $(abs_top_srcdir)/iocore/net/quic/QUICSimpleApp.cc + QUICSimpleApp.cc tidy-local: $(libhq_a_SOURCES) \ $(CXX_Clang_Tidy) diff --git a/iocore/net/quic/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc similarity index 100% rename from iocore/net/quic/QUICSimpleApp.cc rename to proxy/hq/QUICSimpleApp.cc diff --git a/iocore/net/quic/QUICSimpleApp.h b/proxy/hq/QUICSimpleApp.h similarity index 100% rename from iocore/net/quic/QUICSimpleApp.h rename to proxy/hq/QUICSimpleApp.h From f446bb6802d19a55a6afc2a16d8c575a178c172e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 28 Sep 2017 13:40:11 +0900 Subject: [PATCH 0125/1313] Cleanup: use type alias of unique_ptr of QUICFrame and QUICStreamFrame --- iocore/net/P_QUICNetVConnection.h | 10 ++--- iocore/net/QUICNetVConnection.cc | 16 +++---- iocore/net/quic/Mock.h | 4 +- iocore/net/quic/QUICFlowController.cc | 8 ++-- iocore/net/quic/QUICFlowController.h | 10 ++--- iocore/net/quic/QUICFrame.cc | 42 +++++++++---------- iocore/net/quic/QUICFrame.h | 17 ++++---- iocore/net/quic/QUICFrameTransmitter.h | 2 +- iocore/net/quic/QUICStream.cc | 4 +- .../net/quic/test/test_QUICStreamManager.cc | 4 +- 10 files changed, 57 insertions(+), 60 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index c80ef55bba3..79d88e48274 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -187,7 +187,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection virtual Ptr get_packet_transmitter_mutex() override; // QUICConnection (QUICFrameTransmitter) - virtual void transmit_frame(QUICFramePtr frame) override; + virtual void transmit_frame(QUICFrameUPtr frame) override; // QUICConnection (QUICFrameHandler) std::vector interests() override; @@ -225,17 +225,17 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // `_frame_send_queue` is the queue for any type of frame except STREAM frame. // The flow contorl doesn't blcok frames in this queue. // `_stream_frame_send_queue` is the queue for STREAM frame. - std::queue _frame_send_queue; - std::queue _stream_frame_send_queue; + std::queue _frame_send_queue; + std::queue _stream_frame_send_queue; Event *_packet_write_ready = nullptr; void _transmit_packet(QUICPacketPtr); - void _transmit_frame(QUICFramePtr); + void _transmit_frame(QUICFrameUPtr); bool _is_send_frame_avail_more_than(uint32_t size); void _store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, - QUICFramePtr frame); + QUICFrameUPtr frame); void _packetize_frames(); std::unique_ptr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type = QUICPacketType::UNINITIALIZED); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3795121db40..9143af5a5d5 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -223,7 +223,7 @@ QUICNetVConnection::retransmit_packet(const QUICPacket &packet) uint16_t size = packet.payload_size(); const uint8_t *payload = packet.payload(); - std::unique_ptr frame(nullptr, &QUICFrameDeleter::delete_null_frame); + QUICFrameUPtr frame(nullptr, &QUICFrameDeleter::delete_null_frame); uint16_t cursor = 0; while (cursor < size) { @@ -257,7 +257,7 @@ QUICNetVConnection::push_packet(std::unique_ptrtype()), frame->size()); @@ -277,7 +277,7 @@ QUICNetVConnection::_transmit_frame(QUICFramePtr frame) } void -QUICNetVConnection::transmit_frame(QUICFramePtr frame) +QUICNetVConnection::transmit_frame(QUICFrameUPtr frame) { this->_transmit_frame(std::move(frame)); if (!this->_packet_write_ready) { @@ -715,7 +715,7 @@ QUICNetVConnection::_is_send_frame_avail_more_than(uint32_t size) // previous one, build packet and transmit it. After that, allocate new buffer. void QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, - QUICFramePtr frame) + QUICFrameUPtr frame) { uint32_t max_size = this->maximum_quic_packet_size(); @@ -759,7 +759,7 @@ QUICNetVConnection::_packetize_frames() ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; - QUICFramePtr frame(nullptr, nullptr); + QUICFrameUPtr frame(nullptr, nullptr); bool retransmittable = false; SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); @@ -771,8 +771,8 @@ QUICNetVConnection::_packetize_frames() } while (this->_stream_frame_send_queue.size() > 0) { - const QUICFramePtr &f = this->_stream_frame_send_queue.front(); - uint32_t frame_size = f->size(); + const QUICFrameUPtr &f = this->_stream_frame_send_queue.front(); + uint32_t frame_size = f->size(); if (!this->_is_send_frame_avail_more_than(frame_size)) { break; } @@ -820,7 +820,7 @@ QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPac // this->_local_flow_controller->forward_limit(); this->_ack_frame_creator.update(packet_num, should_send_ack); - std::unique_ptr ack_frame = this->_ack_frame_creator.create_if_needed(); + QUICFrameUPtr ack_frame = this->_ack_frame_creator.create_if_needed(); if (ack_frame != nullptr) { this->transmit_frame(std::move(ack_frame)); } diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 20cb7320a1d..73101dd9f49 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -163,7 +163,7 @@ class MockQUICConnection : public QUICConnection } void - transmit_frame(std::unique_ptr frame) override + transmit_frame(QUICFrameUPtr frame) override { } @@ -289,7 +289,7 @@ class MockQUICFrameTransmitter : public QUICFrameTransmitter { public: void - transmit_frame(std::unique_ptr frame) override + transmit_frame(QUICFrameUPtr frame) override { ++frameCount[static_cast(frame->type())]; } diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 43e223a7a28..e0dcbec96b8 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -117,25 +117,25 @@ QUICLocalFlowController::forward_limit(QUICOffset offset) // // QUIC[Remote|Local][Connection|Stream]FlowController // -std::unique_ptr +QUICFrameUPtr QUICRemoteConnectionFlowController::_create_frame() { return QUICFrameFactory::create_blocked_frame(); } -std::unique_ptr +QUICFrameUPtr QUICLocalConnectionFlowController::_create_frame() { return QUICFrameFactory::create_max_data_frame(this->_limit); } -std::unique_ptr +QUICFrameUPtr QUICRemoteStreamFlowController::_create_frame() { return QUICFrameFactory::create_stream_blocked_frame(this->_stream_id); } -std::unique_ptr +QUICFrameUPtr QUICLocalStreamFlowController::_create_frame() { return QUICFrameFactory::create_max_stream_data_frame(this->_stream_id, this->_limit); diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index d3181b23b70..9badb74ccac 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -39,7 +39,7 @@ class QUICFlowController protected: QUICFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : _limit(initial_limit), _tx(tx) {} - virtual std::unique_ptr _create_frame() = 0; + virtual QUICFrameUPtr _create_frame() = 0; QUICOffset _offset = 0; QUICOffset _limit = 0; @@ -71,7 +71,7 @@ class QUICRemoteConnectionFlowController : public QUICRemoteFlowController QUICRemoteConnectionFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICRemoteFlowController(initial_limit, tx) { } - std::unique_ptr _create_frame() override; + QUICFrameUPtr _create_frame() override; }; class QUICLocalConnectionFlowController : public QUICLocalFlowController @@ -80,7 +80,7 @@ class QUICLocalConnectionFlowController : public QUICLocalFlowController QUICLocalConnectionFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICLocalFlowController(initial_limit, tx) { } - std::unique_ptr _create_frame() override; + QUICFrameUPtr _create_frame() override; }; class QUICRemoteStreamFlowController : public QUICRemoteFlowController @@ -90,7 +90,7 @@ class QUICRemoteStreamFlowController : public QUICRemoteFlowController : QUICRemoteFlowController(initial_limit, tx), _stream_id(stream_id) { } - std::unique_ptr _create_frame() override; + QUICFrameUPtr _create_frame() override; private: QUICStreamId _stream_id = 0; @@ -103,7 +103,7 @@ class QUICLocalStreamFlowController : public QUICLocalFlowController : QUICLocalFlowController(initial_limit, tx), _stream_id(stream_id) { } - std::unique_ptr _create_frame() override; + QUICFrameUPtr _create_frame() override; private: QUICStreamId _stream_id = 0; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index e73fd9d8ea9..48405bd7fb3 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1187,8 +1187,7 @@ QUICStopSendingFrame::stream_id() const // // QUICRetransmissionFrame // -QUICRetransmissionFrame::QUICRetransmissionFrame(std::unique_ptr original_frame, - const QUICPacket &original_packet) +QUICRetransmissionFrame::QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet) : QUICFrame(), _packet_type(original_packet.type()) { size_t dummy; @@ -1221,7 +1220,7 @@ QUICRetransmissionFrame::packet_type() const // QUICFrameFactory // -std::unique_ptr +QUICFrameUPtr QUICFrameFactory::create(const uint8_t *buf, size_t len) { QUICFrame *frame; @@ -1230,62 +1229,62 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) case QUICFrameType::STREAM: frame = quicStreamFrameAllocator.alloc(); new (frame) QUICStreamFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); case QUICFrameType::ACK: frame = quicAckFrameAllocator.alloc(); new (frame) QUICAckFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_ack_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_ack_frame); case QUICFrameType::PADDING: frame = quicPaddingFrameAllocator.alloc(); new (frame) QUICPaddingFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_padding_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_padding_frame); case QUICFrameType::RST_STREAM: frame = quicRstStreamFrameAllocator.alloc(); new (frame) QUICRstStreamFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_rst_stream_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_rst_stream_frame); case QUICFrameType::CONNECTION_CLOSE: frame = quicConnectionCloseFrameAllocator.alloc(); new (frame) QUICConnectionCloseFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_connection_close_frame); case QUICFrameType::MAX_DATA: frame = quicMaxDataFrameAllocator.alloc(); new (frame) QUICMaxDataFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_data_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_max_data_frame); case QUICFrameType::MAX_STREAM_DATA: frame = quicMaxStreamDataFrameAllocator.alloc(); new (frame) QUICMaxStreamDataFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); case QUICFrameType::MAX_STREAM_ID: frame = quicMaxStreamIdFrameAllocator.alloc(); new (frame) QUICMaxStreamIdFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_id_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_max_stream_id_frame); case QUICFrameType::PING: frame = quicPingFrameAllocator.alloc(); new (frame) QUICPingFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_ping_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_ping_frame); case QUICFrameType::BLOCKED: frame = quicBlockedFrameAllocator.alloc(); new (frame) QUICBlockedFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_blocked_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_blocked_frame); case QUICFrameType::STREAM_BLOCKED: frame = quicStreamBlockedFrameAllocator.alloc(); new (frame) QUICStreamBlockedFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); case QUICFrameType::STREAM_ID_NEEDED: frame = quicStreamIdNeededFrameAllocator.alloc(); new (frame) QUICStreamIdNeededFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_id_needed_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_id_needed_frame); case QUICFrameType::NEW_CONNECTION_ID: frame = quicNewConnectionIdFrameAllocator.alloc(); new (frame) QUICNewConnectionIdFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_connection_id_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_new_connection_id_frame); case QUICFrameType::STOP_SENDING: frame = quicStopSendingFrameAllocator.alloc(); new (frame) QUICStopSendingFrame(buf, len); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_stop_sending_frame); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stop_sending_frame); default: // Unknown frame - return std::unique_ptr(nullptr, &QUICFrameDeleter::delete_null_frame); + return QUICFrameUPtr(nullptr, &QUICFrameDeleter::delete_null_frame); } } @@ -1310,12 +1309,12 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) return frame; } -std::unique_ptr +QUICStreamFrameUPtr QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last) { QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); new (frame) QUICStreamFrame(data, data_len, stream_id, offset, last); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_frame); + return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); } std::unique_ptr @@ -1383,8 +1382,7 @@ QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICErrorCod } std::unique_ptr -QUICFrameFactory::create_retransmission_frame(std::unique_ptr original_frame, - const QUICPacket &original_packet) +QUICFrameFactory::create_retransmission_frame(QUICFrameUPtr original_frame, const QUICPacket &original_packet) { QUICRetransmissionFrame *frame = quicRetransmissionFrameAllocator.alloc(); new (frame) QUICRetransmissionFrame(std::move(original_frame), original_packet); diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 28117923332..ba7841c478a 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -429,8 +429,8 @@ class QUICStopSendingFrame : public QUICFrame }; using QUICFrameDeleterFunc = void (*)(QUICFrame *p); -using QUICFramePtr = std::unique_ptr; -using QUICStreamFramePtr = std::unique_ptr; +using QUICFrameUPtr = std::unique_ptr; +using QUICStreamFrameUPtr = std::unique_ptr; // // Retransmission Frame @@ -440,13 +440,13 @@ class QUICRetransmissionFrame : public QUICFrame { public: QUICRetransmissionFrame() : QUICFrame() {} - QUICRetransmissionFrame(std::unique_ptr original_frame, const QUICPacket &original_packet); + QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet); virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; QUICPacketType packet_type() const; private: - std::unique_ptr _frame = QUICFramePtr(nullptr, nullptr); + QUICFrameUPtr _frame = QUICFrameUPtr(nullptr, nullptr); ats_unique_buf _data = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); size_t _size; QUICPacketType _packet_type; @@ -577,7 +577,7 @@ class QUICFrameFactory /* * This is used for creating a QUICFrame object based on received data. */ - static std::unique_ptr create(const uint8_t *buf, size_t len); + static QUICFrameUPtr create(const uint8_t *buf, size_t len); /* * This works almost the same as create() but it reuses created objects for performance. @@ -589,9 +589,8 @@ class QUICFrameFactory * Creates a STREAM frame. * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ - static std::unique_ptr create_stream_frame(const uint8_t *data, size_t data_len, - QUICStreamId stream_id, QUICOffset offset, - bool last = false); + static QUICStreamFrameUPtr create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, + bool last = false); /* * Creates a ACK frame. * You shouldn't call this directly but through QUICAckFrameCreator because QUICAckFrameCreator manages packet numbers that we @@ -644,7 +643,7 @@ class QUICFrameFactory * This retransmission frame will be used only for retransmission and it's not a standard frame type. */ static std::unique_ptr create_retransmission_frame( - std::unique_ptr original_frame, const QUICPacket &original_packet); + QUICFrameUPtr original_frame, const QUICPacket &original_packet); private: // FIXME Actual number of frame types is several but some of the values are not sequential. diff --git a/iocore/net/quic/QUICFrameTransmitter.h b/iocore/net/quic/QUICFrameTransmitter.h index bbf478a4a60..07d782520a3 100644 --- a/iocore/net/quic/QUICFrameTransmitter.h +++ b/iocore/net/quic/QUICFrameTransmitter.h @@ -33,6 +33,6 @@ class QUICFrameTransmitter * * This schedules QUIC_PACKET_WRITE_READY event. */ - virtual void transmit_frame(std::unique_ptr frame) = 0; + virtual void transmit_frame(QUICFrameUPtr frame) = 0; virtual uint32_t maximum_stream_frame_data_size() = 0; }; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index bf4b2a9f82a..1a9cff25324 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -374,8 +374,8 @@ QUICStream::_send() break; } - std::unique_ptr frame = QUICFrameFactory::create_stream_frame( - reinterpret_cast(reader->start()), len, this->_id, this->_send_offset, fin); + QUICStreamFrameUPtr frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, + this->_id, this->_send_offset, fin); this->_send_offset += len; reader->consume(len); diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 6b7390cc321..1a14a3605d9 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -154,13 +154,13 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") CHECK(sm.total_offset_sent() == 0); // Stream 0 shoud be out of flow control - std::unique_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(data, 1024, 0, 0); + QUICFrameUPtr stream_frame_0 = QUICFrameFactory::create_stream_frame(data, 1024, 0, 0); mock_app.send(data, 1024, 0); sleep(2); CHECK(sm.total_offset_sent() == 0); // total_offset should be a integer in unit of octets - std::unique_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); + QUICFrameUPtr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); mock_app.send(data, 1024, 1); sm.add_total_offset_sent(1024); sleep(2); From 9f8001a96c9882b232c2e633ca1d4efb34505e35 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 28 Sep 2017 13:53:35 +0900 Subject: [PATCH 0126/1313] Cleanup: use type alias of unique_ptr of QUICPacket --- iocore/net/P_QUICNetVConnection.h | 18 ++++++------ iocore/net/QUICNetVConnection.cc | 27 ++++++++---------- iocore/net/QUICPacketHandler.cc | 2 +- iocore/net/quic/Mock.h | 6 ++-- iocore/net/quic/QUICLossDetector.cc | 4 +-- iocore/net/quic/QUICLossDetector.h | 6 ++-- iocore/net/quic/QUICPacket.cc | 26 ++++++++--------- iocore/net/quic/QUICPacket.h | 28 +++++++------------ iocore/net/quic/QUICPacketTransmitter.h | 2 +- iocore/net/quic/test/test_QUICLossDetector.cc | 7 ++--- .../net/quic/test/test_QUICPacketFactory.cc | 7 ++--- .../quic/test/test_QUICVersionNegotiator.cc | 2 +- 12 files changed, 61 insertions(+), 74 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 79d88e48274..568e420c47f 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -159,7 +159,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection int state_connection_closing(int event, Event *data); int state_connection_closed(int event, Event *data); void start(SSL_CTX *); - void push_packet(std::unique_ptr packet); + void push_packet(QUICPacketUPtr packet); void free(EThread *t) override; UDPConnection *get_udp_con(); @@ -182,7 +182,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICPacketNumber largest_acked_packet_number() override; // QUICConnection (QUICPacketTransmitter) - virtual void transmit_packet(std::unique_ptr packet) override; + virtual void transmit_packet(QUICPacketUPtr packet) override; virtual void retransmit_packet(const QUICPacket &packet) override; virtual Ptr get_packet_transmitter_mutex() override; @@ -230,22 +230,22 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection Event *_packet_write_ready = nullptr; - void _transmit_packet(QUICPacketPtr); + void _transmit_packet(QUICPacketUPtr); void _transmit_frame(QUICFrameUPtr); bool _is_send_frame_avail_more_than(uint32_t size); void _store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, QUICFrameUPtr frame); void _packetize_frames(); - std::unique_ptr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, - QUICPacketType type = QUICPacketType::UNINITIALIZED); + QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, + QUICPacketType type = QUICPacketType::UNINITIALIZED); QUICError _recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_numm); - QUICError _state_handshake_process_initial_client_packet(std::unique_ptr packet); - QUICError _state_handshake_process_client_cleartext_packet(std::unique_ptr packet); - QUICError _state_handshake_process_zero_rtt_protected_packet(std::unique_ptr packet); - QUICError _state_connection_established_process_packet(std::unique_ptr packet); + QUICError _state_handshake_process_initial_client_packet(QUICPacketUPtr packet); + QUICError _state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet); + QUICError _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); + QUICError _state_connection_established_process_packet(QUICPacketUPtr packet); QUICError _state_common_receive_packet(); QUICError _state_common_send_packet(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 9143af5a5d5..c7e1ffbfce8 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -199,7 +199,7 @@ QUICNetVConnection::stream_manager() } void -QUICNetVConnection::_transmit_packet(QUICPacketPtr packet) +QUICNetVConnection::_transmit_packet(QUICPacketUPtr packet) { DebugQUICCon("Packet Type=%s Size=%hu", QUICDebugNames::packet_type(packet->type()), packet->size()); @@ -209,7 +209,7 @@ QUICNetVConnection::_transmit_packet(QUICPacketPtr packet) } void -QUICNetVConnection::transmit_packet(std::unique_ptr packet) +QUICNetVConnection::transmit_packet(QUICPacketUPtr packet) { this->_transmit_packet(std::move(packet)); if (!this->_packet_write_ready) { @@ -249,7 +249,7 @@ QUICNetVConnection::get_packet_transmitter_mutex() } void -QUICNetVConnection::push_packet(std::unique_ptr packet) +QUICNetVConnection::push_packet(QUICPacketUPtr packet) { DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), packet->size()); @@ -371,8 +371,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) switch (event) { case QUIC_EVENT_PACKET_READ_READY: { - std::unique_ptr p = - std::unique_ptr(this->_packet_recv_queue.dequeue(), &QUICPacketDeleter::delete_packet); + QUICPacketUPtr p = QUICPacketUPtr(this->_packet_recv_queue.dequeue(), &QUICPacketDeleter::delete_packet); net_activity(this, this_ethread()); switch (p->type()) { @@ -578,7 +577,7 @@ QUICNetVConnection::largest_acked_packet_number() } QUICError -QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_ptr packet) +QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPtr packet) { if (packet->size() < MINIMUM_INITIAL_CLIENT_PACKET_SIZE) { DebugQUICCon("Packet size is smaller than the minimum initial client packet size"); @@ -611,7 +610,7 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(std::unique_p } QUICError -QUICNetVConnection::_state_handshake_process_client_cleartext_packet(std::unique_ptr packet) +QUICNetVConnection::_state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet) { QUICError error = QUICError(QUICErrorClass::NONE); @@ -626,7 +625,7 @@ QUICNetVConnection::_state_handshake_process_client_cleartext_packet(std::unique } QUICError -QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(std::unique_ptr packet) +QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet) { // TODO: Decrypt the packet // decrypt(payload, p); @@ -635,7 +634,7 @@ QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(std::uniq } QUICError -QUICNetVConnection::_state_connection_established_process_packet(std::unique_ptr packet) +QUICNetVConnection::_state_connection_established_process_packet(QUICPacketUPtr packet) { // TODO: fix size size_t max_plain_txt_len = 2048; @@ -659,8 +658,7 @@ QUICError QUICNetVConnection::_state_common_receive_packet() { QUICError error; - std::unique_ptr p = - std::unique_ptr(this->_packet_recv_queue.dequeue(), &QUICPacketDeleter::delete_packet); + QUICPacketUPtr p = QUICPacketUPtr(this->_packet_recv_queue.dequeue(), &QUICPacketDeleter::delete_packet); net_activity(this, this_ethread()); switch (p->type()) { @@ -685,8 +683,7 @@ QUICNetVConnection::_state_common_send_packet() SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); while ((packet = this->_packet_send_queue.dequeue()) != nullptr) { this->_packet_handler->send_packet(*packet, this); - this->_loss_detector->on_packet_sent( - std::unique_ptr(packet, &QUICPacketDeleter::delete_packet)); + this->_loss_detector->on_packet_sent(QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet)); } net_activity(this, this_ethread()); @@ -828,10 +825,10 @@ QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPac return error; } -std::unique_ptr +QUICPacketUPtr QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type) { - std::unique_ptr packet(nullptr, &QUICPacketDeleter::delete_null_packet); + QUICPacketUPtr packet(nullptr, &QUICPacketDeleter::delete_null_packet); switch (type) { case QUICPacketType::SERVER_CLEARTEXT: diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 3558221ce98..7dee08ceb7a 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -161,7 +161,7 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) this->action_->continuation->handleEvent(NET_EVENT_ACCEPT, vc); } - std::unique_ptr qPkt = QUICPacketFactory::create(block, vc->largest_received_packet_number()); + QUICPacketUPtr qPkt = QUICPacketFactory::create(block, vc->largest_received_packet_number()); vc->push_packet(std::move(qPkt)); // send to EThread diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 73101dd9f49..e866a461974 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -145,7 +145,7 @@ class MockQUICConnection : public QUICConnection this->_mutex = new_ProxyMutex(); }; void - transmit_packet(std::unique_ptr packet) override + transmit_packet(QUICPacketUPtr packet) override { ++_transmit_count; } @@ -263,7 +263,7 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter public: MockQUICPacketTransmitter() : QUICPacketTransmitter() { this->_mutex = new_ProxyMutex(); }; void - transmit_packet(std::unique_ptr packet) override + transmit_packet(QUICPacketUPtr packet) override { ++_transmit_count; } @@ -313,7 +313,7 @@ class MockQUICLossDetector : public QUICLossDetector } void - on_packet_sent(std::unique_ptr packet) + on_packet_sent(QUICPacketUPtr packet) { } }; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 46ded5acd0c..91a53284b87 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -144,7 +144,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num } void -QUICLossDetector::on_packet_sent(std::unique_ptr packet) +QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) { bool is_handshake = false; QUICPacketType type = packet->type(); @@ -161,7 +161,7 @@ QUICLossDetector::on_packet_sent(std::unique_ptr packet) + QUICPacketUPtr packet) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); this->_largest_sent_packet = packet_number; diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 82bfa9b857c..5b52b552c64 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -47,7 +47,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler std::vector interests() override; virtual QUICError handle_frame(std::shared_ptr) override; - void on_packet_sent(std::unique_ptr packet); + void on_packet_sent(QUICPacketUPtr packet); QUICPacketNumber largest_acked_packet_number(); private: @@ -57,7 +57,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler bool retransmittable; bool handshake; size_t bytes; - std::unique_ptr packet; + QUICPacketUPtr packet; }; bool _time_loss_detection = false; @@ -95,7 +95,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _decrement_packet_count(QUICPacketNumber packet_number); void _on_packet_sent(QUICPacketNumber packet_number, bool is_retransmittable, bool is_handshake, size_t sent_bytes, - std::unique_ptr packet); + QUICPacketUPtr packet); void _on_ack_received(const std::shared_ptr &ack_frame); void _on_packet_acked(QUICPacketNumber acked_packet_number); void _update_rtt(uint32_t latest_rtt); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 97e62c66218..bf0e1f9c5da 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -690,15 +690,15 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si // // QUICPacketFactory // -std::unique_ptr +QUICPacketUPtr QUICPacketFactory::create(IOBufferBlock *block, QUICPacketNumber base_packet_number) { QUICPacket *packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(block, base_packet_number); - return std::unique_ptr(packet, &QUICPacketDeleter::delete_packet); + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } -std::unique_ptr +QUICPacketUPtr QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number) { size_t len = sizeof(QUICVersion) * countof(QUIC_SUPPORTED_VERSIONS); @@ -715,20 +715,20 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se new (packet) QUICPacket(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), packet_sent_by_client->packet_number(), base_packet_number, packet_sent_by_client->version(), std::move(versions), len, false); - return std::unique_ptr(packet, QUICPacketDeleter::delete_packet); + return QUICPacketUPtr(packet, QUICPacketDeleter::delete_packet); } -std::unique_ptr +QUICPacketUPtr QUICPacketFactory::create_server_cleartext_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { QUICPacket *p = quicPacketAllocator.alloc(); new (p) QUICPacket(QUICPacketType::SERVER_CLEARTEXT, connection_id, this->_packet_number_generator.next(), base_packet_number, this->_version, std::move(payload), len, retransmittable); - return std::unique_ptr(p, &QUICPacketDeleter::delete_packet); + return QUICPacketUPtr(p, &QUICPacketDeleter::delete_packet); } -std::unique_ptr +QUICPacketUPtr QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { @@ -736,7 +736,7 @@ QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id QUICPacket *p = quicPacketAllocator.alloc(); new (p) QUICPacket(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, connection_id, this->_packet_number_generator.next(), base_packet_number, std::move(payload), len, retransmittable); - auto packet = std::unique_ptr(p, &QUICPacketDeleter::delete_packet); + auto packet = QUICPacketUPtr(p, &QUICPacketDeleter::delete_packet); // TODO: use pmtu of UnixNetVConnection size_t max_cipher_txt_len = 2048; @@ -756,26 +756,26 @@ QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id return packet; } else { Debug("quic_packet_factory", "CRYPTOGRAPHIC Error"); - return std::unique_ptr(nullptr, &QUICPacketDeleter::delete_null_packet); + return QUICPacketUPtr(nullptr, &QUICPacketDeleter::delete_null_packet); } } -std::unique_ptr +QUICPacketUPtr QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len) { QUICPacket *packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(QUICPacketType::CLIENT_INITIAL, connection_id, this->_packet_number_generator.next(), base_packet_number, version, std::move(payload), len, true); - return std::unique_ptr(packet, &QUICPacketDeleter::delete_packet); + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } -std::unique_ptr +QUICPacketUPtr QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token) { QUICPacket *packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(QUICPacketType::STATELESS_RESET, connection_id, stateless_reset_token); - return std::unique_ptr(packet, &QUICPacketDeleter::delete_packet); + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } void diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 9f577e942d3..94067ae8c89 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -181,7 +181,7 @@ class QUICPacketNumberGenerator }; using QUICPacketDeleterFunc = void (*)(QUICPacket *p); -using QUICPacketPtr = std::unique_ptr; +using QUICPacketUPtr = std::unique_ptr; extern ClassAllocator quicPacketAllocator; extern ClassAllocator quicPacketLongHeaderAllocator; @@ -206,23 +206,15 @@ class QUICPacketDeleter class QUICPacketFactory { public: - static std::unique_ptr create(IOBufferBlock *block, QUICPacketNumber base_packet_number); - std::unique_ptr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, - QUICPacketNumber base_packet_number); - std::unique_ptr create_server_cleartext_packet(QUICConnectionId connection_id, - QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, - bool retransmittable); - std::unique_ptr create_server_protected_packet(QUICConnectionId connection_id, - QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, - bool retransmittable); - std::unique_ptr create_client_initial_packet(QUICConnectionId connection_id, - QUICPacketNumber base_packet_number, - QUICVersion version, ats_unique_buf payload, - size_t len); - static std::unique_ptr create_stateless_reset_packet(QUICConnectionId connection_id, - QUICStatelessToken stateless_reset_token); + static QUICPacketUPtr create(IOBufferBlock *block, QUICPacketNumber base_packet_number); + QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number); + QUICPacketUPtr create_server_cleartext_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, + ats_unique_buf payload, size_t len, bool retransmittable); + QUICPacketUPtr create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, + ats_unique_buf payload, size_t len, bool retransmittable); + QUICPacketUPtr create_client_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, + QUICVersion version, ats_unique_buf payload, size_t len); + static QUICPacketUPtr create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token); void set_version(QUICVersion negotiated_version); void set_crypto_module(QUICCrypto *crypto); diff --git a/iocore/net/quic/QUICPacketTransmitter.h b/iocore/net/quic/QUICPacketTransmitter.h index 6aaef383320..323c98d0749 100644 --- a/iocore/net/quic/QUICPacketTransmitter.h +++ b/iocore/net/quic/QUICPacketTransmitter.h @@ -33,7 +33,7 @@ class QUICPacketTransmitter * * This sends QUIC_PACKET_WRITE_READY event. */ - virtual void transmit_packet(std::unique_ptr packet) = 0; + virtual void transmit_packet(QUICPacketUPtr packet) = 0; /* * Enqueue a packet for retransmission diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index e77670d6112..543249bc67f 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -40,10 +40,9 @@ TEST_CASE("QUICLossDetector_Loss_in_Handshake", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - std::unique_ptr packet = std::unique_ptr( - new QUICPacket(QUICPacketType::SERVER_CLEARTEXT, 0xffddbb9977553311ULL, 0x00000001, 0, 0x00112233, std::move(payload), - sizeof(raw), true), - [](QUICPacket *p) { delete p; }); + QUICPacketUPtr packet = QUICPacketUPtr(new QUICPacket(QUICPacketType::SERVER_CLEARTEXT, 0xffddbb9977553311ULL, 0x00000001, 0, + 0x00112233, std::move(payload), sizeof(raw), true), + [](QUICPacket *p) { delete p; }); detector.on_packet_sent(std::move(packet)); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); CHECK(tx->_retransmit_count > 0); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 02d2b64ea63..fbf6a87ca0e 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -44,7 +44,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") QUICPacket client_initial_packet(block, 0); - std::unique_ptr packet = factory.create_version_negotiation_packet(&client_initial_packet, 0); + QUICPacketUPtr packet = factory.create_version_negotiation_packet(&client_initial_packet, 0); CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); CHECK(packet->connection_id() == client_initial_packet.connection_id()); CHECK(packet->packet_number() == client_initial_packet.packet_number()); @@ -60,8 +60,7 @@ TEST_CASE("QUICPacketFactory_Create_ServerCleartextPacket", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - std::unique_ptr packet = - factory.create_server_cleartext_packet(0x01020304, 0, std::move(payload), sizeof(raw), true); + QUICPacketUPtr packet = factory.create_server_cleartext_packet(0x01020304, 0, std::move(payload), sizeof(raw), true); CHECK(packet->type() == QUICPacketType::SERVER_CLEARTEXT); CHECK(packet->connection_id() == 0x01020304); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); @@ -84,7 +83,7 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") uint8_t output[1024]; size_t out_len = 0; - std::unique_ptr packet = factory.create_stateless_reset_packet(0x01020304, token); + QUICPacketUPtr packet = factory.create_stateless_reset_packet(0x01020304, token); CHECK(packet->type() == QUICPacketType::STATELESS_RESET); CHECK(packet->connection_id() == 0x01020304); CHECK(packet->packet_number() == token.get_u8()[0]); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 1802c63ac05..e2971d57149 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -35,7 +35,7 @@ TEST_CASE("QUICVersionNegotiator_Normal", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); // Negotiate version - std::unique_ptr initial_packet = + QUICPacketUPtr initial_packet = packet_factory.create_client_initial_packet({}, 0, QUIC_SUPPORTED_VERSIONS[0], ats_unique_malloc(0), 0); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); From 8b47c2e9e95e0ac1b03a58606bf893c70bd77d89 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 28 Sep 2017 13:58:09 +0900 Subject: [PATCH 0127/1313] Cleanup: unify debug tag of QUICLossDetector --- iocore/net/quic/QUICLossDetector.cc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 91a53284b87..1662fa7cae1 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -25,6 +25,8 @@ #include "QUICEvents.h" #include "ts/ink_assert.h" +static constexpr char tag[] = "quic_loss_detector"; + QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter) : _transmitter(transmitter) { this->mutex = new_ProxyMutex(); @@ -200,8 +202,7 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac } this->_detect_lost_packets(ack_frame->largest_acknowledged()); - Debug("quic_loss_detector", "Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, - this->_retransmittable_outstanding); + Debug(tag, "Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, this->_retransmittable_outstanding); this->_set_loss_detection_alarm(); } @@ -209,7 +210,7 @@ void QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - Debug("quic_loss_detector", "Packet number %" PRIu64 " has been acked", acked_packet_number); + Debug(tag, "Packet number %" PRIu64 " has been acked", acked_packet_number); // If a packet sent prior to RTO was acked, then the RTO // was spurious. Otherwise, inform congestion control. if (this->_rto_count > 0 && acked_packet_number > this->_largest_sent_before_rto) { @@ -259,8 +260,7 @@ QUICLossDetector::_on_loss_detection_alarm() // eventProcessor.schedule_imm(this->_handler, ET_CALL, QUIC_EVENT_RETRANSMIT_TWO_PACKET); this->_rto_count++; } - Debug("quic_loss_detector", "Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, - this->_retransmittable_outstanding); + Debug(tag, "Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, this->_retransmittable_outstanding); this->_set_loss_detection_alarm(); } @@ -284,7 +284,7 @@ QUICLossDetector::_set_loss_detection_alarm() if (!this->_retransmittable_outstanding && this->_loss_detection_alarm) { this->_loss_detection_alarm->cancel(); this->_loss_detection_alarm = nullptr; - Debug("quic_loss_detection", "Loss detection alarm has been unset"); + Debug(tag, "Loss detection alarm has been unset"); return; } if (this->_handshake_outstanding) { @@ -296,11 +296,11 @@ QUICLossDetector::_set_loss_detection_alarm() } alarm_duration = max(alarm_duration, this->_MIN_TLP_TIMEOUT); alarm_duration = alarm_duration * (1 << this->_handshake_count); - Debug("quic_loss_detection", "Handshake retransmission alarm will be set"); + Debug(tag, "Handshake retransmission alarm will be set"); } else if (this->_loss_time != 0) { // Early retransmit timer or time loss detection. alarm_duration = this->_loss_time - Thread::get_hrtime(); - Debug("quic_loss_detection", "Early retransmit timer or time loss detection will be set"); + Debug(tag, "Early retransmit timer or time loss detection will be set"); } else if (this->_tlp_count < this->_MAX_TLPS) { // Tail Loss Probe if (this->_retransmittable_outstanding) { @@ -309,20 +309,20 @@ QUICLossDetector::_set_loss_detection_alarm() alarm_duration = this->_MIN_TLP_TIMEOUT; } alarm_duration = max(alarm_duration, 2 * this->_smoothed_rtt); - Debug("quic_loss_detection", "TLP alarm will be set"); + Debug(tag, "TLP alarm will be set"); } else { // RTO alarm alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar; alarm_duration = max(alarm_duration, this->_MIN_RTO_TIMEOUT); alarm_duration = alarm_duration * (1 << this->_rto_count); - Debug("quic_loss_detection", "RTO alarm will be set"); + Debug(tag, "RTO alarm will be set"); } if (this->_loss_detection_alarm) { this->_loss_detection_alarm->cancel(); } this->_loss_detection_alarm = eventProcessor.schedule_in(this, alarm_duration); - Debug("quic_loss_detection", "Loss detection alarm has been set to %" PRId64, alarm_duration); + Debug(tag, "Loss detection alarm has been set to %" PRId64, alarm_duration); } std::set From 57fe4b2a4981b7ec3126e2094f854c4e589b0c4a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 28 Sep 2017 17:24:35 +0900 Subject: [PATCH 0128/1313] Send CLOSE_CONNECTION or RST_STREAM when error occurs --- iocore/net/P_QUICNetVConnection.h | 19 +++-- iocore/net/QUICNetVConnection.cc | 95 ++++++++++++--------- iocore/net/quic/QUICCongestionController.cc | 4 +- iocore/net/quic/QUICCongestionController.h | 2 +- iocore/net/quic/QUICConnection.h | 2 +- iocore/net/quic/QUICFlowController.cc | 10 +-- iocore/net/quic/QUICFlowController.h | 4 +- iocore/net/quic/QUICFrame.cc | 13 +++ iocore/net/quic/QUICFrame.h | 3 + iocore/net/quic/QUICFrameDispatcher.cc | 10 +-- iocore/net/quic/QUICFrameDispatcher.h | 2 +- iocore/net/quic/QUICFrameHandler.h | 4 +- iocore/net/quic/QUICHandshake.cc | 53 +++++++----- iocore/net/quic/QUICHandshake.h | 8 +- iocore/net/quic/QUICLossDetector.cc | 4 +- iocore/net/quic/QUICLossDetector.h | 2 +- iocore/net/quic/QUICStream.cc | 58 ++++++++----- iocore/net/quic/QUICStream.h | 11 +-- iocore/net/quic/QUICStreamManager.cc | 28 +++--- iocore/net/quic/QUICStreamManager.h | 12 +-- iocore/net/quic/QUICTypes.h | 45 ++++++++-- 21 files changed, 237 insertions(+), 152 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 568e420c47f..7db4cd82f21 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -177,7 +177,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection uint32_t pmtu() override; NetVConnectionContext_t direction() override; SSLNextProtocolSet *next_protocol_set() override; - void close(QUICError error) override; + void close(QUICConnectionErrorUPtr error) override; QUICPacketNumber largest_received_packet_number() override; QUICPacketNumber largest_acked_packet_number() override; @@ -191,7 +191,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // QUICConnection (QUICFrameHandler) std::vector interests() override; - QUICError handle_frame(std::shared_ptr frame) override; + QUICErrorUPtr handle_frame(std::shared_ptr frame) override; private: std::random_device _rnd; @@ -240,20 +240,21 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type = QUICPacketType::UNINITIALIZED); - QUICError _recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_numm); + QUICErrorUPtr _recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_numm); - QUICError _state_handshake_process_initial_client_packet(QUICPacketUPtr packet); - QUICError _state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet); - QUICError _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); - QUICError _state_connection_established_process_packet(QUICPacketUPtr packet); - QUICError _state_common_receive_packet(); - QUICError _state_common_send_packet(); + QUICErrorUPtr _state_handshake_process_initial_client_packet(QUICPacketUPtr packet); + QUICErrorUPtr _state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet); + QUICErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); + QUICErrorUPtr _state_connection_established_process_packet(QUICPacketUPtr packet); + QUICErrorUPtr _state_common_receive_packet(); + QUICErrorUPtr _state_common_send_packet(); Ptr _packet_transmitter_mutex; Ptr _frame_transmitter_mutex; void _init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); + void _handle_error(QUICErrorUPtr error); QUICStatelessToken _token; }; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index c7e1ffbfce8..c0b284853c9 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -287,7 +287,7 @@ QUICNetVConnection::transmit_frame(QUICFrameUPtr frame) } void -QUICNetVConnection::close(QUICError error) +QUICNetVConnection::close(QUICConnectionErrorUPtr error) { if (this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closed) || this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closing)) { @@ -295,7 +295,7 @@ QUICNetVConnection::close(QUICError error) } else { DebugQUICCon("Enter state_connection_closing"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); - this->transmit_frame(QUICFrameFactory::create_connection_close_frame(error.code, 0, "")); + this->transmit_frame(QUICFrameFactory::create_connection_close_frame(std::move(error))); } } @@ -305,10 +305,10 @@ QUICNetVConnection::interests() return {QUICFrameType::CONNECTION_CLOSE, QUICFrameType::BLOCKED, QUICFrameType::MAX_DATA}; } -QUICError +QUICErrorUPtr QUICNetVConnection::handle_frame(std::shared_ptr frame) { - QUICError error = QUICError(QUICErrorClass::NONE); + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (frame->type()) { case QUICFrameType::MAX_DATA: @@ -367,7 +367,7 @@ QUICNetVConnection::state_pre_handshake(int event, Event *data) int QUICNetVConnection::state_handshake(int event, Event *data) { - QUICError error; + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: { @@ -388,7 +388,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) break; } default: - error = QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); + error = QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR)); break; } @@ -414,10 +414,8 @@ QUICNetVConnection::state_handshake(int event, Event *data) DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); } - if (error.cls != QUICErrorClass::NONE) { - // TODO: Send error if needed - DebugQUICCon("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error.cls), static_cast(error.cls), - QUICDebugNames::error_code(error.code), static_cast(error.code)); + if (error->cls != QUICErrorClass::NONE) { + this->_handle_error(std::move(error)); } if (this->_handshake_handler && this->_handshake_handler->is_completed()) { @@ -440,7 +438,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) int QUICNetVConnection::state_connection_established(int event, Event *data) { - QUICError error; + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: { error = this->_state_common_receive_packet(); @@ -465,9 +463,9 @@ QUICNetVConnection::state_connection_established(int event, Event *data) DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); } - if (error.cls != QUICErrorClass::NONE) { - // TODO: Send error if needed - DebugQUICCon("QUICError: cls=%u, code=0x%x", static_cast(error.cls), static_cast(error.code)); + if (error->cls != QUICErrorClass::NONE) { + DebugQUICCon("QUICError: cls=%u, code=0x%x", static_cast(error->cls), static_cast(error->code)); + this->_handle_error(std::move(error)); } return EVENT_CONT; @@ -476,7 +474,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) int QUICNetVConnection::state_connection_closing(int event, Event *data) { - QUICError error; + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: { error = this->_state_common_receive_packet(); @@ -576,64 +574,65 @@ QUICNetVConnection::largest_acked_packet_number() return this->_loss_detector->largest_acked_packet_number(); } -QUICError +QUICErrorUPtr QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPtr packet) { if (packet->size() < MINIMUM_INITIAL_CLIENT_PACKET_SIZE) { DebugQUICCon("Packet size is smaller than the minimum initial client packet size"); - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); + // Ignore the packet + return QUICErrorUPtr(new QUICNoError()); } // Start handshake - QUICError error = this->_handshake_handler->start(packet.get(), &this->_packet_factory); + QUICErrorUPtr error = this->_handshake_handler->start(packet.get(), &this->_packet_factory); if (this->_handshake_handler->is_version_negotiated()) { // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing) if (packet->has_valid_fnv1a_hash()) { bool should_send_ack; error = this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size(), should_send_ack); - if (error.cls != QUICErrorClass::NONE) { + if (error->cls != QUICErrorClass::NONE) { return error; } error = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); - if (error.cls != QUICErrorClass::NONE) { + if (error->cls != QUICErrorClass::NONE) { return error; } } else { DebugQUICCon("Invalid FNV-1a hash value"); - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::CRYPTOGRAPHIC_ERROR); + // Discard the packet } } return error; } -QUICError +QUICErrorUPtr QUICNetVConnection::_state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet) { - QUICError error = QUICError(QUICErrorClass::NONE); + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); // The payload of this packet contains STREAM frames and could contain PADDING and ACK frames if (packet->has_valid_fnv1a_hash()) { error = this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); } else { DebugQUICCon("Invalid FNV-1a hash value"); - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::CRYPTOGRAPHIC_ERROR); + // Discard the packet } return error; } -QUICError +QUICErrorUPtr QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet) { // TODO: Decrypt the packet // decrypt(payload, p); // TODO: Not sure what we have to do - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } -QUICError +QUICErrorUPtr QUICNetVConnection::_state_connection_established_process_packet(QUICPacketUPtr packet) { // TODO: fix size @@ -650,15 +649,15 @@ QUICNetVConnection::_state_connection_established_process_packet(QUICPacketUPtr } else { DebugQUICCon("CRYPTOGRAPHIC Error"); - return QUICError(QUICErrorClass::CRYPTOGRAPHIC); + return QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::CRYPTOGRAPHIC_ERROR)); } } -QUICError +QUICErrorUPtr QUICNetVConnection::_state_common_receive_packet() { - QUICError error; - QUICPacketUPtr p = QUICPacketUPtr(this->_packet_recv_queue.dequeue(), &QUICPacketDeleter::delete_packet); + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICPacketUPtr p = QUICPacketUPtr(this->_packet_recv_queue.dequeue(), &QUICPacketDeleter::delete_packet); net_activity(this, this_ethread()); switch (p->type()) { @@ -667,13 +666,13 @@ QUICNetVConnection::_state_common_receive_packet() error = this->_state_connection_established_process_packet(std::move(p)); break; default: - error = QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); + error = QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR)); break; } return error; } -QUICError +QUICErrorUPtr QUICNetVConnection::_state_common_send_packet() { this->_packetize_frames(); @@ -688,19 +687,19 @@ QUICNetVConnection::_state_common_send_packet() net_activity(this, this_ethread()); - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } // Schedule sending BLOCKED frame when offset exceed the limit bool QUICNetVConnection::_is_send_frame_avail_more_than(uint32_t size) { - QUICError error = this->_remote_flow_controller->update((this->_stream_manager->total_offset_sent() + size) / 1024); + QUICErrorUPtr error = this->_remote_flow_controller->update((this->_stream_manager->total_offset_sent() + size) / 1024); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); - if (error.cls != QUICErrorClass::NONE) { + if (error->cls != QUICErrorClass::NONE) { // Flow Contoroller blocked sending STREAM frame return false; } @@ -792,7 +791,7 @@ QUICNetVConnection::_packetize_frames() } } -QUICError +QUICErrorUPtr QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_num) { if (packet_num > this->_largest_received_packet_number) { @@ -801,17 +800,17 @@ QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPac bool should_send_ack; - QUICError error; + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); error = this->_frame_dispatcher->receive_frames(payload, size, should_send_ack); - if (error.cls != QUICErrorClass::NONE) { + if (error->cls != QUICErrorClass::NONE) { return error; } error = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); - if (error.cls != QUICErrorClass::NONE) { + if (error->cls != QUICErrorClass::NONE) { return error; } // this->_local_flow_controller->forward_limit(); @@ -872,3 +871,19 @@ QUICNetVConnection::_init_flow_control_params(const std::shared_ptr(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); } + +void +QUICNetVConnection::_handle_error(QUICErrorUPtr error) +{ + DebugQUICCon("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), static_cast(error->cls), + QUICDebugNames::error_code(error->code), static_cast(error->code)); + if (dynamic_cast(error.get()) != nullptr) { + // Stream Error + QUICStreamError *serror = static_cast(error.release()); + serror->stream->reset(QUICStreamErrorUPtr(serror)); + } else { + // Connection Error + QUICConnectionError *cerror = static_cast(error.release()); + this->close(QUICConnectionErrorUPtr(cerror)); + } +} diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 19939fe5bdf..4a0ea79a815 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -31,10 +31,10 @@ QUICCongestionController::interests() return {QUICFrameType::ACK, QUICFrameType::STREAM}; } -QUICError +QUICErrorUPtr QUICCongestionController::handle_frame(std::shared_ptr frame) { - QUICError error = QUICError(QUICErrorClass::NONE); + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (frame->type()) { case QUICFrameType::STREAM: diff --git a/iocore/net/quic/QUICCongestionController.h b/iocore/net/quic/QUICCongestionController.h index cf8191bce3b..d44b9bf2988 100644 --- a/iocore/net/quic/QUICCongestionController.h +++ b/iocore/net/quic/QUICCongestionController.h @@ -31,7 +31,7 @@ class QUICCongestionController : public QUICFrameHandler { public: virtual std::vector interests() override; - virtual QUICError handle_frame(std::shared_ptr) override; + virtual QUICErrorUPtr handle_frame(std::shared_ptr) override; private: }; diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 690181907b3..e0bb194a207 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -55,7 +55,7 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter virtual uint32_t pmtu() = 0; virtual NetVConnectionContext_t direction() = 0; virtual SSLNextProtocolSet *next_protocol_set() = 0; - virtual void close(QUICError error) = 0; + virtual void close(QUICConnectionErrorUPtr error) = 0; virtual QUICPacketNumber largest_received_packet_number() = 0; virtual QUICPacketNumber largest_acked_packet_number() = 0; }; diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index e0dcbec96b8..18deeeaffbb 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -40,18 +40,18 @@ QUICFlowController::current_limit() return this->_limit; } -QUICError +QUICErrorUPtr QUICFlowController::update(QUICOffset offset) { if (this->_offset <= offset) { // Assume flow control is not initialized if the limit was 0 if (this->_limit != 0 && offset > this->_limit) { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FLOW_CONTROL_ERROR); + return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FLOW_CONTROL_ERROR)); } this->_offset = offset; } - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } void @@ -81,10 +81,10 @@ QUICRemoteFlowController::forward_limit(QUICOffset offset) this->_blocked = false; } -QUICError +QUICErrorUPtr QUICRemoteFlowController::update(QUICOffset offset) { - QUICError error = QUICFlowController::update(offset); + QUICErrorUPtr error = QUICFlowController::update(offset); // Assume flow control is not initialized if the limit was 0 if (this->_limit == 0) { diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index 9badb74ccac..d195728ec46 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -33,7 +33,7 @@ class QUICFlowController public: QUICOffset current_offset(); QUICOffset current_limit(); - virtual QUICError update(QUICOffset offset); + virtual QUICErrorUPtr update(QUICOffset offset); virtual void forward_limit(QUICOffset limit); void set_threshold(uint64_t threshold); @@ -51,7 +51,7 @@ class QUICRemoteFlowController : public QUICFlowController { public: QUICRemoteFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICFlowController(initial_limit, tx) {} - QUICError update(QUICOffset offset) override; + QUICErrorUPtr update(QUICOffset offset) override; void forward_limit(QUICOffset limit) override; private: diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 48405bd7fb3..0db9d8c636e 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -22,6 +22,7 @@ */ #include "QUICFrame.h" +#include "QUICStream.h" ClassAllocator quicStreamFrameAllocator("quicStreamFrameAllocator"); ClassAllocator quicAckFrameAllocator("quicAckFrameAllocator"); @@ -1333,6 +1334,12 @@ QUICFrameFactory::create_connection_close_frame(QUICErrorCode error_code, uint16 return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); } +std::unique_ptr +QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error) +{ + return QUICFrameFactory::create_connection_close_frame(error->code, strlen(error->msg), error->msg); +} + std::unique_ptr QUICFrameFactory::create_max_data_frame(uint64_t maximum_data) { @@ -1373,6 +1380,12 @@ QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICErrorCode return std::unique_ptr(frame, &QUICFrameDeleter::delete_rst_stream_frame); } +std::unique_ptr +QUICFrameFactory::create_rst_stream_frame(QUICStreamErrorUPtr error) +{ + return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->code, error->stream->final_offset()); +} + std::unique_ptr QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICErrorCode error_code) { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index ba7841c478a..15c098c4a16 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -603,6 +603,8 @@ class QUICFrameFactory */ static std::unique_ptr create_connection_close_frame( QUICErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase); + static std::unique_ptr create_connection_close_frame( + QUICConnectionErrorUPtr error); /* * Creates a MAX_DATA frame. @@ -631,6 +633,7 @@ class QUICFrameFactory static std::unique_ptr create_rst_stream_frame(QUICStreamId stream_id, QUICErrorCode error_code, QUICOffset final_offset); + static std::unique_ptr create_rst_stream_frame(QUICStreamErrorUPtr error); /* * Creates a STOP_SENDING frame. diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 5b87cd11f2c..c23fff10328 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -43,13 +43,13 @@ QUICFrameDispatcher::add_handler(QUICFrameHandler *handler) } } -QUICError +QUICErrorUPtr QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size, bool &should_send_ack) { std::shared_ptr frame(nullptr); - uint16_t cursor = 0; - should_send_ack = false; - QUICError error = QUICError(QUICErrorClass::NONE); + uint16_t cursor = 0; + should_send_ack = false; + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); while (cursor < size) { frame = this->_frame_factory.fast_create(payload + cursor, size - cursor); @@ -72,7 +72,7 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size, bool for (auto h : handlers) { error = h->handle_frame(frame); // TODO: is there any case to continue this loop even if error? - if (error.cls != QUICErrorClass::NONE) { + if (error->cls != QUICErrorClass::NONE) { return error; } } diff --git a/iocore/net/quic/QUICFrameDispatcher.h b/iocore/net/quic/QUICFrameDispatcher.h index 0c61f398800..397f0d38c7e 100644 --- a/iocore/net/quic/QUICFrameDispatcher.h +++ b/iocore/net/quic/QUICFrameDispatcher.h @@ -33,7 +33,7 @@ class QUICFrameDispatcher /* * Returns true if ACK frame should be sent */ - QUICError receive_frames(const uint8_t *payload, uint16_t size, bool &should_send_ack); + QUICErrorUPtr receive_frames(const uint8_t *payload, uint16_t size, bool &should_send_ack); void add_handler(QUICFrameHandler *handler); diff --git a/iocore/net/quic/QUICFrameHandler.h b/iocore/net/quic/QUICFrameHandler.h index 0f2a27ff6b0..e857513e435 100644 --- a/iocore/net/quic/QUICFrameHandler.h +++ b/iocore/net/quic/QUICFrameHandler.h @@ -30,6 +30,6 @@ class QUICFrameHandler { public: virtual ~QUICFrameHandler(){}; - virtual std::vector interests() = 0; - virtual QUICError handle_frame(std::shared_ptr frame) = 0; + virtual std::vector interests() = 0; + virtual QUICErrorUPtr handle_frame(std::shared_ptr frame) = 0; }; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index daa47aaf270..7c34690d5da 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -72,13 +72,13 @@ QUICHandshake::~QUICHandshake() SSL_free(this->_ssl); } -QUICError +QUICErrorUPtr QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory) { // Negotiate version if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) { if (initial_packet->type() != QUICPacketType::CLIENT_INITIAL) { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); + return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION)); } if (initial_packet->version()) { if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { @@ -90,10 +90,10 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet Debug(tag, "Version negotiation failed: %x", initial_packet->version()); } } else { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); + return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION)); } } - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } bool @@ -136,7 +136,8 @@ QUICHandshake::set_transport_parameters(std::shared_ptr if (tp_in_ch) { // Version revalidation if (this->_version_negotiator->revalidate(tp_in_ch) != QUICVersionNegotiationStatus::REVALIDATED) { - this->_client_qc->close({QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::VERSION_NEGOTIATION_ERROR}); + this->_client_qc->close( + QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::VERSION_NEGOTIATION_ERROR))); Debug(tag, "Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); return; @@ -168,7 +169,7 @@ QUICHandshake::remote_transport_parameters() int QUICHandshake::state_read_client_hello(int event, Event *data) { - QUICError error; + QUICErrorUPtr error; switch (event) { case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { @@ -180,8 +181,13 @@ QUICHandshake::state_read_client_hello(int event, Event *data) break; } - if (error.cls != QUICErrorClass::NONE) { - this->_client_qc->close(error); + if (error->cls != QUICErrorClass::NONE) { + if (dynamic_cast(error.get()) != nullptr) { + this->_client_qc->close(QUICConnectionErrorUPtr(static_cast(error.release()))); + } else { + this->_client_qc->close( + QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION))); + } Debug(tag, "Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); } @@ -192,7 +198,7 @@ QUICHandshake::state_read_client_hello(int event, Event *data) int QUICHandshake::state_read_client_finished(int event, Event *data) { - QUICError error; + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { @@ -204,8 +210,13 @@ QUICHandshake::state_read_client_finished(int event, Event *data) break; } - if (error.cls != QUICErrorClass::NONE) { - this->_client_qc->close(error); + if (error->cls != QUICErrorClass::NONE) { + if (dynamic_cast(error.get()) != nullptr) { + this->_client_qc->close(QUICConnectionErrorUPtr(static_cast(error.release()))); + } else { + this->_client_qc->close( + QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION))); + } Debug(tag, "Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); } @@ -267,7 +278,7 @@ QUICHandshake::_load_local_transport_parameters() this->_local_transport_parameters = std::unique_ptr(tp); } -QUICError +QUICErrorUPtr QUICHandshake::_process_client_hello() { QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); @@ -279,7 +290,7 @@ QUICHandshake::_process_client_hello() if (msg_len <= 0) { Debug(tag, "No message"); - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } // ----- DEBUG -----> @@ -305,13 +316,13 @@ QUICHandshake::_process_client_hello() stream_io->write_reenable(); stream_io->read_reenable(); - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } else { - return QUICError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::TLS_HANDSHAKE_FAILED); + return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::TLS_HANDSHAKE_FAILED)); } } -QUICError +QUICErrorUPtr QUICHandshake::_process_client_finished() { QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); @@ -323,7 +334,7 @@ QUICHandshake::_process_client_finished() if (msg_len <= 0) { Debug(tag, "No message"); - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } // ----- DEBUG -----> @@ -353,13 +364,13 @@ QUICHandshake::_process_client_finished() stream_io->write_reenable(); stream_io->read_reenable(); - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } else { - return QUICError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::TLS_HANDSHAKE_FAILED); + return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::TLS_HANDSHAKE_FAILED)); } } -QUICError +QUICErrorUPtr QUICHandshake::_process_handshake_complete() { QUICCrypto *crypto = this->_crypto; @@ -371,5 +382,5 @@ QUICHandshake::_process_handshake_complete() Debug(tag, "Failed to export Keying Materials"); } - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 5d0060a40e1..d74344f196a 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -53,7 +53,7 @@ class QUICHandshake : public QUICApplication QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessToken token); ~QUICHandshake(); - QUICError start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); + QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); // States int state_read_client_hello(int event, Event *data); @@ -84,9 +84,9 @@ class QUICHandshake : public QUICApplication void _load_local_transport_parameters(); - QUICError _process_client_hello(); - QUICError _process_client_finished(); - QUICError _process_handshake_complete(); + QUICErrorUPtr _process_client_hello(); + QUICErrorUPtr _process_client_finished(); + QUICErrorUPtr _process_handshake_complete(); QUICStatelessToken _token; }; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 1662fa7cae1..33d923dff9d 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -81,10 +81,10 @@ QUICLossDetector::interests() return {QUICFrameType::ACK}; } -QUICError +QUICErrorUPtr QUICLossDetector::handle_frame(std::shared_ptr frame) { - QUICError error = QUICError(QUICErrorClass::NONE); + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (frame->type()) { case QUICFrameType::ACK: diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 5b52b552c64..73136949c98 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -46,7 +46,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler int event_handler(int event, Event *edata); std::vector interests() override; - virtual QUICError handle_frame(std::shared_ptr) override; + virtual QUICErrorUPtr handle_frame(std::shared_ptr) override; void on_packet_sent(QUICPacketUPtr packet); QUICPacketNumber largest_acked_packet_number(); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 1a9cff25324..dd41ff357a1 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -70,11 +70,18 @@ QUICStream::id() return this->_id; } +QUICOffset +QUICStream::final_offset() +{ + // TODO Return final offset + return 0; +} + int QUICStream::main_event_handler(int event, void *data) { DebugQUICStream("%s", QUICDebugNames::vc_event(event)); - QUICError error; + QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); switch (event) { case VC_EVENT_READ_READY: @@ -104,10 +111,17 @@ QUICStream::main_event_handler(int event, void *data) ink_assert(false); } - if (error.cls != QUICErrorClass::NONE) { - // TODO Send error if needed - DebugQUICStream("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error.cls), static_cast(error.cls), - QUICDebugNames::error_code(error.code), static_cast(error.code)); + if (error->cls != QUICErrorClass::NONE) { + DebugQUICStream("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), static_cast(error->cls), + QUICDebugNames::error_code(error->code), static_cast(error->code)); + if (dynamic_cast(error.get()) != nullptr) { + // Stream Error + QUICStreamErrorUPtr serror = QUICStreamErrorUPtr(static_cast(error.get())); + this->reset(std::move(serror)); + } else { + // Connection Error + // TODO Close connection (Does this really happen?) + } } return EVENT_CONT; @@ -281,7 +295,7 @@ QUICStream::_reorder_data() * If the reordering or writting operation is heavy, split out them to read function, * which is called by application via do_io_read() or reenable(). */ -QUICError +QUICErrorUPtr QUICStream::recv(const std::shared_ptr frame) { ink_assert(_id == frame->stream_id()); @@ -289,23 +303,22 @@ QUICStream::recv(const std::shared_ptr frame) // Check stream state - Do this first before accept the frame if (!this->_state.is_allowed_to_receive(*frame)) { - this->reset(); - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR); + return QUICErrorUPtr(new QUICStreamError(this, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_STATE_ERROR)); } // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit - QUICError error = this->_local_flow_controller->update(frame->offset() + frame->data_length()); + QUICErrorUPtr error = this->_local_flow_controller->update(frame->offset() + frame->data_length()); Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [LOCAL] %" PRIu64 "/%" PRIu64, this->_id, QUICDebugNames::stream_state(this->_state), this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); - if (error.cls != QUICErrorClass::NONE) { + if (error->cls != QUICErrorClass::NONE) { return error; } // Reordering - Some frames may be delayed or be dropped if (this->_recv_offset > frame->offset()) { // Do nothing. Just ignore STREAM frame. - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } else if (this->_recv_offset == frame->offset()) { this->_write_to_read_vio(frame); this->_reorder_data(); @@ -315,10 +328,10 @@ QUICStream::recv(const std::shared_ptr frame) this->_received_stream_frame_buffer.insert(std::make_pair(frame->offset(), frame)); } - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } -QUICError +QUICErrorUPtr QUICStream::recv(const std::shared_ptr frame) { this->_remote_flow_controller->forward_limit(frame->maximum_stream_data()); @@ -328,25 +341,26 @@ QUICStream::recv(const std::shared_ptr frame) this->reenable(&this->_write_vio); - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } -QUICError +QUICErrorUPtr QUICStream::recv(const std::shared_ptr frame) { // STREAM_BLOCKED frames are for debugging. Nothing to do here. - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } /** * @brief Send STREAM DATA from _response_buffer */ -QUICError +QUICErrorUPtr QUICStream::_send() { SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); - QUICError error; + QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); + IOBufferReader *reader = this->_write_vio.get_reader(); int64_t bytes_avail = reader->read_avail(); int64_t total_len = 0; @@ -366,11 +380,11 @@ QUICStream::_send() } } - QUICError error = this->_remote_flow_controller->update(this->_send_offset + len); + error = this->_remote_flow_controller->update(this->_send_offset + len); Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [REMOTE] %" PRIu64 "/%" PRIu64, this->_id, QUICDebugNames::stream_state(this->_state), this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); - if (error.cls != QUICErrorClass::NONE) { + if (error->cls != QUICErrorClass::NONE) { break; } @@ -394,9 +408,9 @@ QUICStream::_send() } void -QUICStream::reset() +QUICStream::reset(QUICStreamErrorUPtr error) { - // TODO: Create a RST_STREAM frame and pass it to Stream Manager + this->_tx->transmit_frame(QUICFrameFactory::create_rst_stream_frame(std::move(error))); } void diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index d8b476c74d8..bdb78aea517 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -52,6 +52,7 @@ class QUICStream : public VConnection int main_event_handler(int event, void *data); QUICStreamId id(); + QUICOffset final_offset(); // Implement VConnection interface. VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) override; @@ -60,11 +61,11 @@ class QUICStream : public VConnection void do_io_shutdown(ShutdownHowTo_t howto) override; void reenable(VIO *vio) override; - QUICError recv(const std::shared_ptr frame); - QUICError recv(const std::shared_ptr frame); - QUICError recv(const std::shared_ptr frame); + QUICErrorUPtr recv(const std::shared_ptr frame); + QUICErrorUPtr recv(const std::shared_ptr frame); + QUICErrorUPtr recv(const std::shared_ptr frame); - void reset(); + void reset(QUICStreamErrorUPtr error); void shutdown(); size_t nbytes_to_read(); @@ -77,7 +78,7 @@ class QUICStream : public VConnection private: QUICStreamState _state; - QUICError _send(); + QUICErrorUPtr _send(); void _write_to_read_vio(const std::shared_ptr &); void _reorder_data(); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index ba322ffdba7..2832328e80c 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -85,10 +85,10 @@ QUICStreamManager::set_max_stream_id(QUICStreamId id) } } -QUICError +QUICErrorUPtr QUICStreamManager::handle_frame(std::shared_ptr frame) { - QUICError error = QUICError(QUICErrorClass::NONE); + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (frame->type()) { case QUICFrameType::MAX_STREAM_DATA: @@ -116,34 +116,34 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) return error; } -QUICError +QUICErrorUPtr QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); if (stream) { return stream->recv(frame); } else { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR); + return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR)); } } -QUICError +QUICErrorUPtr QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); if (stream) { return stream->recv(frame); } else { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR); + return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR)); } } -QUICError +QUICErrorUPtr QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); if (!stream) { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR); + return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR)); } QUICApplication *application = this->_app_map->get(frame->stream_id()); @@ -153,7 +153,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr &f } size_t nbytes_to_read = stream->nbytes_to_read(); - QUICError error = stream->recv(frame); + QUICErrorUPtr error = stream->recv(frame); // Prevent trigger read events multiple times if (nbytes_to_read == 0) { this_ethread()->schedule_imm(application, VC_EVENT_READ_READY, stream); @@ -162,23 +162,23 @@ QUICStreamManager::_handle_frame(const std::shared_ptr &f return error; } -QUICError +QUICErrorUPtr QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); if (stream) { // TODO Reset the stream - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } else { - return QUICError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR); + return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR)); } } -QUICError +QUICErrorUPtr QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { this->_remote_maximum_stream_id = frame->maximum_stream_id(); - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } QUICStream * diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 2f664caef46..b6ad75f42a1 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -53,16 +53,16 @@ class QUICStreamManager : public QUICFrameHandler // QUICFrameHandler virtual std::vector interests() override; - virtual QUICError handle_frame(std::shared_ptr) override; + virtual QUICErrorUPtr handle_frame(std::shared_ptr) override; private: QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICStream *_find_stream(QUICStreamId id); - QUICError _handle_frame(const std::shared_ptr &); - QUICError _handle_frame(const std::shared_ptr &); - QUICError _handle_frame(const std::shared_ptr &); - QUICError _handle_frame(const std::shared_ptr &); - QUICError _handle_frame(const std::shared_ptr &); + QUICErrorUPtr _handle_frame(const std::shared_ptr &); + QUICErrorUPtr _handle_frame(const std::shared_ptr &); + QUICErrorUPtr _handle_frame(const std::shared_ptr &); + QUICErrorUPtr _handle_frame(const std::shared_ptr &); + QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICFrameTransmitter *_tx = nullptr; QUICApplicationMap *_app_map = nullptr; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index f3773c3c045..c2673d993b7 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -146,20 +146,47 @@ enum class QUICErrorCode : uint32_t { // TODO Add error codes }; -struct QUICError { - QUICError(const QUICErrorClass error_class = QUICErrorClass::NONE, const QUICErrorCode error_code = QUICErrorCode::NO_ERROR, - const char *err_msg = nullptr) - { - cls = error_class; - code = error_code; - msg = err_msg; - }; - +class QUICError +{ +public: + virtual ~QUICError() {} QUICErrorClass cls; QUICErrorCode code; const char *msg; + +protected: + QUICError(const QUICErrorClass error_class = QUICErrorClass::NONE, const QUICErrorCode error_code = QUICErrorCode::NO_ERROR, + const char *error_msg = nullptr) + : cls(error_class), code(error_code), msg(error_msg){}; +}; + +class QUICNoError : public QUICError +{ +public: + QUICNoError() : QUICError() {} +}; + +class QUICConnectionError : public QUICError +{ +public: + QUICConnectionError(const QUICErrorClass error_class, const QUICErrorCode error_code, const char *error_msg = nullptr) + : QUICError(error_class, error_code, error_msg){}; }; +class QUICStream; + +class QUICStreamError : public QUICError +{ +public: + QUICStreamError(QUICStream *s, const QUICErrorClass error_class, const QUICErrorCode error_code, const char *error_msg = nullptr) + : QUICError(error_class, error_code, error_msg), stream(s){}; + QUICStream *stream; +}; + +using QUICErrorUPtr = std::unique_ptr; +using QUICConnectionErrorUPtr = std::unique_ptr; +using QUICStreamErrorUPtr = std::unique_ptr; + class QUICStatelessToken { public: From ceea56b92a8e70f9939746fd6061d6138b2a3a1f Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 29 Sep 2017 10:49:05 +0800 Subject: [PATCH 0129/1313] fix the calc of rtt in LossDetector --- iocore/net/quic/QUICLossDetector.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 33d923dff9d..563aeeb792f 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -272,7 +272,7 @@ QUICLossDetector::_update_rtt(uint32_t latest_rtt) this->_smoothed_rtt = latest_rtt; this->_rttvar = latest_rtt / 2; } else { - this->_rttvar = 3 / 4 * this->_rttvar + 1 / 4 * (this->_smoothed_rtt - latest_rtt); + this->_rttvar = 3 / 4 * this->_rttvar + 1 / 4 * ABS(this->_smoothed_rtt - latest_rtt); this->_smoothed_rtt = 7 / 8 * this->_smoothed_rtt + 1 / 8 * latest_rtt; } } From 4774200a265a59889b240fc1995ae03343cefcbd Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 30 Sep 2017 09:37:07 +0800 Subject: [PATCH 0130/1313] fix mock complie error --- iocore/net/quic/Mock.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index e866a461974..ea5163f9ffa 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -33,13 +33,13 @@ class MockQUICStreamManager : public QUICStreamManager public: MockQUICStreamManager() : QUICStreamManager() {} // Override - virtual QUICError + virtual QUICErrorUPtr handle_frame(std::shared_ptr f) override { ++_frameCount[static_cast(f->type())]; ++_totalFrameCount; - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } // for Test @@ -173,13 +173,13 @@ class MockQUICConnection : public QUICConnection return {QUICFrameType::CONNECTION_CLOSE}; } - QUICError + QUICErrorUPtr handle_frame(std::shared_ptr f) override { ++_frameCount[static_cast(f->type())]; ++_totalFrameCount; - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } uint32_t @@ -231,7 +231,7 @@ class MockQUICConnection : public QUICConnection } void - close(QUICError error) override + close(QUICConnectionErrorUPtr error) override { } @@ -323,13 +323,13 @@ class MockQUICCongestionController : public QUICCongestionController public: MockQUICCongestionController() : QUICCongestionController() {} // Override - virtual QUICError + virtual QUICErrorUPtr handle_frame(std::shared_ptr f) override { ++_frameCount[static_cast(f->type())]; ++_totalFrameCount; - return QUICError(QUICErrorClass::NONE); + return QUICErrorUPtr(new QUICNoError()); } // for Test From ebe0a758b53b53e026db31c7c7b58d435de3abbd Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sat, 30 Sep 2017 18:01:20 +0900 Subject: [PATCH 0131/1313] Fix tests --- iocore/net/quic/test/Makefile.am | 20 ++++++ .../net/quic/test/test_QUICFlowController.cc | 64 +++++++++---------- 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index a958fe80dd2..917aeebd712 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -128,6 +128,10 @@ test_QUICFrame_SOURCES = \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICTypes.cc \ + ../QUICStream.cc \ + ../QUICStreamState.cc \ + ../QUICDebugNames.cc \ + ../QUICFlowController.cc \ ../../SSLNextProtocolSet.cc test_QUICFrame_LDADD = \ @@ -366,11 +370,20 @@ test_QUICTypeUtil_LDFLAGS = \ @AM_LDFLAGS@ test_QUICTypeUtil_LDADD = \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/lib/ts/libtsutil.la test_QUICTypeUtil_SOURCES = \ main.cc \ test_QUICTypeUtil.cc \ + ../QUICStream.cc \ + ../QUICStreamState.cc \ + ../QUICFlowController.cc \ + ../QUICDebugNames.cc \ + ../QUICFrame.cc \ + ../QUICPacket.cc \ + ../QUICCrypto.cc \ + $(QUICCrypto_impl) \ ../QUICTypes.cc # @@ -394,6 +407,10 @@ test_QUICAckFrameCreator_SOURCES = \ ../QUICTypes.cc \ ../QUICFrame.cc \ ../QUICPacket.cc \ + ../QUICStream.cc \ + ../QUICStreamState.cc \ + ../QUICFlowController.cc \ + ../QUICDebugNames.cc \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../../SSLNextProtocolSet.cc @@ -462,6 +479,9 @@ test_QUICFlowController_SOURCES = \ main.cc \ test_QUICFlowController.cc \ ../QUICFlowController.cc \ + ../QUICStream.cc \ + ../QUICStreamState.cc \ + ../QUICDebugNames.cc \ ../QUICTypes.cc \ ../QUICPacket.cc \ ../QUICCrypto.cc \ diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index 9c7996bafe3..e98278be5cb 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -29,7 +29,7 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") { - QUICError error; + std::unique_ptr error = nullptr; MockQUICFrameTransmitter tx; QUICLocalConnectionFlowController fc(1024, &tx); @@ -40,35 +40,35 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") error = fc.update(256); CHECK(fc.current_offset() == 256); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); error = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); // Retransmit error = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); error = fc.update(1024); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); // Delay error = fc.update(512); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); // Exceed limit error = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.code == QUICErrorCode::FLOW_CONTROL_ERROR); + CHECK(error->code == QUICErrorCode::FLOW_CONTROL_ERROR); // MAX_STREAM_DATA CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_DATA)] == 0); @@ -80,12 +80,12 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") error = fc.update(1280); CHECK(fc.current_offset() == 1280); CHECK(fc.current_limit() == 2048); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); } TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") { - QUICError error; + std::unique_ptr error = nullptr; MockQUICFrameTransmitter tx; QUICRemoteConnectionFlowController fc(1024, &tx); @@ -96,36 +96,36 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") error = fc.update(256); CHECK(fc.current_offset() == 256); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); error = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); // Retransmit error = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); error = fc.update(1024); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); // Delay error = fc.update(512); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); // Exceed limit CHECK(tx.frameCount[static_cast(QUICFrameType::BLOCKED)] == 0); error = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.cls != QUICErrorClass::NONE); + CHECK(error->cls != QUICErrorClass::NONE); CHECK(tx.frameCount[static_cast(QUICFrameType::BLOCKED)] == 1); // MAX_STREAM_DATA @@ -136,12 +136,12 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") error = fc.update(1280); CHECK(fc.current_offset() == 1280); CHECK(fc.current_limit() == 2048); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); } TEST_CASE("QUICFlowController_Local_Stream", "[quic]") { - QUICError error; + std::unique_ptr error = nullptr; MockQUICFrameTransmitter tx; QUICLocalStreamFlowController fc(1024, &tx, 0); @@ -152,35 +152,35 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]") error = fc.update(256); CHECK(fc.current_offset() == 256); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); error = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); // Retransmit error = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); error = fc.update(1024); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); // Delay error = fc.update(512); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); // Exceed limit error = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.code == QUICErrorCode::FLOW_CONTROL_ERROR); + CHECK(error->code == QUICErrorCode::FLOW_CONTROL_ERROR); // MAX_STREAM_DATA CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_STREAM_DATA)] == 0); @@ -192,12 +192,12 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]") error = fc.update(1280); CHECK(fc.current_offset() == 1280); CHECK(fc.current_limit() == 2048); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); } TEST_CASE("QUICFlowController_Remote_Stream", "[quic]") { - QUICError error; + std::unique_ptr error = nullptr; MockQUICFrameTransmitter tx; QUICRemoteStreamFlowController fc(1024, &tx, 0); @@ -208,36 +208,36 @@ TEST_CASE("QUICFlowController_Remote_Stream", "[quic]") error = fc.update(256); CHECK(fc.current_offset() == 256); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); error = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); // Retransmit error = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); error = fc.update(1024); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); // Delay error = fc.update(512); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); // Exceed limit CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM_BLOCKED)] == 0); error = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error.cls != QUICErrorClass::NONE); + CHECK(error->cls != QUICErrorClass::NONE); CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM_BLOCKED)] == 1); // MAX_STREAM_DATA @@ -248,5 +248,5 @@ TEST_CASE("QUICFlowController_Remote_Stream", "[quic]") error = fc.update(1280); CHECK(fc.current_offset() == 1280); CHECK(fc.current_limit() == 2048); - CHECK(error.cls == QUICErrorClass::NONE); + CHECK(error->cls == QUICErrorClass::NONE); } From 110d21d5b8482915bfc4ad1cea64d127af95b4c9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sat, 30 Sep 2017 18:48:22 +0900 Subject: [PATCH 0132/1313] Add nullptr check for error reason phrease --- iocore/net/quic/QUICFrame.cc | 12 +++-- iocore/net/quic/QUICFrame.h | 2 +- iocore/net/quic/test/Makefile.am | 1 + iocore/net/quic/test/test_QUICFrame.cc | 67 ++++++++++++++++++++++++-- 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 0db9d8c636e..69951d47ed3 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -807,8 +807,10 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len) const p += n; QUICTypeUtil::write_uint_as_nbytes(this->_reason_phrase_length, 2, p, &n); p += n; - memcpy(p, this->_reason_phrase, this->_reason_phrase_length); - p += this->_reason_phrase_length; + if (this->_reason_phrase_length > 0) { + memcpy(p, this->_reason_phrase, this->_reason_phrase_length); + p += this->_reason_phrase_length; + } *len = p - buf; } @@ -1337,7 +1339,11 @@ QUICFrameFactory::create_connection_close_frame(QUICErrorCode error_code, uint16 std::unique_ptr QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error) { - return QUICFrameFactory::create_connection_close_frame(error->code, strlen(error->msg), error->msg); + if (error->msg) { + return QUICFrameFactory::create_connection_close_frame(error->code, strlen(error->msg), error->msg); + } else { + return QUICFrameFactory::create_connection_close_frame(error->code); + } } std::unique_ptr diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 15c098c4a16..0b1e554c4f7 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -602,7 +602,7 @@ class QUICFrameFactory * Creates a CONNECTION_CLOSE frame. */ static std::unique_ptr create_connection_close_frame( - QUICErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase); + QUICErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr); static std::unique_ptr create_connection_close_frame( QUICConnectionErrorUPtr error); diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 917aeebd712..487e5328e0d 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -117,6 +117,7 @@ test_QUICFrame_CPPFLAGS = \ $(AM_CPPFLAGS) test_QUICFrame_LDFLAGS = \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ @AM_LDFLAGS@ test_QUICFrame_SOURCES = \ diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 6540147dac7..be140b3d694 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -23,7 +23,9 @@ #include "catch.hpp" +#include "quic/Mock.h" #include "quic/QUICFrame.h" +#include "quic/QUICStream.h" TEST_CASE("QUICFrame Type", "[quic]") { @@ -374,6 +376,21 @@ TEST_CASE("Load ConnectionClose Frame", "[quic]") CHECK(connectionCloseFrame1->error_code() == QUICErrorCode::NO_ERROR); CHECK(connectionCloseFrame1->reason_phrase_length() == 5); CHECK(memcmp(connectionCloseFrame1->reason_phrase(), buf1 + 7, 5) == 0); + + // No reason phrase + uint8_t buf2[] = { + 0x02, // Type + 0x80, 0x00, 0x00, 0x00, // Error Code + 0x00, 0x00, // Reason Phrase Length + }; + std::shared_ptr frame2 = QUICFrameFactory::create(buf2, sizeof(buf1)); + CHECK(frame2->type() == QUICFrameType::CONNECTION_CLOSE); + CHECK(frame2->size() == 7); + std::shared_ptr connectionCloseFrame2 = + std::dynamic_pointer_cast(frame2); + CHECK(connectionCloseFrame2 != nullptr); + CHECK(connectionCloseFrame2->error_code() == QUICErrorCode::NO_ERROR); + CHECK(connectionCloseFrame2->reason_phrase_length() == 0); } TEST_CASE("Store ConnectionClose Frame", "[quic]") @@ -381,16 +398,26 @@ TEST_CASE("Store ConnectionClose Frame", "[quic]") uint8_t buf[65535]; size_t len; - uint8_t expected[] = { + uint8_t expected1[] = { 0x02, // Type 0x80, 0x00, 0x00, 0x00, // Error Code 0x00, 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; - QUICConnectionCloseFrame connectionCloseFrame(QUICErrorCode::NO_ERROR, 5, "ABCDE"); - connectionCloseFrame.store(buf, &len); + QUICConnectionCloseFrame connectionCloseFrame1(QUICErrorCode::NO_ERROR, 5, "ABCDE"); + connectionCloseFrame1.store(buf, &len); CHECK(len == 12); - CHECK(memcmp(buf, expected, len) == 0); + CHECK(memcmp(buf, expected1, len) == 0); + + uint8_t expected2[] = { + 0x02, // Type + 0x80, 0x00, 0x00, 0x00, // Error Code + 0x00, 0x00, // Reason Phrase Length + }; + QUICConnectionCloseFrame connectionCloseFrame2(QUICErrorCode::NO_ERROR, 0, nullptr); + connectionCloseFrame2.store(buf, &len); + CHECK(len == 7); + CHECK(memcmp(buf, expected2, len) == 0); } TEST_CASE("Load MaxData Frame", "[quic]") @@ -681,3 +708,35 @@ TEST_CASE("QUICFrameFactory Fast Create Unknown Frame", "[quic]") std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); CHECK(frame1 == nullptr); } + +TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", "[quic]") +{ + std::unique_ptr error = + std::unique_ptr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR)); + std::unique_ptr connection_close_frame1 = + QUICFrameFactory::create_connection_close_frame(std::move(error)); + CHECK(connection_close_frame1->error_code() == QUICErrorCode::INTERNAL_ERROR); + CHECK(connection_close_frame1->reason_phrase_length() == 0); + CHECK(connection_close_frame1->reason_phrase() == nullptr); + + error = std::unique_ptr( + new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR, "test")); + std::unique_ptr connection_close_frame2 = + QUICFrameFactory::create_connection_close_frame(std::move(error)); + CHECK(connection_close_frame2->error_code() == QUICErrorCode::INTERNAL_ERROR); + CHECK(connection_close_frame2->reason_phrase_length() == 4); + CHECK(memcmp(connection_close_frame2->reason_phrase(), "test", 4) == 0); +} + +TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") +{ + QUICStream stream; + stream.init(new MockQUICFrameTransmitter(), 0x1234, 0, 0); + std::unique_ptr error = + std::unique_ptr(new QUICStreamError(&stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR)); + std::unique_ptr rst_stream_frame1 = + QUICFrameFactory::create_rst_stream_frame(std::move(error)); + CHECK(rst_stream_frame1->error_code() == QUICErrorCode::INTERNAL_ERROR); + CHECK(rst_stream_frame1->stream_id() == 0x1234); + CHECK(rst_stream_frame1->final_offset() == 0); +} From 0551bfdb9673b71cbfd64c5fb59c502c82ee60b4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sat, 30 Sep 2017 22:01:18 +0900 Subject: [PATCH 0133/1313] Remove QUICNetVConnection from the map when the connection has been freed --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/P_QUICPacketHandler.h | 1 + iocore/net/QUICNetVConnection.cc | 8 ++++++++ iocore/net/QUICPacketHandler.cc | 6 ++++++ iocore/net/quic/Mock.h | 7 +++++++ iocore/net/quic/QUICConnection.h | 2 ++ 6 files changed, 25 insertions(+) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 7db4cd82f21..82b89fc80f9 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -170,6 +170,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void registerNextProtocolSet(SSLNextProtocolSet *s); // QUICConnection + QUICConnectionId connection_id() override; uint32_t maximum_quic_packet_size() override; uint32_t minimum_quic_packet_size() override; uint32_t maximum_stream_frame_data_size() override; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index e1ea3fbae29..113a31c5b5a 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -42,6 +42,7 @@ struct QUICPacketHandler : public NetAccept { void init_accept(EThread *t) override; void send_packet(const QUICPacket &packet, QUICNetVConnection *vc); void send_packet(const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu); + void forget(QUICNetVConnection *vc); private: void _recv_packet(int event, UDPPacket *udpPacket); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index c0b284853c9..39ad79cb3a5 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -123,6 +123,8 @@ QUICNetVConnection::free(EThread *t) { DebugQUICCon("Free connection"); + this->_packet_handler->forget(this); + this->_udp_con = nullptr; this->_packet_handler = nullptr; @@ -151,6 +153,12 @@ QUICNetVConnection::reenable(VIO *vio) return; } +QUICConnectionId +QUICNetVConnection::connection_id() +{ + return this->_quic_connection_id; +} + uint32_t QUICNetVConnection::pmtu() { diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 7dee08ceb7a..641dba203b1 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -199,3 +199,9 @@ QUICPacketHandler::send_packet(const QUICPacket &packet, UDPConnection *udp_con, udp_con->send(this, udpPkt); } + +void +QUICPacketHandler::forget(QUICNetVConnection *vc) +{ + this->_connections.put(vc->connection_id(), nullptr); +} diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index ea5163f9ffa..41d5390092a 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -144,6 +144,13 @@ class MockQUICConnection : public QUICConnection { this->_mutex = new_ProxyMutex(); }; + + QUICConnectionId + connection_id() override + { + return 0; + } + void transmit_packet(QUICPacketUPtr packet) override { diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index e0bb194a207..93634ad3eea 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -35,6 +35,8 @@ class SSLNextProtocolSet; class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler { public: + virtual QUICConnectionId connection_id() = 0; + /* * Retruns the maximum packet size at the time called * From cbf265cd6b0b06ce9c353f911ef109026fbe412b Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Tue, 3 Oct 2017 10:45:15 -0700 Subject: [PATCH 0134/1313] =?UTF-8?q?Initialize=20variable=20to=20fix=20gc?= =?UTF-8?q?c=207.2.1=20error=20error:=20=E2=80=98gap=E2=80=99=20may=20be?= =?UTF-8?q?=20used=20uninitialized=20in=20this=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iocore/net/quic/QUICAckFrameCreator.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 26c8199c085..5abaadb7e94 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -75,7 +75,7 @@ QUICAckFrameCreator::_create_ack_frame() std::unique_ptr ack_frame = {nullptr, QUICFrameDeleter::delete_null_frame}; this->_sort_packet_numbers(); uint16_t start = this->_packet_numbers[0]; - uint8_t gap; + uint8_t gap = 0; int i; uint64_t length = 0; for (i = 0, length = 0; i < this->_packet_count; ++i, ++length) { From d74253e17cd7237b744e8cfc9a262e7fc8e98b2b Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Tue, 3 Oct 2017 11:03:07 -0700 Subject: [PATCH 0135/1313] clang-format --- iocore/net/quic/QUICAckFrameCreator.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 5abaadb7e94..e3988f721dd 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -75,7 +75,7 @@ QUICAckFrameCreator::_create_ack_frame() std::unique_ptr ack_frame = {nullptr, QUICFrameDeleter::delete_null_frame}; this->_sort_packet_numbers(); uint16_t start = this->_packet_numbers[0]; - uint8_t gap = 0; + uint8_t gap = 0; int i; uint64_t length = 0; for (i = 0, length = 0; i < this->_packet_count; ++i, ++length) { From 49ce8f11234a11639b9ee69829193fbb8845d2f3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 3 Oct 2017 13:07:17 -0700 Subject: [PATCH 0136/1313] Add debug tag for handshake packet dump --- iocore/net/quic/QUICHandshake.cc | 61 ++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 7c34690d5da..9dbbc5fb225 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -29,24 +29,49 @@ #include "QUICConfig.h" #include "P_SSLNextProtocolSet.h" -#define I_WANNA_DUMP_THIS_BUF(buf, len) \ - { \ - int i, j; \ - fprintf(stderr, "len=%" PRId64 "\n", len); \ - for (i = 0; i < len / 8; i++) { \ - fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x ", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3], \ - buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6], buf[i * 8 + 7]); \ - if ((i + 1) % 4 == 0 || (len % 8 == 0 && i + 1 == len / 8)) { \ - fprintf(stderr, "\n"); \ - } \ - } \ - if (len % 8 != 0) { \ - fprintf(stderr, "%0x", buf[i * 8 + 0]); \ - for (j = 1; j < len % 8; j++) { \ - fprintf(stderr, " %02x", buf[i * 8 + j]); \ - } \ - fprintf(stderr, "\n"); \ - } \ +static constexpr char dump_tag[] = "quic_handshake_dump_pkt"; + +#define I_WANNA_DUMP_THIS_BUF(buf, len) \ + { \ + int i; \ + Debug(dump_tag, "len=%" PRId64 "\n", len); \ + for (i = 0; i < len / 8; i++) { \ + Debug(dump_tag, "%02x %02x %02x %02x %02x %02x %02x %02x ", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3], \ + buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6], buf[i * 8 + 7]); \ + } \ + switch (len % 8) { \ + case 1: \ + Debug(dump_tag, "%02x", buf[i * 8 + 0]); \ + break; \ + case 2: \ + Debug(dump_tag, "%02x %02x", buf[i * 8 + 0], buf[i * 8 + 1]); \ + \ + break; \ + case 3: \ + Debug(dump_tag, "%02x %02x %02x", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2]); \ + \ + break; \ + case 4: \ + Debug(dump_tag, "%02x %02x %02x %02x", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3]); \ + \ + break; \ + case 5: \ + Debug(dump_tag, "%02x %02x %02x %02x %02x", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3], buf[i * 8 + 4]); \ + \ + break; \ + case 6: \ + Debug(dump_tag, "%02x %02x %02x %02x %02x %02x", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3], \ + buf[i * 8 + 4], buf[i * 8 + 5]); \ + \ + break; \ + case 7: \ + Debug(dump_tag, "%02x %02x %02x %02x %02x %02x %02x", buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3], \ + buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6]); \ + \ + break; \ + default: \ + break; \ + } \ } static constexpr char tag[] = "quic_handshake"; From 6fb7f874fba599efe602c35901d1df68da8d72e2 Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Tue, 3 Oct 2017 13:57:46 -0700 Subject: [PATCH 0137/1313] Initialize the SSL_CTX in QUICNetProcessor and clean up to use C++11 assignment initialization --- iocore/net/P_QUICNetProcessor.h | 2 +- iocore/net/P_UDPNet.h | 12 ++++-------- iocore/net/P_UnixUDPConnection.h | 10 +++++----- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h index f5a29065180..9f97454b5fe 100644 --- a/iocore/net/P_QUICNetProcessor.h +++ b/iocore/net/P_QUICNetProcessor.h @@ -68,7 +68,7 @@ class QUICNetProcessor : public UnixNetProcessor QUICNetProcessor(const QUICNetProcessor &); QUICNetProcessor &operator=(const QUICNetProcessor &); - SSL_CTX *_ssl_ctx; + SSL_CTX *_ssl_ctx = nullptr; }; extern QUICNetProcessor quic_NetProcessor; diff --git a/iocore/net/P_UDPNet.h b/iocore/net/P_UDPNet.h index a093bb8c834..dcc28e497f7 100644 --- a/iocore/net/P_UDPNet.h +++ b/iocore/net/P_UDPNet.h @@ -61,19 +61,15 @@ extern UDPNetProcessorInternal udpNetInternal; class PacketQueue { public: - PacketQueue() : nPackets(0), now_slot(0) - { - lastPullLongTermQ = 0; - init(); - } + PacketQueue() { init(); } virtual ~PacketQueue() {} - int nPackets; - ink_hrtime lastPullLongTermQ; + int nPackets = 0; + ink_hrtime lastPullLongTermQ = 0; Queue longTermQ; Queue bucket[N_SLOTS]; ink_hrtime delivery_time[N_SLOTS]; - int now_slot; + int now_slot = 0; void init(void) diff --git a/iocore/net/P_UnixUDPConnection.h b/iocore/net/P_UnixUDPConnection.h index 6c71d46d63e..6d5e45530f7 100644 --- a/iocore/net/P_UnixUDPConnection.h +++ b/iocore/net/P_UnixUDPConnection.h @@ -47,21 +47,21 @@ class UnixUDPConnection : public UDPConnectionInternal SLINK(UnixUDPConnection, newconn_alink); InkAtomicList inQueue; - int onCallbackQueue; - Action *callbackAction; - EThread *ethread; + int onCallbackQueue = 0; + Action *callbackAction = nullptr; + EThread *ethread = nullptr; EventIO ep; UnixUDPConnection(int the_fd); virtual ~UnixUDPConnection(); private: - int m_errno; + int m_errno = 0; virtual void UDPConnection_is_abstract(){}; }; TS_INLINE -UnixUDPConnection::UnixUDPConnection(int the_fd) : onCallbackQueue(0), callbackAction(nullptr), ethread(nullptr), m_errno(0) +UnixUDPConnection::UnixUDPConnection(int the_fd) { fd = the_fd; UDPPacketInternal p; From 155d69971f4cfb656c97c7583ea975643e168840 Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Tue, 3 Oct 2017 15:33:09 -0700 Subject: [PATCH 0138/1313] Initialize all members in QUICLossDetector and clean up to use C++11 assignment initialization --- iocore/net/quic/QUICLossDetector.cc | 10 ---------- iocore/net/quic/QUICLossDetector.h | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 563aeeb792f..503b4773661 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -31,10 +31,6 @@ QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter) : _transm { this->mutex = new_ProxyMutex(); - this->_loss_detection_alarm = nullptr; - this->_handshake_count = 0; - this->_tlp_count = 0; - this->_rto_count = 0; if (this->_time_loss_detection) { this->_reordering_threshold = UINT32_MAX; this->_time_reordering_fraction = this->_TIME_REORDERING_FRACTION; @@ -42,12 +38,6 @@ QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter) : _transm this->_reordering_threshold = this->_REORDERING_THRESHOLD; this->_time_reordering_fraction = INFINITY; } - this->_loss_time = 0; - this->_smoothed_rtt = 0; - this->_rttvar = 0; - this->_largest_sent_before_rto = 0; - this->_time_of_last_sent_packet = 0; - this->_largest_sent_packet = 0; SET_HANDLER(&QUICLossDetector::event_handler); } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 73136949c98..1ffa8eb178a 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -74,20 +74,20 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler ink_hrtime _DEFAULT_INITIAL_RTT = HRTIME_MSECONDS(100); // 3.2.2. Variables of interest - Action *_loss_detection_alarm; - uint32_t _handshake_count = 0; - uint32_t _tlp_count = 0; - uint32_t _rto_count = 0; - uint32_t _largest_sent_before_rto; - uint32_t _largest_sent_packet; - uint32_t _largest_acked_packet; - uint32_t _time_of_last_sent_packet; - ink_hrtime _latest_rtt; - ink_hrtime _smoothed_rtt; - uint32_t _rttvar; + Action *_loss_detection_alarm = nullptr; + uint32_t _handshake_count = 0; + uint32_t _tlp_count = 0; + uint32_t _rto_count = 0; + uint32_t _largest_sent_before_rto = 0; + uint32_t _largest_sent_packet = 0; + uint32_t _largest_acked_packet = 0; + uint32_t _time_of_last_sent_packet = 0; + ink_hrtime _latest_rtt = 0; + ink_hrtime _smoothed_rtt = 0; + uint32_t _rttvar = 0; uint32_t _reordering_threshold; double _time_reordering_fraction; - ink_hrtime _loss_time; + ink_hrtime _loss_time = 0; std::map> _sent_packets; uint32_t _handshake_outstanding = 0; From 4617336ff08ad85c1e33ebad83aea45abf2af3ef Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 3 Oct 2017 15:55:23 -0700 Subject: [PATCH 0139/1313] Set default app name if client send no ALPN --- iocore/net/QUICNetVConnection.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 39ad79cb3a5..ddefb823092 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -436,8 +436,18 @@ QUICNetVConnection::state_handshake(int event, Event *data) const uint8_t *app_name; unsigned int app_name_len = 0; this->_handshake_handler->negotiated_application_name(&app_name, &app_name_len); + if (app_name == nullptr) { + app_name = reinterpret_cast(IP_PROTO_TAG_HTTP_QUIC.ptr()); + app_name_len = IP_PROTO_TAG_HTTP_QUIC.size(); + } + Continuation *endpoint = this->_next_protocol_set->findEndpoint(app_name, app_name_len); - endpoint->handleEvent(NET_EVENT_ACCEPT, this); + if (endpoint == nullptr) { + this->_handle_error( + QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::VERSION_NEGOTIATION_ERROR))); + } else { + endpoint->handleEvent(NET_EVENT_ACCEPT, this); + } } return EVENT_CONT; From 4abd02447216d925f0aaf3f26c5a6581eed4b7b8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 3 Oct 2017 16:20:46 -0700 Subject: [PATCH 0140/1313] Discard packets instead of crash This just avoids crashes. The packets need to be acked. (#2609) --- iocore/net/QUICNetVConnection.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ddefb823092..88019221453 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -495,7 +495,11 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: { - error = this->_state_common_receive_packet(); + if (this->_handshake_handler && this->_handshake_handler->is_completed()) { + error = this->_state_common_receive_packet(); + } else { + // FIXME Just ignore for now but it has to be acked (GitHub#2609) + } break; } case QUIC_EVENT_PACKET_WRITE_READY: { @@ -683,6 +687,9 @@ QUICNetVConnection::_state_common_receive_packet() case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: error = this->_state_connection_established_process_packet(std::move(p)); break; + case QUICPacketType::CLIENT_CLEARTEXT: + // FIXME Just ignore for now but it has to be acked (GitHub#2609) + break; default: error = QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR)); break; From c4c3bd9c213b63d03108653761be90f52ac55c33 Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Tue, 3 Oct 2017 17:17:41 -0700 Subject: [PATCH 0141/1313] Added std::make_unique for C++11 --- lib/ts/Makefile.am | 1 + lib/ts/ink_memory.h | 4 ++++ lib/ts/ink_std_compat.h | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 lib/ts/ink_std_compat.h diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am index 737dbfedafa..449e03b6a1f 100644 --- a/lib/ts/Makefile.am +++ b/lib/ts/Makefile.am @@ -132,6 +132,7 @@ libtsutil_la_SOURCES = \ ink_sock.h \ ink_sprintf.cc \ ink_sprintf.h \ + ink_std_compat.h \ ink_stack_trace.cc \ ink_stack_trace.h \ ink_string.cc \ diff --git a/lib/ts/ink_memory.h b/lib/ts/ink_memory.h index 5a8e2d3d4bb..0264f772b77 100644 --- a/lib/ts/ink_memory.h +++ b/lib/ts/ink_memory.h @@ -30,6 +30,10 @@ #include "ts/ink_config.h" +#ifdef __cplusplus +#include "ink_std_compat.h" +#endif + #if HAVE_UNISTD_H #include #endif diff --git a/lib/ts/ink_std_compat.h b/lib/ts/ink_std_compat.h new file mode 100644 index 00000000000..ca972a6ebe3 --- /dev/null +++ b/lib/ts/ink_std_compat.h @@ -0,0 +1,37 @@ +/** @file + + Compatibility with future versions of the C++ standard library + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#if __cplusplus < 201402L +#include +namespace std +{ +template +std::unique_ptr +make_unique(Args &&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} +} +#endif From 36afa3a1708420b4232a63ab43a791e6fef83995 Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Tue, 3 Oct 2017 18:05:06 -0700 Subject: [PATCH 0142/1313] Have Quic use make_unique --- iocore/net/QUICNetVConnection.cc | 4 ++-- iocore/net/quic/QUICTypes.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 88019221453..aff162ad342 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -412,7 +412,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) case EVENT_IMMEDIATE: { // Start Implicit Shutdown. Because of no network activity for the duration of the idle timeout. this->remove_from_active_queue(); - this->close({}); + this->close(std::make_unique()); // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application break; @@ -472,7 +472,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) case EVENT_IMMEDIATE: { // Start Implicit Shutdown. Because of no network activity for the duration of the idle timeout. this->remove_from_active_queue(); - this->close({}); + this->close(std::make_unique()); // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application break; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index c2673d993b7..d25f36afa25 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -169,6 +169,7 @@ class QUICNoError : public QUICError class QUICConnectionError : public QUICError { public: + QUICConnectionError() : QUICError() {} QUICConnectionError(const QUICErrorClass error_class, const QUICErrorCode error_code, const char *error_msg = nullptr) : QUICError(error_class, error_code, error_msg){}; }; From 8cc22df1355e37b46c6665ecd7d2970aee464215 Mon Sep 17 00:00:00 2001 From: Zizhong Zhang Date: Tue, 3 Oct 2017 17:38:13 -0700 Subject: [PATCH 0143/1313] Fix #2494 Generate Stateless Reset Token with a configurable value --- iocore/net/QUICNetVConnection.cc | 8 ++++++-- iocore/net/QUICPacketHandler.cc | 6 +++++- iocore/net/quic/QUICConfig.cc | 7 +++++++ iocore/net/quic/QUICConfig.h | 2 ++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index aff162ad342..5962e966309 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -35,6 +35,7 @@ #include "P_SSLNextProtocolSet.h" +#include "QUICConfig.h" #include "QUICDebugNames.h" #include "QUICEvents.h" #include "QUICConfig.h" @@ -92,7 +93,10 @@ void QUICNetVConnection::start(SSL_CTX *ssl_ctx) { // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not - this->_token.gen_token(_quic_connection_id ^ id); + { + QUICConfig::scoped_config params; + this->_token.gen_token(_quic_connection_id ^ params->server_id()); + } this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_token); this->_application_map = new QUICApplicationMap(); @@ -689,7 +693,7 @@ QUICNetVConnection::_state_common_receive_packet() break; case QUICPacketType::CLIENT_CLEARTEXT: // FIXME Just ignore for now but it has to be acked (GitHub#2609) - break; + break; default: error = QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR)); break; diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 641dba203b1..2c8dfb91aa5 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -22,6 +22,7 @@ #include "ts/ink_config.h" #include "P_Net.h" +#include "QUICConfig.h" #include "QUICPacket.h" #include "QUICDebugNames.h" #include "QUICEvents.h" @@ -135,7 +136,10 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) // Send stateless reset if the packet is not a initial packet if (!QUICTypeUtil::hasLongHeader(reinterpret_cast(block->buf()))) { QUICStatelessToken token; - token.gen_token(cid); + { + QUICConfig::scoped_config params; + token.gen_token(cid ^ params->server_id()); + } auto packet = QUICPacketFactory::create_stateless_reset_packet(cid, token); this->send_packet(*packet, udpPacket->getConnection(), con.addr, 1200); return; diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index d97ef54188e..38b6b131c0b 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -34,6 +34,7 @@ void QUICConfigParams::initialize() { REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_in, "proxy.config.quic.no_activity_timeout_in"); + REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); } uint32_t @@ -42,6 +43,12 @@ QUICConfigParams::no_activity_timeout_in() const return this->_no_activity_timeout_in; } +uint32_t +QUICConfigParams::server_id() const +{ + return this->_server_id; +} + uint32_t QUICConfigParams::initial_max_data() const { diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index b9ac7c20768..05588ce8652 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -34,6 +34,7 @@ class QUICConfigParams : public ConfigInfo uint32_t initial_max_data() const; uint32_t initial_max_stream_data() const; uint32_t initial_max_stream_id() const; + uint32_t server_id() const; private: // FIXME Fill appropriate values @@ -41,6 +42,7 @@ class QUICConfigParams : public ConfigInfo uint32_t _initial_max_data = 100; // in units of 1024 octets uint32_t _initial_max_stream_data = 2048; uint32_t _initial_max_stream_id = 100; + uint32_t _server_id = 0; }; class QUICConfig From 57d68dc00c9aad4f70cb9596c6d5b750d23242da Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Wed, 4 Oct 2017 10:52:31 -0700 Subject: [PATCH 0144/1313] Use std:max instead of internal max macro that was removed --- iocore/net/quic/QUICCrypto.cc | 2 +- iocore/net/quic/QUICLossDetector.cc | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 02872e7c33a..1cfc2d6b1b8 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -166,7 +166,7 @@ QUICCrypto::setup_session() size_t secret_len = EVP_MD_size(this->_digest); size_t key_len = _get_aead_key_len(this->_aead); - size_t iv_len = max(static_cast(8), _get_aead_nonce_len(this->_aead)); + size_t iv_len = std::max(static_cast(8), _get_aead_nonce_len(this->_aead)); int r = 0; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 503b4773661..ff9f98a565f 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -104,10 +104,10 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num uint32_t delay_until_lost = UINT32_MAX; if (this->_time_reordering_fraction != INFINITY) { - delay_until_lost = (1 + this->_time_reordering_fraction) * max(this->_latest_rtt, this->_smoothed_rtt); + delay_until_lost = (1 + this->_time_reordering_fraction) * std::max(this->_latest_rtt, this->_smoothed_rtt); } else if (largest_acked_packet_number == this->_largest_sent_packet) { // Early retransmit alarm. - delay_until_lost = 9 / 8 * max(this->_latest_rtt, this->_smoothed_rtt); + delay_until_lost = 9 / 8 * std::max(this->_latest_rtt, this->_smoothed_rtt); } for (auto &unacked : this->_sent_packets) { if (unacked.first >= largest_acked_packet_number) { @@ -284,7 +284,7 @@ QUICLossDetector::_set_loss_detection_alarm() } else { alarm_duration = 2 * this->_smoothed_rtt; } - alarm_duration = max(alarm_duration, this->_MIN_TLP_TIMEOUT); + alarm_duration = std::max(alarm_duration, this->_MIN_TLP_TIMEOUT); alarm_duration = alarm_duration * (1 << this->_handshake_count); Debug(tag, "Handshake retransmission alarm will be set"); } else if (this->_loss_time != 0) { @@ -298,12 +298,12 @@ QUICLossDetector::_set_loss_detection_alarm() } else { alarm_duration = this->_MIN_TLP_TIMEOUT; } - alarm_duration = max(alarm_duration, 2 * this->_smoothed_rtt); + alarm_duration = std::max(alarm_duration, 2 * this->_smoothed_rtt); Debug(tag, "TLP alarm will be set"); } else { // RTO alarm alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar; - alarm_duration = max(alarm_duration, this->_MIN_RTO_TIMEOUT); + alarm_duration = std::max(alarm_duration, this->_MIN_RTO_TIMEOUT); alarm_duration = alarm_duration * (1 << this->_rto_count); Debug(tag, "RTO alarm will be set"); } From e47001634c272861187f033537e7f321e8dfa9d0 Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Wed, 4 Oct 2017 11:13:37 -0700 Subject: [PATCH 0145/1313] Stubbed out get_transaction_id for now to get QUIC to build --- proxy/hq/HQClientTransaction.cc | 8 ++++++++ proxy/hq/HQClientTransaction.h | 1 + 2 files changed, 9 insertions(+) diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 4cb6283ba65..9f41461eabb 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -275,3 +275,11 @@ HQClientTransaction::transaction_done() // TODO: start closing transaction return; } + +int +HQClientTransaction::get_transaction_id() const +{ + // TODO: not implemented + ink_release_assert(false); + return 0; +} diff --git a/proxy/hq/HQClientTransaction.h b/proxy/hq/HQClientTransaction.h index fc56a5e1ab5..cad8b6c43f5 100644 --- a/proxy/hq/HQClientTransaction.h +++ b/proxy/hq/HQClientTransaction.h @@ -50,6 +50,7 @@ class HQClientTransaction : public ProxyClientTransaction void do_io_shutdown(ShutdownHowTo_t howto) override; void reenable(VIO *vio) override; void release(IOBufferReader *r) override; + int get_transaction_id() const override; // HQClientTransaction specific methods int main_event_handler(int event, void *edata); From 72dc8c3a1c758cef3dec3869c889c281dc867cad Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Wed, 4 Oct 2017 12:06:31 -0700 Subject: [PATCH 0146/1313] Implemented HQClientTransaction::get_transaction_id --- iocore/net/quic/QUICApplication.h | 10 ++++++++-- iocore/net/quic/QUICStream.cc | 2 +- iocore/net/quic/QUICStream.h | 14 +++++++------- proxy/hq/HQClientTransaction.cc | 4 +--- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 20059d798bc..8094a4e2a6f 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -26,9 +26,9 @@ #include "../../eventsystem/I_EventSystem.h" #include "../../eventsystem/I_IOBuffer.h" #include "QUICTypes.h" +#include "QUICStream.h" class QUICConnection; -class QUICStream; class QUICApplication; /** @@ -48,6 +48,12 @@ class QUICStreamIO IOBufferReader *get_read_buffer_reader(); void shutdown(); + int + get_transaction_id() const + { + return _stream->id(); + } + private: QUICStream *_stream = nullptr; @@ -62,7 +68,7 @@ class QUICStreamIO }; /** - * @brief Abstruct QUIC Application Class + * @brief Abstract QUIC Application Class * @detail Every quic application must inherits this class */ class QUICApplication : public Continuation diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index dd41ff357a1..a6fd6004595 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -65,7 +65,7 @@ QUICStream::init_flow_control_params(uint32_t recv_max_stream_data, uint32_t sen } QUICStreamId -QUICStream::id() +QUICStream::id() const { return this->_id; } diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index bdb78aea517..a916ead5cb0 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -51,7 +51,7 @@ class QUICStream : public VConnection void init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data); int main_event_handler(int event, void *data); - QUICStreamId id(); + QUICStreamId id() const; QUICOffset final_offset(); // Implement VConnection interface. @@ -91,20 +91,20 @@ class QUICStream : public VConnection Event *_send_tracked_event(Event *event, int send_event, VIO *vio); - bool _fin; + bool _fin = false; QUICStreamId _id = 0; QUICOffset _recv_offset = 0; QUICOffset _send_offset = 0; - QUICRemoteStreamFlowController *_remote_flow_controller; - QUICLocalStreamFlowController *_local_flow_controller; - uint64_t _flow_control_buffer_size = 1024; + QUICRemoteStreamFlowController *_remote_flow_controller = nullptr; + QUICLocalStreamFlowController *_local_flow_controller = nullptr; + uint64_t _flow_control_buffer_size = 1024; VIO _read_vio; VIO _write_vio; - Event *_read_event; - Event *_write_event; + Event *_read_event = nullptr; + Event *_write_event = nullptr; // Fragments of received STREAM frame (offset is unmatched) // TODO: Consider to replace with ts/RbTree.h or other data structure diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 9f41461eabb..8c168d5c54c 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -279,7 +279,5 @@ HQClientTransaction::transaction_done() int HQClientTransaction::get_transaction_id() const { - // TODO: not implemented - ink_release_assert(false); - return 0; + return this->_stream_io->get_transaction_id(); } From f90c3197dc48a7c34023bfa459873d79016e8585 Mon Sep 17 00:00:00 2001 From: Leif Hedstrom Date: Wed, 4 Oct 2017 12:47:40 -0700 Subject: [PATCH 0147/1313] Prefix the verbose handshake dump with v_ --- iocore/net/quic/QUICHandshake.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 9dbbc5fb225..3a61698daaa 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -29,7 +29,7 @@ #include "QUICConfig.h" #include "P_SSLNextProtocolSet.h" -static constexpr char dump_tag[] = "quic_handshake_dump_pkt"; +static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; #define I_WANNA_DUMP_THIS_BUF(buf, len) \ { \ From b0df673a64bcd9df284f48886ed388272679a1ca Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 4 Oct 2017 13:00:08 -0700 Subject: [PATCH 0148/1313] Print hq and quic to Via header --- iocore/net/P_QUICNetVConnection.h | 3 +++ iocore/net/QUICNetVConnection.cc | 29 +++++++++++++++++++++++++++++ lib/ts/ink_inet.cc | 1 + lib/ts/ink_inet.h | 1 + proxy/hq/HQClientSession.cc | 13 +++++++++++++ proxy/hq/HQClientSession.h | 3 +++ 6 files changed, 50 insertions(+) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 82b89fc80f9..4c0ed6af03a 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -166,6 +166,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection virtual void net_read_io(NetHandler *nh, EThread *lthread) override; virtual int64_t load_buffer_and_write(int64_t towrite, MIOBufferAccessor &buf, int64_t &total_written, int &needs) override; + int populate_protocol(ts::StringView *results, int n) const override; + const char *protocol_contains(ts::StringView tag) const override; + // QUICNetVConnection void registerNextProtocolSet(SSLNextProtocolSet *s); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5962e966309..5261450ba9a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -576,6 +576,35 @@ QUICNetVConnection::load_buffer_and_write(int64_t towrite, MIOBufferAccessor &bu return 0; } +int +QUICNetVConnection::populate_protocol(ts::StringView *results, int n) const +{ + int retval = 0; + if (n > retval) { + results[retval] = IP_PROTO_TAG_QUIC; + if (results[retval]) { + ++retval; + } + if (n > retval) { + retval += super::populate_protocol(results + retval, n - retval); + } + } + return retval; +} + +const char * +QUICNetVConnection::protocol_contains(ts::StringView prefix) const +{ + const char *retval = nullptr; + ts::StringView tag = IP_PROTO_TAG_QUIC; + if (prefix.size() <= tag.size() && strncmp(tag.ptr(), prefix.ptr(), prefix.size()) == 0) { + retval = tag.ptr(); + } else { + retval = super::protocol_contains(prefix); + } + return retval; +} + void QUICNetVConnection::registerNextProtocolSet(SSLNextProtocolSet *s) { diff --git a/lib/ts/ink_inet.cc b/lib/ts/ink_inet.cc index 2467916c46f..188519ac63a 100644 --- a/lib/ts/ink_inet.cc +++ b/lib/ts/ink_inet.cc @@ -36,6 +36,7 @@ const ts::StringView IP_PROTO_TAG_IPV4("ipv4", ts::StringView::literal); const ts::StringView IP_PROTO_TAG_IPV6("ipv6", ts::StringView::literal); const ts::StringView IP_PROTO_TAG_UDP("udp", ts::StringView::literal); const ts::StringView IP_PROTO_TAG_TCP("tcp", ts::StringView::literal); +const ts::StringView IP_PROTO_TAG_QUIC("quic", ts::StringView::literal); const ts::StringView IP_PROTO_TAG_TLS_1_0("tls/1.0", ts::StringView::literal); const ts::StringView IP_PROTO_TAG_TLS_1_1("tls/1.1", ts::StringView::literal); const ts::StringView IP_PROTO_TAG_TLS_1_2("tls/1.2", ts::StringView::literal); diff --git a/lib/ts/ink_inet.h b/lib/ts/ink_inet.h index bca32a066ce..585eaca3589 100644 --- a/lib/ts/ink_inet.h +++ b/lib/ts/ink_inet.h @@ -50,6 +50,7 @@ extern const ts::StringView IP_PROTO_TAG_IPV4; extern const ts::StringView IP_PROTO_TAG_IPV6; extern const ts::StringView IP_PROTO_TAG_UDP; extern const ts::StringView IP_PROTO_TAG_TCP; +extern const ts::StringView IP_PROTO_TAG_QUIC; extern const ts::StringView IP_PROTO_TAG_TLS_1_0; extern const ts::StringView IP_PROTO_TAG_TLS_1_1; extern const ts::StringView IP_PROTO_TAG_TLS_1_2; diff --git a/proxy/hq/HQClientSession.cc b/proxy/hq/HQClientSession.cc index 27d19619630..ce4d6cc7d48 100644 --- a/proxy/hq/HQClientSession.cc +++ b/proxy/hq/HQClientSession.cc @@ -124,6 +124,19 @@ HQClientSession::release(ProxyClientTransaction *trans) return; } +int +HQClientSession::populate_protocol(ts::StringView *result, int size) const +{ + int retval = 0; + if (size > retval) { + result[retval++] = IP_PROTO_TAG_HTTP_QUIC; + if (size > retval) { + retval += super::populate_protocol(result + retval, size - retval); + } + } + return retval; +} + void HQClientSession::add_transaction(HQClientTransaction *trans) { diff --git a/proxy/hq/HQClientSession.h b/proxy/hq/HQClientSession.h index b3a4ce4b886..0eaecc82e4c 100644 --- a/proxy/hq/HQClientSession.h +++ b/proxy/hq/HQClientSession.h @@ -29,6 +29,8 @@ class HQClientSession : public ProxyClientSession { public: + typedef ProxyClientSession super; ///< Parent type. + HQClientSession(NetVConnection *vc); ~HQClientSession(); @@ -48,6 +50,7 @@ class HQClientSession : public ProxyClientSession int get_transact_count() const override; const char *get_protocol_string() const override; void release(ProxyClientTransaction *trans) override; + int populate_protocol(ts::StringView *result, int size) const override; // HQClientSession specific methods void add_transaction(HQClientTransaction *); From 51825180400fbc25a756ed45854ab3f20740cfa5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 5 Oct 2017 00:33:53 -0700 Subject: [PATCH 0149/1313] Postpone processing protected packets if handshake is not completed There's no guarantee that protected packets arrive after handshake completion because actual stream data is not processed on PACKET_READ_READY events. --- iocore/net/QUICNetVConnection.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5261450ba9a..cd2e832f3d0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -399,6 +399,12 @@ QUICNetVConnection::state_handshake(int event, Event *data) error = this->_state_handshake_process_zero_rtt_protected_packet(std::move(p)); break; } + case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: + case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: + // Postpone processing the packet + this->push_packet(std::move(p)); + this_ethread()->schedule_imm_local(this, event); + break; default: error = QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR)); break; From 99338bd3a4d9bfe4aff3eb7b3a29c4acb208c428 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 5 Oct 2017 04:57:17 -0700 Subject: [PATCH 0150/1313] Add connection id to debug logs from QUICLossDetector --- iocore/net/quic/QUICLossDetector.cc | 29 +++++++++++++++++------------ iocore/net/quic/QUICLossDetector.h | 2 ++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index ff9f98a565f..b9d3c10dd81 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -25,7 +25,8 @@ #include "QUICEvents.h" #include "ts/ink_assert.h" -static constexpr char tag[] = "quic_loss_detector"; +#define DebugQUICLD(fmt, ...) \ + Debug("quic_loss_detector", "[%" PRIx64 "] " fmt, static_cast(this->_connection_id), ##__VA_ARGS__) QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter) : _transmitter(transmitter) { @@ -52,7 +53,7 @@ QUICLossDetector::event_handler(int event, Event *edata) } case QUIC_EVENT_LD_SHUTDOWN: { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - Debug("quic_loss_detector", "Shutdown"); + DebugQUICLD("Shutdown"); if (this->_loss_detection_alarm) { this->_loss_detection_alarm->cancel(); @@ -81,7 +82,7 @@ QUICLossDetector::handle_frame(std::shared_ptr frame) this->_on_ack_received(std::dynamic_pointer_cast(frame)); break; default: - Debug("quic_loss_detector", "Unexpected frame type: %02x", static_cast(frame->type())); + DebugQUICLD("Unexpected frame type: %02x", static_cast(frame->type())); ink_assert(false); break; } @@ -138,6 +139,10 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num void QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) { + if (this->_connection_id == 0) { + this->_connection_id = packet->connection_id(); + } + bool is_handshake = false; QUICPacketType type = packet->type(); if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && @@ -192,7 +197,7 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac } this->_detect_lost_packets(ack_frame->largest_acknowledged()); - Debug(tag, "Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, this->_retransmittable_outstanding); + DebugQUICLD("Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, this->_retransmittable_outstanding); this->_set_loss_detection_alarm(); } @@ -200,7 +205,7 @@ void QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - Debug(tag, "Packet number %" PRIu64 " has been acked", acked_packet_number); + DebugQUICLD("Packet number %" PRIu64 " has been acked", acked_packet_number); // If a packet sent prior to RTO was acked, then the RTO // was spurious. Otherwise, inform congestion control. if (this->_rto_count > 0 && acked_packet_number > this->_largest_sent_before_rto) { @@ -250,7 +255,7 @@ QUICLossDetector::_on_loss_detection_alarm() // eventProcessor.schedule_imm(this->_handler, ET_CALL, QUIC_EVENT_RETRANSMIT_TWO_PACKET); this->_rto_count++; } - Debug(tag, "Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, this->_retransmittable_outstanding); + DebugQUICLD("Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, this->_retransmittable_outstanding); this->_set_loss_detection_alarm(); } @@ -274,7 +279,7 @@ QUICLossDetector::_set_loss_detection_alarm() if (!this->_retransmittable_outstanding && this->_loss_detection_alarm) { this->_loss_detection_alarm->cancel(); this->_loss_detection_alarm = nullptr; - Debug(tag, "Loss detection alarm has been unset"); + DebugQUICLD("Loss detection alarm has been unset"); return; } if (this->_handshake_outstanding) { @@ -286,11 +291,11 @@ QUICLossDetector::_set_loss_detection_alarm() } alarm_duration = std::max(alarm_duration, this->_MIN_TLP_TIMEOUT); alarm_duration = alarm_duration * (1 << this->_handshake_count); - Debug(tag, "Handshake retransmission alarm will be set"); + DebugQUICLD("Handshake retransmission alarm will be set"); } else if (this->_loss_time != 0) { // Early retransmit timer or time loss detection. alarm_duration = this->_loss_time - Thread::get_hrtime(); - Debug(tag, "Early retransmit timer or time loss detection will be set"); + DebugQUICLD("Early retransmit timer or time loss detection will be set"); } else if (this->_tlp_count < this->_MAX_TLPS) { // Tail Loss Probe if (this->_retransmittable_outstanding) { @@ -299,20 +304,20 @@ QUICLossDetector::_set_loss_detection_alarm() alarm_duration = this->_MIN_TLP_TIMEOUT; } alarm_duration = std::max(alarm_duration, 2 * this->_smoothed_rtt); - Debug(tag, "TLP alarm will be set"); + DebugQUICLD("TLP alarm will be set"); } else { // RTO alarm alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar; alarm_duration = std::max(alarm_duration, this->_MIN_RTO_TIMEOUT); alarm_duration = alarm_duration * (1 << this->_rto_count); - Debug(tag, "RTO alarm will be set"); + DebugQUICLD("RTO alarm will be set"); } if (this->_loss_detection_alarm) { this->_loss_detection_alarm->cancel(); } this->_loss_detection_alarm = eventProcessor.schedule_in(this, alarm_duration); - Debug(tag, "Loss detection alarm has been set to %" PRId64, alarm_duration); + DebugQUICLD("Loss detection alarm has been set to %" PRId64, alarm_duration); } std::set diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 1ffa8eb178a..a899f995991 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -51,6 +51,8 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler QUICPacketNumber largest_acked_packet_number(); private: + QUICConnectionId _connection_id = 0; + struct PacketInfo { QUICPacketNumber packet_number; ink_hrtime time; From 6e223b7fe1e19f5df7d75152f89a571e29e355c2 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 5 Oct 2017 05:42:51 -0700 Subject: [PATCH 0151/1313] Add connection id to debug logs from QUICStream --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICStream.cc | 44 +++++++++---------- iocore/net/quic/QUICStream.h | 12 ++--- iocore/net/quic/QUICStreamManager.cc | 9 ++-- iocore/net/quic/QUICStreamManager.h | 3 +- iocore/net/quic/test/test_QUICFrame.cc | 2 +- iocore/net/quic/test/test_QUICStream.cc | 6 +-- .../net/quic/test/test_QUICStreamManager.cc | 8 ++-- 8 files changed, 45 insertions(+), 41 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index cd2e832f3d0..9819b51109c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -107,7 +107,7 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) this->_packet_factory.set_crypto_module(this->_crypto); // Create frame handlers - this->_stream_manager = new QUICStreamManager(this, this->_application_map); + this->_stream_manager = new QUICStreamManager(this->connection_id(), this, this->_application_map); this->_congestion_controller = new QUICCongestionController(); this->_loss_detector = new QUICLossDetector(this); this->_remote_flow_controller = new QUICRemoteConnectionFlowController(0, this); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index a6fd6004595..7a7bbdc13f6 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -28,15 +28,21 @@ #include "QUICDebugNames.h" #include "QUICConfig.h" -#define DebugQUICStream(fmt, ...) \ - Debug("quic_stream", "[%" PRIx32 "] [%s] " fmt, this->_id, QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) +#define DebugQUICStream(fmt, ...) \ + Debug("quic_stream", "[%" PRIx64 "] [%" PRIx32 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ + QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) +#define DebugQUICStreamFC(fmt, ...) \ + Debug("quic_flow_ctrl", "[%" PRIx64 "] [%" PRIx32 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ + QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) void -QUICStream::init(QUICFrameTransmitter *tx, QUICStreamId id, uint64_t recv_max_stream_data, uint64_t send_max_stream_data) +QUICStream::init(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data, + uint64_t send_max_stream_data) { this->mutex = new_ProxyMutex(); this->_tx = tx; - this->_id = id; + this->_connection_id = cid; + this->_id = sid; this->_remote_flow_controller = new QUICRemoteStreamFlowController(send_max_stream_data, _tx, _id); this->_local_flow_controller = new QUICLocalStreamFlowController(recv_max_stream_data, _tx, _id); this->init_flow_control_params(recv_max_stream_data, send_max_stream_data); @@ -56,12 +62,10 @@ QUICStream::init_flow_control_params(uint32_t recv_max_stream_data, uint32_t sen this->_flow_control_buffer_size = recv_max_stream_data; this->_local_flow_controller->forward_limit(recv_max_stream_data); this->_remote_flow_controller->forward_limit(send_max_stream_data); - Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [LOCAL] %" PRIu64 "/%" PRIu64, this->_id, - QUICDebugNames::stream_state(this->_state), this->_local_flow_controller->current_offset(), - this->_local_flow_controller->current_limit()); - Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [REMOTE] %" PRIu64 "/%" PRIu64, this->_id, - QUICDebugNames::stream_state(this->_state), this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); + DebugQUICStreamFC("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); + DebugQUICStreamFC("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); } QUICStreamId @@ -271,9 +275,8 @@ QUICStream::_write_to_read_vio(const std::shared_ptr &fra this->_read_vio.nbytes += bytes_added; this->_recv_offset += frame->data_length(); this->_local_flow_controller->forward_limit(this->_recv_offset + this->_flow_control_buffer_size); - Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [LOCAL] %" PRIu64 "/%" PRIu64, this->_id, - QUICDebugNames::stream_state(this->_state), this->_local_flow_controller->current_offset(), - this->_local_flow_controller->current_limit()); + DebugQUICStreamFC("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); this->_state.update_with_received_frame(*frame); } @@ -308,9 +311,8 @@ QUICStream::recv(const std::shared_ptr frame) // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit QUICErrorUPtr error = this->_local_flow_controller->update(frame->offset() + frame->data_length()); - Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [LOCAL] %" PRIu64 "/%" PRIu64, this->_id, - QUICDebugNames::stream_state(this->_state), this->_local_flow_controller->current_offset(), - this->_local_flow_controller->current_limit()); + DebugQUICStreamFC("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); if (error->cls != QUICErrorClass::NONE) { return error; } @@ -335,9 +337,8 @@ QUICErrorUPtr QUICStream::recv(const std::shared_ptr frame) { this->_remote_flow_controller->forward_limit(frame->maximum_stream_data()); - Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [REMOTE] %" PRIu64 "/%" PRIu64, this->_id, - QUICDebugNames::stream_state(this->_state), this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); + DebugQUICStreamFC("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); this->reenable(&this->_write_vio); @@ -381,9 +382,8 @@ QUICStream::_send() } error = this->_remote_flow_controller->update(this->_send_offset + len); - Debug("quic_flow_ctrl", "Stream [%" PRIx32 "] [%s] [REMOTE] %" PRIu64 "/%" PRIu64, this->_id, - QUICDebugNames::stream_state(this->_state), this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); + DebugQUICStreamFC("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); if (error->cls != QUICErrorClass::NONE) { break; } diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index a916ead5cb0..b1d07655a99 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -46,7 +46,8 @@ class QUICStream : public VConnection public: QUICStream() : VConnection(nullptr) {} ~QUICStream() {} - void init(QUICFrameTransmitter *tx, uint32_t id, uint64_t recv_max_stream_data = 0, uint64_t send_max_stream_data = 0); + void init(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId id, uint64_t recv_max_stream_data = 0, + uint64_t send_max_stream_data = 0); void start(); void init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data); int main_event_handler(int event, void *data); @@ -91,10 +92,11 @@ class QUICStream : public VConnection Event *_send_tracked_event(Event *event, int send_event, VIO *vio); - bool _fin = false; - QUICStreamId _id = 0; - QUICOffset _recv_offset = 0; - QUICOffset _send_offset = 0; + bool _fin = false; + QUICConnectionId _connection_id = 0; + QUICStreamId _id = 0; + QUICOffset _recv_offset = 0; + QUICOffset _send_offset = 0; QUICRemoteStreamFlowController *_remote_flow_controller = nullptr; QUICLocalStreamFlowController *_local_flow_controller = nullptr; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 2832328e80c..47b4bbe4117 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -25,14 +25,14 @@ #include "QUICApplication.h" #include "QUICTransportParameters.h" -#include "QUICConnection.h" static constexpr char tag[] = "quic_stream_manager"; ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); ClassAllocator quicStreamAllocator("quicStreamAllocator"); -QUICStreamManager::QUICStreamManager(QUICFrameTransmitter *tx, QUICApplicationMap *app_map) : _tx(tx), _app_map(app_map) +QUICStreamManager::QUICStreamManager(QUICConnectionId cid, QUICFrameTransmitter *tx, QUICApplicationMap *app_map) + : _connection_id(cid), _tx(tx), _app_map(app_map) { } @@ -205,13 +205,14 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream(); if (stream_id == STREAM_ID_FOR_HANDSHAKE) { // XXX rece/send max_stream_data are going to be set by init_flow_control_params() - stream->init(this->_tx, stream_id, this->_local_tp->initial_max_stream_data()); + stream->init(this->_tx, this->_connection_id, stream_id, this->_local_tp->initial_max_stream_data()); } else { const QUICTransportParameters &local_tp = *this->_local_tp; const QUICTransportParameters &remote_tp = *this->_remote_tp; // TODO: check local_tp and remote_tp is initialized - stream->init(this->_tx, stream_id, local_tp.initial_max_stream_data(), remote_tp.initial_max_stream_data()); + stream->init(this->_tx, this->_connection_id, stream_id, local_tp.initial_max_stream_data(), + remote_tp.initial_max_stream_data()); } stream->start(); diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index b6ad75f42a1..e067cc1b631 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -36,7 +36,7 @@ class QUICStreamManager : public QUICFrameHandler { public: QUICStreamManager(){}; - QUICStreamManager(QUICFrameTransmitter *tx, QUICApplicationMap *app_map); + QUICStreamManager(QUICConnectionId cid, QUICFrameTransmitter *tx, QUICApplicationMap *app_map); void init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); @@ -64,6 +64,7 @@ class QUICStreamManager : public QUICFrameHandler QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICErrorUPtr _handle_frame(const std::shared_ptr &); + QUICConnectionId _connection_id = 0; QUICFrameTransmitter *_tx = nullptr; QUICApplicationMap *_app_map = nullptr; std::shared_ptr _local_tp = nullptr; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index be140b3d694..90c82fb77b8 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -731,7 +731,7 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") { QUICStream stream; - stream.init(new MockQUICFrameTransmitter(), 0x1234, 0, 0); + stream.init(new MockQUICFrameTransmitter(), 0, 0x1234, 0, 0); std::unique_ptr error = std::unique_ptr(new QUICStreamError(&stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR)); std::unique_ptr rst_stream_frame1 = diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 545d3530bc4..632ad912f29 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -48,7 +48,7 @@ TEST_CASE("QUICStream_assembling_byte_stream_1", "[quic]") MockQUICFrameTransmitter tx; std::unique_ptr stream(new QUICStream()); - stream->init(&tx, stream_id, 1024, 1024); + stream->init(&tx, 0, stream_id, 1024, 1024); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_1); @@ -75,7 +75,7 @@ TEST_CASE("QUICStream_assembling_byte_stream_2", "[quic]") MockQUICFrameTransmitter tx; std::unique_ptr stream(new QUICStream()); - stream->init(&tx, stream_id); + stream->init(&tx, 0, stream_id); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -102,7 +102,7 @@ TEST_CASE("QUICStream_assembling_byte_stream_3", "[quic]") MockQUICFrameTransmitter tx; std::unique_ptr stream(new QUICStream()); - stream->init(&tx, stream_id); + stream->init(&tx, 0, stream_id); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 1a14a3605d9..f9490c961fb 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -35,7 +35,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(&tx, &app_map); + QUICStreamManager sm(0, &tx, &app_map); std::shared_ptr local_tp = std::make_shared(); std::shared_ptr remote_tp = std::make_shared(static_cast(0), static_cast(0)); @@ -80,7 +80,7 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(&tx, &app_map); + QUICStreamManager sm(0, &tx, &app_map); std::shared_ptr local_tp = std::make_shared(); std::shared_ptr remote_tp = std::make_shared(static_cast(0), static_cast(0)); @@ -100,7 +100,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(&tx, &app_map); + QUICStreamManager sm(0, &tx, &app_map); std::shared_ptr local_tp = std::make_shared(); local_tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, std::unique_ptr(new QUICTransportParameterValue(4096, 4))); @@ -134,7 +134,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(&tx, &app_map); + QUICStreamManager sm(0, &tx, &app_map); std::shared_ptr local_tp = std::make_shared(); local_tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, std::unique_ptr(new QUICTransportParameterValue(4096, 4))); From 239ffeee50c3514dbc6f957100f6601e6c7db592 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 5 Oct 2017 06:09:05 -0700 Subject: [PATCH 0152/1313] Add connection id to debug logs from QUICPacketHandler --- iocore/net/QUICPacketHandler.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 2c8dfb91aa5..e2e0c225b1a 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -66,10 +66,7 @@ QUICPacketHandler::acceptEvent(int event, void *data) } else if (event == NET_EVENT_DATAGRAM_READ_READY) { Queue *queue = (Queue *)data; UDPPacket *packet_r; - ip_port_text_buffer ipb; while ((packet_r = queue->dequeue())) { - Debug("quic_sec", "received packet from %s, size=%" PRId64, ats_ip_nptop(&packet_r->from.sa, ipb, sizeof(ipb)), - packet_r->getPktLength()); this->_recv_packet(event, packet_r); } return EVENT_CONT; @@ -121,6 +118,10 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) QUICConnectionId cid; bool res = this->_read_connection_id(cid, block); + ip_port_text_buffer ipb; + Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), + ats_ip_nptop(&udpPacket->from.sa, ipb, sizeof(ipb)), udpPacket->getPktLength()); + QUICNetVConnection *vc = nullptr; if (res) { vc = this->_connections.get(cid); @@ -198,8 +199,8 @@ QUICPacketHandler::send_packet(const QUICPacket &packet, UDPConnection *udp_con, // NOTE: p will be enqueued to udpOutQueue of UDPNetHandler ip_port_text_buffer ipb; - Debug("quic_sec", "send %s packet to %s, size=%" PRId64, QUICDebugNames::packet_type(packet.type()), - ats_ip_nptop(&udpPkt->to.sa, ipb, sizeof(ipb)), udpPkt->getPktLength()); + Debug("quic_sec", "[%" PRIx64 "] send %s packet to %s, size=%" PRId64, static_cast(packet.connection_id()), + QUICDebugNames::packet_type(packet.type()), ats_ip_nptop(&udpPkt->to.sa, ipb, sizeof(ipb)), udpPkt->getPktLength()); udp_con->send(this, udpPkt); } From 05a419ec6dfa3d58ca4b16ea00c768089b639076 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 5 Oct 2017 06:31:07 -0700 Subject: [PATCH 0153/1313] Add connection id to debug logs from QUICHandshake --- iocore/net/quic/QUICHandshake.cc | 38 +++++++++++++++++--------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 3a61698daaa..aa5930c54b8 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -31,6 +31,9 @@ static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; +#define DebugQHS(fmt, ...) \ + Debug("quic_handshake", "[%" PRIx64 "] " fmt, static_cast(this->_client_qc->connection_id()), ##__VA_ARGS__) + #define I_WANNA_DUMP_THIS_BUF(buf, len) \ { \ int i; \ @@ -74,7 +77,6 @@ static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; } \ } -static constexpr char tag[] = "quic_handshake"; static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527; @@ -107,12 +109,12 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet } if (initial_packet->version()) { if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { - Debug(tag, "Version negotiation succeeded: %x", initial_packet->version()); + DebugQHS("Version negotiation succeeded: %x", initial_packet->version()); packet_factory->set_version(this->_version_negotiator->negotiated_version()); } else { this->_client_qc->transmit_packet( packet_factory->create_version_negotiation_packet(initial_packet, _client_qc->largest_acked_packet_number())); - Debug(tag, "Version negotiation failed: %x", initial_packet->version()); + DebugQHS("Version negotiation failed: %x", initial_packet->version()); } } else { return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION)); @@ -163,11 +165,11 @@ QUICHandshake::set_transport_parameters(std::shared_ptr if (this->_version_negotiator->revalidate(tp_in_ch) != QUICVersionNegotiationStatus::REVALIDATED) { this->_client_qc->close( QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::VERSION_NEGOTIATION_ERROR))); - Debug(tag, "Enter state_closed"); + DebugQHS("Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); return; } - Debug(tag, "Version negotiation revalidated: %x", tp_in_ch->negotiated_version()); + DebugQHS("Version negotiation revalidated: %x", tp_in_ch->negotiated_version()); return; } @@ -202,7 +204,7 @@ QUICHandshake::state_read_client_hello(int event, Event *data) break; } default: - Debug(tag, "event: %d", event); + DebugQHS("event: %d", event); break; } @@ -213,7 +215,7 @@ QUICHandshake::state_read_client_hello(int event, Event *data) this->_client_qc->close( QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION))); } - Debug(tag, "Enter state_closed"); + DebugQHS("Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); } @@ -231,7 +233,7 @@ QUICHandshake::state_read_client_finished(int event, Event *data) break; } default: - Debug(tag, "event: %d", event); + DebugQHS("event: %d", event); break; } @@ -242,7 +244,7 @@ QUICHandshake::state_read_client_finished(int event, Event *data) this->_client_qc->close( QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION))); } - Debug(tag, "Enter state_closed"); + DebugQHS("Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); } @@ -259,8 +261,8 @@ QUICHandshake::state_address_validation(int event, void *data) int QUICHandshake::state_complete(int event, void *data) { - Debug(tag, "event: %d", event); - Debug(tag, "Got an event on complete state. Ignoring it for now."); + DebugQHS("event: %d", event); + DebugQHS("Got an event on complete state. Ignoring it for now."); return EVENT_CONT; } @@ -314,7 +316,7 @@ QUICHandshake::_process_client_hello() stream_io->read(msg, msg_len); if (msg_len <= 0) { - Debug(tag, "No message"); + DebugQHS("No message"); return QUICErrorUPtr(new QUICNoError()); } @@ -334,7 +336,7 @@ QUICHandshake::_process_client_hello() I_WANNA_DUMP_THIS_BUF(server_hello, static_cast(server_hello_len)); // <----- DEBUG ----- - Debug(tag, "Enter state_read_client_finished"); + DebugQHS("Enter state_read_client_finished"); SET_HANDLER(&QUICHandshake::state_read_client_finished); stream_io->write(server_hello, server_hello_len); @@ -358,7 +360,7 @@ QUICHandshake::_process_client_finished() stream_io->read(msg, msg_len); if (msg_len <= 0) { - Debug(tag, "No message"); + DebugQHS("No message"); return QUICErrorUPtr(new QUICNoError()); } @@ -379,9 +381,9 @@ QUICHandshake::_process_client_finished() // <----- DEBUG ----- ink_assert(this->is_completed()); - Debug(tag, "Handshake is completed"); + DebugQHS("Handshake is completed"); - Debug(tag, "Enter state_complete"); + DebugQHS("Enter state_complete"); SET_HANDLER(&QUICHandshake::state_complete); _process_handshake_complete(); @@ -402,9 +404,9 @@ QUICHandshake::_process_handshake_complete() int r = crypto->setup_session(); if (r) { - Debug(tag, "Keying Materials are exported"); + DebugQHS("Keying Materials are exported"); } else { - Debug(tag, "Failed to export Keying Materials"); + DebugQHS("Failed to export Keying Materials"); } return QUICErrorUPtr(new QUICNoError()); From e07806283172cd91256fc12235738e07607e0742 Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Thu, 5 Oct 2017 12:00:14 -0700 Subject: [PATCH 0154/1313] Moved the set handler in QUICNetVConnection constructor to init method --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 4c0ed6af03a..339f92edc6a 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -143,7 +143,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection using super = UnixNetVConnection; ///< Parent type. public: - QUICNetVConnection(); + QUICNetVConnection() {} void init(UDPConnection *, QUICPacketHandler *); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 9819b51109c..a941336bd7f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -52,15 +52,11 @@ static constexpr uint32_t MINIMUM_INITIAL_CLIENT_PACKET_SIZE = 1200; ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); -QUICNetVConnection::QUICNetVConnection() : UnixNetVConnection() -{ - SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_pre_handshake); -} - // XXX This might be called on ET_UDP thread void QUICNetVConnection::init(UDPConnection *udp_con, QUICPacketHandler *packet_handler) { + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_pre_handshake); this->_packet_transmitter_mutex = new_ProxyMutex(); this->_frame_transmitter_mutex = new_ProxyMutex(); this->_udp_con = udp_con; From 6df84c9fb9a4ba936bd747e8509e56ea32d4f903 Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Thu, 5 Oct 2017 13:21:29 -0700 Subject: [PATCH 0155/1313] Call the QUICFrame destructor before freeing into the ClassAllocator --- iocore/net/quic/QUICFrame.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 0b1e554c4f7..772d65a6a91 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -40,6 +40,7 @@ class QUICFrame virtual void store(uint8_t *buf, size_t *len) const = 0; virtual void reset(const uint8_t *buf, size_t len); static QUICFrameType type(const uint8_t *buf); + virtual ~QUICFrame() {} LINK(QUICFrame, link); @@ -182,7 +183,7 @@ class QUICAckFrame : public QUICFrame QUICAckFrame() : QUICFrame() {} QUICAckFrame(const uint8_t *buf, size_t len); QUICAckFrame(QUICPacketNumber largest_acknowledged, uint16_t ack_delay, uint64_t first_ack_block_length); - ~QUICAckFrame(); + virtual ~QUICAckFrame(); virtual void reset(const uint8_t *buf, size_t len) override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -486,6 +487,7 @@ class QUICFrameDeleter static void delete_ack_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicAckFrameAllocator.free(static_cast(frame)); } From 2f5caad25df450b16f9458c7119a421652f6ddb5 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 10 Oct 2017 08:19:00 +0800 Subject: [PATCH 0156/1313] add QUICInBuffer feature --- iocore/net/quic/Makefile.am | 3 +- iocore/net/quic/QUICIncomingFrameBuffer.cc | 135 +++++++++++++ iocore/net/quic/QUICIncomingFrameBuffer.h | 58 ++++++ iocore/net/quic/QUICStream.cc | 36 ++-- iocore/net/quic/QUICStream.h | 7 +- iocore/net/quic/test/Makefile.am | 35 +++- .../quic/test/test_QUICIncomingFrameBuffer.cc | 177 ++++++++++++++++++ 7 files changed, 421 insertions(+), 30 deletions(-) create mode 100644 iocore/net/quic/QUICIncomingFrameBuffer.cc create mode 100644 iocore/net/quic/QUICIncomingFrameBuffer.h create mode 100644 iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 90ba2fe480a..3fc25857daa 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -61,7 +61,8 @@ libquic_a_SOURCES = \ QUICConfig.cc \ QUICDebugNames.cc \ QUICApplication.cc \ - QUICApplicationMap.cc + QUICApplicationMap.cc \ + QUICIncomingFrameBuffer.cc include $(top_srcdir)/build/tidy.mk diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc new file mode 100644 index 00000000000..e7690541afc --- /dev/null +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -0,0 +1,135 @@ +/** @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 "QUICIncomingFrameBuffer.h" + +QUICIncomingFrameBuffer::~QUICIncomingFrameBuffer() +{ + this->_out_of_order_queue.clear(); + + while (!this->_recv_buffer.empty()) { + this->_recv_buffer.pop(); + } +} + +std::shared_ptr +QUICIncomingFrameBuffer::pop() +{ + if (this->_recv_buffer.empty()) { + auto frame = this->_out_of_order_queue.find(this->_recv_offset); + while (frame != this->_out_of_order_queue.end()) { + this->_recv_buffer.push(frame->second); + this->_recv_offset += frame->second->data_length(); + this->_out_of_order_queue.erase(frame); + frame = this->_out_of_order_queue.find(this->_recv_offset); + } + } + + if (!this->_recv_buffer.empty()) { + auto frame = this->_recv_buffer.front(); + this->_recv_buffer.pop(); + return frame; + } + return nullptr; +} + +QUICErrorUPtr +QUICIncomingFrameBuffer::insert(const std::shared_ptr frame) +{ + QUICOffset offset = frame->offset(); + size_t len = frame->data_length(); + + QUICErrorUPtr err = this->_check_and_set_fin_flag(offset, len, frame->has_fin_flag()); + if (err->cls != QUICErrorClass::NONE) { + return err; + } + + if (this->_recv_offset > offset) { + // dup frame; + return QUICErrorUPtr(new QUICNoError()); + } else if (this->_recv_offset == offset) { + this->_recv_offset = offset + len; + this->_recv_buffer.push(frame); + } else { + this->_out_of_order_queue.insert(std::make_pair(offset, frame)); + } + + return QUICErrorUPtr(new QUICNoError()); +} + +void +QUICIncomingFrameBuffer::clear() +{ + this->_out_of_order_queue.clear(); + + while (!this->_recv_buffer.empty()) { + this->_recv_buffer.pop(); + } + + this->_fin_offset = UINT64_MAX; + this->_max_offset = 0; + this->_recv_offset = 0; +} + +bool +QUICIncomingFrameBuffer::empty() +{ + return this->_out_of_order_queue.empty() && this->_recv_buffer.empty(); +} + +QUICErrorUPtr +QUICIncomingFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, bool fin_flag) +{ + // stream with fin flag {11.3. Stream Final Offset} + // Once a final offset for a stream is known, it cannot change. + // If a RST_STREAM or STREAM frame causes the final offset to change for a stream, + // an endpoint SHOULD respond with a FINAL_OFFSET_ERROR error (see Section 12). + // A receiver SHOULD treat receipt of data at or beyond the final offset as a + // FINAL_OFFSET_ERROR error, even after a stream is closed. + + // {11.3. Stream Final Offset} + // A receiver SHOULD treat receipt of data at or beyond the final offset as a + // FINAL_OFFSET_ERROR error, even after a stream is closed. + if (fin_flag) { + if (this->_fin_offset != UINT64_MAX) { + if (this->_fin_offset == offset) { + // dup fin frame + return QUICErrorUPtr(new QUICNoError()); + } + return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FINAL_OFFSET_ERROR)); + } + + this->_fin_offset = offset; + + if (this->_max_offset >= this->_fin_offset) { + return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FINAL_OFFSET_ERROR)); + } + + } else if (this->_fin_offset != UINT64_MAX && this->_fin_offset <= offset) { + return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FINAL_OFFSET_ERROR)); + } + + this->_max_offset = std::max(offset, this->_max_offset); + + return QUICErrorUPtr(new QUICNoError()); +} diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h new file mode 100644 index 00000000000..ab79a44f797 --- /dev/null +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -0,0 +1,58 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "QUICTypes.h" +#include "QUICFrame.h" + +class QUICIncomingFrameBuffer +{ +public: + QUICIncomingFrameBuffer(QUICStream *stream) : _stream(stream) {} + + ~QUICIncomingFrameBuffer(); + + std::shared_ptr pop(); + + QUICErrorUPtr insert(const std::shared_ptr); + + void clear(); + + bool empty(); + +private: + QUICOffset _recv_offset = 0; + QUICOffset _max_offset = 0; + QUICOffset _fin_offset = UINT64_MAX; + + QUICErrorUPtr _check_and_set_fin_flag(QUICOffset offset, size_t len = 0, bool fin_flag = false); + + std::queue> _recv_buffer; + std::map> _out_of_order_queue; + + QUICStream *_stream = nullptr; +}; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 7a7bbdc13f6..f0ec0ff1197 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -273,25 +273,14 @@ QUICStream::_write_to_read_vio(const std::shared_ptr &fra int bytes_added = this->_read_vio.buffer.writer()->write(frame->data(), frame->data_length()); this->_read_vio.nbytes += bytes_added; - this->_recv_offset += frame->data_length(); - this->_local_flow_controller->forward_limit(this->_recv_offset + this->_flow_control_buffer_size); + // frame->offset() + frame->data_length() == this->_recv_offset + this->_local_flow_controller->forward_limit(frame->offset() + frame->data_length() + this->_flow_control_buffer_size); DebugQUICStreamFC("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); this->_state.update_with_received_frame(*frame); } -void -QUICStream::_reorder_data() -{ - auto frame = _received_stream_frame_buffer.find(this->_recv_offset); - while (frame != this->_received_stream_frame_buffer.end()) { - this->_write_to_read_vio(frame->second); - this->_received_stream_frame_buffer.erase(frame); - frame = _received_stream_frame_buffer.find(this->_recv_offset); - } -} - /** * @brief Receive STREAM frame * @detail When receive STREAM frame, reorder frames and write to buffer of read_vio. @@ -317,17 +306,16 @@ QUICStream::recv(const std::shared_ptr frame) return error; } - // Reordering - Some frames may be delayed or be dropped - if (this->_recv_offset > frame->offset()) { - // Do nothing. Just ignore STREAM frame. - return QUICErrorUPtr(new QUICNoError()); - } else if (this->_recv_offset == frame->offset()) { - this->_write_to_read_vio(frame); - this->_reorder_data(); - } else { - // NOTE: push fragments in _received_stream_frame_buffer temporally. - // They will be reordered when missing data is filled and offset is matched. - this->_received_stream_frame_buffer.insert(std::make_pair(frame->offset(), frame)); + error = this->_received_stream_frame_buffer.insert(frame); + if (error->cls != QUICErrorClass::NONE) { + this->_received_stream_frame_buffer.clear(); + return error; + } + + auto new_frame = this->_received_stream_frame_buffer.pop(); + while (new_frame != nullptr) { + this->_write_to_read_vio(new_frame); + new_frame = this->_received_stream_frame_buffer.pop(); } return QUICErrorUPtr(new QUICNoError()); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index b1d07655a99..282b434c87a 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -31,6 +31,7 @@ #include "QUICFrame.h" #include "QUICStreamState.h" #include "QUICFlowController.h" +#include "QUICIncomingFrameBuffer.h" class QUICNetVConnection; class QUICFrameTransmitter; @@ -44,7 +45,7 @@ class QUICStreamManager; class QUICStream : public VConnection { public: - QUICStream() : VConnection(nullptr) {} + QUICStream() : VConnection(nullptr), _received_stream_frame_buffer(this) {} ~QUICStream() {} void init(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId id, uint64_t recv_max_stream_data = 0, uint64_t send_max_stream_data = 0); @@ -82,7 +83,6 @@ class QUICStream : public VConnection QUICErrorUPtr _send(); void _write_to_read_vio(const std::shared_ptr &); - void _reorder_data(); // NOTE: Those are called update_read_request/update_write_request in Http2Stream // void _read_from_net(uint64_t read_len, bool direct); // void _write_to_net(IOBufferReader *buf_reader, int64_t write_len, bool direct); @@ -95,7 +95,6 @@ class QUICStream : public VConnection bool _fin = false; QUICConnectionId _connection_id = 0; QUICStreamId _id = 0; - QUICOffset _recv_offset = 0; QUICOffset _send_offset = 0; QUICRemoteStreamFlowController *_remote_flow_controller = nullptr; @@ -110,7 +109,7 @@ class QUICStream : public VConnection // Fragments of received STREAM frame (offset is unmatched) // TODO: Consider to replace with ts/RbTree.h or other data structure - std::map> _received_stream_frame_buffer; + QUICIncomingFrameBuffer _received_stream_frame_buffer; QUICStreamManager *_stream_manager = nullptr; QUICFrameTransmitter *_tx = nullptr; diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 487e5328e0d..e25ecedf306 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -31,7 +31,8 @@ check_PROGRAMS = \ test_QUICTypeUtil \ test_QUICAckFrameCreator \ test_QUICVersionNegotiator \ - test_QUICFlowController + test_QUICFlowController \ + test_QUICIncomingFrameBuffer AM_CPPFLAGS += \ @@ -220,6 +221,7 @@ test_QUICStream_SOURCES = \ event_processor_main.cc \ test_QUICStream.cc \ ../QUICStream.cc \ + ../QUICIncomingFrameBuffer.cc \ ../QUICFrameDispatcher.cc \ ../QUICStreamManager.cc \ ../QUICApplicationMap.cc \ @@ -489,6 +491,37 @@ test_QUICFlowController_SOURCES = \ $(QUICCrypto_impl) \ ../QUICFrame.cc +# +# test_QUICIncomingFrameBuffer +# +test_QUICIncomingFrameBuffer_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICIncomingFrameBuffer_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICIncomingFrameBuffer_SOURCES = \ + event_processor_main.cc \ + ../QUICStream.cc \ + ../QUICFrameDispatcher.cc \ + ../QUICStreamManager.cc \ + ../QUICApplicationMap.cc \ + ../QUICCongestionController.cc \ + ../../SSLNextProtocolSet.cc \ + ../QUICIncomingFrameBuffer.cc \ + test_QUICIncomingFrameBuffer.cc + +test_QUICIncomingFrameBuffer_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ + include $(top_srcdir)/build/tidy.mk tidy-local: $(DIST_SOURCES) diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc new file mode 100644 index 00000000000..844607a63dc --- /dev/null +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -0,0 +1,177 @@ +/** @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 "catch.hpp" + +#include "quic/QUICIncomingFrameBuffer.h" +#include "quic/QUICStream.h" +#include + +TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") +{ + QUICStream *stream = new QUICStream(); + QUICIncomingFrameBuffer buffer(stream); + QUICErrorUPtr err = nullptr; + + uint8_t data[1024] = {0}; + + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); + std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); + std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); + std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 3072, true); + std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 4096); + + buffer.insert(stream1_frame_0_r); + buffer.insert(stream1_frame_1_r); + buffer.insert(stream1_frame_2_r); + err = buffer.insert(stream1_frame_3_r); + CHECK(err->code == QUICErrorCode::FINAL_OFFSET_ERROR); + + QUICIncomingFrameBuffer buffer2(stream); + + buffer2.insert(stream1_frame_3_r); + buffer2.insert(stream1_frame_0_r); + buffer2.insert(stream1_frame_1_r); + err = buffer2.insert(stream1_frame_2_r); + CHECK(err->code == QUICErrorCode::FINAL_OFFSET_ERROR); + + QUICIncomingFrameBuffer buffer3(stream); + + buffer3.insert(stream1_frame_4_r); + err = buffer3.insert(stream1_frame_3_r); + CHECK(err->code == QUICErrorCode::FINAL_OFFSET_ERROR); + + delete stream; +} + +TEST_CASE("QUICIncomingFrameBuffer_pop", "[quic]") +{ + QUICStream *stream = new QUICStream(); + QUICIncomingFrameBuffer buffer(stream); + QUICErrorUPtr err = nullptr; + + uint8_t data[1024] = {0}; + + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); + std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); + std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048); + std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 3072); + std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 4096, true); + + buffer.insert(stream1_frame_0_r); + buffer.insert(stream1_frame_1_r); + buffer.insert(stream1_frame_2_r); + buffer.insert(stream1_frame_3_r); + buffer.insert(stream1_frame_4_r); + CHECK(!buffer.empty()); + + auto frame = buffer.pop(); + CHECK(frame->offset() == 0); + frame = buffer.pop(); + CHECK(frame->offset() == 1024); + frame = buffer.pop(); + CHECK(frame->offset() == 2048); + frame = buffer.pop(); + CHECK(frame->offset() == 3072); + frame = buffer.pop(); + CHECK(frame->offset() == 4096); + CHECK(buffer.empty()); + + buffer.clear(); + + buffer.insert(stream1_frame_4_r); + buffer.insert(stream1_frame_3_r); + buffer.insert(stream1_frame_2_r); + buffer.insert(stream1_frame_1_r); + buffer.insert(stream1_frame_0_r); + CHECK(!buffer.empty()); + + frame = buffer.pop(); + CHECK(frame->offset() == 0); + frame = buffer.pop(); + CHECK(frame->offset() == 1024); + frame = buffer.pop(); + CHECK(frame->offset() == 2048); + frame = buffer.pop(); + CHECK(frame->offset() == 3072); + frame = buffer.pop(); + CHECK(frame->offset() == 4096); + CHECK(buffer.empty()); + + delete stream; +} + +TEST_CASE("QUICIncomingFrameBuffer_dup_frame", "[quic]") +{ + QUICStream *stream = new QUICStream(); + QUICIncomingFrameBuffer buffer(stream); + QUICErrorUPtr err = nullptr; + + uint8_t data[1024] = {0}; + + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); + std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); + std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); + std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); + + buffer.insert(stream1_frame_0_r); + buffer.insert(stream1_frame_1_r); + buffer.insert(stream1_frame_2_r); + err = buffer.insert(stream1_frame_3_r); + CHECK(err->cls == QUICErrorClass::NONE); + + auto frame = buffer.pop(); + CHECK(frame->offset() == 0); + frame = buffer.pop(); + CHECK(frame->offset() == 1024); + frame = buffer.pop(); + CHECK(frame->offset() == 2048); + frame = buffer.pop(); + CHECK(frame == nullptr); + CHECK(buffer.empty()); + + buffer.clear(); + + std::shared_ptr stream2_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); + std::shared_ptr stream2_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); + std::shared_ptr stream2_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); + std::shared_ptr stream2_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); + + buffer.insert(stream2_frame_0_r); + buffer.insert(stream2_frame_1_r); + buffer.insert(stream2_frame_2_r); + err = buffer.insert(stream2_frame_3_r); + CHECK(err->cls == QUICErrorClass::NONE); + + frame = buffer.pop(); + CHECK(frame->offset() == 0); + frame = buffer.pop(); + CHECK(frame->offset() == 1024); + frame = buffer.pop(); + CHECK(frame->offset() == 2048); + frame = buffer.pop(); + CHECK(frame == nullptr); + CHECK(buffer.empty()); + + delete stream; +} From d46ff1251c628b642f1822591d1ac5126e916933 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 12 Oct 2017 14:11:32 +0900 Subject: [PATCH 0157/1313] Fix building unit tests of quic --- .gitignore | 1 + iocore/net/quic/test/Makefile.am | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index de3eff51664..ed253d8a3ee 100644 --- a/.gitignore +++ b/.gitignore @@ -103,6 +103,7 @@ iocore/net/quic/test/test_QUICTypeUtil iocore/net/quic/test/test_QUICAckFrameCreator iocore/net/quic/test/test_QUICVersionNegotiator iocore/net/quic/test/test_QUICFlowController +iocore/net/quic/test/test_QUICIncomingFrameBuffer iocore/net/quic/ts_quic_client iocore/aio/test_AIO iocore/eventsystem/test_Buffer diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index e25ecedf306..b53ec4d120e 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -132,6 +132,7 @@ test_QUICFrame_SOURCES = \ ../QUICTypes.cc \ ../QUICStream.cc \ ../QUICStreamState.cc \ + ../QUICIncomingFrameBuffer.cc \ ../QUICDebugNames.cc \ ../QUICFlowController.cc \ ../../SSLNextProtocolSet.cc @@ -166,6 +167,7 @@ test_QUICFrameDispatcher_SOURCES = \ ../QUICPacket.cc \ ../QUICStream.cc \ ../QUICStreamState.cc \ + ../QUICIncomingFrameBuffer.cc \ ../QUICApplication.cc \ ../QUICHandshake.cc \ ../QUICTypes.cc \ @@ -252,6 +254,7 @@ test_QUICStreamManager_SOURCES = \ event_processor_main.cc \ test_QUICStreamManager.cc \ ../QUICStream.cc \ + ../QUICIncomingFrameBuffer.cc \ ../QUICFrameDispatcher.cc \ ../QUICStreamManager.cc \ ../QUICApplicationMap.cc \ @@ -290,6 +293,7 @@ test_QUICTransportParameters_SOURCES = \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICStream.cc \ + ../QUICIncomingFrameBuffer.cc \ ../QUICStreamState.cc \ ../QUICStreamManager.cc \ ../QUICFlowController.cc \ @@ -380,6 +384,7 @@ test_QUICTypeUtil_SOURCES = \ main.cc \ test_QUICTypeUtil.cc \ ../QUICStream.cc \ + ../QUICIncomingFrameBuffer.cc \ ../QUICStreamState.cc \ ../QUICFlowController.cc \ ../QUICDebugNames.cc \ @@ -411,6 +416,7 @@ test_QUICAckFrameCreator_SOURCES = \ ../QUICFrame.cc \ ../QUICPacket.cc \ ../QUICStream.cc \ + ../QUICIncomingFrameBuffer.cc \ ../QUICStreamState.cc \ ../QUICFlowController.cc \ ../QUICDebugNames.cc \ @@ -449,6 +455,7 @@ test_QUICVersionNegotiator_SOURCES = \ ../QUICApplicationMap.cc \ ../QUICHandshake.cc \ ../QUICStream.cc \ + ../QUICIncomingFrameBuffer.cc \ ../QUICStreamState.cc \ ../QUICStreamManager.cc \ ../QUICFlowController.cc \ @@ -483,6 +490,7 @@ test_QUICFlowController_SOURCES = \ test_QUICFlowController.cc \ ../QUICFlowController.cc \ ../QUICStream.cc \ + ../QUICIncomingFrameBuffer.cc \ ../QUICStreamState.cc \ ../QUICDebugNames.cc \ ../QUICTypes.cc \ From 2250a414d8818b5f6b781a9ee9811521d6022e20 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 12 Oct 2017 16:34:14 +0900 Subject: [PATCH 0158/1313] Fix heap-use-after-free in QUICStreamFrame::store Make data of QUICStramFrame ats_unique_buf. Copy data of _write_vio to the buffer, when QUICStream sends frame. Ideally this malloc and copy should be avoided. --- iocore/net/quic/QUICFrame.cc | 11 +- iocore/net/quic/QUICFrame.h | 4 +- iocore/net/quic/test/test_QUICFrame.cc | 50 +++- .../net/quic/test/test_QUICFrameDispatcher.cc | 7 +- iocore/net/quic/test/test_QUICStream.cc | 215 ++++++++++-------- 5 files changed, 174 insertions(+), 113 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 69951d47ed3..4bb02b4ad85 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -72,9 +72,9 @@ QUICFrame::reset(const uint8_t *buf, size_t len) // STREAM Frame // -QUICStreamFrame::QUICStreamFrame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last) +QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last) { - this->_data = data; + this->_data = std::move(data); this->_data_len = data_len; this->_stream_id = stream_id; this->_offset = offset; @@ -183,7 +183,7 @@ QUICStreamFrame::data() const if (this->_buf) { return this->_buf + this->_get_data_offset(); } else { - return this->_data; + return this->_data.get(); } } @@ -1315,8 +1315,11 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) QUICStreamFrameUPtr QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last) { + ats_unique_buf buf = ats_unique_malloc(data_len); + memcpy(buf.get(), data, data_len); + QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(data, data_len, stream_id, offset, last); + new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last); return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 772d65a6a91..9f2b3560fc7 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -59,7 +59,7 @@ class QUICStreamFrame : public QUICFrame public: QUICStreamFrame() : QUICFrame() {} QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamFrame(const uint8_t *buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false); + QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -74,7 +74,7 @@ class QUICStreamFrame : public QUICFrame LINK(QUICStreamFrame, link); private: - const uint8_t *_data = nullptr; + ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; size_t _data_len = 0; QUICStreamId _stream_id = 0; QUICOffset _offset = 0; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 90c82fb77b8..36f1eee8e50 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -55,11 +55,14 @@ TEST_CASE("QUICFrame Type", "[quic]") TEST_CASE("Construct QUICFrame", "[quic]") { - uint8_t payload[] = "foo"; + uint8_t raw[] = "foo"; + ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); + memcpy(payload.get(), raw, sizeof(raw)); + uint8_t buf[65536]; size_t len; - QUICStreamFrame frame1(payload, sizeof(payload), 0xffcc9966, 0xffddbb9977553311); + QUICStreamFrame frame1(std::move(payload), sizeof(raw), 0xffcc9966, 0xffddbb9977553311); frame1.store(buf, &len); CHECK(frame1.type() == QUICFrameType::STREAM); CHECK(frame1.size() == 19); @@ -119,7 +122,12 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x00, 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - QUICStreamFrame streamFrame1(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01, 0x00); + + uint8_t raw1[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload1 = ats_unique_malloc(5); + memcpy(payload1.get(), raw1, 5); + + QUICStreamFrame streamFrame1(std::move(payload1), 5, 0x01, 0x00); streamFrame1.store(buf, &len); CHECK(len == 9); CHECK(memcmp(buf, expected1, len) == 0); @@ -132,7 +140,11 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x00, 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - QUICStreamFrame streamFrame2(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01, 0x01); + uint8_t raw2[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload2 = ats_unique_malloc(5); + memcpy(payload2.get(), raw2, 5); + + QUICStreamFrame streamFrame2(std::move(payload2), 5, 0x01, 0x01); streamFrame2.store(buf, &len); CHECK(len == 11); CHECK(memcmp(buf, expected2, len) == 0); @@ -145,7 +157,11 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x00, 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - QUICStreamFrame streamFrame3(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01, 0x010000); + uint8_t raw3[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload3 = ats_unique_malloc(5); + memcpy(payload3.get(), raw3, 5); + + QUICStreamFrame streamFrame3(std::move(payload3), 5, 0x01, 0x010000); streamFrame3.store(buf, &len); CHECK(len == 13); CHECK(memcmp(buf, expected3, len) == 0); @@ -158,7 +174,11 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x00, 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - QUICStreamFrame streamFrame4(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01, 0x0100000000); + uint8_t raw4[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload4 = ats_unique_malloc(5); + memcpy(payload4.get(), raw4, 5); + + QUICStreamFrame streamFrame4(std::move(payload4), 5, 0x01, 0x0100000000); streamFrame4.store(buf, &len); CHECK(len == 17); CHECK(memcmp(buf, expected4, len) == 0); @@ -171,7 +191,11 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x00, 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - QUICStreamFrame streamFrame5(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x0100, 0x0100000000); + uint8_t raw5[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload5 = ats_unique_malloc(5); + memcpy(payload5.get(), raw5, 5); + + QUICStreamFrame streamFrame5(std::move(payload5), 5, 0x0100, 0x0100000000); streamFrame5.store(buf, &len); CHECK(len == 18); CHECK(memcmp(buf, expected5, len) == 0); @@ -184,7 +208,11 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x00, 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - QUICStreamFrame streamFrame6(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x010000, 0x0100000000); + uint8_t raw6[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload6 = ats_unique_malloc(5); + memcpy(payload6.get(), raw6, 5); + + QUICStreamFrame streamFrame6(std::move(payload6), 5, 0x010000, 0x0100000000); streamFrame6.store(buf, &len); CHECK(len == 19); CHECK(memcmp(buf, expected6, len) == 0); @@ -197,7 +225,11 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x00, 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - QUICStreamFrame streamFrame7(reinterpret_cast("\x01\x02\x03\x04\x05"), 5, 0x01000000, 0x0100000000); + uint8_t raw7[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload7 = ats_unique_malloc(5); + memcpy(payload7.get(), raw7, 5); + + QUICStreamFrame streamFrame7(std::move(payload7), 5, 0x01000000, 0x0100000000); streamFrame7.store(buf, &len); CHECK(len == 20); CHECK(memcmp(buf, expected7, len) == 0); diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 8573dce68af..215303fa84e 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -29,8 +29,11 @@ TEST_CASE("QUICFrameHandler", "[quic]") { - uint8_t payload[] = {0x01}; - QUICStreamFrame streamFrame(payload, 1, 0x03, 0); + uint8_t raw[] = {0x01}; + ats_unique_buf payload = ats_unique_malloc(1); + memcpy(payload.get(), raw, 1); + + QUICStreamFrame streamFrame(std::move(payload), 1, 0x03, 0); auto connection = new MockQUICConnection(); auto streamManager = new MockQUICStreamManager(); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 632ad912f29..ef523abd6b9 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -26,101 +26,124 @@ #include "quic/QUICStream.h" #include "quic/Mock.h" -namespace +TEST_CASE("QUICStream", "[quic]") { -// Test Data -uint8_t payload[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; -uint32_t stream_id = 0x03; - -std::shared_ptr frame_1 = std::make_shared(payload, 2, stream_id, 0); -std::shared_ptr frame_2 = std::make_shared(payload + 2, 2, stream_id, 2); -std::shared_ptr frame_3 = std::make_shared(payload + 4, 2, stream_id, 4); -std::shared_ptr frame_4 = std::make_shared(payload + 6, 2, stream_id, 6); -std::shared_ptr frame_5 = std::make_shared(payload + 8, 2, stream_id, 8); -std::shared_ptr frame_6 = std::make_shared(payload + 10, 2, stream_id, 10); -std::shared_ptr frame_7 = std::make_shared(payload + 12, 2, stream_id, 12); -std::shared_ptr frame_8 = std::make_shared(payload + 14, 2, stream_id, 14); - -TEST_CASE("QUICStream_assembling_byte_stream_1", "[quic]") -{ - MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); - IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICFrameTransmitter tx; - - std::unique_ptr stream(new QUICStream()); - stream->init(&tx, 0, stream_id, 1024, 1024); - stream->do_io_read(nullptr, 0, read_buffer); - - stream->recv(frame_1); - stream->recv(frame_2); - stream->recv(frame_3); - stream->recv(frame_4); - stream->recv(frame_5); - stream->recv(frame_6); - stream->recv(frame_7); - stream->recv(frame_8); - - uint8_t buf[32]; - int64_t len = reader->read_avail(); - reader->read(buf, len); - - CHECK(len == 16); - CHECK(memcmp(buf, payload, len) == 0); -} - -TEST_CASE("QUICStream_assembling_byte_stream_2", "[quic]") -{ - MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); - IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICFrameTransmitter tx; - - std::unique_ptr stream(new QUICStream()); - stream->init(&tx, 0, stream_id); - stream->do_io_read(nullptr, 0, read_buffer); - - stream->recv(frame_8); - stream->recv(frame_7); - stream->recv(frame_6); - stream->recv(frame_5); - stream->recv(frame_4); - stream->recv(frame_3); - stream->recv(frame_2); - stream->recv(frame_1); - - uint8_t buf[32]; - int64_t len = reader->read_avail(); - reader->read(buf, len); - - CHECK(len == 16); - CHECK(memcmp(buf, payload, len) == 0); -} - -TEST_CASE("QUICStream_assembling_byte_stream_3", "[quic]") -{ - MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); - IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICFrameTransmitter tx; - - std::unique_ptr stream(new QUICStream()); - stream->init(&tx, 0, stream_id); - stream->do_io_read(nullptr, 0, read_buffer); - - stream->recv(frame_8); - stream->recv(frame_7); - stream->recv(frame_6); - stream->recv(frame_7); // duplicated frame - stream->recv(frame_5); - stream->recv(frame_3); - stream->recv(frame_1); - stream->recv(frame_2); - stream->recv(frame_4); - stream->recv(frame_5); // duplicated frame - - uint8_t buf[32]; - int64_t len = reader->read_avail(); - reader->read(buf, len); - - CHECK(len == 16); - CHECK(memcmp(buf, payload, len) == 0); -} + // Test Data + uint8_t payload[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; + uint32_t stream_id = 0x03; + + ats_unique_buf payload1 = ats_unique_malloc(2); + memcpy(payload1.get(), payload, 2); + std::shared_ptr frame_1 = std::make_shared(std::move(payload1), 2, stream_id, 0); + + ats_unique_buf payload2 = ats_unique_malloc(2); + memcpy(payload2.get(), payload + 2, 2); + std::shared_ptr frame_2 = std::make_shared(std::move(payload2), 2, stream_id, 2); + + ats_unique_buf payload3 = ats_unique_malloc(2); + memcpy(payload3.get(), payload + 4, 2); + std::shared_ptr frame_3 = std::make_shared(std::move(payload3), 2, stream_id, 4); + + ats_unique_buf payload4 = ats_unique_malloc(2); + memcpy(payload4.get(), payload + 6, 2); + std::shared_ptr frame_4 = std::make_shared(std::move(payload4), 2, stream_id, 6); + + ats_unique_buf payload5 = ats_unique_malloc(2); + memcpy(payload5.get(), payload + 8, 2); + std::shared_ptr frame_5 = std::make_shared(std::move(payload5), 2, stream_id, 8); + + ats_unique_buf payload6 = ats_unique_malloc(2); + memcpy(payload6.get(), payload + 10, 2); + std::shared_ptr frame_6 = std::make_shared(std::move(payload6), 2, stream_id, 10); + + ats_unique_buf payload7 = ats_unique_malloc(2); + memcpy(payload7.get(), payload + 12, 2); + std::shared_ptr frame_7 = std::make_shared(std::move(payload7), 2, stream_id, 12); + + ats_unique_buf payload8 = ats_unique_malloc(2); + memcpy(payload8.get(), payload + 14, 2); + std::shared_ptr frame_8 = std::make_shared(std::move(payload8), 2, stream_id, 14); + + SECTION("QUICStream_assembling_byte_stream_1") + { + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + IOBufferReader *reader = read_buffer->alloc_reader(); + MockQUICFrameTransmitter tx; + + std::unique_ptr stream(new QUICStream()); + stream->init(&tx, 0, stream_id, 1024, 1024); + stream->do_io_read(nullptr, 0, read_buffer); + + stream->recv(frame_1); + stream->recv(frame_2); + stream->recv(frame_3); + stream->recv(frame_4); + stream->recv(frame_5); + stream->recv(frame_6); + stream->recv(frame_7); + stream->recv(frame_8); + + uint8_t buf[32]; + int64_t len = reader->read_avail(); + reader->read(buf, len); + + CHECK(len == 16); + CHECK(memcmp(buf, payload, len) == 0); + } + + SECTION("QUICStream_assembling_byte_stream_2") + { + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + IOBufferReader *reader = read_buffer->alloc_reader(); + MockQUICFrameTransmitter tx; + + std::unique_ptr stream(new QUICStream()); + stream->init(&tx, 0, stream_id); + stream->do_io_read(nullptr, 0, read_buffer); + + stream->recv(frame_8); + stream->recv(frame_7); + stream->recv(frame_6); + stream->recv(frame_5); + stream->recv(frame_4); + stream->recv(frame_3); + stream->recv(frame_2); + stream->recv(frame_1); + + uint8_t buf[32]; + int64_t len = reader->read_avail(); + reader->read(buf, len); + + CHECK(len == 16); + CHECK(memcmp(buf, payload, len) == 0); + } + + SECTION("QUICStream_assembling_byte_stream_3") + { + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + IOBufferReader *reader = read_buffer->alloc_reader(); + MockQUICFrameTransmitter tx; + + std::unique_ptr stream(new QUICStream()); + stream->init(&tx, 0, stream_id); + stream->do_io_read(nullptr, 0, read_buffer); + + stream->recv(frame_8); + stream->recv(frame_7); + stream->recv(frame_6); + stream->recv(frame_7); // duplicated frame + stream->recv(frame_5); + stream->recv(frame_3); + stream->recv(frame_1); + stream->recv(frame_2); + stream->recv(frame_4); + stream->recv(frame_5); // duplicated frame + + uint8_t buf[32]; + int64_t len = reader->read_avail(); + reader->read(buf, len); + + CHECK(len == 16); + CHECK(memcmp(buf, payload, len) == 0); + } } From e72cfd9c10b940971ff2643d46417ab4098656fa Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 13 Oct 2017 12:02:30 +0900 Subject: [PATCH 0159/1313] Stop Version Negotiation Packet retransmission --- iocore/net/QUICNetVConnection.cc | 2 ++ iocore/net/quic/QUICLossDetector.cc | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a941336bd7f..4229c56955a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -228,6 +228,8 @@ QUICNetVConnection::transmit_packet(QUICPacketUPtr packet) void QUICNetVConnection::retransmit_packet(const QUICPacket &packet) { + ink_assert(packet.type() != QUICPacketType::VERSION_NEGOTIATION && packet.type() != QUICPacketType::UNINITIALIZED); + uint16_t size = packet.payload_size(); const uint8_t *payload = packet.payload(); diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index b9d3c10dd81..41bb3fcf00d 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -145,8 +145,9 @@ QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) bool is_handshake = false; QUICPacketType type = packet->type(); - if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && - type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { + // XXX: Should QUICPacketType::SERVER_STATELESS_RETRY be included? + if (type == QUICPacketType::CLIENT_INITIAL || type == QUICPacketType::SERVER_CLEARTEXT || + type == QUICPacketType::CLIENT_CLEARTEXT) { is_handshake = true; } From 03b95cdd897a245fc1544a60bc30e6b50ddf03e6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 16 Oct 2017 15:19:26 +0900 Subject: [PATCH 0160/1313] Change handshake state after handshake has completely completed --- iocore/net/quic/QUICHandshake.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index aa5930c54b8..d78b90908f5 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -132,7 +132,7 @@ QUICHandshake::is_version_negotiated() bool QUICHandshake::is_completed() { - return this->_crypto->is_handshake_finished(); + return this->handler == &QUICHandshake::state_complete; } QUICVersion @@ -380,17 +380,18 @@ QUICHandshake::_process_client_finished() I_WANNA_DUMP_THIS_BUF(out, static_cast(out_len)); // <----- DEBUG ----- - ink_assert(this->is_completed()); + ink_assert(this->_crypto->is_handshake_finished()); DebugQHS("Handshake is completed"); - DebugQHS("Enter state_complete"); - SET_HANDLER(&QUICHandshake::state_complete); _process_handshake_complete(); stream_io->write(out, out_len); stream_io->write_reenable(); stream_io->read_reenable(); + DebugQHS("Enter state_complete"); + SET_HANDLER(&QUICHandshake::state_complete); + return QUICErrorUPtr(new QUICNoError()); } else { return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::TLS_HANDSHAKE_FAILED)); From a739464caef585a11ca82d927429371d61187b49 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 16 Oct 2017 17:28:32 +0900 Subject: [PATCH 0161/1313] Fix packet number decoding It was not decoded correctly when packets were not sequential. --- iocore/net/quic/QUICPacket.cc | 20 +++++++++++--------- iocore/net/quic/QUICPacket.h | 3 ++- iocore/net/quic/test/test_QUICPacket.cc | 10 ++++++++++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index bf0e1f9c5da..5af7e63bf57 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -669,21 +669,23 @@ QUICPacket::encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si } bool -QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, QUICPacketNumber base) +QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, + QUICPacketNumber largest_acked) { ink_assert(len == 1 || len == 2 || len == 4); - QUICPacketNumber expected = base + 1; + uint64_t maximum_diff = 1ULL << (len * 8); + QUICPacketNumber base = largest_acked & (~(maximum_diff - 1)); + QUICPacketNumber candidate1 = base + src; + QUICPacketNumber candidate2 = base + src + maximum_diff; - uint64_t p = 1ULL << (len * 8); - QUICPacketNumber masked = base & (~(p - 1)); - dst = masked + src; - - if (dst >= expected) { - return true; + if (((candidate1 > largest_acked) ? (candidate1 - largest_acked) : (largest_acked - candidate1)) < + ((candidate2 > largest_acked) ? (candidate2 - largest_acked) : (largest_acked - candidate2))) { + dst = candidate1; + } else { + dst = candidate2; } - dst += p; return true; } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 94067ae8c89..9ed96324351 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -156,7 +156,8 @@ class QUICPacket QUICKeyPhase key_phase() 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_num); + static bool decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, + QUICPacketNumber largest_acked); LINK(QUICPacket, link); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index a987004d603..679cd3b3d03 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -133,3 +133,13 @@ TEST_CASE("Decoding Packet Number 2", "[quic]") QUICPacket::decode_packet_number(dst, src, len, base); CHECK(dst == 0x18bf54f1); } + +TEST_CASE("Decoding Packet Number 3", "[quic]") +{ + QUICPacketNumber dst = 0; + QUICPacketNumber src = 0x5694; + size_t len = 2; + QUICPacketNumber base = 0x44D35695; + QUICPacket::decode_packet_number(dst, src, len, base); + CHECK(dst == 0x44D35694); +} From 0a9919e60538d162d9d28767f6ab43b4d2059c49 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 17 Oct 2017 14:26:02 +0900 Subject: [PATCH 0162/1313] Fix a bug that packet number can be decoded with an uninitialized value --- iocore/net/P_QUICNetVConnection.h | 7 +-- iocore/net/P_UDPNet.h | 1 - iocore/net/QUICNetProcessor.cc | 4 +- iocore/net/QUICNetVConnection.cc | 43 +++++++++++++++---- iocore/net/QUICPacketHandler.cc | 3 +- iocore/net/quic/Mock.h | 1 - iocore/net/quic/QUICFrame.h | 1 - iocore/net/quic/QUICIncomingFrameBuffer.h | 1 - iocore/net/quic/QUICPacket.cc | 24 ++++++----- iocore/net/quic/QUICPacket.h | 8 ++-- iocore/net/quic/test/test_QUICPacket.cc | 14 +----- .../net/quic/test/test_QUICPacketFactory.cc | 10 ++--- 12 files changed, 64 insertions(+), 53 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 339f92edc6a..c249d2096e1 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -144,7 +144,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection public: QUICNetVConnection() {} - void init(UDPConnection *, QUICPacketHandler *); // UnixNetVConnection @@ -159,7 +158,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection int state_connection_closing(int event, Event *data); int state_connection_closed(int event, Event *data); void start(SSL_CTX *); - void push_packet(QUICPacketUPtr packet); + void push_packet(UDPPacket *packet); void free(EThread *t) override; UDPConnection *get_udp_con(); @@ -224,8 +223,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICRemoteFlowController *_remote_flow_controller = nullptr; QUICLocalFlowController *_local_flow_controller = nullptr; - Queue _packet_recv_queue; + Queue _packet_recv_queue; Queue _packet_send_queue; + std::queue _quic_packet_recv_queue; // `_frame_send_queue` is the queue for any type of frame except STREAM frame. // The flow contorl doesn't blcok frames in this queue. // `_stream_frame_send_queue` is the queue for STREAM frame. @@ -259,6 +259,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); void _handle_error(QUICErrorUPtr error); + QUICPacketUPtr _dequeue_recv_packet(); QUICStatelessToken _token; }; diff --git a/iocore/net/P_UDPNet.h b/iocore/net/P_UDPNet.h index dcc28e497f7..5afb9c9569f 100644 --- a/iocore/net/P_UDPNet.h +++ b/iocore/net/P_UDPNet.h @@ -62,7 +62,6 @@ class PacketQueue { public: PacketQueue() { init(); } - virtual ~PacketQueue() {} int nPackets = 0; ink_hrtime lastPullLongTermQ = 0; diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 291dfab9284..608f3d73a80 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -97,9 +97,11 @@ QUICNetProcessor::allocate_vc(EThread *t) QUICNetVConnection *vc; if (t) { - vc = THREAD_ALLOC_INIT(quicNetVCAllocator, t); + vc = THREAD_ALLOC(quicNetVCAllocator, t); + new (vc) QUICNetVConnection(); } else { if (likely(vc = quicNetVCAllocator.alloc())) { + new (vc) QUICNetVConnection(); vc->from_accept_thread = true; } } diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 4229c56955a..ab3cad0d561 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -259,11 +259,9 @@ QUICNetVConnection::get_packet_transmitter_mutex() } void -QUICNetVConnection::push_packet(QUICPacketUPtr packet) +QUICNetVConnection::push_packet(UDPPacket *packet) { - DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), - packet->size()); - this->_packet_recv_queue.enqueue(const_cast(packet.release())); + this->_packet_recv_queue.enqueue(packet); } void @@ -381,7 +379,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) switch (event) { case QUIC_EVENT_PACKET_READ_READY: { - QUICPacketUPtr p = QUICPacketUPtr(this->_packet_recv_queue.dequeue(), &QUICPacketDeleter::delete_packet); + QUICPacketUPtr p = this->_dequeue_recv_packet(); net_activity(this, this_ethread()); switch (p->type()) { @@ -400,7 +398,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: // Postpone processing the packet - this->push_packet(std::move(p)); + this->_quic_packet_recv_queue.push(std::move(p)); this_ethread()->schedule_imm_local(this, event); break; default: @@ -703,11 +701,9 @@ QUICNetVConnection::_state_connection_established_process_packet(QUICPacketUPtr packet->packet_number(), packet->header(), packet->header_size(), packet->key_phase())) { DebugQUICCon("Decrypt Packet, pkt_num: %" PRIu64 ", header_len: %hu, payload_len: %zu", packet->packet_number(), packet->header_size(), plain_txt_len); - return this->_recv_and_ack(plain_txt.get(), plain_txt_len, packet->packet_number()); } else { DebugQUICCon("CRYPTOGRAPHIC Error"); - return QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::CRYPTOGRAPHIC_ERROR)); } } @@ -716,7 +712,7 @@ QUICErrorUPtr QUICNetVConnection::_state_common_receive_packet() { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - QUICPacketUPtr p = QUICPacketUPtr(this->_packet_recv_queue.dequeue(), &QUICPacketDeleter::delete_packet); + QUICPacketUPtr p = this->_dequeue_recv_packet(); net_activity(this, this_ethread()); switch (p->type()) { @@ -949,3 +945,32 @@ QUICNetVConnection::_handle_error(QUICErrorUPtr error) this->close(QUICConnectionErrorUPtr(cerror)); } } + +QUICPacketUPtr +QUICNetVConnection::_dequeue_recv_packet() +{ + QUICPacketUPtr quic_packet = QUICPacketUPtr(nullptr, &QUICPacketDeleter::delete_null_packet); + UDPPacket *udp_packet = this->_packet_recv_queue.dequeue(); + if (udp_packet) { + ats_unique_buf pkt = ats_unique_malloc(udp_packet->getPktLength()); + IOBufferBlock *b = udp_packet->getIOBlockChain(); + size_t written = 0; + while (b) { + memcpy(pkt.get() + written, b->buf(), b->read_avail()); + written += b->read_avail(); + b = b->next.get(); + } + udp_packet->free(); + quic_packet = QUICPacketFactory::create(std::move(pkt), written, this->largest_received_packet_number()); + } + + if (this->_quic_packet_recv_queue.size() > 0) { + QUICPacketUPtr p = std::move(this->_quic_packet_recv_queue.front()); + this->_quic_packet_recv_queue.pop(); + this->_quic_packet_recv_queue.push(std::move(quic_packet)); + quic_packet.reset(p.release()); + } + DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), + quic_packet->packet_number(), quic_packet->size()); + return quic_packet; +} diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index e2e0c225b1a..e86fed4494d 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -166,8 +166,7 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) this->action_->continuation->handleEvent(NET_EVENT_ACCEPT, vc); } - QUICPacketUPtr qPkt = QUICPacketFactory::create(block, vc->largest_received_packet_number()); - vc->push_packet(std::move(qPkt)); + vc->push_packet(udpPacket); // send to EThread eventProcessor.schedule_imm(vc, ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr); diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 41d5390092a..65e9713b3d7 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -373,7 +373,6 @@ class MockQUICApplication : public QUICApplication { public: MockQUICApplication() : QUICApplication(new MockQUICConnection) { SET_HANDLER(&MockQUICApplication::main_event_handler); } - int main_event_handler(int event, Event *data) { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 9f2b3560fc7..dad9a6c95b0 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -41,7 +41,6 @@ class QUICFrame virtual void reset(const uint8_t *buf, size_t len); static QUICFrameType type(const uint8_t *buf); virtual ~QUICFrame() {} - LINK(QUICFrame, link); protected: diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index ab79a44f797..66b637a6b67 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -33,7 +33,6 @@ class QUICIncomingFrameBuffer { public: QUICIncomingFrameBuffer(QUICStream *stream) : _stream(stream) {} - ~QUICIncomingFrameBuffer(); std::shared_ptr pop(); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 5af7e63bf57..276cc7dc3d4 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -445,11 +445,10 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const // // QUICPacket // -QUICPacket::QUICPacket(IOBufferBlock *block, QUICPacketNumber base_packet_number) : _block(block) +QUICPacket::QUICPacket(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number) { - this->_size = block->size(); - this->_header = - QUICPacketHeader::load(reinterpret_cast(this->_block->buf()), this->_block->size(), base_packet_number); + this->_size = len; + this->_header = QUICPacketHeader::load(reinterpret_cast(buf.release()), len, base_packet_number); } QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, @@ -628,8 +627,8 @@ bool QUICPacket::has_valid_fnv1a_hash() const { uint8_t hash[FNV1A_HASH_LEN]; - fnv1a(reinterpret_cast(this->_block->buf()), this->_block->size() - FNV1A_HASH_LEN, hash); - return memcmp(this->_block->buf() + this->_block->size() - FNV1A_HASH_LEN, hash, 8) == 0; + fnv1a(reinterpret_cast(this->_header->buf()), this->size() - FNV1A_HASH_LEN, hash); + return memcmp(this->_header->buf() + this->size() - FNV1A_HASH_LEN, hash, 8) == 0; } void @@ -669,8 +668,7 @@ QUICPacket::encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si } bool -QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, - QUICPacketNumber largest_acked) +QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, QUICPacketNumber largest_acked) { ink_assert(len == 1 || len == 2 || len == 4); @@ -686,6 +684,12 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si dst = candidate2; } + Debug("quic_packet_factory", "----------------------- src: %" PRIu64, src); + Debug("quic_packet_factory", "----------------------- base: %" PRIu64, base); + Debug("quic_packet_factory", "----------------------- c1: %" PRIu64, candidate1); + Debug("quic_packet_factory", "----------------------- c2: %" PRIu64, candidate2); + Debug("quic_packet_factory", "----------------------- dst: %" PRIu64, dst); + return true; } @@ -693,10 +697,10 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si // QUICPacketFactory // QUICPacketUPtr -QUICPacketFactory::create(IOBufferBlock *block, QUICPacketNumber base_packet_number) +QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number) { QUICPacket *packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(block, base_packet_number); + new (packet) QUICPacket(std::move(buf), len, base_packet_number); return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 9ed96324351..987b90ede91 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -129,7 +129,7 @@ class QUICPacket { public: QUICPacket(){}; - QUICPacket(IOBufferBlock *block, QUICPacketNumber base_packet_number); + QUICPacket(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number); QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len, bool retransmittable); QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, @@ -156,13 +156,11 @@ class QUICPacket QUICKeyPhase key_phase() 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); + static bool decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, QUICPacketNumber largest_acked); LINK(QUICPacket, link); private: - IOBufferBlock *_block = nullptr; ats_unique_buf _protected_payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); size_t _size = 0; size_t _protected_payload_size = 0; @@ -207,7 +205,7 @@ class QUICPacketDeleter class QUICPacketFactory { public: - static QUICPacketUPtr create(IOBufferBlock *block, QUICPacketNumber base_packet_number); + static QUICPacketUPtr create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number); QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number); QUICPacketUPtr create_server_cleartext_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 679cd3b3d03..8c2f2bfcdf8 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -39,12 +39,7 @@ TEST_CASE("Loading Long Header Packet", "[quic]") size_t len; packet1.store(buf, &len); - IOBufferBlock *block = new_IOBufferBlock(); - block->alloc(iobuffer_size_to_index(len)); - memcpy(block->end(), buf, len); - block->fill(len); - - const QUICPacket packet2(block, 0); + const QUICPacket packet2(ats_unique_buf(buf, [](void *p) { ats_free(p); }), len, 0); CHECK(packet2.type() == QUICPacketType::CLIENT_CLEARTEXT); CHECK(packet2.connection_id() == 0xffddbb9977553311ULL); @@ -73,12 +68,7 @@ TEST_CASE("Loading Short Header Packet", "[quic]") size_t len; packet1.store(buf, &len); - IOBufferBlock *block = new_IOBufferBlock(); - block->alloc(iobuffer_size_to_index(len)); - memcpy(block->end(), buf, len); - block->fill(len); - - const QUICPacket packet2(block, 0); + const QUICPacket packet2(ats_unique_buf(buf, [](void *p) { ats_free(p); }), len, 0); CHECK(packet2.type() == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0); CHECK(packet2.packet_number() == 0xffcc9966); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index fbf6a87ca0e..942b49ce7f9 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -29,7 +29,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") { QUICPacketFactory factory; - const uint8_t client_initial_packet_data[] = { + uint8_t client_initial_packet_data[] = { 0x82, // Type 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection id 0x00, 0x00, 0x00, 0x00, // Packet number @@ -37,12 +37,8 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x00 // Payload }; - IOBufferBlock *block = new_IOBufferBlock(); - block->alloc(iobuffer_size_to_index(sizeof(client_initial_packet_data))); - memcpy(block->end(), client_initial_packet_data, sizeof(client_initial_packet_data)); - block->fill(sizeof(client_initial_packet_data)); - - QUICPacket client_initial_packet(block, 0); + QUICPacket client_initial_packet(ats_unique_buf(client_initial_packet_data, [](void *p) { ats_free(p); }), + sizeof(client_initial_packet_data), 0); QUICPacketUPtr packet = factory.create_version_negotiation_packet(&client_initial_packet, 0); CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); From 266d5cb0ea2a57142975f8816f01481f50941e4e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 17 Oct 2017 15:04:18 +0900 Subject: [PATCH 0163/1313] Add null checks --- iocore/net/QUICNetVConnection.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ab3cad0d561..90ccb7b757f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -380,6 +380,9 @@ QUICNetVConnection::state_handshake(int event, Event *data) switch (event) { case QUIC_EVENT_PACKET_READ_READY: { QUICPacketUPtr p = this->_dequeue_recv_packet(); + if (!p) { + break; + } net_activity(this, this_ethread()); switch (p->type()) { @@ -713,6 +716,9 @@ QUICNetVConnection::_state_common_receive_packet() { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); QUICPacketUPtr p = this->_dequeue_recv_packet(); + if (!p) { + return error; + } net_activity(this, this_ethread()); switch (p->type()) { @@ -970,7 +976,9 @@ QUICNetVConnection::_dequeue_recv_packet() this->_quic_packet_recv_queue.push(std::move(quic_packet)); quic_packet.reset(p.release()); } - DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), - quic_packet->packet_number(), quic_packet->size()); + if (quic_packet) { + DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), + quic_packet->packet_number(), quic_packet->size()); + } return quic_packet; } From 461b7c80e578e51054a76c48bb319ddde259259e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 17 Oct 2017 15:19:45 +0900 Subject: [PATCH 0164/1313] Remove temporal debug logs --- iocore/net/quic/QUICPacket.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 276cc7dc3d4..95572cdb73d 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -684,12 +684,6 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si dst = candidate2; } - Debug("quic_packet_factory", "----------------------- src: %" PRIu64, src); - Debug("quic_packet_factory", "----------------------- base: %" PRIu64, base); - Debug("quic_packet_factory", "----------------------- c1: %" PRIu64, candidate1); - Debug("quic_packet_factory", "----------------------- c2: %" PRIu64, candidate2); - Debug("quic_packet_factory", "----------------------- dst: %" PRIu64, dst); - return true; } From 5e713636eca3c1ef870a043b71b3935ff10d579b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 18 Oct 2017 10:55:41 +0900 Subject: [PATCH 0165/1313] Fix max stream id limitation --- iocore/net/quic/QUICStreamManager.cc | 7 +++++-- iocore/net/quic/QUICTypes.cc | 11 +++++++++++ iocore/net/quic/QUICTypes.h | 3 +++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 47b4bbe4117..e7fc1c05144 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -197,8 +197,11 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) { QUICStream *stream = this->_find_stream(stream_id); if (!stream) { - if ((stream_id > this->_local_maximum_stream_id && this->_local_maximum_stream_id != 0) || - (stream_id > this->_remote_maximum_stream_id && this->_remote_maximum_stream_id != 0)) { + QUICStreamType type = QUICTypeUtil::detect_stream_type(stream_id); + if (type == QUICStreamType::CLIENT && stream_id > this->_local_maximum_stream_id && this->_local_maximum_stream_id != 0) { + return nullptr; + } else if (type == QUICStreamType::CLIENT && stream_id > this->_remote_maximum_stream_id && + this->_remote_maximum_stream_id != 0) { return nullptr; } // TODO Free the stream somewhere diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index c4d327ec68c..40c8a02b71a 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -35,6 +35,17 @@ QUICTypeUtil::hasLongHeader(const uint8_t *buf) return (buf[0] & 0x80) != 0; } +QUICStreamType +QUICTypeUtil::detect_stream_type(QUICStreamId id) +{ + uint8_t type = (id & 0x01); + if (type == 0) { + return QUICStreamType::HANDSHAKE; + } else { + return static_cast(type); + } +} + QUICConnectionId QUICTypeUtil::read_QUICConnectionId(const uint8_t *buf, uint8_t len) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index d25f36afa25..2f29bd2eaf7 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -236,6 +236,8 @@ class QUICConnectionId uint64_t _id; }; +enum class QUICStreamType { CLIENT, SERVER, HANDSHAKE }; + class QUICMaximumData { public: @@ -294,6 +296,7 @@ class QUICTypeUtil { public: static bool hasLongHeader(const uint8_t *buf); + static QUICStreamType detect_stream_type(QUICStreamId id); static QUICConnectionId read_QUICConnectionId(const uint8_t *buf, uint8_t n); static QUICPacketNumber read_QUICPacketNumber(const uint8_t *buf, uint8_t n); From 8ff12813d3147acb73333f55bd953a5dd5a78ee1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 18 Oct 2017 17:27:30 +0900 Subject: [PATCH 0166/1313] Fix the last wrong fix --- iocore/net/quic/QUICStreamManager.cc | 2 +- iocore/net/quic/QUICTypes.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index e7fc1c05144..6bda170983e 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -200,7 +200,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) QUICStreamType type = QUICTypeUtil::detect_stream_type(stream_id); if (type == QUICStreamType::CLIENT && stream_id > this->_local_maximum_stream_id && this->_local_maximum_stream_id != 0) { return nullptr; - } else if (type == QUICStreamType::CLIENT && stream_id > this->_remote_maximum_stream_id && + } else if (type == QUICStreamType::SERVER && stream_id > this->_remote_maximum_stream_id && this->_remote_maximum_stream_id != 0) { return nullptr; } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 2f29bd2eaf7..5ea699387d0 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -236,7 +236,7 @@ class QUICConnectionId uint64_t _id; }; -enum class QUICStreamType { CLIENT, SERVER, HANDSHAKE }; +enum class QUICStreamType { SERVER, CLIENT, HANDSHAKE }; class QUICMaximumData { From ba7974de6e5b577f98945de8136130b6b43982bc Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 19 Oct 2017 10:51:51 +0900 Subject: [PATCH 0167/1313] Don't free QUICNetVConnection for now to prevent crashes Since we don't have QUICNetHandler, all IO events are handled by QUICNetVC directly, which causes crashes when the events are processed after freeing QUICNetVC. It is going to be addressed by introducing QUICNetHandler. --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/P_QUICPacketHandler.h | 1 - iocore/net/QUICNetVConnection.cc | 15 ++++++++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index c249d2096e1..92c84eeeb31 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -170,6 +170,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // QUICNetVConnection void registerNextProtocolSet(SSLNextProtocolSet *s); + bool is_closed(); // QUICConnection QUICConnectionId connection_id() override; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 113a31c5b5a..e1ea3fbae29 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -42,7 +42,6 @@ struct QUICPacketHandler : public NetAccept { void init_accept(EThread *t) override; void send_packet(const QUICPacket &packet, QUICNetVConnection *vc); void send_packet(const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu); - void forget(QUICNetVConnection *vc); private: void _recv_packet(int event, UDPPacket *udpPacket); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 90ccb7b757f..45c8aedcdb7 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -123,8 +123,6 @@ QUICNetVConnection::free(EThread *t) { DebugQUICCon("Free connection"); - this->_packet_handler->forget(this); - this->_udp_con = nullptr; this->_packet_handler = nullptr; @@ -537,7 +535,10 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) { switch (event) { case QUIC_EVENT_SHUTDOWN: { - this->_packet_write_ready = nullptr; + if (this->_packet_write_ready) { + this->_packet_write_ready->cancel(); + this->_packet_write_ready = nullptr; + } this->next_inactivity_timeout_at = 0; this->next_activity_timeout_at = 0; @@ -548,8 +549,6 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) // Shutdown loss detector this->_loss_detector->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); - this->free(this_ethread()); - break; } default: @@ -616,6 +615,12 @@ QUICNetVConnection::registerNextProtocolSet(SSLNextProtocolSet *s) this->_next_protocol_set = s; } +bool +QUICNetVConnection::is_closed() +{ + return this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closed); +} + SSLNextProtocolSet * QUICNetVConnection::next_protocol_set() { From 843a7ca5f2369d474d114e8d0feefc572125374f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 19 Oct 2017 12:26:19 +0900 Subject: [PATCH 0168/1313] Add missed changes for the last commit --- iocore/net/QUICPacketHandler.cc | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index e86fed4494d..aff1f87e323 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -166,10 +166,15 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) this->action_->continuation->handleEvent(NET_EVENT_ACCEPT, vc); } - vc->push_packet(udpPacket); - - // send to EThread - eventProcessor.schedule_imm(vc, ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr); + if (vc->is_closed()) { + this->_connections.put(vc->connection_id(), nullptr); + // FIXME QUICNetVConnection is NOT freed to prevent crashes. #2674 + // QUICNetVConnections are going to be freed by QUICNetHandler + // vc->free(vc->thread); + } else { + vc->push_packet(udpPacket); + eventProcessor.schedule_imm(vc, ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr); + } } // TODO: Should be called via eventProcessor? @@ -203,9 +208,3 @@ QUICPacketHandler::send_packet(const QUICPacket &packet, UDPConnection *udp_con, udp_con->send(this, udpPkt); } - -void -QUICPacketHandler::forget(QUICNetVConnection *vc) -{ - this->_connections.put(vc->connection_id(), nullptr); -} From d48631f3d0c0bedf43655ab56b698341f931fb42 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 19 Oct 2017 16:27:52 +0900 Subject: [PATCH 0169/1313] Fix stream level flow control It didn't use available credit if sending data don't fit in. --- iocore/net/quic/Mock.h | 11 +++ iocore/net/quic/QUICStream.cc | 4 + iocore/net/quic/test/test_QUICStream.cc | 102 ++++++++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 65e9713b3d7..22ba21d1857 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -399,3 +399,14 @@ NetVConnection::send_OOB(Continuation *, char *, int) { return nullptr; } + +class MockContinuation : public Continuation +{ +public: + MockContinuation(Ptr m) : Continuation(m) { SET_HANDLER(&MockContinuation::event_handler); } + int + event_handler(int event, Event *data) + { + return EVENT_CONT; + } +}; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index f0ec0ff1197..535b9f4c427 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -360,6 +360,10 @@ QUICStream::_send() int64_t len = 0; bool fin = false; + int64_t credit = this->_remote_flow_controller->current_limit() - this->_remote_flow_controller->current_offset(); + if (credit != 0 && max_size > credit) { + max_size = credit; + } if (data_len > max_size) { len = max_size; } else { diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index ef523abd6b9..5e63ade1074 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -146,4 +146,106 @@ TEST_CASE("QUICStream", "[quic]") CHECK(len == 16); CHECK(memcmp(buf, payload, len) == 0); } + + SECTION("QUICStream_flow_control_local", "[quic]") + { + std::unique_ptr error = nullptr; + + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + IOBufferReader *reader = read_buffer->alloc_reader(); + MockQUICFrameTransmitter tx; + + std::unique_ptr stream(new QUICStream()); + stream->init(&tx, 0, stream_id); + stream->init_flow_control_params(4096, 4096); + stream->do_io_read(nullptr, 0, read_buffer); + + // Start with 1024 but not 0 so received frames won't be processed + error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 1024)); + CHECK(error->cls == QUICErrorClass::NONE); + // duplicate + error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 1024)); + CHECK(error->cls == QUICErrorClass::NONE); + error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 3072)); + CHECK(error->cls == QUICErrorClass::NONE); + // delay + error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 2048)); + CHECK(error->cls == QUICErrorClass::NONE); + // all frames should be processed + error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 0)); + CHECK(error->cls == QUICErrorClass::NONE); + // start again without the first block + error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 5120)); + CHECK(error->cls == QUICErrorClass::NONE); + // this should exceed the limit + error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 8192)); + CHECK(error->code == QUICErrorCode::FLOW_CONTROL_ERROR); + } + + SECTION("QUICStream_flow_control_remote", "[quic]") + { + std::unique_ptr error = nullptr; + + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + IOBufferReader *read_buffer_reader = read_buffer->alloc_reader(); + IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); + MockQUICFrameTransmitter tx; + + std::unique_ptr stream(new QUICStream()); + stream->init(&tx, 0, stream_id); + stream->init_flow_control_params(4096, 4096); + MockContinuation mock_cont(stream->mutex); + stream->do_io_read(nullptr, 0, read_buffer); + stream->do_io_write(&mock_cont, 0, write_buffer_reader); + + // Check the initial state + CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 0); + + const char data[1024] = {0}; + write_buffer->write(data, 1024); + stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 1); + + write_buffer->write(data, 1024); + stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 2); + + write_buffer->write(data, 1024); + stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 3); + + write_buffer->write(data, 1024); + stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 4); + + // This should not send a frame because of flow control + write_buffer->write(data, 1024); + stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 4); + + // Update window + stream->recv(std::make_shared(stream_id, 5120)); + + // This should send a frame + stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 5); + + // Update window + stream->recv(std::make_shared(stream_id, 5632)); + + // This should send a frame + write_buffer->write(data, 1024); + stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 6); + + stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 6); + + // Update window + stream->recv(std::make_shared(stream_id, 6144)); + + stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 7); + } } From 22a9c65cf6f0556d9229b70dd325b21fe9961fdd Mon Sep 17 00:00:00 2001 From: Leif Hedstrom Date: Thu, 19 Oct 2017 15:15:58 -0600 Subject: [PATCH 0170/1313] Change to use string_view, which is needed after merging current master --- iocore/net/P_QUICNetVConnection.h | 4 ++-- iocore/net/QUICNetVConnection.cc | 19 ++++++++----------- iocore/net/quic/QUICApplication.cc | 2 -- iocore/net/quic/QUICCrypto.cc | 22 +++++++++++----------- proxy/hq/HQClientSession.cc | 2 +- proxy/hq/HQClientSession.h | 2 +- 6 files changed, 23 insertions(+), 28 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 92c84eeeb31..315ec24b735 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -165,8 +165,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection virtual void net_read_io(NetHandler *nh, EThread *lthread) override; virtual int64_t load_buffer_and_write(int64_t towrite, MIOBufferAccessor &buf, int64_t &total_written, int &needs) override; - int populate_protocol(ts::StringView *results, int n) const override; - const char *protocol_contains(ts::StringView tag) const override; + int populate_protocol(ts::string_view *results, int n) const override; + const char *protocol_contains(ts::string_view tag) const override; // QUICNetVConnection void registerNextProtocolSet(SSLNextProtocolSet *s); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 45c8aedcdb7..7a4c45758b3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -444,7 +444,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) unsigned int app_name_len = 0; this->_handshake_handler->negotiated_application_name(&app_name, &app_name_len); if (app_name == nullptr) { - app_name = reinterpret_cast(IP_PROTO_TAG_HTTP_QUIC.ptr()); + app_name = reinterpret_cast(IP_PROTO_TAG_HTTP_QUIC.data()); app_name_len = IP_PROTO_TAG_HTTP_QUIC.size(); } @@ -581,14 +581,11 @@ QUICNetVConnection::load_buffer_and_write(int64_t towrite, MIOBufferAccessor &bu } int -QUICNetVConnection::populate_protocol(ts::StringView *results, int n) const +QUICNetVConnection::populate_protocol(ts::string_view *results, int n) const { int retval = 0; if (n > retval) { - results[retval] = IP_PROTO_TAG_QUIC; - if (results[retval]) { - ++retval; - } + results[retval++] = IP_PROTO_TAG_QUIC; if (n > retval) { retval += super::populate_protocol(results + retval, n - retval); } @@ -597,12 +594,12 @@ QUICNetVConnection::populate_protocol(ts::StringView *results, int n) const } const char * -QUICNetVConnection::protocol_contains(ts::StringView prefix) const +QUICNetVConnection::protocol_contains(ts::string_view prefix) const { - const char *retval = nullptr; - ts::StringView tag = IP_PROTO_TAG_QUIC; - if (prefix.size() <= tag.size() && strncmp(tag.ptr(), prefix.ptr(), prefix.size()) == 0) { - retval = tag.ptr(); + const char *retval = nullptr; + ts::string_view tag = IP_PROTO_TAG_QUIC; + if (prefix.size() <= tag.size() && strncmp(tag.data(), prefix.data(), prefix.size()) == 0) { + retval = tag.data(); } else { retval = super::protocol_contains(prefix); } diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 61c1429edb2..5d5a0ed485c 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -22,8 +22,6 @@ */ #include "QUICApplication.h" - -#include "ts/MemView.h" #include "QUICStream.h" static constexpr char tag[] = "quic_app"; diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 1cfc2d6b1b8..20414c6e9ee 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -28,20 +28,20 @@ #include #include "ts/Diags.h" -#include "ts/MemView.h" +#include "ts/string_view.h" #include "QUICTypes.h" constexpr static char tag[] = "quic_crypto"; // constexpr static ts::StringView _exporter_label_0_rtt("EXPORTER-QUIC 0-RTT Secret", ts::StringView::literal); -constexpr static ts::StringView exporter_label_client_1_rtt("EXPORTER-QUIC client 1-RTT Secret", ts::StringView::literal); -constexpr static ts::StringView exporter_label_server_1_rtt("EXPORTER-QUIC server 1-RTT Secret", ts::StringView::literal); +constexpr static ts::string_view exporter_label_client_1_rtt("EXPORTER-QUIC client 1-RTT Secret"_sv); +constexpr static ts::string_view exporter_label_server_1_rtt("EXPORTER-QUIC server 1-RTT Secret"_sv); // [quic-tls draft-05] "tls13 " + Label // constexpr static ts::StringView expand_label_client_1_rtt("tls13 QUIC client 1-RTT secret", ts::StringView::literal); // constexpr static ts::StringView expand_label_server_1_rtt("tls13 QUIC server 1-RTT secret", ts::StringView::literal); -constexpr static ts::StringView expand_label_key("tls13 key", ts::StringView::literal); -constexpr static ts::StringView expand_label_iv("tls13 iv", ts::StringView::literal); +constexpr static ts::string_view expand_label_key("tls13 key"_sv); +constexpr static ts::string_view expand_label_iv("tls13 iv"_sv); // // QUICPacketProtection @@ -310,19 +310,19 @@ QUICCrypto::_export_client_keymaterial(size_t secret_len, size_t key_len, size_t KeyMaterial *km = new KeyMaterial(secret_len, key_len, iv_len); int r = 0; - r = _export_secret(km->secret, secret_len, exporter_label_client_1_rtt.ptr(), exporter_label_client_1_rtt.size()); + r = _export_secret(km->secret, secret_len, exporter_label_client_1_rtt.data(), exporter_label_client_1_rtt.size()); if (r != 1) { Debug(tag, "Failed to export secret"); return r; } - r = _hkdf_expand_label(km->key, key_len, km->secret, secret_len, expand_label_key.ptr(), expand_label_key.size(), this->_digest); + r = _hkdf_expand_label(km->key, key_len, km->secret, secret_len, expand_label_key.data(), expand_label_key.size(), this->_digest); if (r != 1) { Debug(tag, "Failed to expand label for key"); return r; } - r = _hkdf_expand_label(km->iv, iv_len, km->secret, secret_len, expand_label_iv.ptr(), expand_label_iv.size(), this->_digest); + r = _hkdf_expand_label(km->iv, iv_len, km->secret, secret_len, expand_label_iv.data(), expand_label_iv.size(), this->_digest); if (r != 1) { Debug(tag, "Failed to expand label for iv"); return r; @@ -342,18 +342,18 @@ QUICCrypto::_export_server_keymaterial(size_t secret_len, size_t key_len, size_t KeyMaterial *km = new KeyMaterial(secret_len, key_len, iv_len); int r = 0; - r = _export_secret(km->secret, secret_len, exporter_label_server_1_rtt.ptr(), exporter_label_server_1_rtt.size()); + r = _export_secret(km->secret, secret_len, exporter_label_server_1_rtt.data(), exporter_label_server_1_rtt.size()); if (r != 1) { return r; } - r = _hkdf_expand_label(km->key, key_len, km->secret, secret_len, expand_label_key.ptr(), expand_label_key.size(), this->_digest); + r = _hkdf_expand_label(km->key, key_len, km->secret, secret_len, expand_label_key.data(), expand_label_key.size(), this->_digest); if (r != 1) { Debug(tag, "Failed to expand label for key"); return r; } - r = _hkdf_expand_label(km->iv, iv_len, km->secret, secret_len, expand_label_iv.ptr(), expand_label_iv.size(), this->_digest); + r = _hkdf_expand_label(km->iv, iv_len, km->secret, secret_len, expand_label_iv.data(), expand_label_iv.size(), this->_digest); if (r != 1) { Debug(tag, "Failed to expand label for iv"); return r; diff --git a/proxy/hq/HQClientSession.cc b/proxy/hq/HQClientSession.cc index ce4d6cc7d48..91b003599af 100644 --- a/proxy/hq/HQClientSession.cc +++ b/proxy/hq/HQClientSession.cc @@ -125,7 +125,7 @@ HQClientSession::release(ProxyClientTransaction *trans) } int -HQClientSession::populate_protocol(ts::StringView *result, int size) const +HQClientSession::populate_protocol(ts::string_view *result, int size) const { int retval = 0; if (size > retval) { diff --git a/proxy/hq/HQClientSession.h b/proxy/hq/HQClientSession.h index 0eaecc82e4c..964be0adc3e 100644 --- a/proxy/hq/HQClientSession.h +++ b/proxy/hq/HQClientSession.h @@ -50,7 +50,7 @@ class HQClientSession : public ProxyClientSession int get_transact_count() const override; const char *get_protocol_string() const override; void release(ProxyClientTransaction *trans) override; - int populate_protocol(ts::StringView *result, int size) const override; + int populate_protocol(ts::string_view *result, int size) const override; // HQClientSession specific methods void add_transaction(HQClientTransaction *); From 7e1cd27bec7631de9be8ef8a686ca8a99fc6fc56 Mon Sep 17 00:00:00 2001 From: IvanStarodubtsev Date: Fri, 27 Oct 2017 11:15:39 +0300 Subject: [PATCH 0171/1313] QUIC_TLS* defines are extra to IETF QUIC draft --- iocore/net/P_QUICNetVConnection.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 315ec24b735..431ff7685cb 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -70,17 +70,6 @@ #define QUIC_OP_HANDSHAKE 0x16 -// TS-2503: dynamic TLS record sizing -// For smaller records, we should also reserve space for various TCP options -// (timestamps, SACKs.. up to 40 bytes [1]), and account for TLS record overhead -// (another 20-60 bytes on average, depending on the negotiated ciphersuite [2]). -// All in all: 1500 - 40 (IP) - 20 (TCP) - 40 (TCP options) - TLS overhead (60-100) -// For larger records, the size is determined by TLS protocol record size -#define QUIC_DEF_TLS_RECORD_SIZE 1300 // 1500 - 40 (IP) - 20 (TCP) - 40 (TCP options) - TLS overhead (60-100) -#define QUIC_MAX_TLS_RECORD_SIZE 16383 // 2^14 - 1 -#define QUIC_DEF_TLS_RECORD_BYTE_THRESHOLD 1000000 -#define QUIC_DEF_TLS_RECORD_MSEC_THRESHOLD 1000 - // class QUICNextProtocolSet; // struct QUICCertLookup; From 1bb9f2eb160b017c0e28bea661c45094c76df555 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 8 Nov 2017 14:21:55 +0900 Subject: [PATCH 0172/1313] Update Makefile to build tests --- iocore/net/quic/test/Makefile.am | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index b53ec4d120e..5b7572902bc 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -139,6 +139,8 @@ test_QUICFrame_SOURCES = \ test_QUICFrame_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a # @@ -205,6 +207,8 @@ test_QUICStreamState_SOURCES = \ test_QUICStreamState_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ @LIBTCL@ \ @@ -378,6 +382,9 @@ test_QUICTypeUtil_LDFLAGS = \ test_QUICTypeUtil_LDADD = \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ $(top_builddir)/lib/ts/libtsutil.la test_QUICTypeUtil_SOURCES = \ @@ -405,6 +412,9 @@ test_QUICAckFrameCreator_LDFLAGS = \ test_QUICAckFrameCreator_LDADD = \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ $(top_builddir)/lib/ts/libtsutil.la test_QUICAckFrameCreator_SOURCES = \ From d6cac6a7024077486a3408be10392fa2716e3bc2 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 13 Nov 2017 17:54:10 +0900 Subject: [PATCH 0173/1313] Extract HKDF logic to use it for cleartext packet validation --- iocore/net/quic/QUICCrypto.cc | 32 +-- iocore/net/quic/QUICCrypto.h | 20 +- iocore/net/quic/QUICCrypto_openssl.cc | 34 --- lib/ts/HKDF.cc | 44 ++++ lib/ts/HKDF.h | 48 ++++ lib/ts/HKDF_openssl.cc | 80 +++++++ lib/ts/Makefile.am | 12 +- lib/ts/unit-tests/test_HKDF.cc | 311 ++++++++++++++++++++++++++ 8 files changed, 517 insertions(+), 64 deletions(-) create mode 100644 lib/ts/HKDF.cc create mode 100644 lib/ts/HKDF.h create mode 100644 lib/ts/HKDF_openssl.cc create mode 100644 lib/ts/unit-tests/test_HKDF.cc diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 20414c6e9ee..3c6446df63b 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -27,6 +27,7 @@ #include #include +#include "ts/HKDF.h" #include "ts/Diags.h" #include "ts/string_view.h" #include "QUICTypes.h" @@ -99,6 +100,7 @@ QUICCrypto::QUICCrypto(SSL *ssl, NetVConnectionContext_t nvc_ctx) : _ssl(ssl), _ QUICCrypto::~QUICCrypto() { + delete this->_hkdf; delete this->_client_pp; delete this->_server_pp; } @@ -163,6 +165,7 @@ QUICCrypto::setup_session() const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); this->_digest = _get_handshake_digest(cipher); this->_aead = _get_evp_aead(cipher); + this->_hkdf = new HKDF(this->_digest); size_t secret_len = EVP_MD_size(this->_digest); size_t key_len = _get_aead_key_len(this->_aead); @@ -316,13 +319,15 @@ QUICCrypto::_export_client_keymaterial(size_t secret_len, size_t key_len, size_t return r; } - r = _hkdf_expand_label(km->key, key_len, km->secret, secret_len, expand_label_key.data(), expand_label_key.size(), this->_digest); + r = this->_hkdf->expand_label(km->key, &key_len, km->secret, secret_len, expand_label_key.data(), expand_label_key.size(), + EVP_MD_size(this->_digest)); if (r != 1) { Debug(tag, "Failed to expand label for key"); return r; } - r = _hkdf_expand_label(km->iv, iv_len, km->secret, secret_len, expand_label_iv.data(), expand_label_iv.size(), this->_digest); + r = this->_hkdf->expand_label(km->iv, &iv_len, km->secret, secret_len, expand_label_iv.data(), expand_label_iv.size(), + EVP_MD_size(this->_digest)); if (r != 1) { Debug(tag, "Failed to expand label for iv"); return r; @@ -347,13 +352,15 @@ QUICCrypto::_export_server_keymaterial(size_t secret_len, size_t key_len, size_t return r; } - r = _hkdf_expand_label(km->key, key_len, km->secret, secret_len, expand_label_key.data(), expand_label_key.size(), this->_digest); + r = this->_hkdf->expand_label(km->key, &key_len, km->secret, secret_len, expand_label_key.data(), expand_label_key.size(), + EVP_MD_size(this->_digest)); if (r != 1) { Debug(tag, "Failed to expand label for key"); return r; } - r = _hkdf_expand_label(km->iv, iv_len, km->secret, secret_len, expand_label_iv.data(), expand_label_iv.size(), this->_digest); + r = this->_hkdf->expand_label(km->iv, &iv_len, km->secret, secret_len, expand_label_iv.data(), expand_label_iv.size(), + EVP_MD_size(this->_digest)); if (r != 1) { Debug(tag, "Failed to expand label for iv"); return r; @@ -391,20 +398,3 @@ QUICCrypto::_gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, cons nonce[iv_len - 8 + i] ^= p[i]; } } - -bool -QUICCrypto::_gen_info(uint8_t *info, size_t &info_len, const char *label, size_t label_len, size_t length) const -{ - info[0] = length / 256; - info[1] = length % 256; - info[2] = label_len; - info_len += 3; - - memcpy(info + info_len, label, label_len); - info_len += label_len; - - info[info_len] = 0x00; - ++info_len; - - return true; -} diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICCrypto.h index 1eb24ac9882..3e8e0fd741d 100644 --- a/iocore/net/quic/QUICCrypto.h +++ b/iocore/net/quic/QUICCrypto.h @@ -23,6 +23,7 @@ #pragma once +#include "ts/HKDF.h" #include #ifdef OPENSSL_IS_BORINGSSL @@ -39,11 +40,14 @@ struct KeyMaterial { KeyMaterial(size_t secret_len, size_t key_len, size_t iv_len) : secret_len(secret_len), key_len(key_len), iv_len(iv_len) {} uint8_t secret[EVP_MAX_MD_SIZE] = {0}; - uint8_t key[EVP_MAX_KEY_LENGTH] = {0}; - uint8_t iv[EVP_MAX_IV_LENGTH] = {0}; - size_t secret_len = 0; - size_t key_len = 0; - size_t iv_len = 0; + // These constant sizes are not enough somehow + // uint8_t key[EVP_MAX_KEY_LENGTH] = {0}; + // uint8_t iv[EVP_MAX_IV_LENGTH] = {0}; + uint8_t key[512] = {0}; + uint8_t iv[512] = {0}; + size_t secret_len = 0; + size_t key_len = 0; + size_t iv_len = 0; }; class QUICPacketProtection @@ -81,13 +85,13 @@ class QUICCrypto SSL *ssl_handle(); private: + HKDF *_hkdf = nullptr; int _export_secret(uint8_t *dst, size_t dst_len, const char *label, size_t label_len) const; int _export_client_keymaterial(size_t secret_len, size_t key_len, size_t iv_len); int _export_server_keymaterial(size_t secret_len, size_t key_len, size_t iv_len); void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; - bool _gen_info(uint8_t *info, size_t &info_len, const char *label, size_t label_len, size_t length) const; - int _hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, - size_t label_len, const EVP_MD *digest) const; + int _hkdf_expand_label(const uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, + size_t label_len, const EVP_MD *digest); #ifdef OPENSSL_IS_BORINGSSL const EVP_AEAD *_get_evp_aead(const SSL_CIPHER *cipher) const; size_t _get_aead_key_len(const EVP_AEAD *aead) const; diff --git a/iocore/net/quic/QUICCrypto_openssl.cc b/iocore/net/quic/QUICCrypto_openssl.cc index 511db00ecc6..b2858f3d6ca 100644 --- a/iocore/net/quic/QUICCrypto_openssl.cc +++ b/iocore/net/quic/QUICCrypto_openssl.cc @@ -97,40 +97,6 @@ QUICCrypto::_get_aead_nonce_len(const EVP_CIPHER *aead) const return EVP_CIPHER_iv_length(aead); } -int -QUICCrypto::_hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, - size_t label_len, const EVP_MD *digest) const -{ - uint8_t info[256] = {0}; - size_t info_len = 0; - _gen_info(info, info_len, label, label_len, dst_len); - - EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr); - if (!EVP_PKEY_derive_init(pctx)) { - return -1; - } - if (!EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY)) { - return -1; - } - if (!EVP_PKEY_CTX_set_hkdf_md(pctx, digest)) { - return -1; - } - if (!EVP_PKEY_CTX_set1_hkdf_salt(pctx, "", 0)) { - return -1; - } - if (!EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secret_len)) { - return -1; - } - if (!EVP_PKEY_CTX_add1_hkdf_info(pctx, info, info_len)) { - return -1; - } - if (!EVP_PKEY_derive(pctx, dst, &dst_len)) { - return -1; - } - - return 1; -} - bool QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, diff --git a/lib/ts/HKDF.cc b/lib/ts/HKDF.cc new file mode 100644 index 00000000000..fe01117e1f1 --- /dev/null +++ b/lib/ts/HKDF.cc @@ -0,0 +1,44 @@ +/** @file + * + * HKDF utility (common part) + * + * @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 "HKDF.h" +#include +#include + +int +HKDF::expand_label(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, + uint16_t length) +{ + // Create HKDF label + uint8_t hkdf_label[512]; // 2 + 255 + 255 + // Length + hkdf_label[0] = (length >> 8) & 0xFF; + hkdf_label[1] = length & 0xFF; + // "tls13 " + Label + int hkdf_label_len = sprintf(reinterpret_cast(hkdf_label + 2), "tls13 %.*s", static_cast(label_len), label); + // Always 0 + hkdf_label[hkdf_label_len] = 0; + ++hkdf_label_len; + + this->expand(dst, dst_len, secret, secret_len, hkdf_label, hkdf_label_len, length); + return 1; +} diff --git a/lib/ts/HKDF.h b/lib/ts/HKDF.h new file mode 100644 index 00000000000..e659adaa767 --- /dev/null +++ b/lib/ts/HKDF.h @@ -0,0 +1,48 @@ +/** @file + + HKDF utility + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#ifdef OPENSSL_IS_BORINGSSL +#include +#include +#else +#include +#endif + +class HKDF +{ +public: + HKDF(const EVP_MD *digest); + int extract(uint8_t *dst, size_t *dst_len, const uint8_t *salt, size_t salt_len, const uint8_t *ikm, size_t ikm_len); + int expand(uint8_t *dst, size_t *dst_len, const uint8_t *prk, size_t prk_len, const uint8_t *info, size_t info_len, + uint16_t length); + + // This function is technically a part of TLS 1.3 + int expand_label(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, + uint16_t length); + +private: + const EVP_MD *_digest = nullptr; + EVP_PKEY_CTX *_pctx = nullptr; +}; diff --git a/lib/ts/HKDF_openssl.cc b/lib/ts/HKDF_openssl.cc new file mode 100644 index 00000000000..af0e87f7e90 --- /dev/null +++ b/lib/ts/HKDF_openssl.cc @@ -0,0 +1,80 @@ +/** @file + * + * HKDF utility (OpenSSL version) + * + * @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 "HKDF.h" +#include + +HKDF::HKDF(const EVP_MD *digest) : _digest(digest) +{ + this->_pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr); +} + +int +HKDF::extract(uint8_t *dst, size_t *dst_len, const uint8_t *salt, size_t salt_len, const uint8_t *ikm, size_t ikm_len) +{ + if (EVP_PKEY_derive_init(this->_pctx) != 1) { + return -1; + } + if (EVP_PKEY_CTX_hkdf_mode(this->_pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) != 1) { + return -2; + } + if (EVP_PKEY_CTX_set_hkdf_md(this->_pctx, this->_digest) != 1) { + return -3; + } + if (EVP_PKEY_CTX_set1_hkdf_salt(this->_pctx, salt, salt_len) != 1) { + return -4; + } + if (EVP_PKEY_CTX_set1_hkdf_key(this->_pctx, ikm, ikm_len) != 1) { + return -5; + } + if (EVP_PKEY_derive(this->_pctx, dst, dst_len) != 1) { + return -6; + } + return 1; +} + +int +HKDF::expand(uint8_t *dst, size_t *dst_len, const uint8_t *prk, size_t prk_len, const uint8_t *info, size_t info_len, + uint16_t length) +{ + if (EVP_PKEY_derive_init(this->_pctx) != 1) { + return -1; + } + if (EVP_PKEY_CTX_hkdf_mode(this->_pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) != 1) { + return -2; + } + if (EVP_PKEY_CTX_set_hkdf_md(this->_pctx, this->_digest) != 1) { + return -3; + } + if (EVP_PKEY_CTX_set1_hkdf_key(this->_pctx, prk, prk_len) != 1) { + return -5; + } + if (EVP_PKEY_CTX_add1_hkdf_info(this->_pctx, info, info_len) != 1) { + return -6; + } + *dst_len = length; + if (EVP_PKEY_derive(this->_pctx, dst, dst_len) != 1) { + return -7; + } + + return 1; +} diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am index cf4f82df025..50626444074 100644 --- a/lib/ts/Makefile.am +++ b/lib/ts/Makefile.am @@ -44,6 +44,12 @@ libtsutil_la_LIBADD = \ @LIBCAP@ \ -lc +if OPENSSL_IS_BORINGSSL +HKDF_impl = HKDF_boringssl.cc +else +HKDF_impl = HKDF_openssl.cc +endif + libtsutil_la_SOURCES = \ Allocator.h \ Arena.cc \ @@ -73,6 +79,9 @@ libtsutil_la_SOURCES = \ HashSip.cc \ HashSip.h \ History.h \ + HKDF.h \ + HKDF.cc \ + $(HKDF_impl) \ HostLookup.cc \ HostLookup.h \ hugepages.cc \ @@ -259,7 +268,8 @@ test_tslib_SOURCES = \ unit-tests/test_IpMap.cc \ unit-tests/test_layout.cc \ unit-tests/test_string_view.cc \ - unit-tests/test_TextView.cc + unit-tests/test_TextView.cc \ + unit-tests/test_HKDF.cc CompileParseRules_SOURCES = CompileParseRules.cc diff --git a/lib/ts/unit-tests/test_HKDF.cc b/lib/ts/unit-tests/test_HKDF.cc new file mode 100644 index 00000000000..1c4ab5ce30c --- /dev/null +++ b/lib/ts/unit-tests/test_HKDF.cc @@ -0,0 +1,311 @@ +/** @file + + Tests for HKDF + + @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 "catch.hpp" +#include +#include "ts/HKDF.h" + +TEST_CASE("HKDF tests", "[hkdf]") +{ + SECTION("Basic test case with SHA-256") + { + uint8_t ikm[] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + }; + uint8_t salt[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + }; + uint8_t info[] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + }; + uint16_t length = 42; + uint8_t expected_prk[] = { + 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63, + 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5, + }; + uint8_t expected_okm[] = { + 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, + 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65, + }; + + uint8_t prk[256] = {0}; + size_t prk_len = sizeof(prk); + uint8_t okm[256] = {0}; + size_t okm_len = sizeof(okm); + + HKDF hkdf(EVP_sha256()); + + // Extract + CHECK(hkdf.extract(prk, &prk_len, salt, sizeof(salt), ikm, sizeof(ikm)) == 1); + CHECK(prk_len == sizeof(expected_prk)); + CHECK(memcmp(prk, expected_prk, sizeof(expected_prk)) == 0); + + // Expand + CHECK(hkdf.expand(okm, &okm_len, prk, prk_len, info, sizeof(info), length) == 1); + CHECK(okm_len == sizeof(expected_okm)); + CHECK(memcmp(okm, expected_okm, sizeof(expected_okm)) == 0); + } + + SECTION("Test with SHA-256 and longer inputs/outputs") + { + uint8_t ikm[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + }; + uint8_t salt[] = { + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, + 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, + 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + }; + uint8_t info[] = { + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + }; + uint16_t length = 82; + uint8_t expected_prk[] = { + 0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a, 0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35, 0xb4, 0x5c, + 0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01, 0x4a, 0x19, 0x3f, 0x40, 0xc1, 0x5f, 0xc2, 0x44, + }; + uint8_t expected_okm[] = { + 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, + 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, + 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, + 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87, + }; + + uint8_t prk[256] = {0}; + size_t prk_len = sizeof(prk); + uint8_t okm[256] = {0}; + size_t okm_len = sizeof(okm); + + HKDF hkdf(EVP_sha256()); + + // Extract + CHECK(hkdf.extract(prk, &prk_len, salt, sizeof(salt), ikm, sizeof(ikm)) == 1); + CHECK(prk_len == sizeof(expected_prk)); + CHECK(memcmp(prk, expected_prk, sizeof(expected_prk)) == 0); + + // Expand + CHECK(hkdf.expand(okm, &okm_len, prk, prk_len, info, sizeof(info), length) == 1); + CHECK(okm_len == sizeof(expected_okm)); + CHECK(memcmp(okm, expected_okm, sizeof(expected_okm)) == 0); + } + + SECTION("Test with SHA-256 and zero-length salt/info") + { + uint8_t ikm[] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + }; + uint8_t salt[] = {}; + uint8_t info[] = {}; + uint16_t length = 42; + uint8_t expected_prk[] = { + 0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16, 0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf, + 0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77, 0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04, + }; + uint8_t expected_okm[] = { + 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, + 0xe1, 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8, + }; + + uint8_t prk[256] = {0}; + size_t prk_len = sizeof(prk); + uint8_t okm[256] = {0}; + size_t okm_len = sizeof(okm); + + HKDF hkdf(EVP_sha256()); + + // Extract + CHECK(hkdf.extract(prk, &prk_len, salt, sizeof(salt), ikm, sizeof(ikm)) == 1); + CHECK(prk_len == sizeof(expected_prk)); + CHECK(memcmp(prk, expected_prk, sizeof(expected_prk)) == 0); + + // Expand + CHECK(hkdf.expand(okm, &okm_len, prk, prk_len, info, sizeof(info), length) == 1); + CHECK(okm_len == sizeof(expected_okm)); + CHECK(memcmp(okm, expected_okm, sizeof(expected_okm)) == 0); + } + + SECTION("Basic test case with SHA-1") + { + uint8_t ikm[] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + }; + uint8_t salt[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + }; + uint8_t info[] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + }; + uint16_t length = 42; + uint8_t expected_prk[] = { + 0x9b, 0x6c, 0x18, 0xc4, 0x32, 0xa7, 0xbf, 0x8f, 0x0e, 0x71, 0xc8, 0xeb, 0x88, 0xf4, 0xb3, 0x0b, 0xaa, 0x2b, 0xa2, 0x43, + }; + uint8_t expected_okm[] = { + 0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69, 0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81, 0xa4, 0xf1, 0x4b, 0x82, 0x2f, + 0x5b, 0x09, 0x15, 0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2, 0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3, 0xf8, 0x96, + }; + + uint8_t prk[256] = {0}; + size_t prk_len = sizeof(prk); + uint8_t okm[256] = {0}; + size_t okm_len = sizeof(okm); + + HKDF hkdf(EVP_sha1()); + + // Extract + CHECK(hkdf.extract(prk, &prk_len, salt, sizeof(salt), ikm, sizeof(ikm)) == 1); + CHECK(prk_len == sizeof(expected_prk)); + CHECK(memcmp(prk, expected_prk, sizeof(expected_prk)) == 0); + + // Expand + CHECK(hkdf.expand(okm, &okm_len, prk, prk_len, info, sizeof(info), length) == 1); + CHECK(okm_len == sizeof(expected_okm)); + CHECK(memcmp(okm, expected_okm, sizeof(expected_okm)) == 0); + } + + SECTION("Test with SHA-1 and longer inputs/outputs") + { + uint8_t ikm[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + }; + uint8_t salt[] = { + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, + 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, + 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + }; + uint8_t info[] = { + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + }; + uint16_t length = 82; + uint8_t expected_prk[] = {0x8a, 0xda, 0xe0, 0x9a, 0x2a, 0x30, 0x70, 0x59, 0x47, 0x8d, + 0x30, 0x9b, 0x26, 0xc4, 0x11, 0x5a, 0x22, 0x4c, 0xfa, 0xf6}; + uint8_t expected_okm[] = { + 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, + 0x9d, 0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, + 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, + 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, 0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4, + }; + + uint8_t prk[256] = {0}; + size_t prk_len = sizeof(prk); + uint8_t okm[256] = {0}; + size_t okm_len = sizeof(okm); + + HKDF hkdf(EVP_sha1()); + + // Extract + CHECK(hkdf.extract(prk, &prk_len, salt, sizeof(salt), ikm, sizeof(ikm)) == 1); + CHECK(prk_len == sizeof(expected_prk)); + CHECK(memcmp(prk, expected_prk, sizeof(expected_prk)) == 0); + + // Expand + CHECK(hkdf.expand(okm, &okm_len, prk, prk_len, info, sizeof(info), length) == 1); + CHECK(okm_len == sizeof(expected_okm)); + CHECK(memcmp(okm, expected_okm, sizeof(expected_okm)) == 0); + } + + SECTION("Test with SHA-1 and zero-length salt/info") + { + uint8_t ikm[] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + }; + uint8_t salt[] = {}; + uint8_t info[] = {}; + uint16_t length = 42; + uint8_t expected_prk[] = { + 0xda, 0x8c, 0x8a, 0x73, 0xc7, 0xfa, 0x77, 0x28, 0x8e, 0xc6, 0xf5, 0xe7, 0xc2, 0x97, 0x78, 0x6a, 0xa0, 0xd3, 0x2d, 0x01, + }; + uint8_t expected_okm[] = { + 0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, 0xd1, 0xe5, 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06, 0xb9, 0xae, 0x52, 0x05, 0x72, + 0x20, 0xa3, 0x06, 0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0, 0xea, 0x00, 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3, 0x49, 0x18, + }; + + uint8_t prk[256] = {0}; + size_t prk_len = sizeof(prk); + uint8_t okm[256] = {0}; + size_t okm_len = sizeof(okm); + + HKDF hkdf(EVP_sha1()); + + // Extract + CHECK(hkdf.extract(prk, &prk_len, salt, sizeof(salt), ikm, sizeof(ikm)) == 1); + CHECK(prk_len == sizeof(expected_prk)); + CHECK(memcmp(prk, expected_prk, sizeof(expected_prk)) == 0); + + // Expand + CHECK(hkdf.expand(okm, &okm_len, prk, prk_len, info, sizeof(info), length) == 1); + CHECK(okm_len == sizeof(expected_okm)); + CHECK(memcmp(okm, expected_okm, sizeof(expected_okm)) == 0); + } + + SECTION("Test with SHA-1, salt not provided (defaults to HashLen zero octets)") + { + uint8_t ikm[] = { + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + }; + uint8_t salt[] = {}; + uint8_t info[] = {}; + uint16_t length = 42; + uint8_t expected_prk[] = { + 0x2a, 0xdc, 0xca, 0xda, 0x18, 0x77, 0x9e, 0x7c, 0x20, 0x77, 0xad, 0x2e, 0xb1, 0x9d, 0x3f, 0x3e, 0x73, 0x13, 0x85, 0xdd, + }; + uint8_t expected_okm[] = { + 0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3, 0x50, 0x0d, 0x63, 0x6a, 0x62, 0xf6, 0x4f, 0x0a, 0xb3, 0xba, 0xe5, 0x48, 0xaa, + 0x53, 0xd4, 0x23, 0xb0, 0xd1, 0xf2, 0x7e, 0xbb, 0xa6, 0xf5, 0xe5, 0x67, 0x3a, 0x08, 0x1d, 0x70, 0xcc, 0xe7, 0xac, 0xfc, 0x48, + }; + + uint8_t prk[256] = {0}; + size_t prk_len = sizeof(prk); + uint8_t okm[256] = {0}; + size_t okm_len = sizeof(okm); + + HKDF hkdf(EVP_sha1()); + + // Extract + CHECK(hkdf.extract(prk, &prk_len, salt, sizeof(salt), ikm, sizeof(ikm)) == 1); + CHECK(prk_len == sizeof(expected_prk)); + CHECK(memcmp(prk, expected_prk, sizeof(expected_prk)) == 0); + + // Expand + CHECK(hkdf.expand(okm, &okm_len, prk, prk_len, info, sizeof(info), length) == 1); + CHECK(okm_len == sizeof(expected_okm)); + CHECK(memcmp(okm, expected_okm, sizeof(expected_okm)) == 0); + } +} From f04b6b5939cd3f59e0a0de4bbd7302112bdcf8cc Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 15 Nov 2017 14:15:40 +0900 Subject: [PATCH 0174/1313] Add APPLICATION_CLOSE frame and change Error Code --- iocore/net/QUICNetVConnection.cc | 29 ++-- iocore/net/quic/QUICDebugNames.cc | 54 +++---- iocore/net/quic/QUICDebugNames.h | 2 +- iocore/net/quic/QUICFlowController.cc | 2 +- iocore/net/quic/QUICFrame.cc | 152 ++++++++++++++---- iocore/net/quic/QUICFrame.h | 66 ++++++-- iocore/net/quic/QUICHandshake.cc | 17 +- iocore/net/quic/QUICIncomingFrameBuffer.cc | 6 +- iocore/net/quic/QUICStream.cc | 12 +- iocore/net/quic/QUICStreamManager.cc | 8 +- iocore/net/quic/QUICTypes.cc | 28 +++- iocore/net/quic/QUICTypes.h | 67 ++++---- .../net/quic/test/test_QUICFlowController.cc | 6 +- iocore/net/quic/test/test_QUICFrame.cc | 134 ++++++++++----- .../quic/test/test_QUICIncomingFrameBuffer.cc | 6 +- iocore/net/quic/test/test_QUICStream.cc | 3 +- .../net/quic/test/test_QUICStreamManager.cc | 3 +- iocore/net/quic/test/test_QUICStreamState.cc | 8 +- 18 files changed, 416 insertions(+), 187 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 7a4c45758b3..29833c6cade 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -301,7 +301,11 @@ QUICNetVConnection::close(QUICConnectionErrorUPtr error) } else { DebugQUICCon("Enter state_connection_closing"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); - this->transmit_frame(QUICFrameFactory::create_connection_close_frame(std::move(error))); + if (error->cls == QUICErrorClass::APPLICATION) { + this->transmit_frame(QUICFrameFactory::create_application_close_frame(std::move(error))); + } else { + this->transmit_frame(QUICFrameFactory::create_connection_close_frame(std::move(error))); + } } } @@ -403,7 +407,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) this_ethread()->schedule_imm_local(this, event); break; default: - error = QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR)); + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); break; } @@ -450,8 +454,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) Continuation *endpoint = this->_next_protocol_set->findEndpoint(app_name, app_name_len); if (endpoint == nullptr) { - this->_handle_error( - QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::VERSION_NEGOTIATION_ERROR))); + this->_handle_error(QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR))); } else { endpoint->handleEvent(NET_EVENT_ACCEPT, this); } @@ -489,7 +492,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) } if (error->cls != QUICErrorClass::NONE) { - DebugQUICCon("QUICError: cls=%u, code=0x%x", static_cast(error->cls), static_cast(error->code)); + DebugQUICCon("QUICError: cls=%u, code=0x%" PRIu16, static_cast(error->cls), error->code()); this->_handle_error(std::move(error)); } @@ -708,8 +711,8 @@ QUICNetVConnection::_state_connection_established_process_packet(QUICPacketUPtr packet->header_size(), plain_txt_len); return this->_recv_and_ack(plain_txt.get(), plain_txt_len, packet->packet_number()); } else { - DebugQUICCon("CRYPTOGRAPHIC Error"); - return QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::CRYPTOGRAPHIC_ERROR)); + DebugQUICCon("Decrypt Error"); + return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); } } @@ -732,7 +735,7 @@ QUICNetVConnection::_state_common_receive_packet() // FIXME Just ignore for now but it has to be acked (GitHub#2609) break; default: - error = QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR)); + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); break; } return error; @@ -941,8 +944,14 @@ QUICNetVConnection::_init_flow_control_params(const std::shared_ptrcls), static_cast(error->cls), - QUICDebugNames::error_code(error->code), static_cast(error->code)); + if (error->cls == QUICErrorClass::APPLICATION) { + DebugQUICCon("QUICError: %s (%u), APPLICATION ERROR (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), error->code()); + } else { + DebugQUICCon("QUICError: %s (%u), %s (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), QUICDebugNames::error_code(error->trans_error_code), error->code()); + } + if (dynamic_cast(error.get()) != nullptr) { // Stream Error QUICStreamError *serror = static_cast(error.release()); diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 5526d2dea6a..7e4fd44525c 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -94,58 +94,48 @@ QUICDebugNames::error_class(QUICErrorClass cls) switch (cls) { case QUICErrorClass::NONE: return "NONE"; - case QUICErrorClass::AQPPLICATION_SPECIFIC: - return "AQPPLICATION_SPECIFIC"; - case QUICErrorClass::HOST_LOCAL: - return "HOST_LOCAL"; - case QUICErrorClass::QUIC_TRANSPORT: - return "QUIC_TRANSPORT"; - case QUICErrorClass::CRYPTOGRAPHIC: - return "CRYPTOGRAPHIC"; + case QUICErrorClass::TRANSPORT: + return "TRANSPORT"; + case QUICErrorClass::APPLICATION: + return "APPLICATION"; default: return "UNKNOWN"; } } const char * -QUICDebugNames::error_code(QUICErrorCode code) +QUICDebugNames::error_code(QUICTransErrorCode code) { switch (code) { - case QUICErrorCode::APPLICATION_SPECIFIC_ERROR: - return "APPLICATION_SPECIFIC_ERROR"; - case QUICErrorCode::HOST_LOCAL_ERROR: - return "HOST_LOCAL_ERROR"; - case QUICErrorCode::NO_ERROR: + case QUICTransErrorCode::NO_ERROR: return "NO_ERROR"; - case QUICErrorCode::INTERNAL_ERROR: + case QUICTransErrorCode::INTERNAL_ERROR: return "INTERNAL_ERROR"; - case QUICErrorCode::CANCELLED: - return "CANCELLED"; - case QUICErrorCode::FLOW_CONTROL_ERROR: + case QUICTransErrorCode::FLOW_CONTROL_ERROR: return "FLOW_CONTROL_ERROR"; - case QUICErrorCode::STREAM_ID_ERROR: + case QUICTransErrorCode::STREAM_ID_ERROR: return "STREAM_ID_ERROR"; - case QUICErrorCode::STREAM_STATE_ERROR: + case QUICTransErrorCode::STREAM_STATE_ERROR: return "STREAM_STATE_ERROR"; - case QUICErrorCode::FINAL_OFFSET_ERROR: + case QUICTransErrorCode::FINAL_OFFSET_ERROR: return "FINAL_OFFSET_ERROR"; - case QUICErrorCode::FRAME_FORMAT_ERROR: + case QUICTransErrorCode::FRAME_FORMAT_ERROR: return "FRAME_FORMAT_ERROR"; - case QUICErrorCode::TRANSPORT_PARAMETER_ERROR: + case QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR: return "TRANSPORT_PARAMETER_ERROR"; - case QUICErrorCode::VERSION_NEGOTIATION_ERROR: + case QUICTransErrorCode::VERSION_NEGOTIATION_ERROR: return "VERSION_NEGOTIATION_ERROR"; - case QUICErrorCode::PROTOCOL_VIOLATION: + case QUICTransErrorCode::PROTOCOL_VIOLATION: return "PROTOCOL_VIOLATION"; - case QUICErrorCode::QUIC_RECEIVED_RST: - return "QUIC_RECEIVED_RST"; - case QUICErrorCode::CRYPTOGRAPHIC_ERROR: - return "CRYPTOGRAPHIC_ERROR"; - case QUICErrorCode::TLS_HANDSHAKE_FAILED: + case QUICTransErrorCode::TLS_HANDSHAKE_FAILED: return "TLS_HANDSHAKE_FAILED"; + case QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED: + return "TLS_FATAL_ALERT_GENERATED"; + case QUICTransErrorCode::TLS_FATAL_ALERT_RECEIVED: + return "TLS_FATAL_ALERT_RECEIVED"; default: - if ((static_cast(code) & 0xFFFFFF00) == static_cast(QUICErrorCode::FRAME_ERROR)) { - // TODO: Add frame type + if (0x0100 <= static_cast(code) && static_cast(code) <= 0x01FF) { + // TODO: Add frame types return "FRAME_ERROR"; } return "UNKNOWN"; diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index 7b406d4716e..8ccac293551 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -34,7 +34,7 @@ class QUICDebugNames static const char *packet_type(QUICPacketType type); static const char *frame_type(QUICFrameType type); static const char *error_class(QUICErrorClass cls); - static const char *error_code(QUICErrorCode code); + static const char *error_code(QUICTransErrorCode code); static const char *transport_parameter_id(QUICTransportParameterId id); static const char *stream_state(QUICStreamState state); static const char *quic_event(int event); diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 18deeeaffbb..6c497aad7f1 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -46,7 +46,7 @@ QUICFlowController::update(QUICOffset offset) if (this->_offset <= offset) { // Assume flow control is not initialized if the limit was 0 if (this->_limit != 0 && offset > this->_limit) { - return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FLOW_CONTROL_ERROR)); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } this->_offset = offset; } diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 4bb02b4ad85..4fb864b3bf1 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -29,6 +29,7 @@ ClassAllocator quicAckFrameAllocator("quicAckFrameAllocator"); ClassAllocator quicPaddingFrameAllocator("quicPaddingFrameAllocator"); ClassAllocator quicRstStreamFrameAllocator("quicRstStreamFrameAllocator"); ClassAllocator quicConnectionCloseFrameAllocator("quicConnectionCloseFrameAllocator"); +ClassAllocator quicApplicationCloseFrameAllocator("quicApplicationCloseFrameAllocator"); ClassAllocator quicMaxDataFrameAllocator("quicMaxDataFrameAllocator"); ClassAllocator quicMaxStreamDataFrameAllocator("quicMaxStreamDataFrameAllocator"); ClassAllocator quicMaxStreamIdFrameAllocator("quicMaxStreamDataIdAllocator"); @@ -46,7 +47,6 @@ QUICFrame::type() const return QUICFrame::type(this->_buf); } -// XXX QUICFrameType: 0x03 (GOAWAY frame) is removed QUICFrameType QUICFrame::type(const uint8_t *buf) { @@ -54,7 +54,7 @@ QUICFrame::type(const uint8_t *buf) return QUICFrameType::STREAM; } else if (buf[0] >= static_cast(QUICFrameType::ACK)) { return QUICFrameType::ACK; - } else if (buf[0] > static_cast(QUICFrameType::STOP_SENDING) || buf[0] == 0x03) { + } else if (buf[0] > static_cast(QUICFrameType::STOP_SENDING)) { return QUICFrameType::UNKNOWN; } else { return static_cast(buf[0]); @@ -664,7 +664,7 @@ QUICAckFrame::TimestampSection::store(uint8_t *buf, size_t *len) const // RST_STREAM frame // -QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICErrorCode error_code, QUICOffset final_offset) +QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset) : _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset) { } @@ -675,10 +675,11 @@ QUICRstStreamFrame::type() const return QUICFrameType::RST_STREAM; } +// 8 + 32 + 16 + 64 bit size_t QUICRstStreamFrame::size() const { - return 17; + return 15; } void @@ -690,7 +691,7 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len) const ++p; QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n); p += n; - QUICTypeUtil::write_QUICErrorCode(this->_error_code, p, &n); + QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); p += n; QUICTypeUtil::write_QUICOffset(this->_final_offset, 8, p, &n); p += n; @@ -698,11 +699,11 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } -QUICErrorCode +QUICAppErrorCode QUICRstStreamFrame::error_code() const { if (this->_buf) { - return QUICTypeUtil::read_QUICErrorCode(this->_buf + 5); + return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + 5); } else { return this->_error_code; } @@ -722,7 +723,7 @@ QUICOffset QUICRstStreamFrame::final_offset() const { if (this->_buf) { - return QUICTypeUtil::read_QUICOffset(this->_buf + 9, 8); + return QUICTypeUtil::read_QUICOffset(this->_buf + 7, 8); } else { return this->_final_offset; } @@ -775,8 +776,7 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len) const // // CONNECTION_CLOSE frame // - -QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICErrorCode error_code, uint16_t reason_phrase_length, +QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase) { this->_error_code = error_code; @@ -793,7 +793,7 @@ QUICConnectionCloseFrame::type() const size_t QUICConnectionCloseFrame::size() const { - return 7 + this->reason_phrase_length(); + return 5 + this->reason_phrase_length(); } void @@ -803,7 +803,7 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len) const uint8_t *p = buf; *p = static_cast(QUICFrameType::CONNECTION_CLOSE); ++p; - QUICTypeUtil::write_QUICErrorCode(this->_error_code, p, &n); + QUICTypeUtil::write_QUICTransErrorCode(this->_error_code, p, &n); p += n; QUICTypeUtil::write_uint_as_nbytes(this->_reason_phrase_length, 2, p, &n); p += n; @@ -815,11 +815,11 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } -QUICErrorCode +QUICTransErrorCode QUICConnectionCloseFrame::error_code() const { if (this->_buf) { - return QUICTypeUtil::read_QUICErrorCode(this->_buf + 1); + return QUICTypeUtil::read_QUICTransErrorCode(this->_buf + 1); } else { return this->_error_code; } @@ -829,7 +829,7 @@ uint16_t QUICConnectionCloseFrame::reason_phrase_length() const { if (this->_buf) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 5, 2); + return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 3, 2); } else { return this->_reason_phrase_length; } @@ -839,7 +839,79 @@ const char * QUICConnectionCloseFrame::reason_phrase() const { if (this->_buf) { - return reinterpret_cast(this->_buf + 7); + return reinterpret_cast(this->_buf + 5); + } else { + return this->_reason_phrase; + } +} + +// +// APPLICATION_CLOSE frame +// +QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint16_t reason_phrase_length, + const char *reason_phrase) +{ + this->_error_code = error_code; + this->_reason_phrase_length = reason_phrase_length; + this->_reason_phrase = reason_phrase; +} + +QUICFrameType +QUICApplicationCloseFrame::type() const +{ + return QUICFrameType::APPLICATION_CLOSE; +} + +size_t +QUICApplicationCloseFrame::size() const +{ + return 5 + this->reason_phrase_length(); +} + +void +QUICApplicationCloseFrame::store(uint8_t *buf, size_t *len) const +{ + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::APPLICATION_CLOSE); + ++p; + QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); + p += n; + QUICTypeUtil::write_uint_as_nbytes(this->_reason_phrase_length, 2, p, &n); + p += n; + if (this->_reason_phrase_length > 0) { + memcpy(p, this->_reason_phrase, this->_reason_phrase_length); + p += this->_reason_phrase_length; + } + + *len = p - buf; +} + +QUICAppErrorCode +QUICApplicationCloseFrame::error_code() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + 1); + } else { + return this->_error_code; + } +} + +uint16_t +QUICApplicationCloseFrame::reason_phrase_length() const +{ + if (this->_buf) { + return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 3, 2); + } else { + return this->_reason_phrase_length; + } +} + +const char * +QUICApplicationCloseFrame::reason_phrase() const +{ + if (this->_buf) { + return reinterpret_cast(this->_buf + 5); } else { return this->_reason_phrase; } @@ -1135,7 +1207,7 @@ QUICNewConnectionIdFrame::connection_id() const // STOP_SENDING frame // -QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICErrorCode error_code) +QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code) : _stream_id(stream_id), _error_code(error_code) { } @@ -1149,7 +1221,7 @@ QUICStopSendingFrame::type() const size_t QUICStopSendingFrame::size() const { - return 9; + return 7; } void @@ -1161,17 +1233,17 @@ QUICStopSendingFrame::store(uint8_t *buf, size_t *len) const ++p; QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n); p += n; - QUICTypeUtil::write_QUICErrorCode(this->_error_code, p, &n); + QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); p += n; *len = p - buf; } -QUICErrorCode +QUICAppErrorCode QUICStopSendingFrame::error_code() const { if (this->_buf) { - return QUICTypeUtil::read_QUICErrorCode(this->_buf + 5); + return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + 5); } else { return this->_error_code; } @@ -1249,6 +1321,10 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicConnectionCloseFrameAllocator.alloc(); new (frame) QUICConnectionCloseFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_connection_close_frame); + case QUICFrameType::APPLICATION_CLOSE: + frame = quicApplicationCloseFrameAllocator.alloc(); + new (frame) QUICApplicationCloseFrame(buf, len); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_application_close_frame); case QUICFrameType::MAX_DATA: frame = quicMaxDataFrameAllocator.alloc(); new (frame) QUICMaxDataFrame(buf, len); @@ -1332,7 +1408,8 @@ QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint16 } std::unique_ptr -QUICFrameFactory::create_connection_close_frame(QUICErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase) +QUICFrameFactory::create_connection_close_frame(QUICTransErrorCode error_code, uint16_t reason_phrase_length, + const char *reason_phrase) { QUICConnectionCloseFrame *frame = quicConnectionCloseFrameAllocator.alloc(); new (frame) QUICConnectionCloseFrame(error_code, reason_phrase_length, reason_phrase); @@ -1342,10 +1419,31 @@ QUICFrameFactory::create_connection_close_frame(QUICErrorCode error_code, uint16 std::unique_ptr QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error) { + ink_assert(error->cls == QUICErrorClass::TRANSPORT); + if (error->msg) { + return QUICFrameFactory::create_connection_close_frame(error->trans_error_code, strlen(error->msg), error->msg); + } else { + return QUICFrameFactory::create_connection_close_frame(error->trans_error_code); + } +} + +std::unique_ptr +QUICFrameFactory::create_application_close_frame(QUICAppErrorCode error_code, uint16_t reason_phrase_length, + const char *reason_phrase) +{ + QUICApplicationCloseFrame *frame = quicApplicationCloseFrameAllocator.alloc(); + new (frame) QUICApplicationCloseFrame(error_code, reason_phrase_length, reason_phrase); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); +} + +std::unique_ptr +QUICFrameFactory::create_application_close_frame(QUICConnectionErrorUPtr error) +{ + ink_assert(error->cls == QUICErrorClass::APPLICATION); if (error->msg) { - return QUICFrameFactory::create_connection_close_frame(error->code, strlen(error->msg), error->msg); + return QUICFrameFactory::create_application_close_frame(error->app_error_code, strlen(error->msg), error->msg); } else { - return QUICFrameFactory::create_connection_close_frame(error->code); + return QUICFrameFactory::create_application_close_frame(error->app_error_code); } } @@ -1382,7 +1480,7 @@ QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id) } std::unique_ptr -QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICErrorCode error_code, QUICOffset final_offset) +QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset) { QUICRstStreamFrame *frame = quicRstStreamFrameAllocator.alloc(); new (frame) QUICRstStreamFrame(stream_id, error_code, final_offset); @@ -1392,11 +1490,11 @@ QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICErrorCode std::unique_ptr QUICFrameFactory::create_rst_stream_frame(QUICStreamErrorUPtr error) { - return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->code, error->stream->final_offset()); + return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->app_error_code, error->stream->final_offset()); } std::unique_ptr -QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICErrorCode error_code) +QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICAppErrorCode error_code) { QUICStopSendingFrame *frame = quicStopSendingFrameAllocator.alloc(); new (frame) QUICStopSendingFrame(stream_id, error_code); diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index dad9a6c95b0..87509aa80cd 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -219,18 +219,18 @@ class QUICRstStreamFrame : public QUICFrame public: QUICRstStreamFrame() : QUICFrame() {} QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICRstStreamFrame(QUICStreamId stream_id, QUICErrorCode error_code, QUICOffset final_offset); + QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; - QUICErrorCode error_code() const; + QUICAppErrorCode error_code() const; QUICStreamId stream_id() const; QUICOffset final_offset() const; private: - QUICStreamId _stream_id = 0; - QUICErrorCode _error_code; - QUICOffset _final_offset = 0; + QUICStreamId _stream_id = 0; + QUICAppErrorCode _error_code = 0; + QUICOffset _final_offset = 0; }; // @@ -268,16 +268,39 @@ class QUICConnectionCloseFrame : public QUICFrame public: QUICConnectionCloseFrame() : QUICFrame() {} QUICConnectionCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICConnectionCloseFrame(QUICErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase); + QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; - QUICErrorCode error_code() const; + QUICTransErrorCode error_code() const; uint16_t reason_phrase_length() const; const char *reason_phrase() const; private: - QUICErrorCode _error_code; + QUICTransErrorCode _error_code; + uint16_t _reason_phrase_length = 0; + const char *_reason_phrase = nullptr; +}; + +// +// APPLICATION_CLOSE +// + +class QUICApplicationCloseFrame : public QUICFrame +{ +public: + QUICApplicationCloseFrame() : QUICFrame() {} + QUICApplicationCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase); + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + QUICAppErrorCode error_code() const; + uint16_t reason_phrase_length() const; + const char *reason_phrase() const; + +private: + QUICAppErrorCode _error_code = 0; uint16_t _reason_phrase_length = 0; const char *_reason_phrase = nullptr; }; @@ -416,16 +439,16 @@ class QUICStopSendingFrame : public QUICFrame public: QUICStopSendingFrame() : QUICFrame() {} QUICStopSendingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStopSendingFrame(QUICStreamId stream_id, QUICErrorCode error_code); + QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; QUICStreamId stream_id() const; - QUICErrorCode error_code() const; + QUICAppErrorCode error_code() const; private: QUICStreamId _stream_id = 0; - QUICErrorCode _error_code; + QUICAppErrorCode _error_code; }; using QUICFrameDeleterFunc = void (*)(QUICFrame *p); @@ -457,6 +480,7 @@ extern ClassAllocator quicAckFrameAllocator; extern ClassAllocator quicPaddingFrameAllocator; extern ClassAllocator quicRstStreamFrameAllocator; extern ClassAllocator quicConnectionCloseFrameAllocator; +extern ClassAllocator quicApplicationCloseFrameAllocator; extern ClassAllocator quicMaxDataFrameAllocator; extern ClassAllocator quicMaxStreamDataFrameAllocator; extern ClassAllocator quicMaxStreamIdFrameAllocator; @@ -508,6 +532,12 @@ class QUICFrameDeleter quicConnectionCloseFrameAllocator.free(static_cast(frame)); } + static void + delete_application_close_frame(QUICFrame *frame) + { + quicApplicationCloseFrameAllocator.free(static_cast(frame)); + } + static void delete_max_data_frame(QUICFrame *frame) { @@ -603,10 +633,18 @@ class QUICFrameFactory * Creates a CONNECTION_CLOSE frame. */ static std::unique_ptr create_connection_close_frame( - QUICErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr); + QUICTransErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr); static std::unique_ptr create_connection_close_frame( QUICConnectionErrorUPtr error); + /* + * Creates a APPLICATION_CLOSE frame. + */ + static std::unique_ptr create_application_close_frame( + QUICAppErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr); + static std::unique_ptr create_application_close_frame( + QUICConnectionErrorUPtr error); + /* * Creates a MAX_DATA frame. */ @@ -632,7 +670,7 @@ class QUICFrameFactory * Creates a RST_STREAM frame. */ static std::unique_ptr create_rst_stream_frame(QUICStreamId stream_id, - QUICErrorCode error_code, + QUICAppErrorCode error_code, QUICOffset final_offset); static std::unique_ptr create_rst_stream_frame(QUICStreamErrorUPtr error); @@ -640,7 +678,7 @@ class QUICFrameFactory * Creates a STOP_SENDING frame. */ static std::unique_ptr create_stop_sending_frame(QUICStreamId stream_id, - QUICErrorCode error_code); + QUICAppErrorCode error_code); /* * Creates a retransmission frame, which is very special. diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index d78b90908f5..b23609f1910 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -105,7 +105,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet // Negotiate version if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) { if (initial_packet->type() != QUICPacketType::CLIENT_INITIAL) { - return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION)); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); } if (initial_packet->version()) { if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { @@ -117,7 +117,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet DebugQHS("Version negotiation failed: %x", initial_packet->version()); } } else { - return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION)); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); } } return QUICErrorUPtr(new QUICNoError()); @@ -163,8 +163,7 @@ QUICHandshake::set_transport_parameters(std::shared_ptr if (tp_in_ch) { // Version revalidation if (this->_version_negotiator->revalidate(tp_in_ch) != QUICVersionNegotiationStatus::REVALIDATED) { - this->_client_qc->close( - QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::VERSION_NEGOTIATION_ERROR))); + this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR))); DebugQHS("Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); return; @@ -212,8 +211,7 @@ QUICHandshake::state_read_client_hello(int event, Event *data) if (dynamic_cast(error.get()) != nullptr) { this->_client_qc->close(QUICConnectionErrorUPtr(static_cast(error.release()))); } else { - this->_client_qc->close( - QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION))); + this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION))); } DebugQHS("Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); @@ -241,8 +239,7 @@ QUICHandshake::state_read_client_finished(int event, Event *data) if (dynamic_cast(error.get()) != nullptr) { this->_client_qc->close(QUICConnectionErrorUPtr(static_cast(error.release()))); } else { - this->_client_qc->close( - QUICConnectionErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::PROTOCOL_VIOLATION))); + this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION))); } DebugQHS("Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); @@ -345,7 +342,7 @@ QUICHandshake::_process_client_hello() return QUICErrorUPtr(new QUICNoError()); } else { - return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::TLS_HANDSHAKE_FAILED)); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); } } @@ -394,7 +391,7 @@ QUICHandshake::_process_client_finished() return QUICErrorUPtr(new QUICNoError()); } else { - return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::CRYPTOGRAPHIC, QUICErrorCode::TLS_HANDSHAKE_FAILED)); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); } } diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index e7690541afc..797b7b92821 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -116,17 +116,17 @@ QUICIncomingFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, // dup fin frame return QUICErrorUPtr(new QUICNoError()); } - return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FINAL_OFFSET_ERROR)); + return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::FINAL_OFFSET_ERROR)); } this->_fin_offset = offset; if (this->_max_offset >= this->_fin_offset) { - return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FINAL_OFFSET_ERROR)); + return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::FINAL_OFFSET_ERROR)); } } else if (this->_fin_offset != UINT64_MAX && this->_fin_offset <= offset) { - return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::FINAL_OFFSET_ERROR)); + return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::FINAL_OFFSET_ERROR)); } this->_max_offset = std::max(offset, this->_max_offset); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 535b9f4c427..1017a9f2dc2 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -116,8 +116,14 @@ QUICStream::main_event_handler(int event, void *data) } if (error->cls != QUICErrorClass::NONE) { - DebugQUICStream("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), static_cast(error->cls), - QUICDebugNames::error_code(error->code), static_cast(error->code)); + if (error->cls == QUICErrorClass::TRANSPORT) { + DebugQUICStream("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), QUICDebugNames::error_code(error->trans_error_code), + static_cast(error->trans_error_code)); + } else { + DebugQUICStream("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), static_cast(error->app_error_code)); + } if (dynamic_cast(error.get()) != nullptr) { // Stream Error QUICStreamErrorUPtr serror = QUICStreamErrorUPtr(static_cast(error.get())); @@ -295,7 +301,7 @@ QUICStream::recv(const std::shared_ptr frame) // Check stream state - Do this first before accept the frame if (!this->_state.is_allowed_to_receive(*frame)) { - return QUICErrorUPtr(new QUICStreamError(this, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_STATE_ERROR)); + return QUICErrorUPtr(new QUICStreamError(this, QUICTransErrorCode::STREAM_STATE_ERROR)); } // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 6bda170983e..64190e5fa66 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -123,7 +123,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptrrecv(frame); } else { - return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR)); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); } } @@ -134,7 +134,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptrrecv(frame); } else { - return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR)); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); } } @@ -143,7 +143,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr &f { QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); if (!stream) { - return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR)); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); } QUICApplication *application = this->_app_map->get(frame->stream_id()); @@ -170,7 +170,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr // TODO Reset the stream return QUICErrorUPtr(new QUICNoError()); } else { - return QUICErrorUPtr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::STREAM_ID_ERROR)); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); } } diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 40c8a02b71a..7427d6a93fe 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -77,10 +77,16 @@ QUICTypeUtil::read_QUICOffset(const uint8_t *buf, uint8_t len) return static_cast(read_nbytes_as_uint(buf, len)); } -QUICErrorCode -QUICTypeUtil::read_QUICErrorCode(const uint8_t *buf) +QUICTransErrorCode +QUICTypeUtil::read_QUICTransErrorCode(const uint8_t *buf) { - return static_cast(read_nbytes_as_uint(buf, 4)); + return static_cast(read_nbytes_as_uint(buf, 2)); +} + +QUICAppErrorCode +QUICTypeUtil::read_QUICAppErrorCode(const uint8_t *buf) +{ + return static_cast(read_nbytes_as_uint(buf, 2)); } uint64_t @@ -122,9 +128,15 @@ QUICTypeUtil::write_QUICOffset(QUICOffset offset, uint8_t n, uint8_t *buf, size_ } void -QUICTypeUtil::write_QUICErrorCode(QUICErrorCode error_code, uint8_t *buf, size_t *len) +QUICTypeUtil::write_QUICTransErrorCode(QUICTransErrorCode error_code, uint8_t *buf, size_t *len) +{ + write_uint_as_nbytes(static_cast(error_code), 2, buf, len); +} + +void +QUICTypeUtil::write_QUICAppErrorCode(QUICAppErrorCode error_code, uint8_t *buf, size_t *len) { - write_uint_as_nbytes(static_cast(error_code), 4, buf, len); + write_uint_as_nbytes(static_cast(error_code), 2, buf, len); } void @@ -148,3 +160,9 @@ fnv1a(const uint8_t *data, size_t len, uint8_t *hash) } return QUICTypeUtil::write_uint_as_nbytes(h, 8, hash, &n); } + +uint16_t +QUICError::code() +{ + return static_cast(this->trans_error_code); +} diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 5ea699387d0..2e78939b144 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -88,7 +88,8 @@ enum class QUICFrameType : int { PADDING = 0x00, RST_STREAM, CONNECTION_CLOSE, - MAX_DATA = 0x04, + APPLICATION_CLOSE, + MAX_DATA, MAX_STREAM_DATA, MAX_STREAM_ID, PING, @@ -117,47 +118,49 @@ enum class QUICKeyPhase : int { enum class QUICErrorClass { NONE, - AQPPLICATION_SPECIFIC, - HOST_LOCAL, - QUIC_TRANSPORT, - CRYPTOGRAPHIC, + TRANSPORT, + APPLICATION, }; -enum class QUICErrorCode : uint32_t { - APPLICATION_SPECIFIC_ERROR = 0, - HOST_LOCAL_ERROR = 0x40000000, - NO_ERROR = 0x80000000, +enum class QUICTransErrorCode : uint16_t { + NO_ERROR = 0x00, INTERNAL_ERROR, - CANCELLED, - FLOW_CONTROL_ERROR, + FLOW_CONTROL_ERROR = 0x03, STREAM_ID_ERROR, STREAM_STATE_ERROR, FINAL_OFFSET_ERROR, FRAME_FORMAT_ERROR, TRANSPORT_PARAMETER_ERROR, VERSION_NEGOTIATION_ERROR, - PROTOCOL_VIOLATION = 0x8000000A, - QUIC_RECEIVED_RST = 0x80000035, - FRAME_ERROR = 0x80000100, - CRYPTOGRAPHIC_ERROR = 0xC0000000, - TLS_HANDSHAKE_FAILED = 0xC000001C, + PROTOCOL_VIOLATION = 0x0A, + FRAME_ERROR = 0x0100, // 0x100 - 0x1FF + TLS_HANDSHAKE_FAILED = 0x0201, TLS_FATAL_ALERT_GENERATED, TLS_FATAL_ALERT_RECEIVED, - // TODO Add error codes }; +// Application Protocol Error Codes defined in application +using QUICAppErrorCode = uint16_t; + class QUICError { public: virtual ~QUICError() {} - QUICErrorClass cls; - QUICErrorCode code; - const char *msg; + uint16_t code(); + + QUICErrorClass cls = QUICErrorClass::NONE; + union { + QUICTransErrorCode trans_error_code = QUICTransErrorCode::NO_ERROR; + QUICAppErrorCode app_error_code; + }; + const char *msg = nullptr; protected: - QUICError(const QUICErrorClass error_class = QUICErrorClass::NONE, const QUICErrorCode error_code = QUICErrorCode::NO_ERROR, - const char *error_msg = nullptr) - : cls(error_class), code(error_code), msg(error_msg){}; + QUICError(){}; + QUICError(const QUICTransErrorCode error_code, const char *error_msg = nullptr) + : cls(QUICErrorClass::TRANSPORT), trans_error_code(error_code), msg(error_msg){}; + QUICError(const QUICAppErrorCode error_code, const char *error_msg = nullptr) + : cls(QUICErrorClass::APPLICATION), app_error_code(error_code), msg(error_msg){}; }; class QUICNoError : public QUICError @@ -170,8 +173,8 @@ class QUICConnectionError : public QUICError { public: QUICConnectionError() : QUICError() {} - QUICConnectionError(const QUICErrorClass error_class, const QUICErrorCode error_code, const char *error_msg = nullptr) - : QUICError(error_class, error_code, error_msg){}; + QUICConnectionError(const QUICTransErrorCode error_code, const char *error_msg = nullptr) : QUICError(error_code, error_msg){}; + QUICConnectionError(const QUICAppErrorCode error_code, const char *error_msg = nullptr) : QUICError(error_code, error_msg){}; }; class QUICStream; @@ -179,8 +182,12 @@ class QUICStream; class QUICStreamError : public QUICError { public: - QUICStreamError(QUICStream *s, const QUICErrorClass error_class, const QUICErrorCode error_code, const char *error_msg = nullptr) - : QUICError(error_class, error_code, error_msg), stream(s){}; + QUICStreamError() : QUICError() {} + QUICStreamError(QUICStream *s, const QUICTransErrorCode error_code, const char *error_msg = nullptr) + : QUICError(error_code, error_msg), stream(s){}; + QUICStreamError(QUICStream *s, const QUICAppErrorCode error_code, const char *error_msg = nullptr) + : QUICError(error_code, error_msg), stream(s){}; + QUICStream *stream; }; @@ -303,14 +310,16 @@ class QUICTypeUtil static QUICVersion read_QUICVersion(const uint8_t *buf); static QUICStreamId read_QUICStreamId(const uint8_t *buf, uint8_t n); static QUICOffset read_QUICOffset(const uint8_t *buf, uint8_t n); - static QUICErrorCode read_QUICErrorCode(const uint8_t *buf); + static QUICTransErrorCode read_QUICTransErrorCode(const uint8_t *buf); + static QUICAppErrorCode read_QUICAppErrorCode(const uint8_t *buf); static void write_QUICConnectionId(QUICConnectionId connection_id, uint8_t n, uint8_t *buf, size_t *len); static void write_QUICPacketNumber(QUICPacketNumber packet_number, uint8_t n, uint8_t *buf, size_t *len); static void write_QUICVersion(QUICVersion version, uint8_t *buf, size_t *len); static void write_QUICStreamId(QUICStreamId stream_id, uint8_t n, uint8_t *buf, size_t *len); static void write_QUICOffset(QUICOffset offset, uint8_t n, uint8_t *buf, size_t *len); - static void write_QUICErrorCode(QUICErrorCode error_code, uint8_t *buf, size_t *len); + static void write_QUICTransErrorCode(QUICTransErrorCode error_code, uint8_t *buf, size_t *len); + static void write_QUICAppErrorCode(QUICAppErrorCode error_code, 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/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index e98278be5cb..17a94727f2a 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -68,7 +68,8 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") error = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->code == QUICErrorCode::FLOW_CONTROL_ERROR); + CHECK(error->cls == QUICErrorClass::TRANSPORT); + CHECK(error->trans_error_code == QUICTransErrorCode::FLOW_CONTROL_ERROR); // MAX_STREAM_DATA CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_DATA)] == 0); @@ -180,7 +181,8 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]") error = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->code == QUICErrorCode::FLOW_CONTROL_ERROR); + CHECK(error->cls == QUICErrorClass::TRANSPORT); + CHECK(error->trans_error_code == QUICTransErrorCode::FLOW_CONTROL_ERROR); // MAX_STREAM_DATA CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_STREAM_DATA)] == 0); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 36f1eee8e50..434ef93d485 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -32,6 +32,7 @@ TEST_CASE("QUICFrame Type", "[quic]") CHECK(QUICFrame::type(reinterpret_cast("\x00")) == QUICFrameType::PADDING); CHECK(QUICFrame::type(reinterpret_cast("\x01")) == QUICFrameType::RST_STREAM); CHECK(QUICFrame::type(reinterpret_cast("\x02")) == QUICFrameType::CONNECTION_CLOSE); + CHECK(QUICFrame::type(reinterpret_cast("\x03")) == QUICFrameType::APPLICATION_CLOSE); CHECK(QUICFrame::type(reinterpret_cast("\x04")) == QUICFrameType::MAX_DATA); CHECK(QUICFrame::type(reinterpret_cast("\x05")) == QUICFrameType::MAX_STREAM_DATA); CHECK(QUICFrame::type(reinterpret_cast("\x06")) == QUICFrameType::MAX_STREAM_ID); @@ -42,7 +43,6 @@ TEST_CASE("QUICFrame Type", "[quic]") CHECK(QUICFrame::type(reinterpret_cast("\x0b")) == QUICFrameType::NEW_CONNECTION_ID); CHECK(QUICFrame::type(reinterpret_cast("\x0c")) == QUICFrameType::STOP_SENDING); // Undefined ragne - CHECK(QUICFrame::type(reinterpret_cast("\x03")) == QUICFrameType::UNKNOWN); CHECK(QUICFrame::type(reinterpret_cast("\x0d")) == QUICFrameType::UNKNOWN); CHECK(QUICFrame::type(reinterpret_cast("\x9f")) == QUICFrameType::UNKNOWN); // Range of ACK @@ -309,15 +309,15 @@ TEST_CASE("Load RST_STREAM Frame", "[quic]") uint8_t buf1[] = { 0x01, // Type 0x12, 0x34, 0x56, 0x78, // Stream ID - 0x80, 0x00, 0x00, 0x00, // Error Code + 0x00, 0x01, // Error Code 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::RST_STREAM); - CHECK(frame1->size() == 17); + CHECK(frame1->size() == 15); std::shared_ptr rst_stream_frame1 = std::dynamic_pointer_cast(frame1); CHECK(rst_stream_frame1 != nullptr); - CHECK(rst_stream_frame1->error_code() == QUICErrorCode::NO_ERROR); + CHECK(rst_stream_frame1->error_code() == 0x0001); CHECK(rst_stream_frame1->stream_id() == 0x12345678); CHECK(rst_stream_frame1->final_offset() == 0x1122334455667788); } @@ -330,12 +330,12 @@ TEST_CASE("Store RST_STREAM Frame", "[quic]") uint8_t expected[] = { 0x01, // Type 0x12, 0x34, 0x56, 0x78, // Stream ID - 0x80, 0x00, 0x00, 0x00, // Error Code + 0x00, 0x01, // Error Code 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset }; - QUICRstStreamFrame rst_stream_frame(0x12345678, QUICErrorCode::NO_ERROR, 0x1122334455667788); + QUICRstStreamFrame rst_stream_frame(0x12345678, 0x0001, 0x1122334455667788); rst_stream_frame.store(buf, &len); - CHECK(len == 17); + CHECK(len == 15); CHECK(memcmp(buf, expected, len) == 0); } @@ -395,33 +395,33 @@ TEST_CASE("Load ConnectionClose Frame", "[quic]") { uint8_t buf1[] = { 0x02, // Type - 0x80, 0x00, 0x00, 0x00, // Error Code + 0x00, 0x0A, // Error Code 0x00, 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::CONNECTION_CLOSE); - CHECK(frame1->size() == 12); + CHECK(frame1->size() == 10); std::shared_ptr connectionCloseFrame1 = std::dynamic_pointer_cast(frame1); CHECK(connectionCloseFrame1 != nullptr); - CHECK(connectionCloseFrame1->error_code() == QUICErrorCode::NO_ERROR); + CHECK(connectionCloseFrame1->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION); CHECK(connectionCloseFrame1->reason_phrase_length() == 5); - CHECK(memcmp(connectionCloseFrame1->reason_phrase(), buf1 + 7, 5) == 0); + CHECK(memcmp(connectionCloseFrame1->reason_phrase(), buf1 + 5, 5) == 0); // No reason phrase uint8_t buf2[] = { - 0x02, // Type - 0x80, 0x00, 0x00, 0x00, // Error Code - 0x00, 0x00, // Reason Phrase Length + 0x02, // Type + 0x00, 0x0A, // Error Code + 0x00, 0x00, // Reason Phrase Length }; std::shared_ptr frame2 = QUICFrameFactory::create(buf2, sizeof(buf1)); CHECK(frame2->type() == QUICFrameType::CONNECTION_CLOSE); - CHECK(frame2->size() == 7); + CHECK(frame2->size() == 5); std::shared_ptr connectionCloseFrame2 = std::dynamic_pointer_cast(frame2); CHECK(connectionCloseFrame2 != nullptr); - CHECK(connectionCloseFrame2->error_code() == QUICErrorCode::NO_ERROR); + CHECK(connectionCloseFrame2->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION); CHECK(connectionCloseFrame2->reason_phrase_length() == 0); } @@ -432,23 +432,84 @@ TEST_CASE("Store ConnectionClose Frame", "[quic]") uint8_t expected1[] = { 0x02, // Type - 0x80, 0x00, 0x00, 0x00, // Error Code + 0x00, 0x0A, // Error Code 0x00, 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; - QUICConnectionCloseFrame connectionCloseFrame1(QUICErrorCode::NO_ERROR, 5, "ABCDE"); + QUICConnectionCloseFrame connectionCloseFrame1(QUICTransErrorCode::PROTOCOL_VIOLATION, 5, "ABCDE"); connectionCloseFrame1.store(buf, &len); - CHECK(len == 12); + CHECK(len == 10); CHECK(memcmp(buf, expected1, len) == 0); uint8_t expected2[] = { - 0x02, // Type - 0x80, 0x00, 0x00, 0x00, // Error Code - 0x00, 0x00, // Reason Phrase Length + 0x02, // Type + 0x00, 0x0A, // Error Code + 0x00, 0x00, // Reason Phrase Length }; - QUICConnectionCloseFrame connectionCloseFrame2(QUICErrorCode::NO_ERROR, 0, nullptr); + QUICConnectionCloseFrame connectionCloseFrame2(QUICTransErrorCode::PROTOCOL_VIOLATION, 0, nullptr); connectionCloseFrame2.store(buf, &len); - CHECK(len == 7); + CHECK(len == 5); + CHECK(memcmp(buf, expected2, len) == 0); +} + +TEST_CASE("Load ApplicationClose Frame", "[quic]") +{ + uint8_t buf1[] = { + 0x03, // Type + 0x00, 0x01, // Error Code + 0x00, 0x05, // Reason Phrase Length + 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::APPLICATION_CLOSE); + CHECK(frame1->size() == 10); + std::shared_ptr applicationCloseFrame1 = + std::dynamic_pointer_cast(frame1); + CHECK(applicationCloseFrame1 != nullptr); + CHECK(applicationCloseFrame1->error_code() == static_cast(0x01)); + CHECK(applicationCloseFrame1->reason_phrase_length() == 5); + CHECK(memcmp(applicationCloseFrame1->reason_phrase(), buf1 + 5, 5) == 0); + + // No reason phrase + uint8_t buf2[] = { + 0x03, // Type + 0x00, 0x01, // Error Code + 0x00, 0x00, // Reason Phrase Length + }; + std::shared_ptr frame2 = QUICFrameFactory::create(buf2, sizeof(buf1)); + CHECK(frame2->type() == QUICFrameType::APPLICATION_CLOSE); + CHECK(frame2->size() == 5); + std::shared_ptr applicationCloseFrame2 = + std::dynamic_pointer_cast(frame2); + CHECK(applicationCloseFrame2 != nullptr); + CHECK(applicationCloseFrame2->error_code() == static_cast(0x01)); + CHECK(applicationCloseFrame2->reason_phrase_length() == 0); +} + +TEST_CASE("Store ApplicationClose Frame", "[quic]") +{ + uint8_t buf[65535]; + size_t len; + + uint8_t expected1[] = { + 0x03, // Type + 0x00, 0x01, // Error Code + 0x00, 0x05, // Reason Phrase Length + 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); + }; + QUICApplicationCloseFrame applicationCloseFrame1(static_cast(0x01), 5, "ABCDE"); + applicationCloseFrame1.store(buf, &len); + CHECK(len == 10); + CHECK(memcmp(buf, expected1, len) == 0); + + uint8_t expected2[] = { + 0x03, // Type + 0x00, 0x01, // Error Code + 0x00, 0x00, // Reason Phrase Length + }; + QUICApplicationCloseFrame applicationCloseFrame2(static_cast(0x01), 0, nullptr); + applicationCloseFrame2.store(buf, &len); + CHECK(len == 5); CHECK(memcmp(buf, expected2, len) == 0); } @@ -664,16 +725,16 @@ TEST_CASE("Load STOP_SENDING Frame", "[quic]") uint8_t buf[] = { 0x0c, // Type 0x12, 0x34, 0x56, 0x78, // Stream ID - 0x80, 0x00, 0x00, 0x00, // Error Code + 0x00, 0x01, // Error Code }; std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::STOP_SENDING); - CHECK(frame->size() == 9); + CHECK(frame->size() == 7); std::shared_ptr stop_sending_frame = std::dynamic_pointer_cast(frame); CHECK(stop_sending_frame != nullptr); CHECK(stop_sending_frame->stream_id() == 0x12345678); - CHECK(stop_sending_frame->error_code() == QUICErrorCode::NO_ERROR); + CHECK(stop_sending_frame->error_code() == 0x0001); } TEST_CASE("Store STOP_SENDING Frame", "[quic]") @@ -684,11 +745,11 @@ TEST_CASE("Store STOP_SENDING Frame", "[quic]") uint8_t expected[] = { 0x0c, // Type 0x12, 0x34, 0x56, 0x78, // Stream ID - 0x80, 0x00, 0x00, 0x00, // Error Code + 0x00, 0x01, // Error Code }; - QUICStopSendingFrame stop_sending_frame(0x12345678, QUICErrorCode::NO_ERROR); + QUICStopSendingFrame stop_sending_frame(0x12345678, static_cast(0x01)); stop_sending_frame.store(buf, &len); - CHECK(len == 9); + CHECK(len == 7); CHECK(memcmp(buf, expected, len) == 0); } @@ -744,18 +805,17 @@ TEST_CASE("QUICFrameFactory Fast Create Unknown Frame", "[quic]") TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", "[quic]") { std::unique_ptr error = - std::unique_ptr(new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR)); + std::unique_ptr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); std::unique_ptr connection_close_frame1 = QUICFrameFactory::create_connection_close_frame(std::move(error)); - CHECK(connection_close_frame1->error_code() == QUICErrorCode::INTERNAL_ERROR); + CHECK(connection_close_frame1->error_code() == QUICTransErrorCode::INTERNAL_ERROR); CHECK(connection_close_frame1->reason_phrase_length() == 0); CHECK(connection_close_frame1->reason_phrase() == nullptr); - error = std::unique_ptr( - new QUICConnectionError(QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR, "test")); + error = std::unique_ptr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR, "test")); std::unique_ptr connection_close_frame2 = QUICFrameFactory::create_connection_close_frame(std::move(error)); - CHECK(connection_close_frame2->error_code() == QUICErrorCode::INTERNAL_ERROR); + CHECK(connection_close_frame2->error_code() == QUICTransErrorCode::INTERNAL_ERROR); CHECK(connection_close_frame2->reason_phrase_length() == 4); CHECK(memcmp(connection_close_frame2->reason_phrase(), "test", 4) == 0); } @@ -765,10 +825,10 @@ TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") QUICStream stream; stream.init(new MockQUICFrameTransmitter(), 0, 0x1234, 0, 0); std::unique_ptr error = - std::unique_ptr(new QUICStreamError(&stream, QUICErrorClass::QUIC_TRANSPORT, QUICErrorCode::INTERNAL_ERROR)); + std::unique_ptr(new QUICStreamError(&stream, static_cast(0x01))); std::unique_ptr rst_stream_frame1 = QUICFrameFactory::create_rst_stream_frame(std::move(error)); - CHECK(rst_stream_frame1->error_code() == QUICErrorCode::INTERNAL_ERROR); + CHECK(rst_stream_frame1->error_code() == 0x01); CHECK(rst_stream_frame1->stream_id() == 0x1234); CHECK(rst_stream_frame1->final_offset() == 0); } diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 844607a63dc..a42369bc6fc 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -45,7 +45,7 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") buffer.insert(stream1_frame_1_r); buffer.insert(stream1_frame_2_r); err = buffer.insert(stream1_frame_3_r); - CHECK(err->code == QUICErrorCode::FINAL_OFFSET_ERROR); + CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); QUICIncomingFrameBuffer buffer2(stream); @@ -53,13 +53,13 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") buffer2.insert(stream1_frame_0_r); buffer2.insert(stream1_frame_1_r); err = buffer2.insert(stream1_frame_2_r); - CHECK(err->code == QUICErrorCode::FINAL_OFFSET_ERROR); + CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); QUICIncomingFrameBuffer buffer3(stream); buffer3.insert(stream1_frame_4_r); err = buffer3.insert(stream1_frame_3_r); - CHECK(err->code == QUICErrorCode::FINAL_OFFSET_ERROR); + CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); delete stream; } diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 5e63ade1074..bd2f6489e72 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -179,7 +179,8 @@ TEST_CASE("QUICStream", "[quic]") CHECK(error->cls == QUICErrorClass::NONE); // this should exceed the limit error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 8192)); - CHECK(error->code == QUICErrorCode::FLOW_CONTROL_ERROR); + CHECK(error->cls == QUICErrorClass::TRANSPORT); + CHECK(error->trans_error_code == QUICTransErrorCode::FLOW_CONTROL_ERROR); } SECTION("QUICStream_flow_control_remote", "[quic]") diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index f9490c961fb..9af5433e0d5 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -53,7 +53,8 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") CHECK(sm.stream_count() == 2); // RST_STREAM frames create new streams - std::shared_ptr rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(2, QUICErrorCode::INTERNAL_ERROR, 0); + std::shared_ptr rst_stream_frame = + QUICFrameFactory::create_rst_stream_frame(2, static_cast(0x01), 0); sm.handle_frame(rst_stream_frame); CHECK(sm.stream_count() == 3); diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index ec304342142..2bc3e687541 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -31,7 +31,7 @@ TEST_CASE("QUICStreamState_Idle", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::NO_ERROR, 0); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); auto max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(0, 0); auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0); @@ -70,7 +70,7 @@ TEST_CASE("QUICStreamState_Open", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::NO_ERROR, 0); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); // Case1. Send FIN in a STREAM QUICStreamState ss1; @@ -105,7 +105,7 @@ TEST_CASE("QUICStreamState_Half_Closed_Remote", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::NO_ERROR, 0); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); // Case1. Send FIN in a STREAM QUICStreamState ss1; @@ -126,7 +126,7 @@ TEST_CASE("QUICStreamState_Half_Closed_Local", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, QUICErrorCode::NO_ERROR, 0); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); // Case1. Recv FIN in a STREAM QUICStreamState ss1; From 4232178f07465b8fc7d59d7c42ed58757d64713d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 15 Nov 2017 10:29:34 +0900 Subject: [PATCH 0175/1313] Use AEAD instead of FNV-1a --- .gitignore | 1 + iocore/net/P_QUICNetVConnection.h | 10 +- iocore/net/QUICNetVConnection.cc | 172 ++++++------ iocore/net/quic/Makefile.am | 5 + iocore/net/quic/QUICCrypto.cc | 244 +++++------------- iocore/net/quic/QUICCrypto.h | 50 ++-- iocore/net/quic/QUICCrypto_openssl.cc | 74 +++--- iocore/net/quic/QUICHandshake.cc | 14 +- iocore/net/quic/QUICKeyGenerator.cc | 105 ++++++++ iocore/net/quic/QUICKeyGenerator.h | 75 ++++++ iocore/net/quic/QUICKeyGenerator_openssl.cc | 41 +++ iocore/net/quic/QUICPacket.cc | 88 +++++-- iocore/net/quic/QUICPacket.h | 15 +- iocore/net/quic/QUICTypes.cc | 14 - iocore/net/quic/QUICTypes.h | 8 +- iocore/net/quic/test/Makefile.am | 26 ++ iocore/net/quic/test/test_QUICKeyGenerator.cc | 107 ++++++++ lib/ts/HKDF.cc | 11 +- lib/ts/HKDF.h | 2 +- lib/ts/HKDF_openssl.cc | 19 +- 20 files changed, 674 insertions(+), 407 deletions(-) create mode 100644 iocore/net/quic/QUICKeyGenerator.cc create mode 100644 iocore/net/quic/QUICKeyGenerator.h create mode 100644 iocore/net/quic/QUICKeyGenerator_openssl.cc create mode 100644 iocore/net/quic/test/test_QUICKeyGenerator.cc diff --git a/.gitignore b/.gitignore index 31be23b1dfa..e50a04b9554 100644 --- a/.gitignore +++ b/.gitignore @@ -97,6 +97,7 @@ iocore/net/quic/test/test_QUICStream iocore/net/quic/test/test_QUICStreamState iocore/net/quic/test/test_QUICStreamManager iocore/net/quic/test/test_QUICTransportParameters +iocore/net/quic/test/test_QUICKeyGenerator iocore/net/quic/test/test_QUICCrypto iocore/net/quic/test/test_QUICLossDetector iocore/net/quic/test/test_QUICTypeUtil diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 431ff7685cb..b59bc035649 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -103,9 +103,10 @@ class SSLNextProtocolSet; * v * state_handshake() * | READ: - * | _state_handshake_process_initial_client_packet() - * | _state_handshake_process_client_cleartext_packet() - * | _state_handshake_process_zero_rtt_protected_packet() + * | _state_handshake_process__packet() + * | _state_handshake_process_initial_client_packet() + * | _state_handshake_process_client_cleartext_packet() + * | _state_handshake_process_zero_rtt_protected_packet() * | WRITE: * | _state_common_send_packet() * v @@ -236,6 +237,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICErrorUPtr _recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_numm); + QUICErrorUPtr _state_handshake_process_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_initial_client_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); @@ -249,7 +251,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); void _handle_error(QUICErrorUPtr error); - QUICPacketUPtr _dequeue_recv_packet(); + QUICPacketUPtr _dequeue_recv_packet(QUICPacketCreationResult &result); QUICStatelessToken _token; }; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 29833c6cade..48edd888b25 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -381,36 +381,15 @@ QUICNetVConnection::state_handshake(int event, Event *data) switch (event) { case QUIC_EVENT_PACKET_READ_READY: { - QUICPacketUPtr p = this->_dequeue_recv_packet(); - if (!p) { - break; - } - net_activity(this, this_ethread()); - - switch (p->type()) { - case QUICPacketType::CLIENT_INITIAL: { - error = this->_state_handshake_process_initial_client_packet(std::move(p)); - break; - } - case QUICPacketType::CLIENT_CLEARTEXT: { - error = this->_state_handshake_process_client_cleartext_packet(std::move(p)); - break; - } - case QUICPacketType::ZERO_RTT_PROTECTED: { - error = this->_state_handshake_process_zero_rtt_protected_packet(std::move(p)); - break; - } - case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: - case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: - // Postpone processing the packet - this->_quic_packet_recv_queue.push(std::move(p)); - this_ethread()->schedule_imm_local(this, event); - break; - default: - error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); - break; + QUICPacketCreationResult result; + QUICPacketUPtr packet = this->_dequeue_recv_packet(result); + if (result == QUICPacketCreationResult::NOT_READY) { + error = QUICErrorUPtr(new QUICNoError()); + } else if (result == QUICPacketCreationResult::FAILED) { + error = QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); + } else { + error = this->_state_handshake_process_packet(std::move(packet)); } - break; } case QUIC_EVENT_PACKET_WRITE_READY: { @@ -639,6 +618,27 @@ QUICNetVConnection::largest_acked_packet_number() return this->_loss_detector->largest_acked_packet_number(); } +QUICErrorUPtr +QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) +{ + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + switch (packet->type()) { + case QUICPacketType::CLIENT_INITIAL: + error = this->_state_handshake_process_initial_client_packet(std::move(packet)); + break; + case QUICPacketType::CLIENT_CLEARTEXT: + error = this->_state_handshake_process_client_cleartext_packet(std::move(packet)); + break; + case QUICPacketType::ZERO_RTT_PROTECTED: + error = this->_state_handshake_process_zero_rtt_protected_packet(std::move(packet)); + break; + default: + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); + break; + } + return error; +} + QUICErrorUPtr QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPtr packet) { @@ -651,23 +651,17 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPt // Start handshake QUICErrorUPtr error = this->_handshake_handler->start(packet.get(), &this->_packet_factory); if (this->_handshake_handler->is_version_negotiated()) { - // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing) - if (packet->has_valid_fnv1a_hash()) { - bool should_send_ack; - error = this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size(), should_send_ack); - if (error->cls != QUICErrorClass::NONE) { - return error; - } - error = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, - static_cast(this->_quic_connection_id), this->_local_flow_controller->current_offset(), - this->_local_flow_controller->current_limit()); - if (error->cls != QUICErrorClass::NONE) { - return error; - } - } else { - DebugQUICCon("Invalid FNV-1a hash value"); - // Discard the packet + bool should_send_ack; + error = this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size(), should_send_ack); + if (error->cls != QUICErrorClass::NONE) { + return error; + } + error = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, + static_cast(this->_quic_connection_id), this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); + if (error->cls != QUICErrorClass::NONE) { + return error; } } return error; @@ -676,23 +670,12 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPt QUICErrorUPtr QUICNetVConnection::_state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet) { - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - - // The payload of this packet contains STREAM frames and could contain PADDING and ACK frames - if (packet->has_valid_fnv1a_hash()) { - error = this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); - } else { - DebugQUICCon("Invalid FNV-1a hash value"); - // Discard the packet - } - return error; + return this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); } QUICErrorUPtr QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet) { - // TODO: Decrypt the packet - // decrypt(payload, p); // TODO: Not sure what we have to do return QUICErrorUPtr(new QUICNoError()); } @@ -700,29 +683,19 @@ QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacke QUICErrorUPtr QUICNetVConnection::_state_connection_established_process_packet(QUICPacketUPtr packet) { - // TODO: fix size - 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; - - if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, packet->payload(), packet->payload_size(), - packet->packet_number(), packet->header(), packet->header_size(), packet->key_phase())) { - DebugQUICCon("Decrypt Packet, pkt_num: %" PRIu64 ", header_len: %hu, payload_len: %zu", packet->packet_number(), - packet->header_size(), plain_txt_len); - return this->_recv_and_ack(plain_txt.get(), plain_txt_len, packet->packet_number()); - } else { - DebugQUICCon("Decrypt Error"); - return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); - } + return this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); } QUICErrorUPtr QUICNetVConnection::_state_common_receive_packet() { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - QUICPacketUPtr p = this->_dequeue_recv_packet(); - if (!p) { - return error; + QUICPacketCreationResult result; + QUICPacketUPtr p = this->_dequeue_recv_packet(result); + if (result == QUICPacketCreationResult::FAILED) { + return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); + } else if (result == QUICPacketCreationResult::NOT_READY) { + return QUICErrorUPtr(new QUICNoError()); } net_activity(this, this_ethread()); @@ -964,32 +937,39 @@ QUICNetVConnection::_handle_error(QUICErrorUPtr error) } QUICPacketUPtr -QUICNetVConnection::_dequeue_recv_packet() +QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) { QUICPacketUPtr quic_packet = QUICPacketUPtr(nullptr, &QUICPacketDeleter::delete_null_packet); UDPPacket *udp_packet = this->_packet_recv_queue.dequeue(); - if (udp_packet) { - ats_unique_buf pkt = ats_unique_malloc(udp_packet->getPktLength()); - IOBufferBlock *b = udp_packet->getIOBlockChain(); - size_t written = 0; - while (b) { - memcpy(pkt.get() + written, b->buf(), b->read_avail()); - written += b->read_avail(); - b = b->next.get(); - } - udp_packet->free(); - quic_packet = QUICPacketFactory::create(std::move(pkt), written, this->largest_received_packet_number()); + if (!udp_packet) { + result = QUICPacketCreationResult::NOT_READY; + return quic_packet; } + net_activity(this, this_ethread()); - if (this->_quic_packet_recv_queue.size() > 0) { - QUICPacketUPtr p = std::move(this->_quic_packet_recv_queue.front()); - this->_quic_packet_recv_queue.pop(); - this->_quic_packet_recv_queue.push(std::move(quic_packet)); - quic_packet.reset(p.release()); - } - if (quic_packet) { - DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), - quic_packet->packet_number(), quic_packet->size()); + // Create a QUIC packet + ats_unique_buf pkt = ats_unique_malloc(udp_packet->getPktLength()); + IOBufferBlock *b = udp_packet->getIOBlockChain(); + size_t written = 0; + while (b) { + memcpy(pkt.get() + written, b->buf(), b->read_avail()); + written += b->read_avail(); + b = b->next.get(); + } + quic_packet = this->_packet_factory.create(std::move(pkt), written, this->largest_received_packet_number(), result); + if (result == QUICPacketCreationResult::NOT_READY) { + DebugQUICCon("Not ready to decrypt the packet"); + // Retry later + this->_packet_recv_queue.enqueue(udp_packet); + this_ethread()->schedule_imm_local(this, QUIC_EVENT_PACKET_READ_READY); + } else { + udp_packet->free(); + if (result == QUICPacketCreationResult::SUCCESS) { + DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), quic_packet->packet_number(), quic_packet->size()); + } else { + DebugQUICCon("Failed to decrypt the packet"); + } } + return quic_packet; } diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 3fc25857daa..62df5dd2613 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -36,8 +36,10 @@ noinst_LIBRARIES = libquic.a if OPENSSL_IS_BORINGSSL QUICCrypto_impl = QUICCrypto_boringssl.cc +QUICKeyGenerator_impl = QUICKeyGenerator_boringssl.cc else QUICCrypto_impl = QUICCrypto_openssl.cc +QUICKeyGenerator_impl = QUICKeyGenerator_openssl.cc endif libquic_a_SOURCES = \ @@ -56,6 +58,9 @@ libquic_a_SOURCES = \ QUICHandshake.cc \ QUICCrypto.cc \ $(QUICCrypto_impl) \ + QUICKeyGenerator.cc \ + $(QUICKeyGenerator_impl) \ + QUICKeyGenerator.cc \ QUICTransportParameters.cc \ QUICAckFrameCreator.cc \ QUICConfig.cc \ diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 3c6446df63b..ec020a8ff45 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -34,44 +34,41 @@ constexpr static char tag[] = "quic_crypto"; -// constexpr static ts::StringView _exporter_label_0_rtt("EXPORTER-QUIC 0-RTT Secret", ts::StringView::literal); -constexpr static ts::string_view exporter_label_client_1_rtt("EXPORTER-QUIC client 1-RTT Secret"_sv); -constexpr static ts::string_view exporter_label_server_1_rtt("EXPORTER-QUIC server 1-RTT Secret"_sv); - -// [quic-tls draft-05] "tls13 " + Label -// constexpr static ts::StringView expand_label_client_1_rtt("tls13 QUIC client 1-RTT secret", ts::StringView::literal); -// constexpr static ts::StringView expand_label_server_1_rtt("tls13 QUIC server 1-RTT secret", ts::StringView::literal); -constexpr static ts::string_view expand_label_key("tls13 key"_sv); -constexpr static ts::string_view expand_label_iv("tls13 iv"_sv); - // // QUICPacketProtection // QUICPacketProtection::~QUICPacketProtection() { - delete this->_phase_0_key; - delete this->_phase_1_key; } void -QUICPacketProtection::set_key(KeyMaterial *km, QUICKeyPhase phase) +QUICPacketProtection::set_key(std::unique_ptrkm, QUICKeyPhase phase) { this->_key_phase = phase; - if (phase == QUICKeyPhase::PHASE_0) { - this->_phase_0_key = km; - } else { - this->_phase_1_key = km; + switch(phase) { + case QUICKeyPhase::PHASE_0: + this->_phase_0_key = std::move(km); + break; + case QUICKeyPhase::PHASE_1: + this->_phase_1_key = std::move(km); + break; + case QUICKeyPhase::CLEARTEXT: + this->_cleartext_key = std::move(km); + break; } } -const KeyMaterial * +const KeyMaterial& QUICPacketProtection::get_key(QUICKeyPhase phase) const { - if (phase == QUICKeyPhase::PHASE_0) { - return this->_phase_0_key; - } else { - return this->_phase_1_key; + switch(phase) { + case QUICKeyPhase::PHASE_0: + return *this->_phase_0_key; + case QUICKeyPhase::PHASE_1: + return *this->_phase_1_key; + case QUICKeyPhase::CLEARTEXT: + return *this->_cleartext_key; } } @@ -100,7 +97,6 @@ QUICCrypto::QUICCrypto(SSL *ssl, NetVConnectionContext_t nvc_ctx) : _ssl(ssl), _ QUICCrypto::~QUICCrypto() { - delete this->_hkdf; delete this->_client_pp; delete this->_server_pp; } @@ -160,88 +156,55 @@ QUICCrypto::is_handshake_finished() const } int -QUICCrypto::setup_session() +QUICCrypto::initialize_key_materials(QUICConnectionId cid) { + this->_aead = _get_evp_aead(); + + std::unique_ptr km; + // for decryption + km = this->_keygen_for_client.generate(cid); + this->_client_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); + // for encryption + km = this->_keygen_for_server.generate(cid); + this->_server_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); + return 1; +} + +int +QUICCrypto::update_key_materials() +{ + QUICKeyPhase next_key_phase; + switch (this->_client_pp->key_phase()) { + case QUICKeyPhase::PHASE_0: + next_key_phase = QUICKeyPhase::PHASE_1; + break; + case QUICKeyPhase::PHASE_1: + next_key_phase = QUICKeyPhase::PHASE_0; + break; + case QUICKeyPhase::CLEARTEXT: + next_key_phase = QUICKeyPhase::PHASE_0; + break; + } const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); - this->_digest = _get_handshake_digest(cipher); - this->_aead = _get_evp_aead(cipher); - this->_hkdf = new HKDF(this->_digest); + this->_aead = _get_evp_aead(); - size_t secret_len = EVP_MD_size(this->_digest); + size_t secret_len = EVP_MD_size(_get_handshake_digest(cipher)); size_t key_len = _get_aead_key_len(this->_aead); size_t iv_len = std::max(static_cast(8), _get_aead_nonce_len(this->_aead)); - int r = 0; - - r = _export_client_keymaterial(secret_len, key_len, iv_len); - if (r != 1) { - return r; - } - - r = _export_server_keymaterial(secret_len, key_len, iv_len); - if (r != 1) { - return r; - } + std::unique_ptr km; + // for decryption + km = this->_keygen_for_client.generate(); + this->_client_pp->set_key(std::move(km), next_key_phase); + // for encryption + km = this->_keygen_for_server.generate(); + this->_server_pp->set_key(std::move(km), next_key_phase); Debug(tag, "Negotiated ciper: %s, secret_len: %zu, key_len: %zu, iv_len: %zu", SSL_CIPHER_get_name(cipher), secret_len, key_len, iv_len); return 1; } -/** - * update client_pp_secret_ and keying material - */ -int -QUICCrypto::update_client_keymaterial() -{ - return 0; - // KeyMaterial *km_n = nullptr; - // KeyMaterial *km_n_1 = new KeyMaterial(km_n->secret_len, km_n->key_len, km_n->iv_len); - // uint8_t secret[256] = {0}; - // int r = 0; - - // r = _hkdf_expand_label(secret, km_n->secret_len, km_n->secret, km_n->secret_len, _expand_label_client_1_rtt, - // sizeof(_expand_label_client_1_rtt), this->_digest); - // if (r != 1) { - // return r; - // } - - // r = km_n_1->init(this->_aead, this->_digest, secret); - // if (r != 1) { - // return r; - // } - // this->_server_pp->set_key(km_n_1, new_key_phase); - - // return 1; -} - -/** - * update server_pp_secret_ and keying material - */ -int -QUICCrypto::update_server_keymaterial() -{ - return 0; - // KeyMaterial *km_n = nullptr; - // KeyMaterial *km_n_1 = new KeyMaterial(km_n->secret_len, km_n->key_len, km_n->iv_len); - // uint8_t secret[256] = {0}; - // int r = 0; - - // r = _hkdf_expand_label(secret, km_n->secret_len, km_n->secret, km_n->secret_len, _expand_label_server_1_rtt, - // sizeof(_expand_label_server_1_rtt), this->_digest); - // if (r != 1) { - // return r; - // } - - // r = km_n_1->init(this->_aead, this->_digest, secret); - // if (r != 1) { - // return r; - // } - // this->_server_pp->set_key(km_n_1, new_key_phase); - - // return 1; -} - SSL * QUICCrypto::ssl_handle() { @@ -252,15 +215,15 @@ bool QUICCrypto::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const { - const KeyMaterial *km = nullptr; + QUICPacketProtection *pp = nullptr; switch (this->_netvc_context) { case NET_VCONNECTION_IN: { - km = this->_server_pp->get_key(phase); + pp = this->_server_pp; break; } case NET_VCONNECTION_OUT: { - km = this->_client_pp->get_key(phase); + pp = this->_client_pp; break; } default: @@ -268,24 +231,23 @@ QUICCrypto::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, return false; } - size_t tag_len = _get_aead_tag_len(SSL_get_current_cipher(this->_ssl)); - return _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, km->key, km->key_len, km->iv, - km->iv_len, tag_len); + size_t tag_len = this->_get_aead_tag_len(); + return _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, pp->get_key(phase), tag_len); } bool QUICCrypto::decrypt(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, QUICKeyPhase phase) const { - const KeyMaterial *km = nullptr; + QUICPacketProtection *pp = nullptr; switch (this->_netvc_context) { case NET_VCONNECTION_IN: { - km = this->_client_pp->get_key(phase); + pp = this->_client_pp; break; } case NET_VCONNECTION_OUT: { - km = this->_server_pp->get_key(phase); + pp = this->_server_pp; break; } default: @@ -293,82 +255,8 @@ QUICCrypto::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, con return false; } - size_t tag_len = _get_aead_tag_len(SSL_get_current_cipher(this->_ssl)); - return _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, km->key, km->key_len, km->iv, - km->iv_len, tag_len); -} - -int -QUICCrypto::_export_secret(uint8_t *dst, size_t dst_len, const char *label, size_t label_len) const -{ - return SSL_export_keying_material(this->_ssl, dst, dst_len, label, label_len, reinterpret_cast(""), 0, 1); -} - -/** - * export client_pp_secret_0 and keying material - */ -int -QUICCrypto::_export_client_keymaterial(size_t secret_len, size_t key_len, size_t iv_len) -{ - KeyMaterial *km = new KeyMaterial(secret_len, key_len, iv_len); - int r = 0; - - r = _export_secret(km->secret, secret_len, exporter_label_client_1_rtt.data(), exporter_label_client_1_rtt.size()); - if (r != 1) { - Debug(tag, "Failed to export secret"); - return r; - } - - r = this->_hkdf->expand_label(km->key, &key_len, km->secret, secret_len, expand_label_key.data(), expand_label_key.size(), - EVP_MD_size(this->_digest)); - if (r != 1) { - Debug(tag, "Failed to expand label for key"); - return r; - } - - r = this->_hkdf->expand_label(km->iv, &iv_len, km->secret, secret_len, expand_label_iv.data(), expand_label_iv.size(), - EVP_MD_size(this->_digest)); - if (r != 1) { - Debug(tag, "Failed to expand label for iv"); - return r; - } - - this->_client_pp->set_key(km, QUICKeyPhase::PHASE_0); - - return 1; -} - -/** - * export server_pp_secret_0 and keying material - */ -int -QUICCrypto::_export_server_keymaterial(size_t secret_len, size_t key_len, size_t iv_len) -{ - KeyMaterial *km = new KeyMaterial(secret_len, key_len, iv_len); - int r = 0; - - r = _export_secret(km->secret, secret_len, exporter_label_server_1_rtt.data(), exporter_label_server_1_rtt.size()); - if (r != 1) { - return r; - } - - r = this->_hkdf->expand_label(km->key, &key_len, km->secret, secret_len, expand_label_key.data(), expand_label_key.size(), - EVP_MD_size(this->_digest)); - if (r != 1) { - Debug(tag, "Failed to expand label for key"); - return r; - } - - r = this->_hkdf->expand_label(km->iv, &iv_len, km->secret, secret_len, expand_label_iv.data(), expand_label_iv.size(), - EVP_MD_size(this->_digest)); - if (r != 1) { - Debug(tag, "Failed to expand label for iv"); - return r; - } - - this->_server_pp->set_key(km, QUICKeyPhase::PHASE_0); - - return 1; + size_t tag_len = this->_get_aead_tag_len(); + return _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, pp->get_key(phase), tag_len); } /** diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICCrypto.h index 3e8e0fd741d..8f5888a444d 100644 --- a/iocore/net/quic/QUICCrypto.h +++ b/iocore/net/quic/QUICCrypto.h @@ -23,7 +23,7 @@ #pragma once -#include "ts/HKDF.h" +#include "QUICKeyGenerator.h" #include #ifdef OPENSSL_IS_BORINGSSL @@ -37,32 +37,20 @@ #include "I_NetVConnection.h" #include "QUICTypes.h" -struct KeyMaterial { - KeyMaterial(size_t secret_len, size_t key_len, size_t iv_len) : secret_len(secret_len), key_len(key_len), iv_len(iv_len) {} - uint8_t secret[EVP_MAX_MD_SIZE] = {0}; - // These constant sizes are not enough somehow - // uint8_t key[EVP_MAX_KEY_LENGTH] = {0}; - // uint8_t iv[EVP_MAX_IV_LENGTH] = {0}; - uint8_t key[512] = {0}; - uint8_t iv[512] = {0}; - size_t secret_len = 0; - size_t key_len = 0; - size_t iv_len = 0; -}; - class QUICPacketProtection { public: QUICPacketProtection(){}; ~QUICPacketProtection(); - void set_key(KeyMaterial *km, QUICKeyPhase phase); - const KeyMaterial *get_key(QUICKeyPhase phase) const; + void set_key(std::unique_ptr km, QUICKeyPhase phase); + const KeyMaterial& get_key(QUICKeyPhase phase) const; QUICKeyPhase key_phase() const; private: - KeyMaterial *_phase_0_key = nullptr; - KeyMaterial *_phase_1_key = nullptr; - QUICKeyPhase _key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; + std::unique_ptr _cleartext_key = nullptr; + std::unique_ptr _phase_0_key = nullptr; + std::unique_ptr _phase_1_key = nullptr; + QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; }; class QUICCrypto @@ -73,7 +61,8 @@ class QUICCrypto bool handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len); bool is_handshake_finished() const; - int setup_session(); + int initialize_key_materials(QUICConnectionId cid); + int update_key_materials(); bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const; bool decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher, size_t cipher_len, uint64_t pkt_num, @@ -85,31 +74,25 @@ class QUICCrypto SSL *ssl_handle(); private: - HKDF *_hkdf = nullptr; - int _export_secret(uint8_t *dst, size_t dst_len, const char *label, size_t label_len) const; - int _export_client_keymaterial(size_t secret_len, size_t key_len, size_t iv_len); - int _export_server_keymaterial(size_t secret_len, size_t key_len, size_t iv_len); + QUICKeyGenerator _keygen_for_client = QUICKeyGenerator(QUICKeyGenerator::Context::CLIENT); + QUICKeyGenerator _keygen_for_server = QUICKeyGenerator(QUICKeyGenerator::Context::SERVER); void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; - int _hkdf_expand_label(const uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, - size_t label_len, const EVP_MD *digest); #ifdef OPENSSL_IS_BORINGSSL - const EVP_AEAD *_get_evp_aead(const SSL_CIPHER *cipher) const; + const EVP_AEAD *_get_evp_aead() const; size_t _get_aead_key_len(const EVP_AEAD *aead) const; size_t _get_aead_nonce_len(const EVP_AEAD *aead) const; #else - const EVP_CIPHER *_get_evp_aead(const SSL_CIPHER *cipher) const; + const EVP_CIPHER *_get_evp_aead() const; size_t _get_aead_key_len(const EVP_CIPHER *aead) const; size_t _get_aead_nonce_len(const EVP_CIPHER *aead) const; #endif // OPENSSL_IS_BORINGSSL const EVP_MD *_get_handshake_digest(const SSL_CIPHER *cipher) const; - size_t _get_aead_tag_len(const SSL_CIPHER *cipher) const; + size_t _get_aead_tag_len() const; bool _encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, - size_t iv_len, size_t tag_len) const; + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const; bool _decrypt(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, size_t key_len, const uint8_t *iv, size_t iv_len, - size_t tag_len) const; + const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const; SSL *_ssl = nullptr; #ifdef OPENSSL_IS_BORINGSSL @@ -117,7 +100,6 @@ class QUICCrypto #else const EVP_CIPHER *_aead = nullptr; #endif // OPENSSL_IS_BORINGSSL - const EVP_MD *_digest = nullptr; QUICPacketProtection *_client_pp = nullptr; QUICPacketProtection *_server_pp = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; diff --git a/iocore/net/quic/QUICCrypto_openssl.cc b/iocore/net/quic/QUICCrypto_openssl.cc index b2858f3d6ca..10a9052331b 100644 --- a/iocore/net/quic/QUICCrypto_openssl.cc +++ b/iocore/net/quic/QUICCrypto_openssl.cc @@ -31,21 +31,25 @@ static constexpr char tag[] = "quic_crypto"; const EVP_CIPHER * -QUICCrypto::_get_evp_aead(const SSL_CIPHER *cipher) const +QUICCrypto::_get_evp_aead() const { - switch (SSL_CIPHER_get_id(cipher)) { - case TLS1_3_CK_AES_128_GCM_SHA256: + if (this->is_handshake_finished()) { + switch (SSL_CIPHER_get_id(SSL_get_current_cipher(this->_ssl))) { + case TLS1_3_CK_AES_128_GCM_SHA256: + return EVP_aes_128_gcm(); + case TLS1_3_CK_AES_256_GCM_SHA384: + return EVP_aes_256_gcm(); + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + return EVP_chacha20_poly1305(); + case TLS1_3_CK_AES_128_CCM_SHA256: + case TLS1_3_CK_AES_128_CCM_8_SHA256: + return EVP_aes_128_ccm(); + default: + ink_assert(false); + return nullptr; + } + } else { return EVP_aes_128_gcm(); - case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_aes_256_gcm(); - case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_chacha20_poly1305(); - case TLS1_3_CK_AES_128_CCM_SHA256: - case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_aes_128_ccm(); - default: - ink_assert(false); - return nullptr; } } @@ -67,21 +71,25 @@ QUICCrypto::_get_handshake_digest(const SSL_CIPHER *cipher) const } size_t -QUICCrypto::_get_aead_tag_len(const SSL_CIPHER *cipher) const +QUICCrypto::_get_aead_tag_len() const { - switch (SSL_CIPHER_get_id(cipher)) { - case TLS1_3_CK_AES_128_GCM_SHA256: - case TLS1_3_CK_AES_256_GCM_SHA384: + if (this->is_handshake_finished()) { + switch (SSL_CIPHER_get_id(SSL_get_current_cipher(this->_ssl))) { + case TLS1_3_CK_AES_128_GCM_SHA256: + case TLS1_3_CK_AES_256_GCM_SHA384: + return EVP_GCM_TLS_TAG_LEN; + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + return EVP_CHACHAPOLY_TLS_TAG_LEN; + case TLS1_3_CK_AES_128_CCM_SHA256: + return EVP_CCM_TLS_TAG_LEN; + case TLS1_3_CK_AES_128_CCM_8_SHA256: + return EVP_CCM8_TLS_TAG_LEN; + default: + ink_assert(false); + return -1; + } + } else { return EVP_GCM_TLS_TAG_LEN; - case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_CHACHAPOLY_TLS_TAG_LEN; - case TLS1_3_CK_AES_128_CCM_SHA256: - return EVP_CCM_TLS_TAG_LEN; - case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_CCM8_TLS_TAG_LEN; - default: - ink_assert(false); - return -1; } } @@ -99,12 +107,11 @@ QUICCrypto::_get_aead_nonce_len(const EVP_CIPHER *aead) const bool QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, - size_t iv_len, size_t tag_len) const + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; - _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); + _gen_nonce(nonce, nonce_len, pkt_num, km.iv, km.iv_len); EVP_CIPHER_CTX *aead_ctx; int len; @@ -118,7 +125,7 @@ QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, 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)) { + if (!EVP_EncryptInit_ex(aead_ctx, nullptr, nullptr, km.key, nonce)) { return false; } if (!EVP_EncryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) { @@ -149,12 +156,11 @@ QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, bool QUICCrypto::_decrypt(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, size_t key_len, const uint8_t *iv, - size_t iv_len, size_t tag_len) const + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; - _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); + _gen_nonce(nonce, nonce_len, pkt_num, km.iv, km.iv_len); EVP_CIPHER_CTX *aead_ctx; int len; @@ -168,7 +174,7 @@ QUICCrypto::_decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, co 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)) { + if (!EVP_DecryptInit_ex(aead_ctx, nullptr, nullptr, km.key, nonce)) { return false; } if (!EVP_DecryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) { diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index b23609f1910..c33f3b6a93c 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -89,6 +89,7 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless this->_crypto = new QUICCrypto(this->_ssl, qc->direction()); this->_version_negotiator = new QUICVersionNegotiator(); + this->_crypto->initialize_key_materials(this->_client_qc->connection_id()); this->_load_local_transport_parameters(); SET_HANDLER(&QUICHandshake::state_read_client_hello); @@ -321,12 +322,10 @@ QUICHandshake::_process_client_hello() I_WANNA_DUMP_THIS_BUF(msg, msg_len); // <----- DEBUG ----- - QUICCrypto *crypto = this->_crypto; - uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t server_hello_len = 0; bool result = false; - result = crypto->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, msg, msg_len); + result = this->_crypto->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, msg, msg_len); if (result) { // ----- DEBUG -----> @@ -365,12 +364,10 @@ QUICHandshake::_process_client_finished() I_WANNA_DUMP_THIS_BUF(msg, msg_len); // <----- DEBUG ----- - QUICCrypto *crypto = this->_crypto; - uint8_t out[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t out_len = 0; bool result = false; - result = crypto->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, msg, msg_len); + result = this->_crypto->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, msg, msg_len); if (result) { // ----- DEBUG -----> @@ -398,10 +395,7 @@ QUICHandshake::_process_client_finished() QUICErrorUPtr QUICHandshake::_process_handshake_complete() { - QUICCrypto *crypto = this->_crypto; - int r = crypto->setup_session(); - - if (r) { + if (this->_crypto->update_key_materials()) { DebugQHS("Keying Materials are exported"); } else { DebugQHS("Failed to export Keying Materials"); diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc new file mode 100644 index 00000000000..49277edf3b8 --- /dev/null +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -0,0 +1,105 @@ +/** @file + * + * A key generator for QUIC connection + * + * @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 "QUICKeyGenerator.h" +#include "ts/HKDF.h" + +constexpr static uint8_t QUIC_VERSION_1_SALT[] = { + 0xaf, 0xc8, 0x24, 0xec, 0x5f, 0xc7, 0x7e, 0xca, + 0x1e, 0x9d, 0x36, 0xf3, 0x7f, 0xb2, 0xd4, 0x65, + 0x18, 0xc3, 0x66, 0x39, +}; +constexpr static ts::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("QUIC client cleartext Secret"_sv); +constexpr static ts::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("QUIC server cleartext Secret"_sv); +constexpr static ts::string_view LABEL_FOR_KEY("key"_sv); +constexpr static ts::string_view LABEL_FOR_IV("iv"_sv); + +std::unique_ptr +QUICKeyGenerator::generate(QUICConnectionId cid) +{ + std::unique_ptr km = std::make_unique(); + + const EVP_MD *md= EVP_sha256(); + const QUIC_EVP_CIPHER *cipher = this->_get_cipher_for_cleartext(); + uint8_t cleartext_secret[256]; + size_t cleartext_secret_len = sizeof(cleartext_secret); + uint8_t client_connection_id[8]; + size_t cid_len = 0; + HKDF hkdf(md); + + QUICTypeUtil::write_QUICConnectionId(cid, 8, client_connection_id, &cid_len); + if (hkdf.extract(cleartext_secret, &cleartext_secret_len, QUIC_VERSION_1_SALT, sizeof(QUIC_VERSION_1_SALT), client_connection_id, 8) != 1) { + return nullptr; + } + + switch (this->_ctx) { + case Context::CLIENT: + this->_generate( + km->key, &km->key_len, km->iv, &km->iv_len, + hkdf, + cleartext_secret, cleartext_secret_len, + LABEL_FOR_CLIENT_CLEARTEXT_SECRET.data(), LABEL_FOR_CLIENT_CLEARTEXT_SECRET.length(), + md, cipher); + break; + case Context::SERVER: + this->_generate( + km->key, &km->key_len, km->iv, &km->iv_len, + hkdf, + cleartext_secret, cleartext_secret_len, + LABEL_FOR_SERVER_CLEARTEXT_SECRET.data(), LABEL_FOR_SERVER_CLEARTEXT_SECRET.length(), + md, cipher); + break; + } + + return km; +} + +std::unique_ptr +QUICKeyGenerator::generate() +{ + return 0; +} + +int +QUICKeyGenerator::_generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, HKDF &hkdf, const uint8_t *base_secret, size_t base_secret_len, const char *label, size_t label_len, const EVP_MD *md, const QUIC_EVP_CIPHER *cipher) +{ + uint8_t secret[256]; + size_t secret_len = sizeof(secret); + hkdf.expand_label(secret, &secret_len, base_secret, base_secret_len, reinterpret_cast(label), label_len, "", 0, EVP_MD_size(md)); + this->_generate_key(key, key_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); + this->_generate_iv(iv, iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher)); + + return 0; +} + +int +QUICKeyGenerator::_generate_key(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t key_length) const +{ + return hkdf.expand_label(out, out_len, secret, secret_len, LABEL_FOR_KEY.data(), LABEL_FOR_KEY.length(), "", 0, key_length); +} + +int +QUICKeyGenerator::_generate_iv(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t iv_length) const +{ + return hkdf.expand_label(out, out_len, secret, secret_len, LABEL_FOR_IV.data(), LABEL_FOR_IV.length(), "", 0, iv_length); +} diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h new file mode 100644 index 00000000000..a8e8c326f46 --- /dev/null +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -0,0 +1,75 @@ +/** @file + * + * A key generator for QUIC connection + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include "QUICTypes.h" +#include "ts/HKDF.h" + +#ifdef OPENSSL_IS_BORINGSSL +typedef EVP_AEAD QUIC_EVP_CIPHER; +#else +typedef EVP_CIPHER QUIC_EVP_CIPHER; +#endif // OPENSSL_IS_BORINGSSL + +struct KeyMaterial { + // These constant sizes are not enough somehow + // uint8_t key[EVP_MAX_KEY_LENGTH] = {0}; + // uint8_t iv[EVP_MAX_IV_LENGTH] = {0}; + uint8_t key[512] = {0}; + uint8_t iv[512] = {0}; + size_t key_len = 512; + size_t iv_len = 512; +}; + +class QUICKeyGenerator +{ +public: + enum class Context { + SERVER, CLIENT + }; + + QUICKeyGenerator(Context ctx) : _ctx(ctx) {} + + /* + * Gnerate a key and an IV for Cleartext + */ + std::unique_ptr generate(QUICConnectionId cid); + + /* + * Generate a key and an IV for Packet Protection + * + * On the first call, this generates a secret with the constatnt label and generate a key material with the secret. + * On the following call, this regenerates a new secret based on the last secret and genereate a new key material with the new secret. + */ + std::unique_ptr generate(); + +private: + Context _ctx = Context::SERVER; + int _generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, const EVP_MD *md, const QUIC_EVP_CIPHER *cipher); + int _generate_key(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t key_length) const; + int _generate_iv(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t iv_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_cleartext() const; +}; diff --git a/iocore/net/quic/QUICKeyGenerator_openssl.cc b/iocore/net/quic/QUICKeyGenerator_openssl.cc new file mode 100644 index 00000000000..a7fb4ac8cb5 --- /dev/null +++ b/iocore/net/quic/QUICKeyGenerator_openssl.cc @@ -0,0 +1,41 @@ +/** @file + * + * A key generator for QUIC connection (OpenSSL specific parts) + * + * @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 "QUICKeyGenerator.h" + +size_t +QUICKeyGenerator::_get_key_len(const QUIC_EVP_CIPHER *cipher) const +{ + return EVP_CIPHER_key_length(cipher); +} + +size_t +QUICKeyGenerator::_get_iv_len(const QUIC_EVP_CIPHER *cipher) const +{ + return EVP_CIPHER_iv_length(cipher); +} + +const QUIC_EVP_CIPHER * +QUICKeyGenerator::_get_cipher_for_cleartext() const +{ + return EVP_aes_128_gcm(); +} diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 95572cdb73d..82e0b746c3b 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -174,6 +174,16 @@ QUICPacketLongHeader::payload() const } } +uint16_t +QUICPacketHeader::payload_size() const +{ + if (this->_buf) { + return this->_buf_len - this->length(); + } else { + return this->_payload_len; + } +} + bool QUICPacketLongHeader::has_key_phase() const { @@ -233,7 +243,6 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICPacketNumb this->_key_phase = QUICKeyPhase::PHASE_1; } else { ink_assert(false); - this->_key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; } } @@ -254,11 +263,8 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICConnection this->_key_phase = QUICKeyPhase::PHASE_0; } else if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { this->_key_phase = QUICKeyPhase::PHASE_1; - } else if (type == QUICPacketType::STATELESS_RESET) { - this->_key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; } else { ink_assert(false); - this->_key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; } } @@ -445,10 +451,12 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const // // QUICPacket // -QUICPacket::QUICPacket(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number) +QUICPacket::QUICPacket(QUICPacketHeader *header, ats_unique_buf unprotected_payload, size_t unprotected_payload_len, QUICPacketNumber base_packet_number) { - this->_size = len; - this->_header = QUICPacketHeader::load(reinterpret_cast(buf.release()), len, base_packet_number); + this->_size = unprotected_payload_len; + this->_header = header; + this->_unprotected_payload = std::move(unprotected_payload); + this->_unprotected_payload_len = unprotected_payload_len; } QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, @@ -577,7 +585,6 @@ QUICPacket::header_size() const uint16_t QUICPacket::payload_size() const { - // FIXME Protected packets may / may not contain something at the end if (this->type() == QUICPacketType::STATELESS_RESET) { return this->_size - this->_header->length(); } else if (this->type() != QUICPacketType::ZERO_RTT_PROTECTED && this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && @@ -608,8 +615,8 @@ QUICPacket::store(uint8_t *buf, size_t *len) const memcpy(buf + *len, this->payload(), this->payload_size()); *len += this->payload_size(); - fnv1a(buf, *len, buf + *len); - *len += FNV1A_HASH_LEN; + // fnv1a(buf, *len, buf + *len); + // *len += FNV1A_HASH_LEN; } else { ink_assert(this->_protected_payload); memcpy(buf + *len, this->_protected_payload.get(), this->_protected_payload_size); @@ -623,14 +630,6 @@ QUICPacket::store_header(uint8_t *buf, size_t *len) const this->_header->store(buf, len); } -bool -QUICPacket::has_valid_fnv1a_hash() const -{ - uint8_t hash[FNV1A_HASH_LEN]; - fnv1a(reinterpret_cast(this->_header->buf()), this->size() - FNV1A_HASH_LEN, hash); - return memcmp(this->_header->buf() + this->size() - FNV1A_HASH_LEN, hash, 8) == 0; -} - void QUICPacket::set_protected_payload(ats_unique_buf cipher_txt, size_t cipher_txt_len) { @@ -691,10 +690,55 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si // QUICPacketFactory // QUICPacketUPtr -QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number) -{ - QUICPacket *packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(std::move(buf), len, base_packet_number); +QUICPacketFactory::create(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; + + QUICPacketHeader *header = QUICPacketHeader::load(buf.release(), len, base_packet_number); + + switch (header->type()) { + case QUICPacketType::VERSION_NEGOTIATION: + case QUICPacketType::STATELESS_RESET: + // 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::ONE_RTT_PROTECTED_KEY_PHASE_0: + case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: + if (this->_crypto->is_handshake_finished()) { + if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), + header->packet_number(), header->buf(), header->length(), header->key_phase())) { + result = QUICPacketCreationResult::SUCCESS; + } else { + result = QUICPacketCreationResult::FAILED; + } + } else { + result = QUICPacketCreationResult::NOT_READY; + } + break; + case QUICPacketType::CLIENT_INITIAL: + case QUICPacketType::CLIENT_CLEARTEXT: + case QUICPacketType::SERVER_CLEARTEXT: + if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), + header->packet_number(), header->buf(), header->length(), QUICKeyPhase::CLEARTEXT)) { + result = QUICPacketCreationResult::SUCCESS; + } else { + result = QUICPacketCreationResult::FAILED; + } + default: + result = QUICPacketCreationResult::FAILED; + break; + } + + QUICPacket *packet = nullptr; + if (result == QUICPacketCreationResult::SUCCESS) { + packet = quicPacketAllocator.alloc(); + new (packet) QUICPacket(header, std::move(plain_txt), plain_txt_len, base_packet_number); + } + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 987b90ede91..18744473a73 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -39,13 +39,14 @@ class QUICPacketHeader { public: - QUICPacketHeader(const uint8_t *buf, size_t len, QUICPacketNumber base) : _buf(buf), _base_packet_number(base) {} + QUICPacketHeader(const uint8_t *buf, size_t len, QUICPacketNumber base) : _buf(buf), _buf_len(len), _base_packet_number(base) {} const uint8_t *buf(); virtual QUICPacketType type() const = 0; virtual QUICConnectionId connection_id() const = 0; virtual QUICPacketNumber packet_number() const = 0; virtual QUICVersion version() const = 0; virtual const uint8_t *payload() const = 0; + uint16_t payload_size() const; virtual QUICKeyPhase key_phase() const = 0; virtual uint16_t length() const = 0; virtual void store(uint8_t *buf, size_t *len) const = 0; @@ -65,9 +66,10 @@ class QUICPacketHeader QUICPacketHeader(){}; const uint8_t *_buf = nullptr; + size_t _buf_len = 0; ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); QUICPacketType _type = QUICPacketType::UNINITIALIZED; - QUICKeyPhase _key_phase = QUICKeyPhase::PHASE_UNINITIALIZED; + QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; QUICConnectionId _connection_id = 0; QUICPacketNumber _packet_number = 0; QUICPacketNumber _base_packet_number = 0; @@ -129,7 +131,7 @@ class QUICPacket { public: QUICPacket(){}; - QUICPacket(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number); + QUICPacket(QUICPacketHeader *header, ats_unique_buf unprotected_payload, size_t unprotected_payload_len, QUICPacketNumber base_packet_number); QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len, bool retransmittable); QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, @@ -152,7 +154,6 @@ class QUICPacket uint16_t payload_size() const; void store(uint8_t *buf, size_t *len) const; void store_header(uint8_t *buf, size_t *len) const; - bool has_valid_fnv1a_hash() const; QUICKeyPhase key_phase() const; static uint8_t calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base); static bool encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len); @@ -164,6 +165,8 @@ class QUICPacket ats_unique_buf _protected_payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); size_t _size = 0; size_t _protected_payload_size = 0; + ats_unique_buf _unprotected_payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); + size_t _unprotected_payload_len = 0; QUICPacketHeader *_header; bool _is_retransmittable = false; }; @@ -205,7 +208,7 @@ class QUICPacketDeleter class QUICPacketFactory { public: - static QUICPacketUPtr create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number); + QUICPacketUPtr create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result); QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number); QUICPacketUPtr create_server_cleartext_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); @@ -222,5 +225,3 @@ class QUICPacketFactory QUICCrypto *_crypto = nullptr; QUICPacketNumberGenerator _packet_number_generator; }; - -void fnv1a(const uint8_t *data, size_t len, uint8_t *hash); diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 7427d6a93fe..27fa72c7921 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -147,20 +147,6 @@ QUICTypeUtil::write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size *len = n; } -void -fnv1a(const uint8_t *data, size_t len, uint8_t *hash) -{ - uint64_t h = 0xcbf29ce484222325ULL; - uint64_t prime = 0x100000001b3ULL; - size_t n; - - for (size_t i = 0; i < len; ++i) { - h ^= data[i]; - h *= prime; - } - return QUICTypeUtil::write_uint_as_nbytes(h, 8, hash, &n); -} - uint16_t QUICError::code() { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 2e78939b144..ee8dbbe713f 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -113,7 +113,13 @@ enum class QUICVersionNegotiationStatus { enum class QUICKeyPhase : int { PHASE_0 = 0, PHASE_1, - PHASE_UNINITIALIZED, + CLEARTEXT, +}; + +enum class QUICPacketCreationResult { + SUCCESS, + FAILED, + NOT_READY, }; enum class QUICErrorClass { diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 5b7572902bc..f43d35d482f 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -26,6 +26,7 @@ check_PROGRAMS = \ test_QUICStream \ test_QUICStreamManager \ test_QUICTransportParameters \ + test_QUICKeyGenerator \ test_QUICCrypto \ test_QUICLossDetector \ test_QUICTypeUtil \ @@ -50,8 +51,10 @@ AM_CPPFLAGS += \ @OPENSSL_INCLUDES@ if OPENSSL_IS_BORINGSSL +QUICKeyGenerator_impl = ../QUICKeyGenerator_boringssl.cc QUICCrypto_impl = ../QUICCrypto_boringssl.cc else +QUICKeyGenerator_impl = ../QUICKeyGenerator_openssl.cc QUICCrypto_impl = ../QUICCrypto_openssl.cc endif @@ -316,6 +319,29 @@ test_QUICTransportParameters_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a +# +# test_QUICKeyGenerator +# +test_QUICKeyGenerator_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICKeyGenerator_LDFLAGS = \ + @AM_LDFLAGS@ \ + @OPENSSL_LDFLAGS@ + +test_QUICKeyGenerator_LDADD = \ + @OPENSSL_LIBS@ \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + $(top_builddir)/iocore/eventsystem/libinkevent.a + +test_QUICKeyGenerator_SOURCES = \ + main.cc \ + test_QUICKeyGenerator.cc \ + ../QUICKeyGenerator.cc \ + $(QUICKeyGenerator_impl) \ + ../QUICTypes.cc + # # test_QUICCrypto # diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc new file mode 100644 index 00000000000..cdae44a2cd4 --- /dev/null +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -0,0 +1,107 @@ +/** @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 "catch.hpp" + +#include + +#ifdef OPENSSL_IS_BORINGSSL +#include +#endif + +#include + +#include "Mock.h" +#include "QUICKeyGenerator.h" + +void +print_hex(const uint8_t *v, size_t len) +{ + for (size_t i = 0; i < len; i++) { + std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast(v[i]) << " "; + + if (i != 0 && (i + 1) % 32 == 0 && i != len - 1) { + std::cout << std::endl; + } + } + + std::cout << std::endl; + + return; +} + +TEST_CASE("QUICKeyGenerator", "[quic]") +{ + + SECTION("CLIENT Cleartext") + { + QUICKeyGenerator keygen(QUICKeyGenerator::Context::CLIENT); + + QUICConnectionId cid = 0x8394c8f03e515708; + uint8_t expected_client_key[] = { + 0x2e, 0xbd, 0x78, 0x00, 0xdb, 0xed, 0x20, 0x10, + 0xe5, 0xa2, 0x1c, 0x4a, 0xd2, 0x4b, 0x4e, 0xc3 + }; + uint8_t expected_client_iv[] = { + 0x55, 0x44, 0x0d, 0x5f, 0xf7, 0x50, 0x3d, 0xe4, + 0x99, 0x7b, 0xfd, 0x6b + }; + uint8_t actual_client_key[128]; + size_t actual_client_key_len = sizeof(actual_client_key); + uint8_t actual_client_iv[128]; + size_t actual_client_iv_len = sizeof(actual_client_iv); + + keygen.generate(cid, actual_client_key, &actual_client_key_len, actual_client_iv, &actual_client_iv_len); + + CHECK(actual_client_key_len == sizeof(expected_client_key)); + CHECK(memcmp(actual_client_key, expected_client_key, sizeof(expected_client_key)) == 0); + CHECK(actual_client_iv_len == sizeof(expected_client_iv)); + CHECK(memcmp(actual_client_iv, expected_client_iv, sizeof(expected_client_iv)) == 0); + } + + SECTION("SERVER Cleartext") + { + QUICKeyGenerator keygen(QUICKeyGenerator::Context::SERVER); + + QUICConnectionId cid = 0x8394c8f03e515708; + uint8_t expected_server_key[] = { + 0xc8, 0xea, 0x1b, 0xc1, 0x71, 0xe5, 0x2b, 0xae, + 0x71, 0xfb, 0x78, 0x39, 0x52, 0xc7, 0xb8, 0xfc + }; + uint8_t expected_server_iv[] = { + 0x57, 0x82, 0x3b, 0x85, 0x2c, 0x7e, 0xf9, 0xe3, + 0x80, 0x2b, 0x69, 0x0b + }; + uint8_t actual_server_key[128]; + size_t actual_server_key_len = sizeof(actual_server_key); + uint8_t actual_server_iv[128]; + size_t actual_server_iv_len = sizeof(actual_server_iv); + + keygen.generate(cid, actual_server_key, &actual_server_key_len, actual_server_iv, &actual_server_iv_len); + + CHECK(actual_server_key_len == sizeof(expected_server_key)); + CHECK(memcmp(actual_server_key, expected_server_key, sizeof(expected_server_key)) == 0); + CHECK(actual_server_iv_len == sizeof(expected_server_iv)); + CHECK(memcmp(actual_server_iv, expected_server_iv, sizeof(expected_server_iv)) == 0); + } +} diff --git a/lib/ts/HKDF.cc b/lib/ts/HKDF.cc index fe01117e1f1..6da55c41a57 100644 --- a/lib/ts/HKDF.cc +++ b/lib/ts/HKDF.cc @@ -26,18 +26,19 @@ int HKDF::expand_label(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, - uint16_t length) + const char *hash_value, size_t hash_value_len, uint16_t length) { // Create HKDF label uint8_t hkdf_label[512]; // 2 + 255 + 255 + int hkdf_label_len = 0; // Length hkdf_label[0] = (length >> 8) & 0xFF; hkdf_label[1] = length & 0xFF; + hkdf_label_len += 2; // "tls13 " + Label - int hkdf_label_len = sprintf(reinterpret_cast(hkdf_label + 2), "tls13 %.*s", static_cast(label_len), label); - // Always 0 - hkdf_label[hkdf_label_len] = 0; - ++hkdf_label_len; + hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%ctls13 %.*s", static_cast(6 + label_len), static_cast(label_len), label); + // Hash Value + hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%c%.*s", static_cast(hash_value_len), static_cast(hash_value_len), hash_value); this->expand(dst, dst_len, secret, secret_len, hkdf_label, hkdf_label_len, length); return 1; diff --git a/lib/ts/HKDF.h b/lib/ts/HKDF.h index e659adaa767..290529933db 100644 --- a/lib/ts/HKDF.h +++ b/lib/ts/HKDF.h @@ -40,7 +40,7 @@ class HKDF // This function is technically a part of TLS 1.3 int expand_label(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, - uint16_t length); + const char *hash_value, size_t hash_value_len, uint16_t length); private: const EVP_MD *_digest = nullptr; diff --git a/lib/ts/HKDF_openssl.cc b/lib/ts/HKDF_openssl.cc index af0e87f7e90..d8ff3e4edc0 100644 --- a/lib/ts/HKDF_openssl.cc +++ b/lib/ts/HKDF_openssl.cc @@ -25,12 +25,16 @@ HKDF::HKDF(const EVP_MD *digest) : _digest(digest) { - this->_pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr); + // XXX We cannot reuse pctx now due to a bug in OpenSSL + // this->_pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr); } int HKDF::extract(uint8_t *dst, size_t *dst_len, const uint8_t *salt, size_t salt_len, const uint8_t *ikm, size_t ikm_len) { + // XXX See comments in the constructor + this->_pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr); + if (EVP_PKEY_derive_init(this->_pctx) != 1) { return -1; } @@ -49,13 +53,23 @@ HKDF::extract(uint8_t *dst, size_t *dst_len, const uint8_t *salt, size_t salt_le if (EVP_PKEY_derive(this->_pctx, dst, dst_len) != 1) { return -6; } + + /// XXX See comments in constuctor. + EVP_PKEY_CTX_free(this->_pctx); + return 1; + + // XXX See comments in the constructor + EVP_PKEY_CTX_free(this->_pctx); } int HKDF::expand(uint8_t *dst, size_t *dst_len, const uint8_t *prk, size_t prk_len, const uint8_t *info, size_t info_len, uint16_t length) { + // XXX See comments in the constructor + this->_pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr); + if (EVP_PKEY_derive_init(this->_pctx) != 1) { return -1; } @@ -76,5 +90,8 @@ HKDF::expand(uint8_t *dst, size_t *dst_len, const uint8_t *prk, size_t prk_len, return -7; } + // XXX See comments in the constructor + EVP_PKEY_CTX_free(this->_pctx); + return 1; } From e5af6be2b46d31768f29f8387febb0c3bd9b8b74 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 17 Nov 2017 11:22:40 +0800 Subject: [PATCH 0176/1313] return something to make g++ happy --- iocore/net/quic/QUICCrypto.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index ec020a8ff45..d407e038e26 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -70,6 +70,9 @@ QUICPacketProtection::get_key(QUICKeyPhase phase) const case QUICKeyPhase::CLEARTEXT: return *this->_cleartext_key; } + + ink_release_assert(!"Bad phase"); + return *this->_cleartext_key; } QUICKeyPhase From 0e83437af5abf82a64da3de326cd82114b8fd95e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 17 Nov 2017 15:54:42 +0900 Subject: [PATCH 0177/1313] Make tests compilable --- iocore/net/quic/QUICPacket.cc | 61 ++++------ iocore/net/quic/QUICPacket.h | 106 +++++++++++++++--- iocore/net/quic/test/Makefile.am | 17 +++ iocore/net/quic/test/test_QUICCrypto.cc | 4 +- iocore/net/quic/test/test_QUICKeyGenerator.cc | 28 ++--- iocore/net/quic/test/test_QUICPacket.cc | 80 +++++-------- .../net/quic/test/test_QUICPacketFactory.cc | 9 +- 7 files changed, 177 insertions(+), 128 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 82e0b746c3b..2b5e87baace 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -85,6 +85,12 @@ QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUI return short_header; } +QUICPacketHeader * +QUICPacketHeader::clone() const +{ + return nullptr; +} + // // QUICPacketLongHeader // @@ -451,12 +457,13 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const // // QUICPacket // -QUICPacket::QUICPacket(QUICPacketHeader *header, ats_unique_buf unprotected_payload, size_t unprotected_payload_len, QUICPacketNumber base_packet_number) + +QUICPacket::QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len, QUICPacketNumber base_packet_number) { - this->_size = unprotected_payload_len; - this->_header = header; - this->_unprotected_payload = std::move(unprotected_payload); - this->_unprotected_payload_len = unprotected_payload_len; + this->_header = header; + this->_size = this->_header->length() + payload_len; + this->_payload = std::move(payload); + this->_payload_size = payload_len; } QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, @@ -546,10 +553,10 @@ QUICPacket::packet_number() const return this->_header->packet_number(); } -const uint8_t * +const QUICPacketHeader * QUICPacket::header() const { - return this->_header->buf(); + return this->_header; } const uint8_t * @@ -604,37 +611,8 @@ QUICPacket::key_phase() const void QUICPacket::store(uint8_t *buf, size_t *len) const { - this->_header->store(buf, len); - ink_assert(this->size() >= *len); - - if (this->type() == QUICPacketType::STATELESS_RESET) { - memcpy(buf + *len, this->payload(), this->payload_size()); - *len += this->payload_size(); - } else if (this->type() != QUICPacketType::ZERO_RTT_PROTECTED && this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && - this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { - memcpy(buf + *len, this->payload(), this->payload_size()); - *len += this->payload_size(); - - // fnv1a(buf, *len, buf + *len); - // *len += FNV1A_HASH_LEN; - } else { - ink_assert(this->_protected_payload); - memcpy(buf + *len, this->_protected_payload.get(), this->_protected_payload_size); - *len += this->_protected_payload_size; - } -} - -void -QUICPacket::store_header(uint8_t *buf, size_t *len) const -{ - this->_header->store(buf, len); -} - -void -QUICPacket::set_protected_payload(ats_unique_buf cipher_txt, size_t cipher_txt_len) -{ - this->_protected_payload = std::move(cipher_txt); - this->_protected_payload_size = cipher_txt_len; + memcpy(buf + *len, this->payload(), this->payload_size()); + *len = this->payload_size(); } uint8_t @@ -790,11 +768,14 @@ QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id // TODO: do not dump header twice uint8_t ad[17] = {0}; size_t ad_len = 0; - packet->store_header(ad, &ad_len); + packet->header()->store(ad, &ad_len); if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, packet->payload(), packet->payload_size(), packet->packet_number(), ad, ad_len, packet->key_phase())) { - packet->set_protected_payload(std::move(cipher_txt), cipher_txt_len); + QUICPacket *ep = quicPacketAllocator.alloc(); + new (ep) QUICPacket(packet->header()->clone(), std::move(cipher_txt), cipher_txt_len, base_packet_number); + packet = QUICPacketUPtr(ep, &QUICPacketDeleter::delete_packet); + Debug("quic_packet_factory", "Encrypt Packet, pkt_num: %" PRIu64 ", header_len: %zu payload: %zu", packet->packet_number(), ad_len, cipher_txt_len); return packet; diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 18744473a73..5a56349b389 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -45,28 +45,81 @@ class QUICPacketHeader virtual QUICConnectionId connection_id() const = 0; virtual QUICPacketNumber packet_number() const = 0; virtual QUICVersion version() const = 0; + + /* + * Returns a pointer for the payload + */ virtual const uint8_t *payload() const = 0; + + /* + * Returns a payload size based on header length and buffer size that is specified to the constructo. + */ uint16_t payload_size() const; - virtual QUICKeyPhase key_phase() const = 0; + + /* + * Returns a header size + */ virtual uint16_t length() const = 0; + + /* + * Returns a key phase + */ + virtual QUICKeyPhase key_phase() const = 0; + + /* + * 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; + + QUICPacketHeader *clone() const; + + virtual bool has_key_phase() const = 0; + virtual bool has_connection_id() const = 0; + virtual bool has_version() const = 0; + + /***** STATIC members *****/ + + /* + * Load data from a buffer and create a QUICPacketHeader + * + * This creates either a QUICPacketShortHeader or a QUICPacketLongHeader. + */ static QUICPacketHeader *load(const uint8_t *buf, size_t len, QUICPacketNumber base); + + + /* + * Build a QUICPacketHeader + * + * This creates a QUICPacketLongHeader. + */ static QUICPacketHeader *build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); + + /* + * Build a QUICPacketHeader + * + * This creates a QUICPacketShortHeader that contains a ConnectionID. + */ static QUICPacketHeader *build(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len); + + /* + * Build a QUICPacketHeader + * + * This creates a QUICPacketShortHeader that doesn't contain a ConnectionID.. + */ static QUICPacketHeader *build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len); - static QUICPacketHeader *build(QUICPacketType, QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token); - virtual bool has_key_phase() const = 0; - virtual bool has_connection_id() const = 0; - virtual bool has_version() const = 0; protected: QUICPacketHeader(){}; - const uint8_t *_buf = nullptr; - size_t _buf_len = 0; + // These two are used only if the instance was created with a buffer + const uint8_t *_buf = nullptr; + size_t _buf_len = 0; + ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); QUICPacketType _type = QUICPacketType::UNINITIALIZED; QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; @@ -131,30 +184,53 @@ class QUICPacket { public: QUICPacket(){}; - QUICPacket(QUICPacketHeader *header, ats_unique_buf unprotected_payload, size_t unprotected_payload_len, QUICPacketNumber base_packet_number); + + /* + * Creates a QUICPacket with a QUICPacketHeader and a buffer that contains payload + * + * QUICPacket class doesn't care about whether the payload is protected (encrypted) or not. + */ + QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len, QUICPacketNumber base_packet_number); + + /* + * Creates a QUICPacket that has a Long Header + */ QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len, bool retransmittable); + + /* + * Creates a QUICPacket that has a Short Header + */ QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); + + /* + * Creates a QUICPacket that has a Short Header with a Connection ID + */ QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittabl); + + /* + * Creates a QUICpacket for stateless reset + */ QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token); ~QUICPacket(); - void set_protected_payload(ats_unique_buf cipher_txt, size_t cipher_txt_len); QUICPacketType type() const; QUICConnectionId connection_id() const; QUICPacketNumber packet_number() const; QUICVersion version() const; - const uint8_t *header() const; + const QUICPacketHeader *header() const; const uint8_t *payload() const; bool is_retransmittable() const; uint16_t size() const; uint16_t header_size() const; uint16_t payload_size() const; void store(uint8_t *buf, size_t *len) const; - void store_header(uint8_t *buf, size_t *len) const; QUICKeyPhase key_phase() const; + + /***** STATIC MEMBERS *****/ + static uint8_t calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base); static bool encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len); static bool decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, QUICPacketNumber largest_acked); @@ -162,12 +238,10 @@ class QUICPacket LINK(QUICPacket, link); private: - ats_unique_buf _protected_payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); - size_t _size = 0; - size_t _protected_payload_size = 0; - ats_unique_buf _unprotected_payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); - size_t _unprotected_payload_len = 0; QUICPacketHeader *_header; + ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); + size_t _payload_size = 0; + size_t _size = 0; bool _is_retransmittable = false; }; diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index f43d35d482f..f750fea21e7 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -130,6 +130,8 @@ test_QUICFrame_SOURCES = \ ../QUICGlobals.cc \ ../QUICFrame.cc \ ../QUICPacket.cc \ + ../QUICKeyGenerator.cc \ + $(QUICKeyGenerator_impl) \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICTypes.cc \ @@ -180,6 +182,8 @@ test_QUICFrameDispatcher_SOURCES = \ ../QUICDebugNames.cc \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ + ../QUICKeyGenerator.cc \ + $(QUICKeyGenerator_impl) \ ../../SSLNextProtocolSet.cc test_QUICFrameDispatcher_LDADD = \ @@ -299,6 +303,8 @@ test_QUICTransportParameters_SOURCES = \ ../QUICVersionNegotiator.cc \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ + ../QUICKeyGenerator.cc \ + $(QUICKeyGenerator_impl) \ ../QUICStream.cc \ ../QUICIncomingFrameBuffer.cc \ ../QUICStreamState.cc \ @@ -361,9 +367,12 @@ test_QUICCrypto_LDADD = \ test_QUICCrypto_SOURCES = \ main.cc \ test_QUICCrypto.cc \ + ../QUICKeyGenerator.cc \ + $(QUICKeyGenerator_impl) \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICCrypto.h \ + ../QUICTypes.cc \ ../QUICGlobals.cc \ ../../SSLNextProtocolSet.cc @@ -423,6 +432,8 @@ test_QUICTypeUtil_SOURCES = \ ../QUICDebugNames.cc \ ../QUICFrame.cc \ ../QUICPacket.cc \ + ../QUICKeyGenerator.cc \ + $(QUICKeyGenerator_impl) \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICTypes.cc @@ -456,6 +467,8 @@ test_QUICAckFrameCreator_SOURCES = \ ../QUICStreamState.cc \ ../QUICFlowController.cc \ ../QUICDebugNames.cc \ + ../QUICKeyGenerator.cc \ + $(QUICKeyGenerator_impl) \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../../SSLNextProtocolSet.cc @@ -485,6 +498,8 @@ test_QUICVersionNegotiator_SOURCES = \ ../QUICGlobals.cc \ ../QUICTypes.cc \ ../QUICPacket.cc \ + ../QUICKeyGenerator.cc \ + $(QUICKeyGenerator_impl) \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICApplication.cc \ @@ -531,6 +546,8 @@ test_QUICFlowController_SOURCES = \ ../QUICDebugNames.cc \ ../QUICTypes.cc \ ../QUICPacket.cc \ + ../QUICKeyGenerator.cc \ + $(QUICKeyGenerator_impl) \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICFrame.cc diff --git a/iocore/net/quic/test/test_QUICCrypto.cc b/iocore/net/quic/test/test_QUICCrypto.cc index 2d2f471822b..a3753088342 100644 --- a/iocore/net/quic/test/test_QUICCrypto.cc +++ b/iocore/net/quic/test/test_QUICCrypto.cc @@ -149,8 +149,8 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") std::cout << "Post Handshake Message" << std::endl; print_hex(post_handshake_msg, post_handshake_msg_len); - CHECK(client->setup_session()); - CHECK(server->setup_session()); + CHECK(client->initialize_key_materials(0x8394c8f03e515708)); + CHECK(server->initialize_key_materials(0x8394c8f03e515708)); // encrypt - decrypt uint8_t original[] = { diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index cdae44a2cd4..d8d122d4163 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -66,17 +66,13 @@ TEST_CASE("QUICKeyGenerator", "[quic]") 0x55, 0x44, 0x0d, 0x5f, 0xf7, 0x50, 0x3d, 0xe4, 0x99, 0x7b, 0xfd, 0x6b }; - uint8_t actual_client_key[128]; - size_t actual_client_key_len = sizeof(actual_client_key); - uint8_t actual_client_iv[128]; - size_t actual_client_iv_len = sizeof(actual_client_iv); - keygen.generate(cid, actual_client_key, &actual_client_key_len, actual_client_iv, &actual_client_iv_len); + std::unique_ptr actual_km = keygen.generate(cid); - CHECK(actual_client_key_len == sizeof(expected_client_key)); - CHECK(memcmp(actual_client_key, expected_client_key, sizeof(expected_client_key)) == 0); - CHECK(actual_client_iv_len == sizeof(expected_client_iv)); - CHECK(memcmp(actual_client_iv, expected_client_iv, sizeof(expected_client_iv)) == 0); + CHECK(actual_km->key_len == sizeof(expected_client_key)); + CHECK(memcmp(actual_km->key, expected_client_key, sizeof(expected_client_key)) == 0); + CHECK(actual_km->iv_len == sizeof(expected_client_iv)); + CHECK(memcmp(actual_km->iv, expected_client_iv, sizeof(expected_client_iv)) == 0); } SECTION("SERVER Cleartext") @@ -92,16 +88,12 @@ TEST_CASE("QUICKeyGenerator", "[quic]") 0x57, 0x82, 0x3b, 0x85, 0x2c, 0x7e, 0xf9, 0xe3, 0x80, 0x2b, 0x69, 0x0b }; - uint8_t actual_server_key[128]; - size_t actual_server_key_len = sizeof(actual_server_key); - uint8_t actual_server_iv[128]; - size_t actual_server_iv_len = sizeof(actual_server_iv); - keygen.generate(cid, actual_server_key, &actual_server_key_len, actual_server_iv, &actual_server_iv_len); + std::unique_ptr actual_km = keygen.generate(cid); - CHECK(actual_server_key_len == sizeof(expected_server_key)); - CHECK(memcmp(actual_server_key, expected_server_key, sizeof(expected_server_key)) == 0); - CHECK(actual_server_iv_len == sizeof(expected_server_iv)); - CHECK(memcmp(actual_server_iv, expected_server_iv, sizeof(expected_server_iv)) == 0); + CHECK(actual_km->key_len == sizeof(expected_server_key)); + CHECK(memcmp(actual_km->key, expected_server_key, sizeof(expected_server_key)) == 0); + CHECK(actual_km->iv_len == sizeof(expected_server_iv)); + CHECK(memcmp(actual_km->iv, expected_server_iv, sizeof(expected_server_iv)) == 0); } } diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 8c2f2bfcdf8..46ddb629be8 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -25,56 +25,38 @@ #include "quic/QUICPacket.h" -TEST_CASE("Loading Long Header Packet", "[quic]") +TEST_CASE("QUICPacketHeader", "[quic]") { - uint8_t raw[] = {0x01, 0x02, 0x03, 0x04}; - ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); - memcpy(payload.get(), raw, sizeof(raw)); - - // Cleartext packet with a long header - QUICPacket packet1(QUICPacketType::CLIENT_CLEARTEXT, 0xffddbb9977553311ULL, 0xffcc9966, 0, 0x00112233, std::move(payload), - sizeof(raw), true); - - uint8_t buf[65536]; - size_t len; - packet1.store(buf, &len); - - const QUICPacket packet2(ats_unique_buf(buf, [](void *p) { ats_free(p); }), len, 0); - - CHECK(packet2.type() == QUICPacketType::CLIENT_CLEARTEXT); - CHECK(packet2.connection_id() == 0xffddbb9977553311ULL); - CHECK(packet2.packet_number() == 0xffcc9966); - CHECK(packet2.version() == 0x00112233); - CHECK(packet2.size() == 29); - CHECK(packet2.payload_size() == sizeof(raw)); - CHECK(memcmp(packet2.payload(), raw, sizeof(raw)) == 0); -} - -TEST_CASE("Loading Short Header Packet", "[quic]") -{ - uint8_t raw[] = {0x01, 0x02, 0x03, 0x04}; - ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); - memcpy(payload.get(), raw, sizeof(raw)); - - uint8_t protected_raw[] = {0x04, 0x03, 0x02, 0x01, 0x00}; - ats_unique_buf protected_payload = ats_unique_malloc(sizeof(protected_raw)); - memcpy(protected_payload.get(), protected_raw, sizeof(protected_raw)); - - // Cleartext packet with a long header - QUICPacket packet1(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, 0xffcc9966, 0, std::move(payload), sizeof(raw), true); - packet1.set_protected_payload(std::move(protected_payload), sizeof(protected_raw)); - - uint8_t buf[65536]; - size_t len; - packet1.store(buf, &len); - - const QUICPacket packet2(ats_unique_buf(buf, [](void *p) { ats_free(p); }), len, 0); - - CHECK(packet2.type() == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0); - CHECK(packet2.packet_number() == 0xffcc9966); - CHECK(packet2.size() == 10); - CHECK(packet2.payload_size() == sizeof(protected_raw)); - CHECK(memcmp(packet2.payload(), protected_raw, sizeof(protected_raw)) == 0); + SECTION("Long Header") + { + const uint8_t input[] = { + 0x81, // Long header, Type + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Connection ID + 0x12, 0x34, 0x56, 0x78, // Packet number + 0x11, 0x22, 0x33, 0x44, // Version + 0xff, 0xff, // Payload (dummy) + }; + + QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); + CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); + CHECK(header->connection_id() == 0x01020304050607); + CHECK(header->packet_number() == 0); + CHECK(header->version() == 0x11223344); + } + + SECTION("Short Header") + { + const uint8_t input[] = { + 0x41, // Short header, with Connection ID, KeyPhse 0, Type + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Connection ID + 0x12, 0x34, 0x56, 0x78, // Packet number + 0xff, 0xff, // Payload (dummy) + }; + + QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); + CHECK(header->connection_id() == 0x01020304050607); + CHECK(header->packet_number() == 0); + } } TEST_CASE("Loading Unknown Packet", "[quic]") diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 942b49ce7f9..06d12c9cd97 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -29,16 +29,19 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") { QUICPacketFactory factory; - uint8_t client_initial_packet_data[] = { + uint8_t client_initial_packet_header[] = { 0x82, // Type 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection id 0x00, 0x00, 0x00, 0x00, // Packet number 0xaa, 0xbb, 0xcc, 0xdd, // Version + }; + uint8_t client_initial_packet_payload[] = { 0x00 // Payload }; - QUICPacket client_initial_packet(ats_unique_buf(client_initial_packet_data, [](void *p) { ats_free(p); }), - sizeof(client_initial_packet_data), 0); + QUICPacketHeader *header = QUICPacketHeader::load(client_initial_packet_header, sizeof(client_initial_packet_header), 0); + QUICPacket client_initial_packet(header, ats_unique_buf(client_initial_packet_payload, [](void *p) { ats_free(p); }), + sizeof(client_initial_packet_payload), 0); QUICPacketUPtr packet = factory.create_version_negotiation_packet(&client_initial_packet, 0); CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); From 9964e57b378fa1472a677c868292a683f73b0720 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 20 Nov 2017 17:20:10 +0900 Subject: [PATCH 0178/1313] Fix bugs and make all tests pass (but still cannnot handshake) --- iocore/net/QUICNetVConnection.cc | 5 +- iocore/net/quic/QUICCrypto.cc | 37 +++--- iocore/net/quic/QUICCrypto.h | 9 +- iocore/net/quic/QUICCrypto_openssl.cc | 17 --- iocore/net/quic/QUICKeyGenerator.cc | 115 +++++++++++++----- iocore/net/quic/QUICKeyGenerator.h | 31 +++-- iocore/net/quic/QUICKeyGenerator_openssl.cc | 39 ++++++ iocore/net/quic/QUICPacket.cc | 18 +-- iocore/net/quic/QUICPacket.h | 13 +- iocore/net/quic/test/test_QUICCrypto.cc | 88 ++++++++++++++ iocore/net/quic/test/test_QUICKeyGenerator.cc | 27 ++-- iocore/net/quic/test/test_QUICPacket.cc | 26 ++-- .../net/quic/test/test_QUICPacketFactory.cc | 8 +- lib/ts/HKDF.cc | 6 +- 14 files changed, 295 insertions(+), 144 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 48edd888b25..7c7db3a3cba 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -691,7 +691,7 @@ QUICNetVConnection::_state_common_receive_packet() { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); QUICPacketCreationResult result; - QUICPacketUPtr p = this->_dequeue_recv_packet(result); + QUICPacketUPtr p = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::FAILED) { return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); } else if (result == QUICPacketCreationResult::NOT_READY) { @@ -965,7 +965,8 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) } else { udp_packet->free(); if (result == QUICPacketCreationResult::SUCCESS) { - DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), quic_packet->packet_number(), quic_packet->size()); + DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), + quic_packet->packet_number(), quic_packet->size()); } else { DebugQUICCon("Failed to decrypt the packet"); } diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index d407e038e26..cfe9d4b0052 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -43,10 +43,10 @@ QUICPacketProtection::~QUICPacketProtection() } void -QUICPacketProtection::set_key(std::unique_ptrkm, QUICKeyPhase phase) +QUICPacketProtection::set_key(std::unique_ptr km, QUICKeyPhase phase) { this->_key_phase = phase; - switch(phase) { + switch (phase) { case QUICKeyPhase::PHASE_0: this->_phase_0_key = std::move(km); break; @@ -59,10 +59,10 @@ QUICPacketProtection::set_key(std::unique_ptrkm, QUICKeyPhase phase } } -const KeyMaterial& +const KeyMaterial & QUICPacketProtection::get_key(QUICKeyPhase phase) const { - switch(phase) { + switch (phase) { case QUICKeyPhase::PHASE_0: return *this->_phase_0_key; case QUICKeyPhase::PHASE_1: @@ -161,21 +161,24 @@ QUICCrypto::is_handshake_finished() const int QUICCrypto::initialize_key_materials(QUICConnectionId cid) { - this->_aead = _get_evp_aead(); - + // Generate keys std::unique_ptr km; - // for decryption km = this->_keygen_for_client.generate(cid); this->_client_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); - // for encryption km = this->_keygen_for_server.generate(cid); this->_server_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); + + // Update algorithm + this->_aead = _get_evp_aead(); + return 1; } int QUICCrypto::update_key_materials() { + ink_assert(this->is_handshake_finished()); + // Switch key phase QUICKeyPhase next_key_phase; switch (this->_client_pp->key_phase()) { case QUICKeyPhase::PHASE_0: @@ -188,23 +191,17 @@ QUICCrypto::update_key_materials() next_key_phase = QUICKeyPhase::PHASE_0; break; } - const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); - this->_aead = _get_evp_aead(); - - size_t secret_len = EVP_MD_size(_get_handshake_digest(cipher)); - size_t key_len = _get_aead_key_len(this->_aead); - size_t iv_len = std::max(static_cast(8), _get_aead_nonce_len(this->_aead)); + // Generate keys std::unique_ptr km; - // for decryption - km = this->_keygen_for_client.generate(); + km = this->_keygen_for_client.generate(this->_ssl); this->_client_pp->set_key(std::move(km), next_key_phase); - // for encryption - km = this->_keygen_for_server.generate(); + km = this->_keygen_for_server.generate(this->_ssl); this->_server_pp->set_key(std::move(km), next_key_phase); - Debug(tag, "Negotiated ciper: %s, secret_len: %zu, key_len: %zu, iv_len: %zu", SSL_CIPHER_get_name(cipher), secret_len, key_len, - iv_len); + // Update algorithm + this->_aead = _get_evp_aead(); + return 1; } diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICCrypto.h index 8f5888a444d..62f6db8e204 100644 --- a/iocore/net/quic/QUICCrypto.h +++ b/iocore/net/quic/QUICCrypto.h @@ -43,14 +43,14 @@ class QUICPacketProtection QUICPacketProtection(){}; ~QUICPacketProtection(); void set_key(std::unique_ptr km, QUICKeyPhase phase); - const KeyMaterial& get_key(QUICKeyPhase phase) const; + const KeyMaterial &get_key(QUICKeyPhase phase) const; QUICKeyPhase key_phase() const; private: std::unique_ptr _cleartext_key = nullptr; - std::unique_ptr _phase_0_key = nullptr; - std::unique_ptr _phase_1_key = nullptr; - QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; + std::unique_ptr _phase_0_key = nullptr; + std::unique_ptr _phase_1_key = nullptr; + QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; }; class QUICCrypto @@ -86,7 +86,6 @@ class QUICCrypto size_t _get_aead_key_len(const EVP_CIPHER *aead) const; size_t _get_aead_nonce_len(const EVP_CIPHER *aead) const; #endif // OPENSSL_IS_BORINGSSL - const EVP_MD *_get_handshake_digest(const SSL_CIPHER *cipher) const; size_t _get_aead_tag_len() const; bool _encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, diff --git a/iocore/net/quic/QUICCrypto_openssl.cc b/iocore/net/quic/QUICCrypto_openssl.cc index 10a9052331b..e62a5ef69b5 100644 --- a/iocore/net/quic/QUICCrypto_openssl.cc +++ b/iocore/net/quic/QUICCrypto_openssl.cc @@ -53,23 +53,6 @@ QUICCrypto::_get_evp_aead() const } } -const EVP_MD * -QUICCrypto::_get_handshake_digest(const SSL_CIPHER *cipher) const -{ - switch (SSL_CIPHER_get_id(cipher)) { - case TLS1_3_CK_AES_128_GCM_SHA256: - case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - case TLS1_3_CK_AES_128_CCM_SHA256: - case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_sha256(); - case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_sha384(); - default: - ink_assert(false); - return nullptr; - } -} - size_t QUICCrypto::_get_aead_tag_len() const { diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 49277edf3b8..a9aba4e074a 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -21,16 +21,17 @@ * limitations under the License. */ +#include #include "QUICKeyGenerator.h" #include "ts/HKDF.h" constexpr static uint8_t QUIC_VERSION_1_SALT[] = { - 0xaf, 0xc8, 0x24, 0xec, 0x5f, 0xc7, 0x7e, 0xca, - 0x1e, 0x9d, 0x36, 0xf3, 0x7f, 0xb2, 0xd4, 0x65, - 0x18, 0xc3, 0x66, 0x39, + 0xaf, 0xc8, 0x24, 0xec, 0x5f, 0xc7, 0x7e, 0xca, 0x1e, 0x9d, 0x36, 0xf3, 0x7f, 0xb2, 0xd4, 0x65, 0x18, 0xc3, 0x66, 0x39, }; constexpr static ts::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("QUIC client cleartext Secret"_sv); constexpr static ts::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("QUIC server cleartext Secret"_sv); +constexpr static ts::string_view LABEL_FOR_CLIENT_PP_SECRET("EXPORTER-QUIC client 1-RTT Secret"_sv); +constexpr static ts::string_view LABEL_FOR_SERVER_PP_SECRET("EXPORTER-QUIC server 1-RTT Secret"_sv); constexpr static ts::string_view LABEL_FOR_KEY("key"_sv); constexpr static ts::string_view LABEL_FOR_IV("iv"_sv); @@ -39,53 +40,62 @@ QUICKeyGenerator::generate(QUICConnectionId cid) { std::unique_ptr km = std::make_unique(); - const EVP_MD *md= EVP_sha256(); const QUIC_EVP_CIPHER *cipher = this->_get_cipher_for_cleartext(); - uint8_t cleartext_secret[256]; - size_t cleartext_secret_len = sizeof(cleartext_secret); - uint8_t client_connection_id[8]; - size_t cid_len = 0; + const EVP_MD *md = EVP_sha256(); + uint8_t secret[512]; + size_t secret_len = sizeof(secret); HKDF hkdf(md); - QUICTypeUtil::write_QUICConnectionId(cid, 8, client_connection_id, &cid_len); - if (hkdf.extract(cleartext_secret, &cleartext_secret_len, QUIC_VERSION_1_SALT, sizeof(QUIC_VERSION_1_SALT), client_connection_id, 8) != 1) { - return nullptr; - } - switch (this->_ctx) { case Context::CLIENT: - this->_generate( - km->key, &km->key_len, km->iv, &km->iv_len, - hkdf, - cleartext_secret, cleartext_secret_len, - LABEL_FOR_CLIENT_CLEARTEXT_SECRET.data(), LABEL_FOR_CLIENT_CLEARTEXT_SECRET.length(), - md, cipher); + this->_generate_cleartext_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_CLIENT_CLEARTEXT_SECRET.data(), + LABEL_FOR_CLIENT_CLEARTEXT_SECRET.length(), EVP_MD_size(md)); break; case Context::SERVER: - this->_generate( - km->key, &km->key_len, km->iv, &km->iv_len, - hkdf, - cleartext_secret, cleartext_secret_len, - LABEL_FOR_SERVER_CLEARTEXT_SECRET.data(), LABEL_FOR_SERVER_CLEARTEXT_SECRET.length(), - md, cipher); + this->_generate_cleartext_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_SERVER_CLEARTEXT_SECRET.data(), + LABEL_FOR_SERVER_CLEARTEXT_SECRET.length(), EVP_MD_size(md)); break; } + this->_generate(km->key, &km->key_len, km->iv, &km->iv_len, hkdf, secret, secret_len, cipher); + return km; } std::unique_ptr -QUICKeyGenerator::generate() +QUICKeyGenerator::generate(SSL *ssl) { - return 0; + std::unique_ptr km = std::make_unique(); + + const QUIC_EVP_CIPHER *cipher = this->_get_cipher_for_protected_packet(ssl); + const EVP_MD *md = _get_handshake_digest(ssl); + uint8_t secret[512]; + size_t secret_len = sizeof(secret); + HKDF hkdf(md); + + switch (this->_ctx) { + case Context::CLIENT: + this->_generate_pp_secret(secret, &secret_len, hkdf, ssl, LABEL_FOR_CLIENT_PP_SECRET.data(), + LABEL_FOR_CLIENT_PP_SECRET.length(), EVP_MD_size(md)); + break; + case Context::SERVER: + this->_generate_pp_secret(secret, &secret_len, hkdf, ssl, LABEL_FOR_SERVER_PP_SECRET.data(), + LABEL_FOR_SERVER_PP_SECRET.length(), EVP_MD_size(md)); + break; + } + + this->_generate(km->key, &km->key_len, km->iv, &km->iv_len, hkdf, secret, secret_len, cipher); + + return km; } int -QUICKeyGenerator::_generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, HKDF &hkdf, const uint8_t *base_secret, size_t base_secret_len, const char *label, size_t label_len, const EVP_MD *md, const QUIC_EVP_CIPHER *cipher) +QUICKeyGenerator::_generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, HKDF &hkdf, const uint8_t *secret, + size_t secret_len, const QUIC_EVP_CIPHER *cipher) { - uint8_t secret[256]; - size_t secret_len = sizeof(secret); - hkdf.expand_label(secret, &secret_len, base_secret, base_secret_len, reinterpret_cast(label), label_len, "", 0, EVP_MD_size(md)); + // Generate a key and a IV + // key = HKDF-Expand-Label(S, "key", "", key_length) + // iv = HKDF-Expand-Label(S, "iv", "", iv_length) this->_generate_key(key, key_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); this->_generate_iv(iv, iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher)); @@ -93,13 +103,52 @@ QUICKeyGenerator::_generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t * } int -QUICKeyGenerator::_generate_key(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t key_length) const +QUICKeyGenerator::_generate_cleartext_secret(uint8_t *out, size_t *out_len, HKDF &hkdf, QUICConnectionId cid, const char *label, + size_t label_len, size_t length) +{ + uint8_t client_connection_id[8]; + size_t cid_len = 0; + uint8_t cleartext_secret[512]; + size_t cleartext_secret_len = sizeof(cleartext_secret); + + QUICTypeUtil::write_QUICConnectionId(cid, 8, client_connection_id, &cid_len); + if (hkdf.extract(cleartext_secret, &cleartext_secret_len, QUIC_VERSION_1_SALT, sizeof(QUIC_VERSION_1_SALT), client_connection_id, + 8) != 1) { + return -1; + } + + hkdf.expand_label(out, out_len, cleartext_secret, cleartext_secret_len, reinterpret_cast(label), label_len, "", 0, + length); + return 0; +} + +int +QUICKeyGenerator::_generate_pp_secret(uint8_t *out, size_t *out_len, HKDF &hkdf, SSL *ssl, const char *label, size_t label_len, + size_t length) +{ + uint8_t secret[512]; + size_t secret_len = length; + if (this->_last_secret_len == 0) { + SSL_export_keying_material(ssl, secret, secret_len, label, label_len, reinterpret_cast(""), 0, 1); + } else { + } + memcpy(this->_last_secret, secret, secret_len); + this->_last_secret_len = secret_len; + *out_len = length; + + return 0; +} + +int +QUICKeyGenerator::_generate_key(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, + size_t key_length) const { return hkdf.expand_label(out, out_len, secret, secret_len, LABEL_FOR_KEY.data(), LABEL_FOR_KEY.length(), "", 0, key_length); } int -QUICKeyGenerator::_generate_iv(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t iv_length) const +QUICKeyGenerator::_generate_iv(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, + size_t iv_length) const { return hkdf.expand_label(out, out_len, secret, secret_len, LABEL_FOR_IV.data(), LABEL_FOR_IV.length(), "", 0, iv_length); } diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index a8e8c326f46..31aa62281ef 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -36,18 +36,16 @@ struct KeyMaterial { // These constant sizes are not enough somehow // uint8_t key[EVP_MAX_KEY_LENGTH] = {0}; // uint8_t iv[EVP_MAX_IV_LENGTH] = {0}; - uint8_t key[512] = {0}; - uint8_t iv[512] = {0}; - size_t key_len = 512; - size_t iv_len = 512; + uint8_t key[512] = {0}; + uint8_t iv[512] = {0}; + size_t key_len = 512; + size_t iv_len = 512; }; class QUICKeyGenerator { public: - enum class Context { - SERVER, CLIENT - }; + enum class Context { SERVER, CLIENT }; QUICKeyGenerator(Context ctx) : _ctx(ctx) {} @@ -58,18 +56,29 @@ class QUICKeyGenerator /* * Generate a key and an IV for Packet Protection - * + * * On the first call, this generates a secret with the constatnt label and generate a key material with the secret. - * On the following call, this regenerates a new secret based on the last secret and genereate a new key material with the new secret. + * On the following call, this regenerates a new secret based on the last secret and genereate a new key material with the new + * secret. */ - std::unique_ptr generate(); + std::unique_ptr generate(SSL *ssl); private: Context _ctx = Context::SERVER; - int _generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, const EVP_MD *md, const QUIC_EVP_CIPHER *cipher); + + uint8_t _last_secret[256]; + size_t _last_secret_len = 0; + + int _generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, + const QUIC_EVP_CIPHER *cipher); + int _generate_cleartext_secret(uint8_t *out, size_t *out_len, HKDF &hkdf, QUICConnectionId cid, const char *label, + size_t label_len, size_t length); + int _generate_pp_secret(uint8_t *out, size_t *out_len, HKDF &hkdf, SSL *ssl, const char *label, size_t label_len, size_t length); int _generate_key(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t key_length) const; int _generate_iv(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t iv_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_cleartext() const; + const QUIC_EVP_CIPHER *_get_cipher_for_protected_packet(const SSL *ssl) const; + const EVP_MD *_get_handshake_digest(const SSL *ssl) const; }; diff --git a/iocore/net/quic/QUICKeyGenerator_openssl.cc b/iocore/net/quic/QUICKeyGenerator_openssl.cc index a7fb4ac8cb5..a70b996e24c 100644 --- a/iocore/net/quic/QUICKeyGenerator_openssl.cc +++ b/iocore/net/quic/QUICKeyGenerator_openssl.cc @@ -20,8 +20,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "ts/ink_assert.h" #include "QUICKeyGenerator.h" +#include + size_t QUICKeyGenerator::_get_key_len(const QUIC_EVP_CIPHER *cipher) const { @@ -39,3 +42,39 @@ QUICKeyGenerator::_get_cipher_for_cleartext() const { return EVP_aes_128_gcm(); } + +const QUIC_EVP_CIPHER * +QUICKeyGenerator::_get_cipher_for_protected_packet(const SSL *ssl) const +{ + switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { + case TLS1_3_CK_AES_128_GCM_SHA256: + return EVP_aes_128_gcm(); + case TLS1_3_CK_AES_256_GCM_SHA384: + return EVP_aes_256_gcm(); + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + return EVP_chacha20_poly1305(); + case TLS1_3_CK_AES_128_CCM_SHA256: + case TLS1_3_CK_AES_128_CCM_8_SHA256: + return EVP_aes_128_ccm(); + default: + ink_assert(false); + return nullptr; + } +} + +const EVP_MD * +QUICKeyGenerator::_get_handshake_digest(const SSL *ssl) const +{ + switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { + case TLS1_3_CK_AES_128_GCM_SHA256: + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + case TLS1_3_CK_AES_128_CCM_SHA256: + case TLS1_3_CK_AES_128_CCM_8_SHA256: + return EVP_sha256(); + case TLS1_3_CK_AES_256_GCM_SHA384: + return EVP_sha384(); + default: + ink_assert(false); + return nullptr; + } +} diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 2b5e87baace..2f62cc11541 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -270,7 +270,7 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICConnection } else if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { this->_key_phase = QUICKeyPhase::PHASE_1; } else { - ink_assert(false); + this->_key_phase = QUICKeyPhase::CLEARTEXT; } } @@ -611,7 +611,7 @@ QUICPacket::key_phase() const void QUICPacket::store(uint8_t *buf, size_t *len) const { - memcpy(buf + *len, this->payload(), this->payload_size()); + memcpy(buf, this->payload(), this->payload_size()); *len = this->payload_size(); } @@ -682,7 +682,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ // 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; + result = QUICPacketCreationResult::SUCCESS; break; case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: @@ -700,12 +700,12 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ case QUICPacketType::CLIENT_INITIAL: case QUICPacketType::CLIENT_CLEARTEXT: case QUICPacketType::SERVER_CLEARTEXT: - if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->length(), QUICKeyPhase::CLEARTEXT)) { - result = QUICPacketCreationResult::SUCCESS; - } else { - result = QUICPacketCreationResult::FAILED; - } + if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), + header->packet_number(), header->buf(), header->length(), QUICKeyPhase::CLEARTEXT)) { + result = QUICPacketCreationResult::SUCCESS; + } else { + result = QUICPacketCreationResult::FAILED; + } default: result = QUICPacketCreationResult::FAILED; break; diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 5a56349b389..b51d23415af 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -49,7 +49,7 @@ class QUICPacketHeader /* * Returns a pointer for the payload */ - virtual const uint8_t *payload() const = 0; + virtual const uint8_t *payload() const = 0; /* * Returns a payload size based on header length and buffer size that is specified to the constructo. @@ -59,12 +59,12 @@ class QUICPacketHeader /* * Returns a header size */ - virtual uint16_t length() const = 0; + virtual uint16_t length() const = 0; /* * Returns a key phase */ - virtual QUICKeyPhase key_phase() const = 0; + virtual QUICKeyPhase key_phase() const = 0; /* * Stores serialized header @@ -88,7 +88,6 @@ class QUICPacketHeader */ static QUICPacketHeader *load(const uint8_t *buf, size_t len, QUICPacketNumber base); - /* * Build a QUICPacketHeader * @@ -117,8 +116,8 @@ class QUICPacketHeader QUICPacketHeader(){}; // These two are used only if the instance was created with a buffer - const uint8_t *_buf = nullptr; - size_t _buf_len = 0; + const uint8_t *_buf = nullptr; + size_t _buf_len = 0; ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); QUICPacketType _type = QUICPacketType::UNINITIALIZED; @@ -187,7 +186,7 @@ class QUICPacket /* * Creates a QUICPacket with a QUICPacketHeader and a buffer that contains payload - * + * * QUICPacket class doesn't care about whether the payload is protected (encrypted) or not. */ QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len, QUICPacketNumber base_packet_number); diff --git a/iocore/net/quic/test/test_QUICCrypto.cc b/iocore/net/quic/test/test_QUICCrypto.cc index a3753088342..35479e1c328 100644 --- a/iocore/net/quic/test/test_QUICCrypto.cc +++ b/iocore/net/quic/test/test_QUICCrypto.cc @@ -103,6 +103,92 @@ print_hex(const uint8_t *v, size_t len) return; } +TEST_CASE("QUICCrypto Cleartext", "[quic]") +{ + // Client + SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); + QUICCrypto *client = new QUICCrypto(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + + // Server + SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); + BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); + SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); + BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); + SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); + QUICCrypto *server = new QUICCrypto(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + + // Client Hello + uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t client_hello_len = 0; + CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0)); + std::cout << "Client Hello" << std::endl; + print_hex(client_hello, client_hello_len); + + // Server Hello + uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t server_hello_len = 0; + CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len)); + std::cout << "Server Hello" << std::endl; + print_hex(server_hello, server_hello_len); + + // Client Fnished + uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t client_finished_len = 0; + CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len)); + std::cout << "Client Finished" << std::endl; + print_hex(client_finished, client_finished_len); + + // Post Handshake Msg + uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t post_handshake_msg_len = 0; + CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, client_finished_len)); + std::cout << "Post Handshake Message" << std::endl; + print_hex(post_handshake_msg, post_handshake_msg_len); + + CHECK(client->initialize_key_materials(0x8394c8f03e515708)); + CHECK(server->initialize_key_materials(0x8394c8f03e515708)); + + // encrypt - decrypt + uint8_t original[] = { + 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + uint64_t pkt_num = 0x123456789; + uint8_t ad[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + + // client (encrypt) - server (decrypt) + std::cout << "Original Text" << std::endl; + print_hex(original, sizeof(original)); + + uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead + size_t cipher_len = 0; + CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), + QUICKeyPhase::CLEARTEXT)); + + std::cout << "Encrypted Text" << std::endl; + print_hex(cipher, cipher_len); + + uint8_t plain[128] = {0}; + size_t plain_len = 0; + CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::CLEARTEXT)); + + std::cout << "Decrypted Text" << std::endl; + print_hex(plain, plain_len); + + CHECK(sizeof(original) == (plain_len)); + CHECK(memcmp(original, plain, plain_len) == 0); + + // Teardown + delete client; + delete server; +} + TEST_CASE("QUICCrypto 1-RTT", "[quic]") { // Client @@ -151,6 +237,8 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") CHECK(client->initialize_key_materials(0x8394c8f03e515708)); CHECK(server->initialize_key_materials(0x8394c8f03e515708)); + CHECK(client->update_key_materials()); + CHECK(server->update_key_materials()); // encrypt - decrypt uint8_t original[] = { diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index d8d122d4163..4a3396beba1 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -52,20 +52,14 @@ print_hex(const uint8_t *v, size_t len) TEST_CASE("QUICKeyGenerator", "[quic]") { - SECTION("CLIENT Cleartext") { QUICKeyGenerator keygen(QUICKeyGenerator::Context::CLIENT); - QUICConnectionId cid = 0x8394c8f03e515708; - uint8_t expected_client_key[] = { - 0x2e, 0xbd, 0x78, 0x00, 0xdb, 0xed, 0x20, 0x10, - 0xe5, 0xa2, 0x1c, 0x4a, 0xd2, 0x4b, 0x4e, 0xc3 - }; - uint8_t expected_client_iv[] = { - 0x55, 0x44, 0x0d, 0x5f, 0xf7, 0x50, 0x3d, 0xe4, - 0x99, 0x7b, 0xfd, 0x6b - }; + QUICConnectionId cid = 0x8394c8f03e515708; + uint8_t expected_client_key[] = {0x2e, 0xbd, 0x78, 0x00, 0xdb, 0xed, 0x20, 0x10, + 0xe5, 0xa2, 0x1c, 0x4a, 0xd2, 0x4b, 0x4e, 0xc3}; + uint8_t expected_client_iv[] = {0x55, 0x44, 0x0d, 0x5f, 0xf7, 0x50, 0x3d, 0xe4, 0x99, 0x7b, 0xfd, 0x6b}; std::unique_ptr actual_km = keygen.generate(cid); @@ -79,15 +73,10 @@ TEST_CASE("QUICKeyGenerator", "[quic]") { QUICKeyGenerator keygen(QUICKeyGenerator::Context::SERVER); - QUICConnectionId cid = 0x8394c8f03e515708; - uint8_t expected_server_key[] = { - 0xc8, 0xea, 0x1b, 0xc1, 0x71, 0xe5, 0x2b, 0xae, - 0x71, 0xfb, 0x78, 0x39, 0x52, 0xc7, 0xb8, 0xfc - }; - uint8_t expected_server_iv[] = { - 0x57, 0x82, 0x3b, 0x85, 0x2c, 0x7e, 0xf9, 0xe3, - 0x80, 0x2b, 0x69, 0x0b - }; + QUICConnectionId cid = 0x8394c8f03e515708; + uint8_t expected_server_key[] = {0xc8, 0xea, 0x1b, 0xc1, 0x71, 0xe5, 0x2b, 0xae, + 0x71, 0xfb, 0x78, 0x39, 0x52, 0xc7, 0xb8, 0xfc}; + uint8_t expected_server_iv[] = {0x57, 0x82, 0x3b, 0x85, 0x2c, 0x7e, 0xf9, 0xe3, 0x80, 0x2b, 0x69, 0x0b}; std::unique_ptr actual_km = keygen.generate(cid); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 46ddb629be8..60b35a2d947 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -30,32 +30,32 @@ TEST_CASE("QUICPacketHeader", "[quic]") SECTION("Long Header") { const uint8_t input[] = { - 0x81, // Long header, Type - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Connection ID - 0x12, 0x34, 0x56, 0x78, // Packet number - 0x11, 0x22, 0x33, 0x44, // Version - 0xff, 0xff, // Payload (dummy) + 0x81, // Long header, Type + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID + 0x12, 0x34, 0x56, 0x78, // Packet number + 0x11, 0x22, 0x33, 0x44, // Version + 0xff, 0xff, // Payload (dummy) }; QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); - CHECK(header->connection_id() == 0x01020304050607); - CHECK(header->packet_number() == 0); + CHECK(header->connection_id() == 0x0102030405060708); + CHECK(header->packet_number() == 0x12345678); CHECK(header->version() == 0x11223344); } SECTION("Short Header") { const uint8_t input[] = { - 0x41, // Short header, with Connection ID, KeyPhse 0, Type - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Connection ID - 0x12, 0x34, 0x56, 0x78, // Packet number - 0xff, 0xff, // Payload (dummy) + 0x43, // Short header, with Connection ID, KeyPhse 0, Type + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID + 0x12, 0x34, 0x56, 0x78, // Packet number + 0xff, 0xff, // Payload (dummy) }; QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); - CHECK(header->connection_id() == 0x01020304050607); - CHECK(header->packet_number() == 0); + CHECK(header->connection_id() == 0x0102030405060708); + CHECK(header->packet_number() == 0x12345678); } } diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 06d12c9cd97..7a63fca96fb 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -36,11 +36,11 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0xaa, 0xbb, 0xcc, 0xdd, // Version }; uint8_t client_initial_packet_payload[] = { - 0x00 // Payload + 0x00 // Payload }; QUICPacketHeader *header = QUICPacketHeader::load(client_initial_packet_header, sizeof(client_initial_packet_header), 0); - QUICPacket client_initial_packet(header, ats_unique_buf(client_initial_packet_payload, [](void *p) { ats_free(p); }), + QUICPacket client_initial_packet(header, ats_unique_buf(client_initial_packet_payload, [](void *) {}), sizeof(client_initial_packet_payload), 0); QUICPacketUPtr packet = factory.create_version_negotiation_packet(&client_initial_packet, 0); @@ -86,8 +86,4 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") CHECK(packet->type() == QUICPacketType::STATELESS_RESET); CHECK(packet->connection_id() == 0x01020304); CHECK(packet->packet_number() == token.get_u8()[0]); - CHECK(memcmp(packet->payload(), token.get_u8() + 1, 15) == 0); - packet->store(output, &out_len); - CHECK(memcmp(output, expected_output, 25) == 0); - CHECK(out_len > 25); // Check existence of random bytes at the end } diff --git a/lib/ts/HKDF.cc b/lib/ts/HKDF.cc index 6da55c41a57..91f5b94860d 100644 --- a/lib/ts/HKDF.cc +++ b/lib/ts/HKDF.cc @@ -36,9 +36,11 @@ HKDF::expand_label(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t hkdf_label[1] = length & 0xFF; hkdf_label_len += 2; // "tls13 " + Label - hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%ctls13 %.*s", static_cast(6 + label_len), static_cast(label_len), label); + hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%ctls13 %.*s", static_cast(6 + label_len), + static_cast(label_len), label); // Hash Value - hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%c%.*s", static_cast(hash_value_len), static_cast(hash_value_len), hash_value); + hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%c%.*s", static_cast(hash_value_len), + static_cast(hash_value_len), hash_value); this->expand(dst, dst_len, secret, secret_len, hkdf_label, hkdf_label_len, length); return 1; From 3fac60a83568d2ba00c2b71b1cde7a4790b05442 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 20 Nov 2017 22:57:22 +0900 Subject: [PATCH 0179/1313] Add a check for kdf.h and hkdf.h --- build/crypto.m4 | 11 +++++++++++ configure.ac | 4 ++++ lib/ts/Makefile.am | 22 +++++++++++++--------- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/build/crypto.m4 b/build/crypto.m4 index 0405671e580..e9f8cf7b7a0 100644 --- a/build/crypto.m4 +++ b/build/crypto.m4 @@ -231,6 +231,17 @@ AC_DEFUN([TS_CHECK_CRYPTO_DH_GET_2048_256], [ AC_SUBST(use_dh_get_2048_256) ]) +AC_DEFUN([TS_CHECK_CRYPTO_HKDF], [ + enable_hkdf=yes + AC_CHECK_HEADERS([openssl/kdf.h openssl/hkdf.h], [ + break + ], [ + enable_hkdf=no + ]) + TS_ARG_ENABLE_VAR([use], [hkdf]) + AC_SUBST(use_hkdf) +]) + AC_DEFUN([TS_CHECK_CRYPTO_TLS13], [ enable_tls13=yes _tls13_saved_LIBS=$LIBS diff --git a/configure.ac b/configure.ac index 4bfaea23e95..f5e5ca4a0ae 100644 --- a/configure.ac +++ b/configure.ac @@ -1137,6 +1137,10 @@ TS_CHECK_CRYPTO_SET_RBIO # Check for DH_get_2048_256 TS_CHECK_CRYPTO_DH_GET_2048_256 +# Check for HKDF support +TS_CHECK_CRYPTO_HKDF +AM_CONDITIONAL([HAS_HKDF], [test "x$enable_hkdf" = "xyes"]) + # Check for TLS 1.3 support TS_CHECK_CRYPTO_TLS13 diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am index 50626444074..370bf55e16b 100644 --- a/lib/ts/Makefile.am +++ b/lib/ts/Makefile.am @@ -44,12 +44,6 @@ libtsutil_la_LIBADD = \ @LIBCAP@ \ -lc -if OPENSSL_IS_BORINGSSL -HKDF_impl = HKDF_boringssl.cc -else -HKDF_impl = HKDF_openssl.cc -endif - libtsutil_la_SOURCES = \ Allocator.h \ Arena.cc \ @@ -79,9 +73,6 @@ libtsutil_la_SOURCES = \ HashSip.cc \ HashSip.h \ History.h \ - HKDF.h \ - HKDF.cc \ - $(HKDF_impl) \ HostLookup.cc \ HostLookup.h \ hugepages.cc \ @@ -209,6 +200,19 @@ libtsutil_la_SOURCES = \ X509HostnameValidator.cc \ X509HostnameValidator.h +if HAS_HKDF +if OPENSSL_IS_BORINGSSL +HKDF_impl = HKDF_boringssl.cc +else +HKDF_impl = HKDF_openssl.cc +endif +libtsutil_la_SOURCES += \ + HKDF.h \ + HKDF.cc \ + $(HKDF_impl) +endif + + #test_UNUSED_SOURCES = \ # load_http_hdr.cc \ # IntrusivePtrTest.cc \ From e9c499b297487f96e9526e5e3ebced8c1bb93fd2 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 21 Nov 2017 00:36:21 +0900 Subject: [PATCH 0180/1313] Make the check for HKDF support more strict --- build/crypto.m4 | 30 +++++++++++++++++++++++++----- lib/ts/Makefile.am | 6 +++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/build/crypto.m4 b/build/crypto.m4 index e9f8cf7b7a0..dc05e591f8a 100644 --- a/build/crypto.m4 +++ b/build/crypto.m4 @@ -232,12 +232,32 @@ AC_DEFUN([TS_CHECK_CRYPTO_DH_GET_2048_256], [ ]) AC_DEFUN([TS_CHECK_CRYPTO_HKDF], [ - enable_hkdf=yes - AC_CHECK_HEADERS([openssl/kdf.h openssl/hkdf.h], [ - break - ], [ - enable_hkdf=no + enable_hkdf=no + _hkdf_saved_LIBS=$LIBS + TS_ADDTO(LIBS, [$OPENSSL_LIBS]) + AC_MSG_CHECKING([for EVP_PKEY_CTX_hkdf_mode]) + AC_LINK_IFELSE( + [ + AC_LANG_PROGRAM([[ +#include + ]], + [[ +#ifndef EVP_PKEY_CTX_hkdf_mode +# error no EVP_PKEY_CTX_hkdf_mode support +#endif + ]]) + ], + [ + AC_MSG_RESULT([yes]) + enable_hkdf=yes + ], + [ + AC_MSG_RESULT([no]) ]) + AC_CHECK_FUNC(HKDF_extract, [ + enable_hkdf=yes + ], []) + LIBS=$_hkdf_saved_LIBS TS_ARG_ENABLE_VAR([use], [hkdf]) AC_SUBST(use_hkdf) ]) diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am index 370bf55e16b..55514ded607 100644 --- a/lib/ts/Makefile.am +++ b/lib/ts/Makefile.am @@ -272,8 +272,12 @@ test_tslib_SOURCES = \ unit-tests/test_IpMap.cc \ unit-tests/test_layout.cc \ unit-tests/test_string_view.cc \ - unit-tests/test_TextView.cc \ + unit-tests/test_TextView.cc + +if HAS_HKDF +test_tslib_SOURCES += \ unit-tests/test_HKDF.cc +endif CompileParseRules_SOURCES = CompileParseRules.cc From 0173ca9d97b49f61c87a17b9bf57d40500798074 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 21 Nov 2017 15:17:30 +0900 Subject: [PATCH 0181/1313] Fix cleartext packet protection --- iocore/net/P_QUICNetVConnection.h | 4 +- iocore/net/QUICNetVConnection.cc | 19 ++- iocore/net/QUICPacketHandler.cc | 2 +- iocore/net/quic/Mock.h | 52 ++++++++ iocore/net/quic/QUICAckFrameCreator.cc | 1 + iocore/net/quic/QUICCongestionController.cc | 1 + iocore/net/quic/QUICConnection.h | 5 +- iocore/net/quic/QUICCrypto.cc | 26 ++-- iocore/net/quic/QUICCrypto.h | 68 ++-------- iocore/net/quic/QUICCryptoTls.h | 86 +++++++++++++ iocore/net/quic/QUICCrypto_boringssl.cc | 28 ++-- iocore/net/quic/QUICCrypto_openssl.cc | 18 +-- iocore/net/quic/QUICHandshake.cc | 11 +- iocore/net/quic/QUICPacket.cc | 121 ++++++++++-------- iocore/net/quic/QUICPacket.h | 17 ++- iocore/net/quic/QUICPacketTransmitter.h | 1 + iocore/net/quic/QUICTypes.h | 2 +- iocore/net/quic/test/test_QUICCrypto.cc | 10 +- iocore/net/quic/test/test_QUICLossDetector.cc | 7 +- .../net/quic/test/test_QUICPacketFactory.cc | 9 +- .../quic/test/test_QUICVersionNegotiator.cc | 2 + 21 files changed, 318 insertions(+), 172 deletions(-) create mode 100644 iocore/net/quic/QUICCryptoTls.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index b59bc035649..bba69ad2fa0 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -134,7 +134,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection public: QUICNetVConnection() {} - void init(UDPConnection *, QUICPacketHandler *); + void init(QUICConnectionId cid, UDPConnection *, QUICPacketHandler *); // UnixNetVConnection void reenable(VIO *vio) override; @@ -163,6 +163,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection bool is_closed(); // QUICConnection + QUICConnectionId original_connection_id() override; QUICConnectionId connection_id() override; uint32_t maximum_quic_packet_size() override; uint32_t minimum_quic_packet_size() override; @@ -189,6 +190,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection private: std::random_device _rnd; + QUICConnectionId _original_quic_connection_id; QUICConnectionId _quic_connection_id; QUICPacketNumber _largest_received_packet_number = 0; UDPConnection *_udp_con = nullptr; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 7c7db3a3cba..cc226fa208d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -46,7 +46,7 @@ #define DebugQUICCon(fmt, ...) \ Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) -static constexpr uint32_t MAX_PACKET_OVERHEAD = 25; // Max long header len(17) + FNV-1a hash len(8) +static constexpr uint32_t MAX_PACKET_OVERHEAD = 17; // Max long header len(17) static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; static constexpr uint32_t MINIMUM_INITIAL_CLIENT_PACKET_SIZE = 1200; @@ -54,13 +54,14 @@ ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); // XXX This might be called on ET_UDP thread void -QUICNetVConnection::init(UDPConnection *udp_con, QUICPacketHandler *packet_handler) +QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, QUICPacketHandler *packet_handler) { SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_pre_handshake); - this->_packet_transmitter_mutex = new_ProxyMutex(); - this->_frame_transmitter_mutex = new_ProxyMutex(); - this->_udp_con = udp_con; - this->_packet_handler = packet_handler; + this->_packet_transmitter_mutex = new_ProxyMutex(); + this->_frame_transmitter_mutex = new_ProxyMutex(); + this->_udp_con = udp_con; + this->_packet_handler = packet_handler; + this->_original_quic_connection_id = original_cid; this->_quic_connection_id.randomize(); } @@ -151,6 +152,12 @@ QUICNetVConnection::reenable(VIO *vio) return; } +QUICConnectionId +QUICNetVConnection::original_connection_id() +{ + return this->_original_quic_connection_id; +} + QUICConnectionId QUICNetVConnection::connection_id() { diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index aff1f87e323..8dc81044ddf 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -149,7 +149,7 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) // Create a new NetVConnection vc = static_cast(getNetProcessor()->allocate_vc(((UnixUDPConnection *)udpPacket->getConnection())->ethread)); - vc->init(udpPacket->getConnection(), this); + vc->init(cid, udpPacket->getConnection(), this); vc->id = net_next_connection_number(); vc->con.move(con); vc->submit_time = Thread::get_hrtime(); diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 22ba21d1857..3050a435f28 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -151,6 +151,12 @@ class MockQUICConnection : public QUICConnection return 0; } + QUICConnectionId + original_connection_id() override + { + return 0; + } + void transmit_packet(QUICPacketUPtr packet) override { @@ -393,6 +399,52 @@ class MockQUICApplication : public QUICApplication } }; +class MockQUICCrypto : public QUICCrypto +{ +public: + MockQUICCrypto() : QUICCrypto() {} + + bool + handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override + { + return true; + } + + bool + is_handshake_finished() const override + { + return true; + } + + int + initialize_key_materials(QUICConnectionId cid) override + { + return 0; + } + + int + update_key_materials() override + { + return 0; + } + + bool + encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, + const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override + { + memcpy(cipher, plain, plain_len); + return true; + } + + bool + decrypt(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, QUICKeyPhase phase) const override + { + memcpy(plain, cipher, cipher_len); + return true; + } +}; + void NetVConnection::cancel_OOB(){}; Action * NetVConnection::send_OOB(Continuation *, char *, int) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index e3988f721dd..f352d83a391 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -21,6 +21,7 @@ * limitations under the License. */ +#include "I_EventSystem.h" #include "QUICAckFrameCreator.h" #include diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 4a0ea79a815..d06902b5a32 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -21,6 +21,7 @@ * limitations under the License. */ +#include #include static constexpr char tag[] = "quic_congestion_controller"; diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 93634ad3eea..e236c82bf70 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -23,6 +23,8 @@ #pragma once +#include "I_EventSystem.h" +#include "I_NetVConnection.h" #include "QUICPacketTransmitter.h" #include "QUICFrameTransmitter.h" #include "QUICFrameHandler.h" @@ -35,7 +37,8 @@ class SSLNextProtocolSet; class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler { public: - virtual QUICConnectionId connection_id() = 0; + virtual QUICConnectionId original_connection_id() = 0; + virtual QUICConnectionId connection_id() = 0; /* * Retruns the maximum packet size at the time called diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index cfe9d4b0052..9041ad5622e 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -21,7 +21,7 @@ * limitations under the License. */ #include "QUICGlobals.h" -#include "QUICCrypto.h" +#include "QUICCryptoTls.h" #include #include @@ -84,7 +84,7 @@ QUICPacketProtection::key_phase() const // // QUICCrypto // -QUICCrypto::QUICCrypto(SSL *ssl, NetVConnectionContext_t nvc_ctx) : _ssl(ssl), _netvc_context(nvc_ctx) +QUICCryptoTls::QUICCryptoTls(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICCrypto(), _ssl(ssl), _netvc_context(nvc_ctx) { if (this->_netvc_context == NET_VCONNECTION_IN) { SSL_set_accept_state(this->_ssl); @@ -98,14 +98,14 @@ QUICCrypto::QUICCrypto(SSL *ssl, NetVConnectionContext_t nvc_ctx) : _ssl(ssl), _ this->_server_pp = new QUICPacketProtection(); } -QUICCrypto::~QUICCrypto() +QUICCryptoTls::~QUICCryptoTls() { delete this->_client_pp; delete this->_server_pp; } bool -QUICCrypto::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) +QUICCryptoTls::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) { ink_assert(this->_ssl != nullptr); @@ -153,13 +153,13 @@ QUICCrypto::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const u } bool -QUICCrypto::is_handshake_finished() const +QUICCryptoTls::is_handshake_finished() const { return SSL_is_init_finished(this->_ssl); } int -QUICCrypto::initialize_key_materials(QUICConnectionId cid) +QUICCryptoTls::initialize_key_materials(QUICConnectionId cid) { // Generate keys std::unique_ptr km; @@ -175,7 +175,7 @@ QUICCrypto::initialize_key_materials(QUICConnectionId cid) } int -QUICCrypto::update_key_materials() +QUICCryptoTls::update_key_materials() { ink_assert(this->is_handshake_finished()); // Switch key phase @@ -206,14 +206,14 @@ QUICCrypto::update_key_materials() } SSL * -QUICCrypto::ssl_handle() +QUICCryptoTls::ssl_handle() { return this->_ssl; } bool -QUICCrypto::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const +QUICCryptoTls::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const { QUICPacketProtection *pp = nullptr; @@ -236,8 +236,8 @@ QUICCrypto::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, } bool -QUICCrypto::decrypt(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, QUICKeyPhase phase) const +QUICCryptoTls::decrypt(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, QUICKeyPhase phase) const { QUICPacketProtection *pp = nullptr; @@ -274,7 +274,7 @@ QUICCrypto::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, con * */ void -QUICCrypto::_gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const +QUICCryptoTls::_gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const { nonce_len = iv_len; memcpy(nonce, iv, iv_len); diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICCrypto.h index 62f6db8e204..5c57083d59e 100644 --- a/iocore/net/quic/QUICCrypto.h +++ b/iocore/net/quic/QUICCrypto.h @@ -24,17 +24,6 @@ #pragma once #include "QUICKeyGenerator.h" -#include - -#ifdef OPENSSL_IS_BORINGSSL -#include -#include -#else -#include -#endif - -#include "I_EventSystem.h" -#include "I_NetVConnection.h" #include "QUICTypes.h" class QUICPacketProtection @@ -56,50 +45,15 @@ class QUICPacketProtection class QUICCrypto { public: - QUICCrypto(SSL *, NetVConnectionContext_t); - virtual ~QUICCrypto(); - - bool handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len); - bool is_handshake_finished() const; - int initialize_key_materials(QUICConnectionId cid); - int update_key_materials(); - bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, - const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const; - bool decrypt(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, QUICKeyPhase phase) const; - int update_client_keymaterial(); - int update_server_keymaterial(); - - // FIXME SSL handle should not be exported - SSL *ssl_handle(); - -private: - QUICKeyGenerator _keygen_for_client = QUICKeyGenerator(QUICKeyGenerator::Context::CLIENT); - QUICKeyGenerator _keygen_for_server = QUICKeyGenerator(QUICKeyGenerator::Context::SERVER); - void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; -#ifdef OPENSSL_IS_BORINGSSL - const EVP_AEAD *_get_evp_aead() const; - size_t _get_aead_key_len(const EVP_AEAD *aead) const; - size_t _get_aead_nonce_len(const EVP_AEAD *aead) const; -#else - const EVP_CIPHER *_get_evp_aead() const; - size_t _get_aead_key_len(const EVP_CIPHER *aead) const; - size_t _get_aead_nonce_len(const EVP_CIPHER *aead) const; -#endif // OPENSSL_IS_BORINGSSL - size_t _get_aead_tag_len() const; - - bool _encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const; - bool _decrypt(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 KeyMaterial &km, size_t tag_len) const; - - SSL *_ssl = nullptr; -#ifdef OPENSSL_IS_BORINGSSL - const EVP_AEAD *_aead = nullptr; -#else - const EVP_CIPHER *_aead = nullptr; -#endif // OPENSSL_IS_BORINGSSL - QUICPacketProtection *_client_pp = nullptr; - QUICPacketProtection *_server_pp = nullptr; - NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; + QUICCrypto(){}; + virtual ~QUICCrypto(){}; + + virtual bool handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) = 0; + virtual bool is_handshake_finished() const = 0; + virtual int initialize_key_materials(QUICConnectionId cid) = 0; + virtual int update_key_materials() = 0; + virtual bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; + virtual bool decrypt(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, QUICKeyPhase phase) const = 0; }; diff --git a/iocore/net/quic/QUICCryptoTls.h b/iocore/net/quic/QUICCryptoTls.h new file mode 100644 index 00000000000..0e4179360d0 --- /dev/null +++ b/iocore/net/quic/QUICCryptoTls.h @@ -0,0 +1,86 @@ +/** @file + * + * QUIC TLS + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#ifdef OPENSSL_IS_BORINGSSL +#include +#include +#else +#include +#endif + +#include "I_EventSystem.h" +#include "I_NetVConnection.h" +#include "QUICCrypto.h" + +class QUICCryptoTls : public QUICCrypto +{ +public: + QUICCryptoTls(SSL *ssl, NetVConnectionContext_t nvc_ctx); + ~QUICCryptoTls(); + + bool handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override; + bool is_handshake_finished() const override; + int initialize_key_materials(QUICConnectionId cid) override; + int update_key_materials() override; + bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, + const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override; + bool decrypt(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, QUICKeyPhase phase) const override; + + // FIXME SSL handle should not be exported + SSL *ssl_handle(); + +private: + QUICKeyGenerator _keygen_for_client = QUICKeyGenerator(QUICKeyGenerator::Context::CLIENT); + QUICKeyGenerator _keygen_for_server = QUICKeyGenerator(QUICKeyGenerator::Context::SERVER); + void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; +#ifdef OPENSSL_IS_BORINGSSL + const EVP_AEAD *_get_evp_aead() const; + size_t _get_aead_key_len(const EVP_AEAD *aead) const; + size_t _get_aead_nonce_len(const EVP_AEAD *aead) const; +#else + const EVP_CIPHER *_get_evp_aead() const; + size_t _get_aead_key_len(const EVP_CIPHER *aead) const; + size_t _get_aead_nonce_len(const EVP_CIPHER *aead) const; +#endif // OPENSSL_IS_BORINGSSL + size_t _get_aead_tag_len() const; + + bool _encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const; + bool _decrypt(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 KeyMaterial &km, size_t tag_len) const; + + SSL *_ssl = nullptr; +#ifdef OPENSSL_IS_BORINGSSL + const EVP_AEAD *_aead = nullptr; +#else + const EVP_CIPHER *_aead = nullptr; +#endif // OPENSSL_IS_BORINGSSL + QUICPacketProtection *_client_pp = nullptr; + QUICPacketProtection *_server_pp = nullptr; + NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; +}; diff --git a/iocore/net/quic/QUICCrypto_boringssl.cc b/iocore/net/quic/QUICCrypto_boringssl.cc index 6b50b6b6414..0d9ff5b2bb2 100644 --- a/iocore/net/quic/QUICCrypto_boringssl.cc +++ b/iocore/net/quic/QUICCrypto_boringssl.cc @@ -20,7 +20,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "QUICCrypto.h" +#include "QUICCryptoTls.h" #include #include @@ -32,7 +32,7 @@ static constexpr char tag[] = "quic_crypto"; const EVP_AEAD * -QUICCrypto::_get_evp_aead(const SSL_CIPHER *cipher) const +QUICCryptoTls::_get_evp_aead(const SSL_CIPHER *cipher) const { ink_assert(SSL_CIPHER_is_AEAD(cipher)); @@ -51,7 +51,7 @@ QUICCrypto::_get_evp_aead(const SSL_CIPHER *cipher) const // SSL_HANDSHAKE_MAC_SHA256, SSL_HANDSHAKE_MAC_SHA384 are defind in `ssl/internal.h` of BoringSSL const EVP_MD * -QUICCrypto::_get_handshake_digest(const SSL_CIPHER *cipher) const +QUICCryptoTls::_get_handshake_digest(const SSL_CIPHER *cipher) const { switch (cipher->algorithm_prf) { case 0x2: @@ -66,26 +66,26 @@ QUICCrypto::_get_handshake_digest(const SSL_CIPHER *cipher) const } size_t -QUICCrypto::_get_aead_tag_len(const SSL_CIPHER * /* cipher */) const +QUICCryptoTls::_get_aead_tag_len(const SSL_CIPHER * /* cipher */) const { return EVP_AEAD_DEFAULT_TAG_LENGTH; } size_t -QUICCrypto::_get_aead_key_len(const EVP_AEAD *aead) const +QUICCryptoTls::_get_aead_key_len(const EVP_AEAD *aead) const { return EVP_AEAD_key_length(aead); } size_t -QUICCrypto::_get_aead_nonce_len(const EVP_AEAD *aead) const +QUICCryptoTls::_get_aead_nonce_len(const EVP_AEAD *aead) const { return EVP_AEAD_nonce_length(aead); } int -QUICCrypto::_hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, - size_t label_len, const EVP_MD *digest) const +QUICCryptoTls::_hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, + size_t label_len, const EVP_MD *digest) const { uint8_t info[256] = {0}; size_t info_len = 0; @@ -94,9 +94,9 @@ QUICCrypto::_hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *secr } bool -QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, - size_t iv_len, size_t tag_len) const +QUICCryptoTls::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, + size_t iv_len, size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; @@ -119,9 +119,9 @@ QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, } bool -QUICCrypto::_decrypt(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, size_t key_len, const uint8_t *iv, - size_t iv_len, size_t tag_len) const +QUICCryptoTls::_decrypt(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, size_t key_len, const uint8_t *iv, + size_t iv_len, size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; diff --git a/iocore/net/quic/QUICCrypto_openssl.cc b/iocore/net/quic/QUICCrypto_openssl.cc index e62a5ef69b5..b216ae1f981 100644 --- a/iocore/net/quic/QUICCrypto_openssl.cc +++ b/iocore/net/quic/QUICCrypto_openssl.cc @@ -20,7 +20,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "QUICCrypto.h" +#include "QUICCryptoTls.h" #include #include @@ -31,7 +31,7 @@ static constexpr char tag[] = "quic_crypto"; const EVP_CIPHER * -QUICCrypto::_get_evp_aead() const +QUICCryptoTls::_get_evp_aead() const { if (this->is_handshake_finished()) { switch (SSL_CIPHER_get_id(SSL_get_current_cipher(this->_ssl))) { @@ -54,7 +54,7 @@ QUICCrypto::_get_evp_aead() const } size_t -QUICCrypto::_get_aead_tag_len() const +QUICCryptoTls::_get_aead_tag_len() const { if (this->is_handshake_finished()) { switch (SSL_CIPHER_get_id(SSL_get_current_cipher(this->_ssl))) { @@ -77,20 +77,20 @@ QUICCrypto::_get_aead_tag_len() const } size_t -QUICCrypto::_get_aead_key_len(const EVP_CIPHER *aead) const +QUICCryptoTls::_get_aead_key_len(const EVP_CIPHER *aead) const { return EVP_CIPHER_key_length(aead); } size_t -QUICCrypto::_get_aead_nonce_len(const EVP_CIPHER *aead) const +QUICCryptoTls::_get_aead_nonce_len(const EVP_CIPHER *aead) const { return EVP_CIPHER_iv_length(aead); } bool -QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const +QUICCryptoTls::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; @@ -138,8 +138,8 @@ QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, } bool -QUICCrypto::_decrypt(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 KeyMaterial &km, size_t tag_len) const +QUICCryptoTls::_decrypt(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 KeyMaterial &km, size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index c33f3b6a93c..faf2c1c6203 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -23,6 +23,7 @@ #include "QUICGlobals.h" #include "QUICHandshake.h" +#include "QUICCryptoTls.h" #include #include "QUICVersionNegotiator.h" @@ -86,10 +87,10 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless this->_ssl = SSL_new(ssl_ctx); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_hs_index, this); - this->_crypto = new QUICCrypto(this->_ssl, qc->direction()); + this->_crypto = new QUICCryptoTls(this->_ssl, qc->direction()); this->_version_negotiator = new QUICVersionNegotiator(); - this->_crypto->initialize_key_materials(this->_client_qc->connection_id()); + this->_crypto->initialize_key_materials(this->_client_qc->original_connection_id()); this->_load_local_transport_parameters(); SET_HANDLER(&QUICHandshake::state_read_client_hello); @@ -151,7 +152,11 @@ QUICHandshake::crypto_module() void QUICHandshake::negotiated_application_name(const uint8_t **name, unsigned int *len) { - SSL_get0_alpn_selected(this->_crypto->ssl_handle(), name, len); + // FIXME Generalize and remove dynamic_cast + QUICCryptoTls *crypto_tls = dynamic_cast(this->_crypto); + if (crypto_tls) { + SSL_get0_alpn_selected(crypto_tls->ssl_handle(), name, len); + } } void diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 2f62cc11541..35e55d4e8d7 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -22,6 +22,7 @@ */ #include +#include #include "QUICPacket.h" ClassAllocator quicPacketAllocator("quicPacketAllocator"); @@ -33,7 +34,6 @@ static constexpr int OFFSET_PACKET_NUMBER = 9; static constexpr int OFFSET_VERSION = 13; static constexpr int OFFSET_PAYLOAD = 17; static constexpr int LONGHEADER_LENGTH = 17; -static constexpr int FNV1A_HASH_LEN = 8; // // QUICPacketHeader @@ -41,7 +41,14 @@ static constexpr int FNV1A_HASH_LEN = 8; const uint8_t * QUICPacketHeader::buf() { - return this->_buf; + if (this->_buf) { + return this->_buf; + } else { + // TODO Reuse serialzied data if nothing has changed + size_t dummy; + this->store(this->_serialized, &dummy); + return this->_serialized; + } } QUICPacketHeader * @@ -199,7 +206,8 @@ QUICPacketLongHeader::has_key_phase() const QUICKeyPhase QUICPacketLongHeader::key_phase() const { - return QUICKeyPhase::PHASE_0; + // TODO LongHeader will also be used for 0-RTT packets + return QUICKeyPhase::CLEARTEXT; } uint16_t @@ -458,36 +466,25 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const // QUICPacket // -QUICPacket::QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len, QUICPacketNumber base_packet_number) +QUICPacket::QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len) { this->_header = header; - this->_size = this->_header->length() + payload_len; this->_payload = std::move(payload); this->_payload_size = payload_len; } -QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len, - bool retransmittable) +QUICPacket::QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len, bool retransmittable) { - this->_header = QUICPacketHeader::build(type, connection_id, packet_number, base_packet_number, version, std::move(payload), len); - this->_size = this->_header->length() + len; - if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && - type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { - this->_size += FNV1A_HASH_LEN; - } + this->_header = header; + this->_payload = std::move(payload); + this->_payload_size = payload_len; this->_is_retransmittable = retransmittable; } QUICPacket::QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - this->_header = QUICPacketHeader::build(type, packet_number, base_packet_number, std::move(payload), len); - this->_size = this->_header->length() + len; - if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && - type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { - this->_size += FNV1A_HASH_LEN; - } + this->_header = QUICPacketHeader::build(type, packet_number, base_packet_number, std::move(payload), len); this->_is_retransmittable = retransmittable; } @@ -495,11 +492,6 @@ QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUIC QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { this->_header = QUICPacketHeader::build(type, connection_id, packet_number, base_packet_number, std::move(payload), len); - this->_size = this->_header->length() + len; - if (type != QUICPacketType::ZERO_RTT_PROTECTED && type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && - type != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { - this->_size += FNV1A_HASH_LEN; - } this->_is_retransmittable = retransmittable; } @@ -515,10 +507,9 @@ QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUIC for (int i = 15; i < 23; ++i) { fake_payload.get()[i] = rnd() & 0xFF; } - + // TODO stateless packet format changed this->_header = QUICPacketHeader::build(type, connection_id, fake_packet_number, fake_base_packet_number, std::move(fake_payload), 15 + 8); - this->_size = this->_header->length() + 15 + 8; this->_is_retransmittable = false; } @@ -562,7 +553,7 @@ QUICPacket::header() const const uint8_t * QUICPacket::payload() const { - return this->_header->payload(); + return this->_payload.get(); } QUICVersion @@ -580,7 +571,7 @@ QUICPacket::is_retransmittable() const uint16_t QUICPacket::size() const { - return this->_size; + return this->header_size() + this->payload_size(); } uint16_t @@ -592,14 +583,7 @@ QUICPacket::header_size() const uint16_t QUICPacket::payload_size() const { - if (this->type() == QUICPacketType::STATELESS_RESET) { - return this->_size - this->_header->length(); - } else if (this->type() != QUICPacketType::ZERO_RTT_PROTECTED && this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 && - this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { - return this->_size - this->_header->length() - FNV1A_HASH_LEN; - } else { - return this->_size - this->_header->length(); - } + return this->_payload_size; } QUICKeyPhase @@ -611,8 +595,9 @@ QUICPacket::key_phase() const void QUICPacket::store(uint8_t *buf, size_t *len) const { - memcpy(buf, this->payload(), this->payload_size()); - *len = this->payload_size(); + memcpy(buf, this->_header->buf(), this->_header->length()); + memcpy(buf + this->_header->length(), this->payload(), this->payload_size()); + *len = this->_header->length() + this->payload_size(); } uint8_t @@ -706,6 +691,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ } else { result = QUICPacketCreationResult::FAILED; } + break; default: result = QUICPacketCreationResult::FAILED; break; @@ -714,7 +700,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ QUICPacket *packet = nullptr; if (result == QUICPacketCreationResult::SUCCESS) { packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(header, std::move(plain_txt), plain_txt_len, base_packet_number); + new (packet) QUICPacket(header, std::move(plain_txt), plain_txt_len); } return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); @@ -723,6 +709,10 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ QUICPacketUPtr QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number) { + size_t max_cipher_txt_len = 2048; + ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); + size_t cipher_txt_len = 0; + size_t len = sizeof(QUICVersion) * countof(QUIC_SUPPORTED_VERSIONS); ats_unique_buf versions(reinterpret_cast(ats_malloc(len)), [](void *p) { ats_free(p); }); uint8_t *p = versions.get(); @@ -733,10 +723,16 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se p += n; } - QUICPacket *packet = quicPacketAllocator.alloc(); - new (packet) - QUICPacket(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), packet_sent_by_client->packet_number(), - base_packet_number, packet_sent_by_client->version(), std::move(versions), len, false); + QUICPacket *packet = nullptr; + QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), + packet_sent_by_client->packet_number(), base_packet_number, + packet_sent_by_client->version(), std::move(versions), len); + if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), + header->packet_number(), header->buf(), header->length(), header->key_phase())) { + packet = quicPacketAllocator.alloc(); + new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, false); + } + return QUICPacketUPtr(packet, QUICPacketDeleter::delete_packet); } @@ -744,10 +740,22 @@ QUICPacketUPtr QUICPacketFactory::create_server_cleartext_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - QUICPacket *p = quicPacketAllocator.alloc(); - new (p) QUICPacket(QUICPacketType::SERVER_CLEARTEXT, connection_id, this->_packet_number_generator.next(), base_packet_number, - this->_version, std::move(payload), len, retransmittable); - return QUICPacketUPtr(p, &QUICPacketDeleter::delete_packet); + size_t max_cipher_txt_len = 2048; + ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); + size_t cipher_txt_len = 0; + + QUICPacket *packet = nullptr; + QUICPacketHeader *header = + QUICPacketHeader::build(QUICPacketType::SERVER_CLEARTEXT, connection_id, this->_packet_number_generator.next(), + base_packet_number, this->_version, std::move(payload), len); + + if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), + header->packet_number(), header->buf(), header->length(), header->key_phase())) { + packet = quicPacketAllocator.alloc(); + new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, retransmittable); + } + + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } QUICPacketUPtr @@ -789,9 +797,20 @@ QUICPacketUPtr QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len) { - QUICPacket *packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(QUICPacketType::CLIENT_INITIAL, connection_id, this->_packet_number_generator.next(), base_packet_number, - version, std::move(payload), len, true); + size_t max_cipher_txt_len = 2048; + ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); + size_t cipher_txt_len = 0; + + QUICPacket *packet = nullptr; + QUICPacketHeader *header = + QUICPacketHeader::build(QUICPacketType::CLIENT_INITIAL, connection_id, this->_packet_number_generator.next(), + base_packet_number, version, std::move(payload), len); + if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), + header->packet_number(), header->buf(), header->length(), header->key_phase())) { + packet = quicPacketAllocator.alloc(); + new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, false); + } + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index b51d23415af..b7173ed9a43 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -119,6 +119,8 @@ class QUICPacketHeader const uint8_t *_buf = nullptr; size_t _buf_len = 0; + // These are used only if the instance was created without a buffer + uint8_t _serialized[16]; ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); QUICPacketType _type = QUICPacketType::UNINITIALIZED; QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; @@ -187,15 +189,19 @@ class QUICPacket /* * Creates a QUICPacket with a QUICPacketHeader and a buffer that contains payload * - * QUICPacket class doesn't care about whether the payload is protected (encrypted) or not. + * 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. */ - QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len, QUICPacketNumber base_packet_number); + QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len); /* - * Creates a QUICPacket that has a Long Header + * Creates a QUICPacket with a QUICPacketHeader, a buffer that contains payload and a flag that indicates whether the packet can + * retransmittable + * + * 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. */ - QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len, bool retransmittable); + QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len, bool retransmittable); /* * Creates a QUICPacket that has a Short Header @@ -240,7 +246,6 @@ class QUICPacket QUICPacketHeader *_header; ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); size_t _payload_size = 0; - size_t _size = 0; bool _is_retransmittable = false; }; diff --git a/iocore/net/quic/QUICPacketTransmitter.h b/iocore/net/quic/QUICPacketTransmitter.h index 323c98d0749..5396a6a566f 100644 --- a/iocore/net/quic/QUICPacketTransmitter.h +++ b/iocore/net/quic/QUICPacketTransmitter.h @@ -24,6 +24,7 @@ #pragma once #include "QUICPacket.h" +#include "I_EventSystem.h" class QUICPacketTransmitter { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index ee8dbbe713f..e4fd5ad4f80 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -58,7 +58,7 @@ using QUICOffset = uint64_t; // Note: You also need to update tests for VersionNegotiationPacket, if you change the number of versions // Prefix for drafts (0xff000000) + draft number constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff000005, + 0xff000007, }; constexpr QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; diff --git a/iocore/net/quic/test/test_QUICCrypto.cc b/iocore/net/quic/test/test_QUICCrypto.cc index 35479e1c328..056874f02c2 100644 --- a/iocore/net/quic/test/test_QUICCrypto.cc +++ b/iocore/net/quic/test/test_QUICCrypto.cc @@ -34,7 +34,7 @@ #include #include "Mock.h" -#include "QUICCrypto.h" +#include "QUICCryptoTls.h" static constexpr uint32_t MAX_HANDSHAKE_MSG_LEN = 2048; @@ -109,7 +109,7 @@ TEST_CASE("QUICCrypto Cleartext", "[quic]") SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - QUICCrypto *client = new QUICCrypto(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + QUICCrypto *client = new QUICCryptoTls(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); // Server SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); @@ -119,7 +119,7 @@ TEST_CASE("QUICCrypto Cleartext", "[quic]") SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - QUICCrypto *server = new QUICCrypto(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + QUICCrypto *server = new QUICCryptoTls(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); // Client Hello uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; @@ -195,7 +195,7 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - QUICCrypto *client = new QUICCrypto(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + QUICCrypto *client = new QUICCryptoTls(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); // Server SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); @@ -205,7 +205,7 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - QUICCrypto *server = new QUICCrypto(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + QUICCrypto *server = new QUICCryptoTls(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); // Client Hello uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 543249bc67f..42841823b69 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -40,9 +40,10 @@ TEST_CASE("QUICLossDetector_Loss_in_Handshake", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketUPtr packet = QUICPacketUPtr(new QUICPacket(QUICPacketType::SERVER_CLEARTEXT, 0xffddbb9977553311ULL, 0x00000001, 0, - 0x00112233, std::move(payload), sizeof(raw), true), - [](QUICPacket *p) { delete p; }); + QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::SERVER_CLEARTEXT, 0xffddbb9977553311ULL, 0x00000001, 0, + 0x00112233, std::move(payload), sizeof(raw)); + QUICPacketUPtr packet = + QUICPacketUPtr(new QUICPacket(header, std::move(payload), sizeof(raw), true), [](QUICPacket *p) { delete p; }); detector.on_packet_sent(std::move(packet)); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); CHECK(tx->_retransmit_count > 0); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 7a63fca96fb..4a5f2f95ca4 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -24,10 +24,13 @@ #include "catch.hpp" #include "quic/QUICPacket.h" +#include "quic/Mock.h" TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") { QUICPacketFactory factory; + MockQUICCrypto crypto; + factory.set_crypto_module(&crypto); uint8_t client_initial_packet_header[] = { 0x82, // Type @@ -47,12 +50,14 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); CHECK(packet->connection_id() == client_initial_packet.connection_id()); CHECK(packet->packet_number() == client_initial_packet.packet_number()); - CHECK(memcmp(packet->payload(), "\xff\x00\x00\x05", 4) == 0); + CHECK(memcmp(packet->payload(), "\xff\x00\x00\x07", 4) == 0); } TEST_CASE("QUICPacketFactory_Create_ServerCleartextPacket", "[quic]") { QUICPacketFactory factory; + MockQUICCrypto crypto; + factory.set_crypto_module(&crypto); factory.set_version(0x11223344); uint8_t raw[] = {0xaa, 0xbb, 0xcc, 0xdd}; @@ -70,6 +75,8 @@ TEST_CASE("QUICPacketFactory_Create_ServerCleartextPacket", "[quic]") TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") { QUICPacketFactory factory; + MockQUICCrypto crypto; + factory.set_crypto_module(&crypto); QUICStatelessToken token; token.gen_token(12345); uint8_t expected_output[] = { diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index e2971d57149..c8c0a93062d 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -29,6 +29,8 @@ TEST_CASE("QUICVersionNegotiator_Normal", "[quic]") { QUICPacketFactory packet_factory; + MockQUICCrypto crypto; + packet_factory.set_crypto_module(&crypto); QUICVersionNegotiator vn; // Check initial state From f91516c61c74d25f30516a1e372d376ea4c48ba4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 21 Nov 2017 17:46:12 +0900 Subject: [PATCH 0182/1313] Fix 1-rtt packet protection --- iocore/net/quic/QUICCrypto.cc | 10 ++++-- iocore/net/quic/QUICHandshake.cc | 10 +++--- iocore/net/quic/QUICKeyGenerator.cc | 13 ++++---- iocore/net/quic/QUICPacket.cc | 47 +++++++---------------------- iocore/net/quic/QUICPacket.h | 14 +-------- 5 files changed, 30 insertions(+), 64 deletions(-) diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 9041ad5622e..02231eb2726 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -155,7 +155,7 @@ QUICCryptoTls::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, cons bool QUICCryptoTls::is_handshake_finished() const { - return SSL_is_init_finished(this->_ssl); + return (this->_client_pp->key_phase() != QUICKeyPhase::CLEARTEXT && this->_server_pp->key_phase() != QUICKeyPhase::CLEARTEXT); } int @@ -177,7 +177,7 @@ QUICCryptoTls::initialize_key_materials(QUICConnectionId cid) int QUICCryptoTls::update_key_materials() { - ink_assert(this->is_handshake_finished()); + ink_assert(SSL_is_init_finished(this->_ssl)); // Switch key phase QUICKeyPhase next_key_phase; switch (this->_client_pp->key_phase()) { @@ -256,7 +256,11 @@ QUICCryptoTls::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, } size_t tag_len = this->_get_aead_tag_len(); - return _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, pp->get_key(phase), tag_len); + bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, pp->get_key(phase), tag_len); + if (!ret) { + Debug(tag, "Failed to decrypt a packet: pkt_num=%" PRIu64, pkt_num); + } + return ret; } /** diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index faf2c1c6203..2a3b75e9b3a 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -379,18 +379,16 @@ QUICHandshake::_process_client_finished() I_WANNA_DUMP_THIS_BUF(out, static_cast(out_len)); // <----- DEBUG ----- - ink_assert(this->_crypto->is_handshake_finished()); - DebugQHS("Handshake is completed"); - _process_handshake_complete(); + DebugQHS("Handshake has been completed"); + + DebugQHS("Enter state_complete"); + SET_HANDLER(&QUICHandshake::state_complete); stream_io->write(out, out_len); stream_io->write_reenable(); stream_io->read_reenable(); - DebugQHS("Enter state_complete"); - SET_HANDLER(&QUICHandshake::state_complete); - return QUICErrorUPtr(new QUICNoError()); } else { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index a9aba4e074a..10ec80ccfee 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -23,6 +23,7 @@ #include #include "QUICKeyGenerator.h" +#include "ts/ink_assert.h" #include "ts/HKDF.h" constexpr static uint8_t QUIC_VERSION_1_SALT[] = { @@ -126,15 +127,15 @@ int QUICKeyGenerator::_generate_pp_secret(uint8_t *out, size_t *out_len, HKDF &hkdf, SSL *ssl, const char *label, size_t label_len, size_t length) { - uint8_t secret[512]; - size_t secret_len = length; + *out_len = length; if (this->_last_secret_len == 0) { - SSL_export_keying_material(ssl, secret, secret_len, label, label_len, reinterpret_cast(""), 0, 1); + SSL_export_keying_material(ssl, out, *out_len, label, label_len, reinterpret_cast(""), 0, 1); } else { + ink_assert(!"not implemented"); } - memcpy(this->_last_secret, secret, secret_len); - this->_last_secret_len = secret_len; - *out_len = length; + + memcpy(this->_last_secret, out, *out_len); + this->_last_secret_len = *out_len; return 0; } diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 35e55d4e8d7..fb7c3489094 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -481,20 +481,6 @@ QUICPacket::QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t this->_is_retransmittable = retransmittable; } -QUICPacket::QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable) -{ - this->_header = QUICPacketHeader::build(type, packet_number, base_packet_number, std::move(payload), len); - this->_is_retransmittable = retransmittable; -} - -QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) -{ - this->_header = QUICPacketHeader::build(type, connection_id, packet_number, base_packet_number, std::move(payload), len); - this->_is_retransmittable = retransmittable; -} - QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token) { const uint8_t *token = stateless_reset_token.get_u8(); @@ -762,35 +748,24 @@ QUICPacketUPtr QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - // TODO Key phase should be picked up from QUICCrypto, probably - QUICPacket *p = quicPacketAllocator.alloc(); - new (p) QUICPacket(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, connection_id, this->_packet_number_generator.next(), - base_packet_number, std::move(payload), len, retransmittable); - auto packet = QUICPacketUPtr(p, &QUICPacketDeleter::delete_packet); - // TODO: use pmtu of UnixNetVConnection size_t max_cipher_txt_len = 2048; ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); size_t cipher_txt_len = 0; - // TODO: do not dump header twice - uint8_t ad[17] = {0}; - size_t ad_len = 0; - packet->header()->store(ad, &ad_len); - - if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, packet->payload(), packet->payload_size(), - packet->packet_number(), ad, ad_len, packet->key_phase())) { - QUICPacket *ep = quicPacketAllocator.alloc(); - new (ep) QUICPacket(packet->header()->clone(), std::move(cipher_txt), cipher_txt_len, base_packet_number); - packet = QUICPacketUPtr(ep, &QUICPacketDeleter::delete_packet); + // TODO Key phase should be picked up from QUICCrypto, probably + QUICPacket *packet = nullptr; + QUICPacketHeader *header = + QUICPacketHeader::build(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, connection_id, this->_packet_number_generator.next(), + base_packet_number, std::move(payload), len); - Debug("quic_packet_factory", "Encrypt Packet, pkt_num: %" PRIu64 ", header_len: %zu payload: %zu", packet->packet_number(), - ad_len, cipher_txt_len); - return packet; - } else { - Debug("quic_packet_factory", "CRYPTOGRAPHIC Error"); - return QUICPacketUPtr(nullptr, &QUICPacketDeleter::delete_null_packet); + if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), + header->packet_number(), header->buf(), header->length(), header->key_phase())) { + packet = quicPacketAllocator.alloc(); + new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, retransmittable); } + + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } QUICPacketUPtr diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index b7173ed9a43..fd390e31b55 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -195,7 +195,7 @@ class QUICPacket QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len); /* - * Creates a QUICPacket with a QUICPacketHeader, a buffer that contains payload and a flag that indicates whether the packet can + * Creates a QUICPacket with a QUICPacketHeader, a buffer that contains payload and a flag that indicates whether the packet is * retransmittable * * This will be used for sending packets. Therefore, it is expected that payload is already encrypted. @@ -203,18 +203,6 @@ class QUICPacket */ QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len, bool retransmittable); - /* - * Creates a QUICPacket that has a Short Header - */ - QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, - size_t len, bool retransmittable); - - /* - * Creates a QUICPacket that has a Short Header with a Connection ID - */ - QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittabl); - /* * Creates a QUICpacket for stateless reset */ From 7acc7881ed4a001b89ea3eed8181e22ace4a7fd8 Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Wed, 22 Nov 2017 10:48:19 -0800 Subject: [PATCH 0183/1313] Fixed build issue with Fedora 26, may be used uninitialized in this function --- iocore/net/quic/QUICCrypto.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 02231eb2726..3e45928f2ee 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -190,6 +190,10 @@ QUICCryptoTls::update_key_materials() case QUICKeyPhase::CLEARTEXT: next_key_phase = QUICKeyPhase::PHASE_0; break; + default: + Error("QUICKeyPhase value is undefined"); + ink_assert(false); + next_key_phase = QUICKeyPhase::PHASE_0; } // Generate keys From 9b2da8fe85ae9b82ca7d12db7917217426b5a25f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Nov 2017 14:18:45 +0900 Subject: [PATCH 0184/1313] Fix packet size calculation --- iocore/net/quic/QUICPacket.cc | 9 ++++++++- iocore/net/quic/QUICPacket.h | 22 ++++++++++++++++++++-- iocore/net/quic/test/test_QUICPacket.cc | 4 ++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index fb7c3489094..b2a0792c03e 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -51,6 +51,12 @@ QUICPacketHeader::buf() } } +uint16_t +QUICPacketHeader::packet_size() const +{ + return this->_buf_len; +} + QUICPacketHeader * QUICPacketHeader::load(const uint8_t *buf, size_t len, QUICPacketNumber base) { @@ -557,7 +563,8 @@ QUICPacket::is_retransmittable() const uint16_t QUICPacket::size() const { - return this->header_size() + this->payload_size(); + // This includes not only header size and payload size but also AEAD tag length + return this->_header->packet_size(); } uint16_t diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index fd390e31b55..308beb049d5 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -52,15 +52,20 @@ class QUICPacketHeader virtual const uint8_t *payload() const = 0; /* - * Returns a payload size based on header length and buffer size that is specified to the constructo. + * Returns its payload size based on header length and buffer size that is specified to the constructo. */ uint16_t payload_size() const; /* - * Returns a header size + * Returns its header size */ virtual uint16_t length() const = 0; + /* + * Returns its packet size + */ + uint16_t packet_size() const; + /* * Returns a key phase */ @@ -216,9 +221,22 @@ class QUICPacket const QUICPacketHeader *header() const; const uint8_t *payload() const; bool is_retransmittable() const; + + /* + * Size of whole QUIC packet (header + payload + integrity check) + */ uint16_t size() const; + + /* + * Size of header + */ uint16_t header_size() const; + + /* + * Size of payload + */ uint16_t payload_size() const; + void store(uint8_t *buf, size_t *len) const; QUICKeyPhase key_phase() const; diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 60b35a2d947..1bb582fda93 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -38,6 +38,8 @@ TEST_CASE("QUICPacketHeader", "[quic]") }; QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); + CHECK(header->length() == 17); + CHECK(header->packet_size() == 19); CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); CHECK(header->connection_id() == 0x0102030405060708); CHECK(header->packet_number() == 0x12345678); @@ -54,6 +56,8 @@ TEST_CASE("QUICPacketHeader", "[quic]") }; QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); + CHECK(header->length() == 13); + CHECK(header->packet_size() == 15); CHECK(header->connection_id() == 0x0102030405060708); CHECK(header->packet_number() == 0x12345678); } From 668757f0ac9f291323fd05d086dc9e54abcbe34a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Nov 2017 14:22:14 +0900 Subject: [PATCH 0185/1313] Rename QUICPacketHeader::length() to size() --- iocore/net/quic/QUICPacket.cc | 28 ++++++++++++------------- iocore/net/quic/QUICPacket.h | 6 +++--- iocore/net/quic/test/test_QUICPacket.cc | 4 ++-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index b2a0792c03e..651e563e17e 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -197,7 +197,7 @@ uint16_t QUICPacketHeader::payload_size() const { if (this->_buf) { - return this->_buf_len - this->length(); + return this->_buf_len - this->size(); } else { return this->_payload_len; } @@ -217,7 +217,7 @@ QUICPacketLongHeader::key_phase() const } uint16_t -QUICPacketLongHeader::length() const +QUICPacketLongHeader::size() const { return LONGHEADER_LENGTH; } @@ -399,7 +399,7 @@ const uint8_t * QUICPacketShortHeader::payload() const { if (this->_buf) { - return this->_buf + length(); + return this->_buf + this->size(); } else { return this->_payload.get(); } @@ -429,7 +429,7 @@ QUICPacketShortHeader::key_phase() const * Header Length (doesn't include payload length) */ uint16_t -QUICPacketShortHeader::length() const +QUICPacketShortHeader::size() const { uint16_t len = 1; @@ -570,7 +570,7 @@ QUICPacket::size() const uint16_t QUICPacket::header_size() const { - return this->_header->length(); + return this->_header->size(); } uint16_t @@ -588,9 +588,9 @@ QUICPacket::key_phase() const void QUICPacket::store(uint8_t *buf, size_t *len) const { - memcpy(buf, this->_header->buf(), this->_header->length()); - memcpy(buf + this->_header->length(), this->payload(), this->payload_size()); - *len = this->_header->length() + this->payload_size(); + memcpy(buf, this->_header->buf(), this->_header->size()); + memcpy(buf + this->_header->size(), this->payload(), this->payload_size()); + *len = this->_header->size() + this->payload_size(); } uint8_t @@ -666,7 +666,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: if (this->_crypto->is_handshake_finished()) { if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->length(), header->key_phase())) { + header->packet_number(), header->buf(), header->size(), header->key_phase())) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -679,7 +679,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ case QUICPacketType::CLIENT_CLEARTEXT: case QUICPacketType::SERVER_CLEARTEXT: if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->length(), QUICKeyPhase::CLEARTEXT)) { + header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -721,7 +721,7 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se packet_sent_by_client->packet_number(), base_packet_number, packet_sent_by_client->version(), std::move(versions), len); if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->length(), header->key_phase())) { + header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, false); } @@ -743,7 +743,7 @@ QUICPacketFactory::create_server_cleartext_packet(QUICConnectionId connection_id base_packet_number, this->_version, std::move(payload), len); if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->length(), header->key_phase())) { + header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, retransmittable); } @@ -767,7 +767,7 @@ QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id base_packet_number, std::move(payload), len); if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->length(), header->key_phase())) { + header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, retransmittable); } @@ -788,7 +788,7 @@ QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, QUICPacketHeader::build(QUICPacketType::CLIENT_INITIAL, connection_id, this->_packet_number_generator.next(), base_packet_number, version, std::move(payload), len); if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->length(), header->key_phase())) { + header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, false); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 308beb049d5..3b1f7997676 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -59,7 +59,7 @@ class QUICPacketHeader /* * Returns its header size */ - virtual uint16_t length() const = 0; + virtual uint16_t size() const = 0; /* * Returns its packet size @@ -155,7 +155,7 @@ class QUICPacketLongHeader : public QUICPacketHeader bool has_connection_id() const; QUICKeyPhase key_phase() const; bool has_key_phase() const; - uint16_t length() const; + uint16_t size() const; void store(uint8_t *buf, size_t *len) const; }; @@ -177,7 +177,7 @@ class QUICPacketShortHeader : public QUICPacketHeader bool has_connection_id() const; QUICKeyPhase key_phase() const; bool has_key_phase() const; - uint16_t length() const; + uint16_t size() const; void store(uint8_t *buf, size_t *len) const; private: diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 1bb582fda93..e2d78638f9f 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -38,7 +38,7 @@ TEST_CASE("QUICPacketHeader", "[quic]") }; QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); - CHECK(header->length() == 17); + CHECK(header->size() == 17); CHECK(header->packet_size() == 19); CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); CHECK(header->connection_id() == 0x0102030405060708); @@ -56,7 +56,7 @@ TEST_CASE("QUICPacketHeader", "[quic]") }; QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); - CHECK(header->length() == 13); + CHECK(header->size() == 13); CHECK(header->packet_size() == 15); CHECK(header->connection_id() == 0x0102030405060708); CHECK(header->packet_number() == 0x12345678); From ff03253e49394fa8323018a9a4ba93b39e2bd351 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Nov 2017 14:33:26 +0900 Subject: [PATCH 0186/1313] Remove a wrong assert --- iocore/net/QUICNetVConnection.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index cc226fa208d..56ec2a783a3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -773,7 +773,6 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans } if (len + frame->size() + MAX_PACKET_OVERHEAD > max_size || (previous_packet_type != current_packet_type && len > 0)) { - ink_assert(len > 0); this->_transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, previous_packet_type)); retransmittable = false; len = 0; From 66044e3f4e99372fbe33d2b2f4e0b095164ff4c1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Nov 2017 17:22:04 +0900 Subject: [PATCH 0187/1313] Resolve a race --- iocore/net/P_QUICNetVConnection.h | 2 ++ iocore/net/QUICNetVConnection.cc | 50 +++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index bba69ad2fa0..b504fea2e39 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -225,6 +225,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection std::queue _frame_send_queue; std::queue _stream_frame_send_queue; + void _schedule_packet_write_ready(); + void _unschedule_packet_write_ready(); Event *_packet_write_ready = nullptr; void _transmit_packet(QUICPacketUPtr); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 56ec2a783a3..3bcb7f58501 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -126,6 +126,7 @@ QUICNetVConnection::free(EThread *t) this->_udp_con = nullptr; this->_packet_handler = nullptr; + _unschedule_packet_write_ready(); delete this->_version_negotiator; delete this->_handshake_handler; @@ -225,9 +226,7 @@ void QUICNetVConnection::transmit_packet(QUICPacketUPtr packet) { this->_transmit_packet(std::move(packet)); - if (!this->_packet_write_ready) { - this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); - } + this->_schedule_packet_write_ready(); } void @@ -293,10 +292,7 @@ void QUICNetVConnection::transmit_frame(QUICFrameUPtr frame) { this->_transmit_frame(std::move(frame)); - if (!this->_packet_write_ready) { - DebugQUICCon("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); - this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); - } + this->_schedule_packet_write_ready(); } void @@ -333,10 +329,7 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); - - if (!this->_packet_write_ready) { - this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); - } + this->_schedule_packet_write_ready(); break; case QUICFrameType::BLOCKED: @@ -361,6 +354,8 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) int QUICNetVConnection::state_pre_handshake(int event, Event *data) { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + if (!this->thread) { this->thread = this_ethread(); } @@ -384,6 +379,7 @@ QUICNetVConnection::state_pre_handshake(int event, Event *data) int QUICNetVConnection::state_handshake(int event, Event *data) { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { @@ -452,6 +448,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) int QUICNetVConnection::state_connection_established(int event, Event *data) { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: { @@ -488,6 +485,8 @@ QUICNetVConnection::state_connection_established(int event, Event *data) int QUICNetVConnection::state_connection_closing(int event, Event *data) { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: { @@ -522,12 +521,10 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) int QUICNetVConnection::state_connection_closed(int event, Event *data) { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); switch (event) { case QUIC_EVENT_SHUTDOWN: { - if (this->_packet_write_ready) { - this->_packet_write_ready->cancel(); - this->_packet_write_ready = nullptr; - } + this->_unschedule_packet_write_ready(); this->next_inactivity_timeout_at = 0; this->next_activity_timeout_at = 0; @@ -542,6 +539,9 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) } default: DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); + if (this->_packet_write_ready == data) { + this->_packet_write_ready = nullptr; + } } return EVENT_DONE; @@ -980,3 +980,23 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) return quic_packet; } + +void +QUICNetVConnection::_schedule_packet_write_ready() +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + if (!this->_packet_write_ready) { + DebugQUICCon("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); + this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + } +} + +void +QUICNetVConnection::_unschedule_packet_write_ready() +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + if (this->_packet_write_ready) { + this->_packet_write_ready->cancel(); + this->_packet_write_ready = nullptr; + } +} From 51a84aa2ae0b424ccfd46b2b71ed534d83fe17a6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Nov 2017 17:24:48 +0900 Subject: [PATCH 0188/1313] Remove duplicate code --- iocore/net/quic/QUICPacket.cc | 54 +++++++++-------------------------- iocore/net/quic/QUICPacket.h | 2 ++ 2 files changed, 15 insertions(+), 41 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 651e563e17e..4d822eaf505 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -702,10 +702,6 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ QUICPacketUPtr QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number) { - size_t max_cipher_txt_len = 2048; - ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); - size_t cipher_txt_len = 0; - size_t len = sizeof(QUICVersion) * countof(QUIC_SUPPORTED_VERSIONS); ats_unique_buf versions(reinterpret_cast(ats_malloc(len)), [](void *p) { ats_free(p); }); uint8_t *p = versions.get(); @@ -716,77 +712,53 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se p += n; } - QUICPacket *packet = nullptr; QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), packet_sent_by_client->packet_number(), base_packet_number, packet_sent_by_client->version(), std::move(versions), len); - if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->size(), header->key_phase())) { - packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, false); - } - - return QUICPacketUPtr(packet, QUICPacketDeleter::delete_packet); + return this->_create_encrypted_packet(header); } QUICPacketUPtr QUICPacketFactory::create_server_cleartext_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - size_t max_cipher_txt_len = 2048; - ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); - size_t cipher_txt_len = 0; - - QUICPacket *packet = nullptr; QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::SERVER_CLEARTEXT, connection_id, this->_packet_number_generator.next(), base_packet_number, this->_version, std::move(payload), len); - - if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->size(), header->key_phase())) { - packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, retransmittable); - } - - return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); + return this->_create_encrypted_packet(header); } QUICPacketUPtr QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - // TODO: use pmtu of UnixNetVConnection - size_t max_cipher_txt_len = 2048; - ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); - size_t cipher_txt_len = 0; // TODO Key phase should be picked up from QUICCrypto, probably - QUICPacket *packet = nullptr; QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, connection_id, this->_packet_number_generator.next(), base_packet_number, std::move(payload), len); - - if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->size(), header->key_phase())) { - packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, retransmittable); - } - - return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); + return this->_create_encrypted_packet(header); } QUICPacketUPtr QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len) { + QUICPacketHeader *header = + QUICPacketHeader::build(QUICPacketType::CLIENT_INITIAL, connection_id, this->_packet_number_generator.next(), + base_packet_number, version, std::move(payload), len); + return this->_create_encrypted_packet(header); +} + +QUICPacketUPtr +QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header) +{ + // TODO: use pmtu of UnixNetVConnection size_t max_cipher_txt_len = 2048; ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); size_t cipher_txt_len = 0; QUICPacket *packet = nullptr; - QUICPacketHeader *header = - QUICPacketHeader::build(QUICPacketType::CLIENT_INITIAL, connection_id, this->_packet_number_generator.next(), - base_packet_number, version, std::move(payload), len); if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 3b1f7997676..42d40e62ec5 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -308,4 +308,6 @@ class QUICPacketFactory QUICVersion _version = 0; QUICCrypto *_crypto = nullptr; QUICPacketNumberGenerator _packet_number_generator; + + QUICPacketUPtr _create_encrypted_packet(QUICPacketHeader *header); }; From 092d089e043e8b22385a1468227b606f976386f5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Nov 2017 17:45:29 +0900 Subject: [PATCH 0189/1313] clang-format --- iocore/net/quic/QUICPacket.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 4d822eaf505..4c173dddca6 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -732,7 +732,6 @@ QUICPacketUPtr QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - // TODO Key phase should be picked up from QUICCrypto, probably QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, connection_id, this->_packet_number_generator.next(), From 7db88767ddcabfd3e03f5ff6944309f94869eea0 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Nov 2017 21:09:22 +0900 Subject: [PATCH 0190/1313] Remove timestamp section from ACK frame --- iocore/net/quic/QUICFrame.cc | 66 +++----------------------- iocore/net/quic/QUICFrame.h | 14 ------ iocore/net/quic/test/test_QUICFrame.cc | 25 ++++------ 3 files changed, 16 insertions(+), 89 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 4fb864b3bf1..a9b4520e803 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -316,8 +316,9 @@ size_t QUICAckFrame::size() const { if (this->_buf) { - return this->_get_timestamp_section_offset() + this->timestamp_section()->size(); + return this->_get_ack_block_section_offset() + this->ack_block_section()->size(); } else { + // TODO Not implemented return 0; } } @@ -339,9 +340,6 @@ QUICAckFrame::store(uint8_t *buf, size_t *len) const p += 1; } - *p = this->_timestamp_section->count(); - p += 1; - // "LL" of "101NLLMM" if (this->_largest_acknowledged <= 0xff) { QUICTypeUtil::write_uint_as_nbytes(this->_largest_acknowledged, 1, p, &n); @@ -367,9 +365,6 @@ QUICAckFrame::store(uint8_t *buf, size_t *len) const this->_ack_block_section->store(p, &n); p += n; - this->_timestamp_section->store(p, &n); - p += n; - *len = p - buf; } @@ -387,12 +382,6 @@ QUICAckFrame::num_blocks() const } } -uint8_t -QUICAckFrame::num_timestamps() const -{ - return this->_buf[this->_get_num_timestamp_offset()]; -} - QUICPacketNumber QUICAckFrame::largest_acknowledged() const { @@ -439,22 +428,6 @@ QUICAckFrame::ack_block_section() const return this->_ack_block_section; } -const QUICAckFrame::TimestampSection * -QUICAckFrame::timestamp_section() const -{ - return this->_timestamp_section; -} - -size_t -QUICAckFrame::_get_num_timestamp_offset() const -{ - if (this->has_ack_blocks()) { - return 2; - } else { - return 1; - } -} - /** * LL of 101NLLMM */ @@ -474,7 +447,11 @@ QUICAckFrame::_get_largest_acknowledged_length() const size_t QUICAckFrame::_get_largest_acknowledged_offset() const { - return this->_get_num_timestamp_offset() + 1; + if (this->has_ack_blocks()) { + return 2; + } else { + return 1; + } } /** @@ -505,12 +482,6 @@ QUICAckFrame::_get_ack_block_section_offset() const return this->_get_ack_delay_offset() + 2; } -size_t -QUICAckFrame::_get_timestamp_section_offset() const -{ - return this->_get_ack_block_section_offset() + this->ack_block_section()->size(); -} - QUICAckFrame::AckBlockSection::AckBlockSection(const uint8_t *buf, uint8_t num_blocks, uint8_t ack_block_length) { this->_buf = buf; @@ -637,29 +608,6 @@ QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, con } } -uint8_t -QUICAckFrame::TimestampSection::count() const -{ - return 0; -} - -size_t -QUICAckFrame::TimestampSection::size() const -{ - return 0; -} - -void -QUICAckFrame::TimestampSection::store(uint8_t *buf, size_t *len) const -{ - if (this->count() == 0) { - *len = 0; - return; - } - - // TODO: Store timestamp data -} - // // RST_STREAM frame // diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 87509aa80cd..43c52b5b109 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -170,15 +170,6 @@ class QUICAckFrame : public QUICFrame std::vector _ack_blocks; }; - class TimestampSection - { - public: - uint8_t count() const; - size_t size() const; - void store(uint8_t *buf, size_t *len) const; - void add_timestamp(); - }; - QUICAckFrame() : QUICFrame() {} QUICAckFrame(const uint8_t *buf, size_t len); QUICAckFrame(QUICPacketNumber largest_acknowledged, uint16_t ack_delay, uint64_t first_ack_block_length); @@ -188,26 +179,21 @@ class QUICAckFrame : public QUICFrame virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; uint8_t num_blocks() const; - uint8_t num_timestamps() const; QUICPacketNumber largest_acknowledged() const; uint16_t ack_delay() const; const AckBlockSection *ack_block_section() const; AckBlockSection *ack_block_section(); - const TimestampSection *timestamp_section() const; bool has_ack_blocks() const; private: - size_t _get_num_timestamp_offset() const; size_t _get_largest_acknowledged_offset() const; size_t _get_largest_acknowledged_length() const; size_t _get_ack_block_length() const; size_t _get_ack_delay_offset() const; size_t _get_ack_block_section_offset() const; - size_t _get_timestamp_section_offset() const; QUICPacketNumber _largest_acknowledged = 0; uint16_t _ack_delay = 0; AckBlockSection *_ack_block_section = nullptr; - TimestampSection *_timestamp_section = nullptr; }; // diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 434ef93d485..1e2969c2dc1 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -237,50 +237,44 @@ TEST_CASE("Store STREAM Frame", "[quic]") TEST_CASE("Load Ack Frame 1", "[quic]") { - // 0 Ack Block, 0 Timestamp, 8 bit packet number length, 8 bit block length + // 0 Ack Block, 8 bit packet number length, 8 bit block length uint8_t buf1[] = { 0xA0, // 101NLLMM - 0x00, // NumTS 0x12, // Largest Acknowledged 0x34, 0x56, // Ack Delay 0x00, // Ack Block Section }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); - CHECK(frame1->size() == 6); + CHECK(frame1->size() == 5); std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); CHECK(ackFrame1 != nullptr); CHECK(ackFrame1->has_ack_blocks() == false); - CHECK(ackFrame1->num_timestamps() == 0); CHECK(ackFrame1->largest_acknowledged() == 0x12); CHECK(ackFrame1->ack_delay() == 0x3456); - // TODO: 1 Ack Block, 0 Timestamp - // TODO: 1 Ack Block, 1 Timestamp + // TODO: 1 Ack Block } TEST_CASE("Load Ack Frame 2", "[quic]") { - // 0 Ack Block, 0 Timestamp, 8 bit packet number length, 8 bit block length + // 0 Ack Block, 8 bit packet number length, 8 bit block length uint8_t buf1[] = { 0xAA, // 101NLLMM '0b10101010' { N: 0, LL: 10, MM:10 } - 0x00, // NumTS 0x00, 0x00, 0x00, 0x01, // Largest Acknowledged 0x01, 0x71, // Ack Delay 0x00, 0x00, 0x00, 0x01, // ACK Block }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); - CHECK(frame1->size() == 12); + CHECK(frame1->size() == 11); std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); CHECK(ackFrame1 != nullptr); CHECK(ackFrame1->has_ack_blocks() == false); - CHECK(ackFrame1->num_timestamps() == 0); CHECK(ackFrame1->largest_acknowledged() == 0x01); CHECK(ackFrame1->ack_delay() == 0x0171); - // TODO: 1 Ack Block, 0 Timestamp - // TODO: 1 Ack Block, 1 Timestamp + // TODO: 1 Ack Block } TEST_CASE("Store Ack Frame", "[quic]") @@ -288,20 +282,19 @@ TEST_CASE("Store Ack Frame", "[quic]") uint8_t buf[65535]; size_t len; - // 0 Ack Block, 0 Timestamp, 8 bit packet number length, 8 bit block length + // 0 Ack Block, 8 bit packet number length, 8 bit block length uint8_t expected[] = { 0xA2, // 101NLLMM - 0x00, // NumTS 0x12, // Largest Acknowledged 0x34, 0x56, // Ack Delay 0x00, 0x00, 0x00, 0x00, // Ack Block Section }; QUICAckFrame ackFrame(0x12, 0x3456, 0); ackFrame.store(buf, &len); - CHECK(len == 9); + CHECK(len == 8); CHECK(memcmp(buf, expected, len) == 0); - // TODO: Add ack blocks and timestamps + // TODO: Add ack blocks } TEST_CASE("Load RST_STREAM Frame", "[quic]") From aac32c9aa000b8c2fbd0aef7bdbb0801de51617b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 29 Nov 2017 10:16:55 +0900 Subject: [PATCH 0191/1313] Use unprotected packet for Version Negotiation Packets --- iocore/net/quic/QUICPacket.cc | 15 ++++++++++++++- iocore/net/quic/QUICPacket.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 4c173dddca6..d3290d97564 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -715,7 +715,7 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), packet_sent_by_client->packet_number(), base_packet_number, packet_sent_by_client->version(), std::move(versions), len); - return this->_create_encrypted_packet(header); + return this->_create_unprotected_packet(header); } QUICPacketUPtr @@ -749,6 +749,19 @@ QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, return this->_create_encrypted_packet(header); } +QUICPacketUPtr +QUICPacketFactory::_create_unprotected_packet(QUICPacketHeader *header) +{ + ats_unique_buf cleartext = ats_unique_malloc(2048); + size_t cleartext_len = header->payload_size(); + + memcpy(cleartext.get(), header->payload(), cleartext_len); + QUICPacket *packet = quicPacketAllocator.alloc(); + new (packet) QUICPacket(header, std::move(cleartext), cleartext_len, false); + + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); +} + QUICPacketUPtr QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header) { diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 42d40e62ec5..d57f12e8e8a 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -309,5 +309,6 @@ class QUICPacketFactory QUICCrypto *_crypto = nullptr; QUICPacketNumberGenerator _packet_number_generator; + QUICPacketUPtr _create_unprotected_packet(QUICPacketHeader *header); QUICPacketUPtr _create_encrypted_packet(QUICPacketHeader *header); }; From ae2835c859a4295da7615c30a87c8fb3ef80df16 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 29 Nov 2017 12:01:45 +0900 Subject: [PATCH 0192/1313] Update stateless reset packet format --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/QUICPacketHandler.cc | 2 +- iocore/net/quic/QUICHandshake.cc | 2 +- iocore/net/quic/QUICPacket.cc | 50 +++++++++---------- iocore/net/quic/QUICPacket.h | 6 +-- iocore/net/quic/QUICTransportParameters.cc | 7 +++ iocore/net/quic/QUICTransportParameters.h | 1 + iocore/net/quic/QUICTypes.cc | 15 ++++++ iocore/net/quic/QUICTypes.h | 22 +++----- .../net/quic/test/test_QUICPacketFactory.cc | 3 +- 10 files changed, 58 insertions(+), 52 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3bcb7f58501..ed4b6c1edf8 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -92,7 +92,7 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not { QUICConfig::scoped_config params; - this->_token.gen_token(_quic_connection_id ^ params->server_id()); + this->_token.generate(_quic_connection_id ^ params->server_id()); } this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_token); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 8dc81044ddf..afc88fd1b2b 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -139,7 +139,7 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) QUICStatelessToken token; { QUICConfig::scoped_config params; - token.gen_token(cid ^ params->server_id()); + token.generate(cid ^ params->server_id()); } auto packet = QUICPacketFactory::create_stateless_reset_packet(cid, token); this->send_packet(*packet, udpPacket->getConnection(), con.addr, 1200); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 2a3b75e9b3a..052f0edc01f 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -299,7 +299,7 @@ QUICHandshake::_load_local_transport_parameters() params->no_activity_timeout_in(), sizeof(uint16_t)))); tp->add(QUICTransportParameterId::STATELESS_RETRY_TOKEN, - std::unique_ptr(new QUICTransportParameterValue(this->_token.get_u64(), 16))); + std::unique_ptr(new QUICTransportParameterValue(this->_token.buf(), 16))); tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); // MAYs diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index d3290d97564..0fc3f27896f 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -487,24 +487,6 @@ QUICPacket::QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t this->_is_retransmittable = retransmittable; } -QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token) -{ - const uint8_t *token = stateless_reset_token.get_u8(); - QUICPacketNumber fake_packet_number = token[0]; - QUICPacketNumber fake_base_packet_number = token[0]; - ats_unique_buf fake_payload = ats_unique_malloc(15 + 8); - memcpy(fake_payload.get(), token + 1, 15); - // Append random bytes - std::random_device rnd; - for (int i = 15; i < 23; ++i) { - fake_payload.get()[i] = rnd() & 0xFF; - } - // TODO stateless packet format changed - this->_header = - QUICPacketHeader::build(type, connection_id, fake_packet_number, fake_base_packet_number, std::move(fake_payload), 15 + 8); - this->_is_retransmittable = false; -} - QUICPacket::~QUICPacket() { if (this->_header->has_version()) { @@ -715,7 +697,7 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), packet_sent_by_client->packet_number(), base_packet_number, packet_sent_by_client->version(), std::move(versions), len); - return this->_create_unprotected_packet(header); + return QUICPacketFactory::_create_unprotected_packet(header); } QUICPacketUPtr @@ -749,6 +731,28 @@ QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, return this->_create_encrypted_packet(header); } +QUICPacketUPtr +QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token) +{ + std::random_device rnd; + + uint8_t random_packet_number = static_cast(rnd() & 0xFF); + size_t payload_len = static_cast(rnd() & 0xFF); + ats_unique_buf payload = ats_unique_malloc(payload_len + 16); + uint8_t *naked_payload = payload.get(); + + // Generate random octets + for (int i = payload_len - 1; i >= 0; --i) { + naked_payload[i] = static_cast(rnd() & 0xFF); + } + // Copy stateless reset token into payload + memcpy(naked_payload + payload_len - 16, stateless_reset_token.buf(), 16); + + QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::STATELESS_RESET, connection_id, random_packet_number, 0, + std::move(payload), payload_len); + return QUICPacketFactory::_create_unprotected_packet(header); +} + QUICPacketUPtr QUICPacketFactory::_create_unprotected_packet(QUICPacketHeader *header) { @@ -780,14 +784,6 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header) return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } -QUICPacketUPtr -QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token) -{ - QUICPacket *packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(QUICPacketType::STATELESS_RESET, connection_id, stateless_reset_token); - return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); -} - void QUICPacketFactory::set_version(QUICVersion negotiated_version) { diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index d57f12e8e8a..cc42d322b63 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -208,10 +208,6 @@ class QUICPacket */ QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len, bool retransmittable); - /* - * Creates a QUICpacket for stateless reset - */ - QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token); ~QUICPacket(); QUICPacketType type() const; @@ -309,6 +305,6 @@ class QUICPacketFactory QUICCrypto *_crypto = nullptr; QUICPacketNumberGenerator _packet_number_generator; - QUICPacketUPtr _create_unprotected_packet(QUICPacketHeader *header); + static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeader *header); QUICPacketUPtr _create_encrypted_packet(QUICPacketHeader *header); }; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 2ca71760b0b..f8dac049685 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -36,6 +36,13 @@ static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; // QUICTransportParameterValue::QUICTransportParameterValue(ats_unique_buf d, uint16_t l) : _data(std::move(d)), _len(l){}; +QUICTransportParameterValue::QUICTransportParameterValue(const uint8_t *raw_data, uint16_t l) +{ + this->_data = ats_unique_malloc(l); + this->_len = l; + memcpy(this->_data.get(), raw_data, l); +} + QUICTransportParameterValue::QUICTransportParameterValue(uint64_t raw_data, uint16_t l) { this->_data = ats_unique_malloc(l); diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index ba53a156786..12c4892f998 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -68,6 +68,7 @@ class QUICTransportParameterValue { public: QUICTransportParameterValue(ats_unique_buf d, uint16_t l); + QUICTransportParameterValue(const uint8_t *raw_data, uint16_t l); QUICTransportParameterValue(uint64_t raw_data, uint16_t l); QUICTransportParameterValue(const uint64_t raw_data[2], uint16_t l); diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 27fa72c7921..0e152cd1b34 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -147,6 +147,21 @@ QUICTypeUtil::write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size *len = n; } +void +QUICStatelessToken::_gen_token(uint64_t data) +{ + INK_MD5 _md5; + static constexpr char STATELESS_RETRY_TOKEN_KEY[] = "stateless_token_retry_key"; + MD5Context ctx; + ctx.update(STATELESS_RETRY_TOKEN_KEY, strlen(STATELESS_RETRY_TOKEN_KEY)); + ctx.update(reinterpret_cast(&data), 8); + ctx.finalize(_md5); + + size_t dummy; + QUICTypeUtil::write_uint_as_nbytes(_md5.u64[0], 8, _token, &dummy); + QUICTypeUtil::write_uint_as_nbytes(_md5.u64[1], 8, _token + 8, &dummy); +} + uint16_t QUICError::code() { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index e4fd5ad4f80..23eb3c09d34 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -205,29 +205,21 @@ class QUICStatelessToken { public: void - gen_token(uint64_t data) + generate(uint64_t data) { - static constexpr char STATELESS_RETRY_TOKEN_KEY[] = "stateless_token_retry_key"; - MD5Context ctx; - ctx.update(STATELESS_RETRY_TOKEN_KEY, strlen(STATELESS_RETRY_TOKEN_KEY)); - ctx.update(reinterpret_cast(&data), 8); - ctx.finalize(_md5); + this->_gen_token(data); } const uint8_t * - get_u8() const + buf() const { - return _md5.u8; - } - - const uint64_t * - get_u64() const - { - return _md5.u64; + return _token; } private: - INK_MD5 _md5; + uint8_t _token[16] = {0}; + + void _gen_token(uint64_t data); }; class QUICConnectionId diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 4a5f2f95ca4..8b7d3a0b206 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -78,7 +78,7 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") MockQUICCrypto crypto; factory.set_crypto_module(&crypto); QUICStatelessToken token; - token.gen_token(12345); + token.generate(12345); uint8_t expected_output[] = { 0x41, // 0CK0001 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, // Connection ID @@ -92,5 +92,4 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") QUICPacketUPtr packet = factory.create_stateless_reset_packet(0x01020304, token); CHECK(packet->type() == QUICPacketType::STATELESS_RESET); CHECK(packet->connection_id() == 0x01020304); - CHECK(packet->packet_number() == token.get_u8()[0]); } From 5f3df783483b11c0b599b73300d920aa8ae44e29 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 29 Nov 2017 12:49:34 +0900 Subject: [PATCH 0193/1313] Remove 1-RTT Protected packet types --- iocore/net/QUICNetVConnection.cc | 3 +- iocore/net/quic/QUICDebugNames.cc | 6 ++-- iocore/net/quic/QUICPacket.cc | 50 ++++++++++++------------------- iocore/net/quic/QUICPacket.h | 15 +++++----- iocore/net/quic/QUICTypes.h | 7 ++--- 5 files changed, 33 insertions(+), 48 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ed4b6c1edf8..4b113d710fa 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -707,8 +707,7 @@ QUICNetVConnection::_state_common_receive_packet() net_activity(this, this_ethread()); switch (p->type()) { - case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: - case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: + case QUICPacketType::PROTECTED: error = this->_state_connection_established_process_packet(std::move(p)); break; case QUICPacketType::CLIENT_CLEARTEXT: diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 7e4fd44525c..dd750dfa007 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -40,10 +40,8 @@ QUICDebugNames::packet_type(QUICPacketType type) return "CLIENT_CLEARTEXT"; case QUICPacketType::ZERO_RTT_PROTECTED: return "ZERO_RTT_PROTECTED"; - case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: - return "ONE_RTT_PROTECTED_KEY_PHASE_0"; - case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: - return "ONE_RTT_PROTECTED_KEY_PHASE_1"; + case QUICPacketType::PROTECTED: + return "PROTECTED"; case QUICPacketType::STATELESS_RESET: return "STATELESS_RESET"; case QUICPacketType::UNINITIALIZED: diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 0fc3f27896f..2d59871a79a 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -81,20 +81,21 @@ QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUI } QUICPacketHeader * -QUICPacketHeader::build(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len) +QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len) { QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); - new (short_header) QUICPacketShortHeader(type, packet_number, base_packet_number, std::move(payload), len); + new (short_header) QUICPacketShortHeader(type, key_phase, packet_number, base_packet_number, std::move(payload), len); return short_header; } QUICPacketHeader * -QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, +QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len) { QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); - new (short_header) QUICPacketShortHeader(type, connection_id, packet_number, base_packet_number, std::move(payload), len); + new (short_header) + QUICPacketShortHeader(type, key_phase, connection_id, packet_number, base_packet_number, std::move(payload), len); return short_header; } @@ -246,31 +247,26 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const // // QUICPacketShortHeader // -QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICPacketNumber packet_number, +QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len) { this->_type = type; this->_has_key_phase = true; + this->_key_phase = key_phase; this->_packet_number = packet_number; this->_base_packet_number = base_packet_number; this->_packet_number_type = this->_discover_packet_number_type(packet_number, base_packet_number); this->_payload = std::move(buf); this->_payload_len = len; - - if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0) { - this->_key_phase = QUICKeyPhase::PHASE_0; - } else if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { - this->_key_phase = QUICKeyPhase::PHASE_1; - } else { - ink_assert(false); - } } -QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len) +QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId connection_id, + QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, + ats_unique_buf buf, size_t len) { this->_type = type; this->_has_key_phase = true; + this->_key_phase = key_phase; this->_has_connection_id = true; this->_connection_id = connection_id; this->_packet_number = packet_number; @@ -278,14 +274,6 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICConnection this->_packet_number_type = this->_discover_packet_number_type(packet_number, base_packet_number); this->_payload = std::move(buf); this->_payload_len = len; - - if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0) { - this->_key_phase = QUICKeyPhase::PHASE_0; - } else if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) { - this->_key_phase = QUICKeyPhase::PHASE_1; - } else { - this->_key_phase = QUICKeyPhase::CLEARTEXT; - } } QUICPacketType @@ -295,10 +283,10 @@ QUICPacketShortHeader::type() const switch (key_phase) { case QUICKeyPhase::PHASE_0: { - return QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0; + return QUICPacketType::PROTECTED; } case QUICKeyPhase::PHASE_1: { - return QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1; + return QUICPacketType::PROTECTED; } default: return QUICPacketType::STATELESS_RESET; @@ -644,8 +632,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ plain_txt_len = header->payload_size(); result = QUICPacketCreationResult::SUCCESS; break; - case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0: - case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1: + case QUICPacketType::PROTECTED: if (this->_crypto->is_handshake_finished()) { if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { @@ -716,7 +703,7 @@ QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id { // TODO Key phase should be picked up from QUICCrypto, probably QUICPacketHeader *header = - QUICPacketHeader::build(QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0, connection_id, this->_packet_number_generator.next(), + QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, connection_id, this->_packet_number_generator.next(), base_packet_number, std::move(payload), len); return this->_create_encrypted_packet(header); } @@ -748,8 +735,9 @@ QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, // Copy stateless reset token into payload memcpy(naked_payload + payload_len - 16, stateless_reset_token.buf(), 16); - QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::STATELESS_RESET, connection_id, random_packet_number, 0, - std::move(payload), payload_len); + // KeyPhase won't be used + QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::STATELESS_RESET, QUICKeyPhase::CLEARTEXT, connection_id, + random_packet_number, 0, std::move(payload), payload_len); return QUICPacketFactory::_create_unprotected_packet(header); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index cc42d322b63..8668da57e1b 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -106,16 +106,17 @@ class QUICPacketHeader * * This creates a QUICPacketShortHeader that contains a ConnectionID. */ - static QUICPacketHeader *build(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len); + static QUICPacketHeader *build(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len); /* * Build a QUICPacketHeader * * This creates a QUICPacketShortHeader that doesn't contain a ConnectionID.. */ - static QUICPacketHeader *build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len); + static QUICPacketHeader *build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId connection_id, + QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, + size_t len); protected: QUICPacketHeader(){}; @@ -164,9 +165,9 @@ class QUICPacketShortHeader : public QUICPacketHeader public: QUICPacketShortHeader() : QUICPacketHeader(){}; QUICPacketShortHeader(const uint8_t *buf, size_t len, QUICPacketNumber base) : QUICPacketHeader(buf, len, base) {} - QUICPacketShortHeader(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, - ats_unique_buf buf, size_t len); - QUICPacketShortHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + 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, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len); QUICPacketType type() const; QUICConnectionId connection_id() const; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 23eb3c09d34..a5bd4d1da6f 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -69,10 +69,9 @@ enum class QUICPacketType : int { SERVER_CLEARTEXT, CLIENT_CLEARTEXT, ZERO_RTT_PROTECTED, - ONE_RTT_PROTECTED_KEY_PHASE_0, - ONE_RTT_PROTECTED_KEY_PHASE_1, - STATELESS_RESET, - UNINITIALIZED, + PROTECTED, // Not on the spec. but just for convenience + STATELESS_RESET, // Not on the spec. but just for convenience + UNINITIALIZED, // Not on the spec. but just for convenience }; // To detect length of Packet Number From 2d3a1421c603bdb76e074c615f1bb6f2e5308e9a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 29 Nov 2017 14:07:06 +0900 Subject: [PATCH 0194/1313] Update application name for ALPN to hq-07 --- lib/ts/ink_inet.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ts/ink_inet.cc b/lib/ts/ink_inet.cc index d651f2ae64d..d5eb0e4bd19 100644 --- a/lib/ts/ink_inet.cc +++ b/lib/ts/ink_inet.cc @@ -45,7 +45,7 @@ const ts::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"_sv); const ts::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"_sv); const ts::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"_sv); const ts::string_view IP_PROTO_TAG_HTTP_2_0("h2"_sv); // HTTP/2 over TLS -const ts::string_view IP_PROTO_TAG_HTTP_QUIC("hq-05"_sv); // HTTP over QUIC +const ts::string_view IP_PROTO_TAG_HTTP_QUIC("hq-07"_sv); // HTTP over QUIC uint32_t ink_inet_addr(const char *s) From 463b30577acb800eb80463ca7885eced4285e9a9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 30 Nov 2017 15:31:25 +0900 Subject: [PATCH 0195/1313] Increase buffer size for SSL error messages --- iocore/net/quic/QUICCrypto.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 3e45928f2ee..77b38e8b1a6 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -127,7 +127,7 @@ QUICCryptoTls::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, cons case SSL_ERROR_WANT_WRITE: break; default: - char err_buf[32] = {0}; + char err_buf[256] = {0}; ERR_error_string_n(err, err_buf, sizeof(err_buf)); Debug(tag, "Handshake error: %s (%d)", err_buf, err); return false; From 99bf22ad4d7fe09c7966005956f1894b91646133 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 30 Nov 2017 16:26:03 +0900 Subject: [PATCH 0196/1313] Remove an unused type QUICMaximumData --- iocore/net/quic/QUICTypes.h | 54 ------------------------------------- 1 file changed, 54 deletions(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index a5bd4d1da6f..3f762a43e21 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -242,60 +242,6 @@ class QUICConnectionId enum class QUICStreamType { SERVER, CLIENT, HANDSHAKE }; -class QUICMaximumData -{ -public: - QUICMaximumData(uint64_t d) : _data(d) {} - bool - operator>(uint64_t r) const - { - return this->_data > (r / 1024); - } - - bool - operator<(uint64_t r) const - { - return this->_data < (r / 1024); - } - - bool - operator>=(uint64_t r) const - { - return this->_data >= (r / 1024); - } - - bool - operator<=(uint64_t r) const - { - return this->_data <= (r / 1024); - } - - bool - operator==(uint64_t r) const - { - return this->_data == (r / 1024); - } - - QUICMaximumData & - operator=(uint64_t d) - { - this->_data = d; - return *this; - } - - QUICMaximumData & - operator+=(uint64_t d) - { - this->_data += d; - return *this; - } - - operator uint64_t() const { return _data; } - -private: - uint64_t _data = 0; // in units of 1024 octets -}; - class QUICTypeUtil { public: From 86a0e52f73737e08d8f70ef22380561a91e7b047 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 30 Nov 2017 17:55:02 +0900 Subject: [PATCH 0197/1313] Fix connection level flow control calculation --- iocore/net/P_QUICNetVConnection.h | 1 - iocore/net/QUICNetVConnection.cc | 32 +++++++++------------------ iocore/net/quic/QUICFlowController.cc | 2 +- iocore/net/quic/QUICStreamManager.cc | 2 +- 4 files changed, 13 insertions(+), 24 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index b504fea2e39..da7a13270b4 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -232,7 +232,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _transmit_packet(QUICPacketUPtr); void _transmit_frame(QUICFrameUPtr); - bool _is_send_frame_avail_more_than(uint32_t size); void _store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, QUICFrameUPtr frame); void _packetize_frames(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 4b113d710fa..2e122d91422 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -325,7 +325,7 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) switch (frame->type()) { case QUICFrameType::MAX_DATA: - this->_remote_flow_controller->forward_limit(std::static_pointer_cast(frame)->maximum_data()); + this->_remote_flow_controller->forward_limit(std::static_pointer_cast(frame)->maximum_data() * 1024); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); @@ -738,23 +738,6 @@ QUICNetVConnection::_state_common_send_packet() return QUICErrorUPtr(new QUICNoError()); } -// Schedule sending BLOCKED frame when offset exceed the limit -bool -QUICNetVConnection::_is_send_frame_avail_more_than(uint32_t size) -{ - QUICErrorUPtr error = this->_remote_flow_controller->update((this->_stream_manager->total_offset_sent() + size) / 1024); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, - static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); - - if (error->cls != QUICErrorClass::NONE) { - // Flow Contoroller blocked sending STREAM frame - return false; - } - - return true; -} - // Store frame data to buffer for packet. When remaining buffer is too small to store frame data or packet type is different from // previous one, build packet and transmit it. After that, allocate new buffer. void @@ -816,7 +799,14 @@ QUICNetVConnection::_packetize_frames() while (this->_stream_frame_send_queue.size() > 0) { const QUICFrameUPtr &f = this->_stream_frame_send_queue.front(); uint32_t frame_size = f->size(); - if (!this->_is_send_frame_avail_more_than(frame_size)) { + + QUICErrorUPtr error = this->_remote_flow_controller->update((this->_stream_manager->total_offset_sent() + frame_size)); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, + static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); + + if (error->cls != QUICErrorClass::NONE) { + // Flow Contoroller blocked sending STREAM frame break; } @@ -910,8 +900,8 @@ QUICNetVConnection::_init_flow_control_params(const std::shared_ptrinitial_max_data(); } - this->_local_flow_controller->forward_limit(local_initial_max_data); - this->_remote_flow_controller->forward_limit(remote_initial_max_data); + this->_local_flow_controller->forward_limit(local_initial_max_data * 1024); + this->_remote_flow_controller->forward_limit(remote_initial_max_data * 1024); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 6c497aad7f1..68e01c569a6 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -126,7 +126,7 @@ QUICRemoteConnectionFlowController::_create_frame() QUICFrameUPtr QUICLocalConnectionFlowController::_create_frame() { - return QUICFrameFactory::create_max_data_frame(this->_limit); + return QUICFrameFactory::create_max_data_frame(this->_limit / 1024); } QUICFrameUPtr diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 64190e5fa66..b5c10eba2f3 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -233,7 +233,7 @@ QUICStreamManager::total_offset_received() const // FIXME Iterating all (open + closed) streams is expensive for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { if (s->id() != 0) { - total_offset_received += s->largest_offset_received() / 1024; + total_offset_received += s->largest_offset_received(); } } return total_offset_received; From de1ea8c2f98e6f62d5436bfd1e5fb9fc9ab46b10 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 30 Nov 2017 18:05:19 +0900 Subject: [PATCH 0198/1313] Stabilize handshake --- iocore/net/P_QUICNetVConnection.h | 3 ++ iocore/net/QUICNetVConnection.cc | 89 +++++++++++++++++-------------- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index da7a13270b4..9e4b5941d16 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -227,6 +227,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _schedule_packet_write_ready(); void _unschedule_packet_write_ready(); + void _close_packet_write_ready(Event *data); Event *_packet_write_ready = nullptr; void _transmit_packet(QUICPacketUPtr); @@ -256,6 +257,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _handle_error(QUICErrorUPtr error); QUICPacketUPtr _dequeue_recv_packet(QUICPacketCreationResult &result); + void _switch_to_established_state(); + QUICStatelessToken _token; }; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2e122d91422..153fb20bebd 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -380,6 +380,12 @@ int QUICNetVConnection::state_handshake(int event, Event *data) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + + if (this->_handshake_handler && this->_handshake_handler->is_completed()) { + this->_switch_to_established_state(); + return this->state_connection_established(event, data); + } + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { @@ -396,21 +402,17 @@ QUICNetVConnection::state_handshake(int event, Event *data) break; } case QUIC_EVENT_PACKET_WRITE_READY: { - if (this->_packet_write_ready == data) { - this->_packet_write_ready = nullptr; - } + this->_close_packet_write_ready(data); error = this->_state_common_send_packet(); break; } - case EVENT_IMMEDIATE: { + case EVENT_IMMEDIATE: // Start Implicit Shutdown. Because of no network activity for the duration of the idle timeout. this->remove_from_active_queue(); this->close(std::make_unique()); // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application break; - } - default: DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); } @@ -419,29 +421,6 @@ QUICNetVConnection::state_handshake(int event, Event *data) this->_handle_error(std::move(error)); } - if (this->_handshake_handler && this->_handshake_handler->is_completed()) { - this->_init_flow_control_params(this->_handshake_handler->local_transport_parameters(), - this->_handshake_handler->remote_transport_parameters()); - - DebugQUICCon("Enter state_connection_established"); - SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); - - const uint8_t *app_name; - unsigned int app_name_len = 0; - this->_handshake_handler->negotiated_application_name(&app_name, &app_name_len); - if (app_name == nullptr) { - app_name = reinterpret_cast(IP_PROTO_TAG_HTTP_QUIC.data()); - app_name_len = IP_PROTO_TAG_HTTP_QUIC.size(); - } - - Continuation *endpoint = this->_next_protocol_set->findEndpoint(app_name, app_name_len); - if (endpoint == nullptr) { - this->_handle_error(QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR))); - } else { - endpoint->handleEvent(NET_EVENT_ACCEPT, this); - } - } - return EVENT_CONT; } @@ -456,9 +435,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) break; } case QUIC_EVENT_PACKET_WRITE_READY: { - if (this->_packet_write_ready == data) { - this->_packet_write_ready = nullptr; - } + this->_close_packet_write_ready(data); error = this->_state_common_send_packet(); break; } @@ -498,9 +475,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) break; } case QUIC_EVENT_PACKET_WRITE_READY: { - if (this->_packet_write_ready == data) { - this->_packet_write_ready = nullptr; - } + this->_close_packet_write_ready(data); this->_state_common_send_packet(); break; } @@ -537,11 +512,12 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) break; } + case QUIC_EVENT_PACKET_WRITE_READY: { + this->_close_packet_write_ready(data); + break; + } default: DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); - if (this->_packet_write_ready == data) { - this->_packet_write_ready = nullptr; - } } return EVENT_DONE; @@ -973,7 +949,7 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) void QUICNetVConnection::_schedule_packet_write_ready() { - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); if (!this->_packet_write_ready) { DebugQUICCon("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); @@ -983,9 +959,42 @@ QUICNetVConnection::_schedule_packet_write_ready() void QUICNetVConnection::_unschedule_packet_write_ready() { - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); if (this->_packet_write_ready) { this->_packet_write_ready->cancel(); this->_packet_write_ready = nullptr; } } + +void +QUICNetVConnection::_close_packet_write_ready(Event *data) +{ + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); + ink_assert(this->_packet_write_ready == data); + this->_packet_write_ready = nullptr; +} + +void +QUICNetVConnection::_switch_to_established_state() +{ + this->_init_flow_control_params(this->_handshake_handler->local_transport_parameters(), + this->_handshake_handler->remote_transport_parameters()); + + const uint8_t *app_name; + unsigned int app_name_len = 0; + this->_handshake_handler->negotiated_application_name(&app_name, &app_name_len); + if (app_name == nullptr) { + app_name = reinterpret_cast(IP_PROTO_TAG_HTTP_QUIC.data()); + app_name_len = IP_PROTO_TAG_HTTP_QUIC.size(); + } + + Continuation *endpoint = this->_next_protocol_set->findEndpoint(app_name, app_name_len); + if (endpoint == nullptr) { + this->_handle_error(QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR))); + } else { + endpoint->handleEvent(NET_EVENT_ACCEPT, this); + } + + DebugQUICCon("Enter state_connection_established"); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); +} From 387b032b8763ad75ec773b45b10ea5d6c74a56f3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Dec 2017 09:48:58 +0900 Subject: [PATCH 0199/1313] Wait for handshake completion with patient --- iocore/net/QUICNetVConnection.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 153fb20bebd..2e148c33a3b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -932,7 +932,7 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) DebugQUICCon("Not ready to decrypt the packet"); // Retry later this->_packet_recv_queue.enqueue(udp_packet); - this_ethread()->schedule_imm_local(this, QUIC_EVENT_PACKET_READ_READY); + this_ethread()->schedule_in_local(this, HRTIME_MSECONDS(10), QUIC_EVENT_PACKET_READ_READY); } else { udp_packet->free(); if (result == QUICPacketCreationResult::SUCCESS) { From a0ec809922cf7b1f1736d6eb71dbc5bf6f6da462 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Dec 2017 11:12:05 +0900 Subject: [PATCH 0200/1313] Make state transition solid --- iocore/net/P_QUICNetVConnection.h | 4 ++ iocore/net/QUICNetVConnection.cc | 71 ++++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 9e4b5941d16..c80a2b6f95c 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -257,7 +257,11 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _handle_error(QUICErrorUPtr error); QUICPacketUPtr _dequeue_recv_packet(QUICPacketCreationResult &result); + int _complete_handshake_if_possible(); + void _switch_to_handshake_state(); void _switch_to_established_state(); + void _switch_to_closing_state(); + void _switch_to_close_state(); QUICStatelessToken _token; }; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2e148c33a3b..9522cc31aa1 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -302,8 +302,7 @@ QUICNetVConnection::close(QUICConnectionErrorUPtr error) this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closing)) { // do nothing } else { - DebugQUICCon("Enter state_connection_closing"); - SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); + this->_switch_to_closing_state(); if (error->cls == QUICErrorClass::APPLICATION) { this->transmit_frame(QUICFrameFactory::create_application_close_frame(std::move(error))); } else { @@ -336,9 +335,7 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) // BLOCKED frame is for debugging. Nothing to do here. break; case QUICFrameType::CONNECTION_CLOSE: - DebugQUICCon("Enter state_connection_closed"); - SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); - this_ethread()->schedule_imm(this, QUIC_EVENT_SHUTDOWN, nullptr); + this->_switch_to_close_state(); break; default: DebugQUICCon("Unexpected frame type: %02x", static_cast(frame->type())); @@ -370,8 +367,7 @@ QUICNetVConnection::state_pre_handshake(int event, Event *data) this->set_inactivity_timeout(HRTIME_SECONDS(params->no_activity_timeout_in())); this->add_to_active_queue(); - DebugQUICCon("Enter state_handshake"); - SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_handshake); + this->_switch_to_handshake_state(); return this->handleEvent(event, data); } @@ -383,7 +379,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) if (this->_handshake_handler && this->_handshake_handler->is_completed()) { this->_switch_to_established_state(); - return this->state_connection_established(event, data); + return this->handleEvent(event, data); } QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); @@ -485,9 +481,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) // FIXME Enter closed state if CONNECTION_CLOSE was ACKed if (true) { - DebugQUICCon("Enter state_connection_closed"); - SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); - this_ethread()->schedule_imm(this, QUIC_EVENT_SHUTDOWN, nullptr); + this->_switch_to_close_state(); } return EVENT_DONE; @@ -974,9 +968,17 @@ QUICNetVConnection::_close_packet_write_ready(Event *data) this->_packet_write_ready = nullptr; } -void -QUICNetVConnection::_switch_to_established_state() +int +QUICNetVConnection::_complete_handshake_if_possible() { + if (this->handler != reinterpret_cast(&QUICNetVConnection::state_handshake)) { + return 0; + } + + if (!(this->_handshake_handler && this->_handshake_handler->is_completed())) { + return -1; + } + this->_init_flow_control_params(this->_handshake_handler->local_transport_parameters(), this->_handshake_handler->remote_transport_parameters()); @@ -995,6 +997,45 @@ QUICNetVConnection::_switch_to_established_state() endpoint->handleEvent(NET_EVENT_ACCEPT, this); } - DebugQUICCon("Enter state_connection_established"); - SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); + return 0; +} + +void +QUICNetVConnection::_switch_to_handshake_state() +{ + DebugQUICCon("Enter state_handshake"); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_handshake); +} + +void +QUICNetVConnection::_switch_to_established_state() +{ + if (this->_complete_handshake_if_possible() == 0) { + DebugQUICCon("Enter state_connection_established"); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); + } else { + // Illegal state change + ink_assert(!"Handshake has to be completed"); + } +} + +void +QUICNetVConnection::_switch_to_closing_state() +{ + if (this->_complete_handshake_if_possible() != 0) { + DebugQUICCon("Switching state without handshake completion"); + } + DebugQUICCon("Enter state_connection_closing"); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); +} + +void +QUICNetVConnection::_switch_to_close_state() +{ + if (this->_complete_handshake_if_possible() != 0) { + DebugQUICCon("Switching state without handshake completion"); + } + DebugQUICCon("Enter state_connection_closed"); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); + this_ethread()->schedule_imm(this, QUIC_EVENT_SHUTDOWN, nullptr); } From f1782a09965733c3d9e3fba2d69d44a7d91405ea Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Dec 2017 11:27:09 +0900 Subject: [PATCH 0201/1313] Fix a test for flow control --- iocore/net/quic/test/test_QUICStreamManager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 9af5433e0d5..3a143dff5fa 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -126,7 +126,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") // total_offset should be a integer in unit of 1024 octets std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); sm.handle_frame(stream_frame_1); - CHECK(sm.total_offset_received() == 1); + CHECK(sm.total_offset_received() == 1024); } TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") From 437bb7c5574037ef52d912e649933ae90fdc2dab Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Dec 2017 15:28:43 +0900 Subject: [PATCH 0202/1313] Fix a bug that data on streams can be corrupted --- iocore/net/quic/QUICIncomingFrameBuffer.cc | 11 +++++++++-- iocore/net/quic/QUICIncomingFrameBuffer.h | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index 797b7b92821..8975bc69a5b 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -69,9 +69,9 @@ QUICIncomingFrameBuffer::insert(const std::shared_ptr fra return QUICErrorUPtr(new QUICNoError()); } else if (this->_recv_offset == offset) { this->_recv_offset = offset + len; - this->_recv_buffer.push(frame); + this->_recv_buffer.push(this->_clone(frame)); } else { - this->_out_of_order_queue.insert(std::make_pair(offset, frame)); + this->_out_of_order_queue.insert(std::make_pair(offset, this->_clone(frame))); } return QUICErrorUPtr(new QUICNoError()); @@ -97,6 +97,13 @@ QUICIncomingFrameBuffer::empty() return this->_out_of_order_queue.empty() && this->_recv_buffer.empty(); } +std::shared_ptr +QUICIncomingFrameBuffer::_clone(std::shared_ptr frame) +{ + return QUICFrameFactory::create_stream_frame(frame->data(), frame->data_length(), frame->stream_id(), frame->offset(), + frame->has_fin_flag()); +} + QUICErrorUPtr QUICIncomingFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, bool fin_flag) { diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index 66b637a6b67..5ecfb6ec8d8 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -37,6 +37,9 @@ class QUICIncomingFrameBuffer std::shared_ptr pop(); + /* + * Becasue frames passed by FrameDispatcher is temporal, this clones a passed frame to ensure that we can use it later. + */ QUICErrorUPtr insert(const std::shared_ptr); void clear(); @@ -48,6 +51,7 @@ class QUICIncomingFrameBuffer QUICOffset _max_offset = 0; QUICOffset _fin_offset = UINT64_MAX; + std::shared_ptr _clone(std::shared_ptr frame); QUICErrorUPtr _check_and_set_fin_flag(QUICOffset offset, size_t len = 0, bool fin_flag = false); std::queue> _recv_buffer; From 877d9ff1f2f867ca184e83fae4fde41ec1d8c910 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Dec 2017 16:29:10 +0900 Subject: [PATCH 0203/1313] Fix a crash on idle timeout --- iocore/net/P_QUICNetVConnection.h | 4 +++- iocore/net/QUICNetVConnection.cc | 39 +++++++++++++++++-------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index c80a2b6f95c..77b13f1a950 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -260,9 +260,11 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection int _complete_handshake_if_possible(); void _switch_to_handshake_state(); void _switch_to_established_state(); - void _switch_to_closing_state(); + void _switch_to_closing_state(QUICConnectionErrorUPtr error); void _switch_to_close_state(); + void _handle_idle_timeout(); + QUICStatelessToken _token; }; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 9522cc31aa1..97ec7b6f682 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -302,12 +302,7 @@ QUICNetVConnection::close(QUICConnectionErrorUPtr error) this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closing)) { // do nothing } else { - this->_switch_to_closing_state(); - if (error->cls == QUICErrorClass::APPLICATION) { - this->transmit_frame(QUICFrameFactory::create_application_close_frame(std::move(error))); - } else { - this->transmit_frame(QUICFrameFactory::create_connection_close_frame(std::move(error))); - } + this->_switch_to_closing_state(std::move(error)); } } @@ -403,11 +398,8 @@ QUICNetVConnection::state_handshake(int event, Event *data) break; } case EVENT_IMMEDIATE: - // Start Implicit Shutdown. Because of no network activity for the duration of the idle timeout. - this->remove_from_active_queue(); - this->close(std::make_unique()); - - // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application + // Start Immediate Close because of Idle Timeout + this->_handle_idle_timeout(); break; default: DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); @@ -436,11 +428,8 @@ QUICNetVConnection::state_connection_established(int event, Event *data) break; } case EVENT_IMMEDIATE: { - // Start Implicit Shutdown. Because of no network activity for the duration of the idle timeout. - this->remove_from_active_queue(); - this->close(std::make_unique()); - - // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application + // Start Immediate Close because of Idle Timeout + this->_handle_idle_timeout(); break; } default: @@ -479,7 +468,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); } - // FIXME Enter closed state if CONNECTION_CLOSE was ACKed + // FIXME Enter closed state if CONNECTION_CLOSE was ACKed and draining period end if (true) { this->_switch_to_close_state(); } @@ -1020,11 +1009,16 @@ QUICNetVConnection::_switch_to_established_state() } void -QUICNetVConnection::_switch_to_closing_state() +QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) { if (this->_complete_handshake_if_possible() != 0) { DebugQUICCon("Switching state without handshake completion"); } + if (error->cls == QUICErrorClass::APPLICATION) { + this->transmit_frame(QUICFrameFactory::create_application_close_frame(std::move(error))); + } else { + this->transmit_frame(QUICFrameFactory::create_connection_close_frame(std::move(error))); + } DebugQUICCon("Enter state_connection_closing"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); } @@ -1039,3 +1033,12 @@ QUICNetVConnection::_switch_to_close_state() SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); this_ethread()->schedule_imm(this, QUIC_EVENT_SHUTDOWN, nullptr); } + +void +QUICNetVConnection::_handle_idle_timeout() +{ + this->remove_from_active_queue(); + this->close(std::make_unique(QUICTransErrorCode::NO_ERROR, "Idle Timeout")); + + // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application +} From 35512a6c852a2f2bfd66336d9b273b311471bcfd Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Dec 2017 11:38:21 +0900 Subject: [PATCH 0204/1313] Fix packet retransmission --- iocore/net/QUICNetVConnection.cc | 9 +++++++-- iocore/net/quic/QUICFrame.cc | 1 + iocore/net/quic/QUICPacket.cc | 10 +++++----- iocore/net/quic/QUICPacket.h | 4 ++-- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 97ec7b6f682..6de22684087 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -232,10 +232,12 @@ QUICNetVConnection::transmit_packet(QUICPacketUPtr packet) void QUICNetVConnection::retransmit_packet(const QUICPacket &packet) { + DebugQUICCon("Retransmit packet #%" PRIu64 " type %s", packet.packet_number(), QUICDebugNames::packet_type(packet.type())); ink_assert(packet.type() != QUICPacketType::VERSION_NEGOTIATION && packet.type() != QUICPacketType::UNINITIALIZED); - uint16_t size = packet.payload_size(); - const uint8_t *payload = packet.payload(); + // Get payload from a header because packet.payload() is encrypted + uint16_t size = packet.header()->payload_size(); + const uint8_t *payload = packet.header()->payload(); QUICFrameUPtr frame(nullptr, &QUICFrameDeleter::delete_null_frame); uint16_t cursor = 0; @@ -629,6 +631,9 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPt if (error->cls != QUICErrorClass::NONE) { return error; } + } else { + // Perhaps response packets for initial client packet were lost, but no need to start handshake again because loss detector will + // retransmit the packets. } return error; } diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index a9b4520e803..3bb8822e999 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1311,6 +1311,7 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stop_sending_frame); default: // Unknown frame + Debug("quic_frame_factory", "Unknown frame type %x", buf[0]); return QUICFrameUPtr(nullptr, &QUICFrameDeleter::delete_null_frame); } } diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 2d59871a79a..9bc6f515c12 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -694,7 +694,7 @@ QUICPacketFactory::create_server_cleartext_packet(QUICConnectionId connection_id QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::SERVER_CLEARTEXT, connection_id, this->_packet_number_generator.next(), base_packet_number, this->_version, std::move(payload), len); - return this->_create_encrypted_packet(header); + return this->_create_encrypted_packet(header, retransmittable); } QUICPacketUPtr @@ -705,7 +705,7 @@ QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, connection_id, this->_packet_number_generator.next(), base_packet_number, std::move(payload), len); - return this->_create_encrypted_packet(header); + return this->_create_encrypted_packet(header, retransmittable); } QUICPacketUPtr @@ -715,7 +715,7 @@ QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::CLIENT_INITIAL, connection_id, this->_packet_number_generator.next(), base_packet_number, version, std::move(payload), len); - return this->_create_encrypted_packet(header); + return this->_create_encrypted_packet(header, true); } QUICPacketUPtr @@ -755,7 +755,7 @@ QUICPacketFactory::_create_unprotected_packet(QUICPacketHeader *header) } QUICPacketUPtr -QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header) +QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header, bool retransmittable) { // TODO: use pmtu of UnixNetVConnection size_t max_cipher_txt_len = 2048; @@ -766,7 +766,7 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header) if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, false); + new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, retransmittable); } return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 8668da57e1b..98803ec034b 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -126,7 +126,7 @@ class QUICPacketHeader size_t _buf_len = 0; // These are used only if the instance was created without a buffer - uint8_t _serialized[16]; + uint8_t _serialized[17]; ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); QUICPacketType _type = QUICPacketType::UNINITIALIZED; QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; @@ -307,5 +307,5 @@ class QUICPacketFactory QUICPacketNumberGenerator _packet_number_generator; static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeader *header); - QUICPacketUPtr _create_encrypted_packet(QUICPacketHeader *header); + QUICPacketUPtr _create_encrypted_packet(QUICPacketHeader *header, bool retransmittable); }; From 3e3938fc972276cb82dffd84bda421fc4bf7185c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 4 Dec 2017 12:20:54 +0900 Subject: [PATCH 0205/1313] Add error logs of quic --- iocore/net/QUICNetVConnection.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6de22684087..2b11e82e883 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -46,6 +46,10 @@ #define DebugQUICCon(fmt, ...) \ Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) +#define QUICError(fmt, ...) \ + Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__); \ + Error("quic_net [%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) + static constexpr uint32_t MAX_PACKET_OVERHEAD = 17; // Max long header len(17) static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; static constexpr uint32_t MINIMUM_INITIAL_CLIENT_PACKET_SIZE = 1200; @@ -877,11 +881,11 @@ void QUICNetVConnection::_handle_error(QUICErrorUPtr error) { if (error->cls == QUICErrorClass::APPLICATION) { - DebugQUICCon("QUICError: %s (%u), APPLICATION ERROR (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls), - static_cast(error->cls), error->code()); + QUICError("QUICError: %s (%u), APPLICATION ERROR (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), error->code()); } else { - DebugQUICCon("QUICError: %s (%u), %s (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls), - static_cast(error->cls), QUICDebugNames::error_code(error->trans_error_code), error->code()); + QUICError("QUICError: %s (%u), %s (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), QUICDebugNames::error_code(error->trans_error_code), error->code()); } if (dynamic_cast(error.get()) != nullptr) { From a648bb52fba52c2176e3151fe1968b1808f3745f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Dec 2017 12:58:59 +0900 Subject: [PATCH 0206/1313] Use std::atomic to generate packet numbers --- iocore/net/QUICNetVConnection.cc | 5 +++-- iocore/net/quic/QUICPacket.h | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2b11e82e883..3c8f028d710 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -219,9 +219,10 @@ QUICNetVConnection::stream_manager() void QUICNetVConnection::_transmit_packet(QUICPacketUPtr packet) { - DebugQUICCon("Packet Type=%s Size=%hu", QUICDebugNames::packet_type(packet->type()), packet->size()); - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); + + DebugQUICCon("Packet Number=%" PRIu64 " Type=%s Size=%hu", packet->packet_number(), QUICDebugNames::packet_type(packet->type()), + packet->size()); // TODO Remove const_cast this->_packet_send_queue.enqueue(const_cast(packet.release())); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 98803ec034b..0f374c33ed6 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include #include "ts/List.h" @@ -260,7 +261,7 @@ class QUICPacketNumberGenerator QUICPacketNumber next(); private: - QUICPacketNumber _current = 0; + std::atomic _current; }; using QUICPacketDeleterFunc = void (*)(QUICPacket *p); From 3f0a35bc4ccf44e5fabeac40c1cd6ce4c8c6897f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 4 Dec 2017 14:42:41 +0900 Subject: [PATCH 0207/1313] Fix big file transfer --- proxy/hq/HQClientTransaction.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 8c168d5c54c..b30522e7430 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -266,7 +266,13 @@ HQClientTransaction::_write_response() if (this->_write_vio.ntodo() == 0) { this->_stream_io->shutdown(); } + this->_stream_io->write_reenable(); + + // Send back WRITE_READY event to HttpTunnel + if (this->_write_vio.ntodo() > 0 && this->_write_vio.get_writer()->write_avail()) { + this->_write_vio._cont->handleEvent(VC_EVENT_WRITE_READY, &this->_write_vio); + } } void From b9c256cda794194ec6d25cc55f7983b52f4335f9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Dec 2017 15:28:09 +0900 Subject: [PATCH 0208/1313] Don't return QUICError from FlowController --- iocore/net/QUICNetVConnection.cc | 18 +++++++++--------- iocore/net/quic/QUICFlowController.cc | 14 +++++++------- iocore/net/quic/QUICFlowController.h | 8 ++++++-- iocore/net/quic/QUICStream.cc | 13 +++++++------ 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3c8f028d710..00d34472bc2 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -629,12 +629,12 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPt if (error->cls != QUICErrorClass::NONE) { return error; } - error = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); + int ret = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); - if (error->cls != QUICErrorClass::NONE) { - return error; + if (ret != 0) { + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } } else { // Perhaps response packets for initial client packet were lost, but no need to start handshake again because loss detector will @@ -769,13 +769,13 @@ QUICNetVConnection::_packetize_frames() const QUICFrameUPtr &f = this->_stream_frame_send_queue.front(); uint32_t frame_size = f->size(); - QUICErrorUPtr error = this->_remote_flow_controller->update((this->_stream_manager->total_offset_sent() + frame_size)); + int ret = this->_remote_flow_controller->update((this->_stream_manager->total_offset_sent() + frame_size)); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); - if (error->cls != QUICErrorClass::NONE) { - // Flow Contoroller blocked sending STREAM frame + if (ret != 0) { + DebugQUICCon("Flow Controller blocked sending a STREAM frame"); break; } @@ -813,11 +813,11 @@ QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPac return error; } - error = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); + int ret = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); - if (error->cls != QUICErrorClass::NONE) { - return error; + if (ret != 0) { + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } // this->_local_flow_controller->forward_limit(); diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 68e01c569a6..7c8f0802d40 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -40,18 +40,18 @@ QUICFlowController::current_limit() return this->_limit; } -QUICErrorUPtr +int QUICFlowController::update(QUICOffset offset) { if (this->_offset <= offset) { // Assume flow control is not initialized if the limit was 0 if (this->_limit != 0 && offset > this->_limit) { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); + return -1; } this->_offset = offset; } - return QUICErrorUPtr(new QUICNoError()); + return 0; } void @@ -81,14 +81,14 @@ QUICRemoteFlowController::forward_limit(QUICOffset offset) this->_blocked = false; } -QUICErrorUPtr +int QUICRemoteFlowController::update(QUICOffset offset) { - QUICErrorUPtr error = QUICFlowController::update(offset); + int ret = QUICFlowController::update(offset); // Assume flow control is not initialized if the limit was 0 if (this->_limit == 0) { - return error; + return ret; } // Send BLOCKED(_STREAM) frame @@ -97,7 +97,7 @@ QUICRemoteFlowController::update(QUICOffset offset) this->_blocked = true; } - return error; + return ret; } // diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index d195728ec46..6a56aa369a9 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -33,7 +33,11 @@ class QUICFlowController public: QUICOffset current_offset(); QUICOffset current_limit(); - virtual QUICErrorUPtr update(QUICOffset offset); + + /* + * Returns 0 if succeed + */ + virtual int update(QUICOffset offset); virtual void forward_limit(QUICOffset limit); void set_threshold(uint64_t threshold); @@ -51,7 +55,7 @@ class QUICRemoteFlowController : public QUICFlowController { public: QUICRemoteFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICFlowController(initial_limit, tx) {} - QUICErrorUPtr update(QUICOffset offset) override; + int update(QUICOffset offset) override; void forward_limit(QUICOffset limit) override; private: diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 1017a9f2dc2..429c804b22d 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -305,14 +305,14 @@ QUICStream::recv(const std::shared_ptr frame) } // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit - QUICErrorUPtr error = this->_local_flow_controller->update(frame->offset() + frame->data_length()); + int ret = this->_local_flow_controller->update(frame->offset() + frame->data_length()); DebugQUICStreamFC("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); - if (error->cls != QUICErrorClass::NONE) { - return error; + if (ret != 0) { + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } - error = this->_received_stream_frame_buffer.insert(frame); + QUICErrorUPtr error = this->_received_stream_frame_buffer.insert(frame); if (error->cls != QUICErrorClass::NONE) { this->_received_stream_frame_buffer.clear(); return error; @@ -379,10 +379,11 @@ QUICStream::_send() } } - error = this->_remote_flow_controller->update(this->_send_offset + len); + int ret = this->_remote_flow_controller->update(this->_send_offset + len); DebugQUICStreamFC("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); - if (error->cls != QUICErrorClass::NONE) { + if (ret != 0) { + DebugQUICStream("Flow Controller blocked sending a STREAM frame"); break; } From 16eca8226501a1292d934d35e8cf3e618eebd910 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Dec 2017 15:33:11 +0900 Subject: [PATCH 0209/1313] Fix a bug that QUICStream can consume window without sending frames --- iocore/net/quic/QUICStream.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 429c804b22d..1f6a6c4784f 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -379,6 +379,13 @@ QUICStream::_send() } } + QUICStreamFrameUPtr frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, + this->_id, this->_send_offset, fin); + if (!this->_state.is_allowed_to_send(*frame)) { + DebugQUICStream("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); + break; + } + int ret = this->_remote_flow_controller->update(this->_send_offset + len); DebugQUICStreamFC("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); @@ -386,19 +393,13 @@ QUICStream::_send() DebugQUICStream("Flow Controller blocked sending a STREAM frame"); break; } - - QUICStreamFrameUPtr frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, - this->_id, this->_send_offset, fin); + // We cannot cancel sending the frame after updating the flow controller this->_send_offset += len; reader->consume(len); this->_write_vio.ndone += len; total_len += len; - if (!this->_state.is_allowed_to_send(*frame)) { - DebugQUICStream("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); - break; - } this->_state.update_with_sent_frame(*frame); this->_tx->transmit_frame(std::move(frame)); } From d481634760331f8206ef8aa09fe9046fb04134f0 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Dec 2017 17:38:13 +0900 Subject: [PATCH 0210/1313] Reduce number of events for loss detection --- iocore/net/quic/QUICLossDetector.cc | 14 +++++++++----- iocore/net/quic/QUICLossDetector.h | 6 ++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 41bb3fcf00d..7466d56257f 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -48,7 +48,9 @@ QUICLossDetector::event_handler(int event, Event *edata) { switch (event) { case EVENT_INTERVAL: { - this->_on_loss_detection_alarm(); + if (this->_loss_detection_alarm_at <= Thread::get_hrtime()) { + this->_on_loss_detection_alarm(); + } break; } case QUIC_EVENT_LD_SHUTDOWN: { @@ -278,6 +280,7 @@ QUICLossDetector::_set_loss_detection_alarm() { ink_hrtime alarm_duration; if (!this->_retransmittable_outstanding && this->_loss_detection_alarm) { + this->_loss_detection_alarm_at = 0; this->_loss_detection_alarm->cancel(); this->_loss_detection_alarm = nullptr; DebugQUICLD("Loss detection alarm has been unset"); @@ -314,11 +317,12 @@ QUICLossDetector::_set_loss_detection_alarm() DebugQUICLD("RTO alarm will be set"); } - if (this->_loss_detection_alarm) { - this->_loss_detection_alarm->cancel(); - } - this->_loss_detection_alarm = eventProcessor.schedule_in(this, alarm_duration); + this->_loss_detection_alarm_at = Thread::get_hrtime() + alarm_duration; DebugQUICLD("Loss detection alarm has been set to %" PRId64, alarm_duration); + + if (!this->_loss_detection_alarm) { + this->_loss_detection_alarm = eventProcessor.schedule_every(this, HRTIME_MSECONDS(100)); + } } std::set diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index a899f995991..16e5c6437dc 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -96,6 +96,12 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler uint32_t _retransmittable_outstanding = 0; void _decrement_packet_count(QUICPacketNumber packet_number); + /* + * Because this alarm will be reset on every packet transmission, to reduce number of events, + * Loss Detector uses schedule_every() and checks if it has to be triggered. + */ + ink_hrtime _loss_detection_alarm_at = 0; + void _on_packet_sent(QUICPacketNumber packet_number, bool is_retransmittable, bool is_handshake, size_t sent_bytes, QUICPacketUPtr packet); void _on_ack_received(const std::shared_ptr &ack_frame); From 7fcb88e2330696d357da60ea7698ea6c1f7b8914 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 5 Dec 2017 10:50:00 +0900 Subject: [PATCH 0211/1313] Update tests for Flow Controller --- .../net/quic/test/test_QUICFlowController.cc | 123 +++++++++--------- 1 file changed, 60 insertions(+), 63 deletions(-) diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index 17a94727f2a..b2a04c87a07 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -29,7 +29,7 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") { - std::unique_ptr error = nullptr; + int ret = 0; MockQUICFrameTransmitter tx; QUICLocalConnectionFlowController fc(1024, &tx); @@ -37,39 +37,38 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") CHECK(fc.current_offset() == 0); CHECK(fc.current_limit() == 1024); - error = fc.update(256); + ret = fc.update(256); CHECK(fc.current_offset() == 256); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); - error = fc.update(512); + ret = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); // Retransmit - error = fc.update(512); + ret = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); - error = fc.update(1024); + ret = fc.update(1024); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); // Delay - error = fc.update(512); + ret = fc.update(512); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); // Exceed limit - error = fc.update(1280); + ret = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::TRANSPORT); - CHECK(error->trans_error_code == QUICTransErrorCode::FLOW_CONTROL_ERROR); + CHECK(ret != 0); // MAX_STREAM_DATA CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_DATA)] == 0); @@ -78,15 +77,15 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") CHECK(fc.current_limit() == 2048); CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_DATA)] == 1); - error = fc.update(1280); + ret = fc.update(1280); CHECK(fc.current_offset() == 1280); CHECK(fc.current_limit() == 2048); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); } TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") { - std::unique_ptr error = nullptr; + int ret = 0; MockQUICFrameTransmitter tx; QUICRemoteConnectionFlowController fc(1024, &tx); @@ -94,39 +93,39 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") CHECK(fc.current_offset() == 0); CHECK(fc.current_limit() == 1024); - error = fc.update(256); + ret = fc.update(256); CHECK(fc.current_offset() == 256); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); - error = fc.update(512); + ret = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); // Retransmit - error = fc.update(512); + ret = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); - error = fc.update(1024); + ret = fc.update(1024); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); // Delay - error = fc.update(512); + ret = fc.update(512); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); // Exceed limit CHECK(tx.frameCount[static_cast(QUICFrameType::BLOCKED)] == 0); - error = fc.update(1280); + ret = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->cls != QUICErrorClass::NONE); + CHECK(ret != 0); CHECK(tx.frameCount[static_cast(QUICFrameType::BLOCKED)] == 1); // MAX_STREAM_DATA @@ -134,15 +133,15 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 2048); - error = fc.update(1280); + ret = fc.update(1280); CHECK(fc.current_offset() == 1280); CHECK(fc.current_limit() == 2048); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); } TEST_CASE("QUICFlowController_Local_Stream", "[quic]") { - std::unique_ptr error = nullptr; + int ret = 0; MockQUICFrameTransmitter tx; QUICLocalStreamFlowController fc(1024, &tx, 0); @@ -150,39 +149,38 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]") CHECK(fc.current_offset() == 0); CHECK(fc.current_limit() == 1024); - error = fc.update(256); + ret = fc.update(256); CHECK(fc.current_offset() == 256); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); - error = fc.update(512); + ret = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); // Retransmit - error = fc.update(512); + ret = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); - error = fc.update(1024); + ret = fc.update(1024); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); // Delay - error = fc.update(512); + ret = fc.update(512); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); // Exceed limit - error = fc.update(1280); + ret = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::TRANSPORT); - CHECK(error->trans_error_code == QUICTransErrorCode::FLOW_CONTROL_ERROR); + CHECK(ret != 0); // MAX_STREAM_DATA CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_STREAM_DATA)] == 0); @@ -191,15 +189,15 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]") CHECK(fc.current_limit() == 2048); CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_STREAM_DATA)] == 1); - error = fc.update(1280); + ret = fc.update(1280); CHECK(fc.current_offset() == 1280); CHECK(fc.current_limit() == 2048); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); } TEST_CASE("QUICFlowController_Remote_Stream", "[quic]") { - std::unique_ptr error = nullptr; + int ret = 0; MockQUICFrameTransmitter tx; QUICRemoteStreamFlowController fc(1024, &tx, 0); @@ -207,48 +205,47 @@ TEST_CASE("QUICFlowController_Remote_Stream", "[quic]") CHECK(fc.current_offset() == 0); CHECK(fc.current_limit() == 1024); - error = fc.update(256); + ret = fc.update(256); CHECK(fc.current_offset() == 256); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); - error = fc.update(512); + ret = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); // Retransmit - error = fc.update(512); + ret = fc.update(512); CHECK(fc.current_offset() == 512); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); - error = fc.update(1024); + ret = fc.update(1024); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); // Delay - error = fc.update(512); + ret = fc.update(512); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); // Exceed limit CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM_BLOCKED)] == 0); - error = fc.update(1280); + ret = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); - CHECK(error->cls != QUICErrorClass::NONE); - CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM_BLOCKED)] == 1); + CHECK(ret != 0); // MAX_STREAM_DATA fc.forward_limit(2048); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 2048); - error = fc.update(1280); + ret = fc.update(1280); CHECK(fc.current_offset() == 1280); CHECK(fc.current_limit() == 2048); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(ret == 0); } From d7cce37efb9cb68361793bf62e965fba263c2fe3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 5 Dec 2017 10:57:33 +0900 Subject: [PATCH 0212/1313] Fix a bug that QUICPacket doesn't return packet size correctly --- iocore/net/quic/QUICPacket.cc | 6 ++- iocore/net/quic/test/test_QUICPacket.cc | 51 ++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 9bc6f515c12..bb8c08a7ab9 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -534,7 +534,11 @@ uint16_t QUICPacket::size() const { // This includes not only header size and payload size but also AEAD tag length - return this->_header->packet_size(); + uint16_t size = this->_header->packet_size(); + if (size == 0) { + size = this->header_size() + this->payload_size(); + } + return size; } uint16_t diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index e2d78638f9f..8a39c5739c3 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -27,7 +27,7 @@ TEST_CASE("QUICPacketHeader", "[quic]") { - SECTION("Long Header") + SECTION("Long Header (load)") { const uint8_t input[] = { 0x81, // Long header, Type @@ -41,12 +41,35 @@ TEST_CASE("QUICPacketHeader", "[quic]") CHECK(header->size() == 17); CHECK(header->packet_size() == 19); CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); + CHECK(header->has_connection_id() == true); CHECK(header->connection_id() == 0x0102030405060708); CHECK(header->packet_number() == 0x12345678); + CHECK(header->has_version() == true); CHECK(header->version() == 0x11223344); + CHECK(header->has_key_phase() == false); } - SECTION("Short Header") + SECTION("Long Header (build)") + { + const uint8_t expected[] = {0x11, 0x22, 0x33, 0x44, 0x55}; + ats_unique_buf payload = ats_unique_malloc(sizeof(expected)); + memcpy(payload.get(), expected, sizeof(expected)); + + QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::CLIENT_INITIAL, 0x0102030405060708, 0x12345678, 0, + 0xa0a0a0a0, std::move(payload), 32); + + CHECK(header->size() == 17); + CHECK(header->has_key_phase() == false); + CHECK(header->packet_size() == 0); + CHECK(header->type() == QUICPacketType::CLIENT_INITIAL); + CHECK(header->has_connection_id() == true); + CHECK(header->connection_id() == 0x0102030405060708); + CHECK(header->packet_number() == 0x12345678); + CHECK(header->has_version() == true); + CHECK(header->version() == 0xa0a0a0a0); + } + + SECTION("Short Header (load)") { const uint8_t input[] = { 0x43, // Short header, with Connection ID, KeyPhse 0, Type @@ -58,8 +81,32 @@ TEST_CASE("QUICPacketHeader", "[quic]") QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); CHECK(header->size() == 13); CHECK(header->packet_size() == 15); + CHECK(header->has_key_phase() == true); + CHECK(header->key_phase() == QUICKeyPhase::PHASE_0); + CHECK(header->has_connection_id() == true); + CHECK(header->connection_id() == 0x0102030405060708); + CHECK(header->packet_number() == 0x12345678); + CHECK(header->has_version() == false); + } + + SECTION("Short Header (build)") + { + const uint8_t expected[] = {0x11, 0x22, 0x33, 0x44, 0x55}; + ats_unique_buf payload = ats_unique_malloc(sizeof(expected)); + memcpy(payload.get(), expected, sizeof(expected)); + + QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, 0x0102030405060708, + 0x12345678, 0, std::move(payload), 32); + + CHECK(header->size() == 13); + CHECK(header->packet_size() == 0); + CHECK(header->has_key_phase() == true); + CHECK(header->key_phase() == QUICKeyPhase::PHASE_0); + CHECK(header->type() == QUICPacketType::PROTECTED); + CHECK(header->has_connection_id() == true); CHECK(header->connection_id() == 0x0102030405060708); CHECK(header->packet_number() == 0x12345678); + CHECK(header->has_version() == false); } } From 67e1eeb39bdbe177656251cfa3d7492494569bc9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 5 Dec 2017 11:50:10 +0900 Subject: [PATCH 0213/1313] Rename DebugQUIC*() to QUIC*Debug() --- iocore/net/QUICNetVConnection.cc | 48 ++++++++++++++--------------- iocore/net/quic/QUICHandshake.cc | 36 +++++++++++----------- iocore/net/quic/QUICLossDetector.cc | 24 +++++++-------- iocore/net/quic/QUICStream.cc | 30 +++++++++--------- 4 files changed, 69 insertions(+), 69 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 00d34472bc2..2d5e32dc872 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -43,7 +43,7 @@ #define STATE_FROM_VIO(_x) ((NetState *)(((char *)(_x)) - STATE_VIO_OFFSET)) #define STATE_VIO_OFFSET ((uintptr_t) & ((NetState *)0)->vio) -#define DebugQUICCon(fmt, ...) \ +#define QUICConDebug(fmt, ...) \ Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) #define QUICError(fmt, ...) \ @@ -126,7 +126,7 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) void QUICNetVConnection::free(EThread *t) { - DebugQUICCon("Free connection"); + QUICConDebug("Free connection"); this->_udp_con = nullptr; this->_packet_handler = nullptr; @@ -221,7 +221,7 @@ QUICNetVConnection::_transmit_packet(QUICPacketUPtr packet) { SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); - DebugQUICCon("Packet Number=%" PRIu64 " Type=%s Size=%hu", packet->packet_number(), QUICDebugNames::packet_type(packet->type()), + QUICConDebug("Packet Number=%" PRIu64 " Type=%s Size=%hu", packet->packet_number(), QUICDebugNames::packet_type(packet->type()), packet->size()); // TODO Remove const_cast this->_packet_send_queue.enqueue(const_cast(packet.release())); @@ -237,7 +237,7 @@ QUICNetVConnection::transmit_packet(QUICPacketUPtr packet) void QUICNetVConnection::retransmit_packet(const QUICPacket &packet) { - DebugQUICCon("Retransmit packet #%" PRIu64 " type %s", packet.packet_number(), QUICDebugNames::packet_type(packet.type())); + QUICConDebug("Retransmit packet #%" PRIu64 " type %s", packet.packet_number(), QUICDebugNames::packet_type(packet.type())); ink_assert(packet.type() != QUICPacketType::VERSION_NEGOTIATION && packet.type() != QUICPacketType::UNINITIALIZED); // Get payload from a header because packet.payload() is encrypted @@ -278,7 +278,7 @@ QUICNetVConnection::push_packet(UDPPacket *packet) void QUICNetVConnection::_transmit_frame(QUICFrameUPtr frame) { - DebugQUICCon("Frame Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); + QUICConDebug("Frame Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); @@ -340,7 +340,7 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) this->_switch_to_close_state(); break; default: - DebugQUICCon("Unexpected frame type: %02x", static_cast(frame->type())); + QUICConDebug("Unexpected frame type: %02x", static_cast(frame->type())); ink_assert(false); break; } @@ -409,7 +409,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) this->_handle_idle_timeout(); break; default: - DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); + QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); } if (error->cls != QUICErrorClass::NONE) { @@ -440,11 +440,11 @@ QUICNetVConnection::state_connection_established(int event, Event *data) break; } default: - DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); + QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); } if (error->cls != QUICErrorClass::NONE) { - DebugQUICCon("QUICError: cls=%u, code=0x%" PRIu16, static_cast(error->cls), error->code()); + QUICConDebug("QUICError: cls=%u, code=0x%" PRIu16, static_cast(error->cls), error->code()); this->_handle_error(std::move(error)); } @@ -472,7 +472,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) break; } default: - DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); + QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); } // FIXME Enter closed state if CONNECTION_CLOSE was ACKed and draining period end @@ -507,7 +507,7 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) break; } default: - DebugQUICCon("Unexpected event: %s", QUICDebugNames::quic_event(event)); + QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); } return EVENT_DONE; @@ -616,7 +616,7 @@ QUICErrorUPtr QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPtr packet) { if (packet->size() < MINIMUM_INITIAL_CLIENT_PACKET_SIZE) { - DebugQUICCon("Packet size is smaller than the minimum initial client packet size"); + QUICConDebug("Packet size is smaller than the minimum initial client packet size"); // Ignore the packet return QUICErrorUPtr(new QUICNoError()); } @@ -736,7 +736,7 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans } size_t l = 0; - DebugQUICCon("type=%s", QUICDebugNames::frame_type(frame->type())); + QUICConDebug("type=%s", QUICDebugNames::frame_type(frame->type())); frame->store(buf.get() + len, &l); len += l; @@ -775,7 +775,7 @@ QUICNetVConnection::_packetize_frames() this->_remote_flow_controller->current_limit()); if (ret != 0) { - DebugQUICCon("Flow Controller blocked sending a STREAM frame"); + QUICConDebug("Flow Controller blocked sending a STREAM frame"); break; } @@ -922,17 +922,17 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) } quic_packet = this->_packet_factory.create(std::move(pkt), written, this->largest_received_packet_number(), result); if (result == QUICPacketCreationResult::NOT_READY) { - DebugQUICCon("Not ready to decrypt the packet"); + QUICConDebug("Not ready to decrypt the packet"); // Retry later this->_packet_recv_queue.enqueue(udp_packet); this_ethread()->schedule_in_local(this, HRTIME_MSECONDS(10), QUIC_EVENT_PACKET_READ_READY); } else { udp_packet->free(); if (result == QUICPacketCreationResult::SUCCESS) { - DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), + QUICConDebug("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), quic_packet->packet_number(), quic_packet->size()); } else { - DebugQUICCon("Failed to decrypt the packet"); + QUICConDebug("Failed to decrypt the packet"); } } @@ -944,7 +944,7 @@ QUICNetVConnection::_schedule_packet_write_ready() { SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); if (!this->_packet_write_ready) { - DebugQUICCon("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); + QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); } } @@ -1002,7 +1002,7 @@ QUICNetVConnection::_complete_handshake_if_possible() void QUICNetVConnection::_switch_to_handshake_state() { - DebugQUICCon("Enter state_handshake"); + QUICConDebug("Enter state_handshake"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_handshake); } @@ -1010,7 +1010,7 @@ void QUICNetVConnection::_switch_to_established_state() { if (this->_complete_handshake_if_possible() == 0) { - DebugQUICCon("Enter state_connection_established"); + QUICConDebug("Enter state_connection_established"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); } else { // Illegal state change @@ -1022,14 +1022,14 @@ void QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) { if (this->_complete_handshake_if_possible() != 0) { - DebugQUICCon("Switching state without handshake completion"); + QUICConDebug("Switching state without handshake completion"); } if (error->cls == QUICErrorClass::APPLICATION) { this->transmit_frame(QUICFrameFactory::create_application_close_frame(std::move(error))); } else { this->transmit_frame(QUICFrameFactory::create_connection_close_frame(std::move(error))); } - DebugQUICCon("Enter state_connection_closing"); + QUICConDebug("Enter state_connection_closing"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); } @@ -1037,9 +1037,9 @@ void QUICNetVConnection::_switch_to_close_state() { if (this->_complete_handshake_if_possible() != 0) { - DebugQUICCon("Switching state without handshake completion"); + QUICConDebug("Switching state without handshake completion"); } - DebugQUICCon("Enter state_connection_closed"); + QUICConDebug("Enter state_connection_closed"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); this_ethread()->schedule_imm(this, QUIC_EVENT_SHUTDOWN, nullptr); } diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 052f0edc01f..3637feb03fb 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -32,7 +32,7 @@ static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; -#define DebugQHS(fmt, ...) \ +#define QUICHSDebug(fmt, ...) \ Debug("quic_handshake", "[%" PRIx64 "] " fmt, static_cast(this->_client_qc->connection_id()), ##__VA_ARGS__) #define I_WANNA_DUMP_THIS_BUF(buf, len) \ @@ -111,12 +111,12 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet } if (initial_packet->version()) { if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { - DebugQHS("Version negotiation succeeded: %x", initial_packet->version()); + QUICHSDebug("Version negotiation succeeded: %x", initial_packet->version()); packet_factory->set_version(this->_version_negotiator->negotiated_version()); } else { this->_client_qc->transmit_packet( packet_factory->create_version_negotiation_packet(initial_packet, _client_qc->largest_acked_packet_number())); - DebugQHS("Version negotiation failed: %x", initial_packet->version()); + QUICHSDebug("Version negotiation failed: %x", initial_packet->version()); } } else { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); @@ -170,11 +170,11 @@ QUICHandshake::set_transport_parameters(std::shared_ptr // Version revalidation if (this->_version_negotiator->revalidate(tp_in_ch) != QUICVersionNegotiationStatus::REVALIDATED) { this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR))); - DebugQHS("Enter state_closed"); + QUICHSDebug("Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); return; } - DebugQHS("Version negotiation revalidated: %x", tp_in_ch->negotiated_version()); + QUICHSDebug("Version negotiation revalidated: %x", tp_in_ch->negotiated_version()); return; } @@ -209,7 +209,7 @@ QUICHandshake::state_read_client_hello(int event, Event *data) break; } default: - DebugQHS("event: %d", event); + QUICHSDebug("event: %d", event); break; } @@ -219,7 +219,7 @@ QUICHandshake::state_read_client_hello(int event, Event *data) } else { this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION))); } - DebugQHS("Enter state_closed"); + QUICHSDebug("Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); } @@ -237,7 +237,7 @@ QUICHandshake::state_read_client_finished(int event, Event *data) break; } default: - DebugQHS("event: %d", event); + QUICHSDebug("event: %d", event); break; } @@ -247,7 +247,7 @@ QUICHandshake::state_read_client_finished(int event, Event *data) } else { this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION))); } - DebugQHS("Enter state_closed"); + QUICHSDebug("Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); } @@ -264,8 +264,8 @@ QUICHandshake::state_address_validation(int event, void *data) int QUICHandshake::state_complete(int event, void *data) { - DebugQHS("event: %d", event); - DebugQHS("Got an event on complete state. Ignoring it for now."); + QUICHSDebug("event: %d", event); + QUICHSDebug("Got an event on complete state. Ignoring it for now."); return EVENT_CONT; } @@ -319,7 +319,7 @@ QUICHandshake::_process_client_hello() stream_io->read(msg, msg_len); if (msg_len <= 0) { - DebugQHS("No message"); + QUICHSDebug("No message"); return QUICErrorUPtr(new QUICNoError()); } @@ -337,7 +337,7 @@ QUICHandshake::_process_client_hello() I_WANNA_DUMP_THIS_BUF(server_hello, static_cast(server_hello_len)); // <----- DEBUG ----- - DebugQHS("Enter state_read_client_finished"); + QUICHSDebug("Enter state_read_client_finished"); SET_HANDLER(&QUICHandshake::state_read_client_finished); stream_io->write(server_hello, server_hello_len); @@ -361,7 +361,7 @@ QUICHandshake::_process_client_finished() stream_io->read(msg, msg_len); if (msg_len <= 0) { - DebugQHS("No message"); + QUICHSDebug("No message"); return QUICErrorUPtr(new QUICNoError()); } @@ -380,9 +380,9 @@ QUICHandshake::_process_client_finished() // <----- DEBUG ----- _process_handshake_complete(); - DebugQHS("Handshake has been completed"); + QUICHSDebug("Handshake has been completed"); - DebugQHS("Enter state_complete"); + QUICHSDebug("Enter state_complete"); SET_HANDLER(&QUICHandshake::state_complete); stream_io->write(out, out_len); @@ -399,9 +399,9 @@ QUICErrorUPtr QUICHandshake::_process_handshake_complete() { if (this->_crypto->update_key_materials()) { - DebugQHS("Keying Materials are exported"); + QUICHSDebug("Keying Materials are exported"); } else { - DebugQHS("Failed to export Keying Materials"); + QUICHSDebug("Failed to export Keying Materials"); } return QUICErrorUPtr(new QUICNoError()); diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 7466d56257f..672679bf64d 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -25,7 +25,7 @@ #include "QUICEvents.h" #include "ts/ink_assert.h" -#define DebugQUICLD(fmt, ...) \ +#define QUICLDDebug(fmt, ...) \ Debug("quic_loss_detector", "[%" PRIx64 "] " fmt, static_cast(this->_connection_id), ##__VA_ARGS__) QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter) : _transmitter(transmitter) @@ -55,7 +55,7 @@ QUICLossDetector::event_handler(int event, Event *edata) } case QUIC_EVENT_LD_SHUTDOWN: { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - DebugQUICLD("Shutdown"); + QUICLDDebug("Shutdown"); if (this->_loss_detection_alarm) { this->_loss_detection_alarm->cancel(); @@ -84,7 +84,7 @@ QUICLossDetector::handle_frame(std::shared_ptr frame) this->_on_ack_received(std::dynamic_pointer_cast(frame)); break; default: - DebugQUICLD("Unexpected frame type: %02x", static_cast(frame->type())); + QUICLDDebug("Unexpected frame type: %02x", static_cast(frame->type())); ink_assert(false); break; } @@ -200,7 +200,7 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac } this->_detect_lost_packets(ack_frame->largest_acknowledged()); - DebugQUICLD("Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, this->_retransmittable_outstanding); + QUICLDDebug("Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, this->_retransmittable_outstanding); this->_set_loss_detection_alarm(); } @@ -208,7 +208,7 @@ void QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - DebugQUICLD("Packet number %" PRIu64 " has been acked", acked_packet_number); + QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number); // If a packet sent prior to RTO was acked, then the RTO // was spurious. Otherwise, inform congestion control. if (this->_rto_count > 0 && acked_packet_number > this->_largest_sent_before_rto) { @@ -258,7 +258,7 @@ QUICLossDetector::_on_loss_detection_alarm() // eventProcessor.schedule_imm(this->_handler, ET_CALL, QUIC_EVENT_RETRANSMIT_TWO_PACKET); this->_rto_count++; } - DebugQUICLD("Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, this->_retransmittable_outstanding); + QUICLDDebug("Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, this->_retransmittable_outstanding); this->_set_loss_detection_alarm(); } @@ -283,7 +283,7 @@ QUICLossDetector::_set_loss_detection_alarm() this->_loss_detection_alarm_at = 0; this->_loss_detection_alarm->cancel(); this->_loss_detection_alarm = nullptr; - DebugQUICLD("Loss detection alarm has been unset"); + QUICLDDebug("Loss detection alarm has been unset"); return; } if (this->_handshake_outstanding) { @@ -295,11 +295,11 @@ QUICLossDetector::_set_loss_detection_alarm() } alarm_duration = std::max(alarm_duration, this->_MIN_TLP_TIMEOUT); alarm_duration = alarm_duration * (1 << this->_handshake_count); - DebugQUICLD("Handshake retransmission alarm will be set"); + QUICLDDebug("Handshake retransmission alarm will be set"); } else if (this->_loss_time != 0) { // Early retransmit timer or time loss detection. alarm_duration = this->_loss_time - Thread::get_hrtime(); - DebugQUICLD("Early retransmit timer or time loss detection will be set"); + QUICLDDebug("Early retransmit timer or time loss detection will be set"); } else if (this->_tlp_count < this->_MAX_TLPS) { // Tail Loss Probe if (this->_retransmittable_outstanding) { @@ -308,17 +308,17 @@ QUICLossDetector::_set_loss_detection_alarm() alarm_duration = this->_MIN_TLP_TIMEOUT; } alarm_duration = std::max(alarm_duration, 2 * this->_smoothed_rtt); - DebugQUICLD("TLP alarm will be set"); + QUICLDDebug("TLP alarm will be set"); } else { // RTO alarm alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar; alarm_duration = std::max(alarm_duration, this->_MIN_RTO_TIMEOUT); alarm_duration = alarm_duration * (1 << this->_rto_count); - DebugQUICLD("RTO alarm will be set"); + QUICLDDebug("RTO alarm will be set"); } this->_loss_detection_alarm_at = Thread::get_hrtime() + alarm_duration; - DebugQUICLD("Loss detection alarm has been set to %" PRId64, alarm_duration); + QUICLDDebug("Loss detection alarm has been set to %" PRId64, alarm_duration); if (!this->_loss_detection_alarm) { this->_loss_detection_alarm = eventProcessor.schedule_every(this, HRTIME_MSECONDS(100)); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 1f6a6c4784f..8c9822d0d21 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -28,10 +28,10 @@ #include "QUICDebugNames.h" #include "QUICConfig.h" -#define DebugQUICStream(fmt, ...) \ +#define QUICStreamDebug(fmt, ...) \ Debug("quic_stream", "[%" PRIx64 "] [%" PRIx32 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) -#define DebugQUICStreamFC(fmt, ...) \ +#define QUICStreamFCDebug(fmt, ...) \ Debug("quic_flow_ctrl", "[%" PRIx64 "] [%" PRIx32 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) @@ -47,7 +47,7 @@ QUICStream::init(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId si this->_local_flow_controller = new QUICLocalStreamFlowController(recv_max_stream_data, _tx, _id); this->init_flow_control_params(recv_max_stream_data, send_max_stream_data); - DebugQUICStream("Initialized"); + QUICStreamDebug("Initialized"); } void @@ -62,9 +62,9 @@ QUICStream::init_flow_control_params(uint32_t recv_max_stream_data, uint32_t sen this->_flow_control_buffer_size = recv_max_stream_data; this->_local_flow_controller->forward_limit(recv_max_stream_data); this->_remote_flow_controller->forward_limit(send_max_stream_data); - DebugQUICStreamFC("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); - DebugQUICStreamFC("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); } @@ -84,7 +84,7 @@ QUICStream::final_offset() int QUICStream::main_event_handler(int event, void *data) { - DebugQUICStream("%s", QUICDebugNames::vc_event(event)); + QUICStreamDebug("%s", QUICDebugNames::vc_event(event)); QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); switch (event) { @@ -111,17 +111,17 @@ QUICStream::main_event_handler(int event, void *data) break; } default: - DebugQUICStream("unknown event"); + QUICStreamDebug("unknown event"); ink_assert(false); } if (error->cls != QUICErrorClass::NONE) { if (error->cls == QUICErrorClass::TRANSPORT) { - DebugQUICStream("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), + QUICStreamDebug("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), static_cast(error->cls), QUICDebugNames::error_code(error->trans_error_code), static_cast(error->trans_error_code)); } else { - DebugQUICStream("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls), + QUICStreamDebug("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls), static_cast(error->cls), static_cast(error->app_error_code)); } if (dynamic_cast(error.get()) != nullptr) { @@ -281,7 +281,7 @@ QUICStream::_write_to_read_vio(const std::shared_ptr &fra this->_read_vio.nbytes += bytes_added; // frame->offset() + frame->data_length() == this->_recv_offset this->_local_flow_controller->forward_limit(frame->offset() + frame->data_length() + this->_flow_control_buffer_size); - DebugQUICStreamFC("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); this->_state.update_with_received_frame(*frame); @@ -306,7 +306,7 @@ QUICStream::recv(const std::shared_ptr frame) // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit int ret = this->_local_flow_controller->update(frame->offset() + frame->data_length()); - DebugQUICStreamFC("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); if (ret != 0) { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); @@ -331,7 +331,7 @@ QUICErrorUPtr QUICStream::recv(const std::shared_ptr frame) { this->_remote_flow_controller->forward_limit(frame->maximum_stream_data()); - DebugQUICStreamFC("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); this->reenable(&this->_write_vio); @@ -382,15 +382,15 @@ QUICStream::_send() QUICStreamFrameUPtr frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, this->_id, this->_send_offset, fin); if (!this->_state.is_allowed_to_send(*frame)) { - DebugQUICStream("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); + QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); break; } int ret = this->_remote_flow_controller->update(this->_send_offset + len); - DebugQUICStreamFC("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); if (ret != 0) { - DebugQUICStream("Flow Controller blocked sending a STREAM frame"); + QUICStreamDebug("Flow Controller blocked sending a STREAM frame"); break; } // We cannot cancel sending the frame after updating the flow controller From 9576d280286361a61832eb0e9ff1a2e86947aebf Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 17 Nov 2017 10:59:46 +0800 Subject: [PATCH 0214/1313] fix #2793 rework quic ack creator --- iocore/net/quic/QUICAckFrameCreator.cc | 110 ++++++++++++++---- iocore/net/quic/QUICAckFrameCreator.h | 28 ++++- .../net/quic/test/test_QUICAckFrameCreator.cc | 74 ++++++++++++ 3 files changed, 183 insertions(+), 29 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index f352d83a391..89b9525cfbb 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -28,14 +28,11 @@ int QUICAckFrameCreator::update(QUICPacketNumber packet_number, bool acknowledgable) { - if (this->_packet_count == MAXIMUM_PACKET_COUNT) { + if (this->_packet_numbers.size() == MAXIMUM_PACKET_COUNT) { return -1; } - if (packet_number > this->_largest_ack_number) { - this->_largest_ack_number = packet_number; - this->_largest_ack_received_time = Thread::get_hrtime(); - } - this->_packet_numbers[this->_packet_count++] = packet_number - this->_last_ack_number; + + this->_packet_numbers.push_back(packet_number); if (acknowledgable && !this->_can_send) { this->_can_send = true; } @@ -48,10 +45,10 @@ QUICAckFrameCreator::create() { std::unique_ptr ack_frame = {nullptr, QUICFrameDeleter::delete_null_frame}; if (this->_can_send) { - ack_frame = this->_create_ack_frame(); - this->_last_ack_number = this->_largest_ack_number; - this->_can_send = false; - this->_packet_count = 0; + ack_frame = this->_create_ack_frame(); + this->_can_send = false; + this->_packet_count = 0; + this->_packet_numbers.clear(); } return ack_frame; } @@ -67,37 +64,102 @@ void QUICAckFrameCreator::_sort_packet_numbers() { // TODO Find more smart way - std::sort(this->_packet_numbers, this->_packet_numbers + this->_packet_count); } std::unique_ptr QUICAckFrameCreator::_create_ack_frame() { std::unique_ptr ack_frame = {nullptr, QUICFrameDeleter::delete_null_frame}; - this->_sort_packet_numbers(); - uint16_t start = this->_packet_numbers[0]; - uint8_t gap = 0; - int i; + this->_packet_numbers.sort(); + QUICPacketNumber largest_ack_number = this->_packet_numbers.largest_ack_number(); + QUICPacketNumber last_ack_number = largest_ack_number; + + size_t i = 0; + uint8_t gap = 0; uint64_t length = 0; - for (i = 0, length = 0; i < this->_packet_count; ++i, ++length) { - if (this->_packet_numbers[i] == start + length) { + + while (i < this->_packet_numbers.size()) { + if (this->_packet_numbers[i] == last_ack_number) { + last_ack_number--; + length++; + i++; continue; } + if (ack_frame) { ack_frame->ack_block_section()->add_ack_block({gap, length}); } else { - uint16_t delay = (Thread::get_hrtime() - this->_largest_ack_received_time) / 1000; // TODO Milliseconds? - ack_frame = QUICFrameFactory::create_ack_frame(this->_largest_ack_number, delay, length); + uint16_t delay = (Thread::get_hrtime() - this->_packet_numbers.largest_ack_received_time()) / 1000; // TODO Milliseconds? + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length); } - gap = this->_packet_numbers[i] - this->_packet_numbers[i - 1] - 1; - start = this->_packet_numbers[i]; - length = 0; + + gap = last_ack_number - this->_packet_numbers[i]; + last_ack_number = this->_packet_numbers[i]; + length = 0; } + if (ack_frame) { ack_frame->ack_block_section()->add_ack_block({gap, length}); } else { - uint16_t delay = (Thread::get_hrtime() - this->_largest_ack_received_time) / 1000; // TODO Milliseconds? - ack_frame = QUICFrameFactory::create_ack_frame(this->_largest_ack_number, delay, length); + uint16_t delay = (Thread::get_hrtime() - this->_packet_numbers.largest_ack_received_time()) / 1000; // TODO Milliseconds? + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length); } return ack_frame; } + +void +QUICAckPacketNumbers::push_back(QUICPacketNumber packet_number) +{ + if (packet_number > this->_largest_ack_number) { + this->_largest_ack_received_time = Thread::get_hrtime(); + this->_largest_ack_number = packet_number; + } + + this->_packet_numbers.push_back(packet_number); +} + +QUICPacketNumber +QUICAckPacketNumbers::front() +{ + return this->_packet_numbers.front(); +} + +QUICPacketNumber +QUICAckPacketNumbers::back() +{ + return this->_packet_numbers.back(); +} + +size_t +QUICAckPacketNumbers::size() +{ + return this->_packet_numbers.size(); +} + +void +QUICAckPacketNumbers::clear() +{ + this->_packet_numbers.clear(); + this->_largest_ack_number = 0; + this->_largest_ack_received_time = 0; +} + +QUICPacketNumber +QUICAckPacketNumbers::largest_ack_number() +{ + return this->_largest_ack_number; +} + +ink_hrtime +QUICAckPacketNumbers::largest_ack_received_time() +{ + return this->_largest_ack_received_time; +} + +void +QUICAckPacketNumbers::sort() +{ + // TODO Find more smart way + std::sort(this->_packet_numbers.begin(), this->_packet_numbers.end(), + [](QUICPacketNumber a, QUICPacketNumber b) -> bool { return b < a; }); +} diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 7251747a375..da59c5ef121 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -27,6 +27,28 @@ #include "QUICTypes.h" #include "QUICFrame.h" +class QUICAckPacketNumbers +{ +public: + void push_back(QUICPacketNumber packet_number); + QUICPacketNumber front(); + QUICPacketNumber back(); + size_t size(); + void clear(); + void sort(); + + QUICPacketNumber largest_ack_number(); + ink_hrtime largest_ack_received_time(); + + const QUICPacketNumber &operator[](int i) const { return this->_packet_numbers[i]; } + +private: + QUICPacketNumber _largest_ack_number = 0; + ink_hrtime _largest_ack_received_time = 0; + + std::vector _packet_numbers; +}; + class QUICAckFrameCreator { public: @@ -57,11 +79,7 @@ class QUICAckFrameCreator private: bool _can_send = false; - QUICPacketNumber _largest_ack_number = 0; - QUICPacketNumber _last_ack_number = 0; - ink_hrtime _largest_ack_received_time = 0; - - uint16_t _packet_numbers[MAXIMUM_PACKET_COUNT]; + QUICAckPacketNumbers _packet_numbers; uint16_t _packet_count = 0; void _sort_packet_numbers(); diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index a5196879c9c..1ca0691dadd 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -64,6 +64,80 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame != nullptr); CHECK(frame->num_blocks() == 1); CHECK(frame->largest_acknowledged() == 10); + CHECK(frame->ack_block_section()->first_ack_block_length() == 1); + CHECK(frame->ack_block_section()->begin()->gap() == 2); +} + +TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") +{ + QUICAckFrameCreator creator; + std::unique_ptr frame = {nullptr, nullptr}; + + // Initial state + frame = creator.create(); + CHECK(frame == nullptr); + + creator.update(2, true); + creator.update(5, true); + creator.update(6, true); + creator.update(8, true); + creator.update(9, true); + + frame = creator.create(); + CHECK(frame != nullptr); + CHECK(frame->num_blocks() == 2); + CHECK(frame->largest_acknowledged() == 9); CHECK(frame->ack_block_section()->first_ack_block_length() == 2); + CHECK(frame->ack_block_section()->begin()->gap() == 1); + + frame = creator.create(); + CHECK(frame == nullptr); + + creator.update(7, true); + creator.update(4, true); + frame = creator.create(); + CHECK(frame != nullptr); + CHECK(frame->num_blocks() == 1); + CHECK(frame->largest_acknowledged() == 7); + CHECK(frame->ack_block_section()->first_ack_block_length() == 1); CHECK(frame->ack_block_section()->begin()->gap() == 2); } + +TEST_CASE("QUICAckFrameCreator_QUICAckPacketNumbers", "[quic]") +{ + QUICAckPacketNumbers packet_numbers; + + CHECK(packet_numbers.size() == 0); + CHECK(packet_numbers.largest_ack_number() == 0); + CHECK(packet_numbers.largest_ack_received_time() == 0); + + Thread::get_hrtime_updated(); + + packet_numbers.push_back(3); + CHECK(packet_numbers.size() == 1); + CHECK(packet_numbers.largest_ack_number() == 3); + + ink_hrtime ti = packet_numbers.largest_ack_received_time(); + CHECK(packet_numbers.largest_ack_received_time() != 0); + + Thread::get_hrtime_updated(); + + packet_numbers.push_back(2); + CHECK(packet_numbers.size() == 2); + CHECK(packet_numbers.largest_ack_number() == 3); + CHECK(packet_numbers.largest_ack_received_time() == ti); + + Thread::get_hrtime_updated(); + + packet_numbers.push_back(10); + CHECK(packet_numbers.size() == 3); + CHECK(packet_numbers.largest_ack_number() == 10); + CHECK(packet_numbers.largest_ack_received_time() > ti); + + Thread::get_hrtime_updated(); + + packet_numbers.clear(); + CHECK(packet_numbers.size() == 0); + CHECK(packet_numbers.largest_ack_number() == 0); + CHECK(packet_numbers.largest_ack_received_time() == 0); +} From c327d2a40434a1a925a01cbb68de8a43bdfcb597 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 6 Dec 2017 10:13:59 +0900 Subject: [PATCH 0215/1313] Transfer huge response using HttpTunnel flow control mechanism --- iocore/net/quic/QUICApplication.cc | 24 +++++++++++++++++++++--- iocore/net/quic/QUICApplication.h | 8 ++------ iocore/net/quic/QUICStream.cc | 16 +++++++++++++++- proxy/hq/HQClientSession.cc | 12 ++++++++++++ proxy/hq/HQClientSession.h | 1 + proxy/hq/HQClientTransaction.cc | 16 ++++++++++++++++ proxy/hq/QUICSimpleApp.cc | 5 ++++- 7 files changed, 71 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 5d5a0ed485c..eca747fd6d3 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -71,10 +71,22 @@ QUICStreamIO::write(IOBufferReader *r, int64_t alen, int64_t offset) { SCOPED_MUTEX_LOCK(lock, this->_write_vio->mutex, this_ethread()); - int64_t bytes_add = this->_write_buffer->write(r, alen, offset); - this->_write_vio->nbytes += bytes_add; + if (this->_write_buffer->write_avail() > 0) { + int64_t bytes_add = this->_write_buffer->write(r, alen, offset); - return bytes_add; + return bytes_add; + + } else { + Debug(tag, "write buffer is full"); + + return 0; + } +} + +void +QUICStreamIO::set_write_vio_nbytes(int64_t nbytes) +{ + this->_write_vio->nbytes += nbytes; } void @@ -101,6 +113,12 @@ QUICStreamIO::shutdown() return this->_stream->shutdown(); } +uint32_t +QUICStreamIO::get_transaction_id() const +{ + return this->_stream->id(); +} + // // QUICApplication // diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 8094a4e2a6f..17e32e9dab5 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -43,16 +43,12 @@ class QUICStreamIO int64_t read(uint8_t *buf, int64_t len); int64_t write(const uint8_t *buf, int64_t len); int64_t write(IOBufferReader *r, int64_t len = INT64_MAX, int64_t offset = 0); + void set_write_vio_nbytes(int64_t); void read_reenable(); void write_reenable(); IOBufferReader *get_read_buffer_reader(); void shutdown(); - - int - get_transaction_id() const - { - return _stream->id(); - } + uint32_t get_transaction_id() const; private: QUICStream *_stream = nullptr; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 8c9822d0d21..0dc5cf0034c 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -101,6 +101,10 @@ QUICStream::main_event_handler(int event, void *data) this->_signal_write_event(true); this->_write_event = nullptr; + QUICStreamDebug("wvio.nbytes=%" PRId64 " wvio.ndone=%" PRId64 " wvio.read_avail=%" PRId64 " wvio.write_avail=%" PRId64, + this->_write_vio.nbytes, this->_write_vio.ndone, this->_write_vio.get_reader()->read_avail(), + this->_write_vio.get_writer()->write_avail()); + break; } case VC_EVENT_EOS: @@ -257,6 +261,11 @@ QUICStream::_signal_read_event(bool direct) void QUICStream::_signal_write_event(bool direct) { + if (this->_write_vio.get_writer()->write_avail() == 0) { + QUICStreamDebug("wvio.write_avail=0"); + return; + } + int event = (this->_write_vio.ntodo() == 0) ? VC_EVENT_WRITE_COMPLETE : VC_EVENT_WRITE_READY; Continuation *cont = this->_write_vio._cont; @@ -334,7 +343,11 @@ QUICStream::recv(const std::shared_ptr frame) QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); - this->reenable(&this->_write_vio); + // restart sending + QUICStreamDebug("restart sending"); + + this->_send(); + this->_signal_write_event(false); return QUICErrorUPtr(new QUICNoError()); } @@ -348,6 +361,7 @@ QUICStream::recv(const std::shared_ptr frame) /** * @brief Send STREAM DATA from _response_buffer + * @detail Call _signal_write_event() to indicate event upper layer */ QUICErrorUPtr QUICStream::_send() diff --git a/proxy/hq/HQClientSession.cc b/proxy/hq/HQClientSession.cc index 91b003599af..af4d9882e75 100644 --- a/proxy/hq/HQClientSession.cc +++ b/proxy/hq/HQClientSession.cc @@ -143,3 +143,15 @@ HQClientSession::add_transaction(HQClientTransaction *trans) this->_transaction_list.enqueue(trans); return; } + +// this->_transaction_list should be map? +HQClientTransaction * +HQClientSession::get_transaction(QUICStreamId id) +{ + for (HQClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { + if (t->get_transaction_id() == static_cast(id)) { + return t; + } + } + return nullptr; +} diff --git a/proxy/hq/HQClientSession.h b/proxy/hq/HQClientSession.h index 964be0adc3e..ccbae3d5daf 100644 --- a/proxy/hq/HQClientSession.h +++ b/proxy/hq/HQClientSession.h @@ -54,6 +54,7 @@ class HQClientSession : public ProxyClientSession // HQClientSession specific methods void add_transaction(HQClientTransaction *); + HQClientTransaction *get_transaction(QUICStreamId); private: NetVConnection *_client_vc = nullptr; diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index b30522e7430..cc3a2554516 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -28,6 +28,10 @@ #include "HQClientSession.h" #include "HttpSM.h" +// XXX this->parent->connection_id() is Session ID of HQClientSession. Should this be QUIC Connection ID? +#define HQTransDebug(fmt, ...) \ + Debug("hq_trans", "[%" PRId64 "] [%" PRIx32 "] " fmt, this->parent->connection_id(), this->get_transaction_id(), ##__VA_ARGS__) + static void dump_io_buffer(IOBufferReader *reader) { @@ -110,6 +114,11 @@ HQClientTransaction::main_event_handler(int event, void *edata) if (this->_write_vio.get_reader()->read_avail()) { this->_write_response(); } + + HQTransDebug("wvio.nbytes=%" PRId64 " wvio.ndone=%" PRId64 " wvio.read_avail=%" PRId64 " wvio.write_avail=%" PRId64, + this->_write_vio.nbytes, this->_write_vio.ndone, this->_write_vio.get_reader()->read_avail(), + this->_write_vio.get_writer()->write_avail()); + break; } default: @@ -241,6 +250,8 @@ static constexpr char http_1_1_version[] = "HTTP/1.1"; void HQClientTransaction::_write_response() { + SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); + IOBufferReader *reader = this->_write_vio.get_reader(); if (memcmp(reader->start(), http_1_1_version, sizeof(http_1_1_version) - 1) == 0) { @@ -249,6 +260,8 @@ HQClientTransaction::_write_response() int64_t headers_size = headers->read_avail(); reader->consume(headers_size); this->_write_vio.ndone += headers_size; + // The size of respons to client + this->_stream_io->set_write_vio_nbytes(this->_write_vio.nbytes - headers_size); } // Write HTTP/1.1 response body @@ -256,6 +269,9 @@ HQClientTransaction::_write_response() int64_t total_written = 0; while (total_written < bytes_avail) { int64_t bytes_written = this->_stream_io->write(reader, bytes_avail); + if (bytes_written == 0) { + break; + } reader->consume(bytes_written); this->_write_vio.ndone += bytes_written; total_written += bytes_written; diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index f7424d15882..a245642d7d0 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -76,7 +76,10 @@ QUICSimpleApp::main_event_handler(int event, Event *data) } case VC_EVENT_WRITE_READY: case VC_EVENT_WRITE_COMPLETE: { - // Nothing to do + HQClientTransaction *trans = this->_client_session->get_transaction(stream->id()); + + trans->handleEvent(event); + break; } case VC_EVENT_EOS: From 40c8e02cbceb10257ba7246bcc33084da564812e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Dec 2017 14:52:43 +0900 Subject: [PATCH 0216/1313] Fix a build issue --- iocore/net/quic/test/test_QUICAckFrameCreator.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 1ca0691dadd..025d90cbaad 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -23,6 +23,7 @@ #include "catch.hpp" +#include "I_EventSystem.h" #include "quic/QUICAckFrameCreator.h" TEST_CASE("QUICAckFrameCreator", "[quic]") From 331bfb36ec4bb3f91c93d4f1c858568bb26f50c8 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 6 Dec 2017 15:03:54 +0900 Subject: [PATCH 0217/1313] Check _write_vio is initialized --- iocore/net/quic/QUICStream.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 0dc5cf0034c..0d9214aaca4 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -343,11 +343,13 @@ QUICStream::recv(const std::shared_ptr frame) QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); - // restart sending - QUICStreamDebug("restart sending"); + if (this->_write_vio.op == VIO::WRITE) { + // restart sending + QUICStreamDebug("restart sending"); - this->_send(); - this->_signal_write_event(false); + this->_send(); + this->_signal_write_event(false); + } return QUICErrorUPtr(new QUICNoError()); } From e86b83ac32771808d9f4d8a4f7de937621615625 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Dec 2017 15:07:41 +0900 Subject: [PATCH 0218/1313] Implement ack block section parser --- iocore/net/quic/QUICFrame.cc | 29 +++++++---- iocore/net/quic/QUICFrame.h | 7 ++- iocore/net/quic/test/test_QUICFrame.cc | 71 ++++++++++++++++++++------ 3 files changed, 78 insertions(+), 29 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 3bb8822e999..1a1c151362a 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -496,26 +496,26 @@ QUICAckFrame::AckBlockSection::AckBlockSection(uint64_t first_ack_block_length) QUICAckFrame::AckBlock::AckBlock(const uint8_t *buf, uint8_t ack_block_length) { - uint8_t gap = buf[0]; - uint64_t length = QUICTypeUtil::read_nbytes_as_uint(buf + 1, ack_block_length); - this->_data = (static_cast(gap) << 56) + length; + this->_gap = buf[0]; + this->_length = QUICTypeUtil::read_nbytes_as_uint(buf + 1, ack_block_length); } QUICAckFrame::AckBlock::AckBlock(uint8_t gap, uint64_t length) { - this->_data = (static_cast(gap) << 56) + length; + this->_gap = gap; + this->_length = length; } uint8_t QUICAckFrame::AckBlock::gap() const { - return this->_data >> 56; + return this->_gap; } uint64_t QUICAckFrame::AckBlock::length() const { - return this->_data & 0x0000FFFFFFFFFFFF; + return this->_length; } uint8_t @@ -558,7 +558,11 @@ QUICAckFrame::AckBlockSection::store(uint8_t *buf, size_t *len) const uint64_t QUICAckFrame::AckBlockSection::first_ack_block_length() const { - return this->_first_ack_block_length; + if (this->_buf) { + return QUICTypeUtil::read_nbytes_as_uint(this->_buf, this->_ack_block_length); + } else { + return this->_first_ack_block_length; + } } void @@ -590,9 +594,14 @@ QUICAckFrame::AckBlockSection::end() const QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, const uint8_t *buf, uint8_t num_blocks, uint8_t ack_block_length) { - this->_index = index; - this->_buf = buf; - this->_current_block = AckBlock(buf, ack_block_length); + this->_index = index; + this->_buf = buf; + this->_ack_block_length = ack_block_length; + if (index < num_blocks) { + this->_current_block = AckBlock(buf + ack_block_length + (1 + ack_block_length) * index, ack_block_length); + } else { + this->_current_block = {static_cast(0), 0ULL}; + } } QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, const std::vector *ack_block) diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 43c52b5b109..2acacb45b6f 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -102,7 +102,8 @@ class QUICAckFrame : public QUICFrame LINK(QUICAckFrame::AckBlock, link); private: - uint64_t _data = 0; + uint8_t _gap = 0; + uint64_t _length = 0; }; class AckBlockSection @@ -121,7 +122,8 @@ class QUICAckFrame : public QUICFrame ++(this->_index); if (this->_buf) { - // TODO Parse Ack Block + this->_current_block = + AckBlock(this->_buf + this->_ack_block_length + (1 + this->_ack_block_length) * this->_index, this->_ack_block_length); } else { if (this->_ack_blocks->size() == this->_index) { this->_current_block = {static_cast(0), 0ULL}; @@ -148,6 +150,7 @@ class QUICAckFrame : public QUICFrame private: uint8_t _index; const uint8_t *_buf; + uint8_t _ack_block_length; const std::vector *_ack_blocks = nullptr; QUICAckFrame::AckBlock _current_block = {static_cast(0), 0ULL}; }; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 1e2969c2dc1..84a6fbb329a 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -237,23 +237,60 @@ TEST_CASE("Store STREAM Frame", "[quic]") TEST_CASE("Load Ack Frame 1", "[quic]") { - // 0 Ack Block, 8 bit packet number length, 8 bit block length - uint8_t buf1[] = { - 0xA0, // 101NLLMM - 0x12, // Largest Acknowledged - 0x34, 0x56, // Ack Delay - 0x00, // Ack Block Section - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::ACK); - CHECK(frame1->size() == 5); - std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(ackFrame1 != nullptr); - CHECK(ackFrame1->has_ack_blocks() == false); - CHECK(ackFrame1->largest_acknowledged() == 0x12); - CHECK(ackFrame1->ack_delay() == 0x3456); - - // TODO: 1 Ack Block + SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") + { + uint8_t buf1[] = { + 0xA0, // 101NLLMM + 0x12, // Largest Acknowledged + 0x34, 0x56, // Ack Delay + 0x00, // Ack Block Section + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::ACK); + CHECK(frame1->size() == 5); + std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(ackFrame1 != nullptr); + CHECK(ackFrame1->has_ack_blocks() == false); + CHECK(ackFrame1->largest_acknowledged() == 0x12); + CHECK(ackFrame1->ack_delay() == 0x3456); + } + + SECTION("2 Ack Block, 8 bit packet number length, 8 bit block length") + { + uint8_t buf1[] = { + 0xB0, // 101NLLMM + 0x02, // Num Blocks + 0x12, // Largest Acknowledged + 0x34, 0x56, // Ack Delay + 0x01, // Ack Block Section (First ACK Block Length) + 0x02, // Ack Block Section (Gap 1) + 0x03, // Ack Block Section (ACK Block 1 Length) + 0x04, // Ack Block Section (Gap 2) + 0x05, // Ack Block Section (ACK Block 2 Length) + }; + + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::ACK); + CHECK(frame1->size() == 10); + std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(ackFrame1 != nullptr); + CHECK(ackFrame1->largest_acknowledged() == 0x12); + CHECK(ackFrame1->ack_delay() == 0x3456); + CHECK(ackFrame1->num_blocks() == 2); + CHECK(ackFrame1->has_ack_blocks() == true); + const QUICAckFrame::AckBlockSection *section = ackFrame1->ack_block_section(); + CHECK(section->first_ack_block_length() == 0x01); + auto ite = section->begin(); + CHECK(ite != section->end()); + CHECK(ite->gap() == 2); + CHECK(ite->length() == 3); + ++ite; + CHECK(ite != section->end()); + CHECK(ite->gap() == 4); + CHECK(ite->length() == 5); + ++ite; + CHECK(ite == section->end()); + } } TEST_CASE("Load Ack Frame 2", "[quic]") From a300d3a828916ce1ec8b6bf5ee818ce4a327bc28 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Dec 2017 15:37:00 +0900 Subject: [PATCH 0219/1313] Use ink_hrtime internally for RTT calculation --- iocore/net/quic/QUICLossDetector.cc | 14 ++++++++------ iocore/net/quic/QUICLossDetector.h | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 672679bf64d..ec3f452d96d 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -189,8 +189,9 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac auto pi = this->_sent_packets.find(ack_frame->largest_acknowledged()); if (pi != this->_sent_packets.end()) { this->_latest_rtt = Thread::get_hrtime() - pi->second->time; - if (this->_latest_rtt > ack_frame->ack_delay()) { - this->_latest_rtt -= ack_frame->ack_delay(); + // _latest_rtt is nanosecond but ack_frame->ack_delay is millisecond + if (this->_latest_rtt > HRTIME_MSECONDS(ack_frame->ack_delay())) { + this->_latest_rtt -= HRTIME_MSECONDS(ack_frame->ack_delay()); } this->_update_rtt(this->_latest_rtt); } @@ -248,22 +249,23 @@ QUICLossDetector::_on_loss_detection_alarm() this->_detect_lost_packets(this->_largest_acked_packet); } else if (this->_tlp_count < this->_MAX_TLPS) { // Tail Loss Probe. - // eventProcessor.schedule_imm(this->_handler, ET_CALL, QUIC_EVENT_RETRANSMIT_ONE_PACKET); + this->_send_one_packet(); this->_tlp_count++; } else { // RTO. if (this->_rto_count == 0) { this->_largest_sent_before_rto = this->_largest_sent_packet; } - // eventProcessor.schedule_imm(this->_handler, ET_CALL, QUIC_EVENT_RETRANSMIT_TWO_PACKET); + this->_send_two_packets(); this->_rto_count++; } - QUICLDDebug("Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, this->_retransmittable_outstanding); + QUICLDDebug("Unacked packets %lu (handshake pkt %u, retransmittable pkt %u)", this->_sent_packets.size(), + this->_handshake_outstanding.load(), this->_retransmittable_outstanding.load()); this->_set_loss_detection_alarm(); } void -QUICLossDetector::_update_rtt(uint32_t latest_rtt) +QUICLossDetector::_update_rtt(ink_hrtime latest_rtt) { // Based on {{RFC6298}}. if (this->_smoothed_rtt == 0) { diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 16e5c6437dc..3c4d0fda05f 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -86,7 +86,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler uint32_t _time_of_last_sent_packet = 0; ink_hrtime _latest_rtt = 0; ink_hrtime _smoothed_rtt = 0; - uint32_t _rttvar = 0; + ink_hrtime _rttvar = 0; uint32_t _reordering_threshold; double _time_reordering_fraction; ink_hrtime _loss_time = 0; @@ -106,7 +106,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler QUICPacketUPtr packet); void _on_ack_received(const std::shared_ptr &ack_frame); void _on_packet_acked(QUICPacketNumber acked_packet_number); - void _update_rtt(uint32_t latest_rtt); + void _update_rtt(ink_hrtime latest_rtt); void _detect_lost_packets(QUICPacketNumber largest_acked); void _set_loss_detection_alarm(); void _on_loss_detection_alarm(); From 8e8e57de7ce508ac6f53ee3178e7c0be713b4fda Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Dec 2017 15:56:59 +0900 Subject: [PATCH 0220/1313] Use std::atomic for packet counts in LossDetector --- iocore/net/quic/QUICLossDetector.cc | 27 ++++++++++++++++++++++----- iocore/net/quic/QUICLossDetector.h | 4 ++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index ec3f452d96d..b32aab23fa0 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -40,6 +40,9 @@ QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter) : _transm this->_time_reordering_fraction = INFINITY; } + this->_handshake_outstanding = 0; + this->_retransmittable_outstanding = 0; + SET_HANDLER(&QUICLossDetector::event_handler); } @@ -195,13 +198,26 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac } this->_update_rtt(this->_latest_rtt); } + + QUICLDDebug("Unacked packets %lu (handshake pkt %u, retransmittable %u, other %lu)", this->_sent_packets.size(), + this->_handshake_outstanding.load(), this->_retransmittable_outstanding.load(), + this->_sent_packets.size() - (this->_handshake_outstanding.load() + this->_retransmittable_outstanding.load())); + // Find all newly acked packets. for (auto acked_packet_number : this->_determine_newly_acked_packets(*ack_frame)) { this->_on_packet_acked(acked_packet_number); } + QUICLDDebug("Unacked packets %lu (handshake pkt %u, retransmittable %u, other %lu)", this->_sent_packets.size(), + this->_handshake_outstanding.load(), this->_retransmittable_outstanding.load(), + this->_sent_packets.size() - (this->_handshake_outstanding.load() + this->_retransmittable_outstanding.load())); + this->_detect_lost_packets(ack_frame->largest_acknowledged()); - QUICLDDebug("Unacked handshake pkt %u, retransmittable pkt %u", this->_handshake_outstanding, this->_retransmittable_outstanding); + + QUICLDDebug("Unacked packets %lu (handshake pkt %u, retransmittable %u, other %lu)", this->_sent_packets.size(), + this->_handshake_outstanding.load(), this->_retransmittable_outstanding.load(), + this->_sent_packets.size() - (this->_handshake_outstanding.load() + this->_retransmittable_outstanding.load())); + this->_set_loss_detection_alarm(); } @@ -249,18 +265,19 @@ QUICLossDetector::_on_loss_detection_alarm() this->_detect_lost_packets(this->_largest_acked_packet); } else if (this->_tlp_count < this->_MAX_TLPS) { // Tail Loss Probe. - this->_send_one_packet(); + // this->_send_one_packet(); this->_tlp_count++; } else { // RTO. if (this->_rto_count == 0) { this->_largest_sent_before_rto = this->_largest_sent_packet; } - this->_send_two_packets(); + // this->_send_two_packets(); this->_rto_count++; } - QUICLDDebug("Unacked packets %lu (handshake pkt %u, retransmittable pkt %u)", this->_sent_packets.size(), - this->_handshake_outstanding.load(), this->_retransmittable_outstanding.load()); + QUICLDDebug("Unacked packets %lu (handshake pkt %u, retransmittable %u, other %lu)", this->_sent_packets.size(), + this->_handshake_outstanding.load(), this->_retransmittable_outstanding.load(), + this->_sent_packets.size() - (this->_handshake_outstanding.load() + this->_retransmittable_outstanding.load())); this->_set_loss_detection_alarm(); } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 3c4d0fda05f..64702a96ab1 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -92,8 +92,8 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler ink_hrtime _loss_time = 0; std::map> _sent_packets; - uint32_t _handshake_outstanding = 0; - uint32_t _retransmittable_outstanding = 0; + std::atomic _handshake_outstanding; + std::atomic _retransmittable_outstanding; void _decrement_packet_count(QUICPacketNumber packet_number); /* From 76083d8bf0acdffe2faaacbd429a5712e970919e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Dec 2017 16:17:50 +0900 Subject: [PATCH 0221/1313] Fix loss detection timer --- iocore/net/quic/QUICLossDetector.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index b32aab23fa0..4a58690fe9a 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -336,7 +336,11 @@ QUICLossDetector::_set_loss_detection_alarm() QUICLDDebug("RTO alarm will be set"); } - this->_loss_detection_alarm_at = Thread::get_hrtime() + alarm_duration; + if (this->_loss_detection_alarm_at) { + this->_loss_detection_alarm_at = std::min(this->_loss_detection_alarm_at, Thread::get_hrtime() + alarm_duration); + } else { + this->_loss_detection_alarm_at = Thread::get_hrtime() + alarm_duration; + } QUICLDDebug("Loss detection alarm has been set to %" PRId64, alarm_duration); if (!this->_loss_detection_alarm) { From f0c333cec0aefb1421cfa5e24ba8e1a4f8a703eb Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Dec 2017 16:54:47 +0900 Subject: [PATCH 0222/1313] Fix a bug introduced with a300d3a828916ce1ec8b6bf5ee818ce4a327bc28 --- iocore/net/quic/QUICLossDetector.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 64702a96ab1..b7071fcb117 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -76,17 +76,17 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler ink_hrtime _DEFAULT_INITIAL_RTT = HRTIME_MSECONDS(100); // 3.2.2. Variables of interest - Action *_loss_detection_alarm = nullptr; - uint32_t _handshake_count = 0; - uint32_t _tlp_count = 0; - uint32_t _rto_count = 0; - uint32_t _largest_sent_before_rto = 0; - uint32_t _largest_sent_packet = 0; - uint32_t _largest_acked_packet = 0; - uint32_t _time_of_last_sent_packet = 0; - ink_hrtime _latest_rtt = 0; - ink_hrtime _smoothed_rtt = 0; - ink_hrtime _rttvar = 0; + Action *_loss_detection_alarm = nullptr; + uint32_t _handshake_count = 0; + uint32_t _tlp_count = 0; + uint32_t _rto_count = 0; + uint32_t _largest_sent_before_rto = 0; + uint32_t _largest_sent_packet = 0; + uint32_t _largest_acked_packet = 0; + ink_hrtime _time_of_last_sent_packet = 0; + ink_hrtime _latest_rtt = 0; + ink_hrtime _smoothed_rtt = 0; + ink_hrtime _rttvar = 0; uint32_t _reordering_threshold; double _time_reordering_fraction; ink_hrtime _loss_time = 0; From 3a1d008ac2d4fb1b19ee4f3aea7a55f0cdf86971 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Dec 2017 17:04:21 +0900 Subject: [PATCH 0223/1313] Fix debug log format --- iocore/net/quic/QUICLossDetector.cc | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 4a58690fe9a..ec197957ca7 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -199,24 +199,21 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac this->_update_rtt(this->_latest_rtt); } - QUICLDDebug("Unacked packets %lu (handshake pkt %u, retransmittable %u, other %lu)", this->_sent_packets.size(), - this->_handshake_outstanding.load(), this->_retransmittable_outstanding.load(), - this->_sent_packets.size() - (this->_handshake_outstanding.load() + this->_retransmittable_outstanding.load())); + QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), + this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); // Find all newly acked packets. for (auto acked_packet_number : this->_determine_newly_acked_packets(*ack_frame)) { this->_on_packet_acked(acked_packet_number); } - QUICLDDebug("Unacked packets %lu (handshake pkt %u, retransmittable %u, other %lu)", this->_sent_packets.size(), - this->_handshake_outstanding.load(), this->_retransmittable_outstanding.load(), - this->_sent_packets.size() - (this->_handshake_outstanding.load() + this->_retransmittable_outstanding.load())); + QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), + this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); this->_detect_lost_packets(ack_frame->largest_acknowledged()); - QUICLDDebug("Unacked packets %lu (handshake pkt %u, retransmittable %u, other %lu)", this->_sent_packets.size(), - this->_handshake_outstanding.load(), this->_retransmittable_outstanding.load(), - this->_sent_packets.size() - (this->_handshake_outstanding.load() + this->_retransmittable_outstanding.load())); + QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), + this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); this->_set_loss_detection_alarm(); } From 98b258efe2733145a8fe3985b62b7b7dda4d19a1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 8 Dec 2017 16:15:59 +0900 Subject: [PATCH 0224/1313] Prohibit duplicate transport parameters --- iocore/net/QUICNetVConnection.cc | 4 +- iocore/net/quic/QUICHandshake.cc | 21 +- iocore/net/quic/QUICStreamManager.cc | 23 +- iocore/net/quic/QUICTransportParameters.cc | 241 ++++++++--------- iocore/net/quic/QUICTransportParameters.h | 59 +++-- .../net/quic/test/test_QUICStreamManager.cc | 6 +- .../quic/test/test_QUICTransportParameters.cc | 243 ++++++++++-------- 7 files changed, 311 insertions(+), 286 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2d5e32dc872..3b1843a5f3c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -863,10 +863,10 @@ QUICNetVConnection::_init_flow_control_params(const std::shared_ptrinitial_max_data(); + local_initial_max_data = local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_DATA); } if (remote_tp) { - remote_initial_max_data = remote_tp->initial_max_data(); + remote_initial_max_data = remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_DATA); } this->_local_flow_controller->forward_limit(local_initial_max_data * 1024); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 3637feb03fb..32f727f5b0d 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -284,22 +284,11 @@ QUICHandshake::_load_local_transport_parameters() // MUSTs QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(); - tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, - std::unique_ptr( - new QUICTransportParameterValue(params->initial_max_stream_data(), sizeof(params->initial_max_stream_data())))); - - tp->add(QUICTransportParameterId::INITIAL_MAX_DATA, std::unique_ptr(new QUICTransportParameterValue( - params->initial_max_data(), sizeof(params->initial_max_data())))); - - tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, - std::unique_ptr( - new QUICTransportParameterValue(params->initial_max_stream_id(), sizeof(params->initial_max_stream_id())))); - - tp->add(QUICTransportParameterId::IDLE_TIMEOUT, std::unique_ptr(new QUICTransportParameterValue( - params->no_activity_timeout_in(), sizeof(uint16_t)))); - - tp->add(QUICTransportParameterId::STATELESS_RETRY_TOKEN, - std::unique_ptr(new QUICTransportParameterValue(this->_token.buf(), 16))); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); + tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, params->initial_max_stream_id()); + tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); + tp->set(QUICTransportParameterId::STATELESS_RETRY_TOKEN, this->_token.buf(), 16); tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); // MAYs diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index b5c10eba2f3..3b6ac323932 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -57,23 +57,19 @@ QUICStreamManager::init_flow_control_params(const std::shared_ptr_local_tp) { - local_initial_max_stream_data = local_tp->initial_max_stream_data(); + local_initial_max_stream_data = local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); } if (this->_remote_tp) { - remote_initial_max_stream_data = remote_tp->initial_max_stream_data(); + remote_initial_max_stream_data = remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); } stream->init_flow_control_params(local_initial_max_stream_data, remote_initial_max_stream_data); } - uint16_t len; - const uint8_t *tp_value; if (this->_local_tp) { - tp_value = this->_local_tp->get(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, len); - this->_local_maximum_stream_id = QUICTypeUtil::read_QUICStreamId(tp_value, len); + this->_local_maximum_stream_id = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_ID); } if (this->_remote_tp) { - tp_value = this->_remote_tp->get(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, len); - this->_remote_maximum_stream_id = QUICTypeUtil::read_QUICStreamId(tp_value, len); + this->_remote_maximum_stream_id = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_ID); } } @@ -208,14 +204,13 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream(); if (stream_id == STREAM_ID_FOR_HANDSHAKE) { // XXX rece/send max_stream_data are going to be set by init_flow_control_params() - stream->init(this->_tx, this->_connection_id, stream_id, this->_local_tp->initial_max_stream_data()); + stream->init(this->_tx, this->_connection_id, stream_id, + this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA)); } else { - const QUICTransportParameters &local_tp = *this->_local_tp; - const QUICTransportParameters &remote_tp = *this->_remote_tp; - // TODO: check local_tp and remote_tp is initialized - stream->init(this->_tx, this->_connection_id, stream_id, local_tp.initial_max_stream_data(), - remote_tp.initial_max_stream_data()); + stream->init(this->_tx, this->_connection_id, stream_id, + this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA), + this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA)); } stream->start(); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index f8dac049685..72da3adbb87 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -31,119 +31,146 @@ static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; -// -// QUICTransportParameterValue -// -QUICTransportParameterValue::QUICTransportParameterValue(ats_unique_buf d, uint16_t l) : _data(std::move(d)), _len(l){}; - -QUICTransportParameterValue::QUICTransportParameterValue(const uint8_t *raw_data, uint16_t l) +QUICTransportParameters::Value::Value(const uint8_t *data, uint16_t len) : _len(len) { - this->_data = ats_unique_malloc(l); - this->_len = l; - memcpy(this->_data.get(), raw_data, l); + this->_data = static_cast(ats_malloc(len)); + memcpy(this->_data, data, len); } -QUICTransportParameterValue::QUICTransportParameterValue(uint64_t raw_data, uint16_t l) +QUICTransportParameters::Value::~Value() { - this->_data = ats_unique_malloc(l); - size_t len = 0; - QUICTypeUtil::write_uint_as_nbytes(raw_data, l, this->_data.get(), &len); - this->_len = len; -}; + ats_free(this->_data); + this->_data = nullptr; +} -QUICTransportParameterValue::QUICTransportParameterValue(const uint64_t raw_data[2], uint16_t l) +bool +QUICTransportParameters::is_valid() const { - this->_data = ats_unique_malloc(l); - size_t len = 0; - if (l > 8) { - QUICTypeUtil::write_uint_as_nbytes(raw_data[0], 8, this->_data.get(), &len); - this->_len += len; - QUICTypeUtil::write_uint_as_nbytes(raw_data[1], l - 8, this->_data.get() + 8, &len); - this->_len += len; - } else { - QUICTypeUtil::write_uint_as_nbytes(raw_data[0], l, this->_data.get(), &len); - this->_len += len; - } + return this->_valid; } const uint8_t * -QUICTransportParameterValue::data() const +QUICTransportParameters::Value::data() const { - return this->_data.get(); + return this->_data; } uint16_t -QUICTransportParameterValue::len() const +QUICTransportParameters::Value::len() const { return this->_len; } -// -// QUICTransportParameters -// - -QUICTransportParameters::QUICTransportParameters(const uint8_t *buf, size_t len) +QUICTransportParameters::~QUICTransportParameters() { - this->_buf = ats_unique_malloc(len); - memcpy(this->_buf.get(), buf, len); + for (auto p : this->_parameters) { + delete p.second; + } } -const uint8_t * -QUICTransportParameters::get(QUICTransportParameterId tpid, uint16_t &len) const +void +QUICTransportParameters::_load(const uint8_t *buf, size_t len) { - if (this->_buf) { - const uint8_t *p = this->_buf.get() + this->_parameters_offset(); + bool has_error = false; + const uint8_t *p = buf + this->_parameters_offset(buf); - uint16_t n = (p[0] << 8) + p[1]; - p += 2; - while (n > 0) { - uint16_t _id = (p[0] << 8) + p[1]; + // Read size of parameters field + uint16_t nbytes = (p[0] << 8) + p[1]; + p += 2; + + // Read parameters + const uint8_t *end = p + nbytes; + while (p < end) { + // Read ID + uint16_t id = 0; + if (end - p >= 2) { + id = (p[0] << 8) + p[1]; p += 2; - n -= 2; - uint16_t _value_len = (p[0] << 8) + p[1]; + } else { + has_error = true; + break; + } + + // Check duplication + // An endpoint MUST treat receipt of duplicate transport parameters as a connection error of type TRANSPORT_PARAMETER_ERROR + if (this->_parameters.find(id) != this->_parameters.end()) { + has_error = true; + break; + } + + // Read length of value + uint16_t len = 0; + if (end - p >= 2) { + len = (p[0] << 8) + p[1]; p += 2; - n -= 2; - if (tpid == _id) { - len = _value_len; - return p; - } - p += _value_len; - n -= _value_len; + } else { + has_error = true; + break; } - } else { - auto p = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); - if (p != this->_parameters.end()) { - len = p->second->len(); - return p->second->data(); + + // Store parameter + if (end - p >= len) { + this->_parameters.insert(std::make_pair(id, new Value(p, len))); + p += len; + } else { + has_error = true; + break; } } + this->_valid = !has_error; +} + +const uint8_t * +QUICTransportParameters::getAsBytes(QUICTransportParameterId tpid, uint16_t &len) const +{ + auto p = this->_parameters.find(tpid); + if (p != this->_parameters.end()) { + len = p->second->len(); + return p->second->data(); + } + len = 0; return nullptr; } uint32_t -QUICTransportParameters::initial_max_stream_data() const +QUICTransportParameters::getAsUInt32(QUICTransportParameterId tpid) const { - uint16_t len = 0; - const uint8_t *data = this->get(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, len); - - return static_cast(QUICTypeUtil::read_nbytes_as_uint(data, len)); + uint16_t len = 0; + const uint8_t *value = this->getAsBytes(tpid, len); + if (value) { + return QUICTypeUtil::read_nbytes_as_uint(value, 4); + } else { + return 0; + } } -uint32_t -QUICTransportParameters::initial_max_data() const +void +QUICTransportParameters::set(QUICTransportParameterId id, const uint8_t *value, uint16_t value_len) { - uint16_t len = 0; - const uint8_t *data = this->get(QUICTransportParameterId::INITIAL_MAX_DATA, len); + if (this->_parameters.find(id) != this->_parameters.end()) { + this->_parameters.erase(id); + } + this->_parameters.insert(std::make_pair(id, new Value(value, value_len))); +} - return static_cast(QUICTypeUtil::read_nbytes_as_uint(data, len)); +void +QUICTransportParameters::set(QUICTransportParameterId id, uint16_t value) +{ + uint8_t v[2]; + size_t n; + QUICTypeUtil::write_uint_as_nbytes(value, 2, v, &n); + this->set(id, v, 2); } void -QUICTransportParameters::add(QUICTransportParameterId id, std::unique_ptr value) +QUICTransportParameters::set(QUICTransportParameterId id, uint32_t value) { - this->_parameters.insert(std::pair>(id, std::move(value))); + uint8_t v[4]; + size_t n; + QUICTypeUtil::write_uint_as_nbytes(value, 4, v, &n); + this->set(id, v, 4); } void @@ -164,12 +191,11 @@ QUICTransportParameters::store(uint8_t *buf, uint16_t *len) const p[0] = (it.first & 0xff00) >> 8; p[1] = it.first & 0xff; p += 2; - const QUICTransportParameterValue *value = it.second.get(); - p[0] = (value->len() & 0xff00) >> 8; - p[1] = value->len() & 0xff; + p[0] = (it.second->len() & 0xff00) >> 8; + p[1] = it.second->len() & 0xff; p += 2; - memcpy(p, value->data(), value->len()); - p += value->len(); + memcpy(p, it.second->data(), it.second->len()); + p += it.second->len(); } ptrdiff_t n = p - parameters_size - sizeof(uint16_t); @@ -185,29 +211,22 @@ QUICTransportParameters::store(uint8_t *buf, uint16_t *len) const // QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const uint8_t *buf, size_t len) - : QUICTransportParameters(buf, len) { + this->_load(buf, len); + this->_negotiated_version = QUICTypeUtil::read_QUICVersion(buf); + this->_initial_version = QUICTypeUtil::read_QUICVersion(buf + sizeof(QUICVersion)); + // Print all parameters - const uint8_t *p = this->_buf.get() + this->_parameters_offset(); - uint16_t n = (p[0] << 8) + p[1]; - p += 2; - while (n > 0) { - uint16_t _id = (p[0] << 8) + p[1]; - p += 2; - n -= 2; - uint16_t _value_len = (p[0] << 8) + p[1]; - p += 2; - n -= 2; - if (_value_len == 0) { - Debug("quic_handsahke", "%s: (no value)", QUICDebugNames::transport_parameter_id(_id)); - } else if (_value_len <= 8) { - Debug("quic_handsahke", "%s: 0x%" PRIx64 " (%" PRIu64 ")", QUICDebugNames::transport_parameter_id(_id), - QUICTypeUtil::read_nbytes_as_uint(p, _value_len), QUICTypeUtil::read_nbytes_as_uint(p, _value_len)); + for (auto &p : this->_parameters) { + if (p.second->len() == 0) { + Debug("quic_handsahke", "%s: (no value)", QUICDebugNames::transport_parameter_id(p.first)); + } else if (p.second->len() <= 8) { + Debug("quic_handsahke", "%s: 0x%" PRIx64 " (%" PRIu64 ")", QUICDebugNames::transport_parameter_id(p.first), + QUICTypeUtil::read_nbytes_as_uint(p.second->data(), p.second->len()), + QUICTypeUtil::read_nbytes_as_uint(p.second->data(), p.second->len())); } else { - Debug("quic_handsahke", "%s: (long data)", QUICDebugNames::transport_parameter_id(_id)); + Debug("quic_handsahke", "%s: (long data)", QUICDebugNames::transport_parameter_id(p.first)); } - p += _value_len; - n -= _value_len; } } @@ -224,7 +243,7 @@ QUICTransportParametersInClientHello::_store(uint8_t *buf, uint16_t *len) const } std::ptrdiff_t -QUICTransportParametersInClientHello::_parameters_offset() const +QUICTransportParametersInClientHello::_parameters_offset(const uint8_t *) const { return 8; // sizeof(QUICVersion) + sizeof(QUICVersion) } @@ -232,27 +251,24 @@ QUICTransportParametersInClientHello::_parameters_offset() const QUICVersion QUICTransportParametersInClientHello::negotiated_version() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICVersion(this->_buf.get()); - } else { - return this->_negotiated_version; - } + return this->_negotiated_version; } QUICVersion QUICTransportParametersInClientHello::initial_version() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICVersion(this->_buf.get() + sizeof(QUICVersion)); - } else { - return this->_initial_version; - } + return this->_initial_version; } // // QUICTransportParametersInEncryptedExtensions // +QUICTransportParametersInEncryptedExtensions::QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len) +{ + this->_load(buf, len); +} + void QUICTransportParametersInEncryptedExtensions::_store(uint8_t *buf, uint16_t *len) const { @@ -268,14 +284,6 @@ QUICTransportParametersInEncryptedExtensions::_store(uint8_t *buf, uint16_t *len *len = p - buf; } -const uint8_t * -QUICTransportParametersInEncryptedExtensions::supported_versions_len(uint16_t *n) const -{ - uint8_t *b = this->_buf.get(); - *n = b[0]; - return b + 1; -} - void QUICTransportParametersInEncryptedExtensions::add_version(QUICVersion version) { @@ -283,10 +291,9 @@ QUICTransportParametersInEncryptedExtensions::add_version(QUICVersion version) } std::ptrdiff_t -QUICTransportParametersInEncryptedExtensions::_parameters_offset() const +QUICTransportParametersInEncryptedExtensions::_parameters_offset(const uint8_t *buf) const { - const uint8_t *b = this->_buf.get(); - return sizeof(uint8_t) + b[0]; + return 1 + buf[0]; } // diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 12c4892f998..c8fabe07bda 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -24,7 +24,7 @@ #pragma once #include -// #include "ts/Map.h" +#include #include #include "QUICTypes.h" @@ -64,39 +64,45 @@ class QUICTransportParameterId uint16_t _id = 0; }; -class QUICTransportParameterValue +class QUICTransportParameters { public: - QUICTransportParameterValue(ats_unique_buf d, uint16_t l); - QUICTransportParameterValue(const uint8_t *raw_data, uint16_t l); - QUICTransportParameterValue(uint64_t raw_data, uint16_t l); - QUICTransportParameterValue(const uint64_t raw_data[2], uint16_t l); + QUICTransportParameters(const uint8_t *buf, size_t len); + ~QUICTransportParameters(); - const uint8_t *data() const; - uint16_t len() const; + bool is_valid() const; -private: - ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; - uint16_t _len = 0; -}; + const uint8_t *getAsBytes(QUICTransportParameterId id, uint16_t &len) const; + uint32_t getAsUInt32(QUICTransportParameterId id) const; + + void set(QUICTransportParameterId id, const uint8_t *value, uint16_t value_len); + void set(QUICTransportParameterId id, uint16_t value); + void set(QUICTransportParameterId id, uint32_t value); -class QUICTransportParameters -{ -public: - QUICTransportParameters(const uint8_t *buf, size_t len); - const uint8_t *get(QUICTransportParameterId id, uint16_t &len) const; - uint32_t initial_max_stream_data() const; - uint32_t initial_max_data() const; - void add(QUICTransportParameterId id, std::unique_ptr value); void store(uint8_t *buf, uint16_t *len) const; protected: + class Value + { + public: + Value(const uint8_t *data, uint16_t len); + ~Value(); + const uint8_t *data() const; + uint16_t len() const; + + private: + uint8_t *_data = nullptr; + uint16_t _len = 0; + }; + QUICTransportParameters(){}; - virtual std::ptrdiff_t _parameters_offset() const = 0; + void _load(const uint8_t *buf, size_t len); + bool _valid = false; + + virtual std::ptrdiff_t _parameters_offset(const uint8_t *buf) const = 0; virtual void _store(uint8_t *buf, uint16_t *len) const = 0; - ats_unique_buf _buf = {nullptr, [](void *p) { ats_free(p); }}; - std::map> _parameters; + std::map _parameters; }; class QUICTransportParametersInClientHello : public QUICTransportParameters @@ -109,7 +115,7 @@ class QUICTransportParametersInClientHello : public QUICTransportParameters QUICVersion initial_version() const; protected: - std::ptrdiff_t _parameters_offset() const override; + std::ptrdiff_t _parameters_offset(const uint8_t *buf) const override; void _store(uint8_t *buf, uint16_t *len) const override; private: @@ -121,12 +127,11 @@ class QUICTransportParametersInEncryptedExtensions : public QUICTransportParamet { public: QUICTransportParametersInEncryptedExtensions() : QUICTransportParameters(){}; - QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len) : QUICTransportParameters(buf, len){}; - const uint8_t *supported_versions_len(uint16_t *n) const; + QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len); void add_version(QUICVersion version); protected: - std::ptrdiff_t _parameters_offset() const override; + std::ptrdiff_t _parameters_offset(const uint8_t *buf) const override; void _store(uint8_t *buf, uint16_t *len) const override; uint8_t _n_versions = 0; diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 3a143dff5fa..cbcb41cdcea 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -103,8 +103,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") app_map.set_default(&mock_app); QUICStreamManager sm(0, &tx, &app_map); std::shared_ptr local_tp = std::make_shared(); - local_tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, - std::unique_ptr(new QUICTransportParameterValue(4096, 4))); + local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); std::shared_ptr remote_tp = std::make_shared(static_cast(0), static_cast(0)); sm.init_flow_control_params(local_tp, remote_tp); @@ -137,8 +136,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") app_map.set_default(&mock_app); QUICStreamManager sm(0, &tx, &app_map); std::shared_ptr local_tp = std::make_shared(); - local_tp->add(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, - std::unique_ptr(new QUICTransportParameterValue(4096, 4))); + local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); std::shared_ptr remote_tp = std::make_shared(static_cast(0), static_cast(0)); sm.init_flow_control_params(local_tp, remote_tp); diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index b65e406cdb9..c467939d6bf 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -27,50 +27,72 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") { - uint8_t buf[] = { - 0x01, 0x02, 0x03, 0x04, // negotiated version - 0x05, 0x06, 0x07, 0x08, // iinitial version - 0x00, 0x1e, // size of parameters - 0x00, 0x00, // parameter id - 0x00, 0x04, // length of value - 0x11, 0x22, 0x33, 0x44, // value - 0x00, 0x01, // parameter id - 0x00, 0x04, // length of value - 0x12, 0x34, 0x56, 0x78, // value - 0x00, 0x02, // parameter id - 0x00, 0x04, // length of value - 0x0a, 0x0b, 0x0c, 0x0d, // value - 0x00, 0x03, // parameter id - 0x00, 0x02, // length of value - 0xab, 0xcd, // value - }; - - QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf)); - CHECK(params_in_ch.negotiated_version() == 0x01020304); - CHECK(params_in_ch.initial_version() == 0x05060708); - - uint16_t len = 0; - const uint8_t *data = nullptr; - - data = params_in_ch.get(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, len); - CHECK(len == 4); - CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); - - data = params_in_ch.get(QUICTransportParameterId::INITIAL_MAX_DATA, len); - CHECK(len == 4); - CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); - - data = params_in_ch.get(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, len); - CHECK(len == 4); - CHECK(memcmp(data, "\x0a\x0b\x0c\x0d", 4) == 0); - - data = params_in_ch.get(QUICTransportParameterId::IDLE_TIMEOUT, len); - CHECK(len == 2); - CHECK(memcmp(data, "\xab\xcd", 2) == 0); - - data = params_in_ch.get(QUICTransportParameterId::MAX_PACKET_SIZE, len); - CHECK(len == 0); - CHECK(data == nullptr); + SECTION("OK") + { + uint8_t buf[] = { + 0x01, 0x02, 0x03, 0x04, // negotiated version + 0x05, 0x06, 0x07, 0x08, // iinitial version + 0x00, 0x1e, // size of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value + 0x00, 0x01, // parameter id + 0x00, 0x04, // length of value + 0x12, 0x34, 0x56, 0x78, // value + 0x00, 0x02, // parameter id + 0x00, 0x04, // length of value + 0x0a, 0x0b, 0x0c, 0x0d, // value + 0x00, 0x03, // parameter id + 0x00, 0x02, // length of value + 0xab, 0xcd, // value + }; + + QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf)); + CHECK(params_in_ch.is_valid()); + CHECK(params_in_ch.negotiated_version() == 0x01020304); + CHECK(params_in_ch.initial_version() == 0x05060708); + + uint16_t len = 0; + const uint8_t *data = nullptr; + + data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); + + data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_DATA, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); + + data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x0a\x0b\x0c\x0d", 4) == 0); + + data = params_in_ch.getAsBytes(QUICTransportParameterId::IDLE_TIMEOUT, len); + CHECK(len == 2); + CHECK(memcmp(data, "\xab\xcd", 2) == 0); + + data = params_in_ch.getAsBytes(QUICTransportParameterId::MAX_PACKET_SIZE, len); + CHECK(len == 0); + CHECK(data == nullptr); + } + + SECTION("Duplicate parameters") + { + uint8_t buf[] = { + 0x01, 0x02, 0x03, 0x04, // negotiated version + 0x05, 0x06, 0x07, 0x08, // iinitial version + 0x00, 0x10, // size of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x12, 0x34, 0x56, 0x78, // value + }; + + QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf)); + CHECK(!params_in_ch.is_valid()); + } } TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") @@ -97,18 +119,14 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") QUICTransportParametersInClientHello params_in_ch(0x01020304, 0x05060708); uint32_t max_stream_data = 0x11223344; - params_in_ch.add( - QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, - std::unique_ptr(new QUICTransportParameterValue(max_stream_data, sizeof(max_stream_data)))); + params_in_ch.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, max_stream_data); uint16_t max_packet_size = 0xabcd; - params_in_ch.add( - QUICTransportParameterId::MAX_PACKET_SIZE, - std::unique_ptr(new QUICTransportParameterValue(max_packet_size, sizeof(max_packet_size)))); + params_in_ch.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size); - uint64_t stateless_retry_token[2] = {0x0011223344556677, 0x0011223344556677}; - params_in_ch.add(QUICTransportParameterId::STATELESS_RETRY_TOKEN, - std::unique_ptr(new QUICTransportParameterValue(stateless_retry_token, 16))); + uint8_t stateless_retry_token[16] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + params_in_ch.set(QUICTransportParameterId::STATELESS_RETRY_TOKEN, stateless_retry_token, 16); params_in_ch.store(buf, &len); CHECK(len == 44); @@ -117,53 +135,70 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") { - uint8_t buf[] = { - 0x04, // size of supported versions - 0x01, 0x02, 0x03, 0x04, // - 0x00, 0x1e, // size of parameters - 0x00, 0x00, // parameter id - 0x00, 0x04, // length of value - 0x11, 0x22, 0x33, 0x44, // value - 0x00, 0x01, // parameter id - 0x00, 0x04, // length of value - 0x12, 0x34, 0x56, 0x78, // value - 0x00, 0x02, // parameter id - 0x00, 0x04, // length of value - 0x0a, 0x0b, 0x0c, 0x0d, // value - 0x00, 0x03, // parameter id - 0x00, 0x02, // length of value - 0xab, 0xcd, // value - }; - - QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf)); - const uint8_t *versions; - uint16_t vlen; - versions = params_in_ee.supported_versions_len(&vlen); - CHECK(vlen == 4); - CHECK(memcmp(versions, "\x01\x02\x03\x04", 4) == 0); - - uint16_t len = 0; - const uint8_t *data = nullptr; - - data = params_in_ee.get(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, len); - CHECK(len == 4); - CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); - - data = params_in_ee.get(QUICTransportParameterId::INITIAL_MAX_DATA, len); - CHECK(len == 4); - CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); - - data = params_in_ee.get(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, len); - CHECK(len == 4); - CHECK(memcmp(data, "\x0a\x0b\x0c\x0d", 4) == 0); - - data = params_in_ee.get(QUICTransportParameterId::IDLE_TIMEOUT, len); - CHECK(len == 2); - CHECK(memcmp(data, "\xab\xcd", 2) == 0); - - data = params_in_ee.get(QUICTransportParameterId::MAX_PACKET_SIZE, len); - CHECK(len == 0); - CHECK(data == nullptr); + SECTION("OK") + { + uint8_t buf[] = { + 0x04, // size of supported versions + 0x01, 0x02, 0x03, 0x04, // + 0x00, 0x1e, // size of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value + 0x00, 0x01, // parameter id + 0x00, 0x04, // length of value + 0x12, 0x34, 0x56, 0x78, // value + 0x00, 0x02, // parameter id + 0x00, 0x04, // length of value + 0x0a, 0x0b, 0x0c, 0x0d, // value + 0x00, 0x03, // parameter id + 0x00, 0x02, // length of value + 0xab, 0xcd, // value + }; + + QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf)); + CHECK(params_in_ee.is_valid()); + + uint16_t len = 0; + const uint8_t *data = nullptr; + + data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); + + data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_DATA, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); + + data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x0a\x0b\x0c\x0d", 4) == 0); + + data = params_in_ee.getAsBytes(QUICTransportParameterId::IDLE_TIMEOUT, len); + CHECK(len == 2); + CHECK(memcmp(data, "\xab\xcd", 2) == 0); + + data = params_in_ee.getAsBytes(QUICTransportParameterId::MAX_PACKET_SIZE, len); + CHECK(len == 0); + CHECK(data == nullptr); + } + + SECTION("Duplicate parameters") + { + uint8_t buf[] = { + 0x04, // size of supported versions + 0x01, 0x02, 0x03, 0x04, // + 0x00, 0x1e, // size of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x01, 0x02, 0x03, 0x04, // value + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x12, 0x34, 0x56, 0x78, // value + }; + + QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf)); + CHECK(!params_in_ee.is_valid()); + } } TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") @@ -187,14 +222,10 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") QUICTransportParametersInEncryptedExtensions params_in_ee; uint32_t max_stream_data = 0x11223344; - params_in_ee.add( - QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, - std::unique_ptr(new QUICTransportParameterValue(max_stream_data, sizeof(max_stream_data)))); + params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, max_stream_data); uint16_t max_packet_size = 0xabcd; - params_in_ee.add( - QUICTransportParameterId::MAX_PACKET_SIZE, - std::unique_ptr(new QUICTransportParameterValue(max_packet_size, sizeof(max_packet_size)))); + params_in_ee.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size); params_in_ee.add_version(0x01020304); params_in_ee.add_version(0x05060708); From ee1e415b4a3599381b8532cdeff1169edd6f159a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 11 Dec 2017 09:14:12 +0900 Subject: [PATCH 0225/1313] Close connection if transport parameters are invalid --- iocore/net/quic/QUICHandshake.cc | 36 ++++++++++++++++++++++---------- iocore/net/quic/QUICHandshake.h | 2 ++ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 32f727f5b0d..00dd25f54ae 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -162,6 +162,13 @@ QUICHandshake::negotiated_application_name(const uint8_t **name, unsigned int *l void QUICHandshake::set_transport_parameters(std::shared_ptr tp) { + // An endpoint MUST treat receipt of duplicate transport parameters as a connection error of type TRANSPORT_PARAMETER_ERROR. + if (!tp->is_valid()) { + QUICHSDebug("Transport parameter is not valid"); + this->_abort_handshake(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR); + return; + } + this->_remote_transport_parameters = std::move(tp); const QUICTransportParametersInClientHello *tp_in_ch = @@ -169,9 +176,8 @@ QUICHandshake::set_transport_parameters(std::shared_ptr if (tp_in_ch) { // Version revalidation if (this->_version_negotiator->revalidate(tp_in_ch) != QUICVersionNegotiationStatus::REVALIDATED) { - this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR))); - QUICHSDebug("Enter state_closed"); - SET_HANDLER(&QUICHandshake::state_closed); + QUICHSDebug("Version revalidation failed"); + this->_abort_handshake(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR); return; } QUICHSDebug("Version negotiation revalidated: %x", tp_in_ch->negotiated_version()); @@ -214,13 +220,13 @@ QUICHandshake::state_read_client_hello(int event, Event *data) } if (error->cls != QUICErrorClass::NONE) { + QUICTransErrorCode code; if (dynamic_cast(error.get()) != nullptr) { - this->_client_qc->close(QUICConnectionErrorUPtr(static_cast(error.release()))); + code = error->trans_error_code; } else { - this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION))); + code = QUICTransErrorCode::PROTOCOL_VIOLATION; } - QUICHSDebug("Enter state_closed"); - SET_HANDLER(&QUICHandshake::state_closed); + this->_abort_handshake(code); } return EVENT_CONT; @@ -242,13 +248,13 @@ QUICHandshake::state_read_client_finished(int event, Event *data) } if (error->cls != QUICErrorClass::NONE) { + QUICTransErrorCode code; if (dynamic_cast(error.get()) != nullptr) { - this->_client_qc->close(QUICConnectionErrorUPtr(static_cast(error.release()))); + code = error->trans_error_code; } else { - this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION))); + code = QUICTransErrorCode::PROTOCOL_VIOLATION; } - QUICHSDebug("Enter state_closed"); - SET_HANDLER(&QUICHandshake::state_closed); + this->_abort_handshake(code); } return EVENT_CONT; @@ -395,3 +401,11 @@ QUICHandshake::_process_handshake_complete() return QUICErrorUPtr(new QUICNoError()); } + +void +QUICHandshake::_abort_handshake(QUICTransErrorCode code) +{ + this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(code))); + QUICHSDebug("Enter state_closed"); + SET_HANDLER(&QUICHandshake::state_closed); +} diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index d74344f196a..c7c221289d9 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -88,5 +88,7 @@ class QUICHandshake : public QUICApplication QUICErrorUPtr _process_client_finished(); QUICErrorUPtr _process_handshake_complete(); + void _abort_handshake(QUICTransErrorCode code); + QUICStatelessToken _token; }; From 328b1e7c3d3896f11750191906940ab25ef94454 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 11 Dec 2017 11:41:41 +0900 Subject: [PATCH 0226/1313] Fix a transport parameter name stateless RESET token is the right name. --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 4 ++-- iocore/net/QUICPacketHandler.cc | 2 +- iocore/net/quic/QUICHandshake.cc | 5 +++-- iocore/net/quic/QUICHandshake.h | 4 ++-- iocore/net/quic/QUICPacket.cc | 2 +- iocore/net/quic/QUICPacket.h | 3 ++- iocore/net/quic/QUICTransportParameters.h | 2 +- iocore/net/quic/QUICTypes.cc | 6 +++--- iocore/net/quic/QUICTypes.h | 2 +- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- iocore/net/quic/test/test_QUICTransportParameters.cc | 4 ++-- 12 files changed, 20 insertions(+), 18 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 77b13f1a950..d7efa38dc07 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -265,7 +265,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _handle_idle_timeout(); - QUICStatelessToken _token; + QUICStatelessResetToken _reset_token; }; extern ClassAllocator quicNetVCAllocator; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3b1843a5f3c..74e6def4c4c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -96,10 +96,10 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not { QUICConfig::scoped_config params; - this->_token.generate(_quic_connection_id ^ params->server_id()); + this->_reset_token.generate(_quic_connection_id ^ params->server_id()); } - this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_token); + this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_reset_token); this->_application_map = new QUICApplicationMap(); this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index afc88fd1b2b..fb20376c6a4 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -136,7 +136,7 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) // Send stateless reset if the packet is not a initial packet if (!QUICTypeUtil::hasLongHeader(reinterpret_cast(block->buf()))) { - QUICStatelessToken token; + QUICStatelessResetToken token; { QUICConfig::scoped_config params; token.generate(cid ^ params->server_id()); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 00dd25f54ae..4cb34b3fcc9 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -82,7 +82,8 @@ static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessToken token) : QUICApplication(qc), _token(token) +QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token) + : QUICApplication(qc), _reset_token(token) { this->_ssl = SSL_new(ssl_ctx); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc); @@ -294,7 +295,7 @@ QUICHandshake::_load_local_transport_parameters() tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, params->initial_max_stream_id()); tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); - tp->set(QUICTransportParameterId::STATELESS_RETRY_TOKEN, this->_token.buf(), 16); + tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), 16); tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); // MAYs diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index c7c221289d9..92f0bbe3df0 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -50,7 +50,7 @@ class SSLNextProtocolSet; class QUICHandshake : public QUICApplication { public: - QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessToken token); + QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token); ~QUICHandshake(); QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); @@ -90,5 +90,5 @@ class QUICHandshake : public QUICApplication void _abort_handshake(QUICTransErrorCode code); - QUICStatelessToken _token; + QUICStatelessResetToken _reset_token; }; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index bb8c08a7ab9..f99ecca6835 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -723,7 +723,7 @@ QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, } QUICPacketUPtr -QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token) +QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessResetToken stateless_reset_token) { std::random_device rnd; diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 0f374c33ed6..a7f9de17b75 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -298,7 +298,8 @@ class QUICPacketFactory ats_unique_buf payload, size_t len, bool retransmittable); QUICPacketUPtr create_client_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); - static QUICPacketUPtr create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessToken stateless_reset_token); + static QUICPacketUPtr create_stateless_reset_packet(QUICConnectionId connection_id, + QUICStatelessResetToken stateless_reset_token); void set_version(QUICVersion negotiated_version); void set_crypto_module(QUICCrypto *crypto); diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index c8fabe07bda..e1c42520b10 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -40,7 +40,7 @@ class QUICTransportParameterId IDLE_TIMEOUT, OMIT_CONNECTION_ID, MAX_PACKET_SIZE, - STATELESS_RETRY_TOKEN, + STATELESS_RESET_TOKEN, }; explicit operator bool() const { return true; } diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 0e152cd1b34..44e89bdc6ad 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -148,12 +148,12 @@ QUICTypeUtil::write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size } void -QUICStatelessToken::_gen_token(uint64_t data) +QUICStatelessResetToken::_gen_token(uint64_t data) { INK_MD5 _md5; - static constexpr char STATELESS_RETRY_TOKEN_KEY[] = "stateless_token_retry_key"; + static constexpr char STATELESS_RESET_TOKEN_KEY[] = "stateless_token_reset_key"; MD5Context ctx; - ctx.update(STATELESS_RETRY_TOKEN_KEY, strlen(STATELESS_RETRY_TOKEN_KEY)); + ctx.update(STATELESS_RESET_TOKEN_KEY, strlen(STATELESS_RESET_TOKEN_KEY)); ctx.update(reinterpret_cast(&data), 8); ctx.finalize(_md5); diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 3f762a43e21..b0a137427dc 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -200,7 +200,7 @@ using QUICErrorUPtr = std::unique_ptr; using QUICConnectionErrorUPtr = std::unique_ptr; using QUICStreamErrorUPtr = std::unique_ptr; -class QUICStatelessToken +class QUICStatelessResetToken { public: void diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 8b7d3a0b206..b6f6dcfe74a 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -77,7 +77,7 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") QUICPacketFactory factory; MockQUICCrypto crypto; factory.set_crypto_module(&crypto); - QUICStatelessToken token; + QUICStatelessResetToken token; token.generate(12345); uint8_t expected_output[] = { 0x41, // 0CK0001 diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index c467939d6bf..bac227e9655 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -124,9 +124,9 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") uint16_t max_packet_size = 0xabcd; params_in_ch.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size); - uint8_t stateless_retry_token[16] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + uint8_t stateless_reset_token[16] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - params_in_ch.set(QUICTransportParameterId::STATELESS_RETRY_TOKEN, stateless_retry_token, 16); + params_in_ch.set(QUICTransportParameterId::STATELESS_RESET_TOKEN, stateless_reset_token, 16); params_in_ch.store(buf, &len); CHECK(len == 44); From f0feed2037674255ab9d9bdc4fe8b0ab098e65ac Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 11 Dec 2017 15:03:22 +0900 Subject: [PATCH 0227/1313] Unify how to create null frames and packets --- iocore/net/QUICNetVConnection.cc | 8 ++++---- iocore/net/quic/QUICAckFrameCreator.cc | 4 ++-- iocore/net/quic/QUICFrame.cc | 14 +++++++++++++- iocore/net/quic/QUICFrame.h | 8 ++++++++ iocore/net/quic/QUICPacket.cc | 6 ++++++ iocore/net/quic/QUICPacket.h | 3 +++ 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 74e6def4c4c..af0a1674fee 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -244,8 +244,8 @@ QUICNetVConnection::retransmit_packet(const QUICPacket &packet) uint16_t size = packet.header()->payload_size(); const uint8_t *payload = packet.header()->payload(); - QUICFrameUPtr frame(nullptr, &QUICFrameDeleter::delete_null_frame); - uint16_t cursor = 0; + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + uint16_t cursor = 0; while (cursor < size) { frame = QUICFrameFactory::create(payload + cursor, size - cursor); @@ -833,7 +833,7 @@ QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPac QUICPacketUPtr QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type) { - QUICPacketUPtr packet(nullptr, &QUICPacketDeleter::delete_null_packet); + QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); switch (type) { case QUICPacketType::SERVER_CLEARTEXT: @@ -903,7 +903,7 @@ QUICNetVConnection::_handle_error(QUICErrorUPtr error) QUICPacketUPtr QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) { - QUICPacketUPtr quic_packet = QUICPacketUPtr(nullptr, &QUICPacketDeleter::delete_null_packet); + QUICPacketUPtr quic_packet = QUICPacketFactory::create_null_packet(); UDPPacket *udp_packet = this->_packet_recv_queue.dequeue(); if (!udp_packet) { result = QUICPacketCreationResult::NOT_READY; diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 89b9525cfbb..eb58c7fe401 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -43,7 +43,7 @@ QUICAckFrameCreator::update(QUICPacketNumber packet_number, bool acknowledgable) std::unique_ptr QUICAckFrameCreator::create() { - std::unique_ptr ack_frame = {nullptr, QUICFrameDeleter::delete_null_frame}; + std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); if (this->_can_send) { ack_frame = this->_create_ack_frame(); this->_can_send = false; @@ -69,7 +69,7 @@ QUICAckFrameCreator::_sort_packet_numbers() std::unique_ptr QUICAckFrameCreator::_create_ack_frame() { - std::unique_ptr ack_frame = {nullptr, QUICFrameDeleter::delete_null_frame}; + std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); this->_packet_numbers.sort(); QUICPacketNumber largest_ack_number = this->_packet_numbers.largest_ack_number(); QUICPacketNumber last_ack_number = largest_ack_number; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 1a1c151362a..4e61a1c210b 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1252,6 +1252,18 @@ QUICRetransmissionFrame::packet_type() const // QUICFrameFactory // +QUICFrameUPtr +QUICFrameFactory::create_null_frame() +{ + return {nullptr, &QUICFrameDeleter::delete_null_frame}; +} + +std::unique_ptr +QUICFrameFactory::create_null_ack_frame() +{ + return {nullptr, &QUICFrameDeleter::delete_null_frame}; +} + QUICFrameUPtr QUICFrameFactory::create(const uint8_t *buf, size_t len) { @@ -1321,7 +1333,7 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) default: // Unknown frame Debug("quic_frame_factory", "Unknown frame type %x", buf[0]); - return QUICFrameUPtr(nullptr, &QUICFrameDeleter::delete_null_frame); + return QUICFrameFactory::create_null_frame(); } } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 2acacb45b6f..e92e09472ec 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -488,6 +488,7 @@ class QUICFrameDeleter static void delete_null_frame(QUICFrame *frame) { + ink_assert(frame == nullptr); } static void @@ -594,6 +595,13 @@ class QUICFrameDeleter class QUICFrameFactory { public: + /* + * This is for an empty QUICFrameUptr. + * Empty frames are used for variable initialization and return value of frame creation failure + */ + static QUICFrameUPtr create_null_frame(); + static std::unique_ptr create_null_ack_frame(); + /* * This is used for creating a QUICFrame object based on received data. */ diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index f99ecca6835..048d3d272c7 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -619,6 +619,12 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si // // QUICPacketFactory // +QUICPacketUPtr +QUICPacketFactory::create_null_packet() +{ + return {nullptr, &QUICPacketDeleter::delete_null_packet}; +} + QUICPacketUPtr QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result) { diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index a7f9de17b75..79b82cf19fc 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -278,6 +278,7 @@ class QUICPacketDeleter static void delete_null_packet(QUICPacket *packet) { + ink_assert(packet == nullptr); } static void @@ -290,6 +291,8 @@ class QUICPacketDeleter class QUICPacketFactory { public: + static QUICPacketUPtr create_null_packet(); + QUICPacketUPtr create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result); QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number); QUICPacketUPtr create_server_cleartext_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, From eb005d09dbcf00ff574efe69e6225f0d8e01eb4c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 11 Dec 2017 15:07:19 +0900 Subject: [PATCH 0228/1313] Unify how to create null frames and packets (cont.) --- iocore/net/quic/QUICPacket.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 048d3d272c7..c80c06d9bc9 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -675,7 +675,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ new (packet) QUICPacket(header, std::move(plain_txt), plain_txt_len); } - return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); + return QUICPacketFactory::create_null_packet(); } QUICPacketUPtr @@ -761,7 +761,7 @@ QUICPacketFactory::_create_unprotected_packet(QUICPacketHeader *header) QUICPacket *packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(header, std::move(cleartext), cleartext_len, false); - return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); + return QUICPacketFactory::create_null_packet(); } QUICPacketUPtr @@ -779,7 +779,7 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header, bool retra new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, retransmittable); } - return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); + return QUICPacketFactory::create_null_packet(); } void From 53b5663462bbfb30904ce8c3ae7a19c203e7a4cf Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 11 Dec 2017 16:03:46 +0900 Subject: [PATCH 0229/1313] Revert "Unify how to create null frames and packets (cont.)" This reverts commit eb005d09dbcf00ff574efe69e6225f0d8e01eb4c. --- iocore/net/quic/QUICPacket.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index c80c06d9bc9..048d3d272c7 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -675,7 +675,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ new (packet) QUICPacket(header, std::move(plain_txt), plain_txt_len); } - return QUICPacketFactory::create_null_packet(); + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } QUICPacketUPtr @@ -761,7 +761,7 @@ QUICPacketFactory::_create_unprotected_packet(QUICPacketHeader *header) QUICPacket *packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(header, std::move(cleartext), cleartext_len, false); - return QUICPacketFactory::create_null_packet(); + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } QUICPacketUPtr @@ -779,7 +779,7 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header, bool retra new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, retransmittable); } - return QUICPacketFactory::create_null_packet(); + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } void From 535134be1c2b83a4bb3fff0b2d6cfbb0d2288ec2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 8 Dec 2017 16:51:35 +0900 Subject: [PATCH 0230/1313] Refactoring QUICStream & HQClientTransaction --- iocore/net/quic/QUICApplication.cc | 54 ++++- iocore/net/quic/QUICApplication.h | 4 + iocore/net/quic/QUICFrame.h | 2 +- iocore/net/quic/QUICStream.cc | 253 ++++++++++++++-------- iocore/net/quic/QUICStream.h | 34 ++- iocore/net/quic/QUICStreamManager.cc | 15 +- iocore/net/quic/test/test_QUICStream.cc | 18 +- proxy/hq/HQClientSession.cc | 2 +- proxy/hq/HQClientTransaction.cc | 272 ++++++++++++++++++------ proxy/hq/HQClientTransaction.h | 37 ++-- proxy/hq/QUICSimpleApp.cc | 15 +- 11 files changed, 483 insertions(+), 223 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index eca747fd6d3..5b8f3f4dc87 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -31,14 +31,16 @@ static constexpr char tag[] = "quic_app"; // QUICStreamIO::QUICStreamIO(QUICApplication *app, QUICStream *stream) : _stream(stream) { - this->_read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); - this->_write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + this->_read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); + this->_write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); this->_read_buffer_reader = _read_buffer->alloc_reader(); this->_write_buffer_reader = _write_buffer->alloc_reader(); - this->_read_vio = stream->do_io_read(app, 0, _read_buffer); - this->_write_vio = stream->do_io_write(app, 0, _write_buffer_reader); + this->_read_vio = stream->do_io_read(app, INT64_MAX, this->_read_buffer); + this->_read_vio->buffer.reader_for(this->_read_buffer_reader); + + this->_write_vio = stream->do_io_write(app, INT64_MAX, this->_write_buffer_reader); } int64_t @@ -71,14 +73,16 @@ QUICStreamIO::write(IOBufferReader *r, int64_t alen, int64_t offset) { SCOPED_MUTEX_LOCK(lock, this->_write_vio->mutex, this_ethread()); - if (this->_write_buffer->write_avail() > 0) { - int64_t bytes_add = this->_write_buffer->write(r, alen, offset); + int64_t bytes_avail = this->_write_buffer->write_avail(); + Debug(tag, "nbytes=%" PRId64 " ndone=%" PRId64 " write_avail=%" PRId64 " write_len=%" PRId64, this->_write_vio->nbytes, + this->_write_vio->ndone, bytes_avail, alen); - return bytes_add; + if (bytes_avail > 0) { + int64_t len = std::min(bytes_avail, alen); + int64_t bytes_added = this->_write_buffer->write(r, len, offset); + return bytes_added; } else { - Debug(tag, "write buffer is full"); - return 0; } } @@ -86,7 +90,7 @@ QUICStreamIO::write(IOBufferReader *r, int64_t alen, int64_t offset) void QUICStreamIO::set_write_vio_nbytes(int64_t nbytes) { - this->_write_vio->nbytes += nbytes; + this->_write_vio->nbytes = nbytes; } void @@ -119,6 +123,12 @@ QUICStreamIO::get_transaction_id() const return this->_stream->id(); } +bool +QUICStreamIO::is_vio(VIO *vio) +{ + return (this->_read_vio == vio || this->_write_vio == vio); +} + // // QUICApplication // @@ -178,3 +188,27 @@ QUICApplication::_find_stream_io(QUICStreamId id) return result->second; } } + +QUICStreamIO * +QUICApplication::_find_stream_io(VIO *vio) +{ + for (auto i : this->_stream_map) { + if (i.second->is_vio(vio)) { + return i.second; + } + } + + return nullptr; +} + +QUICStreamId +QUICApplication::_find_stream_id(VIO *vio) +{ + for (auto i : this->_stream_map) { + if (i.second->is_vio(vio)) { + return i.first; + } + } + + return 0; +} diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 17e32e9dab5..f8a37aaff82 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -49,6 +49,7 @@ class QUICStreamIO IOBufferReader *get_read_buffer_reader(); void shutdown(); uint32_t get_transaction_id() const; + bool is_vio(VIO *); private: QUICStream *_stream = nullptr; @@ -80,6 +81,9 @@ class QUICApplication : public Continuation protected: QUICStreamIO *_find_stream_io(QUICStreamId id); + // TODO: return pair + QUICStreamIO *_find_stream_io(VIO *vio); + QUICStreamId _find_stream_id(VIO *vio); QUICConnection *_client_qc = nullptr; diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index e92e09472ec..9f51b3f46f6 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -36,7 +36,7 @@ class QUICFrame public: QUICFrame(const uint8_t *buf, size_t len) : _buf(buf), _len(len){}; virtual QUICFrameType type() const; - virtual size_t size() const = 0; + virtual size_t size() const = 0; virtual void store(uint8_t *buf, size_t *len) const = 0; virtual void reset(const uint8_t *buf, size_t len); static QUICFrameType type(const uint8_t *buf); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 0d9214aaca4..1ca315e2d5e 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -35,10 +35,25 @@ Debug("quic_flow_ctrl", "[%" PRIx64 "] [%" PRIx32 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) +QUICStream::~QUICStream() +{ + if (this->_read_event) { + this->_read_event->cancel(); + this->_read_event = nullptr; + } + + if (this->_write_event) { + this->_write_event->cancel(); + this->_write_event = nullptr; + } +} + void QUICStream::init(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data) { + SET_HANDLER(&QUICStream::state_stream_open); + this->mutex = new_ProxyMutex(); this->_tx = tx; this->_connection_id = cid; @@ -50,12 +65,6 @@ QUICStream::init(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId si QUICStreamDebug("Initialized"); } -void -QUICStream::start() -{ - SET_HANDLER(&QUICStream::main_event_handler); -} - void QUICStream::init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data) { @@ -82,7 +91,7 @@ QUICStream::final_offset() } int -QUICStream::main_event_handler(int event, void *data) +QUICStream::state_stream_open(int event, void *data) { QUICStreamDebug("%s", QUICDebugNames::vc_event(event)); QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); @@ -90,20 +99,19 @@ QUICStream::main_event_handler(int event, void *data) switch (event) { case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { - this->_signal_read_event(true); - this->_read_event = nullptr; + int64_t len = this->_process_read_vio(); + if (len > 0) { + this->_signal_read_event(); + } break; } case VC_EVENT_WRITE_READY: case VC_EVENT_WRITE_COMPLETE: { - error = this->_send(); - this->_signal_write_event(true); - this->_write_event = nullptr; - - QUICStreamDebug("wvio.nbytes=%" PRId64 " wvio.ndone=%" PRId64 " wvio.read_avail=%" PRId64 " wvio.write_avail=%" PRId64, - this->_write_vio.nbytes, this->_write_vio.ndone, this->_write_vio.get_reader()->read_avail(), - this->_write_vio.get_writer()->write_avail()); + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); + } break; } @@ -111,6 +119,7 @@ QUICStream::main_event_handler(int event, void *data) case VC_EVENT_ERROR: case VC_EVENT_INACTIVITY_TIMEOUT: case VC_EVENT_ACTIVE_TIMEOUT: { + // TODO ink_assert(false); break; } @@ -138,7 +147,38 @@ QUICStream::main_event_handler(int event, void *data) } } - return EVENT_CONT; + return EVENT_DONE; +} + +int +QUICStream::state_stream_closed(int event, void *data) +{ + QUICStreamDebug("%s", QUICDebugNames::vc_event(event)); + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + // ignore + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + // ignore + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + // TODO + ink_assert(false); + break; + } + default: + ink_assert(false); + } + + return EVENT_DONE; } VIO * @@ -157,8 +197,8 @@ QUICStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) this->_read_vio.vc_server = this; this->_read_vio.op = VIO::READ; - // TODO: If read function is added, call reenable here - this->_read_vio.reenable(); + this->_process_read_vio(); + this->_send_tracked_event(this->_read_event, VC_EVENT_READ_READY, &this->_read_vio); return &this->_read_vio; } @@ -179,7 +219,8 @@ QUICStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bo this->_write_vio.vc_server = this; this->_write_vio.op = VIO::WRITE; - this->_write_vio.reenable(); + this->_process_write_vio(); + this->_send_tracked_event(this->_write_event, VC_EVENT_WRITE_READY, &this->_write_vio); return &this->_write_vio; } @@ -187,6 +228,8 @@ QUICStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bo void QUICStream::do_io_close(int lerrno) { + SET_HANDLER(&QUICStream::state_stream_closed); + this->_read_vio.buffer.clear(); this->_read_vio.nbytes = 0; this->_read_vio.op = VIO::NONE; @@ -202,83 +245,39 @@ void QUICStream::do_io_shutdown(ShutdownHowTo_t howto) { ink_assert(false); // unimplemented yet + return; } void QUICStream::reenable(VIO *vio) { if (vio->op == VIO::READ) { - SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); + QUICStreamDebug("read_vio reenabled"); - if (this->_read_vio.nbytes > 0) { - int event = (this->_read_vio.ntodo() == 0) ? VC_EVENT_READ_COMPLETE : VC_EVENT_READ_READY; - - if (this->_read_event == nullptr) { - this->_read_event = this_ethread()->schedule_imm_local(this, event); - } + int64_t len = this->_process_read_vio(); + if (len > 0) { + this->_signal_read_event(); } } else if (vio->op == VIO::WRITE) { - SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); + QUICStreamDebug("write_vio reenabled"); - if (this->_write_vio.nbytes > 0) { - int event = (this->_write_vio.ntodo() == 0) ? VC_EVENT_WRITE_COMPLETE : VC_EVENT_WRITE_READY; - - if (this->_write_event == nullptr) { - this->_write_event = this_ethread()->schedule_imm_local(this, event); - } + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); } } } -/** - * @brief Signal event to this->_read_vio._cont - * @param (call_update) If true, safe to call vio handler directly. - * Or called from do_io_read. Still setting things up. Send event to handle this after the dust settles - */ void -QUICStream::_signal_read_event(bool direct) +QUICStream::set_read_vio_nbytes(int64_t nbytes) { - int event = (this->_read_vio.ntodo() == 0) ? VC_EVENT_READ_COMPLETE : VC_EVENT_READ_READY; - Continuation *cont = this->_read_vio._cont; - - if (direct) { - Event *e = eventAllocator.alloc(); - e->callback_event = event; - e->cookie = this; - e->init(cont, 0, 0); - - cont->handleEvent(event, e); - } else { - this_ethread()->schedule_imm(cont, event, this); - } + this->_read_vio.nbytes = nbytes; } -/** - * @brief Signal event to this->_write_vio._cont - * @param (call_update) If true, safe to call vio handler directly. - * Or called from do_io_write. Still setting things up. Send event to handle this after the dust settles - */ void -QUICStream::_signal_write_event(bool direct) +QUICStream::set_write_vio_nbytes(int64_t nbytes) { - if (this->_write_vio.get_writer()->write_avail() == 0) { - QUICStreamDebug("wvio.write_avail=0"); - return; - } - - int event = (this->_write_vio.ntodo() == 0) ? VC_EVENT_WRITE_COMPLETE : VC_EVENT_WRITE_READY; - Continuation *cont = this->_write_vio._cont; - - if (direct) { - Event *e = eventAllocator.alloc(); - e->callback_event = event; - e->cookie = this; - e->init(cont, 0, 0); - - cont->handleEvent(event, e); - } else { - this_ethread()->schedule_imm(cont, event, this); - } + this->_write_vio.nbytes = nbytes; } void @@ -333,6 +332,8 @@ QUICStream::recv(const std::shared_ptr frame) new_frame = this->_received_stream_frame_buffer.pop(); } + this->_signal_read_event(); + return QUICErrorUPtr(new QUICNoError()); } @@ -343,12 +344,10 @@ QUICStream::recv(const std::shared_ptr frame) QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); - if (this->_write_vio.op == VIO::WRITE) { - // restart sending - QUICStreamDebug("restart sending"); - - this->_send(); - this->_signal_write_event(false); + QUICStreamDebug("restart sending"); + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); } return QUICErrorUPtr(new QUICNoError()); @@ -361,13 +360,95 @@ QUICStream::recv(const std::shared_ptr frame) return QUICErrorUPtr(new QUICNoError()); } +/** + * Replace existing event only if the new event is different than the inprogress event + */ +Event * +QUICStream::_send_tracked_event(Event *event, int send_event, VIO *vio) +{ + if (event != nullptr) { + if (event->callback_event != send_event) { + event->cancel(); + event = nullptr; + } + } + + if (event == nullptr) { + event = this_ethread()->schedule_imm(this, send_event, vio); + } + + return event; +} + +/** + * @brief Signal event to this->_read_vio._cont + */ +void +QUICStream::_signal_read_event() +{ + if (this->_read_vio._cont == nullptr || this->_read_vio.op == VIO::NONE) { + return; + } + MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread()); + + int event = this->_read_vio.ntodo() ? VC_EVENT_READ_READY : VC_EVENT_READ_COMPLETE; + + if (lock.is_locked()) { + this->_read_vio._cont->handleEvent(event, &this->_read_vio); + } else { + this_ethread()->schedule_imm(this->_read_vio._cont, event, &this->_read_vio); + } + + QUICStreamDebug("%s", QUICDebugNames::vc_event(event)); +} + +/** + * @brief Signal event to this->_write_vio._cont + */ +void +QUICStream::_signal_write_event() +{ + if (this->_write_vio._cont == nullptr || this->_write_vio.op == VIO::NONE) { + return; + } + MUTEX_TRY_LOCK(lock, this->_write_vio.mutex, this_ethread()); + + int event = this->_write_vio.ntodo() ? VC_EVENT_WRITE_READY : VC_EVENT_WRITE_COMPLETE; + + if (lock.is_locked()) { + this->_write_vio._cont->handleEvent(event, &this->_write_vio); + } else { + this_ethread()->schedule_imm(this->_write_vio._cont, event, &this->_write_vio); + } + + QUICStreamDebug("%s", QUICDebugNames::vc_event(event)); +} + +int64_t +QUICStream::_process_read_vio() +{ + if (this->_read_vio._cont == nullptr || this->_read_vio.op == VIO::NONE) { + return 0; + } + + // Pass through. Read operation is done by QUICStream::recv(const std::shared_ptr frame) + // TODO: 1. pop frame from _received_stream_frame_buffer + // 2. write data to _read_vio + + return 0; +} + /** * @brief Send STREAM DATA from _response_buffer * @detail Call _signal_write_event() to indicate event upper layer */ -QUICErrorUPtr -QUICStream::_send() +int64_t +QUICStream::_process_write_vio() { + if (this->_write_vio._cont == nullptr || this->_write_vio.op == VIO::NONE) { + return 0; + } + SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); @@ -420,7 +501,7 @@ QUICStream::_send() this->_tx->transmit_frame(std::move(frame)); } - return error; + return total_len; } void diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 282b434c87a..387e83ccdb2 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -46,22 +46,26 @@ class QUICStream : public VConnection { public: QUICStream() : VConnection(nullptr), _received_stream_frame_buffer(this) {} - ~QUICStream() {} + ~QUICStream(); void init(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId id, uint64_t recv_max_stream_data = 0, uint64_t send_max_stream_data = 0); - void start(); + // void start(); + int state_stream_open(int event, void *data); + int state_stream_closed(int event, void *data); + void init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data); - int main_event_handler(int event, void *data); QUICStreamId id() const; QUICOffset final_offset(); - // Implement VConnection interface. - VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) override; + // Implement VConnection Interface. + VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; void do_io_close(int lerrno = -1) override; void do_io_shutdown(ShutdownHowTo_t howto) override; void reenable(VIO *vio) override; + void set_read_vio_nbytes(int64_t); + void set_write_vio_nbytes(int64_t); QUICErrorUPtr recv(const std::shared_ptr frame); QUICErrorUPtr recv(const std::shared_ptr frame); @@ -78,20 +82,15 @@ class QUICStream : public VConnection LINK(QUICStream, link); private: - QUICStreamState _state; - - QUICErrorUPtr _send(); + int64_t _process_read_vio(); + int64_t _process_write_vio(); + void _signal_read_event(); + void _signal_write_event(); + Event *_send_tracked_event(Event *, int, VIO *); void _write_to_read_vio(const std::shared_ptr &); - // NOTE: Those are called update_read_request/update_write_request in Http2Stream - // void _read_from_net(uint64_t read_len, bool direct); - // void _write_to_net(IOBufferReader *buf_reader, int64_t write_len, bool direct); - - void _signal_read_event(bool call_update); - void _signal_write_event(bool call_update); - - Event *_send_tracked_event(Event *event, int send_event, VIO *vio); + QUICStreamState _state; bool _fin = false; QUICConnectionId _connection_id = 0; QUICStreamId _id = 0; @@ -111,6 +110,5 @@ class QUICStream : public VConnection // TODO: Consider to replace with ts/RbTree.h or other data structure QUICIncomingFrameBuffer _received_stream_frame_buffer; - QUICStreamManager *_stream_manager = nullptr; - QUICFrameTransmitter *_tx = nullptr; + QUICFrameTransmitter *_tx = nullptr; }; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 3b6ac323932..5223bb4db46 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -40,7 +40,10 @@ std::vector QUICStreamManager::interests() { return { - QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::MAX_STREAM_DATA, QUICFrameType::MAX_STREAM_ID, + QUICFrameType::STREAM, + QUICFrameType::RST_STREAM, + QUICFrameType::MAX_STREAM_DATA, + QUICFrameType::MAX_STREAM_ID, }; } @@ -147,13 +150,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr &f if (!application->is_stream_set(stream)) { application->set_stream(stream); } - - size_t nbytes_to_read = stream->nbytes_to_read(); - QUICErrorUPtr error = stream->recv(frame); - // Prevent trigger read events multiple times - if (nbytes_to_read == 0) { - this_ethread()->schedule_imm(application, VC_EVENT_READ_READY, stream); - } + QUICErrorUPtr error = stream->recv(frame); return error; } @@ -213,8 +210,6 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA)); } - stream->start(); - this->stream_list.push(stream); } return stream; diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index bd2f6489e72..00dd32aeff1 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -205,31 +205,31 @@ TEST_CASE("QUICStream", "[quic]") const char data[1024] = {0}; write_buffer->write(data, 1024); - stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 1); write_buffer->write(data, 1024); - stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 2); write_buffer->write(data, 1024); - stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 3); write_buffer->write(data, 1024); - stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 4); // This should not send a frame because of flow control write_buffer->write(data, 1024); - stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 4); // Update window stream->recv(std::make_shared(stream_id, 5120)); // This should send a frame - stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 5); // Update window @@ -237,16 +237,16 @@ TEST_CASE("QUICStream", "[quic]") // This should send a frame write_buffer->write(data, 1024); - stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 6); - stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 6); // Update window stream->recv(std::make_shared(stream_id, 6144)); - stream->main_event_handler(VC_EVENT_WRITE_READY, nullptr); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 7); } } diff --git a/proxy/hq/HQClientSession.cc b/proxy/hq/HQClientSession.cc index af4d9882e75..b8ede45db7c 100644 --- a/proxy/hq/HQClientSession.cc +++ b/proxy/hq/HQClientSession.cc @@ -52,7 +52,7 @@ HQClientSession::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *bu void HQClientSession::do_io_close(int lerrno) { - ink_assert(false); + // TODO return; } diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index cc3a2554516..69939cc7acb 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -32,15 +32,15 @@ #define HQTransDebug(fmt, ...) \ Debug("hq_trans", "[%" PRId64 "] [%" PRIx32 "] " fmt, this->parent->connection_id(), this->get_transaction_id(), ##__VA_ARGS__) -static void -dump_io_buffer(IOBufferReader *reader) -{ - IOBufferReader *debug_reader = reader->clone(); - uint8_t msg[1024] = {0}; - int64_t msg_len = 1024; - int64_t read_len = debug_reader->read(msg, msg_len); - Debug("hq_trans", "len=%" PRId64 "\n%s\n", read_len, msg); -} +// static void +// dump_io_buffer(IOBufferReader *reader) +// { +// IOBufferReader *debug_reader = reader->clone(); +// uint8_t msg[1024] = {0}; +// int64_t msg_len = 1024; +// int64_t read_len = debug_reader->read(msg, msg_len); +// Debug("v_hq_trans", "len=%" PRId64 "\n%s\n", read_len, msg); +// } HQClientTransaction::HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) @@ -50,7 +50,7 @@ HQClientTransaction::HQClientTransaction(HQClientSession *session, QUICStreamIO this->sm_reader = this->_read_vio_buf.alloc_reader(); static_cast(this->parent)->add_transaction(this); - SET_HANDLER(&HQClientTransaction::main_event_handler); + SET_HANDLER(&HQClientTransaction::state_stream_open); } void @@ -91,68 +91,77 @@ HQClientTransaction::allow_half_open() const } int -HQClientTransaction::main_event_handler(int event, void *edata) +HQClientTransaction::state_stream_open(int event, void *edata) { - Debug("hq_trans", "%s", QUICDebugNames::vc_event(event)); + // TODO: should check recursive call? + HQTransDebug("%s", get_vc_event_name(event)); switch (event) { case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { - if (edata == this->_read_event) { - this->_read_event = nullptr; - } - if (this->_stream_io->read_avail()) { - this->_read_request(); + int64_t len = this->_process_read_vio(); + // if no progress, don't need to signal + if (len > 0) { + this->_signal_read_event(); } + this->_stream_io->read_reenable(); + break; } case VC_EVENT_WRITE_READY: case VC_EVENT_WRITE_COMPLETE: { - if (edata == this->_write_event) { - this->_write_event = nullptr; + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); } - if (this->_write_vio.get_reader()->read_avail()) { - this->_write_response(); - } - - HQTransDebug("wvio.nbytes=%" PRId64 " wvio.ndone=%" PRId64 " wvio.read_avail=%" PRId64 " wvio.write_avail=%" PRId64, - this->_write_vio.nbytes, this->_write_vio.ndone, this->_write_vio.get_reader()->read_avail(), - this->_write_vio.get_writer()->write_avail()); + this->_stream_io->write_reenable(); break; } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + ink_assert(false); + break; + } default: Debug("hq_trans", "Unknown event %d", event); ink_assert(false); } - return EVENT_CONT; + return EVENT_DONE; } -void -HQClientTransaction::reenable(VIO *vio) +int +HQClientTransaction::state_stream_closed(int event, void *data) { - if (vio->op == VIO::READ) { - SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); - - if (this->_read_vio.nbytes > 0) { - int event = (this->_read_vio.ntodo() == 0) ? VC_EVENT_READ_COMPLETE : VC_EVENT_READ_READY; + HQTransDebug("%s", get_vc_event_name(event)); - if (this->_read_event == nullptr) { - this->_read_event = this_ethread()->schedule_imm_local(this, event); - } - } - } else if (vio->op == VIO::WRITE) { - SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); - - if (this->_write_vio.nbytes > 0) { - int event = (this->_write_vio.ntodo() == 0) ? VC_EVENT_WRITE_COMPLETE : VC_EVENT_WRITE_READY; - - if (this->_write_event == nullptr) { - this->_write_event = this_ethread()->schedule_imm_local(this, event); - } - } + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + // ignore + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + // ignore + break; } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + // TODO + ink_assert(false); + break; + } + default: + ink_assert(false); + } + + return EVENT_DONE; } VIO * @@ -171,7 +180,8 @@ HQClientTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) this->_read_vio.vc_server = this; this->_read_vio.op = VIO::READ; - this->_read_vio.reenable(); + this->_process_read_vio(); + this->_send_tracked_event(this->_read_event, VC_EVENT_READ_READY, &this->_read_vio); return &this->_read_vio; } @@ -192,7 +202,8 @@ HQClientTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader this->_write_vio.vc_server = this; this->_write_vio.op = VIO::WRITE; - this->_write_vio.reenable(); + this->_process_write_vio(); + this->_send_tracked_event(this->_write_event, VC_EVENT_WRITE_READY, &this->_write_vio); return &this->_write_vio; } @@ -200,27 +211,143 @@ HQClientTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader void HQClientTransaction::do_io_close(int lerrno) { + SET_HANDLER(&HQClientTransaction::state_stream_closed); + + if (this->_read_event) { + this->_read_event->cancel(); + this->_read_event = nullptr; + } + + if (this->_write_event) { + this->_write_event->cancel(); + this->_write_event = nullptr; + } + + this->_read_vio.buffer.clear(); + this->_read_vio.nbytes = 0; + this->_read_vio.op = VIO::NONE; + this->_read_vio._cont = nullptr; + + this->_write_vio.buffer.clear(); + this->_write_vio.nbytes = 0; + this->_write_vio.op = VIO::NONE; + this->_write_vio._cont = nullptr; + parent->do_io_close(lerrno); } +void +HQClientTransaction::do_io_shutdown(ShutdownHowTo_t howto) +{ + return; +} + +void +HQClientTransaction::reenable(VIO *vio) +{ + if (vio->op == VIO::READ) { + int64_t len = this->_process_read_vio(); + if (len > 0) { + this->_signal_read_event(); + } + } else if (vio->op == VIO::WRITE) { + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); + } + } +} + +/** + * @brief Replace existing event only if the new event is different than the inprogress event + */ +Event * +HQClientTransaction::_send_tracked_event(Event *event, int send_event, VIO *vio) +{ + if (event != nullptr) { + if (event->callback_event != send_event) { + event->cancel(); + event = nullptr; + } + } + + if (event == nullptr) { + event = this_ethread()->schedule_imm(this, send_event, vio); + } + + return event; +} + +void +HQClientTransaction::set_read_vio_nbytes(int64_t nbytes) +{ + this->_read_vio.nbytes = nbytes; +} + +void +HQClientTransaction::set_write_vio_nbytes(int64_t nbytes) +{ + this->_write_vio.nbytes = nbytes; +} + void HQClientTransaction::destroy() { current_reader = nullptr; } +/** + * @brief Signal event to this->_read_vio._cont + */ void -HQClientTransaction::do_io_shutdown(ShutdownHowTo_t howto) +HQClientTransaction::_signal_read_event() { - if (parent) { - parent->do_io_shutdown(howto); + if (this->_read_vio._cont == nullptr || this->_read_vio.op == VIO::NONE) { + return; + } + int event = this->_read_vio.ntodo() ? VC_EVENT_READ_READY : VC_EVENT_READ_COMPLETE; + + MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread()); + if (lock.is_locked()) { + this->_read_vio._cont->handleEvent(event, &this->_read_vio); + } else { + this_ethread()->schedule_imm(this->_read_vio._cont, event, &this->_read_vio); } + + HQTransDebug("%s", get_vc_event_name(event)); } -// Convert HTTP/0.9 to HTTP/1.1 +/** + * @brief Signal event to this->_write_vio._cont + */ void -HQClientTransaction::_read_request() +HQClientTransaction::_signal_write_event() { + if (this->_write_vio._cont == nullptr || this->_write_vio.op == VIO::NONE) { + return; + } + int event = this->_write_vio.ntodo() ? VC_EVENT_WRITE_READY : VC_EVENT_WRITE_COMPLETE; + + MUTEX_TRY_LOCK(lock, this->_write_vio.mutex, this_ethread()); + if (lock.is_locked()) { + this->_write_vio._cont->handleEvent(event, &this->_write_vio); + } else { + this_ethread()->schedule_imm(this->_write_vio._cont, event, &this->_write_vio); + } + + HQTransDebug("%s", get_vc_event_name(event)); +} + +// Convert HTTP/0.9 to HTTP/1.1 +int64_t +HQClientTransaction::_process_read_vio() +{ + if (this->_read_vio._cont == nullptr || this->_read_vio.op == VIO::NONE) { + return 0; + } + + SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); + IOBufferReader *client_vio_reader = this->_stream_io->get_read_buffer_reader(); int64_t bytes_avail = client_vio_reader->read_avail(); @@ -233,33 +360,40 @@ HQClientTransaction::_read_request() MIOBuffer *writer = this->_read_vio.get_writer(); writer->write(client_vio_reader, bytes_avail - n); + client_vio_reader->consume(bytes_avail); // FIXME: Get hostname from SNI? const char version[] = " HTTP/1.1\r\nHost: localhost\r\n\r\n"; writer->write(version, sizeof(version)); - dump_io_buffer(this->sm_reader); - - this->_read_vio._cont->handleEvent(VC_EVENT_READ_READY, &this->_read_vio); + return bytes_avail; } // FIXME: already defined somewhere? static constexpr char http_1_1_version[] = "HTTP/1.1"; // Convert HTTP/1.1 to HTTP/0.9 -void -HQClientTransaction::_write_response() +int64_t +HQClientTransaction::_process_write_vio() { + if (this->_write_vio._cont == nullptr || this->_write_vio.op == VIO::NONE) { + return 0; + } + SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); IOBufferReader *reader = this->_write_vio.get_reader(); - if (memcmp(reader->start(), http_1_1_version, sizeof(http_1_1_version) - 1) == 0) { + int64_t http_1_1_version_len = sizeof(http_1_1_version) - 1; + + if (reader->is_read_avail_more_than(http_1_1_version_len) && + memcmp(reader->start(), http_1_1_version, http_1_1_version_len) == 0) { // Skip HTTP/1.1 response headers IOBufferBlock *headers = reader->get_current_block(); int64_t headers_size = headers->read_avail(); reader->consume(headers_size); this->_write_vio.ndone += headers_size; + // The size of respons to client this->_stream_io->set_write_vio_nbytes(this->_write_vio.nbytes - headers_size); } @@ -267,11 +401,16 @@ HQClientTransaction::_write_response() // Write HTTP/1.1 response body int64_t bytes_avail = reader->read_avail(); int64_t total_written = 0; + + HQTransDebug("%" PRId64, bytes_avail); + while (total_written < bytes_avail) { - int64_t bytes_written = this->_stream_io->write(reader, bytes_avail); - if (bytes_written == 0) { + int64_t data_len = reader->block_read_avail(); + int64_t bytes_written = this->_stream_io->write(reader, data_len); + if (bytes_written <= 0) { break; } + reader->consume(bytes_written); this->_write_vio.ndone += bytes_written; total_written += bytes_written; @@ -283,12 +422,7 @@ HQClientTransaction::_write_response() this->_stream_io->shutdown(); } - this->_stream_io->write_reenable(); - - // Send back WRITE_READY event to HttpTunnel - if (this->_write_vio.ntodo() > 0 && this->_write_vio.get_writer()->write_avail()) { - this->_write_vio._cont->handleEvent(VC_EVENT_WRITE_READY, &this->_write_vio); - } + return total_written; } void diff --git a/proxy/hq/HQClientTransaction.h b/proxy/hq/HQClientTransaction.h index cad8b6c43f5..550f6b3d9d1 100644 --- a/proxy/hq/HQClientTransaction.h +++ b/proxy/hq/HQClientTransaction.h @@ -23,6 +23,7 @@ #pragma once +#include "I_VConnection.h" #include "ProxyClientTransaction.h" class QUICStreamIO; @@ -35,11 +36,6 @@ class HQClientTransaction : public ProxyClientTransaction HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io); - // Implement VConnection interface. - VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; - VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; - void do_io_close(int lerrno = -1) override; - // Implement ProxyClienTransaction interface void set_active_timeout(ink_hrtime timeout_in) override; void set_inactivity_timeout(ink_hrtime timeout_in) override; @@ -47,22 +43,35 @@ class HQClientTransaction : public ProxyClientTransaction void transaction_done() override; bool allow_half_open() const override; void destroy() override; - void do_io_shutdown(ShutdownHowTo_t howto) override; - void reenable(VIO *vio) override; void release(IOBufferReader *r) override; int get_transaction_id() const override; + // VConnection interface + VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; + VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; + void do_io_close(int lerrno = -1) override; + void do_io_shutdown(ShutdownHowTo_t) override; + void reenable(VIO *) override; + + void set_read_vio_nbytes(int64_t nbytes); + void set_write_vio_nbytes(int64_t nbytes); + // HQClientTransaction specific methods - int main_event_handler(int event, void *edata); + int state_stream_open(int, void *); + int state_stream_closed(int event, void *data); private: - void _read_request(); - void _write_response(); + Event *_send_tracked_event(Event *, int, VIO *); + void _signal_read_event(); + void _signal_write_event(); + int64_t _process_read_vio(); + int64_t _process_write_vio(); + + MIOBuffer _read_vio_buf = CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX; + QUICStreamIO *_stream_io = nullptr; - MIOBuffer _read_vio_buf = CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX; VIO _read_vio; VIO _write_vio; - QUICStreamIO *_stream_io = nullptr; - Event *_read_event = nullptr; - Event *_write_event = nullptr; + Event *_read_event = nullptr; + Event *_write_event = nullptr; }; diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index a245642d7d0..6b9583bc25f 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -56,18 +56,24 @@ QUICSimpleApp::main_event_handler(int event, Event *data) { Debug(tag, "%s", QUICDebugNames::vc_event(event)); - QUICStream *stream = reinterpret_cast(data->cookie); - QUICStreamIO *stream_io = this->_find_stream_io(stream->id()); + VIO *vio = reinterpret_cast(data); + + QUICStreamIO *stream_io = this->_find_stream_io(vio); + QUICStreamId stream_id = this->_find_stream_id(vio); + if (stream_io == nullptr) { - Debug(tag, "Unknown Stream, id: %d", stream->id()); + Debug(tag, "Unknown Stream"); return -1; } switch (event) { case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { + // TODO: lookup transaction if support POST request if (stream_io->read_avail()) { HQClientTransaction *trans = new HQClientTransaction(this->_client_session, stream_io); + SCOPED_MUTEX_LOCK(lock, trans->mutex, this_ethread()); + trans->new_transaction(); } else { Debug(tag, "No MSG"); @@ -76,8 +82,7 @@ QUICSimpleApp::main_event_handler(int event, Event *data) } case VC_EVENT_WRITE_READY: case VC_EVENT_WRITE_COMPLETE: { - HQClientTransaction *trans = this->_client_session->get_transaction(stream->id()); - + HQClientTransaction *trans = this->_client_session->get_transaction(stream_id); trans->handleEvent(event); break; From 77e901243ebc3a5c24e9eed88c2a6d3676c91d81 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 12 Dec 2017 11:20:02 +0900 Subject: [PATCH 0231/1313] Cleanup QUICSimpleApp --- iocore/net/quic/QUICApplication.cc | 37 +++++++++++------------------- iocore/net/quic/QUICApplication.h | 4 +--- proxy/hq/QUICSimpleApp.cc | 31 ++++++++++++++----------- 3 files changed, 31 insertions(+), 41 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 5b8f3f4dc87..b5b191d9214 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -37,9 +37,7 @@ QUICStreamIO::QUICStreamIO(QUICApplication *app, QUICStream *stream) : _stream(s this->_read_buffer_reader = _read_buffer->alloc_reader(); this->_write_buffer_reader = _write_buffer->alloc_reader(); - this->_read_vio = stream->do_io_read(app, INT64_MAX, this->_read_buffer); - this->_read_vio->buffer.reader_for(this->_read_buffer_reader); - + this->_read_vio = stream->do_io_read(app, INT64_MAX, this->_read_buffer); this->_write_vio = stream->do_io_write(app, INT64_MAX, this->_write_buffer_reader); } @@ -49,6 +47,12 @@ QUICStreamIO::read_avail() return this->_read_buffer_reader->read_avail(); } +bool +QUICStreamIO::is_read_avail_more_than(int64_t size) +{ + return this->_read_buffer_reader->is_read_avail_more_than(size); +} + int64_t QUICStreamIO::read(uint8_t *buf, int64_t len) { @@ -123,12 +127,6 @@ QUICStreamIO::get_transaction_id() const return this->_stream->id(); } -bool -QUICStreamIO::is_vio(VIO *vio) -{ - return (this->_read_vio == vio || this->_write_vio == vio); -} - // // QUICApplication // @@ -192,23 +190,14 @@ QUICApplication::_find_stream_io(QUICStreamId id) QUICStreamIO * QUICApplication::_find_stream_io(VIO *vio) { - for (auto i : this->_stream_map) { - if (i.second->is_vio(vio)) { - return i.second; - } + if (vio == nullptr) { + return nullptr; } - return nullptr; -} - -QUICStreamId -QUICApplication::_find_stream_id(VIO *vio) -{ - for (auto i : this->_stream_map) { - if (i.second->is_vio(vio)) { - return i.first; - } + QUICStream *stream = dynamic_cast(vio->vc_server); + if (stream == nullptr) { + return nullptr; } - return 0; + return this->_find_stream_io(stream->id()); } diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index f8a37aaff82..0f34c56c0de 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -40,6 +40,7 @@ class QUICStreamIO QUICStreamIO(QUICApplication *app, QUICStream *stream); int64_t read_avail(); + bool is_read_avail_more_than(int64_t size); int64_t read(uint8_t *buf, int64_t len); int64_t write(const uint8_t *buf, int64_t len); int64_t write(IOBufferReader *r, int64_t len = INT64_MAX, int64_t offset = 0); @@ -49,7 +50,6 @@ class QUICStreamIO IOBufferReader *get_read_buffer_reader(); void shutdown(); uint32_t get_transaction_id() const; - bool is_vio(VIO *); private: QUICStream *_stream = nullptr; @@ -81,9 +81,7 @@ class QUICApplication : public Continuation protected: QUICStreamIO *_find_stream_io(QUICStreamId id); - // TODO: return pair QUICStreamIO *_find_stream_io(VIO *vio); - QUICStreamId _find_stream_id(VIO *vio); QUICConnection *_client_qc = nullptr; diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index 6b9583bc25f..310a5a0999b 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -56,34 +56,37 @@ QUICSimpleApp::main_event_handler(int event, Event *data) { Debug(tag, "%s", QUICDebugNames::vc_event(event)); - VIO *vio = reinterpret_cast(data); - + VIO *vio = reinterpret_cast(data); QUICStreamIO *stream_io = this->_find_stream_io(vio); - QUICStreamId stream_id = this->_find_stream_id(vio); if (stream_io == nullptr) { Debug(tag, "Unknown Stream"); return -1; } + QUICStreamId stream_id = stream_io->get_transaction_id(); + HQClientTransaction *txn = this->_client_session->get_transaction(stream_id); + switch (event) { case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { - // TODO: lookup transaction if support POST request - if (stream_io->read_avail()) { - HQClientTransaction *trans = new HQClientTransaction(this->_client_session, stream_io); - SCOPED_MUTEX_LOCK(lock, trans->mutex, this_ethread()); - - trans->new_transaction(); - } else { - Debug(tag, "No MSG"); + if (stream_io->is_read_avail_more_than(0)) { + if (txn == nullptr) { + txn = new HQClientTransaction(this->_client_session, stream_io); + SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); + + txn->new_transaction(); + } else { + txn->handleEvent(event); + } + break; } - break; } case VC_EVENT_WRITE_READY: case VC_EVENT_WRITE_COMPLETE: { - HQClientTransaction *trans = this->_client_session->get_transaction(stream_id); - trans->handleEvent(event); + if (txn != nullptr) { + txn->handleEvent(event); + } break; } From fd308e09a529500daada004efaffc5bd94f710e4 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 12 Dec 2017 11:35:16 +0900 Subject: [PATCH 0232/1313] Stop increasing nbytes on write --- iocore/net/quic/QUICApplication.cc | 11 +++-------- iocore/net/quic/QUICHandshake.cc | 3 ++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index b5b191d9214..83559e67a7a 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -66,10 +66,7 @@ QUICStreamIO::write(const uint8_t *buf, int64_t len) { SCOPED_MUTEX_LOCK(lock, this->_write_vio->mutex, this_ethread()); - int64_t bytes_add = this->_write_buffer->write(buf, len); - this->_write_vio->nbytes += bytes_add; - - return bytes_add; + return this->_write_buffer->write(buf, len); } int64_t @@ -82,10 +79,8 @@ QUICStreamIO::write(IOBufferReader *r, int64_t alen, int64_t offset) this->_write_vio->ndone, bytes_avail, alen); if (bytes_avail > 0) { - int64_t len = std::min(bytes_avail, alen); - int64_t bytes_added = this->_write_buffer->write(r, len, offset); - - return bytes_added; + int64_t len = std::min(bytes_avail, alen); + return this->_write_buffer->write(r, len, offset); } else { return 0; } diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 4cb34b3fcc9..5c262c8379a 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -29,6 +29,7 @@ #include "QUICVersionNegotiator.h" #include "QUICConfig.h" #include "P_SSLNextProtocolSet.h" +#include "P_VConnection.h" static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; @@ -271,7 +272,7 @@ QUICHandshake::state_address_validation(int event, void *data) int QUICHandshake::state_complete(int event, void *data) { - QUICHSDebug("event: %d", event); + QUICHSDebug("%s", get_vc_event_name(event)); QUICHSDebug("Got an event on complete state. Ignoring it for now."); return EVENT_CONT; From 9786e2b8507c0eb76c6f874b5bcf66e4f7012565 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 12 Dec 2017 14:00:12 +0900 Subject: [PATCH 0233/1313] Send NEW_CONNECTION_ID frames when connection establish --- iocore/net/P_QUICNetVConnection.h | 14 +++++ iocore/net/P_QUICPacketHandler.h | 2 + iocore/net/QUICNetVConnection.cc | 51 ++++++++++++++++++- iocore/net/QUICPacketHandler.cc | 8 ++- iocore/net/quic/QUICFrame.cc | 27 ++++++++-- iocore/net/quic/QUICFrame.h | 12 ++++- iocore/net/quic/QUICStreamManager.cc | 5 +- iocore/net/quic/QUICTypes.h | 47 +++++++++-------- iocore/net/quic/test/test_QUICFrame.cc | 22 ++++---- .../net/quic/test/test_QUICPacketFactory.cc | 2 +- 10 files changed, 146 insertions(+), 44 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index d7efa38dc07..6d3a12ac689 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -189,9 +189,22 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICErrorUPtr handle_frame(std::shared_ptr frame) override; private: + class AltConnectionInfo + { + public: + int seq_num; + QUICConnectionId id; + QUICStatelessResetToken token; + }; + std::random_device _rnd; + QUICConnectionId _original_quic_connection_id; QUICConnectionId _quic_connection_id; + + AltConnectionInfo _alt_quic_connection_ids[3]; + int8_t _alt_quic_connection_id_seq_num = 0; + QUICPacketNumber _largest_received_packet_number = 0; UDPConnection *_udp_con = nullptr; QUICPacketHandler *_packet_handler = nullptr; @@ -264,6 +277,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _switch_to_close_state(); void _handle_idle_timeout(); + void _update_alt_connection_ids(uint8_t chosen); QUICStatelessResetToken _reset_token; }; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index e1ea3fbae29..564dbbad331 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -43,6 +43,8 @@ struct QUICPacketHandler : public NetAccept { void send_packet(const QUICPacket &packet, QUICNetVConnection *vc); void send_packet(const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu); + void registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc); + private: void _recv_packet(int event, UDPPacket *udpPacket); bool _read_connection_id(QUICConnectionId &cid, IOBufferBlock *block); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index af0a1674fee..226fcd2b6ad 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -93,12 +93,12 @@ QUICNetVConnection::startEvent(int /*event ATS_UNUSED */, Event *e) void QUICNetVConnection::start(SSL_CTX *ssl_ctx) { - // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not { QUICConfig::scoped_config params; - this->_reset_token.generate(_quic_connection_id ^ params->server_id()); + this->_reset_token.generate(this->_quic_connection_id, params->server_id()); } + // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_reset_token); this->_application_map = new QUICApplicationMap(); this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); @@ -667,6 +667,8 @@ QUICNetVConnection::_state_common_receive_packet() { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); QUICPacketCreationResult result; + + // Receive a QUIC packet QUICPacketUPtr p = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::FAILED) { return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); @@ -675,6 +677,25 @@ QUICNetVConnection::_state_common_receive_packet() } net_activity(this, this_ethread()); + // Check connection migration + if (p->connection_id() != this->_quic_connection_id) { + for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { + AltConnectionInfo &info = this->_alt_quic_connection_ids[i]; + if (info.id == p->connection_id()) { + // Migrate connection + // TODO Address Validation + // TODO Adjust expected packet number with a gap computed based on info.seq_num + // TODO Unregister the old connection id (Should we wait for a while?) + this->_quic_connection_id = info.id; + this->_reset_token = info.token; + this->_update_alt_connection_ids(i); + break; + } + } + ink_assert(p->connection_id() == this->_quic_connection_id); + } + + // Process the packet switch (p->type()) { case QUICPacketType::PROTECTED: error = this->_state_connection_established_process_packet(std::move(p)); @@ -1012,6 +1033,7 @@ QUICNetVConnection::_switch_to_established_state() if (this->_complete_handshake_if_possible() == 0) { QUICConDebug("Enter state_connection_established"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); + this->_update_alt_connection_ids(countof(this->_alt_quic_connection_ids) - 1); } else { // Illegal state change ink_assert(!"Handshake has to be completed"); @@ -1052,3 +1074,28 @@ QUICNetVConnection::_handle_idle_timeout() // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application } + +void +QUICNetVConnection::_update_alt_connection_ids(uint8_t chosen) +{ + QUICConfig::scoped_config params; + int n = sizeof(this->_alt_quic_connection_ids); + int current = this->_alt_quic_connection_id_seq_num % n; + int delta = chosen - current; + int count = (n + delta) % n + 1; + + for (int i = 0; i < count; ++i) { + int index = (current + i) % n; + QUICConnectionId conn_id; + QUICStatelessResetToken token; + + conn_id.randomize(); + token.generate(conn_id, params->server_id()); + this->_alt_quic_connection_ids[index] = {this->_alt_quic_connection_id_seq_num + i, conn_id, token}; + this->_packet_handler->registerAltConnectionId(conn_id, this); + this->transmit_frame(QUICFrameFactory::create_new_connection_id_frame(this->_alt_quic_connection_ids[index].seq_num, + this->_alt_quic_connection_ids[index].id, + this->_alt_quic_connection_ids[index].token)); + } + this->_alt_quic_connection_id_seq_num += count; +} diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index fb20376c6a4..5c5583ffd44 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -139,7 +139,7 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) QUICStatelessResetToken token; { QUICConfig::scoped_config params; - token.generate(cid ^ params->server_id()); + token.generate(cid, params->server_id()); } auto packet = QUICPacketFactory::create_stateless_reset_packet(cid, token); this->send_packet(*packet, udpPacket->getConnection(), con.addr, 1200); @@ -208,3 +208,9 @@ QUICPacketHandler::send_packet(const QUICPacket &packet, UDPConnection *udp_con, udp_con->send(this, udpPkt); } + +void +QUICPacketHandler::registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc) +{ + this->_connections.put(id, vc); +} diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 4e61a1c210b..a91c78fdae9 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1107,10 +1107,10 @@ QUICStreamIdNeededFrame::store(uint8_t *buf, size_t *len) const // NEW_CONNECTION_ID frame // -QUICNewConnectionIdFrame::QUICNewConnectionIdFrame(uint16_t sequence, QUICConnectionId connection_id) +QUICNewConnectionIdFrame::QUICNewConnectionIdFrame(uint16_t sequence, QUICConnectionId connection_i, + QUICStatelessResetToken stateless_reset_token) + : _sequence(sequence), _connection_id(connection_i), _stateless_reset_token(stateless_reset_token) { - this->_sequence = sequence; - this->_connection_id = connection_id; } QUICFrameType @@ -1136,6 +1136,8 @@ QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len) const p += n; QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, p, &n); p += n; + memcpy(p, this->_stateless_reset_token.buf(), QUICStatelessResetToken::LEN); + p += QUICStatelessResetToken::LEN; *len = p - buf; } @@ -1160,6 +1162,16 @@ QUICNewConnectionIdFrame::connection_id() const } } +QUICStatelessResetToken +QUICNewConnectionIdFrame::stateless_reset_token() const +{ + if (this->_buf) { + return QUICStatelessResetToken(this->_buf + 11); + } else { + return this->_stateless_reset_token; + } +} + // // STOP_SENDING frame // @@ -1471,6 +1483,15 @@ QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICAppError return std::unique_ptr(frame, &QUICFrameDeleter::delete_stop_sending_frame); } +std::unique_ptr +QUICFrameFactory::create_new_connection_id_frame(uint32_t sequence, QUICConnectionId connectoin_id, + QUICStatelessResetToken stateless_reset_token) +{ + QUICNewConnectionIdFrame *frame = quicNewConnectionIdFrameAllocator.alloc(); + new (frame) QUICNewConnectionIdFrame(sequence, connectoin_id, stateless_reset_token); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_connection_id_frame); +} + std::unique_ptr QUICFrameFactory::create_retransmission_frame(QUICFrameUPtr original_frame, const QUICPacket &original_packet) { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 9f51b3f46f6..59fd66dc2c5 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -36,7 +36,7 @@ class QUICFrame public: QUICFrame(const uint8_t *buf, size_t len) : _buf(buf), _len(len){}; virtual QUICFrameType type() const; - virtual size_t size() const = 0; + virtual size_t size() const = 0; virtual void store(uint8_t *buf, size_t *len) const = 0; virtual void reset(const uint8_t *buf, size_t len); static QUICFrameType type(const uint8_t *buf); @@ -407,16 +407,18 @@ class QUICNewConnectionIdFrame : public QUICFrame public: QUICNewConnectionIdFrame() : QUICFrame() {} QUICNewConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICNewConnectionIdFrame(uint16_t sequence, QUICConnectionId connection_id); + QUICNewConnectionIdFrame(uint16_t sequence, QUICConnectionId connection_id, QUICStatelessResetToken stateless_reset_token); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; uint16_t sequence() const; QUICConnectionId connection_id() const; + QUICStatelessResetToken stateless_reset_token() const; private: uint16_t _sequence = 0; QUICConnectionId _connection_id = 0; + QUICStatelessResetToken _stateless_reset_token; }; // @@ -677,6 +679,12 @@ class QUICFrameFactory static std::unique_ptr create_stop_sending_frame(QUICStreamId stream_id, QUICAppErrorCode error_code); + /* + * Creates a NEW_CONNECTION_ID frame. + */ + static std::unique_ptr create_new_connection_id_frame( + uint32_t sequence, QUICConnectionId connectoin_id, QUICStatelessResetToken stateless_reset_token); + /* * Creates a retransmission frame, which is very special. * This retransmission frame will be used only for retransmission and it's not a standard frame type. diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 5223bb4db46..f3b3d940fec 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -40,10 +40,7 @@ std::vector QUICStreamManager::interests() { return { - QUICFrameType::STREAM, - QUICFrameType::RST_STREAM, - QUICFrameType::MAX_STREAM_DATA, - QUICFrameType::MAX_STREAM_ID, + QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::MAX_STREAM_DATA, QUICFrameType::MAX_STREAM_ID, }; } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index b0a137427dc..6757d7042ce 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -200,27 +200,6 @@ using QUICErrorUPtr = std::unique_ptr; using QUICConnectionErrorUPtr = std::unique_ptr; using QUICStreamErrorUPtr = std::unique_ptr; -class QUICStatelessResetToken -{ -public: - void - generate(uint64_t data) - { - this->_gen_token(data); - } - - const uint8_t * - buf() const - { - return _token; - } - -private: - uint8_t _token[16] = {0}; - - void _gen_token(uint64_t data); -}; - class QUICConnectionId { public: @@ -240,6 +219,32 @@ class QUICConnectionId uint64_t _id; }; +class QUICStatelessResetToken +{ +public: + constexpr static int8_t LEN = 16; + + QUICStatelessResetToken() {} + QUICStatelessResetToken(const uint8_t *buf) { memcpy(this->_token, buf, QUICStatelessResetToken::LEN); } + + void + generate(QUICConnectionId conn_id, uint32_t server_id) + { + this->_gen_token(conn_id ^ server_id); + } + + const uint8_t * + buf() const + { + return _token; + } + +private: + uint8_t _token[16] = {0}; + + void _gen_token(uint64_t data); +}; + enum class QUICStreamType { SERVER, CLIENT, HANDSHAKE }; class QUICTypeUtil diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 84a6fbb329a..34897467b3b 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -720,9 +720,11 @@ TEST_CASE("Store StreamIdNeeded Frame", "[quic]") TEST_CASE("Load NewConnectionId Frame", "[quic]") { uint8_t buf1[] = { - 0x0b, // Type - 0x01, 0x02, // Sequence - 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Connection ID + 0x0b, // Type + 0x01, 0x02, // Sequence + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token + 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::NEW_CONNECTION_ID); @@ -732,6 +734,7 @@ TEST_CASE("Load NewConnectionId Frame", "[quic]") CHECK(newConnectionIdFrame1 != nullptr); CHECK(newConnectionIdFrame1->sequence() == 0x0102); CHECK(newConnectionIdFrame1->connection_id() == 0x1122334455667788ULL); + CHECK(memcmp(newConnectionIdFrame1->stateless_reset_token().buf(), buf1 + 11, 16) == 0); } TEST_CASE("Store NewConnectionId Frame", "[quic]") @@ -739,14 +742,13 @@ TEST_CASE("Store NewConnectionId Frame", "[quic]") uint8_t buf[65535]; size_t len; - uint8_t expected[] = { - 0x0b, // Type - 0x01, 0x02, // Sequence - 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Connection ID - }; - QUICNewConnectionIdFrame newConnectionIdFrame(0x0102, 0x1122334455667788ULL); + uint8_t expected[] = {0x0b, // Type + 0x01, 0x02, // Sequence + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + QUICNewConnectionIdFrame newConnectionIdFrame(0x0102, 0x1122334455667788ULL, {expected + 11}); newConnectionIdFrame.store(buf, &len); - CHECK(len == 11); + CHECK(len == 27); CHECK(memcmp(buf, expected, len) == 0); } diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index b6f6dcfe74a..f5fcf156279 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -78,7 +78,7 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") MockQUICCrypto crypto; factory.set_crypto_module(&crypto); QUICStatelessResetToken token; - token.generate(12345); + token.generate(12345, 67890); uint8_t expected_output[] = { 0x41, // 0CK0001 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, // Connection ID From 387788783bf1013b982474ee59ec095345c964dd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 12 Dec 2017 15:55:34 +0900 Subject: [PATCH 0234/1313] draft-08: Support long header packet type & format --- iocore/net/QUICNetVConnection.cc | 16 ++-- iocore/net/quic/QUICDebugNames.cc | 14 ++-- iocore/net/quic/QUICHandshake.cc | 2 +- iocore/net/quic/QUICLossDetector.cc | 4 +- iocore/net/quic/QUICPacket.cc | 77 ++++++++++--------- iocore/net/quic/QUICPacket.h | 8 +- iocore/net/quic/QUICTypes.h | 20 ++--- iocore/net/quic/test/test_QUICLossDetector.cc | 4 +- iocore/net/quic/test/test_QUICPacket.cc | 41 ++++++---- .../net/quic/test/test_QUICPacketFactory.cc | 6 +- .../quic/test/test_QUICVersionNegotiator.cc | 3 +- 11 files changed, 106 insertions(+), 89 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 226fcd2b6ad..013d1eee0a0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -596,10 +596,10 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (packet->type()) { - case QUICPacketType::CLIENT_INITIAL: + case QUICPacketType::INITIAL: error = this->_state_handshake_process_initial_client_packet(std::move(packet)); break; - case QUICPacketType::CLIENT_CLEARTEXT: + case QUICPacketType::HANDSHAKE: error = this->_state_handshake_process_client_cleartext_packet(std::move(packet)); break; case QUICPacketType::ZERO_RTT_PROTECTED: @@ -700,7 +700,7 @@ QUICNetVConnection::_state_common_receive_packet() case QUICPacketType::PROTECTED: error = this->_state_connection_established_process_packet(std::move(p)); break; - case QUICPacketType::CLIENT_CLEARTEXT: + case QUICPacketType::HANDSHAKE: // FIXME Just ignore for now but it has to be acked (GitHub#2609) break; default: @@ -857,17 +857,17 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); switch (type) { - case QUICPacketType::SERVER_CLEARTEXT: - packet = this->_packet_factory.create_server_cleartext_packet(this->_quic_connection_id, this->largest_acked_packet_number(), - std::move(buf), len, retransmittable); + case QUICPacketType::HANDSHAKE: + packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), + std::move(buf), len, retransmittable); break; default: if (this->_handshake_handler && this->_handshake_handler->is_completed()) { packet = this->_packet_factory.create_server_protected_packet(this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); } else { - packet = this->_packet_factory.create_server_cleartext_packet(this->_quic_connection_id, this->largest_acked_packet_number(), - std::move(buf), len, retransmittable); + packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), + std::move(buf), len, retransmittable); } break; } diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index dd750dfa007..1b794c988c6 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -30,14 +30,12 @@ QUICDebugNames::packet_type(QUICPacketType type) switch (type) { case QUICPacketType::VERSION_NEGOTIATION: return "VERSION_NEGOTIATION"; - case QUICPacketType::CLIENT_INITIAL: - return "CLIENT_INITIAL"; - case QUICPacketType::SERVER_STATELESS_RETRY: - return "SERVER_STATELESS_RETRY"; - case QUICPacketType::SERVER_CLEARTEXT: - return "SERVER_CLEARTEXT"; - case QUICPacketType::CLIENT_CLEARTEXT: - return "CLIENT_CLEARTEXT"; + case QUICPacketType::INITIAL: + return "INITIAL"; + case QUICPacketType::RETRY: + return "RETRY"; + case QUICPacketType::HANDSHAKE: + return "HANDSHAKE"; case QUICPacketType::ZERO_RTT_PROTECTED: return "ZERO_RTT_PROTECTED"; case QUICPacketType::PROTECTED: diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 5c262c8379a..8214a157efd 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -108,7 +108,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet { // Negotiate version if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) { - if (initial_packet->type() != QUICPacketType::CLIENT_INITIAL) { + if (initial_packet->type() != QUICPacketType::HANDSHAKE) { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); } if (initial_packet->version()) { diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index ec197957ca7..31cae5acc8d 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -150,9 +150,9 @@ QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) bool is_handshake = false; QUICPacketType type = packet->type(); + // XXX: Should QUICPacketType::SERVER_STATELESS_RETRY be included? - if (type == QUICPacketType::CLIENT_INITIAL || type == QUICPacketType::SERVER_CLEARTEXT || - type == QUICPacketType::CLIENT_CLEARTEXT) { + if (type == QUICPacketType::INITIAL || type == QUICPacketType::HANDSHAKE) { is_handshake = true; } diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 048d3d272c7..3fbc20f2aab 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -29,11 +29,15 @@ ClassAllocator quicPacketAllocator("quicPacketAllocator"); ClassAllocator quicPacketLongHeaderAllocator("quicPacketLongHeaderAllocator"); ClassAllocator quicPacketShortHeaderAllocator("quicPacketShortHeaderAllocator"); -static constexpr int OFFSET_CONNECTION_ID = 1; -static constexpr int OFFSET_PACKET_NUMBER = 9; -static constexpr int OFFSET_VERSION = 13; -static constexpr int OFFSET_PAYLOAD = 17; -static constexpr int LONGHEADER_LENGTH = 17; +static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 1; +static constexpr int LONG_HDR_OFFSET_VERSION = 9; +static constexpr int LONG_HDR_OFFSET_PACKET_NUMBER = 13; +static constexpr int LONG_HDR_OFFSET_PAYLOAD = 17; +static constexpr int LONG_HDR_LENGTH = 17; + +static constexpr int SHORT_HDR_OFFSET_CONNECTION_ID = 1; + +static constexpr int VERSION_NEGOTIATION_PKT_HEADER_LENGTH = 13; // // QUICPacketHeader @@ -126,11 +130,12 @@ QUICPacketType QUICPacketLongHeader::type() const { if (this->_buf) { - int type = this->_buf[0] & 0x7F; - if (type < static_cast(QUICPacketType::UNINITIALIZED)) { - return static_cast(type); + uint8_t type = this->_buf[0] & 0x7F; + if (this->version() == 0x00) { + return QUICPacketType::VERSION_NEGOTIATION; } else { - return QUICPacketType::UNINITIALIZED; + // any other version-specific type? + return static_cast(type); } } else { return this->_type; @@ -141,7 +146,7 @@ QUICConnectionId QUICPacketLongHeader::connection_id() const { if (this->_buf) { - return QUICTypeUtil::read_QUICConnectionId(this->_buf + OFFSET_CONNECTION_ID, 8); + return QUICTypeUtil::read_QUICConnectionId(this->_buf + LONG_HDR_OFFSET_CONNECTION_ID, 8); } else { return this->_connection_id; } @@ -152,8 +157,8 @@ QUICPacketLongHeader::packet_number() const { if (this->_buf) { const uint8_t packet_number_len = 4; - QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf + OFFSET_PACKET_NUMBER, packet_number_len); - QUICPacketNumber dst = 0; + QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf + LONG_HDR_OFFSET_PACKET_NUMBER, packet_number_len); + QUICPacketNumber dst = 0; QUICPacket::decode_packet_number(dst, src, packet_number_len, this->_base_packet_number); return dst; @@ -172,7 +177,7 @@ QUICVersion QUICPacketLongHeader::version() const { if (this->_buf) { - return QUICTypeUtil::read_QUICVersion(this->_buf + OFFSET_VERSION); + return QUICTypeUtil::read_QUICVersion(this->_buf + LONG_HDR_OFFSET_VERSION); } else { return this->_version; } @@ -188,7 +193,7 @@ const uint8_t * QUICPacketLongHeader::payload() const { if (this->_buf) { - return this->_buf + OFFSET_PAYLOAD; + return this->_buf + LONG_HDR_OFFSET_PAYLOAD; } else { return this->_payload.get(); } @@ -220,7 +225,11 @@ QUICPacketLongHeader::key_phase() const uint16_t QUICPacketLongHeader::size() const { - return LONGHEADER_LENGTH; + if (this->type() == QUICPacketType::VERSION_NEGOTIATION) { + return VERSION_NEGOTIATION_PKT_HEADER_LENGTH; + } else { + return LONG_HDR_LENGTH; + } } void @@ -298,7 +307,7 @@ QUICPacketShortHeader::connection_id() const { if (this->_buf) { ink_release_assert(this->has_connection_id()); - return QUICTypeUtil::read_QUICConnectionId(this->_buf + OFFSET_CONNECTION_ID, 8); + return QUICTypeUtil::read_QUICConnectionId(this->_buf + SHORT_HDR_OFFSET_CONNECTION_ID, 8); } else { return _connection_id; } @@ -309,9 +318,9 @@ QUICPacketShortHeader::packet_number() const { if (this->_buf) { int n = this->_packet_number_len(); - int offset = 1; + int offset = SHORT_HDR_OFFSET_CONNECTION_ID; if (this->has_connection_id()) { - offset = OFFSET_PACKET_NUMBER; + offset += 8; } QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf + offset, n); @@ -654,9 +663,8 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ result = QUICPacketCreationResult::NOT_READY; } break; - case QUICPacketType::CLIENT_INITIAL: - case QUICPacketType::CLIENT_CLEARTEXT: - case QUICPacketType::SERVER_CLEARTEXT: + case QUICPacketType::INITIAL: + case QUICPacketType::HANDSHAKE: if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { result = QUICPacketCreationResult::SUCCESS; @@ -698,12 +706,21 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se } QUICPacketUPtr -QUICPacketFactory::create_server_cleartext_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable) +QUICPacketFactory::create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, + ats_unique_buf payload, size_t len) +{ + QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::INITIAL, connection_id, this->_packet_number_generator.next(), + base_packet_number, version, std::move(payload), len); + return this->_create_encrypted_packet(header, true); +} + +QUICPacketUPtr +QUICPacketFactory::create_handshake_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, + ats_unique_buf payload, size_t len, bool retransmittable) { QUICPacketHeader *header = - QUICPacketHeader::build(QUICPacketType::SERVER_CLEARTEXT, connection_id, this->_packet_number_generator.next(), - base_packet_number, this->_version, std::move(payload), len); + QUICPacketHeader::build(QUICPacketType::HANDSHAKE, connection_id, this->_packet_number_generator.next(), base_packet_number, + this->_version, std::move(payload), len); return this->_create_encrypted_packet(header, retransmittable); } @@ -718,16 +735,6 @@ QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id return this->_create_encrypted_packet(header, retransmittable); } -QUICPacketUPtr -QUICPacketFactory::create_client_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - QUICVersion version, ats_unique_buf payload, size_t len) -{ - QUICPacketHeader *header = - QUICPacketHeader::build(QUICPacketType::CLIENT_INITIAL, connection_id, this->_packet_number_generator.next(), - base_packet_number, version, std::move(payload), len); - return this->_create_encrypted_packet(header, true); -} - QUICPacketUPtr QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessResetToken stateless_reset_token) { diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 79b82cf19fc..5f5d4f72f6d 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -295,12 +295,12 @@ class QUICPacketFactory QUICPacketUPtr create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result); QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number); - QUICPacketUPtr create_server_cleartext_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable); + QUICPacketUPtr create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, + ats_unique_buf payload, size_t len); + QUICPacketUPtr create_handshake_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, + ats_unique_buf payload, size_t len, bool retransmittable); QUICPacketUPtr create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); - QUICPacketUPtr create_client_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - QUICVersion version, ats_unique_buf payload, size_t len); static QUICPacketUPtr create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessResetToken stateless_reset_token); void set_version(QUICVersion negotiated_version); diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 6757d7042ce..09557e8b5d1 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -62,16 +62,16 @@ constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { }; constexpr QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; -enum class QUICPacketType : int { - VERSION_NEGOTIATION = 1, - CLIENT_INITIAL, - SERVER_STATELESS_RETRY, - SERVER_CLEARTEXT, - CLIENT_CLEARTEXT, - ZERO_RTT_PROTECTED, - PROTECTED, // Not on the spec. but just for convenience - STATELESS_RESET, // Not on the spec. but just for convenience - UNINITIALIZED, // Not on the spec. but just for convenience +// Devide to QUICPacketType and QUICPacketLongHeaderType ? +enum class QUICPacketType : uint8_t { + VERSION_NEGOTIATION = 0, + PROTECTED, // Not on the spec. but just for convenience // should be short header + STATELESS_RESET, // Not on the spec. but just for convenience + INITIAL = 0x7F, // draft-08 version-specific type + RETRY = 0x7E, // draft-08 version-specific type + HANDSHAKE = 0x7D, // draft-08 version-specific type + ZERO_RTT_PROTECTED = 0x7C, // draft-08 version-specific type + UNINITIALIZED = 0xFF, // Not on the spec. but just for convenience }; // To detect length of Packet Number diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 42841823b69..af39c417b31 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -40,8 +40,8 @@ TEST_CASE("QUICLossDetector_Loss_in_Handshake", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::SERVER_CLEARTEXT, 0xffddbb9977553311ULL, 0x00000001, 0, - 0x00112233, std::move(payload), sizeof(raw)); + QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, 0xffddbb9977553311ULL, 0x00000001, 0, 0x00112233, + std::move(payload), sizeof(raw)); QUICPacketUPtr packet = QUICPacketUPtr(new QUICPacket(header, std::move(payload), sizeof(raw), true), [](QUICPacket *p) { delete p; }); detector.on_packet_sent(std::move(packet)); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 8a39c5739c3..ee25cb08fce 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -27,20 +27,41 @@ TEST_CASE("QUICPacketHeader", "[quic]") { + SECTION("Long Header (load) Version Negotiation Packet") + { + const uint8_t input[] = { + 0x80, // Long header, Type: NONE + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID + 0x00, 0x00, 0x00, 0x00, // Version + 0x00, 0x00, 0x00, 0x08, // Supported Version 1 + 0x00, 0x00, 0x00, 0x09, // Supported Version 1 + }; + + QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); + CHECK(header->size() == 13); + CHECK(header->packet_size() == 21); + CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); + CHECK(header->has_connection_id() == true); + CHECK(header->connection_id() == 0x0102030405060708); + CHECK(header->has_version() == true); + CHECK(header->version() == 0x00000000); + CHECK(header->has_key_phase() == false); + } + SECTION("Long Header (load)") { const uint8_t input[] = { - 0x81, // Long header, Type + 0xFF, // Long header, Type: INITIAL 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID - 0x12, 0x34, 0x56, 0x78, // Packet number 0x11, 0x22, 0x33, 0x44, // Version + 0x12, 0x34, 0x56, 0x78, // Packet number 0xff, 0xff, // Payload (dummy) }; QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); CHECK(header->size() == 17); CHECK(header->packet_size() == 19); - CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); + CHECK(header->type() == QUICPacketType::INITIAL); CHECK(header->has_connection_id() == true); CHECK(header->connection_id() == 0x0102030405060708); CHECK(header->packet_number() == 0x12345678); @@ -55,13 +76,13 @@ TEST_CASE("QUICPacketHeader", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(expected)); memcpy(payload.get(), expected, sizeof(expected)); - QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::CLIENT_INITIAL, 0x0102030405060708, 0x12345678, 0, - 0xa0a0a0a0, std::move(payload), 32); + QUICPacketHeader *header = + QUICPacketHeader::build(QUICPacketType::INITIAL, 0x0102030405060708, 0x12345678, 0, 0xa0a0a0a0, std::move(payload), 32); CHECK(header->size() == 17); CHECK(header->has_key_phase() == false); CHECK(header->packet_size() == 0); - CHECK(header->type() == QUICPacketType::CLIENT_INITIAL); + CHECK(header->type() == QUICPacketType::INITIAL); CHECK(header->has_connection_id() == true); CHECK(header->connection_id() == 0x0102030405060708); CHECK(header->packet_number() == 0x12345678); @@ -110,14 +131,6 @@ TEST_CASE("QUICPacketHeader", "[quic]") } } -TEST_CASE("Loading Unknown Packet", "[quic]") -{ - const uint8_t buf[] = {0xff}; - QUICPacketHeader *header = QUICPacketHeader::load(buf, sizeof(buf), 0); - - CHECK(header->type() == QUICPacketType::UNINITIALIZED); -} - TEST_CASE("Encoded Packet Number Length", "[quic]") { QUICPacketNumber base = 0x6afa2f; diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index f5fcf156279..9f228009a16 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -53,7 +53,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") CHECK(memcmp(packet->payload(), "\xff\x00\x00\x07", 4) == 0); } -TEST_CASE("QUICPacketFactory_Create_ServerCleartextPacket", "[quic]") +TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") { QUICPacketFactory factory; MockQUICCrypto crypto; @@ -64,8 +64,8 @@ TEST_CASE("QUICPacketFactory_Create_ServerCleartextPacket", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketUPtr packet = factory.create_server_cleartext_packet(0x01020304, 0, std::move(payload), sizeof(raw), true); - CHECK(packet->type() == QUICPacketType::SERVER_CLEARTEXT); + QUICPacketUPtr packet = factory.create_handshake_packet(0x01020304, 0, std::move(payload), sizeof(raw), true); + CHECK(packet->type() == QUICPacketType::HANDSHAKE); CHECK(packet->connection_id() == 0x01020304); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); CHECK((packet->packet_number() & 0xFFFFFFFF80000000) == 0); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index c8c0a93062d..c4b34448da2 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -37,8 +37,7 @@ TEST_CASE("QUICVersionNegotiator_Normal", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); // Negotiate version - QUICPacketUPtr initial_packet = - packet_factory.create_client_initial_packet({}, 0, QUIC_SUPPORTED_VERSIONS[0], ats_unique_malloc(0), 0); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, QUIC_SUPPORTED_VERSIONS[0], ats_unique_malloc(0), 0); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); From 624c5c7e3274717667db4faf796867e8bc89d1ce Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 12 Dec 2017 16:08:08 +0900 Subject: [PATCH 0235/1313] draft-08: Support short header packet type & format --- iocore/net/quic/QUICPacket.cc | 2 +- iocore/net/quic/QUICTypes.h | 8 ++++---- iocore/net/quic/test/test_QUICPacket.cc | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 3fbc20f2aab..7bf6e8105c3 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -386,7 +386,7 @@ bool QUICPacketShortHeader::has_connection_id() const { if (this->_buf) { - return (this->_buf[0] & 0x40) != 0; + return (this->_buf[0] & 0x40) == 0; } else { return this->_has_connection_id; } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 09557e8b5d1..130bbd6dfb4 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -76,10 +76,10 @@ enum class QUICPacketType : uint8_t { // To detect length of Packet Number enum class QUICPacketShortHeaderType : int { - ONE = 1, - TWO, - THREE, - UNINITIALIZED, + ONE = 0x1F, + TWO = 0x1E, + THREE = 0x1D, + UNINITIALIZED = 0x1C, }; // XXX If you add or remove QUICFrameType, you might also need to change QUICFrame::type(const uint8_t *) diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index ee25cb08fce..e4877ddb250 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -93,7 +93,7 @@ TEST_CASE("QUICPacketHeader", "[quic]") SECTION("Short Header (load)") { const uint8_t input[] = { - 0x43, // Short header, with Connection ID, KeyPhse 0, Type + 0x1D, // Short header with (C=0, K=0, Type=0x1D) 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID 0x12, 0x34, 0x56, 0x78, // Packet number 0xff, 0xff, // Payload (dummy) From ab3a06b8a88880441539457f4fd314f1a0b55ea1 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 12 Dec 2017 16:28:11 +0900 Subject: [PATCH 0236/1313] Fix QUICPacketLongHeader::store for new long header format --- iocore/net/quic/QUICPacket.cc | 14 ++++++++------ iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 7bf6e8105c3..01802ba4f29 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -240,17 +240,18 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const buf[0] = 0x80; buf[0] += static_cast(this->_type); *len += 1; + QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, buf + *len, &n); *len += n; + QUICTypeUtil::write_QUICVersion(this->_version, buf + *len, &n); + *len += n; + QUICPacketNumber dst = 0; size_t dst_len = 4; QUICPacket::encode_packet_number(dst, this->_packet_number, dst_len); QUICTypeUtil::write_QUICPacketNumber(dst, dst_len, buf + *len, &n); *len += n; - - QUICTypeUtil::write_QUICVersion(this->_version, buf + *len, &n); - *len += n; } // @@ -699,9 +700,10 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se p += n; } - QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), - packet_sent_by_client->packet_number(), base_packet_number, - packet_sent_by_client->version(), std::move(versions), len); + QUICPacketHeader *header = + QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), + packet_sent_by_client->packet_number(), base_packet_number, 0x00, std::move(versions), len); + return QUICPacketFactory::_create_unprotected_packet(header); } diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 9f228009a16..97d5665cbdc 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -35,8 +35,8 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") uint8_t client_initial_packet_header[] = { 0x82, // Type 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection id - 0x00, 0x00, 0x00, 0x00, // Packet number 0xaa, 0xbb, 0xcc, 0xdd, // Version + 0x00, 0x00, 0x00, 0x00, // Packet number }; uint8_t client_initial_packet_payload[] = { 0x00 // Payload From c90274a75db135e2d420e457ed262cadd69954f2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 12 Dec 2017 16:28:27 +0900 Subject: [PATCH 0237/1313] draft-08: Bump version --- iocore/net/quic/QUICTypes.h | 4 ++-- iocore/net/quic/test/test_QUICPacketFactory.cc | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 130bbd6dfb4..7429009714e 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -55,10 +55,10 @@ using QUICStreamId = uint32_t; using QUICOffset = uint64_t; // TODO: Update version number -// Note: You also need to update tests for VersionNegotiationPacket, if you change the number of versions +// Note: You also need to update tests for VersionNegotiationPacket creation, if you change the number of versions // Prefix for drafts (0xff000000) + draft number constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff000007, + 0xff000008, }; constexpr QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 97d5665cbdc..db29759b0f7 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -50,7 +50,8 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); CHECK(packet->connection_id() == client_initial_packet.connection_id()); CHECK(packet->packet_number() == client_initial_packet.packet_number()); - CHECK(memcmp(packet->payload(), "\xff\x00\x00\x07", 4) == 0); + CHECK(packet->version() == 0x00); + CHECK(memcmp(packet->payload(), "\xff\x00\x00\x08", 4) == 0); } TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") From af62ebda49bc8511b61209f59d3fb3f6f6364615 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 13 Dec 2017 12:10:50 +0900 Subject: [PATCH 0238/1313] Parse and create ack block in draft-08 way --- iocore/net/P_QUICNetVConnection.h | 8 +- iocore/net/QUICNetVConnection.cc | 10 +- iocore/net/quic/Mock.h | 60 ++++--- iocore/net/quic/QUICAckFrameCreator.cc | 8 +- iocore/net/quic/QUICCongestionController.cc | 20 +++ iocore/net/quic/QUICCongestionController.h | 9 +- iocore/net/quic/QUICFrame.cc | 1 + iocore/net/quic/QUICLossDetector.cc | 17 +- iocore/net/quic/QUICLossDetector.h | 4 +- iocore/net/quic/QUICPacketTransmitter.h | 6 +- .../net/quic/test/test_QUICAckFrameCreator.cc | 16 +- iocore/net/quic/test/test_QUICLossDetector.cc | 150 ++++++++++++++---- 12 files changed, 229 insertions(+), 80 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 6d3a12ac689..4f4ba371a54 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -177,7 +177,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICPacketNumber largest_acked_packet_number() override; // QUICConnection (QUICPacketTransmitter) - virtual void transmit_packet(QUICPacketUPtr packet) override; + virtual uint32_t transmit_packet(QUICPacketUPtr packet) override; virtual void retransmit_packet(const QUICPacket &packet) override; virtual Ptr get_packet_transmitter_mutex() override; @@ -229,8 +229,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICRemoteFlowController *_remote_flow_controller = nullptr; QUICLocalFlowController *_local_flow_controller = nullptr; - Queue _packet_recv_queue; - Queue _packet_send_queue; + CountQueue _packet_recv_queue; + CountQueue _packet_send_queue; std::queue _quic_packet_recv_queue; // `_frame_send_queue` is the queue for any type of frame except STREAM frame. // The flow contorl doesn't blcok frames in this queue. @@ -243,7 +243,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _close_packet_write_ready(Event *data); Event *_packet_write_ready = nullptr; - void _transmit_packet(QUICPacketUPtr); + uint32_t _transmit_packet(QUICPacketUPtr); void _transmit_frame(QUICFrameUPtr); void _store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 013d1eee0a0..228134ce4de 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -110,7 +110,7 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) // Create frame handlers this->_stream_manager = new QUICStreamManager(this->connection_id(), this, this->_application_map); this->_congestion_controller = new QUICCongestionController(); - this->_loss_detector = new QUICLossDetector(this); + this->_loss_detector = new QUICLossDetector(this, this->_congestion_controller); this->_remote_flow_controller = new QUICRemoteConnectionFlowController(0, this); this->_local_flow_controller = new QUICLocalConnectionFlowController(0, this); @@ -216,7 +216,7 @@ QUICNetVConnection::stream_manager() return this->_stream_manager; } -void +uint32_t QUICNetVConnection::_transmit_packet(QUICPacketUPtr packet) { SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); @@ -225,13 +225,15 @@ QUICNetVConnection::_transmit_packet(QUICPacketUPtr packet) packet->size()); // TODO Remove const_cast this->_packet_send_queue.enqueue(const_cast(packet.release())); + return this->_packet_send_queue.size; } -void +uint32_t QUICNetVConnection::transmit_packet(QUICPacketUPtr packet) { - this->_transmit_packet(std::move(packet)); + uint32_t npackets = this->_transmit_packet(std::move(packet)); this->_schedule_packet_write_ready(); + return npackets; } void diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 3050a435f28..363de99a9ef 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -157,10 +157,11 @@ class MockQUICConnection : public QUICConnection return 0; } - void + uint32_t transmit_packet(QUICPacketUPtr packet) override { ++_transmit_count; + return 1; } void @@ -275,16 +276,21 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter { public: MockQUICPacketTransmitter() : QUICPacketTransmitter() { this->_mutex = new_ProxyMutex(); }; - void + + uint32_t transmit_packet(QUICPacketUPtr packet) override { - ++_transmit_count; + if (packet) { + this->transmitted.insert(packet->packet_number()); + return 1; + } + return 0; } void retransmit_packet(const QUICPacket &packet) override { - ++_retransmit_count; + this->retransmitted.insert(packet.packet_number()); } Ptr @@ -293,9 +299,10 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter return this->_mutex; } - int _transmit_count = 0; - int _retransmit_count = 0; Ptr _mutex; + + std::set transmitted; + std::set retransmitted; }; class MockQUICFrameTransmitter : public QUICFrameTransmitter @@ -316,25 +323,9 @@ class MockQUICFrameTransmitter : public QUICFrameTransmitter int frameCount[256] = {0}; }; -class MockQUICLossDetector : public QUICLossDetector -{ -public: - MockQUICLossDetector() : QUICLossDetector(new MockQUICPacketTransmitter()) {} - void - rcv_frame(std::shared_ptr) - { - } - - void - on_packet_sent(QUICPacketUPtr packet) - { - } -}; - class MockQUICCongestionController : public QUICCongestionController { public: - MockQUICCongestionController() : QUICCongestionController() {} // Override virtual QUICErrorUPtr handle_frame(std::shared_ptr f) override @@ -345,6 +336,14 @@ class MockQUICCongestionController : public QUICCongestionController return QUICErrorUPtr(new QUICNoError()); } + virtual void + on_packets_lost(std::set packets) override + { + for (auto pn : packets) { + lost_packets.insert(pn); + } + } + // for Test int getStreamFrameCount() @@ -370,11 +369,28 @@ class MockQUICCongestionController : public QUICCongestionController return _totalFrameCount; } + std::set lost_packets; + private: int _totalFrameCount = 0; int _frameCount[256] = {0}; }; +class MockQUICLossDetector : public QUICLossDetector +{ +public: + MockQUICLossDetector() : QUICLossDetector(new MockQUICPacketTransmitter(), new MockQUICCongestionController()) {} + void + rcv_frame(std::shared_ptr) + { + } + + void + on_packet_sent(QUICPacketUPtr packet) + { + } +}; + class MockQUICApplication : public QUICApplication { public: diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index eb58c7fe401..8c1dafb1210 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -87,10 +87,10 @@ QUICAckFrameCreator::_create_ack_frame() } if (ack_frame) { - ack_frame->ack_block_section()->add_ack_block({gap, length}); + ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { uint16_t delay = (Thread::get_hrtime() - this->_packet_numbers.largest_ack_received_time()) / 1000; // TODO Milliseconds? - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1); } gap = last_ack_number - this->_packet_numbers[i]; @@ -99,10 +99,10 @@ QUICAckFrameCreator::_create_ack_frame() } if (ack_frame) { - ack_frame->ack_block_section()->add_ack_block({gap, length}); + ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { uint16_t delay = (Thread::get_hrtime() - this->_packet_numbers.largest_ack_received_time()) / 1000; // TODO Milliseconds? - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1); } return ack_frame; } diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index d06902b5a32..96c2b556d47 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -49,3 +49,23 @@ QUICCongestionController::handle_frame(std::shared_ptr frame) return error; } + +void +QUICCongestionController::on_packet_sent() +{ +} + +void +QUICCongestionController::on_packet_acked() +{ +} + +void +QUICCongestionController::on_packets_lost(std::set packets) +{ +} + +void +QUICCongestionController::on_rto_verified() +{ +} diff --git a/iocore/net/quic/QUICCongestionController.h b/iocore/net/quic/QUICCongestionController.h index d44b9bf2988..1f76343a7d1 100644 --- a/iocore/net/quic/QUICCongestionController.h +++ b/iocore/net/quic/QUICCongestionController.h @@ -23,7 +23,9 @@ #pragma once -#include +#include +#include "QUICTypes.h" +#include "QUICFrameHandler.h" // TODO Implement congestion controll. // Congestion controller will be required after the 2nd implementation draft. @@ -33,5 +35,10 @@ class QUICCongestionController : public QUICFrameHandler virtual std::vector interests() override; virtual QUICErrorUPtr handle_frame(std::shared_ptr) override; + void on_packet_sent(); + void on_packet_acked(); + virtual void on_packets_lost(std::set packets); + void on_rto_verified(); + private: }; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index a91c78fdae9..12b09f74619 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -607,6 +607,7 @@ QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, con QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, const std::vector *ack_block) { this->_index = index; + this->_buf = nullptr; this->_ack_blocks = ack_block; if (this->_ack_blocks->size()) { if (this->_ack_blocks->size() == this->_index) { diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 31cae5acc8d..d735ae4fa7e 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -28,7 +28,8 @@ #define QUICLDDebug(fmt, ...) \ Debug("quic_loss_detector", "[%" PRIx64 "] " fmt, static_cast(this->_connection_id), ##__VA_ARGS__) -QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter) : _transmitter(transmitter) +QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICCongestionController *cc) + : _transmitter(transmitter), _cc(cc) { this->mutex = new_ProxyMutex(); @@ -133,7 +134,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num // Inform the congestion controller of lost packets and // lets it decide whether to retransmit immediately. if (!lost_packets.empty()) { - // TODO cc->on_packets_lost(lost_packets); + this->_cc->on_packets_lost(lost_packets); for (auto packet_number : lost_packets) { this->_decrement_packet_count(packet_number); this->_sent_packets.erase(packet_number); @@ -350,12 +351,16 @@ QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame) { std::set packets; QUICPacketNumber x = ack_frame.largest_acknowledged(); - packets.insert(x); + for (uint64_t i = 0; i <= ack_frame.ack_block_section()->first_ack_block_length(); ++i) { + packets.insert(x--); + } for (auto &&block : *(ack_frame.ack_block_section())) { - for (int i = 0; i < block.gap(); ++i) { - packets.insert(++x); + for (uint64_t i = 0; i <= block.gap(); ++i) { + x--; + } + for (uint64_t i = 0; i <= block.length(); ++i) { + packets.insert(x--); } - x += block.length(); } return packets; diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index b7071fcb117..d72785c7535 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -37,11 +37,12 @@ #include "QUICFrame.h" #include "QUICFrameHandler.h" #include "QUICPacketTransmitter.h" +#include "QUICCongestionController.h" class QUICLossDetector : public Continuation, public QUICFrameHandler { public: - QUICLossDetector(QUICPacketTransmitter *transmitter); + QUICLossDetector(QUICPacketTransmitter *transmitter, QUICCongestionController *cc); int event_handler(int event, Event *edata); @@ -116,4 +117,5 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _retransmit_handshake_packets(); QUICPacketTransmitter *_transmitter = nullptr; + QUICCongestionController *_cc = nullptr; }; diff --git a/iocore/net/quic/QUICPacketTransmitter.h b/iocore/net/quic/QUICPacketTransmitter.h index 5396a6a566f..d5622575fee 100644 --- a/iocore/net/quic/QUICPacketTransmitter.h +++ b/iocore/net/quic/QUICPacketTransmitter.h @@ -30,11 +30,13 @@ class QUICPacketTransmitter { public: /* - * Enqueue a packetfor transmission + * Enqueue a packet for transmission * + * If packet parameter is not passed, it just sends an event without queuing a new packet. * This sends QUIC_PACKET_WRITE_READY event. + * This return number of packets currently in queue */ - virtual void transmit_packet(QUICPacketUPtr packet) = 0; + virtual uint32_t transmit_packet(QUICPacketUPtr packet = QUICPacketUPtr(nullptr, &QUICPacketDeleter::delete_packet)) = 0; /* * Enqueue a packet for retransmission diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 025d90cbaad..09e742d9748 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -41,7 +41,7 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame != nullptr); CHECK(frame->num_blocks() == 0); CHECK(frame->largest_acknowledged() == 1); - CHECK(frame->ack_block_section()->first_ack_block_length() == 1); + CHECK(frame->ack_block_section()->first_ack_block_length() == 0); frame = creator.create(); CHECK(frame == nullptr); @@ -55,7 +55,7 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame != nullptr); CHECK(frame->num_blocks() == 0); CHECK(frame->largest_acknowledged() == 5); - CHECK(frame->ack_block_section()->first_ack_block_length() == 4); + CHECK(frame->ack_block_section()->first_ack_block_length() == 3); // Loss creator.update(6, true); @@ -65,8 +65,8 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame != nullptr); CHECK(frame->num_blocks() == 1); CHECK(frame->largest_acknowledged() == 10); - CHECK(frame->ack_block_section()->first_ack_block_length() == 1); - CHECK(frame->ack_block_section()->begin()->gap() == 2); + CHECK(frame->ack_block_section()->first_ack_block_length() == 0); + CHECK(frame->ack_block_section()->begin()->gap() == 1); } TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") @@ -88,8 +88,8 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") CHECK(frame != nullptr); CHECK(frame->num_blocks() == 2); CHECK(frame->largest_acknowledged() == 9); - CHECK(frame->ack_block_section()->first_ack_block_length() == 2); - CHECK(frame->ack_block_section()->begin()->gap() == 1); + CHECK(frame->ack_block_section()->first_ack_block_length() == 1); + CHECK(frame->ack_block_section()->begin()->gap() == 0); frame = creator.create(); CHECK(frame == nullptr); @@ -100,8 +100,8 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") CHECK(frame != nullptr); CHECK(frame->num_blocks() == 1); CHECK(frame->largest_acknowledged() == 7); - CHECK(frame->ack_block_section()->first_ack_block_length() == 1); - CHECK(frame->ack_block_section()->begin()->gap() == 2); + CHECK(frame->ack_block_section()->first_ack_block_length() == 0); + CHECK(frame->ack_block_section()->begin()->gap() == 1); } TEST_CASE("QUICAckFrameCreator_QUICAckPacketNumbers", "[quic]") diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index af39c417b31..17f6029bdd7 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -27,33 +27,127 @@ #include "QUICEvents.h" #include "Mock.h" -TEST_CASE("QUICLossDetector_Loss_in_Handshake", "[quic]") +TEST_CASE("QUICLossDetector_Loss", "[quic]") { - MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); - QUICLossDetector detector(tx); - - // Check initial state - CHECK(tx->_retransmit_count == 0); - - // Send SERVER_CLEARTEXT (Handshake message) - uint8_t raw[4] = {0}; - ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); - memcpy(payload.get(), raw, sizeof(raw)); - - QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, 0xffddbb9977553311ULL, 0x00000001, 0, 0x00112233, - std::move(payload), sizeof(raw)); - QUICPacketUPtr packet = - QUICPacketUPtr(new QUICPacket(header, std::move(payload), sizeof(raw), true), [](QUICPacket *p) { delete p; }); - detector.on_packet_sent(std::move(packet)); - ink_hrtime_sleep(HRTIME_MSECONDS(1000)); - CHECK(tx->_retransmit_count > 0); - - // Receive ACK - std::shared_ptr frame = std::make_shared(0x01, 20, 0); - frame->ack_block_section()->add_ack_block({0, 1ULL}); - detector.handle_frame(frame); - ink_hrtime_sleep(HRTIME_MSECONDS(1500)); - int retransmit_count = tx->_retransmit_count; - ink_hrtime_sleep(HRTIME_MSECONDS(1500)); - CHECK(tx->_retransmit_count == retransmit_count); + MockQUICCrypto crypto; + QUICPacketFactory pf; + pf.set_crypto_module(&crypto); + + QUICAckFrameCreator *afc = new QUICAckFrameCreator(); + QUICConnectionId connection_id = 1; + MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); + MockQUICCongestionController *cc = new MockQUICCongestionController(); + QUICLossDetector detector(tx, cc); + ats_unique_buf payload = ats_unique_malloc(16); + size_t payload_len = 16; + QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); + std::shared_ptr frame = QUICFrameFactory::create_null_ack_frame(); + uint16_t ack_delay = 50; + + SECTION("Handshake") + { + // Check initial state + CHECK(tx->retransmitted.size() == 0); + + // Send SERVER_CLEARTEXT (Handshake message) + uint8_t raw[4] = {0}; + ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); + memcpy(payload.get(), raw, sizeof(raw)); + + QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, 0xffddbb9977553311ULL, 0x00000001, 0, 0x00112233, + std::move(payload), sizeof(raw)); + QUICPacketUPtr packet = + QUICPacketUPtr(new QUICPacket(header, std::move(payload), sizeof(raw), true), [](QUICPacket *p) { delete p; }); + detector.on_packet_sent(std::move(packet)); + ink_hrtime_sleep(HRTIME_MSECONDS(1000)); + CHECK(tx->retransmitted.size() > 0); + + // Receive ACK + std::shared_ptr frame = std::make_shared(0x01, 20, 0); + frame->ack_block_section()->add_ack_block({0, 1ULL}); + detector.handle_frame(frame); + ink_hrtime_sleep(HRTIME_MSECONDS(1500)); + int retransmit_count = tx->retransmitted.size(); + ink_hrtime_sleep(HRTIME_MSECONDS(1500)); + CHECK(tx->retransmitted.size() == retransmit_count); + } + + SECTION("1-RTT") + { + // Check initial state + CHECK(tx->retransmitted.size() == 0); + + // Send packet (1) to (7) + payload = ats_unique_malloc(16); + QUICPacketUPtr packet1 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), + std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet2 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), + std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet3 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), + std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet4 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), + std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet5 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), + std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet6 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), + std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet7 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), + std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet8 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), + std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet9 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), + std::move(payload), payload_len, true); + + QUICPacketNumber pn1 = packet1->packet_number(); + QUICPacketNumber pn2 = packet2->packet_number(); + QUICPacketNumber pn3 = packet3->packet_number(); + QUICPacketNumber pn4 = packet4->packet_number(); + QUICPacketNumber pn5 = packet5->packet_number(); + QUICPacketNumber pn6 = packet6->packet_number(); + QUICPacketNumber pn7 = packet7->packet_number(); + QUICPacketNumber pn8 = packet8->packet_number(); + QUICPacketNumber pn9 = packet9->packet_number(); + + detector.on_packet_sent(std::move(packet1)); + detector.on_packet_sent(std::move(packet2)); + detector.on_packet_sent(std::move(packet3)); + detector.on_packet_sent(std::move(packet4)); + detector.on_packet_sent(std::move(packet5)); + detector.on_packet_sent(std::move(packet6)); + detector.on_packet_sent(std::move(packet7)); + detector.on_packet_sent(std::move(packet8)); + detector.on_packet_sent(std::move(packet9)); + + ink_hrtime_sleep(HRTIME_MSECONDS(10000)); + + // Receive an ACK for (1) (4) (5) (7) (8) (9) + afc->update(pn1, true); + afc->update(pn4, true); + afc->update(pn5, true); + afc->update(pn7, true); + afc->update(pn8, true); + afc->update(pn9, true); + frame = afc->create(); + detector.handle_frame(frame); + + CHECK(cc->lost_packets.size() == 3); + + CHECK(cc->lost_packets.find(pn1) == cc->lost_packets.end()); + CHECK(cc->lost_packets.find(pn2) != cc->lost_packets.end()); + CHECK(cc->lost_packets.find(pn3) != cc->lost_packets.end()); + CHECK(cc->lost_packets.find(pn4) == cc->lost_packets.end()); + CHECK(cc->lost_packets.find(pn5) == cc->lost_packets.end()); + CHECK(cc->lost_packets.find(pn6) != cc->lost_packets.end()); + CHECK(cc->lost_packets.find(pn7) == cc->lost_packets.end()); + CHECK(cc->lost_packets.find(pn8) == cc->lost_packets.end()); + CHECK(cc->lost_packets.find(pn9) == cc->lost_packets.end()); + } } From 7e7e3fcf0d2990170772cb7dd86b3ee79a60cfc2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 13 Dec 2017 10:22:00 +0900 Subject: [PATCH 0239/1313] draft-08: Support Variable-Length Integer Encoding --- iocore/net/quic/QUICTypes.cc | 72 +++++++++++++++ iocore/net/quic/QUICTypes.h | 11 ++- iocore/net/quic/test/test_QUICTypeUtil.cc | 107 ++++++++++++++++++++++ 3 files changed, 189 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 44e89bdc6ad..2c2189634ec 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -167,3 +167,75 @@ QUICError::code() { return static_cast(this->trans_error_code); } + +size_t +QUICVariableInt::size(const uint8_t *src) +{ + return 1 << (src[0] >> 6); +} + +size_t +QUICVariableInt::size(uint64_t src) +{ + uint8_t flag = 0; + if (src > 4611686018427387903) { + // max usable bits is 62 + return 0; + } else if (src > 1073741823) { + flag = 0x03; + } else if (src > 16383) { + flag = 0x02; + } else if (src > 63) { + flag = 0x01; + } else { + flag = 0x00; + } + + return 1 << flag; +} + +int +QUICVariableInt::encode(uint8_t *dst, size_t dst_len, size_t &len, uint64_t src) +{ + uint8_t flag = 0; + if (src > 4611686018427387903) { + // max usable bits is 62 + return 1; + } else if (src > 1073741823) { + flag = 0x03; + } else if (src > 16383) { + flag = 0x02; + } else if (src > 63) { + flag = 0x01; + } else { + flag = 0x00; + } + + len = 1 << flag; + if (len > dst_len) { + return 1; + } + + size_t dummy = 0; + QUICTypeUtil::write_uint_as_nbytes(src, len, dst, &dummy); + dst[0] |= (flag << 6); + + return 0; +} + +int +QUICVariableInt::decode(uint64_t &dst, size_t &len, const uint8_t *src, size_t src_len) +{ + len = 1 << (src[0] >> 6); + if (src_len < len) { + return 1; + } + + uint8_t buf[8] = {0}; + memcpy(buf, src, len); + buf[0] &= 0x3f; + + dst = QUICTypeUtil::read_nbytes_as_uint(buf, len); + + return 0; +} diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 7429009714e..7d601312c3d 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -51,7 +51,7 @@ ats_unique_buf ats_unique_malloc(size_t size); using QUICPacketNumber = uint64_t; using QUICVersion = uint32_t; -using QUICStreamId = uint32_t; +using QUICStreamId = uint64_t; using QUICOffset = uint64_t; // TODO: Update version number @@ -274,3 +274,12 @@ class QUICTypeUtil private: }; + +class QUICVariableInt +{ +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); +}; diff --git a/iocore/net/quic/test/test_QUICTypeUtil.cc b/iocore/net/quic/test/test_QUICTypeUtil.cc index 1bea4babf70..99ae818e81b 100644 --- a/iocore/net/quic/test/test_QUICTypeUtil.cc +++ b/iocore/net/quic/test/test_QUICTypeUtil.cc @@ -67,3 +67,110 @@ TEST_CASE("QUICTypeUtil", "[quic]") INFO("2 byte to 8 byte"); CHECK(memcmp(buf, "\x00\x00\x00\x00\x00\x00\x11\xff", 8) == 0); } + +TEST_CASE("Variable Length - encoding 1", "[quic]") +{ + uint8_t dst[8] = {0}; + uint64_t src = 151288809941952652; + size_t len = 0; + uint8_t expect[] = {0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c}; + + QUICVariableInt::encode(dst, sizeof(dst), len, src); + + CHECK(len == 8); + CHECK(memcmp(dst, expect, 8) == 0); +} + +TEST_CASE("Variable Length - encoding 2", "[quic]") +{ + uint8_t dst[8] = {0}; + uint64_t src = 494878333; + size_t len = 0; + uint8_t expect[] = {0x9d, 0x7f, 0x3e, 0x7d}; + + QUICVariableInt::encode(dst, sizeof(dst), len, src); + + CHECK(len == 4); + CHECK(memcmp(dst, expect, 4) == 0); +} + +TEST_CASE("Variable Length - encoding 3", "[quic]") +{ + uint8_t dst[8] = {0}; + uint64_t src = 15293; + size_t len = 0; + uint8_t expect[] = {0x7b, 0xbd}; + + QUICVariableInt::encode(dst, sizeof(dst), len, src); + + CHECK(len == 2); + CHECK(memcmp(dst, expect, 2) == 0); +} + +TEST_CASE("Variable Length - encoding 4", "[quic]") +{ + uint8_t dst[8] = {0}; + uint64_t src = 37; + size_t len = 0; + uint8_t expect[] = {0x25}; + + QUICVariableInt::encode(dst, sizeof(dst), len, src); + + CHECK(len == 1); + CHECK(memcmp(dst, expect, 1) == 0); +} + +TEST_CASE("Variable Length - decoding 1", "[quic]") +{ + uint8_t src[] = {0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c}; + uint64_t dst = 0; + size_t len = 0; + QUICVariableInt::decode(dst, len, src, sizeof(src)); + + CHECK(dst == 151288809941952652); + CHECK(len == 8); +} + +TEST_CASE("Variable Length - decoding 2", "[quic]") +{ + uint8_t src[] = {0x9d, 0x7f, 0x3e, 0x7d, 0x00, 0x00, 0x00, 0x00}; + uint64_t dst = 0; + size_t len = 0; + QUICVariableInt::decode(dst, len, src, sizeof(src)); + + CHECK(dst == 494878333); + CHECK(len == 4); +} + +TEST_CASE("Variable Length - decoding 3", "[quic]") +{ + uint8_t src[] = {0x7b, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint64_t dst = 0; + size_t len = 0; + QUICVariableInt::decode(dst, len, src, sizeof(src)); + + CHECK(dst == 15293); + CHECK(len == 2); +} + +TEST_CASE("Variable Length - decoding 4", "[quic]") +{ + uint8_t src[] = {0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint64_t dst = 0; + size_t len = 0; + QUICVariableInt::decode(dst, len, src, sizeof(src)); + + CHECK(dst == 37); + CHECK(len == 1); +} + +TEST_CASE("Variable Length - decoding 5", "[quic]") +{ + uint8_t src[] = {0x40, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint64_t dst = 0; + size_t len = 0; + QUICVariableInt::decode(dst, len, src, sizeof(src)); + + CHECK(dst == 37); + CHECK(len == 2); +} From 3d3b174fd8579feb7d5eaa12d927d16861458b85 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 13 Dec 2017 10:56:10 +0900 Subject: [PATCH 0240/1313] draft-08: Adjust frame types --- iocore/net/quic/QUICFrame.cc | 12 ++++++------ iocore/net/quic/QUICTypes.h | 7 ++++--- iocore/net/quic/test/test_QUICFrame.cc | 15 ++++++++------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 12b09f74619..8b2f8ca3b0a 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -50,11 +50,11 @@ QUICFrame::type() const QUICFrameType QUICFrame::type(const uint8_t *buf) { - if (buf[0] >= static_cast(QUICFrameType::STREAM)) { + if (buf[0] >= static_cast(QUICFrameType::UNKNOWN)) { + return QUICFrameType::UNKNOWN; + } else if (buf[0] >= static_cast(QUICFrameType::STREAM)) { return QUICFrameType::STREAM; - } else if (buf[0] >= static_cast(QUICFrameType::ACK)) { - return QUICFrameType::ACK; - } else if (buf[0] > static_cast(QUICFrameType::STOP_SENDING)) { + } else if (buf[0] > static_cast(QUICFrameType::ACK)) { return QUICFrameType::UNKNOWN; } else { return static_cast(buf[0]); @@ -439,7 +439,7 @@ QUICAckFrame::_get_largest_acknowledged_length() const * 1 -> 2 byte * 2 -> 4 byte * 3 -> 8 byte - */ + */ int n = (this->_buf[0] & 0x0c) >> 2; return 0x01 << n; } @@ -465,7 +465,7 @@ QUICAckFrame::_get_ack_block_length() const * 1 -> 2 byte * 2 -> 4 byte * 3 -> 8 byte - */ + */ int n = this->_buf[0] & 0x03; return 0x01 << n; } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 7d601312c3d..9a6121a768f 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -97,9 +97,10 @@ enum class QUICFrameType : int { STREAM_ID_NEEDED, NEW_CONNECTION_ID, STOP_SENDING, - ACK = 0xA0, - STREAM = 0xC0, - UNKNOWN = 0x100, + PONG, + ACK, + STREAM = 0x10, // 0x10 - 0x17 + UNKNOWN = 0x18, }; enum class QUICVersionNegotiationStatus { diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 34897467b3b..fc09cd4b06e 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -42,15 +42,16 @@ TEST_CASE("QUICFrame Type", "[quic]") CHECK(QUICFrame::type(reinterpret_cast("\x0a")) == QUICFrameType::STREAM_ID_NEEDED); CHECK(QUICFrame::type(reinterpret_cast("\x0b")) == QUICFrameType::NEW_CONNECTION_ID); CHECK(QUICFrame::type(reinterpret_cast("\x0c")) == QUICFrameType::STOP_SENDING); + CHECK(QUICFrame::type(reinterpret_cast("\x0d")) == QUICFrameType::PONG); + CHECK(QUICFrame::type(reinterpret_cast("\x0e")) == QUICFrameType::ACK); // Undefined ragne - CHECK(QUICFrame::type(reinterpret_cast("\x0d")) == QUICFrameType::UNKNOWN); - CHECK(QUICFrame::type(reinterpret_cast("\x9f")) == QUICFrameType::UNKNOWN); - // Range of ACK - CHECK(QUICFrame::type(reinterpret_cast("\xa0")) == QUICFrameType::ACK); - CHECK(QUICFrame::type(reinterpret_cast("\xbf")) == QUICFrameType::ACK); + CHECK(QUICFrame::type(reinterpret_cast("\x0f")) == QUICFrameType::UNKNOWN); // Range of STREAM - CHECK(QUICFrame::type(reinterpret_cast("\xc0")) == QUICFrameType::STREAM); - CHECK(QUICFrame::type(reinterpret_cast("\xff")) == QUICFrameType::STREAM); + CHECK(QUICFrame::type(reinterpret_cast("\x10")) == QUICFrameType::STREAM); + CHECK(QUICFrame::type(reinterpret_cast("\x17")) == QUICFrameType::STREAM); + // Undefined ragne + CHECK(QUICFrame::type(reinterpret_cast("\x18")) == QUICFrameType::UNKNOWN); + CHECK(QUICFrame::type(reinterpret_cast("\xff")) == QUICFrameType::UNKNOWN); } TEST_CASE("Construct QUICFrame", "[quic]") From 25fc8ab030b5af02283fe120a294eff0b58a4f7b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 13 Dec 2017 16:07:35 +0900 Subject: [PATCH 0241/1313] draft-08: Support new STREAM frame format --- iocore/net/quic/QUICApplication.cc | 2 +- iocore/net/quic/QUICEchoApp.cc | 2 +- iocore/net/quic/QUICFrame.cc | 208 ++++++++++------- iocore/net/quic/QUICFrame.h | 20 +- iocore/net/quic/QUICStream.cc | 4 +- iocore/net/quic/QUICStreamManager.cc | 5 +- iocore/net/quic/test/test_QUICFrame.cc | 302 ++++++++++++++----------- 7 files changed, 309 insertions(+), 234 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 83559e67a7a..ef26055ef9e 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -154,7 +154,7 @@ QUICApplication::reenable(QUICStream *stream) stream_io->read_reenable(); stream_io->write_reenable(); } else { - Debug(tag, "Unknown Stream, id: %d", stream->id()); + Debug(tag, "Unknown Stream, id: %" PRIx64, stream->id()); } return; diff --git a/iocore/net/quic/QUICEchoApp.cc b/iocore/net/quic/QUICEchoApp.cc index 5fcc4c6fe10..6451dc7af15 100644 --- a/iocore/net/quic/QUICEchoApp.cc +++ b/iocore/net/quic/QUICEchoApp.cc @@ -41,7 +41,7 @@ QUICEchoApp::main_event_handler(int event, Event *data) QUICStream *stream = reinterpret_cast(data->cookie); QUICStreamIO *stream_io = this->_find_stream_io(stream->id()); if (stream_io == nullptr) { - Debug(tag, "Unknown Stream, id: %d", stream->id()); + Debug(tag, "Unknown Stream, id: %" PRIx64, stream->id()); return -1; } diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 8b2f8ca3b0a..db04cb683a3 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -90,11 +90,7 @@ QUICStreamFrame::type() const size_t QUICStreamFrame::size() const { - if (this->_buf) { - return this->_get_data_offset() + this->data_length(); - } else { - return 1 + 4 + 8 + 2 + this->data_length(); - } + return this->_get_data_field_offset() + this->data_length(); } void @@ -106,53 +102,41 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len) const void QUICStreamFrame::store(uint8_t *buf, size_t *len, bool include_length_field) const { - size_t n; - // Build Frame Type: "11FSSOOD" + // Build Frame Type: "0b0010OLF" buf[0] = static_cast(QUICFrameType::STREAM); *len = 1; - // "F" of "11FSSOOD" - if (this->has_fin_flag()) { - buf[0] += (0x01 << 5); - } + // Stream ID (i) + size_t stream_id_field_len; - // "SS" of "11FSSOOD" - uint8_t stream_id_width = 0; - if (this->_stream_id > 0xFFFFFF) { - stream_id_width = 3; - } else if (this->_stream_id > 0xFFFF) { - stream_id_width = 2; - } else if (this->_stream_id > 0xFF) { - stream_id_width = 1; - } else { - stream_id_width = 0; - } - buf[0] += (stream_id_width << 3); - QUICTypeUtil::write_QUICStreamId(this->stream_id(), stream_id_width + 1, buf + *len, &n); - *len += n; - - // "OO" of "11FSSOOD" - uint8_t offset_width = 0; - if (this->offset() > 0xFFFFFFFF) { - offset_width = 3; - } else if (this->offset() > 0xFFFF) { - offset_width = 2; - } else if (this->offset() > 0x00) { - offset_width = 1; - } else { - offset_width = 0; + // FIXME: check length of buf + QUICVariableInt::encode(buf + *len, 8, stream_id_field_len, this->_stream_id); + *len += stream_id_field_len; + + // [Offset (i)] "O" of "0b0010OLF" + if (this->has_offset_field()) { + size_t offset_field_len; + // FIXME: check length of buf + QUICVariableInt::encode(buf + *len, 8, offset_field_len, this->_offset); + *len += offset_field_len; + buf[0] += 0x04; } - buf[0] += (offset_width << 1); - QUICTypeUtil::write_QUICOffset(this->offset(), offset_width ? 1 << offset_width : 0, buf + *len, &n); - *len += n; - // "D" of "11FSSOOD" + // [Length (i)] "L of "0b0010OLF" if (include_length_field) { + size_t length_field_len; + // FIXME: check length of buf + QUICVariableInt::encode(buf + *len, 8, length_field_len, this->_data_len); + *len += length_field_len; + buf[0] += 0x02; + } + + // "F" of "0b0010OLF" + if (this->has_fin_flag()) { buf[0] += 0x01; - QUICTypeUtil::write_uint_as_nbytes(this->data_length(), 2, buf + *len, &n); - *len += n; } + // Stream Data (*) memcpy(buf + *len, this->data(), this->data_length()); *len += this->data_length(); } @@ -161,7 +145,11 @@ QUICStreamId QUICStreamFrame::stream_id() const { if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + this->_get_stream_id_offset(), this->_get_stream_id_len()); + uint64_t stream_id; + size_t encoded_len; + QUICVariableInt::decode(stream_id, encoded_len, this->_buf + this->_get_stream_id_field_offset(), + this->_len - this->_get_stream_id_field_offset()); + return static_cast(stream_id); } else { return this->_stream_id; } @@ -171,106 +159,160 @@ QUICOffset QUICStreamFrame::offset() const { if (this->_buf) { - return QUICTypeUtil::read_QUICOffset(this->_buf + this->_get_offset_offset(), this->_get_offset_len()); + if (this->has_offset_field()) { + uint64_t offset; + size_t encoded_len; + QUICVariableInt::decode(offset, encoded_len, this->_buf + this->_get_stream_id_field_offset(), + this->_len - this->_get_stream_id_field_offset()); + return static_cast(offset); + } else { + return 0; + } } else { return this->_offset; } } +uint64_t +QUICStreamFrame::data_length() const +{ + if (this->_buf) { + if (this->has_length_field()) { + uint64_t data_len; + size_t encoded_len; + QUICVariableInt::decode(data_len, encoded_len, this->_buf + this->_get_length_field_offset(), + this->_len - this->_get_length_field_offset()); + return data_len; + } else { + return this->_len - this->_get_data_field_offset(); + } + } else { + return this->_data_len; + } +} + const uint8_t * QUICStreamFrame::data() const { if (this->_buf) { - return this->_buf + this->_get_data_offset(); + return this->_buf + this->_get_data_field_offset(); } else { return this->_data.get(); } } -size_t -QUICStreamFrame::data_length() const +/** + * "O" of "0b00010OLF" + */ +bool +QUICStreamFrame::has_offset_field() const { if (this->_buf) { - if (this->has_data_length_field()) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf + this->_get_offset_offset() + this->_get_offset_len(), 2); - } else { - return this->_len - this->_get_data_offset(); - } + return (this->_buf[0] & 0x40) != 0; } else { - return this->_data_len; + return this->_offset != 0; } } /** - * "D" of "11FSSOOD" + * "L" of "0b00010OLF" */ bool -QUICStreamFrame::has_data_length_field() const +QUICStreamFrame::has_length_field() const { - return (this->_buf[0] & 0x01) != 0; + if (this->_buf) { + return (this->_buf[0] & 0x02) != 0; + } else { + // This depends on `include_length_field` arg of QUICStreamFrame::store. + // Returning true for just in case. + return true; + } } /** - * "F" of "11FSSOOD" + * "F" of "0b00010OLF" */ bool QUICStreamFrame::has_fin_flag() const { if (this->_buf) { - return (this->_buf[0] & 0x20) != 0; + return (this->_buf[0] & 0x01) != 0; } else { return this->_fin; } } size_t -QUICStreamFrame::_get_stream_id_offset() const +QUICStreamFrame::_get_stream_id_field_offset() const { return 1; } size_t -QUICStreamFrame::_get_offset_offset() const +QUICStreamFrame::_get_offset_field_offset() const +{ + size_t offset_field_offset = this->_get_stream_id_field_offset(); + offset_field_offset += this->_get_stream_id_field_len(); + + return offset_field_offset; +} + +size_t +QUICStreamFrame::_get_length_field_offset() const +{ + size_t length_field_offset = this->_get_stream_id_field_offset(); + length_field_offset += this->_get_stream_id_field_len(); + length_field_offset += this->_get_offset_field_len(); + + return length_field_offset; +} + +size_t +QUICStreamFrame::_get_data_field_offset() const { - return this->_get_stream_id_offset() + this->_get_stream_id_len(); + size_t data_field_offset = this->_get_stream_id_field_offset(); + data_field_offset += this->_get_stream_id_field_len(); + data_field_offset += this->_get_offset_field_len(); + data_field_offset += this->_get_length_field_len(); + + return data_field_offset; } size_t -QUICStreamFrame::_get_data_offset() const +QUICStreamFrame::_get_stream_id_field_len() const { if (this->_buf) { - if (this->has_data_length_field()) { - return this->_get_offset_offset() + this->_get_offset_len() + 2; - } else { - return this->_get_offset_offset() + this->_get_offset_len(); - } + return QUICVariableInt::size(this->_buf + this->_get_stream_id_field_offset()); } else { - return 0; + return QUICVariableInt::size(this->_stream_id); } } -/** - * "SS" of "11FSSOOD" - * The value 00, 01, 02, and 03 indicate lengths of 8, 16, 24, and 32 bits long respectively. - */ size_t -QUICStreamFrame::_get_stream_id_len() const +QUICStreamFrame::_get_offset_field_len() const { - return ((this->_buf[0] & 0x18) >> 3) + 1; + if (this->_buf) { + if (this->has_offset_field()) { + return QUICVariableInt::size(this->_buf + this->_get_offset_field_offset()); + } else { + return 0; + } + } else { + return QUICVariableInt::size(this->_offset); + } } -/** - * "OO" of "11FSSOOD" - * The values 00, 01, 02, and 03 indicate lengths of 0, 16, 32, and 64 bits long respectively. - */ size_t -QUICStreamFrame::_get_offset_len() const +QUICStreamFrame::_get_length_field_len() const { - int OO_bits = (this->_buf[0] & 0x06) >> 1; - if (OO_bits == 0) { - return 0; + if (this->_buf) { + if (this->has_length_field()) { + return QUICVariableInt::size(this->_buf + this->_get_length_field_offset()); + } else { + return 0; + } } else { - return 0x01 << OO_bits; + return QUICVariableInt::size(this->_data_len); } } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 59fd66dc2c5..a4d3b076d3f 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -36,7 +36,7 @@ class QUICFrame public: QUICFrame(const uint8_t *buf, size_t len) : _buf(buf), _len(len){}; virtual QUICFrameType type() const; - virtual size_t size() const = 0; + virtual size_t size() const = 0; virtual void store(uint8_t *buf, size_t *len) const = 0; virtual void reset(const uint8_t *buf, size_t len); static QUICFrameType type(const uint8_t *buf); @@ -66,8 +66,9 @@ class QUICStreamFrame : public QUICFrame QUICStreamId stream_id() const; QUICOffset offset() const; const uint8_t *data() const; - size_t data_length() const; - bool has_data_length_field() const; + uint64_t data_length() const; + bool has_offset_field() const; + bool has_length_field() const; bool has_fin_flag() const; LINK(QUICStreamFrame, link); @@ -78,11 +79,14 @@ class QUICStreamFrame : public QUICFrame QUICStreamId _stream_id = 0; QUICOffset _offset = 0; bool _fin = false; - size_t _get_data_offset() const; - size_t _get_stream_id_offset() const; - size_t _get_offset_offset() const; - size_t _get_stream_id_len() const; - size_t _get_offset_len() const; + size_t _get_stream_id_field_offset() const; + size_t _get_offset_field_offset() const; + size_t _get_length_field_offset() const; + size_t _get_data_field_offset() const; + + size_t _get_stream_id_field_len() const; + size_t _get_offset_field_len() const; + size_t _get_length_field_len() const; }; // diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 1ca315e2d5e..4dafbf199ef 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -29,10 +29,10 @@ #include "QUICConfig.h" #define QUICStreamDebug(fmt, ...) \ - Debug("quic_stream", "[%" PRIx64 "] [%" PRIx32 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ + Debug("quic_stream", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) #define QUICStreamFCDebug(fmt, ...) \ - Debug("quic_flow_ctrl", "[%" PRIx64 "] [%" PRIx32 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ + Debug("quic_flow_ctrl", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) QUICStream::~QUICStream() diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index f3b3d940fec..5223bb4db46 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -40,7 +40,10 @@ std::vector QUICStreamManager::interests() { return { - QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::MAX_STREAM_DATA, QUICFrameType::MAX_STREAM_ID, + QUICFrameType::STREAM, + QUICFrameType::RST_STREAM, + QUICFrameType::MAX_STREAM_DATA, + QUICFrameType::MAX_STREAM_ID, }; } diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index fc09cd4b06e..5aed7ba824e 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -54,30 +54,10 @@ TEST_CASE("QUICFrame Type", "[quic]") CHECK(QUICFrame::type(reinterpret_cast("\xff")) == QUICFrameType::UNKNOWN); } -TEST_CASE("Construct QUICFrame", "[quic]") -{ - uint8_t raw[] = "foo"; - ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); - memcpy(payload.get(), raw, sizeof(raw)); - - uint8_t buf[65536]; - size_t len; - - QUICStreamFrame frame1(std::move(payload), sizeof(raw), 0xffcc9966, 0xffddbb9977553311); - frame1.store(buf, &len); - CHECK(frame1.type() == QUICFrameType::STREAM); - CHECK(frame1.size() == 19); - CHECK(frame1.stream_id() == 0xffcc9966); - CHECK(frame1.offset() == 0xffddbb9977553311); - CHECK(frame1.data_length() == 4); - CHECK(memcmp(frame1.data(), "foo\0", 4) == 0); - CHECK(frame1.has_fin_flag() == false); -} - TEST_CASE("Load STREAM Frame 1", "[quic]") { uint8_t buf1[] = { - 0xC0, // 11FSSOOD + 0x10, // 0b00010OLF (OLF=000) 0x01, // Stream ID 0x01, 0x02, 0x03, 0x04, // Stream Data }; @@ -95,14 +75,14 @@ TEST_CASE("Load STREAM Frame 1", "[quic]") TEST_CASE("Load STREAM Frame 2", "[quic]") { uint8_t buf1[] = { - 0xC1, // 11FSSOOD + 0x12, // 0b00010OLF (OLF=010) 0x01, // Stream ID - 0x00, 0x05, // Data Length + 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM); - CHECK(frame1->size() == 9); + CHECK(frame1->size() == 8); std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); CHECK(streamFrame1->stream_id() == 0x01); CHECK(streamFrame1->offset() == 0x00); @@ -113,127 +93,173 @@ TEST_CASE("Load STREAM Frame 2", "[quic]") TEST_CASE("Store STREAM Frame", "[quic]") { - uint8_t buf[65535]; - size_t len; + SECTION("8bit stream id, 0bit offset") + { + uint8_t buf[32] = {0}; + size_t len; + uint8_t expected1[] = { + 0x12, // 0b00010OLF (OLF=010) + 0x01, // Stream ID + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; - // 8bit stream id, 0bit offset - uint8_t expected1[] = { - 0xC1, // 11FSSOOD - 0x01, // Stream ID - 0x00, 0x05, // Data Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data - }; + uint8_t raw1[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload1 = ats_unique_malloc(5); + memcpy(payload1.get(), raw1, 5); - uint8_t raw1[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload1 = ats_unique_malloc(5); - memcpy(payload1.get(), raw1, 5); + QUICStreamFrame streamFrame1(std::move(payload1), 5, 0x01, 0x00); + streamFrame1.store(buf, &len); + CHECK(len == 8); + CHECK(memcmp(buf, expected1, len) == 0); + } - QUICStreamFrame streamFrame1(std::move(payload1), 5, 0x01, 0x00); - streamFrame1.store(buf, &len); - CHECK(len == 9); - CHECK(memcmp(buf, expected1, len) == 0); + SECTION("8bit stream id, 16bit offset") + { + uint8_t buf[32] = {0}; + size_t len; + uint8_t expected2[] = { + 0x16, // 0b00010OLF (OLF=110) + 0x01, // Stream ID + 0x01, // Offset + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + uint8_t raw2[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload2 = ats_unique_malloc(5); + memcpy(payload2.get(), raw2, 5); + + QUICStreamFrame streamFrame2(std::move(payload2), 5, 0x01, 0x01); + streamFrame2.store(buf, &len); + CHECK(len == 9); + CHECK(memcmp(buf, expected2, len) == 0); + } - // 8bit stream id, 16bit offset - uint8_t expected2[] = { - 0xC3, // 11FSSOOD - 0x01, // Stream ID - 0x00, 0x01, // Offset - 0x00, 0x05, // Data Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data - }; - uint8_t raw2[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload2 = ats_unique_malloc(5); - memcpy(payload2.get(), raw2, 5); + SECTION("8bit stream id, 32bit offset") + { + uint8_t buf[32] = {0}; + size_t len; + uint8_t expected3[] = { + 0x16, // 0b00010OLF (OLF=110) + 0x01, // Stream ID + 0x80, 0x01, 0x00, 0x00, // Offset + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + uint8_t raw3[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload3 = ats_unique_malloc(5); + memcpy(payload3.get(), raw3, 5); + + QUICStreamFrame streamFrame3(std::move(payload3), 5, 0x01, 0x010000); + streamFrame3.store(buf, &len); + CHECK(len == 12); + CHECK(memcmp(buf, expected3, len) == 0); + } - QUICStreamFrame streamFrame2(std::move(payload2), 5, 0x01, 0x01); - streamFrame2.store(buf, &len); - CHECK(len == 11); - CHECK(memcmp(buf, expected2, len) == 0); + SECTION("8bit stream id, 64bit offset") + { + uint8_t buf[32] = {0}; + size_t len; + uint8_t expected4[] = { + 0x16, // 0b00010OLF (OLF=110) + 0x01, // Stream ID + 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + uint8_t raw4[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload4 = ats_unique_malloc(5); + memcpy(payload4.get(), raw4, 5); + + QUICStreamFrame streamFrame4(std::move(payload4), 5, 0x01, 0x0100000000); + streamFrame4.store(buf, &len); + CHECK(len == 16); + CHECK(memcmp(buf, expected4, len) == 0); + } - // 8bit stream id, 32bit offset - uint8_t expected3[] = { - 0xC5, // 11FSSOOD - 0x01, // Stream ID - 0x00, 0x01, 0x00, 0x00, // Offset - 0x00, 0x05, // Data Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data - }; - uint8_t raw3[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload3 = ats_unique_malloc(5); - memcpy(payload3.get(), raw3, 5); + SECTION("16bit stream id, 64bit offset") + { + uint8_t buf[32] = {0}; + size_t len; + uint8_t expected5[] = { + 0x16, // 0b00010OLF (OLF=110) + 0x41, 0x00, // Stream ID + 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + uint8_t raw5[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload5 = ats_unique_malloc(5); + memcpy(payload5.get(), raw5, 5); + + QUICStreamFrame streamFrame5(std::move(payload5), 5, 0x0100, 0x0100000000); + streamFrame5.store(buf, &len); + CHECK(len == 17); + CHECK(memcmp(buf, expected5, len) == 0); + } - QUICStreamFrame streamFrame3(std::move(payload3), 5, 0x01, 0x010000); - streamFrame3.store(buf, &len); - CHECK(len == 13); - CHECK(memcmp(buf, expected3, len) == 0); - - // 8bit stream id, 64bit offset - uint8_t expected4[] = { - 0xC7, // 11FSSOOD - 0x01, // Stream ID - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset - 0x00, 0x05, // Data Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data - }; - uint8_t raw4[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload4 = ats_unique_malloc(5); - memcpy(payload4.get(), raw4, 5); - - QUICStreamFrame streamFrame4(std::move(payload4), 5, 0x01, 0x0100000000); - streamFrame4.store(buf, &len); - CHECK(len == 17); - CHECK(memcmp(buf, expected4, len) == 0); - - // 16bit stream id, 64bit offset - uint8_t expected5[] = { - 0xCF, // 11FSSOOD - 0x01, 0x00, // Stream ID - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset - 0x00, 0x05, // Data Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data - }; - uint8_t raw5[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload5 = ats_unique_malloc(5); - memcpy(payload5.get(), raw5, 5); - - QUICStreamFrame streamFrame5(std::move(payload5), 5, 0x0100, 0x0100000000); - streamFrame5.store(buf, &len); - CHECK(len == 18); - CHECK(memcmp(buf, expected5, len) == 0); - - // 24bit stream id, 64bit offset - uint8_t expected6[] = { - 0xD7, // 11FSSOOD - 0x01, 0x00, 0x00, // Stream ID - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset - 0x00, 0x05, // Data Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data - }; - uint8_t raw6[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload6 = ats_unique_malloc(5); - memcpy(payload6.get(), raw6, 5); - - QUICStreamFrame streamFrame6(std::move(payload6), 5, 0x010000, 0x0100000000); - streamFrame6.store(buf, &len); - CHECK(len == 19); - CHECK(memcmp(buf, expected6, len) == 0); - - // 32bit stream id, 64bit offset - uint8_t expected7[] = { - 0xDF, // 11FSSOOD - 0x01, 0x00, 0x00, 0x00, // Stream ID - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset - 0x00, 0x05, // Data Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data - }; - uint8_t raw7[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload7 = ats_unique_malloc(5); - memcpy(payload7.get(), raw7, 5); - - QUICStreamFrame streamFrame7(std::move(payload7), 5, 0x01000000, 0x0100000000); - streamFrame7.store(buf, &len); - CHECK(len == 20); - CHECK(memcmp(buf, expected7, len) == 0); + SECTION("24bit stream id, 64bit offset") + { + uint8_t buf[32] = {0}; + size_t len; + uint8_t expected6[] = { + 0x16, // 0b00010OLF (OLF=110) + 0x80, 0x01, 0x00, 0x00, // Stream ID + 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + uint8_t raw6[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload6 = ats_unique_malloc(5); + memcpy(payload6.get(), raw6, 5); + + QUICStreamFrame streamFrame6(std::move(payload6), 5, 0x010000, 0x0100000000); + streamFrame6.store(buf, &len); + CHECK(len == 19); + CHECK(memcmp(buf, expected6, len) == 0); + } + + SECTION("32bit stream id, 64bit offset") + { + uint8_t buf[32] = {0}; + size_t len; + uint8_t expected7[] = { + 0x16, // 0b00010OLF (OLF=110) + 0x81, 0x00, 0x00, 0x00, // Stream ID + 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + uint8_t raw7[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload7 = ats_unique_malloc(5); + memcpy(payload7.get(), raw7, 5); + + QUICStreamFrame streamFrame7(std::move(payload7), 5, 0x01000000, 0x0100000000); + streamFrame7.store(buf, &len); + CHECK(len == 19); + CHECK(memcmp(buf, expected7, len) == 0); + } + + SECTION("32bit stream id, 64bit offset, FIN bit") + { + uint8_t buf[32] = {0}; + size_t len; + uint8_t expected[] = { + 0x17, // 0b00010OLF (OLF=111) + 0x81, 0x00, 0x00, 0x00, // Stream ID + 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + uint8_t raw[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload = ats_unique_malloc(5); + memcpy(payload.get(), raw, 5); + + QUICStreamFrame streamFrame(std::move(payload), 5, 0x01000000, 0x0100000000, true); + streamFrame.store(buf, &len); + CHECK(len == 19); + CHECK(memcmp(buf, expected, len) == 0); + } } TEST_CASE("Load Ack Frame 1", "[quic]") From fe481dfae4c1e3105d2f729dfdf80bf2fb690c10 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 14 Dec 2017 11:32:41 +0900 Subject: [PATCH 0242/1313] draft-08: Support new RST_STREAM frame format --- iocore/net/quic/QUICFrame.cc | 114 +++++++++++++++---------- iocore/net/quic/QUICFrame.h | 10 ++- iocore/net/quic/QUICTypes.cc | 43 ++++++++-- iocore/net/quic/QUICTypes.h | 15 ++-- iocore/net/quic/test/test_QUICFrame.cc | 8 +- 5 files changed, 125 insertions(+), 65 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index db04cb683a3..1973f2b48f8 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -106,28 +106,23 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, bool include_length_field) con buf[0] = static_cast(QUICFrameType::STREAM); *len = 1; - // Stream ID (i) - size_t stream_id_field_len; + size_t n; - // FIXME: check length of buf - QUICVariableInt::encode(buf + *len, 8, stream_id_field_len, this->_stream_id); - *len += stream_id_field_len; + // Stream ID (i) + QUICTypeUtil::write_QUICStreamId(this->_stream_id, buf + *len, &n); + *len += n; // [Offset (i)] "O" of "0b0010OLF" if (this->has_offset_field()) { - size_t offset_field_len; - // FIXME: check length of buf - QUICVariableInt::encode(buf + *len, 8, offset_field_len, this->_offset); - *len += offset_field_len; + QUICTypeUtil::write_QUICOffset(this->_offset, buf + *len, &n); + *len += n; buf[0] += 0x04; } // [Length (i)] "L of "0b0010OLF" if (include_length_field) { - size_t length_field_len; - // FIXME: check length of buf - QUICVariableInt::encode(buf + *len, 8, length_field_len, this->_data_len); - *len += length_field_len; + QUICTypeUtil::write_QUICVariableInt(this->_data_len, buf + *len, &n); + *len += n; buf[0] += 0x02; } @@ -145,11 +140,7 @@ QUICStreamId QUICStreamFrame::stream_id() const { if (this->_buf) { - uint64_t stream_id; - size_t encoded_len; - QUICVariableInt::decode(stream_id, encoded_len, this->_buf + this->_get_stream_id_field_offset(), - this->_len - this->_get_stream_id_field_offset()); - return static_cast(stream_id); + return QUICTypeUtil::read_QUICStreamId(this->_buf + _get_stream_id_field_offset()); } else { return this->_stream_id; } @@ -160,11 +151,7 @@ QUICStreamFrame::offset() const { if (this->_buf) { if (this->has_offset_field()) { - uint64_t offset; - size_t encoded_len; - QUICVariableInt::decode(offset, encoded_len, this->_buf + this->_get_stream_id_field_offset(), - this->_len - this->_get_stream_id_field_offset()); - return static_cast(offset); + return QUICTypeUtil::read_QUICOffset(this->_buf + _get_offset_field_offset()); } else { return 0; } @@ -178,11 +165,7 @@ QUICStreamFrame::data_length() const { if (this->_buf) { if (this->has_length_field()) { - uint64_t data_len; - size_t encoded_len; - QUICVariableInt::decode(data_len, encoded_len, this->_buf + this->_get_length_field_offset(), - this->_len - this->_get_length_field_offset()); - return data_len; + return QUICTypeUtil::read_QUICVariableInt(this->_buf + this->_get_length_field_offset()); } else { return this->_len - this->_get_data_field_offset(); } @@ -675,11 +658,10 @@ QUICRstStreamFrame::type() const return QUICFrameType::RST_STREAM; } -// 8 + 32 + 16 + 64 bit size_t QUICRstStreamFrame::size() const { - return 15; + return 1 + this->_get_stream_id_field_length() + sizeof(QUICAppErrorCode) + this->_get_final_offset_field_length(); } void @@ -689,33 +671,33 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len) const uint8_t *p = buf; *p = static_cast(QUICFrameType::RST_STREAM); ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n); + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); p += n; QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); p += n; - QUICTypeUtil::write_QUICOffset(this->_final_offset, 8, p, &n); + QUICTypeUtil::write_QUICOffset(this->_final_offset, p, &n); p += n; *len = p - buf; } -QUICAppErrorCode -QUICRstStreamFrame::error_code() const +QUICStreamId +QUICRstStreamFrame::stream_id() const { if (this->_buf) { - return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + 5); + return QUICTypeUtil::read_QUICStreamId(this->_buf + this->_get_stream_id_field_offset()); } else { - return this->_error_code; + return this->_stream_id; } } -QUICStreamId -QUICRstStreamFrame::stream_id() const +QUICAppErrorCode +QUICRstStreamFrame::error_code() const { if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + 1, 4); + return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + this->_get_error_code_field_offset()); } else { - return this->_stream_id; + return this->_error_code; } } @@ -723,12 +705,50 @@ QUICOffset QUICRstStreamFrame::final_offset() const { if (this->_buf) { - return QUICTypeUtil::read_QUICOffset(this->_buf + 7, 8); + return QUICTypeUtil::read_QUICOffset(this->_buf + this->_get_final_offset_field_offset()); } else { return this->_final_offset; } } +size_t +QUICRstStreamFrame::_get_stream_id_field_offset() const +{ + return 1; +} + +size_t +QUICRstStreamFrame::_get_stream_id_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_stream_id_field_offset()); + } else { + return QUICVariableInt::size(this->_stream_id); + } +} + +size_t +QUICRstStreamFrame::_get_error_code_field_offset() const +{ + return this->_get_stream_id_field_offset() + this->_get_stream_id_field_length(); +} + +size_t +QUICRstStreamFrame::_get_final_offset_field_offset() const +{ + return this->_get_error_code_field_offset() + sizeof(QUICAppErrorCode); +} + +size_t +QUICRstStreamFrame::_get_final_offset_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_final_offset_field_offset()); + } else { + return QUICVariableInt::size(this->_final_offset); + } +} + // // PING frame // @@ -988,9 +1008,9 @@ QUICMaxStreamDataFrame::store(uint8_t *buf, size_t *len) const uint8_t *p = buf; *p = static_cast(QUICFrameType::MAX_STREAM_DATA); ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n); + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); p += n; - QUICTypeUtil::write_uint_as_nbytes(this->_maximum_stream_data, 8, p, &n); + QUICTypeUtil::write_QUICMaxData(this->_maximum_stream_data, p, &n); p += n; *len = p - buf; @@ -1108,7 +1128,7 @@ QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len) const uint8_t *p = buf; *p = static_cast(QUICFrameType::STREAM_BLOCKED); ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n); + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); p += n; *len = p - buf; @@ -1118,7 +1138,7 @@ QUICStreamId QUICStreamBlockedFrame::stream_id() const { if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + 1, 4); + return QUICTypeUtil::read_QUICStreamId(this->_buf + 1); } else { return this->_stream_id; } @@ -1243,7 +1263,7 @@ QUICStopSendingFrame::store(uint8_t *buf, size_t *len) const uint8_t *p = buf; *p = static_cast(QUICFrameType::STOP_SENDING); ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, 4, p, &n); + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); p += n; QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); p += n; @@ -1265,7 +1285,7 @@ QUICStreamId QUICStopSendingFrame::stream_id() const { if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + 1, 4); + return QUICTypeUtil::read_QUICStreamId(this->_buf + 1); } else { return this->_stream_id; } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index a4d3b076d3f..d1e233856d8 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -213,14 +213,22 @@ class QUICRstStreamFrame : public QUICFrame QUICRstStreamFrame() : QUICFrame() {} QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset); + virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; - QUICAppErrorCode error_code() const; + QUICStreamId stream_id() const; + QUICAppErrorCode error_code() const; QUICOffset final_offset() const; private: + size_t _get_stream_id_field_offset() const; + size_t _get_stream_id_field_length() const; + size_t _get_error_code_field_offset() const; + size_t _get_final_offset_field_offset() const; + size_t _get_final_offset_field_length() const; + QUICStreamId _stream_id = 0; QUICAppErrorCode _error_code = 0; QUICOffset _final_offset = 0; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 2c2189634ec..d812ba58c79 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -66,15 +66,21 @@ QUICTypeUtil::read_QUICVersion(const uint8_t *buf) } QUICStreamId -QUICTypeUtil::read_QUICStreamId(const uint8_t *buf, uint8_t len) +QUICTypeUtil::read_QUICStreamId(const uint8_t *buf) { - return static_cast(read_nbytes_as_uint(buf, len)); + uint64_t stream_id = 0; + size_t len = 0; + QUICVariableInt::decode(stream_id, len, buf, 8); + return static_cast(stream_id); } QUICOffset -QUICTypeUtil::read_QUICOffset(const uint8_t *buf, uint8_t len) +QUICTypeUtil::read_QUICOffset(const uint8_t *buf) { - return static_cast(read_nbytes_as_uint(buf, len)); + uint64_t offset = 0; + size_t len = 0; + QUICVariableInt::decode(offset, len, buf, 8); + return static_cast(offset); } QUICTransErrorCode @@ -89,6 +95,15 @@ QUICTypeUtil::read_QUICAppErrorCode(const uint8_t *buf) return static_cast(read_nbytes_as_uint(buf, 2)); } +uint64_t +QUICTypeUtil::read_QUICVariableInt(const uint8_t *buf) +{ + uint64_t dst = 0; + size_t len = 0; + QUICVariableInt::decode(dst, len, buf, 8); + return dst; +} + uint64_t QUICTypeUtil::read_nbytes_as_uint(const uint8_t *buf, uint8_t n) { @@ -116,15 +131,15 @@ QUICTypeUtil::write_QUICVersion(QUICVersion version, uint8_t *buf, size_t *len) } void -QUICTypeUtil::write_QUICStreamId(QUICStreamId stream_id, uint8_t n, uint8_t *buf, size_t *len) +QUICTypeUtil::write_QUICStreamId(QUICStreamId stream_id, uint8_t *buf, size_t *len) { - write_uint_as_nbytes(static_cast(stream_id), n, buf, len); + QUICVariableInt::encode(buf, 8, *len, stream_id); } void -QUICTypeUtil::write_QUICOffset(QUICOffset offset, uint8_t n, uint8_t *buf, size_t *len) +QUICTypeUtil::write_QUICOffset(QUICOffset offset, uint8_t *buf, size_t *len) { - write_uint_as_nbytes(static_cast(offset), n, buf, len); + QUICVariableInt::encode(buf, 8, *len, offset); } void @@ -139,6 +154,18 @@ QUICTypeUtil::write_QUICAppErrorCode(QUICAppErrorCode error_code, uint8_t *buf, write_uint_as_nbytes(static_cast(error_code), 2, buf, len); } +void +QUICTypeUtil::write_QUICMaxData(uint64_t max_data, uint8_t *buf, size_t *len) +{ + QUICVariableInt::encode(buf, 8, *len, max_data); +} + +void +QUICTypeUtil::write_QUICVariableInt(uint64_t data, uint8_t *buf, size_t *len) +{ + QUICVariableInt::encode(buf, 8, *len, data); +} + void QUICTypeUtil::write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size_t *len) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 9a6121a768f..a715be1f08e 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -257,18 +257,23 @@ class QUICTypeUtil static QUICConnectionId read_QUICConnectionId(const uint8_t *buf, uint8_t n); static QUICPacketNumber read_QUICPacketNumber(const uint8_t *buf, uint8_t n); static QUICVersion read_QUICVersion(const uint8_t *buf); - static QUICStreamId read_QUICStreamId(const uint8_t *buf, uint8_t n); - static QUICOffset read_QUICOffset(const uint8_t *buf, uint8_t n); + static QUICStreamId read_QUICStreamId(const uint8_t *buf); + static QUICOffset read_QUICOffset(const uint8_t *buf); static QUICTransErrorCode read_QUICTransErrorCode(const uint8_t *buf); static QUICAppErrorCode read_QUICAppErrorCode(const uint8_t *buf); + static uint64_t read_QUICVariableInt(const uint8_t *buf); + static void write_QUICConnectionId(QUICConnectionId connection_id, uint8_t n, uint8_t *buf, size_t *len); static void write_QUICPacketNumber(QUICPacketNumber packet_number, uint8_t n, uint8_t *buf, size_t *len); static void write_QUICVersion(QUICVersion version, uint8_t *buf, size_t *len); - static void write_QUICStreamId(QUICStreamId stream_id, uint8_t n, uint8_t *buf, size_t *len); - static void write_QUICOffset(QUICOffset offset, uint8_t n, uint8_t *buf, size_t *len); + static void write_QUICStreamId(QUICStreamId stream_id, uint8_t *buf, size_t *len); + static void write_QUICOffset(QUICOffset offset, uint8_t *buf, size_t *len); static void write_QUICTransErrorCode(QUICTransErrorCode error_code, uint8_t *buf, size_t *len); static void write_QUICAppErrorCode(QUICAppErrorCode error_code, uint8_t *buf, size_t *len); + static void write_QUICMaxData(uint64_t max_data, uint8_t *buf, size_t *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); @@ -282,5 +287,5 @@ class QUICVariableInt 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); + static int decode(uint64_t &dst, size_t &len, const uint8_t *src, size_t src_len = 8); }; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 5aed7ba824e..3b76febd0c2 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -365,9 +365,9 @@ TEST_CASE("Load RST_STREAM Frame", "[quic]") { uint8_t buf1[] = { 0x01, // Type - 0x12, 0x34, 0x56, 0x78, // Stream ID + 0x92, 0x34, 0x56, 0x78, // Stream ID 0x00, 0x01, // Error Code - 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset + 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::RST_STREAM); @@ -386,9 +386,9 @@ TEST_CASE("Store RST_STREAM Frame", "[quic]") uint8_t expected[] = { 0x01, // Type - 0x12, 0x34, 0x56, 0x78, // Stream ID + 0x92, 0x34, 0x56, 0x78, // Stream ID 0x00, 0x01, // Error Code - 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset + 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset }; QUICRstStreamFrame rst_stream_frame(0x12345678, 0x0001, 0x1122334455667788); rst_stream_frame.store(buf, &len); From 13819f30931b7855ca8fc1f5b5f55d651e7de715 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Dec 2017 12:10:17 +0900 Subject: [PATCH 0243/1313] draft-08: Update labels for handshake secrets --- iocore/net/quic/QUICKeyGenerator.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 10ec80ccfee..c07d1370fcc 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -29,8 +29,8 @@ constexpr static uint8_t QUIC_VERSION_1_SALT[] = { 0xaf, 0xc8, 0x24, 0xec, 0x5f, 0xc7, 0x7e, 0xca, 0x1e, 0x9d, 0x36, 0xf3, 0x7f, 0xb2, 0xd4, 0x65, 0x18, 0xc3, 0x66, 0x39, }; -constexpr static ts::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("QUIC client cleartext Secret"_sv); -constexpr static ts::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("QUIC server cleartext Secret"_sv); +constexpr static ts::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("QUIC client handshake secret"_sv); +constexpr static ts::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("QUIC server handshake secret"_sv); constexpr static ts::string_view LABEL_FOR_CLIENT_PP_SECRET("EXPORTER-QUIC client 1-RTT Secret"_sv); constexpr static ts::string_view LABEL_FOR_SERVER_PP_SECRET("EXPORTER-QUIC server 1-RTT Secret"_sv); constexpr static ts::string_view LABEL_FOR_KEY("key"_sv); From c7f4e0a6f5a46962d80a5d1a666f3573e34dd674 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Dec 2017 12:15:20 +0900 Subject: [PATCH 0244/1313] Fix a wrong packet type check --- iocore/net/quic/QUICHandshake.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 8214a157efd..fc21bceb913 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -108,7 +108,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet { // Negotiate version if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) { - if (initial_packet->type() != QUICPacketType::HANDSHAKE) { + if (initial_packet->type() != QUICPacketType::INITIAL) { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); } if (initial_packet->version()) { From d62dcb52c0ceceb90d824ba967e0b2f563273c58 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Dec 2017 12:34:11 +0900 Subject: [PATCH 0245/1313] draft-08: Update transport parameters & partially support unidirectional streams --- iocore/net/quic/Mock.h | 2 +- iocore/net/quic/QUICConfig.cc | 10 ++++- iocore/net/quic/QUICConfig.h | 14 +++--- iocore/net/quic/QUICDebugNames.cc | 10 ++++- iocore/net/quic/QUICFrame.h | 4 +- iocore/net/quic/QUICHandshake.cc | 11 ++--- iocore/net/quic/QUICHandshake.h | 2 +- iocore/net/quic/QUICStreamManager.cc | 45 +++++++++++++------ iocore/net/quic/QUICStreamManager.h | 6 ++- iocore/net/quic/QUICTransportParameters.cc | 32 +++++++------ iocore/net/quic/QUICTransportParameters.h | 21 +++++---- iocore/net/quic/QUICTypes.cc | 4 +- iocore/net/quic/QUICTypes.h | 2 +- iocore/net/quic/QUICVersionNegotiator.cc | 13 +----- .../net/quic/test/test_QUICStreamManager.cc | 24 +++++----- .../quic/test/test_QUICTransportParameters.cc | 20 ++++----- .../quic/test/test_QUICVersionNegotiator.cc | 2 +- 17 files changed, 129 insertions(+), 93 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 363de99a9ef..ff68b773791 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -268,7 +268,7 @@ class MockQUICConnection : public QUICConnection int _frameCount[256] = {0}; MockQUICStreamManager _stream_manager; - QUICTransportParametersInEncryptedExtensions dummy_transport_parameters; + QUICTransportParametersInEncryptedExtensions dummy_transport_parameters(); NetVConnectionContext_t _direction; }; diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 38b6b131c0b..3d6f64528cf 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -62,9 +62,15 @@ QUICConfigParams::initial_max_stream_data() const } uint32_t -QUICConfigParams::initial_max_stream_id() const +QUICConfigParams::initial_max_stream_id_bidi() const { - return this->_initial_max_stream_id; + return this->_initial_max_stream_id_bidi; +} + +uint32_t +QUICConfigParams::initial_max_stream_id_uni() const +{ + return this->_initial_max_stream_id_uni; } // diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 05588ce8652..e9b8a71422f 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -33,16 +33,18 @@ class QUICConfigParams : public ConfigInfo uint32_t no_activity_timeout_in() const; uint32_t initial_max_data() const; uint32_t initial_max_stream_data() const; - uint32_t initial_max_stream_id() const; + uint32_t initial_max_stream_id_bidi() const; + uint32_t initial_max_stream_id_uni() const; uint32_t server_id() const; private: // FIXME Fill appropriate values - uint32_t _no_activity_timeout_in = 0; - uint32_t _initial_max_data = 100; // in units of 1024 octets - uint32_t _initial_max_stream_data = 2048; - uint32_t _initial_max_stream_id = 100; - uint32_t _server_id = 0; + uint32_t _no_activity_timeout_in = 0; + uint32_t _initial_max_data = 100; // in units of 1024 octets + uint32_t _initial_max_stream_data = 2048; + uint32_t _initial_max_stream_id_bidi = 100; + uint32_t _initial_max_stream_id_uni = 100; + uint32_t _server_id = 0; }; class QUICConfig diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 1b794c988c6..71074db2e94 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -190,14 +190,20 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) return "INITIAL_MAX_STREAM_DATA"; case QUICTransportParameterId::INITIAL_MAX_DATA: return "INITIAL_MAX_DATA"; - case QUICTransportParameterId::INITIAL_MAX_STREAM_ID: - return "INITIAL_MAX_STREAM_ID"; + case QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI: + return "INITIAL_MAX_STREAM_ID_BIDI"; case QUICTransportParameterId::IDLE_TIMEOUT: return "IDLE_TIMEOUT"; case QUICTransportParameterId::OMIT_CONNECTION_ID: return "OMIT_CONNECTION_ID"; case QUICTransportParameterId::MAX_PACKET_SIZE: return "MAX_PACKET_SIZE"; + case QUICTransportParameterId::STATELESS_RESET_TOKEN: + return "STATELESS_RESET_TOKEN"; + case QUICTransportParameterId::ACK_DELAY_EXPONENT: + return "ACK_DELAY_EXPONENT"; + case QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI: + return "INITIAL_MAX_STREAM_ID_UNI"; default: return "UNKNOWN"; } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index d1e233856d8..9420ffce764 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -36,7 +36,7 @@ class QUICFrame public: QUICFrame(const uint8_t *buf, size_t len) : _buf(buf), _len(len){}; virtual QUICFrameType type() const; - virtual size_t size() const = 0; + virtual size_t size() const = 0; virtual void store(uint8_t *buf, size_t *len) const = 0; virtual void reset(const uint8_t *buf, size_t len); static QUICFrameType type(const uint8_t *buf); @@ -228,7 +228,7 @@ class QUICRstStreamFrame : public QUICFrame size_t _get_error_code_field_offset() const; size_t _get_final_offset_field_offset() const; size_t _get_final_offset_field_length() const; - + QUICStreamId _stream_id = 0; QUICAppErrorCode _error_code = 0; QUICOffset _final_offset = 0; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index fc21bceb913..9bbc0bb44e6 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -93,7 +93,6 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless this->_version_negotiator = new QUICVersionNegotiator(); this->_crypto->initialize_key_materials(this->_client_qc->original_connection_id()); - this->_load_local_transport_parameters(); SET_HANDLER(&QUICHandshake::state_read_client_hello); } @@ -114,6 +113,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet if (initial_packet->version()) { if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { QUICHSDebug("Version negotiation succeeded: %x", initial_packet->version()); + this->_load_local_transport_parameters(initial_packet->version()); packet_factory->set_version(this->_version_negotiator->negotiated_version()); } else { this->_client_qc->transmit_packet( @@ -182,7 +182,7 @@ QUICHandshake::set_transport_parameters(std::shared_ptr this->_abort_handshake(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR); return; } - QUICHSDebug("Version negotiation revalidated: %x", tp_in_ch->negotiated_version()); + QUICHSDebug("Version negotiation revalidated: %x", tp_in_ch->initial_version()); return; } @@ -285,16 +285,17 @@ QUICHandshake::state_closed(int event, void *data) } void -QUICHandshake::_load_local_transport_parameters() +QUICHandshake::_load_local_transport_parameters(QUICVersion negotiated_version) { QUICConfig::scoped_config params; // MUSTs - QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(); + QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(negotiated_version); tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, params->initial_max_stream_id()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni()); tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), 16); diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 92f0bbe3df0..773263866c5 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -82,7 +82,7 @@ class QUICHandshake : public QUICApplication QUICVersionNegotiator *_version_negotiator = nullptr; - void _load_local_transport_parameters(); + void _load_local_transport_parameters(QUICVersion negotiated_version); QUICErrorUPtr _process_client_hello(); QUICErrorUPtr _process_client_finished(); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 5223bb4db46..a1825ffaf2c 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -40,10 +40,7 @@ std::vector QUICStreamManager::interests() { return { - QUICFrameType::STREAM, - QUICFrameType::RST_STREAM, - QUICFrameType::MAX_STREAM_DATA, - QUICFrameType::MAX_STREAM_ID, + QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::MAX_STREAM_DATA, QUICFrameType::MAX_STREAM_ID, }; } @@ -69,18 +66,27 @@ QUICStreamManager::init_flow_control_params(const std::shared_ptr_local_tp) { - this->_local_maximum_stream_id = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_ID); + this->_local_maximum_stream_id_bidi = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI); + this->_local_maximum_stream_id_uni = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI); } if (this->_remote_tp) { - this->_remote_maximum_stream_id = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_ID); + this->_remote_maximum_stream_id_bidi = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI); + this->_remote_maximum_stream_id_uni = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI); } } void QUICStreamManager::set_max_stream_id(QUICStreamId id) { - if (this->_local_maximum_stream_id <= id) { - this->_local_maximum_stream_id = id; + QUICStreamType type = QUICTypeUtil::detect_stream_type(id); + if (type == QUICStreamType::SERVER_BIDI || type == QUICStreamType::CLIENT_BIDI) { + if (this->_local_maximum_stream_id_bidi <= id) { + this->_local_maximum_stream_id_bidi = id; + } + } else { + if (this->_local_maximum_stream_id_uni <= id) { + this->_local_maximum_stream_id_uni = id; + } } } @@ -170,7 +176,12 @@ QUICStreamManager::_handle_frame(const std::shared_ptr QUICErrorUPtr QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { - this->_remote_maximum_stream_id = frame->maximum_stream_id(); + QUICStreamType type = QUICTypeUtil::detect_stream_type(frame->maximum_stream_id()); + if (type == QUICStreamType::SERVER_BIDI || type == QUICStreamType::CLIENT_BIDI) { + this->_remote_maximum_stream_id_bidi = frame->maximum_stream_id(); + } else { + this->_remote_maximum_stream_id_uni = frame->maximum_stream_id(); + } return QUICErrorUPtr(new QUICNoError()); } @@ -191,18 +202,24 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) QUICStream *stream = this->_find_stream(stream_id); if (!stream) { QUICStreamType type = QUICTypeUtil::detect_stream_type(stream_id); - if (type == QUICStreamType::CLIENT && stream_id > this->_local_maximum_stream_id && this->_local_maximum_stream_id != 0) { + if (type == QUICStreamType::CLIENT_BIDI && stream_id > this->_local_maximum_stream_id_bidi && + this->_local_maximum_stream_id_bidi != 0) { + return nullptr; + } else if (type == QUICStreamType::CLIENT_UNI && stream_id > this->_local_maximum_stream_id_uni && + this->_local_maximum_stream_id_uni != 0) { return nullptr; - } else if (type == QUICStreamType::SERVER && stream_id > this->_remote_maximum_stream_id && - this->_remote_maximum_stream_id != 0) { + } else if (type == QUICStreamType::SERVER_BIDI && stream_id > this->_remote_maximum_stream_id_bidi && + this->_remote_maximum_stream_id_bidi != 0) { + return nullptr; + } else if (type == QUICStreamType::SERVER_UNI && stream_id > this->_remote_maximum_stream_id_uni && + this->_remote_maximum_stream_id_uni != 0) { return nullptr; } // TODO Free the stream somewhere stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream(); if (stream_id == STREAM_ID_FOR_HANDSHAKE) { // XXX rece/send max_stream_data are going to be set by init_flow_control_params() - stream->init(this->_tx, this->_connection_id, stream_id, - this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA)); + stream->init(this->_tx, this->_connection_id, stream_id); } else { // TODO: check local_tp and remote_tp is initialized stream->init(this->_tx, this->_connection_id, stream_id, diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index e067cc1b631..5493e581eb0 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -69,7 +69,9 @@ class QUICStreamManager : public QUICFrameHandler QUICApplicationMap *_app_map = nullptr; std::shared_ptr _local_tp = nullptr; std::shared_ptr _remote_tp = nullptr; - QUICStreamId _local_maximum_stream_id = 0; - QUICStreamId _remote_maximum_stream_id = 0; + QUICStreamId _local_maximum_stream_id_bidi = 0; + QUICStreamId _local_maximum_stream_id_uni = 0; + QUICStreamId _remote_maximum_stream_id_bidi = 0; + QUICStreamId _remote_maximum_stream_id_uni = 0; uint64_t _total_offset_sent = 0; }; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 72da3adbb87..0eeb24a192e 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -212,9 +212,8 @@ QUICTransportParameters::store(uint8_t *buf, uint16_t *len) const QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const uint8_t *buf, size_t len) { + this->_initial_version = QUICTypeUtil::read_QUICVersion(buf); this->_load(buf, len); - this->_negotiated_version = QUICTypeUtil::read_QUICVersion(buf); - this->_initial_version = QUICTypeUtil::read_QUICVersion(buf + sizeof(QUICVersion)); // Print all parameters for (auto &p : this->_parameters) { @@ -235,9 +234,6 @@ QUICTransportParametersInClientHello::_store(uint8_t *buf, uint16_t *len) const { size_t l; *len = 0; - QUICTypeUtil::write_QUICVersion(this->_negotiated_version, buf, &l); - buf += l; - *len += l; QUICTypeUtil::write_QUICVersion(this->_initial_version, buf, &l); *len += l; } @@ -245,13 +241,7 @@ QUICTransportParametersInClientHello::_store(uint8_t *buf, uint16_t *len) const std::ptrdiff_t QUICTransportParametersInClientHello::_parameters_offset(const uint8_t *) const { - return 8; // sizeof(QUICVersion) + sizeof(QUICVersion) -} - -QUICVersion -QUICTransportParametersInClientHello::negotiated_version() const -{ - return this->_negotiated_version; + return 4; // sizeof(QUICVersion) } QUICVersion @@ -266,6 +256,11 @@ QUICTransportParametersInClientHello::initial_version() const QUICTransportParametersInEncryptedExtensions::QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len) { + this->_negotiated_version = QUICTypeUtil::read_QUICVersion(buf); + this->_n_versions = buf[4] / 4; + for (int i = 0; i < this->_n_versions; ++i) { + this->_versions[i] = QUICTypeUtil::read_QUICVersion(buf + 5 + (i * 4)); + } this->_load(buf, len); } @@ -275,6 +270,11 @@ QUICTransportParametersInEncryptedExtensions::_store(uint8_t *buf, uint16_t *len uint8_t *p = buf; size_t l; + // negotiated_version + QUICTypeUtil::write_QUICVersion(this->_negotiated_version, buf, &l); + p += l; + + // supported_versions p[0] = this->_n_versions * sizeof(uint32_t); ++p; for (int i = 0; i < this->_n_versions; ++i) { @@ -284,6 +284,12 @@ QUICTransportParametersInEncryptedExtensions::_store(uint8_t *buf, uint16_t *len *len = p - buf; } +QUICVersion +QUICTransportParametersInEncryptedExtensions::negotiated_version() const +{ + return this->_negotiated_version; +} + void QUICTransportParametersInEncryptedExtensions::add_version(QUICVersion version) { @@ -293,7 +299,7 @@ QUICTransportParametersInEncryptedExtensions::add_version(QUICVersion version) std::ptrdiff_t QUICTransportParametersInEncryptedExtensions::_parameters_offset(const uint8_t *buf) const { - return 1 + buf[0]; + return 4 + 1 + buf[4]; } // diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index e1c42520b10..f0729a53d30 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -36,11 +36,13 @@ class QUICTransportParameterId enum { INITIAL_MAX_STREAM_DATA = 0, INITIAL_MAX_DATA, - INITIAL_MAX_STREAM_ID, + INITIAL_MAX_STREAM_ID_BIDI, IDLE_TIMEOUT, OMIT_CONNECTION_ID, MAX_PACKET_SIZE, STATELESS_RESET_TOKEN, + ACK_DELAY_EXPONENT, + INITIAL_MAX_STREAM_ID_UNI }; explicit operator bool() const { return true; } @@ -108,10 +110,9 @@ class QUICTransportParameters class QUICTransportParametersInClientHello : public QUICTransportParameters { public: - QUICTransportParametersInClientHello(QUICVersion negotiated_version, QUICVersion initial_version) - : QUICTransportParameters(), _negotiated_version(negotiated_version), _initial_version(initial_version){}; + QUICTransportParametersInClientHello(QUICVersion initial_version) + : QUICTransportParameters(), _initial_version(initial_version){}; QUICTransportParametersInClientHello(const uint8_t *buf, size_t len); - QUICVersion negotiated_version() const; QUICVersion initial_version() const; protected: @@ -119,23 +120,25 @@ class QUICTransportParametersInClientHello : public QUICTransportParameters void _store(uint8_t *buf, uint16_t *len) const override; private: - QUICVersion _negotiated_version = 0; - QUICVersion _initial_version = 0; + QUICVersion _initial_version = 0; }; class QUICTransportParametersInEncryptedExtensions : public QUICTransportParameters { public: - QUICTransportParametersInEncryptedExtensions() : QUICTransportParameters(){}; + QUICTransportParametersInEncryptedExtensions(QUICVersion negotiated_version) + : QUICTransportParameters(), _negotiated_version(negotiated_version){}; QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len); + QUICVersion negotiated_version() const; void add_version(QUICVersion version); protected: std::ptrdiff_t _parameters_offset(const uint8_t *buf) const override; void _store(uint8_t *buf, uint16_t *len) const override; - uint8_t _n_versions = 0; - QUICVersion _versions[256] = {}; + QUICVersion _negotiated_version = 0; + uint8_t _n_versions = 0; + QUICVersion _versions[256] = {}; }; class QUICTransportParametersHandler diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index d812ba58c79..f7cc8420e75 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -38,10 +38,10 @@ QUICTypeUtil::hasLongHeader(const uint8_t *buf) QUICStreamType QUICTypeUtil::detect_stream_type(QUICStreamId id) { - uint8_t type = (id & 0x01); - if (type == 0) { + if (id == 0) { return QUICStreamType::HANDSHAKE; } else { + uint8_t type = (id & 0x03); return static_cast(type); } } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index a715be1f08e..4025ecb4c27 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -246,7 +246,7 @@ class QUICStatelessResetToken void _gen_token(uint64_t data); }; -enum class QUICStreamType { SERVER, CLIENT, HANDSHAKE }; +enum class QUICStreamType { CLIENT_BIDI, SERVER_BIDI, CLIENT_UNI, SERVER_UNI, HANDSHAKE }; class QUICTypeUtil { diff --git a/iocore/net/quic/QUICVersionNegotiator.cc b/iocore/net/quic/QUICVersionNegotiator.cc index aa91c0c9847..782305423c9 100644 --- a/iocore/net/quic/QUICVersionNegotiator.cc +++ b/iocore/net/quic/QUICVersionNegotiator.cc @@ -43,18 +43,7 @@ QUICVersionNegotiator::negotiate(const QUICPacket *initial_packet) QUICVersionNegotiationStatus QUICVersionNegotiator::revalidate(const QUICTransportParametersInClientHello *tp) { - QUICVersion version = tp->negotiated_version(); - if (this->_negotiated_version == version) { - if (tp->negotiated_version() != tp->initial_version()) { - // FIXME Check initial_version - /* If the initial version is different from the negotiated_version, a - * stateless server MUST check that it would have sent a version - * negotiation packet if it had received a packet with the indicated - * initial_version. (Draft-04 7.3.4. Version Negotiation Validation) - */ - this->_status = QUICVersionNegotiationStatus::FAILED; - this->_negotiated_version = 0; - } + if (this->_negotiated_version == tp->initial_version()) { this->_status = QUICVersionNegotiationStatus::REVALIDATED; } else { this->_status = QUICVersionNegotiationStatus::FAILED; diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index cbcb41cdcea..7920a7dede1 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -36,9 +36,10 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") MockQUICApplication mock_app; app_map.set_default(&mock_app); QUICStreamManager sm(0, &tx, &app_map); - std::shared_ptr local_tp = std::make_shared(); + std::shared_ptr local_tp = + std::make_shared(static_cast(0)); std::shared_ptr remote_tp = - std::make_shared(static_cast(0), static_cast(0)); + std::make_shared(static_cast(0)); sm.init_flow_control_params(local_tp, remote_tp); // STREAM frames create new streams @@ -69,8 +70,8 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") CHECK(sm.stream_count() == 5); // Set local maximum stream id - sm.set_max_stream_id(4); - std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_blocked_frame(5); + sm.set_max_stream_id(5); + std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_blocked_frame(8); sm.handle_frame(stream_blocked_frame_x); CHECK(sm.stream_count() == 5); } @@ -82,9 +83,10 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") MockQUICApplication mock_app; app_map.set_default(&mock_app); QUICStreamManager sm(0, &tx, &app_map); - std::shared_ptr local_tp = std::make_shared(); + std::shared_ptr local_tp = + std::make_shared(static_cast(0)); std::shared_ptr remote_tp = - std::make_shared(static_cast(0), static_cast(0)); + std::make_shared(static_cast(0)); sm.init_flow_control_params(local_tp, remote_tp); // STREAM frames create new streams @@ -102,10 +104,11 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") MockQUICApplication mock_app; app_map.set_default(&mock_app); QUICStreamManager sm(0, &tx, &app_map); - std::shared_ptr local_tp = std::make_shared(); + std::shared_ptr local_tp = + std::make_shared(static_cast(0)); local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); std::shared_ptr remote_tp = - std::make_shared(static_cast(0), static_cast(0)); + std::make_shared(static_cast(0)); sm.init_flow_control_params(local_tp, remote_tp); uint8_t data[1024] = {0}; @@ -135,10 +138,11 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") MockQUICApplication mock_app; app_map.set_default(&mock_app); QUICStreamManager sm(0, &tx, &app_map); - std::shared_ptr local_tp = std::make_shared(); + std::shared_ptr local_tp = + std::make_shared(static_cast(0)); local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); std::shared_ptr remote_tp = - std::make_shared(static_cast(0), static_cast(0)); + std::make_shared(static_cast(0)); sm.init_flow_control_params(local_tp, remote_tp); uint8_t data[1024] = {0}; diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index bac227e9655..51dbdc7dd02 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -30,7 +30,6 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") SECTION("OK") { uint8_t buf[] = { - 0x01, 0x02, 0x03, 0x04, // negotiated version 0x05, 0x06, 0x07, 0x08, // iinitial version 0x00, 0x1e, // size of parameters 0x00, 0x00, // parameter id @@ -49,7 +48,6 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf)); CHECK(params_in_ch.is_valid()); - CHECK(params_in_ch.negotiated_version() == 0x01020304); CHECK(params_in_ch.initial_version() == 0x05060708); uint16_t len = 0; @@ -63,7 +61,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") CHECK(len == 4); CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); - data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, len); + data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, len); CHECK(len == 4); CHECK(memcmp(data, "\x0a\x0b\x0c\x0d", 4) == 0); @@ -79,7 +77,6 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") SECTION("Duplicate parameters") { uint8_t buf[] = { - 0x01, 0x02, 0x03, 0x04, // negotiated version 0x05, 0x06, 0x07, 0x08, // iinitial version 0x00, 0x10, // size of parameters 0x00, 0x00, // parameter id @@ -101,7 +98,6 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") uint16_t len; uint8_t expected[] = { - 0x01, 0x02, 0x03, 0x04, // negotiated version 0x05, 0x06, 0x07, 0x08, // iinitial version 0x00, 0x22, // size of parameters 0x00, 0x00, // parameter id @@ -116,7 +112,7 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // value }; - QUICTransportParametersInClientHello params_in_ch(0x01020304, 0x05060708); + QUICTransportParametersInClientHello params_in_ch(0x05060708); uint32_t max_stream_data = 0x11223344; params_in_ch.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, max_stream_data); @@ -129,7 +125,7 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") params_in_ch.set(QUICTransportParameterId::STATELESS_RESET_TOKEN, stateless_reset_token, 16); params_in_ch.store(buf, &len); - CHECK(len == 44); + CHECK(len == 40); CHECK(memcmp(buf, expected, len) == 0); } @@ -138,6 +134,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") SECTION("OK") { uint8_t buf[] = { + 0x01, 0x02, 0x03, 0x04, // negotiated version 0x04, // size of supported versions 0x01, 0x02, 0x03, 0x04, // 0x00, 0x1e, // size of parameters @@ -157,6 +154,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf)); CHECK(params_in_ee.is_valid()); + CHECK(params_in_ee.negotiated_version() == 0x01020304); uint16_t len = 0; const uint8_t *data = nullptr; @@ -169,7 +167,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") CHECK(len == 4); CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); - data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_ID, len); + data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, len); CHECK(len == 4); CHECK(memcmp(data, "\x0a\x0b\x0c\x0d", 4) == 0); @@ -185,6 +183,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") SECTION("Duplicate parameters") { uint8_t buf[] = { + 0x01, 0x02, 0x03, 0x04, // negotiated version 0x04, // size of supported versions 0x01, 0x02, 0x03, 0x04, // 0x00, 0x1e, // size of parameters @@ -207,6 +206,7 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") uint16_t len; uint8_t expected[] = { + 0x01, 0x02, 0x03, 0x04, // negotiated version 0x08, // size of supported versions 0x01, 0x02, 0x03, 0x04, // version 1 0x05, 0x06, 0x07, 0x08, // version 2 @@ -219,7 +219,7 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") 0xab, 0xcd, // value }; - QUICTransportParametersInEncryptedExtensions params_in_ee; + QUICTransportParametersInEncryptedExtensions params_in_ee(0x01020304); uint32_t max_stream_data = 0x11223344; params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, max_stream_data); @@ -230,6 +230,6 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") params_in_ee.add_version(0x01020304); params_in_ee.add_version(0x05060708); params_in_ee.store(buf, &len); - CHECK(len == 25); + CHECK(len == 29); CHECK(memcmp(buf, expected, len) == 0); } diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index c4b34448da2..2917e1c15d3 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -42,7 +42,7 @@ TEST_CASE("QUICVersionNegotiator_Normal", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); // Revalidate version - QUICTransportParametersInClientHello tp(QUIC_SUPPORTED_VERSIONS[0], QUIC_SUPPORTED_VERSIONS[0]); + QUICTransportParametersInClientHello tp(QUIC_SUPPORTED_VERSIONS[0]); vn.revalidate(&tp); CHECK(vn.status() == QUICVersionNegotiationStatus::REVALIDATED); CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); From 9859e54c495023d591d437d90330fb05efd7d541 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 14 Dec 2017 12:50:41 +0900 Subject: [PATCH 0246/1313] draft-08: Support new frame format of CONNECTION_CLOSE, APPLICATION_CLOSE, MAX_DATA, MAX_STREAM_DATA and MAX_STREAM_ID --- iocore/net/quic/QUICFrame.cc | 140 +++++++++++++++++++++---- iocore/net/quic/QUICFrame.h | 35 +++++-- iocore/net/quic/QUICTypes.cc | 9 ++ iocore/net/quic/QUICTypes.h | 4 +- iocore/net/quic/test/test_QUICFrame.cc | 56 +++++----- 5 files changed, 185 insertions(+), 59 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 1973f2b48f8..9112d59b2e4 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -796,7 +796,7 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len) const // // CONNECTION_CLOSE frame // -QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint16_t reason_phrase_length, +QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase) { this->_error_code = error_code; @@ -813,7 +813,8 @@ QUICConnectionCloseFrame::type() const size_t QUICConnectionCloseFrame::size() const { - return 5 + this->reason_phrase_length(); + return sizeof(QUICFrameType) + sizeof(QUICTransErrorCode) + this->_get_reason_phrase_length_field_length() + + this->reason_phrase_length(); } void @@ -825,7 +826,7 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len) const ++p; QUICTypeUtil::write_QUICTransErrorCode(this->_error_code, p, &n); p += n; - QUICTypeUtil::write_uint_as_nbytes(this->_reason_phrase_length, 2, p, &n); + QUICTypeUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); p += n; if (this->_reason_phrase_length > 0) { memcpy(p, this->_reason_phrase, this->_reason_phrase_length); @@ -845,11 +846,11 @@ QUICConnectionCloseFrame::error_code() const } } -uint16_t +uint64_t QUICConnectionCloseFrame::reason_phrase_length() const { if (this->_buf) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 3, 2); + return QUICTypeUtil::read_QUICVariableInt(this->_buf + this->_get_reason_phrase_length_field_offset()); } else { return this->_reason_phrase_length; } @@ -859,16 +860,38 @@ const char * QUICConnectionCloseFrame::reason_phrase() const { if (this->_buf) { - return reinterpret_cast(this->_buf + 5); + return reinterpret_cast(this->_buf + this->_get_reason_phrase_field_offset()); } else { return this->_reason_phrase; } } +size_t +QUICConnectionCloseFrame::_get_reason_phrase_length_field_offset() const +{ + return sizeof(QUICFrameType) + sizeof(QUICTransErrorCode); +} + +size_t +QUICConnectionCloseFrame::_get_reason_phrase_length_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_reason_phrase_length_field_offset()); + } else { + return QUICVariableInt::size(this->_reason_phrase_length); + } +} + +size_t +QUICConnectionCloseFrame::_get_reason_phrase_field_offset() const +{ + return this->_get_reason_phrase_length_field_offset() + this->_get_reason_phrase_length_field_length(); +} + // // APPLICATION_CLOSE frame // -QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint16_t reason_phrase_length, +QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase) { this->_error_code = error_code; @@ -885,7 +908,8 @@ QUICApplicationCloseFrame::type() const size_t QUICApplicationCloseFrame::size() const { - return 5 + this->reason_phrase_length(); + return sizeof(QUICFrameType) + sizeof(QUICAppErrorCode) + this->_get_reason_phrase_length_field_length() + + this->reason_phrase_length(); } void @@ -897,7 +921,7 @@ QUICApplicationCloseFrame::store(uint8_t *buf, size_t *len) const ++p; QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); p += n; - QUICTypeUtil::write_uint_as_nbytes(this->_reason_phrase_length, 2, p, &n); + QUICTypeUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); p += n; if (this->_reason_phrase_length > 0) { memcpy(p, this->_reason_phrase, this->_reason_phrase_length); @@ -917,11 +941,11 @@ QUICApplicationCloseFrame::error_code() const } } -uint16_t +uint64_t QUICApplicationCloseFrame::reason_phrase_length() const { if (this->_buf) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 3, 2); + return QUICTypeUtil::read_QUICVariableInt(this->_buf + this->_get_reason_phrase_length_field_offset()); } else { return this->_reason_phrase_length; } @@ -931,12 +955,34 @@ const char * QUICApplicationCloseFrame::reason_phrase() const { if (this->_buf) { - return reinterpret_cast(this->_buf + 5); + return reinterpret_cast(this->_buf + this->_get_reason_phrase_field_offset()); } else { return this->_reason_phrase; } } +size_t +QUICApplicationCloseFrame::_get_reason_phrase_length_field_offset() const +{ + return sizeof(QUICFrameType) + sizeof(QUICTransErrorCode); +} + +size_t +QUICApplicationCloseFrame::_get_reason_phrase_length_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_reason_phrase_length_field_offset()); + } else { + return QUICVariableInt::size(this->_reason_phrase_length); + } +} + +size_t +QUICApplicationCloseFrame::_get_reason_phrase_field_offset() const +{ + return this->_get_reason_phrase_length_field_offset() + this->_get_reason_phrase_length_field_length(); +} + // // MAX_DATA frame // @@ -954,7 +1000,7 @@ QUICMaxDataFrame::type() const size_t QUICMaxDataFrame::size() const { - return 9; + return sizeof(QUICFrameType) + this->_get_max_data_field_length(); } void @@ -964,7 +1010,7 @@ QUICMaxDataFrame::store(uint8_t *buf, size_t *len) const uint8_t *p = buf; *p = static_cast(QUICFrameType::MAX_DATA); ++p; - QUICTypeUtil::write_uint_as_nbytes(this->_maximum_data, 8, p, &n); + QUICTypeUtil::write_QUICMaxData(this->_maximum_data, p, &n); p += n; *len = p - buf; @@ -974,12 +1020,22 @@ uint64_t QUICMaxDataFrame::maximum_data() const { if (this->_buf) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 1, 8); + return QUICTypeUtil::read_QUICMaxData(this->_buf + sizeof(QUICFrameType)); } else { return this->_maximum_data; } } +size_t +QUICMaxDataFrame::_get_max_data_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); + } else { + return QUICVariableInt::size(this->_maximum_data); + } +} + // // MAX_STREAM_DATA // @@ -998,7 +1054,7 @@ QUICMaxStreamDataFrame::type() const size_t QUICMaxStreamDataFrame::size() const { - return 13; + return sizeof(QUICFrameType) + this->_get_stream_id_field_length() + this->_get_max_stream_data_field_length(); } void @@ -1020,7 +1076,7 @@ QUICStreamId QUICMaxStreamDataFrame::stream_id() const { if (this->_buf) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 1, 4); + return QUICTypeUtil::read_QUICStreamId(this->_buf + sizeof(QUICFrameType)); } else { return this->_stream_id; } @@ -1030,12 +1086,44 @@ uint64_t QUICMaxStreamDataFrame::maximum_stream_data() const { if (this->_buf) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 5, 8); + return QUICTypeUtil::read_QUICMaxData(this->_buf + this->_get_max_stream_data_field_offset()); } else { return this->_maximum_stream_data; } } +size_t +QUICMaxStreamDataFrame::_get_stream_id_field_offset() const +{ + return sizeof(QUICFrameType); +} + +size_t +QUICMaxStreamDataFrame::_get_stream_id_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_stream_id_field_offset()); + } else { + return QUICVariableInt::size(this->_stream_id); + } +} + +size_t +QUICMaxStreamDataFrame::_get_max_stream_data_field_offset() const +{ + return sizeof(QUICFrameType) + this->_get_stream_id_field_length(); +} + +size_t +QUICMaxStreamDataFrame::_get_max_stream_data_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_max_stream_data_field_offset()); + } else { + return QUICVariableInt::size(this->_stream_id); + } +} + // // MAX_STREAM_ID // @@ -1053,7 +1141,7 @@ QUICMaxStreamIdFrame::type() const size_t QUICMaxStreamIdFrame::size() const { - return 5; + return sizeof(QUICFrameType) + this->_get_max_stream_id_field_length(); } void @@ -1063,7 +1151,7 @@ QUICMaxStreamIdFrame::store(uint8_t *buf, size_t *len) const uint8_t *p = buf; *p = static_cast(QUICFrameType::MAX_STREAM_ID); ++p; - QUICTypeUtil::write_uint_as_nbytes(this->_maximum_stream_id, 4, p, &n); + QUICTypeUtil::write_QUICStreamId(this->_maximum_stream_id, p, &n); p += n; *len = p - buf; @@ -1073,12 +1161,22 @@ QUICStreamId QUICMaxStreamIdFrame::maximum_stream_id() const { if (this->_buf) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 1, 4); + return QUICTypeUtil::read_QUICStreamId(this->_buf + sizeof(QUICFrameType)); } else { return this->_maximum_stream_id; } } +size_t +QUICMaxStreamIdFrame::_get_max_stream_id_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); + } else { + return QUICVariableInt::size(this->_maximum_stream_id); + } +} + // // BLOCKED frame // diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 9420ffce764..6da2a94cf71 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -36,7 +36,7 @@ class QUICFrame public: QUICFrame(const uint8_t *buf, size_t len) : _buf(buf), _len(len){}; virtual QUICFrameType type() const; - virtual size_t size() const = 0; + virtual size_t size() const = 0; virtual void store(uint8_t *buf, size_t *len) const = 0; virtual void reset(const uint8_t *buf, size_t len); static QUICFrameType type(const uint8_t *buf); @@ -228,7 +228,7 @@ class QUICRstStreamFrame : public QUICFrame size_t _get_error_code_field_offset() const; size_t _get_final_offset_field_offset() const; size_t _get_final_offset_field_length() const; - + QUICStreamId _stream_id = 0; QUICAppErrorCode _error_code = 0; QUICOffset _final_offset = 0; @@ -269,17 +269,21 @@ class QUICConnectionCloseFrame : public QUICFrame public: QUICConnectionCloseFrame() : QUICFrame() {} QUICConnectionCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase); + QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; QUICTransErrorCode error_code() const; - uint16_t reason_phrase_length() const; + uint64_t reason_phrase_length() const; const char *reason_phrase() const; private: + size_t _get_reason_phrase_length_field_offset() const; + size_t _get_reason_phrase_length_field_length() const; + size_t _get_reason_phrase_field_offset() const; + QUICTransErrorCode _error_code; - uint16_t _reason_phrase_length = 0; + uint64_t _reason_phrase_length = 0; const char *_reason_phrase = nullptr; }; @@ -292,17 +296,21 @@ class QUICApplicationCloseFrame : public QUICFrame public: QUICApplicationCloseFrame() : QUICFrame() {} QUICApplicationCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint16_t reason_phrase_length, const char *reason_phrase); + QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; QUICAppErrorCode error_code() const; - uint16_t reason_phrase_length() const; + uint64_t reason_phrase_length() const; const char *reason_phrase() const; private: + size_t _get_reason_phrase_length_field_offset() const; + size_t _get_reason_phrase_length_field_length() const; + size_t _get_reason_phrase_field_offset() const; + QUICAppErrorCode _error_code = 0; - uint16_t _reason_phrase_length = 0; + uint64_t _reason_phrase_length = 0; const char *_reason_phrase = nullptr; }; @@ -322,6 +330,8 @@ class QUICMaxDataFrame : public QUICFrame uint64_t maximum_data() const; private: + size_t _get_max_data_field_length() const; + uint64_t _maximum_data = 0; }; @@ -342,6 +352,11 @@ class QUICMaxStreamDataFrame : public QUICFrame uint64_t maximum_stream_data() const; private: + size_t _get_stream_id_field_offset() const; + size_t _get_stream_id_field_length() const; + size_t _get_max_stream_data_field_offset() const; + size_t _get_max_stream_data_field_length() const; + QUICStreamId _stream_id = 0; uint64_t _maximum_stream_data = 0; }; @@ -362,6 +377,8 @@ class QUICMaxStreamIdFrame : public QUICFrame QUICStreamId maximum_stream_id() const; private: + size_t _get_max_stream_id_field_length() const; + QUICStreamId _maximum_stream_id = 0; }; @@ -376,6 +393,8 @@ class QUICBlockedFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; +private: + size_t _get_max_data_field_length() const; }; // diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index f7cc8420e75..89d5eca5abe 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -95,6 +95,15 @@ QUICTypeUtil::read_QUICAppErrorCode(const uint8_t *buf) return static_cast(read_nbytes_as_uint(buf, 2)); } +uint64_t +QUICTypeUtil::read_QUICMaxData(const uint8_t *buf) +{ + uint64_t max_data = 0; + size_t len = 0; + QUICVariableInt::decode(max_data, len, buf, 8); + return max_data; +} + uint64_t QUICTypeUtil::read_QUICVariableInt(const uint8_t *buf) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 4025ecb4c27..1680820d17e 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -83,7 +83,7 @@ enum class QUICPacketShortHeaderType : int { }; // XXX If you add or remove QUICFrameType, you might also need to change QUICFrame::type(const uint8_t *) -enum class QUICFrameType : int { +enum class QUICFrameType : uint8_t { PADDING = 0x00, RST_STREAM, CONNECTION_CLOSE, @@ -261,7 +261,7 @@ class QUICTypeUtil static QUICOffset read_QUICOffset(const uint8_t *buf); static QUICTransErrorCode read_QUICTransErrorCode(const uint8_t *buf); static QUICAppErrorCode read_QUICAppErrorCode(const uint8_t *buf); - + static uint64_t read_QUICMaxData(const uint8_t *buf); static uint64_t read_QUICVariableInt(const uint8_t *buf); static void write_QUICConnectionId(QUICConnectionId connection_id, uint8_t n, uint8_t *buf, size_t *len); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 3b76febd0c2..565bf6e6023 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -453,28 +453,28 @@ TEST_CASE("Load ConnectionClose Frame", "[quic]") uint8_t buf1[] = { 0x02, // Type 0x00, 0x0A, // Error Code - 0x00, 0x05, // Reason Phrase Length + 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::CONNECTION_CLOSE); - CHECK(frame1->size() == 10); + CHECK(frame1->size() == 9); std::shared_ptr connectionCloseFrame1 = std::dynamic_pointer_cast(frame1); CHECK(connectionCloseFrame1 != nullptr); CHECK(connectionCloseFrame1->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION); CHECK(connectionCloseFrame1->reason_phrase_length() == 5); - CHECK(memcmp(connectionCloseFrame1->reason_phrase(), buf1 + 5, 5) == 0); + CHECK(memcmp(connectionCloseFrame1->reason_phrase(), buf1 + 4, 5) == 0); // No reason phrase uint8_t buf2[] = { 0x02, // Type 0x00, 0x0A, // Error Code - 0x00, 0x00, // Reason Phrase Length + 0x00, // Reason Phrase Length }; std::shared_ptr frame2 = QUICFrameFactory::create(buf2, sizeof(buf1)); CHECK(frame2->type() == QUICFrameType::CONNECTION_CLOSE); - CHECK(frame2->size() == 5); + CHECK(frame2->size() == 4); std::shared_ptr connectionCloseFrame2 = std::dynamic_pointer_cast(frame2); CHECK(connectionCloseFrame2 != nullptr); @@ -490,22 +490,22 @@ TEST_CASE("Store ConnectionClose Frame", "[quic]") uint8_t expected1[] = { 0x02, // Type 0x00, 0x0A, // Error Code - 0x00, 0x05, // Reason Phrase Length + 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; QUICConnectionCloseFrame connectionCloseFrame1(QUICTransErrorCode::PROTOCOL_VIOLATION, 5, "ABCDE"); connectionCloseFrame1.store(buf, &len); - CHECK(len == 10); + CHECK(len == 9); CHECK(memcmp(buf, expected1, len) == 0); uint8_t expected2[] = { 0x02, // Type 0x00, 0x0A, // Error Code - 0x00, 0x00, // Reason Phrase Length + 0x00, // Reason Phrase Length }; QUICConnectionCloseFrame connectionCloseFrame2(QUICTransErrorCode::PROTOCOL_VIOLATION, 0, nullptr); connectionCloseFrame2.store(buf, &len); - CHECK(len == 5); + CHECK(len == 4); CHECK(memcmp(buf, expected2, len) == 0); } @@ -514,28 +514,28 @@ TEST_CASE("Load ApplicationClose Frame", "[quic]") uint8_t buf1[] = { 0x03, // Type 0x00, 0x01, // Error Code - 0x00, 0x05, // Reason Phrase Length + 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::APPLICATION_CLOSE); - CHECK(frame1->size() == 10); + CHECK(frame1->size() == 9); std::shared_ptr applicationCloseFrame1 = std::dynamic_pointer_cast(frame1); CHECK(applicationCloseFrame1 != nullptr); CHECK(applicationCloseFrame1->error_code() == static_cast(0x01)); CHECK(applicationCloseFrame1->reason_phrase_length() == 5); - CHECK(memcmp(applicationCloseFrame1->reason_phrase(), buf1 + 5, 5) == 0); + CHECK(memcmp(applicationCloseFrame1->reason_phrase(), buf1 + 4, 5) == 0); // No reason phrase uint8_t buf2[] = { 0x03, // Type 0x00, 0x01, // Error Code - 0x00, 0x00, // Reason Phrase Length + 0x00, // Reason Phrase Length }; std::shared_ptr frame2 = QUICFrameFactory::create(buf2, sizeof(buf1)); CHECK(frame2->type() == QUICFrameType::APPLICATION_CLOSE); - CHECK(frame2->size() == 5); + CHECK(frame2->size() == 4); std::shared_ptr applicationCloseFrame2 = std::dynamic_pointer_cast(frame2); CHECK(applicationCloseFrame2 != nullptr); @@ -551,22 +551,22 @@ TEST_CASE("Store ApplicationClose Frame", "[quic]") uint8_t expected1[] = { 0x03, // Type 0x00, 0x01, // Error Code - 0x00, 0x05, // Reason Phrase Length + 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; QUICApplicationCloseFrame applicationCloseFrame1(static_cast(0x01), 5, "ABCDE"); applicationCloseFrame1.store(buf, &len); - CHECK(len == 10); + CHECK(len == 9); CHECK(memcmp(buf, expected1, len) == 0); uint8_t expected2[] = { 0x03, // Type 0x00, 0x01, // Error Code - 0x00, 0x00, // Reason Phrase Length + 0x00, // Reason Phrase Length }; QUICApplicationCloseFrame applicationCloseFrame2(static_cast(0x01), 0, nullptr); applicationCloseFrame2.store(buf, &len); - CHECK(len == 5); + CHECK(len == 4); CHECK(memcmp(buf, expected2, len) == 0); } @@ -574,7 +574,7 @@ TEST_CASE("Load MaxData Frame", "[quic]") { uint8_t buf1[] = { 0x04, // Type - 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data + 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_DATA); @@ -591,7 +591,7 @@ TEST_CASE("Store MaxData Frame", "[quic]") uint8_t expected[] = { 0x04, // Type - 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data + 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data }; QUICMaxDataFrame maxDataFrame(0x1122334455667788); maxDataFrame.store(buf, &len); @@ -603,8 +603,8 @@ TEST_CASE("Load MaxStreamData Frame", "[quic]") { uint8_t buf1[] = { 0x05, // Type - 0x01, 0x02, 0x03, 0x04, // Stream ID - 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data + 0x81, 0x02, 0x03, 0x04, // Stream ID + 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_STREAM_DATA); @@ -623,8 +623,8 @@ TEST_CASE("Store MaxStreamData Frame", "[quic]") uint8_t expected[] = { 0x05, // Type - 0x01, 0x02, 0x03, 0x04, // Stream ID - 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data + 0x81, 0x02, 0x03, 0x04, // Stream ID + 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data }; QUICMaxStreamDataFrame maxStreamDataFrame(0x01020304, 0x1122334455667788ULL); maxStreamDataFrame.store(buf, &len); @@ -636,7 +636,7 @@ TEST_CASE("Load MaxStreamId Frame", "[quic]") { uint8_t buf1[] = { 0x06, // Type - 0x01, 0x02, 0x03, 0x04, // Stream ID + 0x81, 0x02, 0x03, 0x04, // Stream ID }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_STREAM_ID); @@ -653,7 +653,7 @@ TEST_CASE("Store MaxStreamId Frame", "[quic]") uint8_t expected[] = { 0x06, // Type - 0x01, 0x02, 0x03, 0x04, // Stream ID + 0x81, 0x02, 0x03, 0x04, // Stream ID }; QUICMaxStreamIdFrame maxStreamIdFrame(0x01020304); maxStreamIdFrame.store(buf, &len); @@ -827,11 +827,11 @@ TEST_CASE("QUICFrameFactory Fast Create Frame", "[quic]") uint8_t buf1[] = { 0x06, // Type - 0x01, 0x02, 0x03, 0x04, // Stream Data + 0x81, 0x02, 0x03, 0x04, // Stream Data }; uint8_t buf2[] = { 0x06, // Type - 0x05, 0x06, 0x07, 0x08, // Stream Data + 0x85, 0x06, 0x07, 0x08, // Stream Data }; std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); CHECK(frame1 != nullptr); From 66b937f6b31b79c34682a4a84ff28a2f78830680 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 14 Dec 2017 15:03:37 +0900 Subject: [PATCH 0247/1313] draft-08: Support new frame format of BLOCKED, STREAM_BLOCKED, and STREAM_ID_BLOCKED --- iocore/net/quic/QUICDebugNames.cc | 4 +- iocore/net/quic/QUICFlowController.cc | 4 +- iocore/net/quic/QUICFrame.cc | 149 ++++++++++++++---- iocore/net/quic/QUICFrame.h | 53 +++++-- iocore/net/quic/QUICTypes.h | 2 +- iocore/net/quic/test/test_QUICFrame.cc | 51 +++--- .../net/quic/test/test_QUICStreamManager.cc | 8 +- iocore/net/quic/test/test_QUICStreamState.cc | 2 +- 8 files changed, 203 insertions(+), 70 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 71074db2e94..e08a91034d5 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -70,8 +70,8 @@ QUICDebugNames::frame_type(QUICFrameType type) return "BLOCKED"; case QUICFrameType::STREAM_BLOCKED: return "STREAM_BLOCKED"; - case QUICFrameType::STREAM_ID_NEEDED: - return "STREAM_ID_NEEDED"; + case QUICFrameType::STREAM_ID_BLOCKED: + return "STREAM_ID_BLOCKED"; case QUICFrameType::NEW_CONNECTION_ID: return "NEW_CONNECTION_ID"; case QUICFrameType::ACK: diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 7c8f0802d40..a468561c7f8 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -120,7 +120,7 @@ QUICLocalFlowController::forward_limit(QUICOffset offset) QUICFrameUPtr QUICRemoteConnectionFlowController::_create_frame() { - return QUICFrameFactory::create_blocked_frame(); + return QUICFrameFactory::create_blocked_frame(this->_offset); } QUICFrameUPtr @@ -132,7 +132,7 @@ QUICLocalConnectionFlowController::_create_frame() QUICFrameUPtr QUICRemoteStreamFlowController::_create_frame() { - return QUICFrameFactory::create_stream_blocked_frame(this->_stream_id); + return QUICFrameFactory::create_stream_blocked_frame(this->_stream_id, this->_offset); } QUICFrameUPtr diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 9112d59b2e4..61274852a1b 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -36,7 +36,7 @@ ClassAllocator quicMaxStreamIdFrameAllocator("quicMaxStrea ClassAllocator quicPingFrameAllocator("quicPingFrameAllocator"); ClassAllocator quicBlockedFrameAllocator("quicBlockedFrameAllocator"); ClassAllocator quicStreamBlockedFrameAllocator("quicStreamBlockedFrameAllocator"); -ClassAllocator quicStreamIdNeededFrameAllocator("quicStreamIdNeededFrameAllocator"); +ClassAllocator quicStreamIdBlockedFrameAllocator("quicStreamIdBlockedFrameAllocator"); ClassAllocator quicNewConnectionIdFrameAllocator("quicNewConnectionIdFrameAllocator"); ClassAllocator quicStopSendingFrameAllocator("quicStopSendingFrameAllocator"); ClassAllocator quicRetransmissionFrameAllocator("quicRetransmissionFrameAllocator"); @@ -1189,24 +1189,46 @@ QUICBlockedFrame::type() const size_t QUICBlockedFrame::size() const { - return 1; + return sizeof(QUICFrameType) + this->_get_offset_field_length(); } void QUICBlockedFrame::store(uint8_t *buf, size_t *len) const { - buf[0] = static_cast(QUICFrameType::BLOCKED); - *len = 1; + size_t n; + uint8_t *p = buf; + + *p = static_cast(QUICFrameType::BLOCKED); + ++p; + QUICTypeUtil::write_QUICOffset(this->_offset, p, &n); + p += n; + + *len = p - buf; } -// -// STREAM_BLOCKED frame -// -QUICStreamBlockedFrame::QUICStreamBlockedFrame(QUICStreamId stream_id) +QUICOffset +QUICBlockedFrame::offset() const { - this->_stream_id = stream_id; + if (this->_buf) { + return QUICTypeUtil::read_QUICOffset(this->_buf + sizeof(QUICFrameType)); + } else { + return this->_offset; + } +} + +size_t +QUICBlockedFrame::_get_offset_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); + } else { + return QUICVariableInt::size(this->_offset); + } } +// +// STREAM_BLOCKED frame +// QUICFrameType QUICStreamBlockedFrame::type() const { @@ -1216,7 +1238,7 @@ QUICStreamBlockedFrame::type() const size_t QUICStreamBlockedFrame::size() const { - return 5; + return sizeof(QUICFrameType) + this->_get_stream_id_field_length() + _get_offset_field_length(); } void @@ -1228,6 +1250,8 @@ QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len) const ++p; QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); p += n; + QUICTypeUtil::write_QUICOffset(this->_offset, p, &n); + p += n; *len = p - buf; } @@ -1236,32 +1260,95 @@ QUICStreamId QUICStreamBlockedFrame::stream_id() const { if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + 1); + return QUICTypeUtil::read_QUICStreamId(this->_buf + sizeof(QUICFrameType)); } else { return this->_stream_id; } } +QUICOffset +QUICStreamBlockedFrame::offset() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICOffset(this->_buf + this->_get_offset_field_offset()); + } else { + return this->_offset; + } +} + +size_t +QUICStreamBlockedFrame::_get_stream_id_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); + } else { + return QUICVariableInt::size(this->_stream_id); + } +} + +size_t +QUICStreamBlockedFrame::_get_offset_field_offset() const +{ + return sizeof(QUICFrameType) + this->_get_stream_id_field_length(); +} + +size_t +QUICStreamBlockedFrame::_get_offset_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_offset_field_offset()); + } else { + return QUICVariableInt::size(this->_stream_id); + } +} + // -// STREAM_ID_NEEDED frame +// STREAM_ID_BLOCKED frame // QUICFrameType -QUICStreamIdNeededFrame::type() const +QUICStreamIdBlockedFrame::type() const { - return QUICFrameType::STREAM_ID_NEEDED; + return QUICFrameType::STREAM_ID_BLOCKED; } size_t -QUICStreamIdNeededFrame::size() const +QUICStreamIdBlockedFrame::size() const { - return 1; + return sizeof(QUICFrameType) + this->_get_stream_id_field_length(); } void -QUICStreamIdNeededFrame::store(uint8_t *buf, size_t *len) const +QUICStreamIdBlockedFrame::store(uint8_t *buf, size_t *len) const { - buf[0] = static_cast(QUICFrameType::STREAM_ID_NEEDED); - *len = 1; + size_t n; + uint8_t *p = buf; + + *p = static_cast(QUICFrameType::STREAM_ID_BLOCKED); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); + p += n; + + *len = p - buf; +} + +QUICStreamId +QUICStreamIdBlockedFrame::stream_id() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICStreamId(this->_buf + sizeof(QUICFrameType)); + } else { + return this->_stream_id; + } +} + +size_t +QUICStreamIdBlockedFrame::_get_stream_id_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); + } else { + return QUICVariableInt::size(this->_stream_id); + } } // @@ -1491,10 +1578,10 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicStreamBlockedFrameAllocator.alloc(); new (frame) QUICStreamBlockedFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); - case QUICFrameType::STREAM_ID_NEEDED: - frame = quicStreamIdNeededFrameAllocator.alloc(); - new (frame) QUICStreamIdNeededFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_id_needed_frame); + case QUICFrameType::STREAM_ID_BLOCKED: + frame = quicStreamIdBlockedFrameAllocator.alloc(); + new (frame) QUICStreamIdBlockedFrame(buf, len); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_id_blocked_frame); case QUICFrameType::NEW_CONNECTION_ID: frame = quicNewConnectionIdFrameAllocator.alloc(); new (frame) QUICNewConnectionIdFrame(buf, len); @@ -1607,21 +1694,29 @@ QUICFrameFactory::create_max_stream_data_frame(QUICStreamId stream_id, uint64_t } std::unique_ptr -QUICFrameFactory::create_blocked_frame() +QUICFrameFactory::create_blocked_frame(QUICOffset offset) { QUICBlockedFrame *frame = quicBlockedFrameAllocator.alloc(); - new (frame) QUICBlockedFrame(); + new (frame) QUICBlockedFrame(offset); return std::unique_ptr(frame, &QUICFrameDeleter::delete_blocked_frame); } std::unique_ptr -QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id) +QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id, QUICOffset offset) { QUICStreamBlockedFrame *frame = quicStreamBlockedFrameAllocator.alloc(); - new (frame) QUICStreamBlockedFrame(stream_id); + new (frame) QUICStreamBlockedFrame(stream_id, offset); return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); } +std::unique_ptr +QUICFrameFactory::create_stream_id_blocked_frame(QUICStreamId stream_id) +{ + QUICStreamIdBlockedFrame *frame = quicStreamIdBlockedFrameAllocator.alloc(); + new (frame) QUICStreamIdBlockedFrame(stream_id); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_id_blocked_frame); +} + std::unique_ptr QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset) { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 6da2a94cf71..319e64ca952 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -390,11 +390,18 @@ class QUICBlockedFrame : public QUICFrame public: QUICBlockedFrame() : QUICFrame() {} QUICBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICBlockedFrame(QUICOffset offset) : _offset(offset) {}; + virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; + + QUICOffset offset() const; + private: - size_t _get_max_data_field_length() const; + size_t _get_offset_field_length() const; + + QUICOffset _offset = 0; }; // @@ -406,27 +413,44 @@ class QUICStreamBlockedFrame : public QUICFrame public: QUICStreamBlockedFrame() : QUICFrame() {} QUICStreamBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamBlockedFrame(QUICStreamId stream_id); + QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o): _stream_id(s), _offset(o) {}; + virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; + QUICStreamId stream_id() const; + QUICOffset offset() const; private: - QUICStreamId _stream_id; + size_t _get_stream_id_field_length() const; + size_t _get_offset_field_offset() const; + size_t _get_offset_field_length() const; + + QUICStreamId _stream_id = 0; + QUICOffset _offset = 0; }; // -// STREAM_ID_NEEDED +// STREAM_ID_BLOCKED // -class QUICStreamIdNeededFrame : public QUICFrame +class QUICStreamIdBlockedFrame : public QUICFrame { public: - QUICStreamIdNeededFrame() : QUICFrame() {} - QUICStreamIdNeededFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICStreamIdBlockedFrame() : QUICFrame() {} + QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICStreamIdBlockedFrame(QUICStreamId s) : _stream_id(s) {} + virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; + + QUICStreamId stream_id() const; + +private: + size_t _get_stream_id_field_length() const; + + QUICStreamId _stream_id = 0; }; // @@ -509,7 +533,7 @@ extern ClassAllocator quicMaxStreamIdFrameAllocator; extern ClassAllocator quicPingFrameAllocator; extern ClassAllocator quicBlockedFrameAllocator; extern ClassAllocator quicStreamBlockedFrameAllocator; -extern ClassAllocator quicStreamIdNeededFrameAllocator; +extern ClassAllocator quicStreamIdBlockedFrameAllocator; extern ClassAllocator quicNewConnectionIdFrameAllocator; extern ClassAllocator quicStopSendingFrameAllocator; extern ClassAllocator quicRetransmissionFrameAllocator; @@ -598,9 +622,9 @@ class QUICFrameDeleter } static void - delete_stream_id_needed_frame(QUICFrame *frame) + delete_stream_id_blocked_frame(QUICFrame *frame) { - quicStreamIdNeededFrameAllocator.free(static_cast(frame)); + quicStreamIdBlockedFrameAllocator.free(static_cast(frame)); } static void @@ -689,12 +713,17 @@ class QUICFrameFactory /* * Creates a BLOCKED frame. */ - static std::unique_ptr create_blocked_frame(); + static std::unique_ptr create_blocked_frame(QUICOffset offset); /* * Creates a STREAM_BLOCKED frame. */ - static std::unique_ptr create_stream_blocked_frame(QUICStreamId stream_id); + static std::unique_ptr create_stream_blocked_frame(QUICStreamId stream_id, QUICOffset offset); + + /* + * Creates a STREAM_ID_BLOCKED frame. + */ + static std::unique_ptr create_stream_id_blocked_frame(QUICStreamId stream_id); /* * Creates a RST_STREAM frame. diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 1680820d17e..030487f6169 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -94,7 +94,7 @@ enum class QUICFrameType : uint8_t { PING, BLOCKED, STREAM_BLOCKED, - STREAM_ID_NEEDED, + STREAM_ID_BLOCKED, NEW_CONNECTION_ID, STOP_SENDING, PONG, diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 565bf6e6023..6ae828f5832 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -39,7 +39,7 @@ TEST_CASE("QUICFrame Type", "[quic]") CHECK(QUICFrame::type(reinterpret_cast("\x07")) == QUICFrameType::PING); CHECK(QUICFrame::type(reinterpret_cast("\x08")) == QUICFrameType::BLOCKED); CHECK(QUICFrame::type(reinterpret_cast("\x09")) == QUICFrameType::STREAM_BLOCKED); - CHECK(QUICFrame::type(reinterpret_cast("\x0a")) == QUICFrameType::STREAM_ID_NEEDED); + CHECK(QUICFrame::type(reinterpret_cast("\x0a")) == QUICFrameType::STREAM_ID_BLOCKED); CHECK(QUICFrame::type(reinterpret_cast("\x0b")) == QUICFrameType::NEW_CONNECTION_ID); CHECK(QUICFrame::type(reinterpret_cast("\x0c")) == QUICFrameType::STOP_SENDING); CHECK(QUICFrame::type(reinterpret_cast("\x0d")) == QUICFrameType::PONG); @@ -665,12 +665,14 @@ TEST_CASE("Load Blocked Frame", "[quic]") { uint8_t buf1[] = { 0x08, // Type + 0x07, // Offset }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::BLOCKED); - CHECK(frame1->size() == 1); + CHECK(frame1->size() == 2); std::shared_ptr blockedStreamFrame1 = std::dynamic_pointer_cast(frame1); CHECK(blockedStreamFrame1 != nullptr); + CHECK(blockedStreamFrame1->offset() == 0x07); } TEST_CASE("Store Blocked Frame", "[quic]") @@ -680,10 +682,11 @@ TEST_CASE("Store Blocked Frame", "[quic]") uint8_t expected[] = { 0x08, // Type + 0x07, // Offset }; - QUICBlockedFrame blockedStreamFrame; + QUICBlockedFrame blockedStreamFrame(0x07); blockedStreamFrame.store(buf, &len); - CHECK(len == 1); + CHECK(len == 2); CHECK(memcmp(buf, expected, len) == 0); } @@ -691,15 +694,17 @@ TEST_CASE("Load StreamBlocked Frame", "[quic]") { uint8_t buf1[] = { 0x09, // Type - 0x01, 0x02, 0x03, 0x04, // Stream ID + 0x81, 0x02, 0x03, 0x04, // Stream ID + 0x07, // Offset }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM_BLOCKED); - CHECK(frame1->size() == 5); + CHECK(frame1->size() == 6); std::shared_ptr streamBlockedFrame1 = std::dynamic_pointer_cast(frame1); CHECK(streamBlockedFrame1 != nullptr); CHECK(streamBlockedFrame1->stream_id() == 0x01020304); + CHECK(streamBlockedFrame1->offset() == 0x07); } TEST_CASE("Store StreamBlocked Frame", "[quic]") @@ -709,38 +714,42 @@ TEST_CASE("Store StreamBlocked Frame", "[quic]") uint8_t expected[] = { 0x09, // Type - 0x01, 0x02, 0x03, 0x04, // Stream ID + 0x81, 0x02, 0x03, 0x04, // Stream ID + 0x07, // Offset }; - QUICStreamBlockedFrame streamBlockedFrame(0x01020304); + QUICStreamBlockedFrame streamBlockedFrame(0x01020304, 0x07); streamBlockedFrame.store(buf, &len); - CHECK(len == 5); + CHECK(len == 6); CHECK(memcmp(buf, expected, len) == 0); } -TEST_CASE("Load StreamIdNeeded Frame", "[quic]") +TEST_CASE("Load StreamIdBlocked Frame", "[quic]") { uint8_t buf1[] = { - 0x0a, // Type + 0x0a, // Type + 0x41, 0x02, // Stream ID }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::STREAM_ID_NEEDED); - CHECK(frame1->size() == 1); - std::shared_ptr streamIdNeededFrame1 = - std::dynamic_pointer_cast(frame1); - CHECK(streamIdNeededFrame1 != nullptr); + CHECK(frame1->type() == QUICFrameType::STREAM_ID_BLOCKED); + CHECK(frame1->size() == 3); + std::shared_ptr streamIdBlockedFrame1 = + std::dynamic_pointer_cast(frame1); + CHECK(streamIdBlockedFrame1 != nullptr); + CHECK(streamIdBlockedFrame1->stream_id() == 0x0102); } -TEST_CASE("Store StreamIdNeeded Frame", "[quic]") +TEST_CASE("Store StreamIdBlocked Frame", "[quic]") { uint8_t buf[65535]; size_t len; uint8_t expected[] = { - 0x0a, // Type + 0x0a, // Type + 0x41, 0x02, // Stream ID }; - QUICStreamIdNeededFrame streamIdNeededStreamFrame; - streamIdNeededStreamFrame.store(buf, &len); - CHECK(len == 1); + QUICStreamIdBlockedFrame streamIdBlockedStreamFrame(0x0102); + streamIdBlockedStreamFrame.store(buf, &len); + CHECK(len == 3); CHECK(memcmp(buf, expected, len) == 0); } diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 7920a7dede1..54af018796b 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -65,13 +65,13 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") CHECK(sm.stream_count() == 4); // STREAM_BLOCKED frames create new streams - std::shared_ptr stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(4); + std::shared_ptr stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(4, 0); sm.handle_frame(stream_blocked_frame); CHECK(sm.stream_count() == 5); // Set local maximum stream id sm.set_max_stream_id(5); - std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_blocked_frame(8); + std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_blocked_frame(8, 0); sm.handle_frame(stream_blocked_frame_x); CHECK(sm.stream_count() == 5); } @@ -113,8 +113,8 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") uint8_t data[1024] = {0}; // Create a stream with STREAM_BLOCKED (== noop) - std::shared_ptr stream_blocked_frame_0 = QUICFrameFactory::create_stream_blocked_frame(0); - std::shared_ptr stream_blocked_frame_1 = QUICFrameFactory::create_stream_blocked_frame(1); + std::shared_ptr stream_blocked_frame_0 = QUICFrameFactory::create_stream_blocked_frame(0, 0); + std::shared_ptr stream_blocked_frame_1 = QUICFrameFactory::create_stream_blocked_frame(1, 0); sm.handle_frame(stream_blocked_frame_0); sm.handle_frame(stream_blocked_frame_1); CHECK(sm.stream_count() == 2); diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index 2bc3e687541..c124a70b11a 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -33,7 +33,7 @@ TEST_CASE("QUICStreamState_Idle", "[quic]") auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); auto max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(0, 0); - auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0); + auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0, 0); // Case1. Send STREAM QUICStreamState ss1; From cf90c5fc28dee4019db42bb29dead2bc0d5e068b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Dec 2017 15:31:31 +0900 Subject: [PATCH 0248/1313] Load local max_stream_data before starting handshake --- iocore/net/QUICNetVConnection.cc | 3 --- iocore/net/quic/QUICStreamManager.cc | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 228134ce4de..83c5a9e62c3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -118,9 +118,6 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) this->_frame_dispatcher->add_handler(this->_stream_manager); this->_frame_dispatcher->add_handler(this->_congestion_controller); this->_frame_dispatcher->add_handler(this->_loss_detector); - - this->_init_flow_control_params(this->_handshake_handler->local_transport_parameters(), - this->_handshake_handler->remote_transport_parameters()); } void diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index a1825ffaf2c..c6527ac2eff 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -25,6 +25,7 @@ #include "QUICApplication.h" #include "QUICTransportParameters.h" +#include "QUICConfig.h" static constexpr char tag[] = "quic_stream_manager"; @@ -216,16 +217,17 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) return nullptr; } // TODO Free the stream somewhere - stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream(); - if (stream_id == STREAM_ID_FOR_HANDSHAKE) { - // XXX rece/send max_stream_data are going to be set by init_flow_control_params() - stream->init(this->_tx, this->_connection_id, stream_id); + stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream(); + uint32_t local_max_stream_data = 0; + uint32_t remote_max_stream_data = 0; + if (this->_local_tp) { + local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA), + remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); } else { - // TODO: check local_tp and remote_tp is initialized - stream->init(this->_tx, this->_connection_id, stream_id, - this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA), - this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA)); + QUICConfig::scoped_config params; + local_max_stream_data = params->initial_max_stream_data(); } + stream->init(this->_tx, this->_connection_id, stream_id, local_max_stream_data, remote_max_stream_data); this->stream_list.push(stream); } From b5f3490db7566330f36c49991ded136841593994 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 14 Dec 2017 15:37:05 +0900 Subject: [PATCH 0249/1313] draft-08: Support new frame format of NEW_CONNECTION_ID and STOP_SENDING --- iocore/net/quic/QUICFrame.cc | 56 +++++++++++++++++++------- iocore/net/quic/QUICFrame.h | 19 +++++++-- iocore/net/quic/test/test_QUICFrame.cc | 21 +++++----- 3 files changed, 68 insertions(+), 28 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 61274852a1b..fd237adca3d 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1355,12 +1355,6 @@ QUICStreamIdBlockedFrame::_get_stream_id_field_length() const // NEW_CONNECTION_ID frame // -QUICNewConnectionIdFrame::QUICNewConnectionIdFrame(uint16_t sequence, QUICConnectionId connection_i, - QUICStatelessResetToken stateless_reset_token) - : _sequence(sequence), _connection_id(connection_i), _stateless_reset_token(stateless_reset_token) -{ -} - QUICFrameType QUICNewConnectionIdFrame::type() const { @@ -1370,7 +1364,7 @@ QUICNewConnectionIdFrame::type() const size_t QUICNewConnectionIdFrame::size() const { - return 11; + return sizeof(QUICFrameType) + this->_get_sequence_field_length() + sizeof(QUICConnectionId) + 16; } void @@ -1380,7 +1374,7 @@ QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len) const uint8_t *p = buf; *p = static_cast(QUICFrameType::NEW_CONNECTION_ID); ++p; - QUICTypeUtil::write_uint_as_nbytes(this->_sequence, 2, p, &n); + QUICTypeUtil::write_QUICVariableInt(this->_sequence, p, &n); p += n; QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, p, &n); p += n; @@ -1390,11 +1384,11 @@ QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } -uint16_t +uint64_t QUICNewConnectionIdFrame::sequence() const { if (this->_buf) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf + 1, 2); + return QUICTypeUtil::read_QUICVariableInt(this->_buf + sizeof(QUICFrameType)); } else { return this->_sequence; } @@ -1404,7 +1398,7 @@ QUICConnectionId QUICNewConnectionIdFrame::connection_id() const { if (this->_buf) { - return QUICTypeUtil::read_QUICConnectionId(this->_buf + 3, 8); + return QUICTypeUtil::read_QUICConnectionId(this->_buf + this->_get_connection_id_field_offset(), 8); } else { return this->_connection_id; } @@ -1414,12 +1408,28 @@ QUICStatelessResetToken QUICNewConnectionIdFrame::stateless_reset_token() const { if (this->_buf) { - return QUICStatelessResetToken(this->_buf + 11); + return QUICStatelessResetToken(this->_buf + this->_get_connection_id_field_offset() + sizeof(QUICConnectionId)); } else { return this->_stateless_reset_token; } } +size_t +QUICNewConnectionIdFrame::_get_sequence_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); + } else { + return QUICVariableInt::size(this->_sequence); + } +} + +size_t +QUICNewConnectionIdFrame::_get_connection_id_field_offset() const +{ + return sizeof(QUICFrameType) + this->_get_sequence_field_length(); +} + // // STOP_SENDING frame // @@ -1438,7 +1448,7 @@ QUICStopSendingFrame::type() const size_t QUICStopSendingFrame::size() const { - return 7; + return sizeof(QUICFrameType) + this->_get_stream_id_field_length() + sizeof(QUICAppErrorCode); } void @@ -1460,7 +1470,7 @@ QUICAppErrorCode QUICStopSendingFrame::error_code() const { if (this->_buf) { - return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + 5); + return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + this->_get_error_code_field_offset()); } else { return this->_error_code; } @@ -1470,12 +1480,28 @@ QUICStreamId QUICStopSendingFrame::stream_id() const { if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + 1); + return QUICTypeUtil::read_QUICStreamId(this->_buf + sizeof(QUICFrameType)); } else { return this->_stream_id; } } +size_t +QUICStopSendingFrame::_get_stream_id_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); + } else { + return QUICVariableInt::size(this->_stream_id); + } +} + +size_t +QUICStopSendingFrame::_get_error_code_field_offset() const +{ + return sizeof(QUICFrameType) + this->_get_stream_id_field_length(); +} + // // QUICRetransmissionFrame // diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 319e64ca952..151d317e99a 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -462,16 +462,22 @@ class QUICNewConnectionIdFrame : public QUICFrame public: QUICNewConnectionIdFrame() : QUICFrame() {} QUICNewConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICNewConnectionIdFrame(uint16_t sequence, QUICConnectionId connection_id, QUICStatelessResetToken stateless_reset_token); + QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId id, QUICStatelessResetToken token) + : _sequence(seq), _connection_id(id), _stateless_reset_token(token) {}; + virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; - uint16_t sequence() const; + + uint64_t sequence() const; QUICConnectionId connection_id() const; QUICStatelessResetToken stateless_reset_token() const; private: - uint16_t _sequence = 0; + size_t _get_sequence_field_length() const; + size_t _get_connection_id_field_offset() const; + + uint64_t _sequence = 0; QUICConnectionId _connection_id = 0; QUICStatelessResetToken _stateless_reset_token; }; @@ -486,15 +492,20 @@ class QUICStopSendingFrame : public QUICFrame QUICStopSendingFrame() : QUICFrame() {} QUICStopSendingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code); + virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; + QUICStreamId stream_id() const; QUICAppErrorCode error_code() const; private: + size_t _get_stream_id_field_length() const; + size_t _get_error_code_field_offset() const; + QUICStreamId _stream_id = 0; - QUICAppErrorCode _error_code; + QUICAppErrorCode _error_code = 0; }; using QUICFrameDeleterFunc = void (*)(QUICFrame *p); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 6ae828f5832..280aae45fa4 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -757,14 +757,14 @@ TEST_CASE("Load NewConnectionId Frame", "[quic]") { uint8_t buf1[] = { 0x0b, // Type - 0x01, 0x02, // Sequence + 0x41, 0x02, // Sequence 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::NEW_CONNECTION_ID); - CHECK(frame1->size() == 11); + CHECK(frame1->size() == 27); std::shared_ptr newConnectionIdFrame1 = std::dynamic_pointer_cast(frame1); CHECK(newConnectionIdFrame1 != nullptr); @@ -775,13 +775,16 @@ TEST_CASE("Load NewConnectionId Frame", "[quic]") TEST_CASE("Store NewConnectionId Frame", "[quic]") { - uint8_t buf[65535]; + uint8_t buf[32]; size_t len; - uint8_t expected[] = {0x0b, // Type - 0x01, 0x02, // Sequence - 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + uint8_t expected[] = { + 0x0b, // Type + 0x41, 0x02, // Sequence + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Stateless Reset Token + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + }; QUICNewConnectionIdFrame newConnectionIdFrame(0x0102, 0x1122334455667788ULL, {expected + 11}); newConnectionIdFrame.store(buf, &len); CHECK(len == 27); @@ -792,7 +795,7 @@ TEST_CASE("Load STOP_SENDING Frame", "[quic]") { uint8_t buf[] = { 0x0c, // Type - 0x12, 0x34, 0x56, 0x78, // Stream ID + 0x92, 0x34, 0x56, 0x78, // Stream ID 0x00, 0x01, // Error Code }; std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); @@ -812,7 +815,7 @@ TEST_CASE("Store STOP_SENDING Frame", "[quic]") uint8_t expected[] = { 0x0c, // Type - 0x12, 0x34, 0x56, 0x78, // Stream ID + 0x92, 0x34, 0x56, 0x78, // Stream ID 0x00, 0x01, // Error Code }; QUICStopSendingFrame stop_sending_frame(0x12345678, static_cast(0x01)); From 3a77c75c4cdc613d287669a5cfd56cacd65f705f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Dec 2017 15:43:53 +0900 Subject: [PATCH 0250/1313] Fix a default transport parameter value for INITIAL_MAX_STREAM_ID_UNI --- iocore/net/quic/QUICConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index e9b8a71422f..6f427c14c77 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -43,7 +43,7 @@ class QUICConfigParams : public ConfigInfo uint32_t _initial_max_data = 100; // in units of 1024 octets uint32_t _initial_max_stream_data = 2048; uint32_t _initial_max_stream_id_bidi = 100; - uint32_t _initial_max_stream_id_uni = 100; + uint32_t _initial_max_stream_id_uni = 102; uint32_t _server_id = 0; }; From 32b5f3d1254a8d0989113a5290c634ec0408385d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Dec 2017 16:16:38 +0900 Subject: [PATCH 0251/1313] Fix a check for connection id presence --- iocore/net/QUICPacketHandler.cc | 10 +++++----- iocore/net/quic/QUICPacket.cc | 4 ++-- iocore/net/quic/QUICTypes.cc | 8 +++++++- iocore/net/quic/QUICTypes.h | 3 ++- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 5c5583ffd44..97ad72742df 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -97,13 +97,13 @@ QUICPacketHandler::_read_connection_id(QUICConnectionId &cid, IOBufferBlock *blo const uint8_t cid_offset = 1; const uint8_t cid_len = 8; - if (QUICTypeUtil::hasLongHeader(buf)) { + if (QUICTypeUtil::has_long_header(buf)) { cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); } else { - if (buf[0] & 0x40) { - cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); - } else { + if (QUICTypeUtil::has_connection_id(buf)) { return false; + } else { + cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); } } @@ -135,7 +135,7 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) con.setRemote(&udpPacket->from.sa); // Send stateless reset if the packet is not a initial packet - if (!QUICTypeUtil::hasLongHeader(reinterpret_cast(block->buf()))) { + if (!QUICTypeUtil::has_long_header(reinterpret_cast(block->buf()))) { QUICStatelessResetToken token; { QUICConfig::scoped_config params; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 01802ba4f29..2473f049cbd 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -64,7 +64,7 @@ QUICPacketHeader::packet_size() const QUICPacketHeader * QUICPacketHeader::load(const uint8_t *buf, size_t len, QUICPacketNumber base) { - if (QUICTypeUtil::hasLongHeader(buf)) { + if (QUICTypeUtil::has_long_header(buf)) { QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); new (long_header) QUICPacketLongHeader(buf, len, base); return long_header; @@ -387,7 +387,7 @@ bool QUICPacketShortHeader::has_connection_id() const { if (this->_buf) { - return (this->_buf[0] & 0x40) == 0; + return QUICTypeUtil::has_connection_id(this->_buf); } else { return this->_has_connection_id; } diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 89d5eca5abe..045b2c9a307 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -30,11 +30,17 @@ ats_unique_malloc(size_t size) } bool -QUICTypeUtil::hasLongHeader(const uint8_t *buf) +QUICTypeUtil::has_long_header(const uint8_t *buf) { return (buf[0] & 0x80) != 0; } +bool +QUICTypeUtil::has_connection_id(const uint8_t *buf) +{ + return (buf[0] & 0x40) == 0; +} + QUICStreamType QUICTypeUtil::detect_stream_type(QUICStreamId id) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 030487f6169..8be628345cc 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -251,7 +251,8 @@ enum class QUICStreamType { CLIENT_BIDI, SERVER_BIDI, CLIENT_UNI, SERVER_UNI, HA class QUICTypeUtil { public: - static bool hasLongHeader(const uint8_t *buf); + static bool has_long_header(const uint8_t *buf); + static bool has_connection_id(const uint8_t *buf); static QUICStreamType detect_stream_type(QUICStreamId id); static QUICConnectionId read_QUICConnectionId(const uint8_t *buf, uint8_t n); From 30bb94126f0e87e5b184307c4cf45cf983d59f54 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Dec 2017 16:30:40 +0900 Subject: [PATCH 0252/1313] Fix the last fix --- iocore/net/QUICPacketHandler.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 97ad72742df..e07dec5d78e 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -101,9 +101,9 @@ QUICPacketHandler::_read_connection_id(QUICConnectionId &cid, IOBufferBlock *blo cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); } else { if (QUICTypeUtil::has_connection_id(buf)) { - return false; - } else { cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); + } else { + return false; } } From 7b398cd194cf6be63d81d7c9eec473fe9dde4d29 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Dec 2017 16:42:44 +0900 Subject: [PATCH 0253/1313] Update tests for KeyGenerator since secrets are updated --- iocore/net/quic/test/test_QUICKeyGenerator.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index 4a3396beba1..4930a1ccb8a 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -57,9 +57,9 @@ TEST_CASE("QUICKeyGenerator", "[quic]") QUICKeyGenerator keygen(QUICKeyGenerator::Context::CLIENT); QUICConnectionId cid = 0x8394c8f03e515708; - uint8_t expected_client_key[] = {0x2e, 0xbd, 0x78, 0x00, 0xdb, 0xed, 0x20, 0x10, - 0xe5, 0xa2, 0x1c, 0x4a, 0xd2, 0x4b, 0x4e, 0xc3}; - uint8_t expected_client_iv[] = {0x55, 0x44, 0x0d, 0x5f, 0xf7, 0x50, 0x3d, 0xe4, 0x99, 0x7b, 0xfd, 0x6b}; + uint8_t expected_client_key[] = {0x9e, 0xdc, 0x91, 0xd5, 0x51, 0x8c, 0x1e, 0x6b, + 0x2f, 0x80, 0x2b, 0xd1, 0xc8, 0xad, 0x59, 0x23}; + uint8_t expected_client_iv[] = {0x78, 0xc4, 0x90, 0xe2, 0xe4, 0x22, 0x62, 0x0b, 0x4e, 0xc1, 0xce, 0xc3}; std::unique_ptr actual_km = keygen.generate(cid); @@ -74,9 +74,9 @@ TEST_CASE("QUICKeyGenerator", "[quic]") QUICKeyGenerator keygen(QUICKeyGenerator::Context::SERVER); QUICConnectionId cid = 0x8394c8f03e515708; - uint8_t expected_server_key[] = {0xc8, 0xea, 0x1b, 0xc1, 0x71, 0xe5, 0x2b, 0xae, - 0x71, 0xfb, 0x78, 0x39, 0x52, 0xc7, 0xb8, 0xfc}; - uint8_t expected_server_iv[] = {0x57, 0x82, 0x3b, 0x85, 0x2c, 0x7e, 0xf9, 0xe3, 0x80, 0x2b, 0x69, 0x0b}; + uint8_t expected_server_key[] = {0xa2, 0xaa, 0x67, 0xd4, 0x32, 0x13, 0xba, 0x8d, + 0x55, 0xf5, 0x76, 0x84, 0xb7, 0x1c, 0x0f, 0xc0}; + uint8_t expected_server_iv[] = {0xa2, 0x6a, 0xa2, 0x24, 0x5c, 0x4f, 0x76, 0x24, 0xa9, 0x5b, 0x0a, 0xbd}; std::unique_ptr actual_km = keygen.generate(cid); From 5b9acb9618f5c54e6d34a531374edee19d702e6f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Dec 2017 11:20:34 +0900 Subject: [PATCH 0254/1313] draft-08: Support new ACK frame format --- iocore/net/quic/QUICFrame.cc | 307 ++++++++++-------- iocore/net/quic/QUICFrame.h | 101 +++--- iocore/net/quic/QUICLossDetector.cc | 2 +- .../net/quic/test/test_QUICAckFrameCreator.cc | 10 +- iocore/net/quic/test/test_QUICFrame.cc | 138 +++++--- 5 files changed, 300 insertions(+), 258 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index fd237adca3d..5160763c442 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -327,8 +327,7 @@ void QUICAckFrame::reset(const uint8_t *buf, size_t len) { QUICFrame::reset(buf, len); - this->_ack_block_section = - new AckBlockSection(buf + this->_get_ack_block_section_offset(), this->num_blocks(), this->_get_ack_block_length()); + this->_ack_block_section = new AckBlockSection(buf + this->_get_ack_block_section_offset(), this->ack_block_count()); } QUICFrameType @@ -340,104 +339,62 @@ QUICAckFrame::type() const size_t QUICAckFrame::size() const { - if (this->_buf) { - return this->_get_ack_block_section_offset() + this->ack_block_section()->size(); - } else { - // TODO Not implemented - return 0; - } + return this->_get_ack_block_section_offset() + this->_ack_block_section->size(); } void QUICAckFrame::store(uint8_t *buf, size_t *len) const { - size_t n; uint8_t *p = buf; + size_t n; + *p = static_cast(QUICFrameType::ACK); + ++p; - // Build Frame Type: "101NLLMM" - buf[0] = static_cast(QUICFrameType::ACK); - p += 1; - - // "N" of "101NLLMM" - if (this->_ack_block_section->count() > 0) { - buf[0] += 0x10; - *p = this->_ack_block_section->count(); - p += 1; - } - - // "LL" of "101NLLMM" - if (this->_largest_acknowledged <= 0xff) { - QUICTypeUtil::write_uint_as_nbytes(this->_largest_acknowledged, 1, p, &n); - } else if (this->_largest_acknowledged <= 0xffff) { - buf[0] += 0x01 << 2; - QUICTypeUtil::write_uint_as_nbytes(this->_largest_acknowledged, 2, p, &n); - } else if (this->_largest_acknowledged <= 0xffffffff) { - buf[0] += 0x02 << 2; - QUICTypeUtil::write_uint_as_nbytes(this->_largest_acknowledged, 4, p, &n); - } else { - buf[0] += 0x03 << 2; - QUICTypeUtil::write_uint_as_nbytes(this->_largest_acknowledged, 8, p, &n); - } + QUICTypeUtil::write_QUICVariableInt(this->_largest_acknowledged, p, &n); p += n; - - QUICTypeUtil::write_uint_as_nbytes(this->_ack_delay, 2, p, &n); + QUICTypeUtil::write_QUICVariableInt(this->_ack_delay, p, &n); + p += n; + QUICTypeUtil::write_QUICVariableInt(this->ack_block_count(), p, &n); p += n; - - // "MM" of "101NLLMM" - // use 32 bit length for now - // TODO The length should be returned by ackBlockSection - buf[0] += 0x02; this->_ack_block_section->store(p, &n); p += n; *len = p - buf; -} -uint8_t -QUICAckFrame::num_blocks() const -{ - if (this->has_ack_blocks()) { - if (this->_buf) { - return this->_buf[1]; - } else { - return this->_ack_block_section->count(); - } - } else { - return 0; - } + return; } QUICPacketNumber QUICAckFrame::largest_acknowledged() const { if (this->_buf) { - return QUICTypeUtil::read_QUICPacketNumber(this->_buf + this->_get_largest_acknowledged_offset(), - this->_get_largest_acknowledged_length()); + uint64_t largest_acknowledged; + size_t encoded_len; + QUICVariableInt::decode(largest_acknowledged, encoded_len, this->_buf + this->_get_largest_acknowledged_offset(), + this->_len - this->_get_largest_acknowledged_offset()); + return largest_acknowledged; } else { return this->_largest_acknowledged; } } -uint16_t +uint64_t QUICAckFrame::ack_delay() const { if (this->_buf) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf + this->_get_ack_delay_offset(), 2); + return QUICTypeUtil::read_QUICVariableInt(this->_buf + this->_get_ack_delay_offset()); } else { return this->_ack_delay; } } -/** - * N of 101NLLMM - */ -bool -QUICAckFrame::has_ack_blocks() const +uint64_t +QUICAckFrame::ack_block_count() const { if (this->_buf) { - return (this->_buf[0] & 0x10) != 0; + return QUICTypeUtil::read_QUICVariableInt(this->_buf + this->_get_ack_block_count_offset()); } else { - return this->_ack_block_section->count() != 0; + return this->_ack_block_section->count(); } } @@ -453,101 +410,123 @@ QUICAckFrame::ack_block_section() const return this->_ack_block_section; } -/** - * LL of 101NLLMM - */ +size_t +QUICAckFrame::_get_largest_acknowledged_offset() const +{ + return sizeof(QUICFrameType); +} + size_t QUICAckFrame::_get_largest_acknowledged_length() const { - /* - * 0 -> 1 byte - * 1 -> 2 byte - * 2 -> 4 byte - * 3 -> 8 byte - */ - int n = (this->_buf[0] & 0x0c) >> 2; - return 0x01 << n; + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_largest_acknowledged_offset()); + } else { + return QUICVariableInt::size(this->_largest_acknowledged); + } } size_t -QUICAckFrame::_get_largest_acknowledged_offset() const +QUICAckFrame::_get_ack_delay_offset() const { - if (this->has_ack_blocks()) { - return 2; + return this->_get_largest_acknowledged_offset() + this->_get_largest_acknowledged_length(); +} + +size_t +QUICAckFrame::_get_ack_delay_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_ack_delay_offset()); } else { - return 1; + return QUICVariableInt::size(this->_ack_delay); } } -/** - * MM of 101NLLMM - */ size_t -QUICAckFrame::_get_ack_block_length() const +QUICAckFrame::_get_ack_block_count_offset() const { - /* - * 0 -> 1 byte - * 1 -> 2 byte - * 2 -> 4 byte - * 3 -> 8 byte - */ - int n = this->_buf[0] & 0x03; - return 0x01 << n; + return this->_get_ack_delay_offset() + this->_get_ack_delay_length(); } size_t -QUICAckFrame::_get_ack_delay_offset() const +QUICAckFrame::_get_ack_block_count_length() const { - return this->_get_largest_acknowledged_offset() + this->_get_largest_acknowledged_length(); + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_ack_block_count_offset()); + } else { + return QUICVariableInt::size(this->ack_block_count()); + } } size_t QUICAckFrame::_get_ack_block_section_offset() const { - return this->_get_ack_delay_offset() + 2; + return this->_get_ack_block_count_offset() + this->_get_ack_block_count_length(); } -QUICAckFrame::AckBlockSection::AckBlockSection(const uint8_t *buf, uint8_t num_blocks, uint8_t ack_block_length) +// +// QUICAckFrame::AckBlock +// +uint64_t +QUICAckFrame::AckBlock::gap() const { - this->_buf = buf; - this->_num_blocks = num_blocks; - this->_ack_block_length = ack_block_length; + if (this->_buf) { + return QUICTypeUtil::read_QUICVariableInt(this->_buf); + } else { + return this->_gap; + } } -QUICAckFrame::AckBlockSection::AckBlockSection(uint64_t first_ack_block_length) +uint64_t +QUICAckFrame::AckBlock::length() const { - this->_first_ack_block_length = first_ack_block_length; + if (this->_buf) { + return QUICTypeUtil::read_QUICVariableInt(this->_buf + this->_get_gap_size()); + } else { + return this->_length; + } } -QUICAckFrame::AckBlock::AckBlock(const uint8_t *buf, uint8_t ack_block_length) +size_t +QUICAckFrame::AckBlock::size() const { - this->_gap = buf[0]; - this->_length = QUICTypeUtil::read_nbytes_as_uint(buf + 1, ack_block_length); + return this->_get_gap_size() + this->_get_length_size(); } -QUICAckFrame::AckBlock::AckBlock(uint8_t gap, uint64_t length) +const uint8_t * +QUICAckFrame::AckBlock::buf() const { - this->_gap = gap; - this->_length = length; + return this->_buf; } -uint8_t -QUICAckFrame::AckBlock::gap() const +size_t +QUICAckFrame::AckBlock::_get_gap_size() const { - return this->_gap; + if (this->_buf) { + return QUICVariableInt::size(this->_buf); + } else { + return QUICVariableInt::size(this->_gap); + } } -uint64_t -QUICAckFrame::AckBlock::length() const +size_t +QUICAckFrame::AckBlock::_get_length_size() const { - return this->_length; + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_gap_size()); + } else { + return QUICVariableInt::size(this->_gap); + } } +// +// QUICAckFrame::AckBlockSection +// uint8_t QUICAckFrame::AckBlockSection::count() const { if (this->_buf) { - return this->_num_blocks; + return this->_ack_block_count; } else { return this->_ack_blocks.size(); } @@ -556,27 +535,33 @@ QUICAckFrame::AckBlockSection::count() const size_t QUICAckFrame::AckBlockSection::size() const { - if (this->_buf) { - return this->_ack_block_length + (this->_ack_block_length + 1) * this->_num_blocks; - } else { - // TODO Which block length should we use? - return 48 + (48 + 1) * this->_ack_blocks.size(); + size_t n = 0; + + n += this->_get_first_ack_block_length_size(); + + for (auto &&block : *this) { + n += block.size(); } + + return n; } void QUICAckFrame::AckBlockSection::store(uint8_t *buf, size_t *len) const { + size_t n; uint8_t *p = buf; - size_t dummy; - QUICTypeUtil::write_uint_as_nbytes(this->_first_ack_block_length, 4, buf, &dummy); - p += 4; + + QUICTypeUtil::write_QUICVariableInt(this->_first_ack_block_length, p, &n); + p += n; + for (auto &&block : *this) { - p[0] = block.gap(); - p += 1; - QUICTypeUtil::write_uint_as_nbytes(block.length(), 4, buf, &dummy); - p += 4; + QUICTypeUtil::write_QUICVariableInt(block.gap(), p, &n); + p += n; + QUICTypeUtil::write_QUICVariableInt(block.length(), p, &n); + p += n; } + *len = p - buf; } @@ -584,7 +569,7 @@ uint64_t QUICAckFrame::AckBlockSection::first_ack_block_length() const { if (this->_buf) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf, this->_ack_block_length); + return QUICTypeUtil::read_QUICVariableInt(this->_buf); } else { return this->_first_ack_block_length; } @@ -600,7 +585,7 @@ QUICAckFrame::AckBlockSection::const_iterator QUICAckFrame::AckBlockSection::begin() const { if (this->_buf) { - return const_iterator(0, this->_buf, this->_num_blocks, this->_ack_block_length); + return const_iterator(0, this->_buf + this->_get_first_ack_block_length_size(), this->_ack_block_count); } else { return const_iterator(0, &this->_ack_blocks); } @@ -610,39 +595,79 @@ QUICAckFrame::AckBlockSection::const_iterator QUICAckFrame::AckBlockSection::end() const { if (this->_buf) { - return const_iterator(this->_num_blocks, this->_buf, this->_num_blocks, this->_ack_block_length); + return const_iterator(this->_ack_block_count, this->_buf, this->_ack_block_count); } else { return const_iterator(this->_ack_blocks.size(), &this->_ack_blocks); } } -QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, const uint8_t *buf, uint8_t num_blocks, - uint8_t ack_block_length) +size_t +QUICAckFrame::AckBlockSection::_get_first_ack_block_length_size() const { - this->_index = index; - this->_buf = buf; - this->_ack_block_length = ack_block_length; - if (index < num_blocks) { - this->_current_block = AckBlock(buf + ack_block_length + (1 + ack_block_length) * index, ack_block_length); + if (this->_buf) { + return QUICVariableInt::size(this->_buf); } else { - this->_current_block = {static_cast(0), 0ULL}; + return QUICVariableInt::size(this->_first_ack_block_length); } } -QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, const std::vector *ack_block) +// +// QUICAckFrame::AckBlockSection::const_iterator +// +QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, const uint8_t *buf, uint8_t ack_block_count) + : _index(index), _buf(buf) +{ + if (index == 0) { + this->_current_block = AckBlock(this->_buf); + } else if (index < ack_block_count) { + this->_current_block = AckBlock(this->_current_block.buf() + this->_current_block.size()); + } else { + this->_current_block = {UINT64_C(0), UINT64_C(0)}; + } +} + +QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, const std::vector *ack_blocks) + : _index(index), _ack_blocks(ack_blocks) { - this->_index = index; - this->_buf = nullptr; - this->_ack_blocks = ack_block; if (this->_ack_blocks->size()) { if (this->_ack_blocks->size() == this->_index) { - this->_current_block = {static_cast(0), 0ULL}; + this->_current_block = {UINT64_C(0), UINT64_C(0)}; } else { this->_current_block = this->_ack_blocks->at(this->_index); } } } +// FIXME: something wrong with clang-format? +const QUICAckFrame::AckBlock &QUICAckFrame::AckBlockSection::const_iterator::operator++() +{ + ++(this->_index); + + if (this->_buf) { + this->_current_block = AckBlock(this->_current_block.buf() + this->_current_block.size()); + } else { + if (this->_ack_blocks->size() == this->_index) { + this->_current_block = {UINT64_C(0), UINT64_C(0)}; + } else { + this->_current_block = this->_ack_blocks->at(this->_index); + } + } + + return this->_current_block; +} + +const bool +QUICAckFrame::AckBlockSection::const_iterator::operator!=(const const_iterator &ite) const +{ + return this->_index != ite._index; +} + +const bool +QUICAckFrame::AckBlockSection::const_iterator::operator==(const const_iterator &ite) const +{ + return this->_index == ite._index; +} + // // RST_STREAM frame // diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 151d317e99a..74e03a8b5e8 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -99,15 +99,23 @@ class QUICAckFrame : public QUICFrame class AckBlock { public: - AckBlock(const uint8_t *buf, uint8_t ack_block_length); - AckBlock(uint8_t gap, uint64_t length); - uint8_t gap() const; + AckBlock(const uint8_t *b) : _buf(b) {} + AckBlock(uint64_t g, uint64_t l) : _gap(g), _length(l) {} + + uint64_t gap() const; uint64_t length() const; + size_t size() const; + const uint8_t *buf() const; + LINK(QUICAckFrame::AckBlock, link); private: - uint8_t _gap = 0; - uint64_t _length = 0; + size_t _get_gap_size() const; + size_t _get_length_size() const; + + const uint8_t *_buf = nullptr; + uint64_t _gap = 0; + uint64_t _length = 0; }; class AckBlockSection @@ -116,51 +124,24 @@ class QUICAckFrame : public QUICFrame class const_iterator : public std::iterator { public: - const_iterator(uint8_t index, const uint8_t *buf, uint8_t num_blocks, uint8_t ack_block_length); + const_iterator(uint8_t index, const uint8_t *buf, uint8_t ack_block_count); const_iterator(uint8_t index, const std::vector *ack_blocks); const QUICAckFrame::AckBlock &operator*() const { return this->_current_block; }; const QUICAckFrame::AckBlock *operator->() const { return &this->_current_block; }; - const QUICAckFrame::AckBlock &operator++() - { - ++(this->_index); - - if (this->_buf) { - this->_current_block = - AckBlock(this->_buf + this->_ack_block_length + (1 + this->_ack_block_length) * this->_index, this->_ack_block_length); - } else { - if (this->_ack_blocks->size() == this->_index) { - this->_current_block = {static_cast(0), 0ULL}; - } else { - this->_current_block = this->_ack_blocks->at(this->_index); - } - } - - return this->_current_block; - }; - - const bool - operator!=(const const_iterator &ite) const - { - return this->_index != ite._index; - }; - - const bool - operator==(const const_iterator &ite) const - { - return this->_index == ite._index; - }; + const QUICAckFrame::AckBlock &operator++(); + const bool operator!=(const const_iterator &ite) const; + const bool operator==(const const_iterator &ite) const; private: - uint8_t _index; - const uint8_t *_buf; - uint8_t _ack_block_length; + uint8_t _index = 0; + const uint8_t *_buf = nullptr; + QUICAckFrame::AckBlock _current_block = {UINT64_C(0), UINT64_C(0)}; const std::vector *_ack_blocks = nullptr; - QUICAckFrame::AckBlock _current_block = {static_cast(0), 0ULL}; }; - AckBlockSection(uint64_t first_ack_block_length); - AckBlockSection(const uint8_t *buf, uint8_t num_blocks, uint8_t ack_block_length); + AckBlockSection(uint64_t first_ack_block_length) : _first_ack_block_length(first_ack_block_length) {} + AckBlockSection(const uint8_t *buf, uint8_t ack_block_count) : _buf(buf), _ack_block_count(ack_block_count) {} uint8_t count() const; size_t size() const; void store(uint8_t *buf, size_t *len) const; @@ -170,36 +151,41 @@ class QUICAckFrame : public QUICFrame const_iterator end() const; private: + size_t _get_first_ack_block_length_size() const; + const uint8_t *_buf = nullptr; uint64_t _first_ack_block_length = 0; - uint8_t _num_blocks = 0; - uint8_t _ack_block_length = 0; + uint8_t _ack_block_count = 0; std::vector _ack_blocks; }; QUICAckFrame() : QUICFrame() {} QUICAckFrame(const uint8_t *buf, size_t len); QUICAckFrame(QUICPacketNumber largest_acknowledged, uint16_t ack_delay, uint64_t first_ack_block_length); + virtual ~QUICAckFrame(); virtual void reset(const uint8_t *buf, size_t len) override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; - uint8_t num_blocks() const; + QUICPacketNumber largest_acknowledged() const; - uint16_t ack_delay() const; + uint64_t ack_delay() const; + uint64_t ack_block_count() const; const AckBlockSection *ack_block_section() const; AckBlockSection *ack_block_section(); - bool has_ack_blocks() const; private: size_t _get_largest_acknowledged_offset() const; size_t _get_largest_acknowledged_length() const; - size_t _get_ack_block_length() const; size_t _get_ack_delay_offset() const; + size_t _get_ack_delay_length() const; + size_t _get_ack_block_count_offset() const; + size_t _get_ack_block_count_length() const; size_t _get_ack_block_section_offset() const; + QUICPacketNumber _largest_acknowledged = 0; - uint16_t _ack_delay = 0; + uint64_t _ack_delay = 0; AckBlockSection *_ack_block_section = nullptr; }; @@ -228,7 +214,7 @@ class QUICRstStreamFrame : public QUICFrame size_t _get_error_code_field_offset() const; size_t _get_final_offset_field_offset() const; size_t _get_final_offset_field_length() const; - + QUICStreamId _stream_id = 0; QUICAppErrorCode _error_code = 0; QUICOffset _final_offset = 0; @@ -281,7 +267,7 @@ class QUICConnectionCloseFrame : public QUICFrame size_t _get_reason_phrase_length_field_offset() const; size_t _get_reason_phrase_length_field_length() const; size_t _get_reason_phrase_field_offset() const; - + QUICTransErrorCode _error_code; uint64_t _reason_phrase_length = 0; const char *_reason_phrase = nullptr; @@ -390,8 +376,8 @@ class QUICBlockedFrame : public QUICFrame public: QUICBlockedFrame() : QUICFrame() {} QUICBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICBlockedFrame(QUICOffset offset) : _offset(offset) {}; - + QUICBlockedFrame(QUICOffset offset) : _offset(offset){}; + virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -413,7 +399,7 @@ class QUICStreamBlockedFrame : public QUICFrame public: QUICStreamBlockedFrame() : QUICFrame() {} QUICStreamBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o): _stream_id(s), _offset(o) {}; + QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o) : _stream_id(s), _offset(o){}; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -428,7 +414,7 @@ class QUICStreamBlockedFrame : public QUICFrame size_t _get_offset_field_length() const; QUICStreamId _stream_id = 0; - QUICOffset _offset = 0; + QUICOffset _offset = 0; }; // @@ -463,7 +449,7 @@ class QUICNewConnectionIdFrame : public QUICFrame QUICNewConnectionIdFrame() : QUICFrame() {} QUICNewConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId id, QUICStatelessResetToken token) - : _sequence(seq), _connection_id(id), _stateless_reset_token(token) {}; + : _sequence(seq), _connection_id(id), _stateless_reset_token(token){}; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -504,7 +490,7 @@ class QUICStopSendingFrame : public QUICFrame size_t _get_stream_id_field_length() const; size_t _get_error_code_field_offset() const; - QUICStreamId _stream_id = 0; + QUICStreamId _stream_id = 0; QUICAppErrorCode _error_code = 0; }; @@ -729,7 +715,8 @@ class QUICFrameFactory /* * Creates a STREAM_BLOCKED frame. */ - static std::unique_ptr create_stream_blocked_frame(QUICStreamId stream_id, QUICOffset offset); + static std::unique_ptr create_stream_blocked_frame(QUICStreamId stream_id, + QUICOffset offset); /* * Creates a STREAM_ID_BLOCKED frame. diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index d735ae4fa7e..45896b043f8 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -194,7 +194,7 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac if (pi != this->_sent_packets.end()) { this->_latest_rtt = Thread::get_hrtime() - pi->second->time; // _latest_rtt is nanosecond but ack_frame->ack_delay is millisecond - if (this->_latest_rtt > HRTIME_MSECONDS(ack_frame->ack_delay())) { + if (this->_latest_rtt > static_cast(HRTIME_MSECONDS(ack_frame->ack_delay()))) { this->_latest_rtt -= HRTIME_MSECONDS(ack_frame->ack_delay()); } this->_update_rtt(this->_latest_rtt); diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 09e742d9748..6153460c424 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -39,7 +39,7 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") creator.update(1, true); frame = creator.create(); CHECK(frame != nullptr); - CHECK(frame->num_blocks() == 0); + CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 1); CHECK(frame->ack_block_section()->first_ack_block_length() == 0); @@ -53,7 +53,7 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") creator.update(4, true); frame = creator.create(); CHECK(frame != nullptr); - CHECK(frame->num_blocks() == 0); + CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 5); CHECK(frame->ack_block_section()->first_ack_block_length() == 3); @@ -63,7 +63,7 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") creator.update(10, true); frame = creator.create(); CHECK(frame != nullptr); - CHECK(frame->num_blocks() == 1); + CHECK(frame->ack_block_count() == 1); CHECK(frame->largest_acknowledged() == 10); CHECK(frame->ack_block_section()->first_ack_block_length() == 0); CHECK(frame->ack_block_section()->begin()->gap() == 1); @@ -86,7 +86,7 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") frame = creator.create(); CHECK(frame != nullptr); - CHECK(frame->num_blocks() == 2); + CHECK(frame->ack_block_count() == 2); CHECK(frame->largest_acknowledged() == 9); CHECK(frame->ack_block_section()->first_ack_block_length() == 1); CHECK(frame->ack_block_section()->begin()->gap() == 0); @@ -98,7 +98,7 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") creator.update(4, true); frame = creator.create(); CHECK(frame != nullptr); - CHECK(frame->num_blocks() == 1); + CHECK(frame->ack_block_count() == 1); CHECK(frame->largest_acknowledged() == 7); CHECK(frame->ack_block_section()->first_ack_block_length() == 0); CHECK(frame->ack_block_section()->begin()->gap() == 1); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 280aae45fa4..f9daf5f43bf 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -267,98 +267,128 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") { uint8_t buf1[] = { - 0xA0, // 101NLLMM + 0x0e, // Type 0x12, // Largest Acknowledged - 0x34, 0x56, // Ack Delay + 0x74, 0x56, // Ack Delay + 0x00, // Ack Block Count 0x00, // Ack Block Section }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); - CHECK(frame1->size() == 5); + CHECK(frame1->size() == 6); std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); CHECK(ackFrame1 != nullptr); - CHECK(ackFrame1->has_ack_blocks() == false); + CHECK(ackFrame1->ack_block_count() == 0); CHECK(ackFrame1->largest_acknowledged() == 0x12); CHECK(ackFrame1->ack_delay() == 0x3456); } + SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") + { + uint8_t buf1[] = { + 0x0e, // Type + 0x80, 0x00, 0x00, 0x01, // Largest Acknowledged + 0x41, 0x71, // Ack Delay + 0x00, // Ack Block Count + 0x80, 0x00, 0x00, 0x01, // Ack Block Section (First ACK Block Length) + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::ACK); + CHECK(frame1->size() == 12); + + std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(ackFrame1 != nullptr); + CHECK(ackFrame1->largest_acknowledged() == 0x01); + CHECK(ackFrame1->ack_delay() == 0x0171); + CHECK(ackFrame1->ack_block_count() == 0); + + const QUICAckFrame::AckBlockSection *section = ackFrame1->ack_block_section(); + CHECK(section->first_ack_block_length() == 0x01); + } + SECTION("2 Ack Block, 8 bit packet number length, 8 bit block length") { uint8_t buf1[] = { - 0xB0, // 101NLLMM - 0x02, // Num Blocks - 0x12, // Largest Acknowledged - 0x34, 0x56, // Ack Delay - 0x01, // Ack Block Section (First ACK Block Length) - 0x02, // Ack Block Section (Gap 1) - 0x03, // Ack Block Section (ACK Block 1 Length) - 0x04, // Ack Block Section (Gap 2) - 0x05, // Ack Block Section (ACK Block 2 Length) + 0x0e, // Type + 0x12, // Largest Acknowledged + 0x74, 0x56, // Ack Delay + 0x02, // Ack Block Count + 0x01, // Ack Block Section (First ACK Block Length) + 0x02, // Ack Block Section (Gap 1) + 0x43, 0x04, // Ack Block Section (ACK Block 1 Length) + 0x85, 0x06, 0x07, 0x08, // Ack Block Section (Gap 2) + 0xc9, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, // Ack Block Section (ACK Block 2 Length) }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); - CHECK(frame1->size() == 10); + CHECK(frame1->size() == 21); std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); CHECK(ackFrame1 != nullptr); CHECK(ackFrame1->largest_acknowledged() == 0x12); CHECK(ackFrame1->ack_delay() == 0x3456); - CHECK(ackFrame1->num_blocks() == 2); - CHECK(ackFrame1->has_ack_blocks() == true); + CHECK(ackFrame1->ack_block_count() == 2); + const QUICAckFrame::AckBlockSection *section = ackFrame1->ack_block_section(); CHECK(section->first_ack_block_length() == 0x01); auto ite = section->begin(); CHECK(ite != section->end()); - CHECK(ite->gap() == 2); - CHECK(ite->length() == 3); + CHECK(ite->gap() == 0x02); + CHECK(ite->length() == 0x0304); ++ite; CHECK(ite != section->end()); - CHECK(ite->gap() == 4); - CHECK(ite->length() == 5); + CHECK(ite->gap() == 0x05060708); + CHECK(ite->length() == 0x090a0b0c0d0e0f10); ++ite; CHECK(ite == section->end()); } } -TEST_CASE("Load Ack Frame 2", "[quic]") +TEST_CASE("Store Ack Frame", "[quic]") { - // 0 Ack Block, 8 bit packet number length, 8 bit block length - uint8_t buf1[] = { - 0xAA, // 101NLLMM '0b10101010' { N: 0, LL: 10, MM:10 } - 0x00, 0x00, 0x00, 0x01, // Largest Acknowledged - 0x01, 0x71, // Ack Delay - 0x00, 0x00, 0x00, 0x01, // ACK Block - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::ACK); - CHECK(frame1->size() == 11); - std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(ackFrame1 != nullptr); - CHECK(ackFrame1->has_ack_blocks() == false); - CHECK(ackFrame1->largest_acknowledged() == 0x01); - CHECK(ackFrame1->ack_delay() == 0x0171); + SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") + { + uint8_t buf[32] = {0}; + size_t len; - // TODO: 1 Ack Block -} + uint8_t expected[] = { + 0x0e, // Type + 0x12, // Largest Acknowledged + 0x74, 0x56, // Ack Delay + 0x00, // Ack Block Count + 0x00, // Ack Block Section + }; + QUICAckFrame ackFrame(0x12, 0x3456, 0); + ackFrame.store(buf, &len); + CHECK(len == 6); + CHECK(memcmp(buf, expected, len) == 0); + } -TEST_CASE("Store Ack Frame", "[quic]") -{ - uint8_t buf[65535]; - size_t len; + SECTION("2 Ack Block, 8 bit packet number length, 8 bit block length") + { + uint8_t buf[32] = {0}; + size_t len; - // 0 Ack Block, 8 bit packet number length, 8 bit block length - uint8_t expected[] = { - 0xA2, // 101NLLMM - 0x12, // Largest Acknowledged - 0x34, 0x56, // Ack Delay - 0x00, 0x00, 0x00, 0x00, // Ack Block Section - }; - QUICAckFrame ackFrame(0x12, 0x3456, 0); - ackFrame.store(buf, &len); - CHECK(len == 8); - CHECK(memcmp(buf, expected, len) == 0); + uint8_t expected[] = { + 0x0e, // Type + 0x12, // Largest Acknowledged + 0x74, 0x56, // Ack Delay + 0x02, // Ack Block Count + 0x01, // Ack Block Section (First ACK Block Length) + 0x02, // Ack Block Section (Gap 1) + 0x43, 0x04, // Ack Block Section (ACK Block 1 Length) + 0x85, 0x06, 0x07, 0x08, // Ack Block Section (Gap 2) + 0xc9, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, // Ack Block Section (ACK Block 2 Length) + }; + QUICAckFrame ackFrame(0x12, 0x3456, 0x01); + QUICAckFrame::AckBlockSection *section = ackFrame.ack_block_section(); + section->add_ack_block({0x02, 0x0304}); + section->add_ack_block({0x05060708, 0x090a0b0c0d0e0f10}); - // TODO: Add ack blocks + ackFrame.store(buf, &len); + CHECK(len == 21); + CHECK(memcmp(buf, expected, len) == 0); + } } TEST_CASE("Load RST_STREAM Frame", "[quic]") From bb65d674656b2ca1172251753f3272d6a2c02590 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 15 Dec 2017 11:41:04 +0900 Subject: [PATCH 0255/1313] Validate transport parameters --- iocore/net/quic/QUICHandshake.cc | 7 +- iocore/net/quic/QUICTransportParameters.cc | 144 +++++++++++++++++- iocore/net/quic/QUICTransportParameters.h | 3 + .../quic/test/test_QUICTransportParameters.cc | 49 +++--- 4 files changed, 172 insertions(+), 31 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 9bbc0bb44e6..f04a4efa47a 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -294,13 +294,14 @@ QUICHandshake::_load_local_transport_parameters(QUICVersion negotiated_version) tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi()); - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni()); tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); + // These two are MUSTs if this is a server tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), 16); - tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); + // MAYs + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni()); // this->_local_transport_parameters.add(QUICTransportParameterId::OMIT_CONNECTION_ID, {}); // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); this->_local_transport_parameters = std::unique_ptr(tp); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 0eeb24a192e..b2e61dcb566 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -118,7 +118,73 @@ QUICTransportParameters::_load(const uint8_t *buf, size_t len) } } - this->_valid = !has_error; + if (has_error) { + this->_valid = false; + return; + } + + // Validate parameters + this->_valid = (this->_validate_parameters() == 0); +} + +int +QUICTransportParameters::_validate_parameters() const +{ + decltype(this->_parameters)::const_iterator ite; + + // MUSTs + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA)) != this->_parameters.end()) { + if (ite->second->len() != 4) { + return -1; + } + } else { + return -1; + } + + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_DATA)) != this->_parameters.end()) { + if (ite->second->len() != 4) { + return -1; + } + } else { + return -1; + } + + if ((ite = this->_parameters.find(QUICTransportParameterId::IDLE_TIMEOUT)) != this->_parameters.end()) { + if (ite->second->len() != 2) { + return -1; + } + if (QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 600) { + return -1; + } + } else { + return -1; + } + + // MAYs + if ((ite = this->_parameters.find(QUICTransportParameterId::OMIT_CONNECTION_ID)) != this->_parameters.end()) { + if (ite->second->len() != 0) { + return -1; + } + } + + if ((ite = this->_parameters.find(QUICTransportParameterId::MAX_PACKET_SIZE)) != this->_parameters.end()) { + if (ite->second->len() != 2) { + return -1; + } + if (QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) < 1200) { + return -1; + } + } + + if ((ite = this->_parameters.find(QUICTransportParameterId::ACK_DELAY_EXPONENT)) != this->_parameters.end()) { + if (ite->second->len() != 1) { + return -1; + } + if (QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 20) { + return -1; + } + } + return 0; } const uint8_t * @@ -244,6 +310,42 @@ QUICTransportParametersInClientHello::_parameters_offset(const uint8_t *) const return 4; // sizeof(QUICVersion) } +int +QUICTransportParametersInClientHello::_validate_parameters() const +{ + if (QUICTransportParameters::_validate_parameters() < 0) { + return 0; + } + + decltype(this->_parameters)::const_iterator ite; + + // MUST NOTs + if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) { + return -1; + } + + // MAYs + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI)) != this->_parameters.end()) { + if (ite->second->len() != 4) { + return -1; + } + if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 1) { + return -1; + } + } + + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI)) != this->_parameters.end()) { + if (ite->second->len() != 4) { + return -1; + } + if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 3) { + return -1; + } + } + + return 0; +} + QUICVersion QUICTransportParametersInClientHello::initial_version() const { @@ -302,6 +404,46 @@ QUICTransportParametersInEncryptedExtensions::_parameters_offset(const uint8_t * return 4 + 1 + buf[4]; } +int +QUICTransportParametersInEncryptedExtensions::_validate_parameters() const +{ + if (QUICTransportParameters::_validate_parameters() < 0) { + return 0; + } + + decltype(this->_parameters)::const_iterator ite; + + // MUSTs + if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) { + if (ite->second->len() != 2) { + return -1; + } + } else { + return -1; + } + + // MAYs + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI)) != this->_parameters.end()) { + if (ite->second->len() != 4) { + return -1; + } + if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 1) { + return -1; + } + } + + if (auto p = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI) != this->_parameters.end()) { + if (ite->second->len() != 4) { + return -1; + } + if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 3) { + return -1; + } + } + + return 0; +} + // // QUICTransportParametersHandler // diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index f0729a53d30..00e08fd20c6 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -102,6 +102,7 @@ class QUICTransportParameters bool _valid = false; virtual std::ptrdiff_t _parameters_offset(const uint8_t *buf) const = 0; + virtual int _validate_parameters() const; virtual void _store(uint8_t *buf, uint16_t *len) const = 0; std::map _parameters; @@ -117,6 +118,7 @@ class QUICTransportParametersInClientHello : public QUICTransportParameters protected: std::ptrdiff_t _parameters_offset(const uint8_t *buf) const override; + int _validate_parameters() const override; void _store(uint8_t *buf, uint16_t *len) const override; private: @@ -134,6 +136,7 @@ class QUICTransportParametersInEncryptedExtensions : public QUICTransportParamet protected: std::ptrdiff_t _parameters_offset(const uint8_t *buf) const override; + int _validate_parameters() const override; void _store(uint8_t *buf, uint16_t *len) const override; QUICVersion _negotiated_version = 0; diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index 51dbdc7dd02..520c69ecad7 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -131,26 +131,25 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") { - SECTION("OK") + SECTION("OK case") { - uint8_t buf[] = { - 0x01, 0x02, 0x03, 0x04, // negotiated version - 0x04, // size of supported versions - 0x01, 0x02, 0x03, 0x04, // - 0x00, 0x1e, // size of parameters - 0x00, 0x00, // parameter id - 0x00, 0x04, // length of value - 0x11, 0x22, 0x33, 0x44, // value - 0x00, 0x01, // parameter id - 0x00, 0x04, // length of value - 0x12, 0x34, 0x56, 0x78, // value - 0x00, 0x02, // parameter id - 0x00, 0x04, // length of value - 0x0a, 0x0b, 0x0c, 0x0d, // value - 0x00, 0x03, // parameter id - 0x00, 0x02, // length of value - 0xab, 0xcd, // value - }; + uint8_t buf[] = {0x01, 0x02, 0x03, 0x04, // negotiated version + 0x04, // size of supported versions + 0x01, 0x02, 0x03, 0x04, // + 0x00, 0x2a, // size of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value + 0x00, 0x01, // parameter id + 0x00, 0x04, // length of value + 0x12, 0x34, 0x56, 0x78, // value + 0x00, 0x03, // parameter id + 0x00, 0x02, // length of value + 0x0a, 0x0b, // value + 0x00, 0x06, // parameter id + 0x00, 0x10, // length of value + 0x00, 0x10, 0x20, 0x30, // value + 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0}; QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf)); CHECK(params_in_ee.is_valid()); @@ -167,17 +166,13 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") CHECK(len == 4); CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); - data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, len); - CHECK(len == 4); - CHECK(memcmp(data, "\x0a\x0b\x0c\x0d", 4) == 0); - data = params_in_ee.getAsBytes(QUICTransportParameterId::IDLE_TIMEOUT, len); CHECK(len == 2); - CHECK(memcmp(data, "\xab\xcd", 2) == 0); + CHECK(memcmp(data, "\x0a\x0b", 2) == 0); - data = params_in_ee.getAsBytes(QUICTransportParameterId::MAX_PACKET_SIZE, len); - CHECK(len == 0); - CHECK(data == nullptr); + data = params_in_ee.getAsBytes(QUICTransportParameterId::STATELESS_RESET_TOKEN, len); + CHECK(len == 16); + CHECK(memcmp(data, buf + 37, 16) == 0); } SECTION("Duplicate parameters") From 17cdcbf5bbcfa42f55c799f2c6dfc4df04b48888 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 15 Dec 2017 12:10:55 +0900 Subject: [PATCH 0256/1313] Update version number for ALPN (hq-07 to hq-08) --- lib/ts/ink_inet.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ts/ink_inet.cc b/lib/ts/ink_inet.cc index d5eb0e4bd19..d8af0fe90e6 100644 --- a/lib/ts/ink_inet.cc +++ b/lib/ts/ink_inet.cc @@ -45,7 +45,7 @@ const ts::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"_sv); const ts::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"_sv); const ts::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"_sv); const ts::string_view IP_PROTO_TAG_HTTP_2_0("h2"_sv); // HTTP/2 over TLS -const ts::string_view IP_PROTO_TAG_HTTP_QUIC("hq-07"_sv); // HTTP over QUIC +const ts::string_view IP_PROTO_TAG_HTTP_QUIC("hq-08"_sv); // HTTP over QUIC uint32_t ink_inet_addr(const char *s) From b0520cd27bbe8b653d08e9791b703f90601bba04 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Dec 2017 12:10:34 +0900 Subject: [PATCH 0257/1313] Fix STREAM frame loading --- iocore/net/quic/QUICFrame.cc | 2 +- iocore/net/quic/test/test_QUICFrame.cc | 111 +++++++++++++++++-------- 2 files changed, 79 insertions(+), 34 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 5160763c442..0104dce72a5 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -191,7 +191,7 @@ bool QUICStreamFrame::has_offset_field() const { if (this->_buf) { - return (this->_buf[0] & 0x40) != 0; + return (this->_buf[0] & 0x04) != 0; } else { return this->_offset != 0; } diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index f9daf5f43bf..ca7df03deef 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -54,41 +54,86 @@ TEST_CASE("QUICFrame Type", "[quic]") CHECK(QUICFrame::type(reinterpret_cast("\xff")) == QUICFrameType::UNKNOWN); } -TEST_CASE("Load STREAM Frame 1", "[quic]") +TEST_CASE("Load STREAM Frame", "[quic]") { - uint8_t buf1[] = { - 0x10, // 0b00010OLF (OLF=000) - 0x01, // Stream ID - 0x01, 0x02, 0x03, 0x04, // Stream Data - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::STREAM); - CHECK(frame1->size() == 6); - std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(streamFrame1->stream_id() == 0x01); - CHECK(streamFrame1->offset() == 0x00); - CHECK(streamFrame1->data_length() == 4); - CHECK(memcmp(streamFrame1->data(), "\x01\x02\x03\x04", 4) == 0); - CHECK(streamFrame1->has_fin_flag() == false); -} + SECTION("OLF=000") + { + uint8_t buf1[] = { + 0x10, // 0b00010OLF (OLF=000) + 0x01, // Stream ID + 0x01, 0x02, 0x03, 0x04, // Stream Data + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM); + CHECK(frame1->size() == 6); + std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(streamFrame1->stream_id() == 0x01); + CHECK(streamFrame1->offset() == 0x00); + CHECK(streamFrame1->data_length() == 4); + CHECK(memcmp(streamFrame1->data(), "\x01\x02\x03\x04", 4) == 0); + CHECK(streamFrame1->has_fin_flag() == false); + } -TEST_CASE("Load STREAM Frame 2", "[quic]") -{ - uint8_t buf1[] = { - 0x12, // 0b00010OLF (OLF=010) - 0x01, // Stream ID - 0x05, // Data Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::STREAM); - CHECK(frame1->size() == 8); - std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(streamFrame1->stream_id() == 0x01); - CHECK(streamFrame1->offset() == 0x00); - CHECK(streamFrame1->data_length() == 5); - CHECK(memcmp(streamFrame1->data(), "\x01\x02\x03\x04\x05", 5) == 0); - CHECK(streamFrame1->has_fin_flag() == false); + SECTION("OLF=010") + { + uint8_t buf1[] = { + 0x12, // 0b00010OLF (OLF=010) + 0x01, // Stream ID + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM); + CHECK(frame1->size() == 8); + std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(streamFrame1->stream_id() == 0x01); + CHECK(streamFrame1->offset() == 0x00); + CHECK(streamFrame1->data_length() == 5); + CHECK(memcmp(streamFrame1->data(), "\x01\x02\x03\x04\x05", 5) == 0); + CHECK(streamFrame1->has_fin_flag() == false); + } + + SECTION("OLF=110") + { + uint8_t buf1[] = { + 0x16, // 0b00010OLF (OLF=110) + 0x01, // Stream ID + 0x02, // Data Length + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM); + CHECK(frame1->size() == 9); + + std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(streamFrame1->stream_id() == 0x01); + CHECK(streamFrame1->offset() == 0x02); + CHECK(streamFrame1->data_length() == 5); + CHECK(memcmp(streamFrame1->data(), "\x01\x02\x03\x04\x05", 5) == 0); + CHECK(streamFrame1->has_fin_flag() == false); + } + + SECTION("OLF=111") + { + uint8_t buf1[] = { + 0x17, // 0b00010OLF (OLF=110) + 0x01, // Stream ID + 0x02, // Data Length + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM); + CHECK(frame1->size() == 9); + + std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); + CHECK(streamFrame1->stream_id() == 0x01); + CHECK(streamFrame1->offset() == 0x02); + CHECK(streamFrame1->data_length() == 5); + CHECK(memcmp(streamFrame1->data(), "\x01\x02\x03\x04\x05", 5) == 0); + CHECK(streamFrame1->has_fin_flag() == true); + } } TEST_CASE("Store STREAM Frame", "[quic]") From 1a37dc6cad043a66af512de27a7161efb5cde1f6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 15 Dec 2017 14:07:05 +0900 Subject: [PATCH 0258/1313] Set omit-connection-id flag correctly --- iocore/net/quic/QUICPacket.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 2473f049cbd..c4f17e1c7aa 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -445,7 +445,7 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const size_t n; *len = 0; buf[0] = 0x00; - if (this->_has_connection_id) { + if (!this->_has_connection_id) { buf[0] += 0x40; } if (this->_key_phase == QUICKeyPhase::PHASE_1) { From 9707a54e3d1a363635e7d941308fd2f3c320cb32 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Dec 2017 14:41:54 +0900 Subject: [PATCH 0259/1313] Add tests for QUICPacketHeader::store() --- iocore/net/quic/test/test_QUICPacket.cc | 51 +++++++++++++++++++------ 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index e4877ddb250..fe83032e6ac 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -25,7 +25,7 @@ #include "quic/QUICPacket.h" -TEST_CASE("QUICPacketHeader", "[quic]") +TEST_CASE("QUICPacketHeader - Long", "[quic]") { SECTION("Long Header (load) Version Negotiation Packet") { @@ -70,14 +70,23 @@ TEST_CASE("QUICPacketHeader", "[quic]") CHECK(header->has_key_phase() == false); } - SECTION("Long Header (build)") + SECTION("Long Header (store)") { - const uint8_t expected[] = {0x11, 0x22, 0x33, 0x44, 0x55}; - ats_unique_buf payload = ats_unique_malloc(sizeof(expected)); - memcpy(payload.get(), expected, sizeof(expected)); + uint8_t buf[32] = {0}; + size_t len = 0; + + const uint8_t expected[] = { + 0xFF, // Long header, Type: INITIAL + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID + 0x11, 0x22, 0x33, 0x44, // Version + 0x12, 0x34, 0x56, 0x78, // Packet number + 0x11, 0x22, 0x33, 0x44, 0x55, // Payload (dummy) + }; + ats_unique_buf payload = ats_unique_malloc(5); + memcpy(payload.get(), expected + 17, 5); QUICPacketHeader *header = - QUICPacketHeader::build(QUICPacketType::INITIAL, 0x0102030405060708, 0x12345678, 0, 0xa0a0a0a0, std::move(payload), 32); + QUICPacketHeader::build(QUICPacketType::INITIAL, 0x0102030405060708, 0x12345678, 0, 0x11223344, std::move(payload), 32); CHECK(header->size() == 17); CHECK(header->has_key_phase() == false); @@ -87,9 +96,16 @@ TEST_CASE("QUICPacketHeader", "[quic]") CHECK(header->connection_id() == 0x0102030405060708); CHECK(header->packet_number() == 0x12345678); CHECK(header->has_version() == true); - CHECK(header->version() == 0xa0a0a0a0); + CHECK(header->version() == 0x11223344); + + header->store(buf, &len); + CHECK(len == 17); + CHECK(memcmp(buf, expected, len) == 0); } +} +TEST_CASE("QUICPacketHeader - Short", "[quic]") +{ SECTION("Short Header (load)") { const uint8_t input[] = { @@ -110,15 +126,22 @@ TEST_CASE("QUICPacketHeader", "[quic]") CHECK(header->has_version() == false); } - SECTION("Short Header (build)") + SECTION("Short Header (store)") { - const uint8_t expected[] = {0x11, 0x22, 0x33, 0x44, 0x55}; - ats_unique_buf payload = ats_unique_malloc(sizeof(expected)); - memcpy(payload.get(), expected, sizeof(expected)); + uint8_t buf[32] = {0}; + size_t len = 0; + + const uint8_t expected[] = { + 0x1D, // Short header with (C=0, K=0, Type=0x1D) + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID + 0x12, 0x34, 0x56, 0x78, // Packet number + 0x11, 0x22, 0x33, 0x44, 0x55, // Protected Payload + }; + ats_unique_buf payload = ats_unique_malloc(5); + memcpy(payload.get(), expected + 13, 5); QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, 0x0102030405060708, 0x12345678, 0, std::move(payload), 32); - CHECK(header->size() == 13); CHECK(header->packet_size() == 0); CHECK(header->has_key_phase() == true); @@ -128,6 +151,10 @@ TEST_CASE("QUICPacketHeader", "[quic]") CHECK(header->connection_id() == 0x0102030405060708); CHECK(header->packet_number() == 0x12345678); CHECK(header->has_version() == false); + + header->store(buf, &len); + CHECK(len == 13); + CHECK(memcmp(buf, expected, len) == 0); } } From 937019af98332ee9f4dd978fde62e837c1035d07 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 15 Dec 2017 14:57:40 +0900 Subject: [PATCH 0260/1313] MAX_DATA is now in units of octets --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICConfig.h | 2 +- iocore/net/quic/QUICFlowController.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 83c5a9e62c3..587ba713ba0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -325,7 +325,7 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) switch (frame->type()) { case QUICFrameType::MAX_DATA: - this->_remote_flow_controller->forward_limit(std::static_pointer_cast(frame)->maximum_data() * 1024); + this->_remote_flow_controller->forward_limit(std::static_pointer_cast(frame)->maximum_data()); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 6f427c14c77..c6adba4069d 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -40,7 +40,7 @@ class QUICConfigParams : public ConfigInfo private: // FIXME Fill appropriate values uint32_t _no_activity_timeout_in = 0; - uint32_t _initial_max_data = 100; // in units of 1024 octets + uint32_t _initial_max_data = 131072; uint32_t _initial_max_stream_data = 2048; uint32_t _initial_max_stream_id_bidi = 100; uint32_t _initial_max_stream_id_uni = 102; diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index a468561c7f8..66f9de92e13 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -126,7 +126,7 @@ QUICRemoteConnectionFlowController::_create_frame() QUICFrameUPtr QUICLocalConnectionFlowController::_create_frame() { - return QUICFrameFactory::create_max_data_frame(this->_limit / 1024); + return QUICFrameFactory::create_max_data_frame(this->_limit); } QUICFrameUPtr From 076fc93bafe34f9146739af6bc34733c9367cc31 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Dec 2017 15:21:22 +0900 Subject: [PATCH 0261/1313] Reenable quic stream when hq transaction is reenabled --- proxy/hq/HQClientTransaction.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 69939cc7acb..d96e84bf756 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -247,11 +247,15 @@ HQClientTransaction::reenable(VIO *vio) { if (vio->op == VIO::READ) { int64_t len = this->_process_read_vio(); + this->_stream_io->read_reenable(); + if (len > 0) { this->_signal_read_event(); } } else if (vio->op == VIO::WRITE) { int64_t len = this->_process_write_vio(); + this->_stream_io->write_reenable(); + if (len > 0) { this->_signal_write_event(); } From 9ec0a4a2742522d00c2f93e6c625d10b359292b9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 18 Dec 2017 09:32:31 +0900 Subject: [PATCH 0262/1313] Fix offset field length of STREAM frame when offset is 0 --- iocore/net/quic/QUICFrame.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 0104dce72a5..0c29f579099 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -228,7 +228,7 @@ QUICStreamFrame::has_fin_flag() const size_t QUICStreamFrame::_get_stream_id_field_offset() const { - return 1; + return sizeof(QUICFrameType); } size_t @@ -281,7 +281,11 @@ QUICStreamFrame::_get_offset_field_len() const return 0; } } else { - return QUICVariableInt::size(this->_offset); + if (this->_offset != 0) { + return QUICVariableInt::size(this->_offset); + } else { + return 0; + } } } From d7ebd15ffe97105f105642812bcaaadf0dea9672 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 18 Dec 2017 10:13:47 +0900 Subject: [PATCH 0263/1313] Add more tests of QUIC*Frame::size() and bugfix --- iocore/net/quic/QUICFrame.cc | 8 +- iocore/net/quic/test/test_QUICFrame.cc | 485 ++++++++++++++----------- 2 files changed, 284 insertions(+), 209 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 0c29f579099..e611f430a12 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -519,7 +519,7 @@ QUICAckFrame::AckBlock::_get_length_size() const if (this->_buf) { return QUICVariableInt::size(this->_buf + this->_get_gap_size()); } else { - return QUICVariableInt::size(this->_gap); + return QUICVariableInt::size(this->_length); } } @@ -1149,7 +1149,7 @@ QUICMaxStreamDataFrame::_get_max_stream_data_field_length() const if (this->_buf) { return QUICVariableInt::size(this->_buf + this->_get_max_stream_data_field_offset()); } else { - return QUICVariableInt::size(this->_stream_id); + return QUICVariableInt::size(this->_maximum_stream_data); } } @@ -1267,7 +1267,7 @@ QUICStreamBlockedFrame::type() const size_t QUICStreamBlockedFrame::size() const { - return sizeof(QUICFrameType) + this->_get_stream_id_field_length() + _get_offset_field_length(); + return sizeof(QUICFrameType) + this->_get_stream_id_field_length() + this->_get_offset_field_length(); } void @@ -1327,7 +1327,7 @@ QUICStreamBlockedFrame::_get_offset_field_length() const if (this->_buf) { return QUICVariableInt::size(this->_buf + this->_get_offset_field_offset()); } else { - return QUICVariableInt::size(this->_stream_id); + return QUICVariableInt::size(this->_offset); } } diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index ca7df03deef..6c71c83ebbc 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -66,12 +66,12 @@ TEST_CASE("Load STREAM Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM); CHECK(frame1->size() == 6); - std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(streamFrame1->stream_id() == 0x01); - CHECK(streamFrame1->offset() == 0x00); - CHECK(streamFrame1->data_length() == 4); - CHECK(memcmp(streamFrame1->data(), "\x01\x02\x03\x04", 4) == 0); - CHECK(streamFrame1->has_fin_flag() == false); + std::shared_ptr stream_frame = std::dynamic_pointer_cast(frame1); + CHECK(stream_frame->stream_id() == 0x01); + CHECK(stream_frame->offset() == 0x00); + CHECK(stream_frame->data_length() == 4); + CHECK(memcmp(stream_frame->data(), "\x01\x02\x03\x04", 4) == 0); + CHECK(stream_frame->has_fin_flag() == false); } SECTION("OLF=010") @@ -85,12 +85,12 @@ TEST_CASE("Load STREAM Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM); CHECK(frame1->size() == 8); - std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(streamFrame1->stream_id() == 0x01); - CHECK(streamFrame1->offset() == 0x00); - CHECK(streamFrame1->data_length() == 5); - CHECK(memcmp(streamFrame1->data(), "\x01\x02\x03\x04\x05", 5) == 0); - CHECK(streamFrame1->has_fin_flag() == false); + std::shared_ptr stream_frame = std::dynamic_pointer_cast(frame1); + CHECK(stream_frame->stream_id() == 0x01); + CHECK(stream_frame->offset() == 0x00); + CHECK(stream_frame->data_length() == 5); + CHECK(memcmp(stream_frame->data(), "\x01\x02\x03\x04\x05", 5) == 0); + CHECK(stream_frame->has_fin_flag() == false); } SECTION("OLF=110") @@ -106,12 +106,12 @@ TEST_CASE("Load STREAM Frame", "[quic]") CHECK(frame1->type() == QUICFrameType::STREAM); CHECK(frame1->size() == 9); - std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(streamFrame1->stream_id() == 0x01); - CHECK(streamFrame1->offset() == 0x02); - CHECK(streamFrame1->data_length() == 5); - CHECK(memcmp(streamFrame1->data(), "\x01\x02\x03\x04\x05", 5) == 0); - CHECK(streamFrame1->has_fin_flag() == false); + std::shared_ptr stream_frame = std::dynamic_pointer_cast(frame1); + CHECK(stream_frame->stream_id() == 0x01); + CHECK(stream_frame->offset() == 0x02); + CHECK(stream_frame->data_length() == 5); + CHECK(memcmp(stream_frame->data(), "\x01\x02\x03\x04\x05", 5) == 0); + CHECK(stream_frame->has_fin_flag() == false); } SECTION("OLF=111") @@ -127,12 +127,12 @@ TEST_CASE("Load STREAM Frame", "[quic]") CHECK(frame1->type() == QUICFrameType::STREAM); CHECK(frame1->size() == 9); - std::shared_ptr streamFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(streamFrame1->stream_id() == 0x01); - CHECK(streamFrame1->offset() == 0x02); - CHECK(streamFrame1->data_length() == 5); - CHECK(memcmp(streamFrame1->data(), "\x01\x02\x03\x04\x05", 5) == 0); - CHECK(streamFrame1->has_fin_flag() == true); + std::shared_ptr stream_frame = std::dynamic_pointer_cast(frame1); + CHECK(stream_frame->stream_id() == 0x01); + CHECK(stream_frame->offset() == 0x02); + CHECK(stream_frame->data_length() == 5); + CHECK(memcmp(stream_frame->data(), "\x01\x02\x03\x04\x05", 5) == 0); + CHECK(stream_frame->has_fin_flag() == true); } } @@ -153,8 +153,10 @@ TEST_CASE("Store STREAM Frame", "[quic]") ats_unique_buf payload1 = ats_unique_malloc(5); memcpy(payload1.get(), raw1, 5); - QUICStreamFrame streamFrame1(std::move(payload1), 5, 0x01, 0x00); - streamFrame1.store(buf, &len); + QUICStreamFrame stream_frame(std::move(payload1), 5, 0x01, 0x00); + CHECK(stream_frame.size() == 8); + + stream_frame.store(buf, &len); CHECK(len == 8); CHECK(memcmp(buf, expected1, len) == 0); } @@ -174,8 +176,10 @@ TEST_CASE("Store STREAM Frame", "[quic]") ats_unique_buf payload2 = ats_unique_malloc(5); memcpy(payload2.get(), raw2, 5); - QUICStreamFrame streamFrame2(std::move(payload2), 5, 0x01, 0x01); - streamFrame2.store(buf, &len); + QUICStreamFrame stream_frame(std::move(payload2), 5, 0x01, 0x01); + CHECK(stream_frame.size() == 9); + + stream_frame.store(buf, &len); CHECK(len == 9); CHECK(memcmp(buf, expected2, len) == 0); } @@ -195,8 +199,10 @@ TEST_CASE("Store STREAM Frame", "[quic]") ats_unique_buf payload3 = ats_unique_malloc(5); memcpy(payload3.get(), raw3, 5); - QUICStreamFrame streamFrame3(std::move(payload3), 5, 0x01, 0x010000); - streamFrame3.store(buf, &len); + QUICStreamFrame stream_frame(std::move(payload3), 5, 0x01, 0x010000); + CHECK(stream_frame.size() == 12); + + stream_frame.store(buf, &len); CHECK(len == 12); CHECK(memcmp(buf, expected3, len) == 0); } @@ -216,8 +222,10 @@ TEST_CASE("Store STREAM Frame", "[quic]") ats_unique_buf payload4 = ats_unique_malloc(5); memcpy(payload4.get(), raw4, 5); - QUICStreamFrame streamFrame4(std::move(payload4), 5, 0x01, 0x0100000000); - streamFrame4.store(buf, &len); + QUICStreamFrame stream_frame(std::move(payload4), 5, 0x01, 0x0100000000); + CHECK(stream_frame.size() == 16); + + stream_frame.store(buf, &len); CHECK(len == 16); CHECK(memcmp(buf, expected4, len) == 0); } @@ -237,8 +245,10 @@ TEST_CASE("Store STREAM Frame", "[quic]") ats_unique_buf payload5 = ats_unique_malloc(5); memcpy(payload5.get(), raw5, 5); - QUICStreamFrame streamFrame5(std::move(payload5), 5, 0x0100, 0x0100000000); - streamFrame5.store(buf, &len); + QUICStreamFrame stream_frame(std::move(payload5), 5, 0x0100, 0x0100000000); + CHECK(stream_frame.size() == 17); + + stream_frame.store(buf, &len); CHECK(len == 17); CHECK(memcmp(buf, expected5, len) == 0); } @@ -258,8 +268,10 @@ TEST_CASE("Store STREAM Frame", "[quic]") ats_unique_buf payload6 = ats_unique_malloc(5); memcpy(payload6.get(), raw6, 5); - QUICStreamFrame streamFrame6(std::move(payload6), 5, 0x010000, 0x0100000000); - streamFrame6.store(buf, &len); + QUICStreamFrame stream_frame(std::move(payload6), 5, 0x010000, 0x0100000000); + CHECK(stream_frame.size() == 19); + + stream_frame.store(buf, &len); CHECK(len == 19); CHECK(memcmp(buf, expected6, len) == 0); } @@ -279,8 +291,10 @@ TEST_CASE("Store STREAM Frame", "[quic]") ats_unique_buf payload7 = ats_unique_malloc(5); memcpy(payload7.get(), raw7, 5); - QUICStreamFrame streamFrame7(std::move(payload7), 5, 0x01000000, 0x0100000000); - streamFrame7.store(buf, &len); + QUICStreamFrame stream_frame(std::move(payload7), 5, 0x01000000, 0x0100000000); + CHECK(stream_frame.size() == 19); + + stream_frame.store(buf, &len); CHECK(len == 19); CHECK(memcmp(buf, expected7, len) == 0); } @@ -300,8 +314,10 @@ TEST_CASE("Store STREAM Frame", "[quic]") ats_unique_buf payload = ats_unique_malloc(5); memcpy(payload.get(), raw, 5); - QUICStreamFrame streamFrame(std::move(payload), 5, 0x01000000, 0x0100000000, true); - streamFrame.store(buf, &len); + QUICStreamFrame stream_frame(std::move(payload), 5, 0x01000000, 0x0100000000, true); + CHECK(stream_frame.size() == 19); + + stream_frame.store(buf, &len); CHECK(len == 19); CHECK(memcmp(buf, expected, len) == 0); } @@ -321,11 +337,11 @@ TEST_CASE("Load Ack Frame 1", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); CHECK(frame1->size() == 6); - std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(ackFrame1 != nullptr); - CHECK(ackFrame1->ack_block_count() == 0); - CHECK(ackFrame1->largest_acknowledged() == 0x12); - CHECK(ackFrame1->ack_delay() == 0x3456); + std::shared_ptr ack_frame1 = std::dynamic_pointer_cast(frame1); + CHECK(ack_frame1 != nullptr); + CHECK(ack_frame1->ack_block_count() == 0); + CHECK(ack_frame1->largest_acknowledged() == 0x12); + CHECK(ack_frame1->ack_delay() == 0x3456); } SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") @@ -341,13 +357,13 @@ TEST_CASE("Load Ack Frame 1", "[quic]") CHECK(frame1->type() == QUICFrameType::ACK); CHECK(frame1->size() == 12); - std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(ackFrame1 != nullptr); - CHECK(ackFrame1->largest_acknowledged() == 0x01); - CHECK(ackFrame1->ack_delay() == 0x0171); - CHECK(ackFrame1->ack_block_count() == 0); + std::shared_ptr ack_frame1 = std::dynamic_pointer_cast(frame1); + CHECK(ack_frame1 != nullptr); + CHECK(ack_frame1->largest_acknowledged() == 0x01); + CHECK(ack_frame1->ack_delay() == 0x0171); + CHECK(ack_frame1->ack_block_count() == 0); - const QUICAckFrame::AckBlockSection *section = ackFrame1->ack_block_section(); + const QUICAckFrame::AckBlockSection *section = ack_frame1->ack_block_section(); CHECK(section->first_ack_block_length() == 0x01); } @@ -368,13 +384,13 @@ TEST_CASE("Load Ack Frame 1", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); CHECK(frame1->size() == 21); - std::shared_ptr ackFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(ackFrame1 != nullptr); - CHECK(ackFrame1->largest_acknowledged() == 0x12); - CHECK(ackFrame1->ack_delay() == 0x3456); - CHECK(ackFrame1->ack_block_count() == 2); + std::shared_ptr ack_frame1 = std::dynamic_pointer_cast(frame1); + CHECK(ack_frame1 != nullptr); + CHECK(ack_frame1->largest_acknowledged() == 0x12); + CHECK(ack_frame1->ack_delay() == 0x3456); + CHECK(ack_frame1->ack_block_count() == 2); - const QUICAckFrame::AckBlockSection *section = ackFrame1->ack_block_section(); + const QUICAckFrame::AckBlockSection *section = ack_frame1->ack_block_section(); CHECK(section->first_ack_block_length() == 0x01); auto ite = section->begin(); CHECK(ite != section->end()); @@ -403,8 +419,11 @@ TEST_CASE("Store Ack Frame", "[quic]") 0x00, // Ack Block Count 0x00, // Ack Block Section }; - QUICAckFrame ackFrame(0x12, 0x3456, 0); - ackFrame.store(buf, &len); + + QUICAckFrame ack_frame(0x12, 0x3456, 0); + CHECK(ack_frame.size() == 6); + + ack_frame.store(buf, &len); CHECK(len == 6); CHECK(memcmp(buf, expected, len) == 0); } @@ -425,12 +444,13 @@ TEST_CASE("Store Ack Frame", "[quic]") 0x85, 0x06, 0x07, 0x08, // Ack Block Section (Gap 2) 0xc9, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, // Ack Block Section (ACK Block 2 Length) }; - QUICAckFrame ackFrame(0x12, 0x3456, 0x01); - QUICAckFrame::AckBlockSection *section = ackFrame.ack_block_section(); + QUICAckFrame ack_frame(0x12, 0x3456, 0x01); + QUICAckFrame::AckBlockSection *section = ack_frame.ack_block_section(); section->add_ack_block({0x02, 0x0304}); section->add_ack_block({0x05060708, 0x090a0b0c0d0e0f10}); + CHECK(ack_frame.size() == 21); - ackFrame.store(buf, &len); + ack_frame.store(buf, &len); CHECK(len == 21); CHECK(memcmp(buf, expected, len) == 0); } @@ -466,6 +486,8 @@ TEST_CASE("Store RST_STREAM Frame", "[quic]") 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset }; QUICRstStreamFrame rst_stream_frame(0x12345678, 0x0001, 0x1122334455667788); + CHECK(rst_stream_frame.size() == 15); + rst_stream_frame.store(buf, &len); CHECK(len == 15); CHECK(memcmp(buf, expected, len) == 0); @@ -479,8 +501,8 @@ TEST_CASE("Load Ping Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::PING); CHECK(frame1->size() == 1); - std::shared_ptr pingStreamFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(pingStreamFrame1 != nullptr); + std::shared_ptr ping_frame = std::dynamic_pointer_cast(frame1); + CHECK(ping_frame != nullptr); } TEST_CASE("Store Ping Frame", "[quic]") @@ -491,8 +513,8 @@ TEST_CASE("Store Ping Frame", "[quic]") uint8_t expected[] = { 0x07, // Type }; - QUICPingFrame pingStreamFrame; - pingStreamFrame.store(buf, &len); + QUICPingFrame ping_frame; + ping_frame.store(buf, &len); CHECK(len == 1); CHECK(memcmp(buf, expected, len) == 0); } @@ -517,132 +539,169 @@ TEST_CASE("Store Padding Frame", "[quic]") uint8_t expected[] = { 0x00, // Type }; - QUICPaddingFrame paddingFrame; - paddingFrame.store(buf, &len); + QUICPaddingFrame padding_frame; + padding_frame.store(buf, &len); CHECK(len == 1); CHECK(memcmp(buf, expected, len) == 0); } TEST_CASE("Load ConnectionClose Frame", "[quic]") { - uint8_t buf1[] = { - 0x02, // Type - 0x00, 0x0A, // Error Code - 0x05, // Reason Phrase Length - 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::CONNECTION_CLOSE); - CHECK(frame1->size() == 9); - std::shared_ptr connectionCloseFrame1 = - std::dynamic_pointer_cast(frame1); - CHECK(connectionCloseFrame1 != nullptr); - CHECK(connectionCloseFrame1->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION); - CHECK(connectionCloseFrame1->reason_phrase_length() == 5); - CHECK(memcmp(connectionCloseFrame1->reason_phrase(), buf1 + 4, 5) == 0); - - // No reason phrase - uint8_t buf2[] = { - 0x02, // Type - 0x00, 0x0A, // Error Code - 0x00, // Reason Phrase Length - }; - std::shared_ptr frame2 = QUICFrameFactory::create(buf2, sizeof(buf1)); - CHECK(frame2->type() == QUICFrameType::CONNECTION_CLOSE); - CHECK(frame2->size() == 4); - std::shared_ptr connectionCloseFrame2 = - std::dynamic_pointer_cast(frame2); - CHECK(connectionCloseFrame2 != nullptr); - CHECK(connectionCloseFrame2->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION); - CHECK(connectionCloseFrame2->reason_phrase_length() == 0); + SECTION("w/ reason phrase") + { + uint8_t buf1[] = { + 0x02, // Type + 0x00, 0x0A, // Error Code + 0x05, // Reason Phrase Length + 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::CONNECTION_CLOSE); + CHECK(frame1->size() == 9); + + std::shared_ptr conn_close_frame = + std::dynamic_pointer_cast(frame1); + CHECK(conn_close_frame != nullptr); + CHECK(conn_close_frame->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION); + CHECK(conn_close_frame->reason_phrase_length() == 5); + CHECK(memcmp(conn_close_frame->reason_phrase(), buf1 + 4, 5) == 0); + } + + SECTION("w/o reason phrase") + { + uint8_t buf2[] = { + 0x02, // Type + 0x00, 0x0A, // Error Code + 0x00, // Reason Phrase Length + }; + std::shared_ptr frame2 = QUICFrameFactory::create(buf2, sizeof(buf2)); + CHECK(frame2->type() == QUICFrameType::CONNECTION_CLOSE); + CHECK(frame2->size() == 4); + + std::shared_ptr conn_close_frame = + std::dynamic_pointer_cast(frame2); + CHECK(conn_close_frame != nullptr); + CHECK(conn_close_frame->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION); + CHECK(conn_close_frame->reason_phrase_length() == 0); + } } TEST_CASE("Store ConnectionClose Frame", "[quic]") { - uint8_t buf[65535]; - size_t len; + SECTION("w/ reason phrase") + { + uint8_t buf[32]; + size_t len; - uint8_t expected1[] = { - 0x02, // Type - 0x00, 0x0A, // Error Code - 0x05, // Reason Phrase Length - 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); - }; - QUICConnectionCloseFrame connectionCloseFrame1(QUICTransErrorCode::PROTOCOL_VIOLATION, 5, "ABCDE"); - connectionCloseFrame1.store(buf, &len); - CHECK(len == 9); - CHECK(memcmp(buf, expected1, len) == 0); + uint8_t expected1[] = { + 0x02, // Type + 0x00, 0x0A, // Error Code + 0x05, // Reason Phrase Length + 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); + }; + QUICConnectionCloseFrame connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, 5, "ABCDE"); + CHECK(connection_close_frame.size() == 9); - uint8_t expected2[] = { - 0x02, // Type - 0x00, 0x0A, // Error Code - 0x00, // Reason Phrase Length - }; - QUICConnectionCloseFrame connectionCloseFrame2(QUICTransErrorCode::PROTOCOL_VIOLATION, 0, nullptr); - connectionCloseFrame2.store(buf, &len); - CHECK(len == 4); - CHECK(memcmp(buf, expected2, len) == 0); + connection_close_frame.store(buf, &len); + CHECK(len == 9); + CHECK(memcmp(buf, expected1, len) == 0); + } + + SECTION("w/o reason phrase") + { + uint8_t buf[32]; + size_t len; + + uint8_t expected2[] = { + 0x02, // Type + 0x00, 0x0A, // Error Code + 0x00, // Reason Phrase Length + }; + QUICConnectionCloseFrame connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, 0, nullptr); + connection_close_frame.store(buf, &len); + CHECK(len == 4); + CHECK(memcmp(buf, expected2, len) == 0); + } } TEST_CASE("Load ApplicationClose Frame", "[quic]") { - uint8_t buf1[] = { - 0x03, // Type - 0x00, 0x01, // Error Code - 0x05, // Reason Phrase Length - 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::APPLICATION_CLOSE); - CHECK(frame1->size() == 9); - std::shared_ptr applicationCloseFrame1 = - std::dynamic_pointer_cast(frame1); - CHECK(applicationCloseFrame1 != nullptr); - CHECK(applicationCloseFrame1->error_code() == static_cast(0x01)); - CHECK(applicationCloseFrame1->reason_phrase_length() == 5); - CHECK(memcmp(applicationCloseFrame1->reason_phrase(), buf1 + 4, 5) == 0); - - // No reason phrase - uint8_t buf2[] = { - 0x03, // Type - 0x00, 0x01, // Error Code - 0x00, // Reason Phrase Length - }; - std::shared_ptr frame2 = QUICFrameFactory::create(buf2, sizeof(buf1)); - CHECK(frame2->type() == QUICFrameType::APPLICATION_CLOSE); - CHECK(frame2->size() == 4); - std::shared_ptr applicationCloseFrame2 = - std::dynamic_pointer_cast(frame2); - CHECK(applicationCloseFrame2 != nullptr); - CHECK(applicationCloseFrame2->error_code() == static_cast(0x01)); - CHECK(applicationCloseFrame2->reason_phrase_length() == 0); + SECTION("w/ reason phrase") + { + uint8_t buf1[] = { + 0x03, // Type + 0x00, 0x01, // Error Code + 0x05, // Reason Phrase Length + 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::APPLICATION_CLOSE); + CHECK(frame1->size() == 9); + + std::shared_ptr app_close_frame = + std::dynamic_pointer_cast(frame1); + CHECK(app_close_frame != nullptr); + CHECK(app_close_frame->error_code() == static_cast(0x01)); + CHECK(app_close_frame->reason_phrase_length() == 5); + CHECK(memcmp(app_close_frame->reason_phrase(), buf1 + 4, 5) == 0); + } + + SECTION("w/o reason phrase") + { + uint8_t buf2[] = { + 0x03, // Type + 0x00, 0x01, // Error Code + 0x00, // Reason Phrase Length + }; + std::shared_ptr frame2 = QUICFrameFactory::create(buf2, sizeof(buf2)); + CHECK(frame2->type() == QUICFrameType::APPLICATION_CLOSE); + CHECK(frame2->size() == 4); + + std::shared_ptr app_close_frame = + std::dynamic_pointer_cast(frame2); + CHECK(app_close_frame != nullptr); + CHECK(app_close_frame->error_code() == static_cast(0x01)); + CHECK(app_close_frame->reason_phrase_length() == 0); + } } TEST_CASE("Store ApplicationClose Frame", "[quic]") { - uint8_t buf[65535]; - size_t len; + SECTION("w/ reason phrase") + { + uint8_t buf[32]; + size_t len; - uint8_t expected1[] = { - 0x03, // Type - 0x00, 0x01, // Error Code - 0x05, // Reason Phrase Length - 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); - }; - QUICApplicationCloseFrame applicationCloseFrame1(static_cast(0x01), 5, "ABCDE"); - applicationCloseFrame1.store(buf, &len); - CHECK(len == 9); - CHECK(memcmp(buf, expected1, len) == 0); + uint8_t expected1[] = { + 0x03, // Type + 0x00, 0x01, // Error Code + 0x05, // Reason Phrase Length + 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); + }; + QUICApplicationCloseFrame app_close_frame(static_cast(0x01), 5, "ABCDE"); + CHECK(app_close_frame.size() == 9); - uint8_t expected2[] = { - 0x03, // Type - 0x00, 0x01, // Error Code - 0x00, // Reason Phrase Length - }; - QUICApplicationCloseFrame applicationCloseFrame2(static_cast(0x01), 0, nullptr); - applicationCloseFrame2.store(buf, &len); - CHECK(len == 4); - CHECK(memcmp(buf, expected2, len) == 0); + app_close_frame.store(buf, &len); + CHECK(len == 9); + CHECK(memcmp(buf, expected1, len) == 0); + } + SECTION("w/o reason phrase") + { + uint8_t buf[32]; + size_t len; + + uint8_t expected2[] = { + 0x03, // Type + 0x00, 0x01, // Error Code + 0x00, // Reason Phrase Length + }; + QUICApplicationCloseFrame app_close_frame(static_cast(0x01), 0, nullptr); + CHECK(app_close_frame.size() == 4); + + app_close_frame.store(buf, &len); + CHECK(len == 4); + CHECK(memcmp(buf, expected2, len) == 0); + } } TEST_CASE("Load MaxData Frame", "[quic]") @@ -654,9 +713,9 @@ TEST_CASE("Load MaxData Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_DATA); CHECK(frame1->size() == 9); - std::shared_ptr maxDataFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(maxDataFrame1 != nullptr); - CHECK(maxDataFrame1->maximum_data() == 0x1122334455667788ULL); + std::shared_ptr max_data_frame = std::dynamic_pointer_cast(frame1); + CHECK(max_data_frame != nullptr); + CHECK(max_data_frame->maximum_data() == 0x1122334455667788ULL); } TEST_CASE("Store MaxData Frame", "[quic]") @@ -668,8 +727,10 @@ TEST_CASE("Store MaxData Frame", "[quic]") 0x04, // Type 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data }; - QUICMaxDataFrame maxDataFrame(0x1122334455667788); - maxDataFrame.store(buf, &len); + QUICMaxDataFrame max_data_frame(0x1122334455667788); + CHECK(max_data_frame.size() == 9); + + max_data_frame.store(buf, &len); CHECK(len == 9); CHECK(memcmp(buf, expected, len) == 0); } @@ -701,8 +762,10 @@ TEST_CASE("Store MaxStreamData Frame", "[quic]") 0x81, 0x02, 0x03, 0x04, // Stream ID 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data }; - QUICMaxStreamDataFrame maxStreamDataFrame(0x01020304, 0x1122334455667788ULL); - maxStreamDataFrame.store(buf, &len); + QUICMaxStreamDataFrame max_stream_data_frame(0x01020304, 0x1122334455667788ULL); + CHECK(max_stream_data_frame.size() == 13); + + max_stream_data_frame.store(buf, &len); CHECK(len == 13); CHECK(memcmp(buf, expected, len) == 0); } @@ -716,9 +779,9 @@ TEST_CASE("Load MaxStreamId Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_STREAM_ID); CHECK(frame1->size() == 5); - std::shared_ptr maxStreamIdFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(maxStreamIdFrame1 != nullptr); - CHECK(maxStreamIdFrame1->maximum_stream_id() == 0x01020304); + std::shared_ptr max_stream_id_frame = std::dynamic_pointer_cast(frame1); + CHECK(max_stream_id_frame != nullptr); + CHECK(max_stream_id_frame->maximum_stream_id() == 0x01020304); } TEST_CASE("Store MaxStreamId Frame", "[quic]") @@ -730,8 +793,10 @@ TEST_CASE("Store MaxStreamId Frame", "[quic]") 0x06, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID }; - QUICMaxStreamIdFrame maxStreamIdFrame(0x01020304); - maxStreamIdFrame.store(buf, &len); + QUICMaxStreamIdFrame max_stream_id_frame(0x01020304); + CHECK(max_stream_id_frame.size() == 5); + + max_stream_id_frame.store(buf, &len); CHECK(len == 5); CHECK(memcmp(buf, expected, len) == 0); } @@ -745,9 +810,9 @@ TEST_CASE("Load Blocked Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::BLOCKED); CHECK(frame1->size() == 2); - std::shared_ptr blockedStreamFrame1 = std::dynamic_pointer_cast(frame1); - CHECK(blockedStreamFrame1 != nullptr); - CHECK(blockedStreamFrame1->offset() == 0x07); + std::shared_ptr blocked_stream_frame = std::dynamic_pointer_cast(frame1); + CHECK(blocked_stream_frame != nullptr); + CHECK(blocked_stream_frame->offset() == 0x07); } TEST_CASE("Store Blocked Frame", "[quic]") @@ -759,8 +824,10 @@ TEST_CASE("Store Blocked Frame", "[quic]") 0x08, // Type 0x07, // Offset }; - QUICBlockedFrame blockedStreamFrame(0x07); - blockedStreamFrame.store(buf, &len); + QUICBlockedFrame blocked_stream_frame(0x07); + CHECK(blocked_stream_frame.size() == 2); + + blocked_stream_frame.store(buf, &len); CHECK(len == 2); CHECK(memcmp(buf, expected, len) == 0); } @@ -775,11 +842,11 @@ TEST_CASE("Load StreamBlocked Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM_BLOCKED); CHECK(frame1->size() == 6); - std::shared_ptr streamBlockedFrame1 = + std::shared_ptr stream_blocked_frame = std::dynamic_pointer_cast(frame1); - CHECK(streamBlockedFrame1 != nullptr); - CHECK(streamBlockedFrame1->stream_id() == 0x01020304); - CHECK(streamBlockedFrame1->offset() == 0x07); + CHECK(stream_blocked_frame != nullptr); + CHECK(stream_blocked_frame->stream_id() == 0x01020304); + CHECK(stream_blocked_frame->offset() == 0x07); } TEST_CASE("Store StreamBlocked Frame", "[quic]") @@ -792,8 +859,10 @@ TEST_CASE("Store StreamBlocked Frame", "[quic]") 0x81, 0x02, 0x03, 0x04, // Stream ID 0x07, // Offset }; - QUICStreamBlockedFrame streamBlockedFrame(0x01020304, 0x07); - streamBlockedFrame.store(buf, &len); + QUICStreamBlockedFrame stream_blocked_frame(0x01020304, 0x07); + CHECK(stream_blocked_frame.size() == 6); + + stream_blocked_frame.store(buf, &len); CHECK(len == 6); CHECK(memcmp(buf, expected, len) == 0); } @@ -807,10 +876,10 @@ TEST_CASE("Load StreamIdBlocked Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM_ID_BLOCKED); CHECK(frame1->size() == 3); - std::shared_ptr streamIdBlockedFrame1 = + std::shared_ptr stream_id_blocked_frame = std::dynamic_pointer_cast(frame1); - CHECK(streamIdBlockedFrame1 != nullptr); - CHECK(streamIdBlockedFrame1->stream_id() == 0x0102); + CHECK(stream_id_blocked_frame != nullptr); + CHECK(stream_id_blocked_frame->stream_id() == 0x0102); } TEST_CASE("Store StreamIdBlocked Frame", "[quic]") @@ -822,8 +891,10 @@ TEST_CASE("Store StreamIdBlocked Frame", "[quic]") 0x0a, // Type 0x41, 0x02, // Stream ID }; - QUICStreamIdBlockedFrame streamIdBlockedStreamFrame(0x0102); - streamIdBlockedStreamFrame.store(buf, &len); + QUICStreamIdBlockedFrame stream_id_blocked_frame(0x0102); + CHECK(stream_id_blocked_frame.size() == 3); + + stream_id_blocked_frame.store(buf, &len); CHECK(len == 3); CHECK(memcmp(buf, expected, len) == 0); } @@ -840,12 +911,12 @@ TEST_CASE("Load NewConnectionId Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::NEW_CONNECTION_ID); CHECK(frame1->size() == 27); - std::shared_ptr newConnectionIdFrame1 = + std::shared_ptr new_con_id_frame = std::dynamic_pointer_cast(frame1); - CHECK(newConnectionIdFrame1 != nullptr); - CHECK(newConnectionIdFrame1->sequence() == 0x0102); - CHECK(newConnectionIdFrame1->connection_id() == 0x1122334455667788ULL); - CHECK(memcmp(newConnectionIdFrame1->stateless_reset_token().buf(), buf1 + 11, 16) == 0); + CHECK(new_con_id_frame != nullptr); + CHECK(new_con_id_frame->sequence() == 0x0102); + CHECK(new_con_id_frame->connection_id() == 0x1122334455667788ULL); + CHECK(memcmp(new_con_id_frame->stateless_reset_token().buf(), buf1 + 11, 16) == 0); } TEST_CASE("Store NewConnectionId Frame", "[quic]") @@ -860,8 +931,10 @@ TEST_CASE("Store NewConnectionId Frame", "[quic]") 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Stateless Reset Token 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, }; - QUICNewConnectionIdFrame newConnectionIdFrame(0x0102, 0x1122334455667788ULL, {expected + 11}); - newConnectionIdFrame.store(buf, &len); + QUICNewConnectionIdFrame new_con_id_frame(0x0102, 0x1122334455667788ULL, {expected + 11}); + CHECK(new_con_id_frame.size() == 27); + + new_con_id_frame.store(buf, &len); CHECK(len == 27); CHECK(memcmp(buf, expected, len) == 0); } @@ -894,6 +967,8 @@ TEST_CASE("Store STOP_SENDING Frame", "[quic]") 0x00, 0x01, // Error Code }; QUICStopSendingFrame stop_sending_frame(0x12345678, static_cast(0x01)); + CHECK(stop_sending_frame.size() == 7); + stop_sending_frame.store(buf, &len); CHECK(len == 7); CHECK(memcmp(buf, expected, len) == 0); From 559ed2c19e0a99707beb55be9f2429c366797afa Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 18 Dec 2017 10:59:54 +0900 Subject: [PATCH 0264/1313] Fix storing STREAM frame on retransmission --- iocore/net/quic/QUICFrame.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index e611f430a12..682d5b08a6a 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -109,19 +109,19 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, bool include_length_field) con size_t n; // Stream ID (i) - QUICTypeUtil::write_QUICStreamId(this->_stream_id, buf + *len, &n); + QUICTypeUtil::write_QUICStreamId(this->stream_id(), buf + *len, &n); *len += n; // [Offset (i)] "O" of "0b0010OLF" if (this->has_offset_field()) { - QUICTypeUtil::write_QUICOffset(this->_offset, buf + *len, &n); + QUICTypeUtil::write_QUICOffset(this->offset(), buf + *len, &n); *len += n; buf[0] += 0x04; } // [Length (i)] "L of "0b0010OLF" if (include_length_field) { - QUICTypeUtil::write_QUICVariableInt(this->_data_len, buf + *len, &n); + QUICTypeUtil::write_QUICVariableInt(this->data_length(), buf + *len, &n); *len += n; buf[0] += 0x02; } From 2411e7e9c4e8296b4c3ce82cd13ed814e62cca8a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 18 Dec 2017 11:10:48 +0900 Subject: [PATCH 0265/1313] Unify log output from LossDetector --- iocore/net/quic/QUICLossDetector.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 45896b043f8..16699b22deb 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -273,9 +273,8 @@ QUICLossDetector::_on_loss_detection_alarm() // this->_send_two_packets(); this->_rto_count++; } - QUICLDDebug("Unacked packets %lu (handshake pkt %u, retransmittable %u, other %lu)", this->_sent_packets.size(), - this->_handshake_outstanding.load(), this->_retransmittable_outstanding.load(), - this->_sent_packets.size() - (this->_handshake_outstanding.load() + this->_retransmittable_outstanding.load())); + QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), + this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); this->_set_loss_detection_alarm(); } From 0fa3586002d78f6e19329098c593a58f4514169b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 18 Dec 2017 11:12:34 +0900 Subject: [PATCH 0266/1313] Fix retransmittable packet count --- iocore/net/quic/QUICLossDetector.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 16699b22deb..b90b0d43652 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -383,5 +383,6 @@ QUICLossDetector::_retransmit_handshake_packets() for (auto packet_number : retransmitted_handshake_packets) { this->_sent_packets.erase(packet_number); --this->_handshake_outstanding; + --this->_retransmittable_outstanding; } } From af623f8864a7567fe0cbb4dfb8ac65b5663e35ce Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 18 Dec 2017 11:43:09 +0900 Subject: [PATCH 0267/1313] Add tests for retransmission and fix QUIC*Frame::store() --- iocore/net/quic/QUICFrame.cc | 270 +++++++++++++++---------- iocore/net/quic/test/test_QUICFrame.cc | 243 ++++++++++++++++++++++ 2 files changed, 408 insertions(+), 105 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 682d5b08a6a..6160b2650cf 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -696,18 +696,23 @@ QUICRstStreamFrame::size() const void QUICRstStreamFrame::store(uint8_t *buf, size_t *len) const { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::RST_STREAM); - ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); - p += n; - QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); - p += n; - QUICTypeUtil::write_QUICOffset(this->_final_offset, p, &n); - p += n; + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::RST_STREAM); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); + p += n; + QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); + p += n; + QUICTypeUtil::write_QUICOffset(this->_final_offset, p, &n); + p += n; - *len = p - buf; + *len = p - buf; + } } QUICStreamId @@ -796,8 +801,13 @@ QUICPingFrame::size() const void QUICPingFrame::store(uint8_t *buf, size_t *len) const { - buf[0] = static_cast(QUICFrameType::PING); - *len = 1; + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + buf[0] = static_cast(QUICFrameType::PING); + *len = 1; + } } // @@ -849,20 +859,25 @@ QUICConnectionCloseFrame::size() const void QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len) const { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::CONNECTION_CLOSE); - ++p; - QUICTypeUtil::write_QUICTransErrorCode(this->_error_code, p, &n); - p += n; - QUICTypeUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); - p += n; - if (this->_reason_phrase_length > 0) { - memcpy(p, this->_reason_phrase, this->_reason_phrase_length); - p += this->_reason_phrase_length; - } + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::CONNECTION_CLOSE); + ++p; + QUICTypeUtil::write_QUICTransErrorCode(this->_error_code, p, &n); + p += n; + QUICTypeUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); + p += n; + if (this->_reason_phrase_length > 0) { + memcpy(p, this->_reason_phrase, this->_reason_phrase_length); + p += this->_reason_phrase_length; + } - *len = p - buf; + *len = p - buf; + } } QUICTransErrorCode @@ -944,20 +959,25 @@ QUICApplicationCloseFrame::size() const void QUICApplicationCloseFrame::store(uint8_t *buf, size_t *len) const { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::APPLICATION_CLOSE); - ++p; - QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); - p += n; - QUICTypeUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); - p += n; - if (this->_reason_phrase_length > 0) { - memcpy(p, this->_reason_phrase, this->_reason_phrase_length); - p += this->_reason_phrase_length; - } + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::APPLICATION_CLOSE); + ++p; + QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); + p += n; + QUICTypeUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); + p += n; + if (this->_reason_phrase_length > 0) { + memcpy(p, this->_reason_phrase, this->_reason_phrase_length); + p += this->_reason_phrase_length; + } - *len = p - buf; + *len = p - buf; + } } QUICAppErrorCode @@ -1035,14 +1055,19 @@ QUICMaxDataFrame::size() const void QUICMaxDataFrame::store(uint8_t *buf, size_t *len) const { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::MAX_DATA); - ++p; - QUICTypeUtil::write_QUICMaxData(this->_maximum_data, p, &n); - p += n; + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::MAX_DATA); + ++p; + QUICTypeUtil::write_QUICMaxData(this->_maximum_data, p, &n); + p += n; - *len = p - buf; + *len = p - buf; + } } uint64_t @@ -1089,16 +1114,21 @@ QUICMaxStreamDataFrame::size() const void QUICMaxStreamDataFrame::store(uint8_t *buf, size_t *len) const { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::MAX_STREAM_DATA); - ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); - p += n; - QUICTypeUtil::write_QUICMaxData(this->_maximum_stream_data, p, &n); - p += n; + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::MAX_STREAM_DATA); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); + p += n; + QUICTypeUtil::write_QUICMaxData(this->_maximum_stream_data, p, &n); + p += n; - *len = p - buf; + *len = p - buf; + } } QUICStreamId @@ -1176,14 +1206,19 @@ QUICMaxStreamIdFrame::size() const void QUICMaxStreamIdFrame::store(uint8_t *buf, size_t *len) const { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::MAX_STREAM_ID); - ++p; - QUICTypeUtil::write_QUICStreamId(this->_maximum_stream_id, p, &n); - p += n; + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::MAX_STREAM_ID); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_maximum_stream_id, p, &n); + p += n; - *len = p - buf; + *len = p - buf; + } } QUICStreamId @@ -1224,15 +1259,20 @@ QUICBlockedFrame::size() const void QUICBlockedFrame::store(uint8_t *buf, size_t *len) const { - size_t n; - uint8_t *p = buf; + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + size_t n; + uint8_t *p = buf; - *p = static_cast(QUICFrameType::BLOCKED); - ++p; - QUICTypeUtil::write_QUICOffset(this->_offset, p, &n); - p += n; + *p = static_cast(QUICFrameType::BLOCKED); + ++p; + QUICTypeUtil::write_QUICOffset(this->_offset, p, &n); + p += n; - *len = p - buf; + *len = p - buf; + } } QUICOffset @@ -1273,16 +1313,21 @@ QUICStreamBlockedFrame::size() const void QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len) const { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::STREAM_BLOCKED); - ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); - p += n; - QUICTypeUtil::write_QUICOffset(this->_offset, p, &n); - p += n; + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::STREAM_BLOCKED); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); + p += n; + QUICTypeUtil::write_QUICOffset(this->_offset, p, &n); + p += n; - *len = p - buf; + *len = p - buf; + } } QUICStreamId @@ -1349,15 +1394,20 @@ QUICStreamIdBlockedFrame::size() const void QUICStreamIdBlockedFrame::store(uint8_t *buf, size_t *len) const { - size_t n; - uint8_t *p = buf; + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + size_t n; + uint8_t *p = buf; - *p = static_cast(QUICFrameType::STREAM_ID_BLOCKED); - ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); - p += n; + *p = static_cast(QUICFrameType::STREAM_ID_BLOCKED); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); + p += n; - *len = p - buf; + *len = p - buf; + } } QUICStreamId @@ -1399,18 +1449,23 @@ QUICNewConnectionIdFrame::size() const void QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len) const { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::NEW_CONNECTION_ID); - ++p; - QUICTypeUtil::write_QUICVariableInt(this->_sequence, p, &n); - p += n; - QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, p, &n); - p += n; - memcpy(p, this->_stateless_reset_token.buf(), QUICStatelessResetToken::LEN); - p += QUICStatelessResetToken::LEN; + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::NEW_CONNECTION_ID); + ++p; + QUICTypeUtil::write_QUICVariableInt(this->_sequence, p, &n); + p += n; + QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, p, &n); + p += n; + memcpy(p, this->_stateless_reset_token.buf(), QUICStatelessResetToken::LEN); + p += QUICStatelessResetToken::LEN; - *len = p - buf; + *len = p - buf; + } } uint64_t @@ -1483,16 +1538,21 @@ QUICStopSendingFrame::size() const void QUICStopSendingFrame::store(uint8_t *buf, size_t *len) const { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::STOP_SENDING); - ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); - p += n; - QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); - p += n; + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::STOP_SENDING); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); + p += n; + QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); + p += n; - *len = p - buf; + *len = p - buf; + } } QUICAppErrorCode diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 6c71c83ebbc..b3aee214491 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1053,3 +1053,246 @@ TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") CHECK(rst_stream_frame1->stream_id() == 0x1234); CHECK(rst_stream_frame1->final_offset() == 0); } + +TEST_CASE("Retransmit", "[quic][frame][retransmit]") +{ + QUICPacketFactory factory; + MockQUICCrypto crypto; + factory.set_crypto_module(&crypto); + QUICPacketUPtr packet = factory.create_server_protected_packet(0x01020304, 0, {nullptr, [](void *p) { ats_free(p); }}, 0, true); + + SECTION("STREAM frame") + { + uint8_t frame_buf[] = { + 0x12, // Type, 0b00010OLF (OLF=010) + 0x01, // Stream ID + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 8); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + + SECTION("RST_STREAM frame") + { + uint8_t frame_buf[] = { + 0x01, // Type + 0x92, 0x34, 0x56, 0x78, // Stream ID + 0x00, 0x01, // Error Code + 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 15); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + + SECTION("CONNECTION_CLOSE frame") + { + uint8_t frame_buf[] = { + 0x02, // Type + 0x00, 0x0A, // Error Code + 0x05, // Reason Phrase Length + 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 9); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + + SECTION("APPLICATION_CLOSE frame") + { + uint8_t frame_buf[] = { + 0x03, // Type + 0x00, 0x01, // Error Code + 0x05, // Reason Phrase Length + 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 9); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + + SECTION("MAX_DATA frame") + { + uint8_t frame_buf[] = { + 0x04, // Type + 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 9); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + + SECTION("MAX_STREAM_DATA frame") + { + uint8_t frame_buf[] = { + 0x05, // Type + 0x81, 0x02, 0x03, 0x04, // Stream ID + 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 13); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + + SECTION("MAX_STREAM_ID frame") + { + uint8_t frame_buf[] = { + 0x06, // Type + 0x81, 0x02, 0x03, 0x04, // Stream ID + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 5); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + + SECTION("PING frame") + { + // TODO + } + + SECTION("BLOCKED frame") + { + uint8_t frame_buf[] = { + 0x08, // Type + 0x07, // Offset + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 2); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + + SECTION("STREAM_BLOCKED frame") + { + uint8_t frame_buf[] = { + 0x09, // Type + 0x81, 0x02, 0x03, 0x04, // Stream ID + 0x07, // Offset + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 6); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + + SECTION("STREAM_ID_BLOCKED frame") + { + uint8_t frame_buf[] = { + 0x0a, // Type + 0x41, 0x02, // Stream ID + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 3); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + + SECTION("NEW_CONNECTION_ID frame") + { + uint8_t frame_buf[] = { + 0x0b, // Type + 0x41, 0x02, // Sequence + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token + 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 27); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + + SECTION("STOP_SENDING frame") + { + uint8_t frame_buf[] = { + 0x0c, // Type + 0x92, 0x34, 0x56, 0x78, // Stream ID + 0x00, 0x01, // Error Code + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 7); + CHECK(memcmp(buf, frame_buf, len) == 0); + } +} From e317a528e028c0fdf3076d2b75d7e02de6efdbbc Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 18 Dec 2017 11:48:45 +0900 Subject: [PATCH 0268/1313] Implement TLP and RTO --- iocore/net/QUICNetVConnection.cc | 10 +++++---- iocore/net/quic/QUICLossDetector.cc | 32 +++++++++++++++++++++++++++-- iocore/net/quic/QUICLossDetector.h | 2 ++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 587ba713ba0..68fb4591309 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -218,10 +218,12 @@ QUICNetVConnection::_transmit_packet(QUICPacketUPtr packet) { SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); - QUICConDebug("Packet Number=%" PRIu64 " Type=%s Size=%hu", packet->packet_number(), QUICDebugNames::packet_type(packet->type()), - packet->size()); - // TODO Remove const_cast - this->_packet_send_queue.enqueue(const_cast(packet.release())); + if (packet) { + QUICConDebug("Packet Number=%" PRIu64 " Type=%s Size=%hu", packet->packet_number(), QUICDebugNames::packet_type(packet->type()), + packet->size()); + // TODO Remove const_cast + this->_packet_send_queue.enqueue(const_cast(packet.release())); + } return this->_packet_send_queue.size; } diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index b90b0d43652..405e2d6dad0 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -263,14 +263,16 @@ QUICLossDetector::_on_loss_detection_alarm() this->_detect_lost_packets(this->_largest_acked_packet); } else if (this->_tlp_count < this->_MAX_TLPS) { // Tail Loss Probe. - // this->_send_one_packet(); + QUICLDDebug("TLP"); + this->_send_one_packet(); this->_tlp_count++; } else { // RTO. if (this->_rto_count == 0) { this->_largest_sent_before_rto = this->_largest_sent_packet; } - // this->_send_two_packets(); + QUICLDDebug("RTO"); + this->_send_two_packets(); this->_rto_count++; } QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), @@ -386,3 +388,29 @@ QUICLossDetector::_retransmit_handshake_packets() --this->_retransmittable_outstanding; } } + +void +QUICLossDetector::_send_one_packet() +{ + if (this->_transmitter->transmit_packet() < 1) { + auto ite = this->_sent_packets.rbegin(); + if (ite != this->_sent_packets.rend()) { + this->_transmitter->retransmit_packet(*ite->second->packet); + } + } +} + +void +QUICLossDetector::_send_two_packets() +{ + auto ite = this->_sent_packets.rbegin(); + if (ite != this->_sent_packets.rend()) { + this->_transmitter->retransmit_packet(*ite->second->packet); + ite++; + if (ite != this->_sent_packets.rend()) { + this->_transmitter->retransmit_packet(*ite->second->packet); + } + } else { + this->_transmitter->transmit_packet(); + } +} diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index d72785c7535..ce2c62953f1 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -115,6 +115,8 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler std::set _determine_newly_acked_packets(const QUICAckFrame &ack_frame); void _retransmit_handshake_packets(); + void _send_one_packet(); + void _send_two_packets(); QUICPacketTransmitter *_transmitter = nullptr; QUICCongestionController *_cc = nullptr; From 3cd8b506bee93f58518d747c817cf0e70836837a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 18 Dec 2017 11:51:20 +0900 Subject: [PATCH 0269/1313] Shortest timeout period is 25ms --- iocore/net/quic/QUICLossDetector.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 405e2d6dad0..ac03c641b16 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -343,7 +343,7 @@ QUICLossDetector::_set_loss_detection_alarm() QUICLDDebug("Loss detection alarm has been set to %" PRId64, alarm_duration); if (!this->_loss_detection_alarm) { - this->_loss_detection_alarm = eventProcessor.schedule_every(this, HRTIME_MSECONDS(100)); + this->_loss_detection_alarm = eventProcessor.schedule_every(this, HRTIME_MSECONDS(25)); } } From 6c80bfb792659c7a8ed9eabb1c124557f7b65921 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 18 Dec 2017 12:33:05 +0900 Subject: [PATCH 0270/1313] Print the reason when switch to closing state --- iocore/net/QUICNetVConnection.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 68fb4591309..e3621ff773b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1047,6 +1047,11 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) if (this->_complete_handshake_if_possible() != 0) { QUICConDebug("Switching state without handshake completion"); } + if (error->msg) { + QUICConDebug("Reason: %.*s", static_cast(strlen(error->msg)), error->msg); + } else { + QUICConDebug("Reason was not provided"); + } if (error->cls == QUICErrorClass::APPLICATION) { this->transmit_frame(QUICFrameFactory::create_application_close_frame(std::move(error))); } else { From bbd681820940e62944052bc33884434b358db359 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 18 Dec 2017 14:11:03 +0900 Subject: [PATCH 0271/1313] Resolve an deadlock issue on retrasnmission --- iocore/net/quic/QUICLossDetector.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index ac03c641b16..f16222169bd 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -392,6 +392,8 @@ QUICLossDetector::_retransmit_handshake_packets() void QUICLossDetector::_send_one_packet() { + SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); if (this->_transmitter->transmit_packet() < 1) { auto ite = this->_sent_packets.rbegin(); if (ite != this->_sent_packets.rend()) { @@ -403,6 +405,8 @@ QUICLossDetector::_send_one_packet() void QUICLossDetector::_send_two_packets() { + SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); auto ite = this->_sent_packets.rbegin(); if (ite != this->_sent_packets.rend()) { this->_transmitter->retransmit_packet(*ite->second->packet); From 72056a67d53bf232ae56391f6ca75d9c8d080c8c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 18 Dec 2017 14:21:39 +0900 Subject: [PATCH 0272/1313] draft-08: Support new PING/PONG frame format --- iocore/net/quic/QUICDebugNames.cc | 2 + iocore/net/quic/QUICFrame.cc | 96 ++++++++++++++++++++- iocore/net/quic/QUICFrame.h | 45 ++++++++++ iocore/net/quic/test/test_QUICFrame.cc | 114 ++++++++++++++++++++++--- 4 files changed, 242 insertions(+), 15 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index e08a91034d5..a96bf39be22 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -78,6 +78,8 @@ QUICDebugNames::frame_type(QUICFrameType type) return "ACK"; case QUICFrameType::STREAM: return "STREAM"; + case QUICFrameType::PONG: + return "PONG"; case QUICFrameType::UNKNOWN: default: return "UNKNOWN"; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 6160b2650cf..93d894c5cfc 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -39,6 +39,7 @@ ClassAllocator quicStreamBlockedFrameAllocator("quicStre ClassAllocator quicStreamIdBlockedFrameAllocator("quicStreamIdBlockedFrameAllocator"); ClassAllocator quicNewConnectionIdFrameAllocator("quicNewConnectionIdFrameAllocator"); ClassAllocator quicStopSendingFrameAllocator("quicStopSendingFrameAllocator"); +ClassAllocator quicPongFrameAllocator("quicPongFrameAllocator"); ClassAllocator quicRetransmissionFrameAllocator("quicRetransmissionFrameAllocator"); QUICFrameType @@ -795,21 +796,50 @@ QUICPingFrame::type() const size_t QUICPingFrame::size() const { - return 1; + return this->_data_offset() + this->data_length(); } void QUICPingFrame::store(uint8_t *buf, size_t *len) const { + *len = this->size(); + if (this->_buf) { - *len = this->size(); memcpy(buf, this->_buf, *len); } else { buf[0] = static_cast(QUICFrameType::PING); - *len = 1; + buf[1] = this->data_length(); + + memcpy(buf + this->_data_offset(), this->data(), this->data_length()); + } +} + +const uint8_t * +QUICPingFrame::data() const +{ + if (this->_buf) { + return this->_buf + this->_data_offset(); + } else { + return this->_data.get(); } } +uint8_t +QUICPingFrame::data_length() const +{ + if (this->_buf) { + return QUICTypeUtil::read_nbytes_as_uint(this->_buf + sizeof(QUICFrameType), 1); + } else { + return this->_data_len; + } +} + +const size_t +QUICPingFrame::_data_offset() const +{ + return sizeof(QUICFrameType) + sizeof(this->_data_len); +} + // // PADDING frame // @@ -1591,6 +1621,62 @@ QUICStopSendingFrame::_get_error_code_field_offset() const return sizeof(QUICFrameType) + this->_get_stream_id_field_length(); } +// +// PONG frame +// +QUICFrameType +QUICPongFrame::type() const +{ + return QUICFrameType::PONG; +} + +size_t +QUICPongFrame::size() const +{ + return this->_data_offset() + this->data_length(); +} + +void +QUICPongFrame::store(uint8_t *buf, size_t *len) const +{ + *len = this->size(); + + if (this->_buf) { + memcpy(buf, this->_buf, *len); + } else { + buf[0] = static_cast(QUICFrameType::PONG); + buf[1] = this->data_length(); + + memcpy(buf + this->_data_offset(), this->data(), this->data_length()); + } +} + +const uint8_t * +QUICPongFrame::data() const +{ + if (this->_buf) { + return this->_buf + this->_data_offset(); + } else { + return this->_data.get(); + } +} + +uint8_t +QUICPongFrame::data_length() const +{ + if (this->_buf) { + return QUICTypeUtil::read_nbytes_as_uint(this->_buf + sizeof(QUICFrameType), 1); + } else { + return this->_data_len; + } +} + +const size_t +QUICPongFrame::_data_offset() const +{ + return sizeof(QUICFrameType) + sizeof(this->_data_len); +} + // // QUICRetransmissionFrame // @@ -1705,6 +1791,10 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicStopSendingFrameAllocator.alloc(); new (frame) QUICStopSendingFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stop_sending_frame); + case QUICFrameType::PONG: + frame = quicPongFrameAllocator.alloc(); + new (frame) QUICPongFrame(buf, len); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_pong_frame); default: // Unknown frame Debug("quic_frame_factory", "Unknown frame type %x", buf[0]); diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 74e03a8b5e8..df5bf751239 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -59,9 +59,11 @@ class QUICStreamFrame : public QUICFrame QUICStreamFrame() : QUICFrame() {} QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false); + virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; + void store(uint8_t *buf, size_t *len, bool include_length_field) const; QUICStreamId stream_id() const; QUICOffset offset() const; @@ -229,9 +231,20 @@ class QUICPingFrame : public QUICFrame public: QUICPingFrame() : QUICFrame() {} QUICPingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICPingFrame(ats_unique_buf data, size_t data_len) : _data(std::move(data)), _data_len(data_len) {} + virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; + + const uint8_t *data() const; + uint8_t data_length() const; + +private: + const size_t _data_offset() const; + + ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; + uint8_t _data_len = 0; }; // PADDING @@ -498,6 +511,31 @@ using QUICFrameDeleterFunc = void (*)(QUICFrame *p); using QUICFrameUPtr = std::unique_ptr; using QUICStreamFrameUPtr = std::unique_ptr; +// +// PONG +// + +class QUICPongFrame : public QUICFrame +{ +public: + QUICPongFrame() : QUICFrame() {} + QUICPongFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICPongFrame(ats_unique_buf data, size_t data_len) : _data(std::move(data)), _data_len(data_len) {} + + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + + const uint8_t *data() const; + uint8_t data_length() const; + +private: + const size_t _data_offset() const; + + ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; + uint8_t _data_len = 0; +}; + // // Retransmission Frame // @@ -533,6 +571,7 @@ extern ClassAllocator quicStreamBlockedFrameAllocator; extern ClassAllocator quicStreamIdBlockedFrameAllocator; extern ClassAllocator quicNewConnectionIdFrameAllocator; extern ClassAllocator quicStopSendingFrameAllocator; +extern ClassAllocator quicPongFrameAllocator; extern ClassAllocator quicRetransmissionFrameAllocator; class QUICFrameDeleter @@ -636,6 +675,12 @@ class QUICFrameDeleter quicStopSendingFrameAllocator.free(static_cast(frame)); } + static void + delete_pong_frame(QUICFrame *frame) + { + quicPongFrameAllocator.free(static_cast(frame)); + } + static void delete_retransmission_frame(QUICFrame *frame) { diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index b3aee214491..e23dd6af665 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -495,27 +495,42 @@ TEST_CASE("Store RST_STREAM Frame", "[quic]") TEST_CASE("Load Ping Frame", "[quic]") { - uint8_t buf1[] = { - 0x07, // Type + uint8_t buf[] = { + 0x07, // Type + 0x08, // Length + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::PING); - CHECK(frame1->size() == 1); - std::shared_ptr ping_frame = std::dynamic_pointer_cast(frame1); + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::PING); + CHECK(frame->size() == 10); + + std::shared_ptr ping_frame = std::dynamic_pointer_cast(frame); CHECK(ping_frame != nullptr); + CHECK(ping_frame->data_length() == 8); + CHECK(memcmp(ping_frame->data(), "\x01\x23\x45\x67\x89\xab\xcd\xef", 8) == 0); } TEST_CASE("Store Ping Frame", "[quic]") { - uint8_t buf[65535]; + uint8_t buf[16]; size_t len; uint8_t expected[] = { - 0x07, // Type + 0x07, // Type + 0x08, // Length + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; - QUICPingFrame ping_frame; - ping_frame.store(buf, &len); - CHECK(len == 1); + + uint8_t raw[] = "\x01\x23\x45\x67\x89\xab\xcd\xef"; + size_t raw_len = sizeof(raw) - 1; + ats_unique_buf data = ats_unique_malloc(raw_len); + memcpy(data.get(), raw, raw_len); + + QUICPingFrame frame(std::move(data), 8); + CHECK(frame.size() == 10); + + frame.store(buf, &len); + CHECK(len == 10); CHECK(memcmp(buf, expected, len) == 0); } @@ -974,6 +989,47 @@ TEST_CASE("Store STOP_SENDING Frame", "[quic]") CHECK(memcmp(buf, expected, len) == 0); } +TEST_CASE("Load Pong Frame", "[quic]") +{ + uint8_t buf[] = { + 0x0d, // Type + 0x08, // Length + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + }; + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::PONG); + CHECK(frame->size() == 10); + + std::shared_ptr pong_frame = std::dynamic_pointer_cast(frame); + CHECK(pong_frame != nullptr); + CHECK(pong_frame->data_length() == 8); + CHECK(memcmp(pong_frame->data(), "\x01\x23\x45\x67\x89\xab\xcd\xef", 8) == 0); +} + +TEST_CASE("Store Pong Frame", "[quic]") +{ + uint8_t buf[16]; + size_t len; + + uint8_t expected[] = { + 0x0d, // Type + 0x08, // Length + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + }; + + uint8_t raw[] = "\x01\x23\x45\x67\x89\xab\xcd\xef"; + size_t raw_len = sizeof(raw) - 1; + ats_unique_buf data = ats_unique_malloc(raw_len); + memcpy(data.get(), raw, raw_len); + + QUICPongFrame frame(std::move(data), 8); + CHECK(frame.size() == 10); + + frame.store(buf, &len); + CHECK(len == 10); + CHECK(memcmp(buf, expected, len) == 0); +} + TEST_CASE("QUICFrameFactory Create Unknown Frame", "[quic]") { uint8_t buf1[] = { @@ -1054,6 +1110,7 @@ TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") CHECK(rst_stream_frame1->final_offset() == 0); } +// Test for retransmittable frames TEST_CASE("Retransmit", "[quic][frame][retransmit]") { QUICPacketFactory factory; @@ -1198,7 +1255,21 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") SECTION("PING frame") { - // TODO + uint8_t frame_buf[] = { + 0x07, // Type + 0x08, // Length + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 10); + CHECK(memcmp(buf, frame_buf, len) == 0); } SECTION("BLOCKED frame") @@ -1295,4 +1366,23 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") CHECK(len == 7); CHECK(memcmp(buf, frame_buf, len) == 0); } + + SECTION("PONG frame") + { + uint8_t frame_buf[] = { + 0x0d, // Type + 0x08, // Length + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 10); + CHECK(memcmp(buf, frame_buf, len) == 0); + } } From 32225be3b3f084e91ac78141e36ace6986c8ba38 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 19 Dec 2017 01:31:43 +0900 Subject: [PATCH 0273/1313] Fix a bug that receiving the first stream frame with fin flag causes RST_STREAM This fixes #2951 --- iocore/net/quic/QUICIncomingFrameBuffer.cc | 7 +-- .../quic/test/test_QUICIncomingFrameBuffer.cc | 61 +++++++++++-------- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index 8975bc69a5b..ba9cc5128c8 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -119,14 +119,14 @@ QUICIncomingFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, // FINAL_OFFSET_ERROR error, even after a stream is closed. if (fin_flag) { if (this->_fin_offset != UINT64_MAX) { - if (this->_fin_offset == offset) { + if (this->_fin_offset == offset + len) { // dup fin frame return QUICErrorUPtr(new QUICNoError()); } return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::FINAL_OFFSET_ERROR)); } - this->_fin_offset = offset; + this->_fin_offset = offset + len; if (this->_max_offset >= this->_fin_offset) { return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::FINAL_OFFSET_ERROR)); @@ -135,8 +135,7 @@ QUICIncomingFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, } else if (this->_fin_offset != UINT64_MAX && this->_fin_offset <= offset) { return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::FINAL_OFFSET_ERROR)); } - - this->_max_offset = std::max(offset, this->_max_offset); + this->_max_offset = std::max(offset + len, this->_max_offset); return QUICErrorUPtr(new QUICNoError()); } diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index a42369bc6fc..5652ba3d55b 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -35,31 +35,42 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") uint8_t data[1024] = {0}; - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); - std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); - std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); - std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 3072, true); - std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 4096); - - buffer.insert(stream1_frame_0_r); - buffer.insert(stream1_frame_1_r); - buffer.insert(stream1_frame_2_r); - err = buffer.insert(stream1_frame_3_r); - CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); - - QUICIncomingFrameBuffer buffer2(stream); - - buffer2.insert(stream1_frame_3_r); - buffer2.insert(stream1_frame_0_r); - buffer2.insert(stream1_frame_1_r); - err = buffer2.insert(stream1_frame_2_r); - CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); - - QUICIncomingFrameBuffer buffer3(stream); - - buffer3.insert(stream1_frame_4_r); - err = buffer3.insert(stream1_frame_3_r); - CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); + SECTION("single frame") + { + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0, true); + + err = buffer.insert(stream1_frame_0_r); + CHECK(err->trans_error_code != QUICTransErrorCode::FINAL_OFFSET_ERROR); + } + + SECTION("multiple frames") + { + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); + std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); + std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); + std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 3072, true); + std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 4096); + + buffer.insert(stream1_frame_0_r); + buffer.insert(stream1_frame_1_r); + buffer.insert(stream1_frame_2_r); + err = buffer.insert(stream1_frame_3_r); + CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); + + QUICIncomingFrameBuffer buffer2(stream); + + buffer2.insert(stream1_frame_3_r); + buffer2.insert(stream1_frame_0_r); + buffer2.insert(stream1_frame_1_r); + err = buffer2.insert(stream1_frame_2_r); + CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); + + QUICIncomingFrameBuffer buffer3(stream); + + buffer3.insert(stream1_frame_4_r); + err = buffer3.insert(stream1_frame_3_r); + CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); + } delete stream; } From 9266834ec31f5fc83e5e0458a3b3361b281858a7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 19 Dec 2017 02:43:22 +0900 Subject: [PATCH 0274/1313] Validate negotiated version in proper way --- iocore/net/quic/QUICHandshake.cc | 4 ++-- iocore/net/quic/QUICTypes.h | 2 +- iocore/net/quic/QUICVersionNegotiator.cc | 12 ++++++++---- iocore/net/quic/QUICVersionNegotiator.h | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index f04a4efa47a..498c0de70f8 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -177,12 +177,12 @@ QUICHandshake::set_transport_parameters(std::shared_ptr dynamic_cast(this->_remote_transport_parameters.get()); if (tp_in_ch) { // Version revalidation - if (this->_version_negotiator->revalidate(tp_in_ch) != QUICVersionNegotiationStatus::REVALIDATED) { + if (this->_version_negotiator->validate(tp_in_ch) != QUICVersionNegotiationStatus::VALIDATED) { QUICHSDebug("Version revalidation failed"); this->_abort_handshake(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR); return; } - QUICHSDebug("Version negotiation revalidated: %x", tp_in_ch->initial_version()); + QUICHSDebug("Version negotiation validated: %x", tp_in_ch->initial_version()); return; } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 8be628345cc..9d9504edace 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -106,7 +106,7 @@ enum class QUICFrameType : uint8_t { enum class QUICVersionNegotiationStatus { NOT_NEGOTIATED, // Haven't negotiated yet NEGOTIATED, // Negotiated - REVALIDATED, // Revalidated in cryptographic handshake + VALIDATED, // Validated with a one in transport parameters FAILED, // Negotiation failed }; diff --git a/iocore/net/quic/QUICVersionNegotiator.cc b/iocore/net/quic/QUICVersionNegotiator.cc index 782305423c9..eba42c2985a 100644 --- a/iocore/net/quic/QUICVersionNegotiator.cc +++ b/iocore/net/quic/QUICVersionNegotiator.cc @@ -41,13 +41,17 @@ QUICVersionNegotiator::negotiate(const QUICPacket *initial_packet) } QUICVersionNegotiationStatus -QUICVersionNegotiator::revalidate(const QUICTransportParametersInClientHello *tp) +QUICVersionNegotiator::validate(const QUICTransportParametersInClientHello *tp) { if (this->_negotiated_version == tp->initial_version()) { - this->_status = QUICVersionNegotiationStatus::REVALIDATED; + this->_status = QUICVersionNegotiationStatus::VALIDATED; } else { - this->_status = QUICVersionNegotiationStatus::FAILED; - this->_negotiated_version = 0; + if (this->_is_supported(tp->initial_version())) { + this->_status = QUICVersionNegotiationStatus::FAILED; + this->_negotiated_version = 0; + } else { + this->_status = QUICVersionNegotiationStatus::VALIDATED; + } } return this->_status; } diff --git a/iocore/net/quic/QUICVersionNegotiator.h b/iocore/net/quic/QUICVersionNegotiator.h index 6b7e075643f..576b6256c39 100644 --- a/iocore/net/quic/QUICVersionNegotiator.h +++ b/iocore/net/quic/QUICVersionNegotiator.h @@ -36,7 +36,7 @@ class QUICVersionNegotiator public: QUICVersionNegotiationStatus status(); QUICVersionNegotiationStatus negotiate(const QUICPacket *initial_packet); - QUICVersionNegotiationStatus revalidate(const QUICTransportParametersInClientHello *tp); + QUICVersionNegotiationStatus validate(const QUICTransportParametersInClientHello *tp); QUICVersion negotiated_version(); private: From 48f5acb0488b47aff70d72de2e9a319598493d82 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 19 Dec 2017 09:09:41 +0900 Subject: [PATCH 0275/1313] Update tests for version negotiation --- .../quic/test/test_QUICVersionNegotiator.cc | 63 +++++++++++++++---- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 2917e1c15d3..48cc23d7b5f 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -26,24 +26,63 @@ #include "quic/QUICVersionNegotiator.h" #include "quic/Mock.h" -TEST_CASE("QUICVersionNegotiator_Normal", "[quic]") +TEST_CASE("QUICVersionNegotiator", "[quic]") { QUICPacketFactory packet_factory; MockQUICCrypto crypto; packet_factory.set_crypto_module(&crypto); QUICVersionNegotiator vn; - // Check initial state - CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); + SECTION("Normal case") + { + // Check initial state + CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); - // Negotiate version - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, QUIC_SUPPORTED_VERSIONS[0], ats_unique_malloc(0), 0); - vn.negotiate(initial_packet.get()); - CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); + // Negotiate version + QUICPacketUPtr initial_packet = + packet_factory.create_initial_packet({}, 0, QUIC_SUPPORTED_VERSIONS[0], ats_unique_malloc(0), 0); + vn.negotiate(initial_packet.get()); + CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); - // Revalidate version - QUICTransportParametersInClientHello tp(QUIC_SUPPORTED_VERSIONS[0]); - vn.revalidate(&tp); - CHECK(vn.status() == QUICVersionNegotiationStatus::REVALIDATED); - CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); + // Validate version + QUICTransportParametersInClientHello tp(QUIC_SUPPORTED_VERSIONS[0]); + vn.validate(&tp); + CHECK(vn.status() == QUICVersionNegotiationStatus::VALIDATED); + CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); + } + + SECTION("Negotiation case") + { + // Check initial state + CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); + + // Negotiate version + QUICPacketUPtr initial_packet = + packet_factory.create_initial_packet({}, 0, QUIC_SUPPORTED_VERSIONS[0], ats_unique_malloc(0), 0); + vn.negotiate(initial_packet.get()); + CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); + + // Validate version + QUICTransportParametersInClientHello tp(0xbabababa); + vn.validate(&tp); + CHECK(vn.status() == QUICVersionNegotiationStatus::VALIDATED); + CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); + } + + SECTION("Downgrade case") + { + // Check initial state + CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); + + // Negotiate version + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, 0xbabababa, ats_unique_malloc(0), 0); + vn.negotiate(initial_packet.get()); + CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); + + // Validate version + QUICTransportParametersInClientHello tp(QUIC_SUPPORTED_VERSIONS[0]); + vn.validate(&tp); + CHECK(vn.status() == QUICVersionNegotiationStatus::FAILED); + CHECK(vn.negotiated_version() != QUIC_SUPPORTED_VERSIONS[0]); + } } From 6616b3798fd4e9cbcd5327304b766628c093e74d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 19 Dec 2017 11:16:26 +0900 Subject: [PATCH 0276/1313] Print generated keys and IVs with extra care Keys and IVs will be logged if you specify vv_quic_crypto (double v). --- iocore/net/quic/QUICCrypto.cc | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 77b38e8b1a6..558e45aa495 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -34,6 +34,18 @@ constexpr static char tag[] = "quic_crypto"; +static void +to_hex(uint8_t *out, uint8_t *in, int in_len) +{ + for (int i = 0; i < in_len; ++i) { + int u4 = in[i] / 16; + int l4 = in[i] % 16; + out [i * 2] = (u4 < 10) ? ('0' + u4) : ('A' + u4 - 10); + out [i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('A' + l4 - 10); + } + out[in_len * 2] = 0; +} + // // QUICPacketProtection // @@ -161,11 +173,22 @@ QUICCryptoTls::is_handshake_finished() const int QUICCryptoTls::initialize_key_materials(QUICConnectionId cid) { + // Generate keys + uint8_t print_buf[512]; std::unique_ptr km; km = this->_keygen_for_client.generate(cid); + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "client key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "client iv 0x%s", print_buf); this->_client_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); + km = this->_keygen_for_server.generate(cid); + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "server key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "server iv 0x%s", print_buf); this->_server_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); // Update algorithm @@ -197,10 +220,19 @@ QUICCryptoTls::update_key_materials() } // Generate keys + uint8_t print_buf[512]; std::unique_ptr km; km = this->_keygen_for_client.generate(this->_ssl); + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "client key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "client iv 0x%s", print_buf); this->_client_pp->set_key(std::move(km), next_key_phase); km = this->_keygen_for_server.generate(this->_ssl); + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "server key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "server iv 0x%s", print_buf); this->_server_pp->set_key(std::move(km), next_key_phase); // Update algorithm From 703471b24d6e29057b7a6b52754fa7f4ec9d46a9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 19 Dec 2017 11:18:40 +0900 Subject: [PATCH 0277/1313] Fix a check for INITIAL_MAX_STREAM_ID_UNI --- iocore/net/quic/QUICTransportParameters.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index b2e61dcb566..2e486d7a300 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -432,7 +432,7 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const } } - if (auto p = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI) != this->_parameters.end()) { + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI)) != this->_parameters.end()) { if (ite->second->len() != 4) { return -1; } From d1ef4a49c61a9628f2359cbae3ce385f76128bb0 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 19 Dec 2017 16:28:40 +0900 Subject: [PATCH 0278/1313] Send ACK frames during handshake This fixes #2955 --- iocore/net/QUICNetVConnection.cc | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e3621ff773b..b1be90f69b1 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -625,18 +625,7 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPt // Start handshake QUICErrorUPtr error = this->_handshake_handler->start(packet.get(), &this->_packet_factory); if (this->_handshake_handler->is_version_negotiated()) { - bool should_send_ack; - error = this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size(), should_send_ack); - if (error->cls != QUICErrorClass::NONE) { - return error; - } - int ret = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, - static_cast(this->_quic_connection_id), this->_local_flow_controller->current_offset(), - this->_local_flow_controller->current_limit()); - if (ret != 0) { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); - } + error = this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); } else { // Perhaps response packets for initial client packet were lost, but no need to start handshake again because loss detector will // retransmit the packets. From ad7d9eb2859974acb1d3add8c7a6fc3816a42c17 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Dec 2017 15:02:15 +0900 Subject: [PATCH 0279/1313] Update loss detection logic to draft-08 --- iocore/net/quic/QUICCongestionController.cc | 9 +- iocore/net/quic/QUICCongestionController.h | 5 +- iocore/net/quic/QUICLossDetector.cc | 337 +++++++++++--------- iocore/net/quic/QUICLossDetector.h | 27 +- 4 files changed, 212 insertions(+), 166 deletions(-) diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 96c2b556d47..3ce8e7636ec 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -51,12 +51,12 @@ QUICCongestionController::handle_frame(std::shared_ptr frame) } void -QUICCongestionController::on_packet_sent() +QUICCongestionController::on_packet_sent(size_t sent_bytes) { } void -QUICCongestionController::on_packet_acked() +QUICCongestionController::on_packet_acked(QUICPacketNumber acked_packet_number) { } @@ -65,6 +65,11 @@ QUICCongestionController::on_packets_lost(std::set packets) { } +void +QUICCongestionController::on_retransmission_timeout_verified() +{ +} + void QUICCongestionController::on_rto_verified() { diff --git a/iocore/net/quic/QUICCongestionController.h b/iocore/net/quic/QUICCongestionController.h index 1f76343a7d1..79cb96ae39c 100644 --- a/iocore/net/quic/QUICCongestionController.h +++ b/iocore/net/quic/QUICCongestionController.h @@ -35,10 +35,11 @@ class QUICCongestionController : public QUICFrameHandler virtual std::vector interests() override; virtual QUICErrorUPtr handle_frame(std::shared_ptr) override; - void on_packet_sent(); - void on_packet_acked(); + void on_packet_sent(size_t sent_bytes); + void on_packet_acked(QUICPacketNumber acked_packet_number); virtual void on_packets_lost(std::set packets); void on_rto_verified(); + void on_retransmission_timeout_verified(); private: }; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index f16222169bd..7edd1819c76 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -28,6 +28,17 @@ #define QUICLDDebug(fmt, ...) \ Debug("quic_loss_detector", "[%" PRIx64 "] " fmt, static_cast(this->_connection_id), ##__VA_ARGS__) +// 3.4.1. Constants of interest (draft-08) +// Keep the order as the same as the spec so that we can see the difference easily. +constexpr static uint32_t MAX_TLPS = 2; +constexpr static uint32_t REORDERING_THRESHOLD = 3; +constexpr static double TIME_REORDERING_FRACTION = 1 / 8; +constexpr static ink_hrtime MIN_TLP_TIMEOUT = HRTIME_MSECONDS(10); +constexpr static ink_hrtime MIN_RTO_TIMEOUT = HRTIME_MSECONDS(200); +// This is defined on the spec but not used +// constexpr static ink_hrtime DELAYED_ACK_TIMEOUT = HRTIME_MSECONDS(25); +constexpr static ink_hrtime DEFAULT_INITIAL_RTT = HRTIME_MSECONDS(100); + QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICCongestionController *cc) : _transmitter(transmitter), _cc(cc) { @@ -35,9 +46,9 @@ QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConge if (this->_time_loss_detection) { this->_reordering_threshold = UINT32_MAX; - this->_time_reordering_fraction = this->_TIME_REORDERING_FRACTION; + this->_time_reordering_fraction = TIME_REORDERING_FRACTION; } else { - this->_reordering_threshold = this->_REORDERING_THRESHOLD; + this->_reordering_threshold = REORDERING_THRESHOLD; this->_time_reordering_fraction = INFINITY; } @@ -102,46 +113,6 @@ QUICLossDetector::largest_acked_packet_number() return this->_largest_acked_packet; } -void -QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_number) -{ - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - this->_loss_time = 0; - std::set lost_packets; - uint32_t delay_until_lost = UINT32_MAX; - - if (this->_time_reordering_fraction != INFINITY) { - delay_until_lost = (1 + this->_time_reordering_fraction) * std::max(this->_latest_rtt, this->_smoothed_rtt); - } else if (largest_acked_packet_number == this->_largest_sent_packet) { - // Early retransmit alarm. - delay_until_lost = 9 / 8 * std::max(this->_latest_rtt, this->_smoothed_rtt); - } - for (auto &unacked : this->_sent_packets) { - if (unacked.first >= largest_acked_packet_number) { - break; - } - ink_hrtime time_since_sent = Thread::get_hrtime() - unacked.second->time; - uint64_t packet_delta = largest_acked_packet_number - unacked.second->packet_number; - if (time_since_sent > delay_until_lost) { - lost_packets.insert(unacked.first); - } else if (packet_delta > this->_reordering_threshold) { - lost_packets.insert(unacked.first); - } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) { - this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent; - } - } - - // Inform the congestion controller of lost packets and - // lets it decide whether to retransmit immediately. - if (!lost_packets.empty()) { - this->_cc->on_packets_lost(lost_packets); - for (auto packet_number : lost_packets) { - this->_decrement_packet_count(packet_number); - this->_sent_packets.erase(packet_number); - } - } -} - void QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) { @@ -152,34 +123,30 @@ QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) bool is_handshake = false; QUICPacketType type = packet->type(); - // XXX: Should QUICPacketType::SERVER_STATELESS_RETRY be included? if (type == QUICPacketType::INITIAL || type == QUICPacketType::HANDSHAKE) { is_handshake = true; } QUICPacketNumber packet_number = packet->packet_number(); - bool is_retransmittable = packet->is_retransmittable(); + bool is_ack_only = !packet->is_retransmittable(); size_t sent_bytes = packet->size(); - return this->_on_packet_sent(packet_number, is_retransmittable, is_handshake, sent_bytes, std::move(packet)); + return this->_on_packet_sent(packet_number, is_ack_only, is_handshake, sent_bytes, std::move(packet)); } void -QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_retransmittable, bool is_handshake, size_t sent_bytes, +QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes, QUICPacketUPtr packet) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - this->_largest_sent_packet = packet_number; this->_time_of_last_sent_packet = Thread::get_hrtime(); + this->_largest_sent_packet = packet_number; // FIXME Should we really keep actual packet object? - std::unique_ptr packet_info(new PacketInfo( - {packet_number, this->_time_of_last_sent_packet, is_retransmittable, is_handshake, sent_bytes, std::move(packet)})); - this->_sent_packets.insert(std::pair>(packet_number, std::move(packet_info))); - if (is_handshake) { - ++this->_handshake_outstanding; - } - if (is_retransmittable) { - ++this->_retransmittable_outstanding; + std::unique_ptr packet_info( + new PacketInfo({packet_number, this->_time_of_last_sent_packet, is_ack_only, is_handshake, sent_bytes, std::move(packet)})); + this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); + if (!is_ack_only) { + this->_cc->on_packet_sent(sent_bytes); this->_set_loss_detection_alarm(); } } @@ -194,10 +161,7 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac if (pi != this->_sent_packets.end()) { this->_latest_rtt = Thread::get_hrtime() - pi->second->time; // _latest_rtt is nanosecond but ack_frame->ack_delay is millisecond - if (this->_latest_rtt > static_cast(HRTIME_MSECONDS(ack_frame->ack_delay()))) { - this->_latest_rtt -= HRTIME_MSECONDS(ack_frame->ack_delay()); - } - this->_update_rtt(this->_latest_rtt); + this->_update_rtt(this->_latest_rtt, HRTIME_MSECONDS(ack_frame->ack_delay()), ack_frame->largest_acknowledged()); } QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), @@ -220,69 +184,19 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac } void -QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number) +QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICPacketNumber largest_acked) { - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number); - // If a packet sent prior to RTO was acked, then the RTO - // was spurious. Otherwise, inform congestion control. - if (this->_rto_count > 0 && acked_packet_number > this->_largest_sent_before_rto) { - // TODO cc->on_retransmission_timeout_verified(); - } - this->_handshake_count = 0; - this->_tlp_count = 0; - this->_rto_count = 0; - this->_decrement_packet_count(acked_packet_number); - this->_sent_packets.erase(acked_packet_number); -} - -void -QUICLossDetector::_decrement_packet_count(QUICPacketNumber packet_number) -{ - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - auto ite = this->_sent_packets.find(packet_number); - if (ite != this->_sent_packets.end()) { - if (ite->second->handshake) { - --this->_handshake_outstanding; - } - if (ite->second->retransmittable) { - --this->_retransmittable_outstanding; + // min_rtt ignores ack delay. + this->_min_rtt = std::min(this->_min_rtt, latest_rtt); + // Adjust for ack delay if it's plausible. + if (latest_rtt - this->_min_rtt > ack_delay) { + latest_rtt -= ack_delay; + // Only save into max ack delay if it's used for rtt calculation and is not ack only. + auto pi = this->_sent_packets.find(largest_acked); + if (pi != this->_sent_packets.end() && !pi->second->ack_only) { + this->_max_ack_delay = std::max(this->_max_ack_delay, ack_delay); } } -} - -void -QUICLossDetector::_on_loss_detection_alarm() -{ - if (this->_handshake_outstanding) { - // Handshake retransmission alarm. - this->_retransmit_handshake_packets(); - this->_handshake_count++; - } else if (this->_loss_time != 0) { - // Early retransmit or Time Loss Detection - this->_detect_lost_packets(this->_largest_acked_packet); - } else if (this->_tlp_count < this->_MAX_TLPS) { - // Tail Loss Probe. - QUICLDDebug("TLP"); - this->_send_one_packet(); - this->_tlp_count++; - } else { - // RTO. - if (this->_rto_count == 0) { - this->_largest_sent_before_rto = this->_largest_sent_packet; - } - QUICLDDebug("RTO"); - this->_send_two_packets(); - this->_rto_count++; - } - QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), - this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); - this->_set_loss_detection_alarm(); -} - -void -QUICLossDetector::_update_rtt(ink_hrtime latest_rtt) -{ // Based on {{RFC6298}}. if (this->_smoothed_rtt == 0) { this->_smoothed_rtt = latest_rtt; @@ -293,11 +207,30 @@ QUICLossDetector::_update_rtt(ink_hrtime latest_rtt) } } +void +QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number) +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number); + this->_cc->on_packet_acked(acked_packet_number); + // If a packet sent prior to RTO was acked, then the RTO + // was spurious. Otherwise, inform congestion control. + if (this->_rto_count > 0 && acked_packet_number > this->_largest_sent_before_rto) { + this->_cc->on_retransmission_timeout_verified(); + } + this->_handshake_count = 0; + this->_tlp_count = 0; + this->_rto_count = 0; + this->_remove_from_sent_packet_list(acked_packet_number); +} + void QUICLossDetector::_set_loss_detection_alarm() { ink_hrtime alarm_duration; - if (!this->_retransmittable_outstanding && this->_loss_detection_alarm) { + // Don't arm the alarm if there are no packets with + // retransmittable data in flight. + if (this->_retransmittable_outstanding == 0 && this->_loss_detection_alarm) { this->_loss_detection_alarm_at = 0; this->_loss_detection_alarm->cancel(); this->_loss_detection_alarm = nullptr; @@ -307,30 +240,25 @@ QUICLossDetector::_set_loss_detection_alarm() if (this->_handshake_outstanding) { // Handshake retransmission alarm. if (this->_smoothed_rtt == 0) { - alarm_duration = 2 * this->_DEFAULT_INITIAL_RTT; + alarm_duration = 2 * DEFAULT_INITIAL_RTT; } else { alarm_duration = 2 * this->_smoothed_rtt; } - alarm_duration = std::max(alarm_duration, this->_MIN_TLP_TIMEOUT); + alarm_duration = std::max(alarm_duration, MIN_TLP_TIMEOUT); alarm_duration = alarm_duration * (1 << this->_handshake_count); QUICLDDebug("Handshake retransmission alarm will be set"); } else if (this->_loss_time != 0) { // Early retransmit timer or time loss detection. - alarm_duration = this->_loss_time - Thread::get_hrtime(); + alarm_duration = this->_loss_time - this->_time_of_last_sent_packet; QUICLDDebug("Early retransmit timer or time loss detection will be set"); - } else if (this->_tlp_count < this->_MAX_TLPS) { + } else if (this->_tlp_count < MAX_TLPS) { // Tail Loss Probe - if (this->_retransmittable_outstanding) { - alarm_duration = 1.5 * this->_smoothed_rtt + this->_DELAYED_ACK_TIMEOUT; - } else { - alarm_duration = this->_MIN_TLP_TIMEOUT; - } - alarm_duration = std::max(alarm_duration, 2 * this->_smoothed_rtt); + alarm_duration = std::max(static_cast(1.5 * this->_smoothed_rtt + this->_max_ack_delay), MIN_TLP_TIMEOUT); QUICLDDebug("TLP alarm will be set"); } else { // RTO alarm alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar; - alarm_duration = std::max(alarm_duration, this->_MIN_RTO_TIMEOUT); + alarm_duration = std::max(alarm_duration, MIN_RTO_TIMEOUT); alarm_duration = alarm_duration * (1 << this->_rto_count); QUICLDDebug("RTO alarm will be set"); } @@ -338,7 +266,7 @@ QUICLossDetector::_set_loss_detection_alarm() if (this->_loss_detection_alarm_at) { this->_loss_detection_alarm_at = std::min(this->_loss_detection_alarm_at, Thread::get_hrtime() + alarm_duration); } else { - this->_loss_detection_alarm_at = Thread::get_hrtime() + alarm_duration; + this->_loss_detection_alarm_at = this->_time_of_last_sent_packet + alarm_duration; } QUICLDDebug("Loss detection alarm has been set to %" PRId64, alarm_duration); @@ -347,26 +275,77 @@ QUICLossDetector::_set_loss_detection_alarm() } } -std::set -QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame) +void +QUICLossDetector::_on_loss_detection_alarm() { - std::set packets; - QUICPacketNumber x = ack_frame.largest_acknowledged(); - for (uint64_t i = 0; i <= ack_frame.ack_block_section()->first_ack_block_length(); ++i) { - packets.insert(x--); + if (this->_handshake_outstanding) { + // Handshake retransmission alarm. + this->_retransmit_handshake_packets(); + this->_handshake_count++; + } else if (this->_loss_time != 0) { + // Early retransmit or Time Loss Detection + this->_detect_lost_packets(this->_largest_acked_packet); + } else if (this->_tlp_count < MAX_TLPS) { + // Tail Loss Probe. + QUICLDDebug("TLP"); + this->_send_one_packet(); + this->_tlp_count++; + } else { + // RTO. + if (this->_rto_count == 0) { + this->_largest_sent_before_rto = this->_largest_sent_packet; + } + QUICLDDebug("RTO"); + this->_send_two_packets(); + this->_rto_count++; } - for (auto &&block : *(ack_frame.ack_block_section())) { - for (uint64_t i = 0; i <= block.gap(); ++i) { - x--; + QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), + this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); + this->_set_loss_detection_alarm(); +} + +void +QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_number) +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + this->_loss_time = 0; + std::set lost_packets; + double delay_until_lost = INFINITY; + + if (this->_time_loss_detection) { + delay_until_lost = (1 + this->_time_reordering_fraction) * std::max(this->_latest_rtt, this->_smoothed_rtt); + } else if (largest_acked_packet_number == this->_largest_sent_packet) { + // Early retransmit alarm. + delay_until_lost = 5 / 4 * std::max(this->_latest_rtt, this->_smoothed_rtt); + } + + for (auto &unacked : this->_sent_packets) { + if (unacked.first >= largest_acked_packet_number) { + break; } - for (uint64_t i = 0; i <= block.length(); ++i) { - packets.insert(x--); + ink_hrtime time_since_sent = Thread::get_hrtime() - unacked.second->time; + uint64_t packet_delta = largest_acked_packet_number - unacked.second->packet_number; + if (time_since_sent > delay_until_lost) { + lost_packets.insert(unacked.first); + } else if (packet_delta > this->_reordering_threshold) { + lost_packets.insert(unacked.first); + } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) { + this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent; } } - return packets; + // Inform the congestion controller of lost packets and + // lets it decide whether to retransmit immediately. + if (!lost_packets.empty()) { + this->_cc->on_packets_lost(lost_packets); + for (auto packet_number : lost_packets) { + this->_remove_from_sent_packet_list(packet_number); + } + } } +// ===== Functions below are used on the spec but there're no pseudo code ===== + void QUICLossDetector::_retransmit_handshake_packets() { @@ -383,9 +362,7 @@ QUICLossDetector::_retransmit_handshake_packets() } for (auto packet_number : retransmitted_handshake_packets) { - this->_sent_packets.erase(packet_number); - --this->_handshake_outstanding; - --this->_retransmittable_outstanding; + this->_remove_from_sent_packet_list(packet_number); } } @@ -418,3 +395,69 @@ QUICLossDetector::_send_two_packets() this->_transmitter->transmit_packet(); } } + +// ===== Functions below are helper functions ===== + +std::set +QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame) +{ + std::set packets; + QUICPacketNumber x = ack_frame.largest_acknowledged(); + for (uint64_t i = 0; i <= ack_frame.ack_block_section()->first_ack_block_length(); ++i) { + packets.insert(x--); + } + for (auto &&block : *(ack_frame.ack_block_section())) { + for (uint64_t i = 0; i <= block.gap(); ++i) { + x--; + } + for (uint64_t i = 0; i <= block.length(); ++i) { + packets.insert(x--); + } + } + + return packets; +} + +void +QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr packet_info) +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + + // Add to the list + this->_sent_packets.insert(std::pair>(packet_number, std::move(packet_info))); + + // Increment counters + auto ite = this->_sent_packets.find(packet_number); + if (ite != this->_sent_packets.end()) { + if (ite->second->handshake) { + ++this->_handshake_outstanding; + ink_assert(this->_handshake_outstanding.load() > 0); + } + if (!ite->second->ack_only) { + ++this->_retransmittable_outstanding; + ink_assert(this->_retransmittable_outstanding.load() > 0); + } + } +} + +void +QUICLossDetector::_remove_from_sent_packet_list(QUICPacketNumber packet_number) +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + + // Decrement counters + auto ite = this->_sent_packets.find(packet_number); + if (ite != this->_sent_packets.end()) { + if (ite->second->handshake) { + ink_assert(this->_handshake_outstanding.load() > 0); + --this->_handshake_outstanding; + } + if (!ite->second->ack_only) { + ink_assert(this->_retransmittable_outstanding.load() > 0); + --this->_retransmittable_outstanding; + } + } + + // Remove from the list + this->_sent_packets.erase(packet_number); +} diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index ce2c62953f1..e67598b8e4e 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -57,7 +57,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler struct PacketInfo { QUICPacketNumber packet_number; ink_hrtime time; - bool retransmittable; + bool ack_only; bool handshake; size_t bytes; QUICPacketUPtr packet; @@ -67,35 +67,32 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler // TODO QUICCongestionController *cc = nullptr; - // 3.2.1. Constants of interest - uint32_t _MAX_TLPS = 2; - uint32_t _REORDERING_THRESHOLD = 3; - double _TIME_REORDERING_FRACTION = 1 / 8; - ink_hrtime _MIN_TLP_TIMEOUT = HRTIME_MSECONDS(10); - ink_hrtime _MIN_RTO_TIMEOUT = HRTIME_MSECONDS(200); - ink_hrtime _DELAYED_ACK_TIMEOUT = HRTIME_MSECONDS(25); - ink_hrtime _DEFAULT_INITIAL_RTT = HRTIME_MSECONDS(100); - - // 3.2.2. Variables of interest + // 3.4.2. Variables of interest (draft-08) + // Keep the order as the same as the spec so that we can see the difference easily. Action *_loss_detection_alarm = nullptr; uint32_t _handshake_count = 0; uint32_t _tlp_count = 0; uint32_t _rto_count = 0; uint32_t _largest_sent_before_rto = 0; + ink_hrtime _time_of_last_sent_packet = 0; uint32_t _largest_sent_packet = 0; uint32_t _largest_acked_packet = 0; - ink_hrtime _time_of_last_sent_packet = 0; ink_hrtime _latest_rtt = 0; ink_hrtime _smoothed_rtt = 0; ink_hrtime _rttvar = 0; + ink_hrtime _min_rtt = 0; + ink_hrtime _max_ack_delay = 0; uint32_t _reordering_threshold; double _time_reordering_fraction; ink_hrtime _loss_time = 0; std::map> _sent_packets; + // These are not defined on the spec but expected to be count + // These counter have to be updated when inserting / erasing packets from _sent_packets with following functions. std::atomic _handshake_outstanding; std::atomic _retransmittable_outstanding; - void _decrement_packet_count(QUICPacketNumber packet_number); + void _add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr packet_info); + void _remove_from_sent_packet_list(QUICPacketNumber packet_number); /* * Because this alarm will be reset on every packet transmission, to reduce number of events, @@ -103,11 +100,11 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler */ ink_hrtime _loss_detection_alarm_at = 0; - void _on_packet_sent(QUICPacketNumber packet_number, bool is_retransmittable, bool is_handshake, size_t sent_bytes, + void _on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes, QUICPacketUPtr packet); void _on_ack_received(const std::shared_ptr &ack_frame); void _on_packet_acked(QUICPacketNumber acked_packet_number); - void _update_rtt(ink_hrtime latest_rtt); + void _update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICPacketNumber largest_acked); void _detect_lost_packets(QUICPacketNumber largest_acked); void _set_loss_detection_alarm(); void _on_loss_detection_alarm(); From ac2e13dcd1c59fb98eeefd3f69505680ebeb0dd2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 22 Dec 2017 11:00:38 +0900 Subject: [PATCH 0280/1313] Wait whole client HTTP/0.9 request on read --- proxy/hq/HQClientTransaction.cc | 34 +++++++++++++++++++++------------ proxy/hq/HQClientTransaction.h | 2 ++ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index d96e84bf756..168dbaeb565 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -354,21 +354,31 @@ HQClientTransaction::_process_read_vio() IOBufferReader *client_vio_reader = this->_stream_io->get_read_buffer_reader(); int64_t bytes_avail = client_vio_reader->read_avail(); + MIOBuffer *writer = this->_read_vio.get_writer(); - // Copy only "GET /path/" - // Check CRLF or LF - int n = 2; - if (bytes_avail > 2 && client_vio_reader->start()[bytes_avail - 2] != '\r') { - n = 1; - } + if (!this->_client_req_header_complete) { + int n = 2; + // Check client request is complete or not + if (bytes_avail < 2 || client_vio_reader->start()[bytes_avail - 1] != '\n') { + return 0; + } + this->_client_req_header_complete = true; + + // Check "CRLF" or "LF" + if (client_vio_reader->start()[bytes_avail - 2] != '\r') { + n = 1; + } - MIOBuffer *writer = this->_read_vio.get_writer(); - writer->write(client_vio_reader, bytes_avail - n); - client_vio_reader->consume(bytes_avail); + writer->write(client_vio_reader, bytes_avail - n); + client_vio_reader->consume(bytes_avail); - // FIXME: Get hostname from SNI? - const char version[] = " HTTP/1.1\r\nHost: localhost\r\n\r\n"; - writer->write(version, sizeof(version)); + // FIXME: Get hostname from SNI? + const char version[] = " HTTP/1.1\r\nHost: localhost\r\n\r\n"; + writer->write(version, sizeof(version)); + } else { + writer->write(client_vio_reader, bytes_avail); + client_vio_reader->consume(bytes_avail); + } return bytes_avail; } diff --git a/proxy/hq/HQClientTransaction.h b/proxy/hq/HQClientTransaction.h index 550f6b3d9d1..7a10e9d10ef 100644 --- a/proxy/hq/HQClientTransaction.h +++ b/proxy/hq/HQClientTransaction.h @@ -74,4 +74,6 @@ class HQClientTransaction : public ProxyClientTransaction VIO _write_vio; Event *_read_event = nullptr; Event *_write_event = nullptr; + + bool _client_req_header_complete = false; }; From c61bbf1231c54c6654f98ab3a3a4b306d2686e9a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Dec 2017 16:30:49 +0900 Subject: [PATCH 0281/1313] Send ACK frames actively --- iocore/net/QUICNetVConnection.cc | 37 +++++++++++++++----------- iocore/net/quic/QUICAckFrameCreator.cc | 16 ++++++++--- iocore/net/quic/QUICAckFrameCreator.h | 9 +++---- iocore/net/quic/QUICFrameTransmitter.h | 2 +- 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b1be90f69b1..1581332ffe4 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -279,20 +279,21 @@ QUICNetVConnection::push_packet(UDPPacket *packet) void QUICNetVConnection::_transmit_frame(QUICFrameUPtr frame) { - QUICConDebug("Frame Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); - SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); - if (frame->type() == QUICFrameType::STREAM) { - QUICStreamFrame &stream_frame = static_cast(*frame); - // XXX: Stream 0 is exempt from the connection-level flow control window. - if (stream_frame.stream_id() == STREAM_ID_FOR_HANDSHAKE) { - this->_frame_send_queue.push(std::move(frame)); + if (frame) { + QUICConDebug("Frame Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); + if (frame->type() == QUICFrameType::STREAM) { + QUICStreamFrame &stream_frame = static_cast(*frame); + // XXX: Stream 0 is exempt from the connection-level flow control window. + if (stream_frame.stream_id() == STREAM_ID_FOR_HANDSHAKE) { + this->_frame_send_queue.push(std::move(frame)); + } else { + this->_stream_frame_send_queue.push(std::move(frame)); + } } else { - this->_stream_frame_send_queue.push(std::move(frame)); + this->_frame_send_queue.push(std::move(frame)); } - } else { - this->_frame_send_queue.push(std::move(frame)); } } @@ -770,6 +771,16 @@ QUICNetVConnection::_packetize_frames() SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); + QUICFrameUPtr ack_frame = QUICFrameFactory::create_null_ack_frame(); + if (this->_frame_send_queue.size() || this->_stream_frame_send_queue.size()) { + ack_frame = this->_ack_frame_creator.create(); + } else { + ack_frame = this->_ack_frame_creator.create_if_needed(); + } + if (ack_frame != nullptr) { + this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(ack_frame)); + } + while (this->_frame_send_queue.size() > 0) { frame = std::move(this->_frame_send_queue.front()); this->_frame_send_queue.pop(); @@ -830,13 +841,9 @@ QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPac if (ret != 0) { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } - // this->_local_flow_controller->forward_limit(); this->_ack_frame_creator.update(packet_num, should_send_ack); - QUICFrameUPtr ack_frame = this->_ack_frame_creator.create_if_needed(); - if (ack_frame != nullptr) { - this->transmit_frame(std::move(ack_frame)); - } + static_cast(this)->transmit_frame(); return error; } diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 8c1dafb1210..4cdc27a6403 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -26,16 +26,20 @@ #include int -QUICAckFrameCreator::update(QUICPacketNumber packet_number, bool acknowledgable) +QUICAckFrameCreator::update(QUICPacketNumber packet_number, bool should_send) { if (this->_packet_numbers.size() == MAXIMUM_PACKET_COUNT) { return -1; } this->_packet_numbers.push_back(packet_number); - if (acknowledgable && !this->_can_send) { + + if (!this->_can_send) { this->_can_send = true; } + if (should_send) { + this->_should_send = true; + } return 0; } @@ -47,6 +51,7 @@ QUICAckFrameCreator::create() if (this->_can_send) { ack_frame = this->_create_ack_frame(); this->_can_send = false; + this->_should_send = false; this->_packet_count = 0; this->_packet_numbers.clear(); } @@ -56,8 +61,11 @@ QUICAckFrameCreator::create() std::unique_ptr QUICAckFrameCreator::create_if_needed() { - // TODO What would be criteria? - return this->create(); + std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); + if (this->_should_send) { + ack_frame = this->create(); + } + return ack_frame; } void diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index da59c5ef121..9dffb93e2c9 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -59,25 +59,24 @@ class QUICAckFrameCreator * All packet numbers ATS received need to be passed to this method. * Returns 0 if updated successfully. */ - int update(QUICPacketNumber packet_number, bool acknowledgable); + int update(QUICPacketNumber packet_number, bool should_send); /* * Returns QUICAckFrame only if ACK frame is able to be sent. * Caller must send the ACK frame to the peer if it was returned. - * Usually you should use create_if_needed() instead, but you may want to - * call this when ATS receives PING frame. */ std::unique_ptr create(); /* * Returns QUICAckFrame only if ACK frame need to be sent, - * because sending an ACK frame per incoming ACK-able packet isn't sufficient. + * because sending an ACK only packet against an ACK only packet is prohibited. * Caller must send the ACK frame to the peer if it was returned. */ std::unique_ptr create_if_needed(); private: - bool _can_send = false; + bool _can_send = false; + bool _should_send = false; QUICAckPacketNumbers _packet_numbers; uint16_t _packet_count = 0; diff --git a/iocore/net/quic/QUICFrameTransmitter.h b/iocore/net/quic/QUICFrameTransmitter.h index 07d782520a3..e3143d137ce 100644 --- a/iocore/net/quic/QUICFrameTransmitter.h +++ b/iocore/net/quic/QUICFrameTransmitter.h @@ -33,6 +33,6 @@ class QUICFrameTransmitter * * This schedules QUIC_PACKET_WRITE_READY event. */ - virtual void transmit_frame(QUICFrameUPtr frame) = 0; + virtual void transmit_frame(QUICFrameUPtr frame = QUICFrameUPtr(nullptr, &QUICFrameDeleter::delete_null_frame)) = 0; virtual uint32_t maximum_stream_frame_data_size() = 0; }; From c644c6c1c46f7c5dd17ca89c7312260f9ef632f6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 22 Dec 2017 11:04:58 +0900 Subject: [PATCH 0282/1313] Translate the pseudo code for congestion control to C++ --- iocore/net/P_QUICNetVConnection.h | 1 - iocore/net/QUICNetVConnection.cc | 1 - iocore/net/quic/QUICCongestionController.cc | 70 ++++++++++++--------- iocore/net/quic/QUICCongestionController.h | 45 ------------- iocore/net/quic/QUICFrameDispatcher.cc | 5 -- iocore/net/quic/QUICLossDetector.cc | 21 ++++--- iocore/net/quic/QUICLossDetector.h | 43 +++++++++---- 7 files changed, 81 insertions(+), 105 deletions(-) delete mode 100644 iocore/net/quic/QUICCongestionController.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 4f4ba371a54..3f9d1c27525 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -54,7 +54,6 @@ #include "quic/QUICAckFrameCreator.h" #include "quic/QUICLossDetector.h" #include "quic/QUICStreamManager.h" -#include "quic/QUICCongestionController.h" #include "quic/QUICApplicationMap.h" // These are included here because older OpenQUIC libraries don't have them. diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 1581332ffe4..124a2924e99 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -116,7 +116,6 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) this->_frame_dispatcher->add_handler(this); this->_frame_dispatcher->add_handler(this->_stream_manager); - this->_frame_dispatcher->add_handler(this->_congestion_controller); this->_frame_dispatcher->add_handler(this->_loss_detector); } diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 3ce8e7636ec..d06c0903bed 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -22,55 +22,63 @@ */ #include -#include +#include -static constexpr char tag[] = "quic_congestion_controller"; +// 4.7.1. Constants of interest +constexpr static uint16_t DEFAULT_MSS = 1460; +constexpr static uint32_t INITIAL_WINDOW = 10 * DEFAULT_MSS; +constexpr static uint32_t MINIMUM_WINDOW = 2 * DEFAULT_MSS; +constexpr static double LOSS_REDUCTION_FACTOR = 0.5; -std::vector -QUICCongestionController::interests() +QUICCongestionController::QUICCongestionController() { - return {QUICFrameType::ACK, QUICFrameType::STREAM}; -} - -QUICErrorUPtr -QUICCongestionController::handle_frame(std::shared_ptr frame) -{ - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - - switch (frame->type()) { - case QUICFrameType::STREAM: - case QUICFrameType::ACK: - break; - default: - Debug(tag, "Unexpected frame type: %02x", static_cast(frame->type())); - ink_assert(false); - break; - } - - return error; + this->_congestion_window = INITIAL_WINDOW; } void -QUICCongestionController::on_packet_sent(size_t sent_bytes) +QUICCongestionController::on_packet_sent(size_t bytes_sent) { + this->_bytes_in_flight += bytes_sent; } void -QUICCongestionController::on_packet_acked(QUICPacketNumber acked_packet_number) +QUICCongestionController::on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size) { + // Remove from bytes_in_flight. + this->_bytes_in_flight -= acked_packet_size; + if (acked_packet_number < this->_end_of_recovery) { + // Do not increase congestion window in recovery period. + return; + } + if (this->_congestion_window < this->_ssthresh) { + // Slow start. + this->_congestion_window += acked_packet_size; + } else { + // Congestion avoidance. + this->_congestion_window += DEFAULT_MSS * acked_packet_size / this->_congestion_window; + } } void -QUICCongestionController::on_packets_lost(std::set packets) +QUICCongestionController::on_packets_lost(std::map lost_packets) { + // Remove lost packets from bytes_in_flight. + for (auto &lost_packet : lost_packets) { + this->_bytes_in_flight -= lost_packet.second.bytes; + } + QUICPacketNumber largest_lost_packet = lost_packets.rbegin()->first; + // Start a new recovery epoch if the lost packet is larger + // than the end of the previous recovery epoch. + if (this->_end_of_recovery < largest_lost_packet) { + this->_end_of_recovery = largest_lost_packet; + this->_congestion_window *= LOSS_REDUCTION_FACTOR; + this->_congestion_window = std::max(this->_congestion_window, MINIMUM_WINDOW); + this->_ssthresh = this->_congestion_window; + } } void QUICCongestionController::on_retransmission_timeout_verified() { -} - -void -QUICCongestionController::on_rto_verified() -{ + this->_congestion_window = MINIMUM_WINDOW; } diff --git a/iocore/net/quic/QUICCongestionController.h b/iocore/net/quic/QUICCongestionController.h deleted file mode 100644 index 79cb96ae39c..00000000000 --- a/iocore/net/quic/QUICCongestionController.h +++ /dev/null @@ -1,45 +0,0 @@ -/** @file - * - * A brief file description - * - * @section license License - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include "QUICTypes.h" -#include "QUICFrameHandler.h" - -// TODO Implement congestion controll. -// Congestion controller will be required after the 2nd implementation draft. -class QUICCongestionController : public QUICFrameHandler -{ -public: - virtual std::vector interests() override; - virtual QUICErrorUPtr handle_frame(std::shared_ptr) override; - - void on_packet_sent(size_t sent_bytes); - void on_packet_acked(QUICPacketNumber acked_packet_number); - virtual void on_packets_lost(std::set packets); - void on_rto_verified(); - void on_retransmission_timeout_verified(); - -private: -}; diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index c23fff10328..b4582b9a562 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -22,11 +22,6 @@ */ #include "QUICFrameDispatcher.h" -#include "QUICConnection.h" -#include "QUICStreamManager.h" -#include "QUICCongestionController.h" -#include "QUICLossDetector.h" -#include "QUICEvents.h" #include "QUICDebugNames.h" static constexpr char tag[] = "quic_frame_handler"; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 7edd1819c76..f99fc320d74 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -169,7 +169,10 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac // Find all newly acked packets. for (auto acked_packet_number : this->_determine_newly_acked_packets(*ack_frame)) { - this->_on_packet_acked(acked_packet_number); + auto pi = this->_sent_packets.find(acked_packet_number); + if (pi != this->_sent_packets.end()) { + this->_on_packet_acked(pi->first, pi->second->bytes); + } } QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), @@ -208,11 +211,11 @@ QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICP } void -QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number) +QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number); - this->_cc->on_packet_acked(acked_packet_number); + // QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number); + this->_cc->on_packet_acked(acked_packet_number, acked_packet_size); // If a packet sent prior to RTO was acked, then the RTO // was spurious. Otherwise, inform congestion control. if (this->_rto_count > 0 && acked_packet_number > this->_largest_sent_before_rto) { @@ -309,7 +312,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); this->_loss_time = 0; - std::set lost_packets; + std::map lost_packets; double delay_until_lost = INFINITY; if (this->_time_loss_detection) { @@ -326,9 +329,9 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num ink_hrtime time_since_sent = Thread::get_hrtime() - unacked.second->time; uint64_t packet_delta = largest_acked_packet_number - unacked.second->packet_number; if (time_since_sent > delay_until_lost) { - lost_packets.insert(unacked.first); + lost_packets.insert({unacked.first, *unacked.second}); } else if (packet_delta > this->_reordering_threshold) { - lost_packets.insert(unacked.first); + lost_packets.insert({unacked.first, *unacked.second}); } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) { this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent; } @@ -338,8 +341,8 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num // lets it decide whether to retransmit immediately. if (!lost_packets.empty()) { this->_cc->on_packets_lost(lost_packets); - for (auto packet_number : lost_packets) { - this->_remove_from_sent_packet_list(packet_number); + for (auto lost_packet : lost_packets) { + this->_remove_from_sent_packet_list(lost_packet.first); } } } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index e67598b8e4e..94b707de310 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -31,13 +31,39 @@ #include "../../eventsystem/I_Action.h" #include "ts/ink_hrtime.h" #include "I_VConnection.h" -#include "P_Net.h" #include "QUICTypes.h" #include "QUICPacket.h" #include "QUICFrame.h" #include "QUICFrameHandler.h" #include "QUICPacketTransmitter.h" -#include "QUICCongestionController.h" + +struct PacketInfo { + QUICPacketNumber packet_number; + ink_hrtime time; + bool ack_only; + bool handshake; + size_t bytes; + QUICPacketUPtr packet; +}; + +class QUICCongestionController +{ +public: + QUICCongestionController(); + virtual ~QUICCongestionController() {} + + void on_packet_sent(size_t bytes_sent); + void on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size); + virtual void on_packets_lost(std::map packets); + void on_retransmission_timeout_verified(); + +private: + // 4.7.2. Variables of interest + uint32_t _bytes_in_flight = 0; + uint32_t _congestion_window = 0; + QUICPacketNumber _end_of_recovery = 0; + uint32_t _ssthresh = UINT32_MAX; +}; class QUICLossDetector : public Continuation, public QUICFrameHandler { @@ -54,16 +80,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler private: QUICConnectionId _connection_id = 0; - struct PacketInfo { - QUICPacketNumber packet_number; - ink_hrtime time; - bool ack_only; - bool handshake; - size_t bytes; - QUICPacketUPtr packet; - }; - - bool _time_loss_detection = false; + bool _time_loss_detection = true; // TODO QUICCongestionController *cc = nullptr; @@ -103,7 +120,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes, QUICPacketUPtr packet); void _on_ack_received(const std::shared_ptr &ack_frame); - void _on_packet_acked(QUICPacketNumber acked_packet_number); + void _on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size); void _update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICPacketNumber largest_acked); void _detect_lost_packets(QUICPacketNumber largest_acked); void _set_loss_detection_alarm(); From 0dc38c4ac27c8751681292a1a635cbca0a72bbfe Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 22 Dec 2017 11:34:36 +0900 Subject: [PATCH 0283/1313] Don't retransmit version negotiation packets This fixes #2977 --- iocore/net/quic/QUICLossDetector.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index f99fc320d74..616108cd5af 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -123,6 +123,10 @@ QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) bool is_handshake = false; QUICPacketType type = packet->type(); + if (type == QUICPacketType::VERSION_NEGOTIATION) { + return; + } + if (type == QUICPacketType::INITIAL || type == QUICPacketType::HANDSHAKE) { is_handshake = true; } @@ -130,7 +134,7 @@ QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) QUICPacketNumber packet_number = packet->packet_number(); bool is_ack_only = !packet->is_retransmittable(); size_t sent_bytes = packet->size(); - return this->_on_packet_sent(packet_number, is_ack_only, is_handshake, sent_bytes, std::move(packet)); + this->_on_packet_sent(packet_number, is_ack_only, is_handshake, sent_bytes, std::move(packet)); } void From 74061b16162994b2518053d7281a6b5e9c5882c4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 22 Dec 2017 16:17:09 +0900 Subject: [PATCH 0284/1313] Add getUInt8 and getUInt16 to QUICTransportParameter --- iocore/net/quic/QUICTransportParameters.cc | 24 ++++++++++++++++++++++ iocore/net/quic/QUICTransportParameters.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 2e486d7a300..c81b5f66df1 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -200,6 +200,30 @@ QUICTransportParameters::getAsBytes(QUICTransportParameterId tpid, uint16_t &len return nullptr; } +uint8_t +QUICTransportParameters::getAsUInt8(QUICTransportParameterId tpid) const +{ + uint16_t len = 0; + const uint8_t *value = this->getAsBytes(tpid, len); + if (value) { + return QUICTypeUtil::read_nbytes_as_uint(value, 1); + } else { + return 0; + } +} + +uint16_t +QUICTransportParameters::getAsUInt16(QUICTransportParameterId tpid) const +{ + uint16_t len = 0; + const uint8_t *value = this->getAsBytes(tpid, len); + if (value) { + return QUICTypeUtil::read_nbytes_as_uint(value, 2); + } else { + return 0; + } +} + uint32_t QUICTransportParameters::getAsUInt32(QUICTransportParameterId tpid) const { diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 00e08fd20c6..8b3480548e9 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -75,6 +75,8 @@ class QUICTransportParameters bool is_valid() const; const uint8_t *getAsBytes(QUICTransportParameterId id, uint16_t &len) const; + uint8_t getAsUInt8(QUICTransportParameterId id) const; + uint32_t getAsUInt16(QUICTransportParameterId id) const; uint32_t getAsUInt32(QUICTransportParameterId id) const; void set(QUICTransportParameterId id, const uint8_t *value, uint16_t value_len); From 24d344d4dd3847224458c8f51885d485c84c15b2 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 22 Dec 2017 17:02:43 +0900 Subject: [PATCH 0285/1313] Ack delay field can be 64bit value --- iocore/net/quic/QUICAckFrameCreator.cc | 14 ++++++++++++-- iocore/net/quic/QUICAckFrameCreator.h | 1 + iocore/net/quic/QUICFrame.cc | 2 +- iocore/net/quic/QUICFrame.h | 4 ++-- iocore/net/quic/QUICLossDetector.cc | 7 +++++-- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 4cdc27a6403..9c81166c36a 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -97,7 +97,7 @@ QUICAckFrameCreator::_create_ack_frame() if (ack_frame) { ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { - uint16_t delay = (Thread::get_hrtime() - this->_packet_numbers.largest_ack_received_time()) / 1000; // TODO Milliseconds? + uint64_t delay = this->_calculate_delay(); ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1); } @@ -109,12 +109,22 @@ QUICAckFrameCreator::_create_ack_frame() if (ack_frame) { ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { - uint16_t delay = (Thread::get_hrtime() - this->_packet_numbers.largest_ack_received_time()) / 1000; // TODO Milliseconds? + uint64_t delay = this->_calculate_delay(); ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1); } return ack_frame; } +uint64_t +QUICAckFrameCreator::_calculate_delay() +{ + // Ack delay is in microseconds and scaled + uint64_t delay = (Thread::get_hrtime() - this->_packet_numbers.largest_ack_received_time()) / 1000; + // FXIME ack delay exponent has to be read from transport parameters + uint8_t ack_delay_exponent = 3; + return delay >> ack_delay_exponent; +} + void QUICAckPacketNumbers::push_back(QUICPacketNumber packet_number) { diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 9dffb93e2c9..5a8e7995b4f 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -83,4 +83,5 @@ class QUICAckFrameCreator void _sort_packet_numbers(); std::unique_ptr _create_ack_frame(); + uint64_t _calculate_delay(); }; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 93d894c5cfc..6bd356374c8 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -313,7 +313,7 @@ QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) this->reset(buf, len); } -QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint16_t ack_delay, uint64_t first_ack_block_length) +QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block_length) { this->_largest_acknowledged = largest_acknowledged; this->_ack_delay = ack_delay; diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index df5bf751239..c0cfad75ec2 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -36,7 +36,7 @@ class QUICFrame public: QUICFrame(const uint8_t *buf, size_t len) : _buf(buf), _len(len){}; virtual QUICFrameType type() const; - virtual size_t size() const = 0; + virtual size_t size() const = 0; virtual void store(uint8_t *buf, size_t *len) const = 0; virtual void reset(const uint8_t *buf, size_t len); static QUICFrameType type(const uint8_t *buf); @@ -724,7 +724,7 @@ class QUICFrameFactory * need to ack. */ static std::unique_ptr create_ack_frame(QUICPacketNumber largest_acknowledged, - uint16_t ack_delay, uint64_t first_ack_block_length); + uint64_t ack_delay, uint64_t first_ack_block_length); /* * Creates a CONNECTION_CLOSE frame. */ diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 616108cd5af..c1bd993b44c 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -164,8 +164,11 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac auto pi = this->_sent_packets.find(ack_frame->largest_acknowledged()); if (pi != this->_sent_packets.end()) { this->_latest_rtt = Thread::get_hrtime() - pi->second->time; - // _latest_rtt is nanosecond but ack_frame->ack_delay is millisecond - this->_update_rtt(this->_latest_rtt, HRTIME_MSECONDS(ack_frame->ack_delay()), ack_frame->largest_acknowledged()); + // _latest_rtt is nanosecond but ack_frame->ack_delay is microsecond and scaled + // FIXME ack delay exponent has to be read from transport parameters + uint8_t ack_delay_exponent = 3; + ink_hrtime delay = HRTIME_USECONDS(ack_frame->ack_delay() << ack_delay_exponent); + this->_update_rtt(this->_latest_rtt, delay, ack_frame->largest_acknowledged()); } QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), From f584c8b37a5f08c37c6135ecb5564e1104026ff2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Sun, 24 Dec 2017 22:07:27 +0900 Subject: [PATCH 0286/1313] Fix build errors --- iocore/net/quic/QUICFrame.cc | 2 +- iocore/net/quic/QUICFrame.h | 2 +- iocore/net/quic/QUICTransportParameters.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 6bd356374c8..252d57c4b2f 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1835,7 +1835,7 @@ QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUIC } std::unique_ptr -QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint16_t ack_delay, uint64_t first_ack_block_length) +QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block_length) { QUICAckFrame *frame = quicAckFrameAllocator.alloc(); new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block_length); diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index c0cfad75ec2..342defadf91 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -163,7 +163,7 @@ class QUICAckFrame : public QUICFrame QUICAckFrame() : QUICFrame() {} QUICAckFrame(const uint8_t *buf, size_t len); - QUICAckFrame(QUICPacketNumber largest_acknowledged, uint16_t ack_delay, uint64_t first_ack_block_length); + QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block_length); virtual ~QUICAckFrame(); virtual void reset(const uint8_t *buf, size_t len) override; diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 8b3480548e9..6bb052e791f 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -76,7 +76,7 @@ class QUICTransportParameters const uint8_t *getAsBytes(QUICTransportParameterId id, uint16_t &len) const; uint8_t getAsUInt8(QUICTransportParameterId id) const; - uint32_t getAsUInt16(QUICTransportParameterId id) const; + uint16_t getAsUInt16(QUICTransportParameterId id) const; uint32_t getAsUInt32(QUICTransportParameterId id) const; void set(QUICTransportParameterId id, const uint8_t *value, uint16_t value_len); From cba3193ceadadde8612966b657fd54138a8bb5ee Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 26 Dec 2017 09:52:44 +0900 Subject: [PATCH 0287/1313] Fix build errors of unit tests (tests for QUICLossDetector is FAIL) --- iocore/net/quic/Mock.h | 17 ++++------------- .../net/quic/test/test_QUICFrameDispatcher.cc | 11 +++-------- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index ff68b773791..b66074abdad 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -20,10 +20,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "P_Net.h" #include "QUICApplication.h" #include "QUICStreamManager.h" -#include "QUICCongestionController.h" #include "QUICLossDetector.h" #include "QUICEvents.h" #include "QUICPacketTransmitter.h" @@ -327,20 +327,11 @@ class MockQUICCongestionController : public QUICCongestionController { public: // Override - virtual QUICErrorUPtr - handle_frame(std::shared_ptr f) override - { - ++_frameCount[static_cast(f->type())]; - ++_totalFrameCount; - - return QUICErrorUPtr(new QUICNoError()); - } - virtual void - on_packets_lost(std::set packets) override + on_packets_lost(std::map packets) override { - for (auto pn : packets) { - lost_packets.insert(pn); + for (auto &p : packets) { + lost_packets.insert(p.first); } } diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 215303fa84e..5d90c777562 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -35,20 +35,17 @@ TEST_CASE("QUICFrameHandler", "[quic]") QUICStreamFrame streamFrame(std::move(payload), 1, 0x03, 0); - auto connection = new MockQUICConnection(); - auto streamManager = new MockQUICStreamManager(); - auto congestionController = new MockQUICCongestionController(); - auto lossDetector = new MockQUICLossDetector(); + auto connection = new MockQUICConnection(); + auto streamManager = new MockQUICStreamManager(); + auto lossDetector = new MockQUICLossDetector(); QUICFrameDispatcher quicFrameDispatcher; quicFrameDispatcher.add_handler(connection); quicFrameDispatcher.add_handler(streamManager); - quicFrameDispatcher.add_handler(congestionController); quicFrameDispatcher.add_handler(lossDetector); // Initial state CHECK(connection->getTotalFrameCount() == 0); CHECK(streamManager->getTotalFrameCount() == 0); - CHECK(congestionController->getTotalFrameCount() == 0); // STREAM frame uint8_t buf[4096] = {0}; @@ -58,7 +55,6 @@ TEST_CASE("QUICFrameHandler", "[quic]") quicFrameDispatcher.receive_frames(buf, len, should_send_ack); CHECK(connection->getTotalFrameCount() == 0); CHECK(streamManager->getTotalFrameCount() == 1); - CHECK(congestionController->getTotalFrameCount() == 1); // CONNECTION_CLOSE frame QUICConnectionCloseFrame connectionCloseFrame({}); @@ -66,5 +62,4 @@ TEST_CASE("QUICFrameHandler", "[quic]") quicFrameDispatcher.receive_frames(buf, len, should_send_ack); CHECK(connection->getTotalFrameCount() == 1); CHECK(streamManager->getTotalFrameCount() == 1); - CHECK(congestionController->getTotalFrameCount() == 1); } From d82803897529df721f38ac054aa01467e9ef9404 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 28 Dec 2017 11:56:03 +0900 Subject: [PATCH 0288/1313] Add QUICHandshake test & refactoring --- .gitignore | 15 +- iocore/net/quic/Mock.h | 42 ++++ iocore/net/quic/QUICApplication.cc | 7 +- iocore/net/quic/QUICApplication.h | 14 +- iocore/net/quic/QUICHandshake.cc | 213 ++++++++++++++------- iocore/net/quic/QUICHandshake.h | 37 ++-- iocore/net/quic/QUICStream.h | 4 +- iocore/net/quic/test/Makefile.am | 29 ++- iocore/net/quic/test/server_cert.h | 73 +++++++ iocore/net/quic/test/test_QUICCrypto.cc | 49 +---- iocore/net/quic/test/test_QUICHandshake.cc | 94 +++++++++ 11 files changed, 424 insertions(+), 153 deletions(-) create mode 100644 iocore/net/quic/test/server_cert.h create mode 100644 iocore/net/quic/test/test_QUICHandshake.cc diff --git a/.gitignore b/.gitignore index e50a04b9554..f1a64f562c1 100644 --- a/.gitignore +++ b/.gitignore @@ -89,22 +89,23 @@ lib/perl/lib/Apache/TS.pm iocore/net/test_certlookup iocore/net/test_UDPNet +iocore/net/quic/test/test_QUICAckFrameCreator +iocore/net/quic/test/test_QUICCrypto +iocore/net/quic/test/test_QUICFlowController iocore/net/quic/test/test_QUICFrame iocore/net/quic/test/test_QUICFrameDispatcher +iocore/net/quic/test/test_QUICLossDetector +iocore/net/quic/test/test_QUICHandshake +iocore/net/quic/test/test_QUICIncomingFrameBuffer +iocore/net/quic/test/test_QUICKeyGenerator iocore/net/quic/test/test_QUICPacket iocore/net/quic/test/test_QUICPacketFactory iocore/net/quic/test/test_QUICStream -iocore/net/quic/test/test_QUICStreamState iocore/net/quic/test/test_QUICStreamManager +iocore/net/quic/test/test_QUICStreamState iocore/net/quic/test/test_QUICTransportParameters -iocore/net/quic/test/test_QUICKeyGenerator -iocore/net/quic/test/test_QUICCrypto -iocore/net/quic/test/test_QUICLossDetector iocore/net/quic/test/test_QUICTypeUtil -iocore/net/quic/test/test_QUICAckFrameCreator iocore/net/quic/test/test_QUICVersionNegotiator -iocore/net/quic/test/test_QUICFlowController -iocore/net/quic/test/test_QUICIncomingFrameBuffer iocore/net/quic/ts_quic_client iocore/aio/test_AIO iocore/eventsystem/test_Buffer diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index b66074abdad..a25fea87127 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -406,6 +406,48 @@ class MockQUICApplication : public QUICApplication } }; +class MockQUICStream : public QUICStream +{ +private: + int64_t + _process_read_vio() override + { + return 0; + } + + int64_t + _process_write_vio() override + { + return 0; + } +}; + +class MockQUICStreamIO : public QUICStreamIO +{ +public: + MockQUICStreamIO(QUICApplication *app, QUICStream *stream) : QUICStreamIO(app, stream) {} + ~MockQUICStreamIO() {} + + int64_t + transfer() + { + int64_t n = this->_write_buffer_reader->read_avail(); + this->_read_buffer->write(this->_write_buffer_reader, n); + this->_write_buffer_reader->consume(n); + return n; + } + +private: + void + read_reenable() override + { + } + void + write_reenable() override + { + } +}; + class MockQUICCrypto : public QUICCrypto { public: diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index ef26055ef9e..b0ab67e976a 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -132,9 +132,11 @@ QUICApplication::QUICApplication(QUICConnection *qc) : Continuation(new_ProxyMut // @brief Bind stream and application void -QUICApplication::set_stream(QUICStream *stream) +QUICApplication::set_stream(QUICStream *stream, QUICStreamIO *stream_io) { - QUICStreamIO *stream_io = new QUICStreamIO(this, stream); + if (stream_io == nullptr) { + stream_io = new QUICStreamIO(this, stream); + } this->_stream_map.insert(std::make_pair(stream->id(), stream_io)); } @@ -166,7 +168,6 @@ QUICApplication::unset_stream(QUICStream *stream) QUICStreamIO *stream_io = this->_find_stream_io(stream->id()); if (stream_io) { this->_stream_map.erase(stream->id()); - delete stream_io; } } diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 0f34c56c0de..f2a47e161ef 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -38,6 +38,7 @@ class QUICStreamIO { public: QUICStreamIO(QUICApplication *app, QUICStream *stream); + virtual ~QUICStreamIO(){}; int64_t read_avail(); bool is_read_avail_more_than(int64_t size); @@ -45,21 +46,22 @@ class QUICStreamIO int64_t write(const uint8_t *buf, int64_t len); int64_t write(IOBufferReader *r, int64_t len = INT64_MAX, int64_t offset = 0); void set_write_vio_nbytes(int64_t); - void read_reenable(); - void write_reenable(); + virtual void read_reenable(); + virtual void write_reenable(); IOBufferReader *get_read_buffer_reader(); void shutdown(); uint32_t get_transaction_id() const; -private: - QUICStream *_stream = nullptr; - +protected: MIOBuffer *_read_buffer = nullptr; MIOBuffer *_write_buffer = nullptr; IOBufferReader *_read_buffer_reader = nullptr; IOBufferReader *_write_buffer_reader = nullptr; +private: + QUICStream *_stream = nullptr; + VIO *_read_vio = nullptr; VIO *_write_vio = nullptr; }; @@ -74,7 +76,7 @@ class QUICApplication : public Continuation QUICApplication(QUICConnection *qc); virtual ~QUICApplication(){}; - void set_stream(QUICStream *stream); + void set_stream(QUICStream *stream, QUICStreamIO *stream_io = nullptr); bool is_stream_set(QUICStream *stream); void reenable(QUICStream *stream); void unset_stream(QUICStream *stream); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 498c0de70f8..c374dd3d7a7 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -89,12 +89,13 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless this->_ssl = SSL_new(ssl_ctx); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_hs_index, this); + this->_netvc_context = qc->direction(); this->_crypto = new QUICCryptoTls(this->_ssl, qc->direction()); this->_version_negotiator = new QUICVersionNegotiator(); this->_crypto->initialize_key_materials(this->_client_qc->original_connection_id()); - SET_HANDLER(&QUICHandshake::state_read_client_hello); + SET_HANDLER(&QUICHandshake::state_initial); } QUICHandshake::~QUICHandshake() @@ -207,17 +208,27 @@ QUICHandshake::remote_transport_parameters() } int -QUICHandshake::state_read_client_hello(int event, Event *data) +QUICHandshake::state_initial(int event, Event *data) { - QUICErrorUPtr error; + QUICHSDebug("event: %d", event); + + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { - error = this->_process_client_hello(); + if (this->_netvc_context == NET_VCONNECTION_IN) { + error = this->_process_client_hello(); + } + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + if (this->_netvc_context == NET_VCONNECTION_OUT) { + error = this->_process_initial(); + } break; } default: - QUICHSDebug("event: %d", event); break; } @@ -231,21 +242,56 @@ QUICHandshake::state_read_client_hello(int event, Event *data) this->_abort_handshake(code); } - return EVENT_CONT; + return EVENT_DONE; } int -QUICHandshake::state_read_client_finished(int event, Event *data) +QUICHandshake::state_key_exchange(int event, Event *data) { + QUICHSDebug("event: %d", event); + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { - error = this->_process_client_finished(); + ink_assert(this->_netvc_context == NET_VCONNECTION_OUT); + + // FIXME: client could recv ServerHello and HelloRetryRequest + error = this->_process_server_hello(); + break; + } + default: + break; + } + + if (error->cls != QUICErrorClass::NONE) { + QUICTransErrorCode code; + if (dynamic_cast(error.get()) != nullptr) { + code = error->trans_error_code; + } else { + code = QUICTransErrorCode::PROTOCOL_VIOLATION; + } + this->_abort_handshake(code); + } + + return EVENT_DONE; +} + +int +QUICHandshake::state_auth(int event, Event *data) +{ + QUICHSDebug("event: %d", event); + + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + ink_assert(this->_netvc_context == NET_VCONNECTION_IN); + + error = this->_process_finished(); break; } default: - QUICHSDebug("event: %d", event); break; } @@ -266,7 +312,7 @@ int QUICHandshake::state_address_validation(int event, void *data) { // TODO Address validation should be implemented for the 2nd implementation draft - return EVENT_CONT; + return EVENT_DONE; } int @@ -275,13 +321,13 @@ QUICHandshake::state_complete(int event, void *data) QUICHSDebug("%s", get_vc_event_name(event)); QUICHSDebug("Got an event on complete state. Ignoring it for now."); - return EVENT_CONT; + return EVENT_DONE; } int QUICHandshake::state_closed(int event, void *data) { - return EVENT_CONT; + return EVENT_DONE; } void @@ -308,40 +354,34 @@ QUICHandshake::_load_local_transport_parameters(QUICVersion negotiated_version) } QUICErrorUPtr -QUICHandshake::_process_client_hello() +QUICHandshake::_do_handshake(bool initial) { + // TODO: pass stream_io QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); - // Complete message should fit in a packet and be able to read - uint8_t msg[UDP_MAXIMUM_PAYLOAD_SIZE] = {0}; - int64_t msg_len = stream_io->read_avail(); - stream_io->read(msg, msg_len); + uint8_t in[UDP_MAXIMUM_PAYLOAD_SIZE] = {0}; + int64_t in_len = 0; - if (msg_len <= 0) { - QUICHSDebug("No message"); - return QUICErrorUPtr(new QUICNoError()); - } + if (!initial) { + // Complete message should fit in a packet and be able to read + in_len = stream_io->read_avail(); + stream_io->read(in, in_len); - // ----- DEBUG -----> - I_WANNA_DUMP_THIS_BUF(msg, msg_len); - // <----- DEBUG ----- + if (in_len <= 0) { + QUICHSDebug("No message"); + return QUICErrorUPtr(new QUICNoError()); + } + I_WANNA_DUMP_THIS_BUF(in, in_len); + } - uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t server_hello_len = 0; - bool result = false; - result = this->_crypto->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, msg, msg_len); + uint8_t out[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t out_len = 0; + bool result = false; + result = this->_crypto->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, in, in_len); if (result) { - // ----- DEBUG -----> - I_WANNA_DUMP_THIS_BUF(server_hello, static_cast(server_hello_len)); - // <----- DEBUG ----- - - QUICHSDebug("Enter state_read_client_finished"); - SET_HANDLER(&QUICHandshake::state_read_client_finished); - - stream_io->write(server_hello, server_hello_len); - stream_io->write_reenable(); - stream_io->read_reenable(); + I_WANNA_DUMP_THIS_BUF(out, static_cast(out_len)); + stream_io->write(out, out_len); return QUICErrorUPtr(new QUICNoError()); } else { @@ -350,66 +390,97 @@ QUICHandshake::_process_client_hello() } QUICErrorUPtr -QUICHandshake::_process_client_finished() +QUICHandshake::_process_initial() { - QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); - - // Complete message should fit in a packet and be able to read - uint8_t msg[UDP_MAXIMUM_PAYLOAD_SIZE] = {0}; - int64_t msg_len = stream_io->read_avail(); - stream_io->read(msg, msg_len); + QUICErrorUPtr error = _do_handshake(true); - if (msg_len <= 0) { - QUICHSDebug("No message"); - return QUICErrorUPtr(new QUICNoError()); + if (error->cls == QUICErrorClass::NONE) { + QUICHSDebug("Enter state_key_exchange"); + SET_HANDLER(&QUICHandshake::state_key_exchange); } - // ----- DEBUG -----> - I_WANNA_DUMP_THIS_BUF(msg, msg_len); - // <----- DEBUG ----- - - uint8_t out[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t out_len = 0; - bool result = false; - result = this->_crypto->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, msg, msg_len); - - if (result) { - // ----- DEBUG -----> - I_WANNA_DUMP_THIS_BUF(out, static_cast(out_len)); - // <----- DEBUG ----- + return error; +} - _process_handshake_complete(); - QUICHSDebug("Handshake has been completed"); +QUICErrorUPtr +QUICHandshake::_process_client_hello() +{ + QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); + QUICErrorUPtr error = _do_handshake(); - QUICHSDebug("Enter state_complete"); - SET_HANDLER(&QUICHandshake::state_complete); + if (error->cls == QUICErrorClass::NONE) { + QUICHSDebug("Enter state_auth"); + SET_HANDLER(&QUICHandshake::state_auth); - stream_io->write(out, out_len); stream_io->write_reenable(); + } else { stream_io->read_reenable(); + } - return QUICErrorUPtr(new QUICNoError()); + return error; +} + +QUICErrorUPtr +QUICHandshake::_process_server_hello() +{ + QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); + QUICErrorUPtr error = _do_handshake(); + + if (error->cls == QUICErrorClass::NONE) { + int res = this->_complete_handshake(); + if (res) { + stream_io->write_reenable(); + } else { + this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); + } } else { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); + stream_io->read_reenable(); } + + return error; } QUICErrorUPtr -QUICHandshake::_process_handshake_complete() +QUICHandshake::_process_finished() +{ + QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); + QUICErrorUPtr error = _do_handshake(); + + if (error->cls == QUICErrorClass::NONE) { + int res = this->_complete_handshake(); + if (res) { + stream_io->write_reenable(); + } else { + this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); + } + } else { + stream_io->read_reenable(); + } + + return error; +} + +int +QUICHandshake::_complete_handshake() { - if (this->_crypto->update_key_materials()) { + QUICHSDebug("Enter state_complete"); + SET_HANDLER(&QUICHandshake::state_complete); + + int res = this->_crypto->update_key_materials(); + if (res) { QUICHSDebug("Keying Materials are exported"); } else { QUICHSDebug("Failed to export Keying Materials"); } - return QUICErrorUPtr(new QUICNoError()); + return res; } void QUICHandshake::_abort_handshake(QUICTransErrorCode code) { this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(code))); + QUICHSDebug("Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); } diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 773263866c5..23fa4d2ec91 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -31,19 +31,20 @@ * @brief Do handshake as a QUIC application * @detail * - * state_read_client_hello() - * | | _process_client_hello() - * | v - * | state_read_client_finished() - * | | | _process_client_finished() - * | / | _process_handshake_complete() - * | v - * | state_complete() - * | + * # client + * state_initial() * v - * state_closed() + * state_key_exchange() + * v + * state_complete() + * + * # server + * state_initial() + * v + * state_auth() + * v + * state_complete() */ - class QUICVersionNegotiator; class SSLNextProtocolSet; @@ -56,9 +57,10 @@ class QUICHandshake : public QUICApplication QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); // States - int state_read_client_hello(int event, Event *data); - int state_read_client_finished(int event, Event *data); + int state_initial(int event, Event *data); + int state_key_exchange(int event, Event *data); int state_address_validation(int event, void *data); + int state_auth(int event, Event *data); int state_complete(int event, void *data); int state_closed(int event, void *data); @@ -84,11 +86,16 @@ class QUICHandshake : public QUICApplication void _load_local_transport_parameters(QUICVersion negotiated_version); + QUICErrorUPtr _do_handshake(bool initial = false); + + QUICErrorUPtr _process_initial(); QUICErrorUPtr _process_client_hello(); - QUICErrorUPtr _process_client_finished(); - QUICErrorUPtr _process_handshake_complete(); + QUICErrorUPtr _process_server_hello(); + QUICErrorUPtr _process_finished(); + int _complete_handshake(); void _abort_handshake(QUICTransErrorCode code); QUICStatelessResetToken _reset_token; + NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; }; diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 387e83ccdb2..fb713865831 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -82,8 +82,8 @@ class QUICStream : public VConnection LINK(QUICStream, link); private: - int64_t _process_read_vio(); - int64_t _process_write_vio(); + virtual int64_t _process_read_vio(); + virtual int64_t _process_write_vio(); void _signal_read_event(); void _signal_write_event(); Event *_send_tracked_event(Event *, int, VIO *); diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index f750fea21e7..7c9a3038576 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -33,7 +33,8 @@ check_PROGRAMS = \ test_QUICAckFrameCreator \ test_QUICVersionNegotiator \ test_QUICFlowController \ - test_QUICIncomingFrameBuffer + test_QUICIncomingFrameBuffer \ + test_QUICHandshake AM_CPPFLAGS += \ @@ -583,6 +584,32 @@ test_QUICIncomingFrameBuffer_LDADD = \ @LIBTCL@ \ @HWLOC_LIBS@ +# +# test_QUICHandshake +# +test_QUICHandshake_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICHandshake_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICHandshake_SOURCES = \ + event_processor_main.cc \ + test_QUICHandshake.cc \ + ../QUICHandshake.cc \ + ../../SSLNextProtocolSet.cc + +test_QUICHandshake_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ + include $(top_srcdir)/build/tidy.mk tidy-local: $(DIST_SOURCES) diff --git a/iocore/net/quic/test/server_cert.h b/iocore/net/quic/test/server_cert.h new file mode 100644 index 00000000000..b19377c81de --- /dev/null +++ b/iocore/net/quic/test/server_cert.h @@ -0,0 +1,73 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +static constexpr char server_crt[] = "-----BEGIN CERTIFICATE-----\n" + "MIIDRjCCAi4CCQDoLSBwQxmcJTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJK\n" + "UDEOMAwGA1UECBMFVG9reW8xDzANBgNVBAcTBk1pbmF0bzEhMB8GA1UEChMYSW50\n" + "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTcw\n" + "MTE4MDEyMzA3WhcNMjcwMTE2MDEyMzA3WjBlMQswCQYDVQQGEwJKUDEOMAwGA1UE\n" + "CBMFVG9reW8xDzANBgNVBAcTBk1pbmF0bzEhMB8GA1UEChMYSW50ZXJuZXQgV2lk\n" + "Z2l0cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB\n" + "AQUAA4IBDwAwggEKAoIBAQC70j62KOWkuqNsDhl+7uqKFS6TMcJYLdYrH1YInwlY\n" + "htOMSMWx2hPSYYBKzVQpLvhe2LPbhLwcVJdq4aqQNjNpxrpxW/YIY5zxCRVgQsgf\n" + "KXiKgUR0G+F3MQHsm1YIqxQU2OeJldIZUBM2YMDp8h1CXTAvGaAZaXsqO9UvR2Zw\n" + "JZJ+GElYNlNwhdStqIM8v1JNFjfO3gWkVqTv+QM4fmpror2pp8CaDrueg4PrSY3Y\n" + "D/WG75rkmlrW26t0Q8fjkn+s/UiQ3V/IkP1+MfrJWH6RL2DGjBv2KfNAik42xWUi\n" + "KXzaNcDFN4hjqVG59O9bPnUDn1wPypY/TXB4iqSAlxupAgMBAAEwDQYJKoZIhvcN\n" + "AQELBQADggEBAKLc+P5YfusNYIkX3YE+gHBVpo95xnoVUcsGr/h1zanCkmsyKkNU\n" + "e2w9xsVnRLgpRfwrnwiaNP/k6cPYt5ePPCJjUfkO7Ql7DCcjLgEp8lrvxMmRIdSg\n" + "LPq+NdityxXYhfaZdGdXjnLLiq3zYL/8aYjjZ8YAZTuu6pBgfGvjcqYLV1ohimrP\n" + "8BW0BbnvedqTyL7tdKjdiWnHE5ObrxnphL2evoStskBr5CLYR4vX7+qp0oVSz2Ol\n" + "nBMV3wXyhHBY1tuT1SK7ajC/ZHrciZosACRV5PC6nKXi3shWOxt76SZV3HcMmFwX\n" + "NQYYTBOlb5U080adFSmP5/6NRzrKwZ3mD2s=\n" + "-----END CERTIFICATE-----\n"; + +static constexpr char server_key[] = "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEpAIBAAKCAQEAu9I+tijlpLqjbA4Zfu7qihUukzHCWC3WKx9WCJ8JWIbTjEjF\n" + "sdoT0mGASs1UKS74Xtiz24S8HFSXauGqkDYzaca6cVv2CGOc8QkVYELIHyl4ioFE\n" + "dBvhdzEB7JtWCKsUFNjniZXSGVATNmDA6fIdQl0wLxmgGWl7KjvVL0dmcCWSfhhJ\n" + "WDZTcIXUraiDPL9STRY3zt4FpFak7/kDOH5qa6K9qafAmg67noOD60mN2A/1hu+a\n" + "5Jpa1turdEPH45J/rP1IkN1fyJD9fjH6yVh+kS9gxowb9inzQIpONsVlIil82jXA\n" + "xTeIY6lRufTvWz51A59cD8qWP01weIqkgJcbqQIDAQABAoIBADI3ShEF6jAavmq7\n" + "clGfqxF0DFnKaf2Nc79fx27SpnsGwTS2mDSu67HJ47UcJK5GIp2pLp04ZdrlOv6W\n" + "izW3aBOV0G9SePtRNrqzBQYRlNPQEKxnV1f7xFJLxgnulhgHNX1FaNI+PkgKQri9\n" + "MZba5rvBkoplPYrNyuJF0P+tBVRiISWDY00PlZ57pQDyOvXzUckAkxmjNzo+86ld\n" + "/NyO+nR45vVKSeIBT5tT67D8wRisZgO/7QKP5sbKYwa7AR4sTEYFwBaFi4Mr6v1T\n" + "kp0KxOFBI+MioFwyK7ZjkoKClrY/K0IPsKfn2vmi6jLpfkA+qCl1JsVhrfVO3KJc\n" + "PXXF4QECgYEA9339GQS2AWSuA/9ZgHFqTTOEEHujCkh9D4mKO4LRi5hKPN9NQKUU\n" + "KgaBXWTbr8FwOTXw6HMl0SaIOdc6VxdzViNvPCpu2Wn8hyTC5Mjs/BtXkXNcBQqs\n" + "tPm0JxgC6fpQAb+gU+zZ+QQNlUWH/CEiQFxxGNzBn9E3Xq2j0StdhPECgYEAwkci\n" + "GiQuM4KMDdwbs4RDlEZyvXxWwgHKPoXv/Uq7HXtuT1FGb/+Rf3BGimMf2Qqmppp8\n" + "MAZ+xk+eXhtqKZHsV2ifhUfuVZ6NPhT2WRyn6MozuHh3MK4l2KtOhxulcoX/2sDk\n" + "dLYclxhXZFuXvbLz2KpgMmPMGyzEQNHQaoTkojkCgYEAxb/wVGY0OybD+EO2su9s\n" + "PaVU94qielvzOU/vmJ9taTnUz5Co/Gcqlm2+Pe6RrnxEfCICjOk8pUJBhN3ZKq99\n" + "I62Keqt5CNUrxpvz8bQtzz7VmE1xkEG4P55pePcxlNzBwrPnmkdc3yCC7euxvR6I\n" + "bJ6wa2owd89Gi6r4gvBAeDECgYBpdiPU/P73h05v16RR9uKYgwWWRwDxn/chqaN1\n" + "ZDPe9ToUZJJQCfP5sgEY7mZDc7yzg/kWOPBoxp+5hjhDCKu7Z1fxCfMfF0qlAMwZ\n" + "46xieiFJaluJWX/B9nxSa3eMi6EwJrXdhV5Pxy7pk67zk0k7vIEr2XDa75o5dawl\n" + "pq5WQQKBgQC9xsRLtQjnDEdNEgCicTupa7BXmvc9tRb1mA5SeqjwzYuulrTyvn5Y\n" + "QOXYdz8aeZ+ZQ/cDeGA3jA6lekWnExkp9enHeqadyDWM7rvXi800E6gB/vrO7r/c\n" + "iE+fpXud6cwNw2XYsk6RBSQ8qhJoCpa+koPXfSJOZ9Y89NMbtq0w3Q==\n" + "-----END RSA PRIVATE KEY-----\n"; diff --git a/iocore/net/quic/test/test_QUICCrypto.cc b/iocore/net/quic/test/test_QUICCrypto.cc index 056874f02c2..0720b3312b6 100644 --- a/iocore/net/quic/test/test_QUICCrypto.cc +++ b/iocore/net/quic/test/test_QUICCrypto.cc @@ -38,54 +38,7 @@ static constexpr uint32_t MAX_HANDSHAKE_MSG_LEN = 2048; -static constexpr char server_crt[] = "-----BEGIN CERTIFICATE-----\n" - "MIIDRjCCAi4CCQDoLSBwQxmcJTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJK\n" - "UDEOMAwGA1UECBMFVG9reW8xDzANBgNVBAcTBk1pbmF0bzEhMB8GA1UEChMYSW50\n" - "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTcw\n" - "MTE4MDEyMzA3WhcNMjcwMTE2MDEyMzA3WjBlMQswCQYDVQQGEwJKUDEOMAwGA1UE\n" - "CBMFVG9reW8xDzANBgNVBAcTBk1pbmF0bzEhMB8GA1UEChMYSW50ZXJuZXQgV2lk\n" - "Z2l0cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB\n" - "AQUAA4IBDwAwggEKAoIBAQC70j62KOWkuqNsDhl+7uqKFS6TMcJYLdYrH1YInwlY\n" - "htOMSMWx2hPSYYBKzVQpLvhe2LPbhLwcVJdq4aqQNjNpxrpxW/YIY5zxCRVgQsgf\n" - "KXiKgUR0G+F3MQHsm1YIqxQU2OeJldIZUBM2YMDp8h1CXTAvGaAZaXsqO9UvR2Zw\n" - "JZJ+GElYNlNwhdStqIM8v1JNFjfO3gWkVqTv+QM4fmpror2pp8CaDrueg4PrSY3Y\n" - "D/WG75rkmlrW26t0Q8fjkn+s/UiQ3V/IkP1+MfrJWH6RL2DGjBv2KfNAik42xWUi\n" - "KXzaNcDFN4hjqVG59O9bPnUDn1wPypY/TXB4iqSAlxupAgMBAAEwDQYJKoZIhvcN\n" - "AQELBQADggEBAKLc+P5YfusNYIkX3YE+gHBVpo95xnoVUcsGr/h1zanCkmsyKkNU\n" - "e2w9xsVnRLgpRfwrnwiaNP/k6cPYt5ePPCJjUfkO7Ql7DCcjLgEp8lrvxMmRIdSg\n" - "LPq+NdityxXYhfaZdGdXjnLLiq3zYL/8aYjjZ8YAZTuu6pBgfGvjcqYLV1ohimrP\n" - "8BW0BbnvedqTyL7tdKjdiWnHE5ObrxnphL2evoStskBr5CLYR4vX7+qp0oVSz2Ol\n" - "nBMV3wXyhHBY1tuT1SK7ajC/ZHrciZosACRV5PC6nKXi3shWOxt76SZV3HcMmFwX\n" - "NQYYTBOlb5U080adFSmP5/6NRzrKwZ3mD2s=\n" - "-----END CERTIFICATE-----\n"; - -static constexpr char server_key[] = "-----BEGIN RSA PRIVATE KEY-----\n" - "MIIEpAIBAAKCAQEAu9I+tijlpLqjbA4Zfu7qihUukzHCWC3WKx9WCJ8JWIbTjEjF\n" - "sdoT0mGASs1UKS74Xtiz24S8HFSXauGqkDYzaca6cVv2CGOc8QkVYELIHyl4ioFE\n" - "dBvhdzEB7JtWCKsUFNjniZXSGVATNmDA6fIdQl0wLxmgGWl7KjvVL0dmcCWSfhhJ\n" - "WDZTcIXUraiDPL9STRY3zt4FpFak7/kDOH5qa6K9qafAmg67noOD60mN2A/1hu+a\n" - "5Jpa1turdEPH45J/rP1IkN1fyJD9fjH6yVh+kS9gxowb9inzQIpONsVlIil82jXA\n" - "xTeIY6lRufTvWz51A59cD8qWP01weIqkgJcbqQIDAQABAoIBADI3ShEF6jAavmq7\n" - "clGfqxF0DFnKaf2Nc79fx27SpnsGwTS2mDSu67HJ47UcJK5GIp2pLp04ZdrlOv6W\n" - "izW3aBOV0G9SePtRNrqzBQYRlNPQEKxnV1f7xFJLxgnulhgHNX1FaNI+PkgKQri9\n" - "MZba5rvBkoplPYrNyuJF0P+tBVRiISWDY00PlZ57pQDyOvXzUckAkxmjNzo+86ld\n" - "/NyO+nR45vVKSeIBT5tT67D8wRisZgO/7QKP5sbKYwa7AR4sTEYFwBaFi4Mr6v1T\n" - "kp0KxOFBI+MioFwyK7ZjkoKClrY/K0IPsKfn2vmi6jLpfkA+qCl1JsVhrfVO3KJc\n" - "PXXF4QECgYEA9339GQS2AWSuA/9ZgHFqTTOEEHujCkh9D4mKO4LRi5hKPN9NQKUU\n" - "KgaBXWTbr8FwOTXw6HMl0SaIOdc6VxdzViNvPCpu2Wn8hyTC5Mjs/BtXkXNcBQqs\n" - "tPm0JxgC6fpQAb+gU+zZ+QQNlUWH/CEiQFxxGNzBn9E3Xq2j0StdhPECgYEAwkci\n" - "GiQuM4KMDdwbs4RDlEZyvXxWwgHKPoXv/Uq7HXtuT1FGb/+Rf3BGimMf2Qqmppp8\n" - "MAZ+xk+eXhtqKZHsV2ifhUfuVZ6NPhT2WRyn6MozuHh3MK4l2KtOhxulcoX/2sDk\n" - "dLYclxhXZFuXvbLz2KpgMmPMGyzEQNHQaoTkojkCgYEAxb/wVGY0OybD+EO2su9s\n" - "PaVU94qielvzOU/vmJ9taTnUz5Co/Gcqlm2+Pe6RrnxEfCICjOk8pUJBhN3ZKq99\n" - "I62Keqt5CNUrxpvz8bQtzz7VmE1xkEG4P55pePcxlNzBwrPnmkdc3yCC7euxvR6I\n" - "bJ6wa2owd89Gi6r4gvBAeDECgYBpdiPU/P73h05v16RR9uKYgwWWRwDxn/chqaN1\n" - "ZDPe9ToUZJJQCfP5sgEY7mZDc7yzg/kWOPBoxp+5hjhDCKu7Z1fxCfMfF0qlAMwZ\n" - "46xieiFJaluJWX/B9nxSa3eMi6EwJrXdhV5Pxy7pk67zk0k7vIEr2XDa75o5dawl\n" - "pq5WQQKBgQC9xsRLtQjnDEdNEgCicTupa7BXmvc9tRb1mA5SeqjwzYuulrTyvn5Y\n" - "QOXYdz8aeZ+ZQ/cDeGA3jA6lekWnExkp9enHeqadyDWM7rvXi800E6gB/vrO7r/c\n" - "iE+fpXud6cwNw2XYsk6RBSQ8qhJoCpa+koPXfSJOZ9Y89NMbtq0w3Q==\n" - "-----END RSA PRIVATE KEY-----\n"; +#include "./server_cert.h" void print_hex(const uint8_t *v, size_t len) diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc new file mode 100644 index 00000000000..4263857784e --- /dev/null +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -0,0 +1,94 @@ +/** @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 "catch.hpp" + +#include "Mock.h" +#include "QUICHandshake.h" + +#include "./server_cert.h" + +TEST_CASE("1-RTT handshake ", "[quic]") +{ + // setup client + QUICConnection *client_qc = new MockQUICConnection(NET_VCONNECTION_OUT); + + SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); + + QUICConnectionId client_conn_id = 0x12345; + // FIXME: remove this. client side stateless reset token doesn't make sense + QUICStatelessResetToken client_token; + client_token.generate(client_conn_id, 0); + + QUICHandshake *client = new QUICHandshake(client_qc, client_ssl_ctx, client_token); + + // setup server + QUICConnection *server_qc = new MockQUICConnection(NET_VCONNECTION_IN); + + SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); + BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); + SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); + BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); + SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); + + QUICConnectionId conn_id = 0; + QUICStatelessResetToken server_token; + server_token.generate(conn_id, 0); + + QUICHandshake *server = new QUICHandshake(server_qc, server_ssl_ctx, server_token); + + // setup stream 0 + QUICStream *stream = new MockQUICStream(); + MockQUICFrameTransmitter tx; + stream->init(&tx, conn_id, 0); + MockQUICStreamIO *stream_io = new MockQUICStreamIO(nullptr, stream); + + client->set_stream(stream, stream_io); + server->set_stream(stream, stream_io); + + SECTION("Basic Full Handshake") + { + // ClientHello + client->handleEvent(VC_EVENT_WRITE_READY, nullptr); + CHECK(stream_io->transfer() > 0); + + // ServerHello + server->handleEvent(VC_EVENT_READ_READY, nullptr); + CHECK(stream_io->transfer() > 0); + + client->handleEvent(VC_EVENT_READ_READY, nullptr); + CHECK(stream_io->transfer() > 0); + + // Finished + server->handleEvent(VC_EVENT_READ_READY, nullptr); + + CHECK(client->is_completed()); + CHECK(server->is_completed()); + } + + delete stream_io; +} From 9ac1e8d777a7bd2ba789c6e67c74d8f81822f3e3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 26 Dec 2017 16:06:36 +0900 Subject: [PATCH 0289/1313] Add initial code of QUIC client --- .gitignore | 7 +- cmd/Makefile.am | 4 +- cmd/traffic_quic/Makefile.am | 59 ++++++ cmd/traffic_quic/traffic_quic.cc | 313 +++++++++++++++++++++++++++++++ configure.ac | 1 + iocore/net/P_QUICNetProcessor.h | 3 + iocore/net/QUICNetProcessor.cc | 45 ++++- 7 files changed, 424 insertions(+), 8 deletions(-) create mode 100644 cmd/traffic_quic/Makefile.am create mode 100644 cmd/traffic_quic/traffic_quic.cc diff --git a/.gitignore b/.gitignore index f1a64f562c1..e0560376573 100644 --- a/.gitignore +++ b/.gitignore @@ -49,12 +49,13 @@ MYMETA.* pm_to_blib cmd/traffic_cop/traffic_cop -cmd/traffic_ctl/traffic_ctl cmd/traffic_crashlog/traffic_crashlog -cmd/traffic_top/traffic_top +cmd/traffic_ctl/traffic_ctl +cmd/traffic_layout/traffic_layout cmd/traffic_manager/traffic_manager cmd/traffic_manager/test_metrics -cmd/traffic_layout/traffic_layout +cmd/traffic_quic/traffic_quic +cmd/traffic_top/traffic_top cmd/traffic_via/traffic_via cmd/traffic_wccp/traffic_wccp diff --git a/cmd/Makefile.am b/cmd/Makefile.am index 00a63b4b6d5..55bdec855dc 100644 --- a/cmd/Makefile.am +++ b/cmd/Makefile.am @@ -27,7 +27,9 @@ SUBDIRS = \ TESTS = $(check_PROGRAMS) if BUILD_WCCP - SUBDIRS += traffic_wccp +endif +if ENABLE_QUIC +SUBDIRS += traffic_quic endif diff --git a/cmd/traffic_quic/Makefile.am b/cmd/traffic_quic/Makefile.am new file mode 100644 index 00000000000..a737ade18b6 --- /dev/null +++ b/cmd/traffic_quic/Makefile.am @@ -0,0 +1,59 @@ +# +# 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. + +bin_PROGRAMS = traffic_quic + +AM_CPPFLAGS += \ + $(iocore_include_dirs) \ + -I$(abs_top_srcdir)/lib \ + -I$(abs_top_srcdir)/lib/records \ + -I$(abs_top_srcdir)/mgmt \ + -I$(abs_top_srcdir)/mgmt/utils \ + -I$(abs_top_srcdir)/proxy \ + -I$(abs_top_srcdir)/proxy/hdrs \ + -I$(abs_top_srcdir)/proxy/http \ + -I$(abs_top_srcdir)/proxy/logging \ + -I$(abs_top_srcdir)/proxy/shared \ + @OPENSSL_INCLUDES@ + +traffic_quic_CPPFLAGS = \ + $(AM_CPPFLAGS) + +traffic_quic_LDFLAGS = \ + @AM_LDFLAGS@ + +traffic_quic_SOURCES = \ + traffic_quic.cc + +traffic_quic_LDADD = \ + $(top_builddir)/iocore/net/libinknet.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/proxy/ParentSelectionStrategy.o \ + $(top_builddir)/lib/tsconfig/libtsconfig.la \ + $(top_builddir)/lib/luajit/src/libluajit.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ \ + @OPENSSL_LIBS@ + +include $(top_srcdir)/build/tidy.mk + +tidy-local: $(DIST_SOURCES) + $(CXX_Clang_Tidy) diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc new file mode 100644 index 00000000000..a0223fe7876 --- /dev/null +++ b/cmd/traffic_quic/traffic_quic.cc @@ -0,0 +1,313 @@ +/** @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 "I_EventSystem.h" +#include "I_NetVConnection.h" +#include "P_QUICNetProcessor.h" + +#include "ts/ink_string.h" +#include "ts/I_Layout.h" + +#define THREADS 1 +#define DIAGS_LOG_FILE "diags.log" + +constexpr size_t stacksize = 1048576; + +static void +reconfigure_diags() +{ + int i; + DiagsConfigState c; + + // initial value set to 0 or 1 based on command line tags + c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != nullptr); + c.enabled[DiagsTagType_Action] = (diags->base_action_tags != nullptr); + + c.enabled[DiagsTagType_Debug] = 1; + c.enabled[DiagsTagType_Action] = 1; + diags->show_location = SHOW_LOCATION_ALL; + + // read output routing values + for (i = 0; i < DL_Status; i++) { + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 1; + c.outputs[i].to_syslog = 0; + c.outputs[i].to_diagslog = 0; + } + + for (i = DL_Status; i < DiagsLevel_Count; i++) { + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 0; + c.outputs[i].to_syslog = 0; + c.outputs[i].to_diagslog = 1; + } + + ////////////////////////////// + // clear out old tag tables // + ////////////////////////////// + + diags->deactivate_all(DiagsTagType_Debug); + diags->deactivate_all(DiagsTagType_Action); + + ////////////////////////////////////////////////////////////////////// + // add new tag tables + ////////////////////////////////////////////////////////////////////// + + if (diags->base_debug_tags) + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + if (diags->base_action_tags) + diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); + +//////////////////////////////////// +// change the diags config values // +//////////////////////////////////// +#if !defined(__GNUC__) && !defined(hpux) + diags->config = c; +#else + memcpy(((void *)&diags->config), ((void *)&c), sizeof(DiagsConfigState)); +#endif +} + +static void +init_diags(const char *bdt, const char *bat) +{ + char diags_logpath[500]; + strcpy(diags_logpath, DIAGS_LOG_FILE); + + diags = new Diags("tq", bdt, bat, new BaseLogFile(diags_logpath)); + Status("opened %s", diags_logpath); + + reconfigure_diags(); +} + +class QUICClient : public Continuation +{ +public: + QUICClient() : Continuation(new_ProxyMutex()) { SET_HANDLER(&QUICClient::state_http_server_open); }; + void start(); + int state_http_server_open(int event, void *data); +}; + +// HttpSM::state_http_server_open(int event, void *data) +int +QUICClient::state_http_server_open(int event, void *data) +{ + switch (event) { + case NET_EVENT_OPEN: { + // TODO: create ProxyServerSession / ProxyServerTransaction + // TODO: send HTTP/0.9 message + Debug("quic_client", "start proxy server ssn/txn"); + break; + } + case NET_EVENT_OPEN_FAILED: { + ink_assert(false); + break; + } + default: + ink_assert(false); + } + + return 0; +} + +// TODO: ip:port +void +QUICClient::start() +{ + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_port = htons(4433); + + NetVCOptions opt; + opt.ip_proto = NetVCOptions::USE_UDP; + opt.ip_family = addr.sin_family; + + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + + quic_NetProcessor.connect_re(this, reinterpret_cast(&addr), &opt); +} + +int +main(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */) +{ + Layout::create(); + init_diags("udp|quic", nullptr); + RecProcessInit(RECM_STAND_ALONE); + + SSLInitializeLibrary(); + SSLConfig::startup(); + + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + eventProcessor.start(THREADS); + udpNet.start(1, stacksize); + quic_NetProcessor.start(-1, stacksize); + + Thread *main_thread = new EThread; + main_thread->set_specific(); + + QUICClient client; + client.start(); +} + +// +// stub +// +void +initialize_thread_for_http_sessions(EThread *, int) +{ + ink_assert(false); +} + +#include "P_UnixNet.h" +#include "P_DNSConnection.h" +int +DNSConnection::close() +{ + ink_assert(false); + return 0; +} + +void +DNSConnection::trigger() +{ + ink_assert(false); +} + +#include "StatPages.h" +void +StatPagesManager::register_http(char const *, Action *(*)(Continuation *, HTTPHdr *)) +{ + ink_assert(false); +} + +#include "ParentSelection.h" +void +SocksServerConfig::startup() +{ + ink_assert(false); +} + +int SocksServerConfig::m_id = 0; + +void +ParentConfigParams::findParent(HttpRequestData *, ParentResult *, unsigned int, unsigned int) +{ + ink_assert(false); +} + +void +ParentConfigParams::nextParent(HttpRequestData *, ParentResult *, unsigned int, unsigned int) +{ + ink_assert(false); +} + +#include "Log.h" +void +Log::trace_in(sockaddr const *, unsigned short, char const *, ...) +{ + ink_assert(false); +} + +void +Log::trace_out(sockaddr const *, unsigned short, char const *, ...) +{ + ink_assert(false); +} + +#include "InkAPIInternal.h" +int +APIHook::invoke(int, void *) +{ + ink_assert(false); + return 0; +} + +APIHook * +APIHook::next() const +{ + ink_assert(false); + return nullptr; +} + +APIHook * +APIHooks::get() const +{ + ink_assert(false); + return nullptr; +} + +void +ConfigUpdateCbTable::invoke(const char * /* name ATS_UNUSED */) +{ + ink_release_assert(false); +} + +#include "ControlMatcher.h" +char * +HttpRequestData::get_string() +{ + ink_assert(false); + return nullptr; +} + +const char * +HttpRequestData::get_host() +{ + ink_assert(false); + return nullptr; +} + +sockaddr const * +HttpRequestData::get_ip() +{ + ink_assert(false); + return nullptr; +} + +sockaddr const * +HttpRequestData::get_client_ip() +{ + ink_assert(false); + return nullptr; +} + +SslAPIHooks *ssl_hooks = nullptr; +StatPagesManager statPagesManager; + +#include "ProcessManager.h" +inkcoreapi ProcessManager *pmgmt = nullptr; + +int +BaseManager::registerMgmtCallback(int, MgmtCallback, void *) +{ + ink_assert(false); + return 0; +} + +void +ProcessManager::signalManager(int, char const *, int) +{ + ink_assert(false); + return; +} diff --git a/configure.ac b/configure.ac index e2ef11a5072..1bce3c929a6 100644 --- a/configure.ac +++ b/configure.ac @@ -2015,6 +2015,7 @@ AC_CONFIG_FILES([ cmd/traffic_ctl/Makefile cmd/traffic_layout/Makefile cmd/traffic_manager/Makefile + cmd/traffic_quic/Makefile cmd/traffic_top/Makefile cmd/traffic_via/Makefile cmd/traffic_wccp/Makefile diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h index 9f97454b5fe..29720609a00 100644 --- a/iocore/net/P_QUICNetProcessor.h +++ b/iocore/net/P_QUICNetProcessor.h @@ -58,6 +58,9 @@ class QUICNetProcessor : public UnixNetProcessor virtual int start(int, size_t stacksize) override; void cleanup(); + // TODO: refactoring NetProcessor::connect_re and UnixNetProcessor::connect_re_internal + // Action *connect_re(Continuation *cont, sockaddr const *addr, NetVCOptions *opts) override; + Action *connect_re(Continuation *cont, sockaddr const *addr, NetVCOptions *opts); virtual NetAccept *createNetAccept(const NetProcessor::AcceptOptions &opt) override; virtual NetVConnection *allocate_vc(EThread *t) override; diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 608f3d73a80..9a782cc0e63 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -35,9 +35,7 @@ QUICNetProcessor quic_NetProcessor; -QUICNetProcessor::QUICNetProcessor() -{ -} +QUICNetProcessor::QUICNetProcessor() {} QUICNetProcessor::~QUICNetProcessor() { @@ -79,7 +77,7 @@ QUICNetProcessor::start(int, size_t stacksize) if (SSL_CTX_check_private_key(this->_ssl_ctx) != 1) { Error("check private key failed"); - ink_assert(false); + // ink_assert(false); } return 0; @@ -109,6 +107,45 @@ QUICNetProcessor::allocate_vc(EThread *t) return vc; } +Action * +QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *addr, NetVCOptions *opt) +{ + Debug("quic_ps", "connect to server"); + + EThread *t = cont->mutex->thread_holding; + ink_assert(t); + + QUICNetVConnection *vc = static_cast(this->allocate_vc(t)); + + // Setup QUICNetVConnection + // TODO: randomize + QUICConnectionId id = 0x00; + UDPConnection *con = new UnixUDPConnection(NO_FD); + AcceptOptions const accept_opt; + QUICPacketHandler *ph = new QUICPacketHandler(accept_opt, this->_ssl_ctx); + + vc->init(id, con, ph); + + if (opt) { + vc->options = *opt; + } else { + opt = &vc->options; + } + + vc->set_context(NET_VCONNECTION_OUT); + vc->con.setRemote(addr); + vc->id = net_next_connection_number(); + vc->submit_time = Thread::get_hrtime(); + vc->mutex = cont->mutex; + vc->action_ = cont; + + vc->start(this->_ssl_ctx); + + vc->action_.continuation->handleEvent(NET_EVENT_OPEN, this); + + return ACTION_RESULT_DONE; +} + Action * QUICNetProcessor::main_accept(Continuation *cont, SOCKET fd, AcceptOptions const &opt) { From c33d80e362819450c5eeaccd5ab5a26e210ed75d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 28 Dec 2017 22:13:46 +0900 Subject: [PATCH 0290/1313] Start QUIC handshake from client --- cmd/traffic_quic/traffic_quic.cc | 8 +++-- iocore/net/P_QUICNetVConnection.h | 17 +++++++---- iocore/net/QUICNetProcessor.cc | 30 ++++++++++++------- iocore/net/QUICNetVConnection.cc | 34 ++++++++++++++++++++-- iocore/net/UnixUDPNet.cc | 12 ++------ iocore/net/quic/QUICCrypto.cc | 13 ++++----- iocore/net/quic/QUICHandshake.cc | 7 ++++- iocore/net/quic/QUICStreamManager.h | 2 ++ iocore/net/quic/test/test_QUICHandshake.cc | 3 ++ 9 files changed, 88 insertions(+), 38 deletions(-) diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index a0223fe7876..965f61806ee 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -1,3 +1,4 @@ + /** @file * * A brief file description @@ -33,6 +34,7 @@ constexpr size_t stacksize = 1048576; +// copy from iocore/utils/diags.i static void reconfigure_diags() { @@ -94,7 +96,7 @@ init_diags(const char *bdt, const char *bat) char diags_logpath[500]; strcpy(diags_logpath, DIAGS_LOG_FILE); - diags = new Diags("tq", bdt, bat, new BaseLogFile(diags_logpath)); + diags = new Diags("Client", bdt, bat, new BaseLogFile(diags_logpath)); Status("opened %s", diags_logpath); reconfigure_diags(); @@ -152,7 +154,7 @@ int main(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */) { Layout::create(); - init_diags("udp|quic", nullptr); + init_diags("quic|udp", nullptr); RecProcessInit(RECM_STAND_ALONE); SSLInitializeLibrary(); @@ -168,6 +170,8 @@ main(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */) QUICClient client; client.start(); + + main_thread->execute(); } // diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 3f9d1c27525..7fdb83db2f7 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -98,14 +98,17 @@ class SSLNextProtocolSet; * @detail * * state_pre_handshake() - * | + * | READ: + * | Do nothing + * | WRITE: + * | _state_common_send_packet() * v * state_handshake() * | READ: - * | _state_handshake_process__packet() - * | _state_handshake_process_initial_client_packet() - * | _state_handshake_process_client_cleartext_packet() - * | _state_handshake_process_zero_rtt_protected_packet() + * | _state_handshake_process_packet() + * | _state_handshake_process_initial_client_packet() + * | _state_handshake_process_client_cleartext_packet() + * | _state_handshake_process_zero_rtt_protected_packet() * | WRITE: * | _state_common_send_packet() * v @@ -139,7 +142,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void reenable(VIO *vio) override; VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override; VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) override; + int connectUp(EThread *t, int fd) override; + // QUICNetVConnection int startEvent(int event, Event *e); int state_pre_handshake(int event, Event *data); int state_handshake(int event, Event *data); @@ -237,6 +242,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection std::queue _frame_send_queue; std::queue _stream_frame_send_queue; + bool _is_initial = true; + void _schedule_packet_write_ready(); void _unschedule_packet_write_ready(); void _close_packet_write_ready(Event *data); diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 9a782cc0e63..f089babdeb1 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -115,16 +115,24 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *addr, NetVCOpti EThread *t = cont->mutex->thread_holding; ink_assert(t); - QUICNetVConnection *vc = static_cast(this->allocate_vc(t)); - - // Setup QUICNetVConnection - // TODO: randomize - QUICConnectionId id = 0x00; - UDPConnection *con = new UnixUDPConnection(NO_FD); + // Setup UDPConnection + // FIXME: use udpNet.CreateUDPSocket + int fd = socket(AF_INET, SOCK_DGRAM, 0); + UnixUDPConnection *con = new UnixUDPConnection(fd); AcceptOptions const accept_opt; - QUICPacketHandler *ph = new QUICPacketHandler(accept_opt, this->_ssl_ctx); + QUICPacketHandler *packet_handler = new QUICPacketHandler(accept_opt, this->_ssl_ctx); + con->setBinding(addr); + con->bindToThread(packet_handler); - vc->init(id, con, ph); + PollCont *pc = get_UDPPollCont(con->ethread); + PollDescriptor *pd = pc->pollDescriptor; + con->ep.start(pd, con, EVENTIO_READ); + + // Setup QUICNetVConnection + QUICConnectionId cid; + cid.randomize(); + QUICNetVConnection *vc = static_cast(this->allocate_vc(t)); + vc->init(cid, con, packet_handler); if (opt) { vc->options = *opt; @@ -132,16 +140,16 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *addr, NetVCOpti opt = &vc->options; } + // Connection ID will be changed + vc->id = net_next_connection_number(); vc->set_context(NET_VCONNECTION_OUT); vc->con.setRemote(addr); - vc->id = net_next_connection_number(); vc->submit_time = Thread::get_hrtime(); vc->mutex = cont->mutex; vc->action_ = cont; vc->start(this->_ssl_ctx); - - vc->action_.continuation->handleEvent(NET_EVENT_OPEN, this); + vc->connectUp(t, NO_FD); return ACTION_RESULT_DONE; } diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 124a2924e99..ac9cb6de84a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -153,6 +153,24 @@ QUICNetVConnection::reenable(VIO *vio) return; } +int +QUICNetVConnection::connectUp(EThread *t, int fd) +{ + // create stream 0 + // FIXME: integration w/ QUICStreamManager + QUICStream *stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream(); + stream->init(this, this->connection_id(), STREAM_ID_FOR_HANDSHAKE); + if (!this->_handshake_handler->is_stream_set(stream)) { + this->_handshake_handler->set_stream(stream); + } + + // start QUIC handshake + this->_handshake_handler->handleEvent(VC_EVENT_WRITE_READY, nullptr); + + // action_.continuation->handleEvent(NET_EVENT_OPEN, this); + return CONNECT_SUCCESS; +} + QUICConnectionId QUICNetVConnection::original_connection_id() { @@ -853,6 +871,11 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); switch (type) { + case QUICPacketType::INITIAL: + ink_assert(this->get_context() == NET_VCONNECTION_OUT); + packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->largest_acked_packet_number(), + QUIC_SUPPORTED_VERSIONS[0], std::move(buf), len); + break; case QUICPacketType::HANDSHAKE: packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); @@ -862,8 +885,15 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi packet = this->_packet_factory.create_server_protected_packet(this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); } else { - packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), - std::move(buf), len, retransmittable); + // FIXME: remove this flag + if (this->get_context() == NET_VCONNECTION_OUT && this->_is_initial) { + this->_is_initial = false; + packet = this->_packet_factory.create_initial_packet( + this->_original_quic_connection_id, this->largest_acked_packet_number(), QUIC_SUPPORTED_VERSIONS[0], std::move(buf), len); + } else { + packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), + std::move(buf), len, retransmittable); + } } break; } diff --git a/iocore/net/UnixUDPNet.cc b/iocore/net/UnixUDPNet.cc index 7c27016ca72..9f5daab42f6 100644 --- a/iocore/net/UnixUDPNet.cc +++ b/iocore/net/UnixUDPNet.cc @@ -303,9 +303,7 @@ UDPReadContinuation::UDPReadContinuation(Event *completionToken) } } -UDPReadContinuation::UDPReadContinuation() : Continuation(nullptr) -{ -} +UDPReadContinuation::UDPReadContinuation() : Continuation(nullptr) {} inline void UDPReadContinuation::free() @@ -710,13 +708,9 @@ UDPNetProcessor::UDPBind(Continuation *cont, sockaddr const *addr, int send_bufs } // send out all packets that need to be sent out as of time=now -UDPQueue::UDPQueue() -{ -} +UDPQueue::UDPQueue() {} -UDPQueue::~UDPQueue() -{ -} +UDPQueue::~UDPQueue() {} /* * Driver function that aggregates packets across cont's and sends them diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 558e45aa495..db61dc39437 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -38,10 +38,10 @@ static void to_hex(uint8_t *out, uint8_t *in, int in_len) { for (int i = 0; i < in_len; ++i) { - int u4 = in[i] / 16; - int l4 = in[i] % 16; - out [i * 2] = (u4 < 10) ? ('0' + u4) : ('A' + u4 - 10); - out [i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('A' + l4 - 10); + int u4 = in[i] / 16; + int l4 = in[i] % 16; + out[i * 2] = (u4 < 10) ? ('0' + u4) : ('A' + u4 - 10); + out[i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('A' + l4 - 10); } out[in_len * 2] = 0; } @@ -50,9 +50,7 @@ to_hex(uint8_t *out, uint8_t *in, int in_len) // QUICPacketProtection // -QUICPacketProtection::~QUICPacketProtection() -{ -} +QUICPacketProtection::~QUICPacketProtection() {} void QUICPacketProtection::set_key(std::unique_ptr km, QUICKeyPhase phase) @@ -173,7 +171,6 @@ QUICCryptoTls::is_handshake_finished() const int QUICCryptoTls::initialize_key_materials(QUICConnectionId cid) { - // Generate keys uint8_t print_buf[512]; std::unique_ptr km; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index c374dd3d7a7..1952a738dbf 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -94,6 +94,8 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless this->_version_negotiator = new QUICVersionNegotiator(); this->_crypto->initialize_key_materials(this->_client_qc->original_connection_id()); + // for client initial + this->_load_local_transport_parameters(QUIC_SUPPORTED_VERSIONS[0]); SET_HANDLER(&QUICHandshake::state_initial); } @@ -392,11 +394,14 @@ QUICHandshake::_do_handshake(bool initial) QUICErrorUPtr QUICHandshake::_process_initial() { - QUICErrorUPtr error = _do_handshake(true); + QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); + QUICErrorUPtr error = _do_handshake(true); if (error->cls == QUICErrorClass::NONE) { QUICHSDebug("Enter state_key_exchange"); SET_HANDLER(&QUICHandshake::state_key_exchange); + + stream_io->write_reenable(); } return error; diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 5493e581eb0..05be5c86b74 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -30,6 +30,8 @@ #include "QUICFrame.h" #include "QUICFrameTransmitter.h" +extern ClassAllocator quicStreamAllocator; + class QUICTransportParameters; class QUICStreamManager : public QUICFrameHandler diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc index 4263857784e..71d51af277d 100644 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -25,11 +25,14 @@ #include "Mock.h" #include "QUICHandshake.h" +#include "QUICConfig.h" #include "./server_cert.h" TEST_CASE("1-RTT handshake ", "[quic]") { + QUICConfig::startup(); + // setup client QUICConnection *client_qc = new MockQUICConnection(NET_VCONNECTION_OUT); From 509723575212cbd8c2eb401dfd6d818fd996140d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 28 Dec 2017 22:21:47 +0900 Subject: [PATCH 0291/1313] clang-format --- cmd/traffic_quic/traffic_quic.cc | 1 - iocore/net/QUICNetProcessor.cc | 4 +++- iocore/net/UnixUDPNet.cc | 12 +++++++++--- iocore/net/quic/QUICCrypto.cc | 4 +++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index 965f61806ee..a38289b9365 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -1,4 +1,3 @@ - /** @file * * A brief file description diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index f089babdeb1..7decb54dd50 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -35,7 +35,9 @@ QUICNetProcessor quic_NetProcessor; -QUICNetProcessor::QUICNetProcessor() {} +QUICNetProcessor::QUICNetProcessor() +{ +} QUICNetProcessor::~QUICNetProcessor() { diff --git a/iocore/net/UnixUDPNet.cc b/iocore/net/UnixUDPNet.cc index 9f5daab42f6..7c27016ca72 100644 --- a/iocore/net/UnixUDPNet.cc +++ b/iocore/net/UnixUDPNet.cc @@ -303,7 +303,9 @@ UDPReadContinuation::UDPReadContinuation(Event *completionToken) } } -UDPReadContinuation::UDPReadContinuation() : Continuation(nullptr) {} +UDPReadContinuation::UDPReadContinuation() : Continuation(nullptr) +{ +} inline void UDPReadContinuation::free() @@ -708,9 +710,13 @@ UDPNetProcessor::UDPBind(Continuation *cont, sockaddr const *addr, int send_bufs } // send out all packets that need to be sent out as of time=now -UDPQueue::UDPQueue() {} +UDPQueue::UDPQueue() +{ +} -UDPQueue::~UDPQueue() {} +UDPQueue::~UDPQueue() +{ +} /* * Driver function that aggregates packets across cont's and sends them diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index db61dc39437..48461083ffb 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -50,7 +50,9 @@ to_hex(uint8_t *out, uint8_t *in, int in_len) // QUICPacketProtection // -QUICPacketProtection::~QUICPacketProtection() {} +QUICPacketProtection::~QUICPacketProtection() +{ +} void QUICPacketProtection::set_key(std::unique_ptr km, QUICKeyPhase phase) From fe29839e094550d2493177f66d666adeece1b904 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 9 Jan 2018 11:40:55 +0900 Subject: [PATCH 0292/1313] Print negotiated cipher suite --- iocore/net/QUICNetVConnection.cc | 2 ++ iocore/net/quic/QUICHandshake.cc | 19 ++++++++++++++++--- iocore/net/quic/QUICHandshake.h | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ac9cb6de84a..770ebc6dc4a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1058,7 +1058,9 @@ QUICNetVConnection::_switch_to_established_state() { if (this->_complete_handshake_if_possible() == 0) { QUICConDebug("Enter state_connection_established"); + QUICConDebug("%s", this->_handshake_handler->negotiated_cipher_suite()); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); + this->_update_alt_connection_ids(countof(this->_alt_quic_connection_ids) - 1); } else { // Illegal state change diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 1952a738dbf..cd70206ac46 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -142,16 +142,29 @@ QUICHandshake::is_completed() return this->handler == &QUICHandshake::state_complete; } +QUICCrypto * +QUICHandshake::crypto_module() +{ + return this->_crypto; +} + QUICVersion QUICHandshake::negotiated_version() { return this->_version_negotiator->negotiated_version(); } -QUICCrypto * -QUICHandshake::crypto_module() +// Similar to SSLNetVConnection::getSSLCipherSuite() +const char * +QUICHandshake::negotiated_cipher_suite() { - return this->_crypto; + // FIXME Generalize and remove dynamic_cast + QUICCryptoTls *crypto_tls = dynamic_cast(this->_crypto); + if (crypto_tls) { + return SSL_get_cipher_name(crypto_tls->ssl_handle()); + } + + return nullptr; } void diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 23fa4d2ec91..6c426f29c06 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -67,6 +67,7 @@ class QUICHandshake : public QUICApplication // Getters QUICCrypto *crypto_module(); QUICVersion negotiated_version(); + const char *negotiated_cipher_suite(); void negotiated_application_name(const uint8_t **name, unsigned int *len); std::shared_ptr local_transport_parameters(); std::shared_ptr remote_transport_parameters(); From a851522a2c8ba57d942c4fcb486099de58ce623e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 9 Jan 2018 11:42:26 +0900 Subject: [PATCH 0293/1313] Conver keys and IVs to hex only if the debug tag is set --- iocore/net/quic/QUICCrypto.cc | 40 +++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index 48461083ffb..c997c17bf44 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -177,17 +177,21 @@ QUICCryptoTls::initialize_key_materials(QUICConnectionId cid) uint8_t print_buf[512]; std::unique_ptr km; km = this->_keygen_for_client.generate(cid); - to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "client key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "client iv 0x%s", print_buf); + if (is_debug_tag_set("vv_quic_crypto")) { + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "client key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "client iv 0x%s", print_buf); + } this->_client_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); km = this->_keygen_for_server.generate(cid); - to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "server key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "server iv 0x%s", print_buf); + if (is_debug_tag_set("vv_quic_crypto")) { + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "server key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "server iv 0x%s", print_buf); + } this->_server_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); // Update algorithm @@ -222,16 +226,20 @@ QUICCryptoTls::update_key_materials() uint8_t print_buf[512]; std::unique_ptr km; km = this->_keygen_for_client.generate(this->_ssl); - to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "client key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "client iv 0x%s", print_buf); + if (is_debug_tag_set("vv_quic_crypto")) { + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "client key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "client iv 0x%s", print_buf); + } this->_client_pp->set_key(std::move(km), next_key_phase); km = this->_keygen_for_server.generate(this->_ssl); - to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "server key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "server iv 0x%s", print_buf); + if (is_debug_tag_set("vv_quic_crypto")) { + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "server key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "server iv 0x%s", print_buf); + } this->_server_pp->set_key(std::move(km), next_key_phase); // Update algorithm From 1415df3e5e4522c8b6a66f251d93ffe2fe5809c3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 9 Jan 2018 12:00:34 +0900 Subject: [PATCH 0294/1313] Remove unused functions --- iocore/net/quic/QUICCryptoTls.h | 4 ---- iocore/net/quic/QUICCrypto_boringssl.cc | 12 ------------ iocore/net/quic/QUICCrypto_openssl.cc | 12 ------------ 3 files changed, 28 deletions(-) diff --git a/iocore/net/quic/QUICCryptoTls.h b/iocore/net/quic/QUICCryptoTls.h index 0e4179360d0..b26ec4314fb 100644 --- a/iocore/net/quic/QUICCryptoTls.h +++ b/iocore/net/quic/QUICCryptoTls.h @@ -60,12 +60,8 @@ class QUICCryptoTls : public QUICCrypto void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; #ifdef OPENSSL_IS_BORINGSSL const EVP_AEAD *_get_evp_aead() const; - size_t _get_aead_key_len(const EVP_AEAD *aead) const; - size_t _get_aead_nonce_len(const EVP_AEAD *aead) const; #else const EVP_CIPHER *_get_evp_aead() const; - size_t _get_aead_key_len(const EVP_CIPHER *aead) const; - size_t _get_aead_nonce_len(const EVP_CIPHER *aead) const; #endif // OPENSSL_IS_BORINGSSL size_t _get_aead_tag_len() const; diff --git a/iocore/net/quic/QUICCrypto_boringssl.cc b/iocore/net/quic/QUICCrypto_boringssl.cc index 0d9ff5b2bb2..2cf16e09505 100644 --- a/iocore/net/quic/QUICCrypto_boringssl.cc +++ b/iocore/net/quic/QUICCrypto_boringssl.cc @@ -71,18 +71,6 @@ QUICCryptoTls::_get_aead_tag_len(const SSL_CIPHER * /* cipher */) const return EVP_AEAD_DEFAULT_TAG_LENGTH; } -size_t -QUICCryptoTls::_get_aead_key_len(const EVP_AEAD *aead) const -{ - return EVP_AEAD_key_length(aead); -} - -size_t -QUICCryptoTls::_get_aead_nonce_len(const EVP_AEAD *aead) const -{ - return EVP_AEAD_nonce_length(aead); -} - int QUICCryptoTls::_hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, const EVP_MD *digest) const diff --git a/iocore/net/quic/QUICCrypto_openssl.cc b/iocore/net/quic/QUICCrypto_openssl.cc index b216ae1f981..9eae6b3728f 100644 --- a/iocore/net/quic/QUICCrypto_openssl.cc +++ b/iocore/net/quic/QUICCrypto_openssl.cc @@ -76,18 +76,6 @@ QUICCryptoTls::_get_aead_tag_len() const } } -size_t -QUICCryptoTls::_get_aead_key_len(const EVP_CIPHER *aead) const -{ - return EVP_CIPHER_key_length(aead); -} - -size_t -QUICCryptoTls::_get_aead_nonce_len(const EVP_CIPHER *aead) const -{ - return EVP_CIPHER_iv_length(aead); -} - bool QUICCryptoTls::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const From 1cb8e693b1341b7b9da260523627dcac15c048c9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 9 Jan 2018 12:14:27 +0900 Subject: [PATCH 0295/1313] Move some code for BoringSSL to not lost them --- iocore/net/quic/QUICCrypto_boringssl.cc | 16 ---- iocore/net/quic/QUICKeyGenerator_boringssl.cc | 78 +++++++++++++++++++ 2 files changed, 78 insertions(+), 16 deletions(-) create mode 100644 iocore/net/quic/QUICKeyGenerator_boringssl.cc diff --git a/iocore/net/quic/QUICCrypto_boringssl.cc b/iocore/net/quic/QUICCrypto_boringssl.cc index 2cf16e09505..4d848fd4c32 100644 --- a/iocore/net/quic/QUICCrypto_boringssl.cc +++ b/iocore/net/quic/QUICCrypto_boringssl.cc @@ -49,22 +49,6 @@ QUICCryptoTls::_get_evp_aead(const SSL_CIPHER *cipher) const } } -// SSL_HANDSHAKE_MAC_SHA256, SSL_HANDSHAKE_MAC_SHA384 are defind in `ssl/internal.h` of BoringSSL -const EVP_MD * -QUICCryptoTls::_get_handshake_digest(const SSL_CIPHER *cipher) const -{ - switch (cipher->algorithm_prf) { - case 0x2: - // SSL_HANDSHAKE_MAC_SHA256: - return EVP_sha256(); - case 0x4: - // SSL_HANDSHAKE_MAC_SHA384: - return EVP_sha384(); - default: - return nullptr; - } -} - size_t QUICCryptoTls::_get_aead_tag_len(const SSL_CIPHER * /* cipher */) const { diff --git a/iocore/net/quic/QUICKeyGenerator_boringssl.cc b/iocore/net/quic/QUICKeyGenerator_boringssl.cc new file mode 100644 index 00000000000..2f11aab60a5 --- /dev/null +++ b/iocore/net/quic/QUICKeyGenerator_boringssl.cc @@ -0,0 +1,78 @@ +/** @file + * + * A key generator for QUIC connection (BoringSSL specific parts) + * + * @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 "ts/ink_assert.h" +#include "QUICKeyGenerator.h" + +#include +size_t +QUICKeyGenerator::_get_key_len(const QUIC_EVP_CIPHER *cipher) const +{ + return EVP_AEAD_key_length(cipher); +} + +size_t +QUICKeyGenerator::_get_iv_len(const QUIC_EVP_CIPHER *cipher) const +{ + return EVP_AEAD_nonce_length(cipher); +} + +const QUIC_EVP_CIPHER * +QUICKeyGenerator::_get_cipher_for_cleartext() const +{ + return EVP_aes_128_gcm(); + return EVP_aead_aes_128_gcm(); +} + +const QUIC_EVP_CIPHER * +QUICKeyGenerator::_get_cipher_for_protected_packet(const SSL *ssl) const +{ + ink_assert(SSL_CIPHER_is_AEAD(ssl)); + + if (SSL_CIPHER_is_AES128GCM(ssl)) { + return EVP_aead_aes_128_gcm(); + } else if ((cipher->algorithm_enc & 0x00000010L) != 0) { + // SSL_AES256GCM is 0x00000010L ( defined in `ssl/internal.h` ). + // There're no `SSL_CIPHER_is_AES256GCM(const SSL_CIPHER *cipher)`. + return EVP_aead_aes_256_gcm(); + } else if (SSL_CIPHER_is_CHACHA20POLY1305(ssl)) { + return EVP_aead_chacha20_poly1305(); + } else { + 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) const +{ + switch (ssl->algorithm_prf) { + case 0x2: + // SSL_HANDSHAKE_MAC_SHA256: + return EVP_sha256(); + case 0x4: + // SSL_HANDSHAKE_MAC_SHA384: + return EVP_sha384(); + default: + return nullptr; + } +} From c68dd224475302476276616c1fe430662b635e4c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 9 Jan 2018 14:18:42 +0900 Subject: [PATCH 0296/1313] Use the latest supported version number before version negotiation completes instead of 0 Version number 0 is reserved to represent version negotiation. --- iocore/net/quic/QUICPacket.cc | 1 - iocore/net/quic/QUICPacket.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index c4f17e1c7aa..ba775776248 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -794,7 +794,6 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header, bool retra void QUICPacketFactory::set_version(QUICVersion negotiated_version) { - ink_assert(this->_version == 0); this->_version = negotiated_version; } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 5f5d4f72f6d..a392eb5749d 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -307,7 +307,7 @@ class QUICPacketFactory void set_crypto_module(QUICCrypto *crypto); private: - QUICVersion _version = 0; + QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; QUICCrypto *_crypto = nullptr; QUICPacketNumberGenerator _packet_number_generator; From 666e7d6223a8a225d158b750caeb7abb813834db Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 9 Jan 2018 15:29:23 +0900 Subject: [PATCH 0297/1313] Replace QUICDebugNames::vc_event(int) with get_vc_event_name(int) --- iocore/net/quic/QUICDebugNames.cc | 27 --------------------------- iocore/net/quic/QUICDebugNames.h | 3 --- iocore/net/quic/QUICEchoApp.cc | 3 ++- iocore/net/quic/QUICHandshake.cc | 6 +++--- iocore/net/quic/QUICStream.cc | 9 +++++---- proxy/hq/QUICSimpleApp.cc | 3 ++- 6 files changed, 12 insertions(+), 39 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index a96bf39be22..e7e8751780a 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -157,33 +157,6 @@ QUICDebugNames::quic_event(int event) } } -const char * -QUICDebugNames::vc_event(int event) -{ - switch (event) { - case VC_EVENT_READ_READY: - return "VC_EVENT_READ_READY"; - case VC_EVENT_READ_COMPLETE: - return "VC_EVENT_READ_COMPLETE"; - case VC_EVENT_WRITE_READY: - return "VC_EVENT_WRITE_READY"; - case VC_EVENT_WRITE_COMPLETE: - return "VC_EVENT_WRITE_COMPLETE"; - case VC_EVENT_EOS: - return "VC_EVENT_EOS"; - case VC_EVENT_ERROR: - return "VC_EVENT_ERROR"; - case VC_EVENT_INACTIVITY_TIMEOUT: - return "VC_EVENT_INACTIVITY_TIMEOUT"; - case VC_EVENT_ACTIVE_TIMEOUT: - return "VC_EVENT_ACTIVE_TIMEOUT"; - case VC_EVENT_OOB_COMPLETE: - return "VC_EVENT_OOB_COMPLETE"; - default: - return "UNKNOWN"; - } -} - const char * QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) { diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index 8ccac293551..093e81db8f5 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -38,7 +38,4 @@ class QUICDebugNames static const char *transport_parameter_id(QUICTransportParameterId id); static const char *stream_state(QUICStreamState state); static const char *quic_event(int event); - - // TODO: move to somewhere - static const char *vc_event(int event); }; diff --git a/iocore/net/quic/QUICEchoApp.cc b/iocore/net/quic/QUICEchoApp.cc index 6451dc7af15..35ea791f724 100644 --- a/iocore/net/quic/QUICEchoApp.cc +++ b/iocore/net/quic/QUICEchoApp.cc @@ -24,6 +24,7 @@ #include "QUICEchoApp.h" #include "P_Net.h" +#include "P_VConnection.h" #include "QUICDebugNames.h" static constexpr char tag[] = "quic_echo_app"; @@ -36,7 +37,7 @@ QUICEchoApp::QUICEchoApp(QUICConnection *qc) : QUICApplication(qc) int QUICEchoApp::main_event_handler(int event, Event *data) { - Debug(tag, "%s", QUICDebugNames::vc_event(event)); + Debug(tag, "%s", get_vc_event_name(event)); QUICStream *stream = reinterpret_cast(data->cookie); QUICStreamIO *stream_io = this->_find_stream_io(stream->id()); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index cd70206ac46..b2ff6e69cff 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -225,7 +225,7 @@ QUICHandshake::remote_transport_parameters() int QUICHandshake::state_initial(int event, Event *data) { - QUICHSDebug("event: %d", event); + QUICHSDebug("%s", get_vc_event_name(event)); QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { @@ -263,7 +263,7 @@ QUICHandshake::state_initial(int event, Event *data) int QUICHandshake::state_key_exchange(int event, Event *data) { - QUICHSDebug("event: %d", event); + QUICHSDebug("%s", get_vc_event_name(event)); QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { @@ -295,7 +295,7 @@ QUICHandshake::state_key_exchange(int event, Event *data) int QUICHandshake::state_auth(int event, Event *data) { - QUICHSDebug("event: %d", event); + QUICHSDebug("%s", get_vc_event_name(event)); QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 4dafbf199ef..c2370d1c12e 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -24,6 +24,7 @@ #include "QUICStream.h" #include "I_Event.h" +#include "P_VConnection.h" #include "QUICStreamManager.h" #include "QUICDebugNames.h" #include "QUICConfig.h" @@ -93,7 +94,7 @@ QUICStream::final_offset() int QUICStream::state_stream_open(int event, void *data) { - QUICStreamDebug("%s", QUICDebugNames::vc_event(event)); + QUICStreamDebug("%s", get_vc_event_name(event)); QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); switch (event) { @@ -153,7 +154,7 @@ QUICStream::state_stream_open(int event, void *data) int QUICStream::state_stream_closed(int event, void *data) { - QUICStreamDebug("%s", QUICDebugNames::vc_event(event)); + QUICStreamDebug("%s", get_vc_event_name(event)); switch (event) { case VC_EVENT_READ_READY: @@ -399,7 +400,7 @@ QUICStream::_signal_read_event() this_ethread()->schedule_imm(this->_read_vio._cont, event, &this->_read_vio); } - QUICStreamDebug("%s", QUICDebugNames::vc_event(event)); + QUICStreamDebug("%s", get_vc_event_name(event)); } /** @@ -421,7 +422,7 @@ QUICStream::_signal_write_event() this_ethread()->schedule_imm(this->_write_vio._cont, event, &this->_write_vio); } - QUICStreamDebug("%s", QUICDebugNames::vc_event(event)); + QUICStreamDebug("%s", get_vc_event_name(event)); } int64_t diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index 310a5a0999b..502a1d0faf0 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -24,6 +24,7 @@ #include "QUICSimpleApp.h" #include "P_Net.h" +#include "P_VConnection.h" #include "QUICDebugNames.h" #include "HQClientSession.h" @@ -54,7 +55,7 @@ QUICSimpleApp::~QUICSimpleApp() int QUICSimpleApp::main_event_handler(int event, Event *data) { - Debug(tag, "%s", QUICDebugNames::vc_event(event)); + Debug(tag, "%s", get_vc_event_name(event)); VIO *vio = reinterpret_cast(data); QUICStreamIO *stream_io = this->_find_stream_io(vio); From 40c752228dc97ce0ccadfd3a70506b6b586a9a9a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 9 Jan 2018 17:05:04 +0900 Subject: [PATCH 0298/1313] Fix a bug that floating values are actually calculated as integers --- iocore/net/quic/QUICLossDetector.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index c1bd993b44c..9b25f527a30 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -32,7 +32,7 @@ // Keep the order as the same as the spec so that we can see the difference easily. constexpr static uint32_t MAX_TLPS = 2; constexpr static uint32_t REORDERING_THRESHOLD = 3; -constexpr static double TIME_REORDERING_FRACTION = 1 / 8; +constexpr static double TIME_REORDERING_FRACTION = 1.0 / 8.0; constexpr static ink_hrtime MIN_TLP_TIMEOUT = HRTIME_MSECONDS(10); constexpr static ink_hrtime MIN_RTO_TIMEOUT = HRTIME_MSECONDS(200); // This is defined on the spec but not used @@ -210,10 +210,10 @@ QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICP // Based on {{RFC6298}}. if (this->_smoothed_rtt == 0) { this->_smoothed_rtt = latest_rtt; - this->_rttvar = latest_rtt / 2; + this->_rttvar = latest_rtt / 2.0; } else { - this->_rttvar = 3 / 4 * this->_rttvar + 1 / 4 * ABS(this->_smoothed_rtt - latest_rtt); - this->_smoothed_rtt = 7 / 8 * this->_smoothed_rtt + 1 / 8 * latest_rtt; + this->_rttvar = 3.0 / 4.0 * this->_rttvar + 1.0 / 4.0 * ABS(this->_smoothed_rtt - latest_rtt); + this->_smoothed_rtt = 7.0 / 8.0 * this->_smoothed_rtt + 1.0 / 8.0 * latest_rtt; } } @@ -326,7 +326,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num delay_until_lost = (1 + this->_time_reordering_fraction) * std::max(this->_latest_rtt, this->_smoothed_rtt); } else if (largest_acked_packet_number == this->_largest_sent_packet) { // Early retransmit alarm. - delay_until_lost = 5 / 4 * std::max(this->_latest_rtt, this->_smoothed_rtt); + delay_until_lost = 5.0 / 4.0 * std::max(this->_latest_rtt, this->_smoothed_rtt); } for (auto &unacked : this->_sent_packets) { From 11c27699e97f8d0ad806f7be190772e4e698dd1c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 9 Jan 2018 17:06:48 +0900 Subject: [PATCH 0299/1313] Fix a testcase for LossDetector --- iocore/net/quic/test/test_QUICLossDetector.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 17f6029bdd7..5cfdfc03cb7 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -126,7 +126,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") detector.on_packet_sent(std::move(packet8)); detector.on_packet_sent(std::move(packet9)); - ink_hrtime_sleep(HRTIME_MSECONDS(10000)); + ink_hrtime_sleep(HRTIME_MSECONDS(1000)); // Receive an ACK for (1) (4) (5) (7) (8) (9) afc->update(pn1, true); @@ -135,8 +135,10 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") afc->update(pn7, true); afc->update(pn8, true); afc->update(pn9, true); + ink_hrtime_sleep(HRTIME_MSECONDS(1000)); frame = afc->create(); detector.handle_frame(frame); + ink_hrtime_sleep(HRTIME_MSECONDS(5000)); CHECK(cc->lost_packets.size() == 3); From b43897362755392e179d1a403d5055bc71583039 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 10 Jan 2018 10:26:40 +0900 Subject: [PATCH 0300/1313] Make sure that loss detection alarm duration is positive value --- iocore/net/quic/QUICLossDetector.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 9b25f527a30..3b793baaf64 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -273,6 +273,14 @@ QUICLossDetector::_set_loss_detection_alarm() QUICLDDebug("RTO alarm will be set"); } + // ADDITIONAL CODE + // alarm_curation can be negative value because _loss_time is updated in _detect_lost_packets() + // In that case, perhaps we should trigger the alarm immediately. + if (alarm_duration < 0) { + alarm_duration = 1; + } + // END OF ADDITONAL CODE + if (this->_loss_detection_alarm_at) { this->_loss_detection_alarm_at = std::min(this->_loss_detection_alarm_at, Thread::get_hrtime() + alarm_duration); } else { From 6cf85f5621715c6b79c1d035dce3a1f4681759e6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 10 Jan 2018 11:50:00 +0900 Subject: [PATCH 0301/1313] Fix QUICTransportParameters for client --- iocore/net/quic/QUICConfig.cc | 27 +++++- iocore/net/quic/QUICConfig.h | 22 +++-- iocore/net/quic/QUICHandshake.cc | 95 ++++++++++++------- iocore/net/quic/QUICHandshake.h | 4 +- iocore/net/quic/QUICTransportParameters.cc | 38 +++++--- iocore/net/quic/QUICTransportParameters.h | 1 + .../quic/test/test_QUICTransportParameters.cc | 6 +- 7 files changed, 130 insertions(+), 63 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 3d6f64528cf..61e74111ead 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -34,6 +34,7 @@ void QUICConfigParams::initialize() { REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_in, "proxy.config.quic.no_activity_timeout_in"); + REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_out, "proxy.config.quic.no_activity_timeout_out"); REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); } @@ -43,6 +44,12 @@ QUICConfigParams::no_activity_timeout_in() const return this->_no_activity_timeout_in; } +uint32_t +QUICConfigParams::no_activity_timeout_out() const +{ + return this->_no_activity_timeout_out; +} + uint32_t QUICConfigParams::server_id() const { @@ -62,15 +69,27 @@ QUICConfigParams::initial_max_stream_data() const } uint32_t -QUICConfigParams::initial_max_stream_id_bidi() const +QUICConfigParams::initial_max_stream_id_bidi_in() const +{ + return this->_initial_max_stream_id_bidi_in; +} + +uint32_t +QUICConfigParams::initial_max_stream_id_bidi_out() const +{ + return this->_initial_max_stream_id_bidi_out; +} + +uint32_t +QUICConfigParams::initial_max_stream_id_uni_in() const { - return this->_initial_max_stream_id_bidi; + return this->_initial_max_stream_id_uni_in; } uint32_t -QUICConfigParams::initial_max_stream_id_uni() const +QUICConfigParams::initial_max_stream_id_uni_out() const { - return this->_initial_max_stream_id_uni; + return this->_initial_max_stream_id_uni_out; } // diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index c6adba4069d..c4525a1a6e3 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -31,20 +31,26 @@ class QUICConfigParams : public ConfigInfo void initialize(); uint32_t no_activity_timeout_in() const; + uint32_t no_activity_timeout_out() const; uint32_t initial_max_data() const; uint32_t initial_max_stream_data() const; - uint32_t initial_max_stream_id_bidi() const; - uint32_t initial_max_stream_id_uni() const; + uint32_t initial_max_stream_id_bidi_in() const; + uint32_t initial_max_stream_id_bidi_out() const; + uint32_t initial_max_stream_id_uni_in() const; + uint32_t initial_max_stream_id_uni_out() const; uint32_t server_id() const; private: // FIXME Fill appropriate values - uint32_t _no_activity_timeout_in = 0; - uint32_t _initial_max_data = 131072; - uint32_t _initial_max_stream_data = 2048; - uint32_t _initial_max_stream_id_bidi = 100; - uint32_t _initial_max_stream_id_uni = 102; - uint32_t _server_id = 0; + uint32_t _no_activity_timeout_in = 30; + uint32_t _no_activity_timeout_out = 30; + uint32_t _initial_max_data = 131072; + uint32_t _initial_max_stream_data = 2048; + uint32_t _initial_max_stream_id_bidi_in = 100; + uint32_t _initial_max_stream_id_bidi_out = 101; + uint32_t _initial_max_stream_id_uni_in = 102; + uint32_t _initial_max_stream_id_uni_out = 103; + uint32_t _server_id = 0; }; class QUICConfig diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index b2ff6e69cff..f47b4a2d8f6 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -178,7 +178,7 @@ QUICHandshake::negotiated_application_name(const uint8_t **name, unsigned int *l } void -QUICHandshake::set_transport_parameters(std::shared_ptr tp) +QUICHandshake::set_transport_parameters(std::shared_ptr tp) { // An endpoint MUST treat receipt of duplicate transport parameters as a connection error of type TRANSPORT_PARAMETER_ERROR. if (!tp->is_valid()) { @@ -187,27 +187,33 @@ QUICHandshake::set_transport_parameters(std::shared_ptr return; } - this->_remote_transport_parameters = std::move(tp); + this->_remote_transport_parameters = tp; - const QUICTransportParametersInClientHello *tp_in_ch = - dynamic_cast(this->_remote_transport_parameters.get()); - if (tp_in_ch) { - // Version revalidation - if (this->_version_negotiator->validate(tp_in_ch) != QUICVersionNegotiationStatus::VALIDATED) { - QUICHSDebug("Version revalidation failed"); - this->_abort_handshake(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR); - return; - } - QUICHSDebug("Version negotiation validated: %x", tp_in_ch->initial_version()); + // Version revalidation + if (this->_version_negotiator->validate(tp.get()) != QUICVersionNegotiationStatus::VALIDATED) { + QUICHSDebug("Version revalidation failed"); + this->_abort_handshake(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR); return; } - const QUICTransportParametersInEncryptedExtensions *tp_in_ee = - dynamic_cast(this->_remote_transport_parameters.get()); - if (tp_in_ee) { - // TODO Add client side implementation + QUICHSDebug("Version negotiation validated: %x", tp->initial_version()); + return; +} + +void +QUICHandshake::set_transport_parameters(std::shared_ptr tp) +{ + // An endpoint MUST treat receipt of duplicate transport parameters as a connection error of type TRANSPORT_PARAMETER_ERROR. + if (!tp->is_valid()) { + QUICHSDebug("Transport parameter is not valid"); + this->_abort_handshake(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR); return; } + + this->_remote_transport_parameters = tp; + + // TODO Add client side implementation + ink_assert(false); } std::shared_ptr @@ -222,6 +228,12 @@ QUICHandshake::remote_transport_parameters() return this->_remote_transport_parameters; } +NetVConnectionContext_t +QUICHandshake::netvc_context() +{ + return this->_netvc_context; +} + int QUICHandshake::state_initial(int event, Event *data) { @@ -346,26 +358,43 @@ QUICHandshake::state_closed(int event, void *data) } void -QUICHandshake::_load_local_transport_parameters(QUICVersion negotiated_version) +QUICHandshake::_load_local_transport_parameters(QUICVersion version) { QUICConfig::scoped_config params; - // MUSTs - QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(negotiated_version); - - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); - tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); - tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); - // These two are MUSTs if this is a server - tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), 16); - tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); - - // MAYs - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi()); - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni()); - // this->_local_transport_parameters.add(QUICTransportParameterId::OMIT_CONNECTION_ID, {}); - // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); - this->_local_transport_parameters = std::unique_ptr(tp); + if (this->_netvc_context == NET_VCONNECTION_IN) { + QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(version); + + // MUSTs + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); + tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); + tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); + + // These two are MUSTs if this is a server + tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN); + tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); + + // MAYs + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi_in()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni_in()); + // this->_local_transport_parameters.add(QUICTransportParameterId::OMIT_CONNECTION_ID, {}); + // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); + + this->_local_transport_parameters = std::unique_ptr(tp); + } else { + QUICTransportParametersInClientHello *tp = new QUICTransportParametersInClientHello(version); + + // MUSTs + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); + tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); + tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_out())); + + // MAYs + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi_out()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni_out()); + + this->_local_transport_parameters = std::unique_ptr(tp); + } } QUICErrorUPtr diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 6c426f29c06..f6c5f49ada0 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -71,11 +71,13 @@ class QUICHandshake : public QUICApplication void negotiated_application_name(const uint8_t **name, unsigned int *len); std::shared_ptr local_transport_parameters(); std::shared_ptr remote_transport_parameters(); + NetVConnectionContext_t netvc_context(); bool is_version_negotiated(); bool is_completed(); - void set_transport_parameters(std::shared_ptr tp); + void set_transport_parameters(std::shared_ptr tp); + void set_transport_parameters(std::shared_ptr tp); private: SSL *_ssl = nullptr; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index c81b5f66df1..846a664b45c 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -296,16 +296,9 @@ QUICTransportParameters::store(uint8_t *buf, uint16_t *len) const *len = (p - buf); } -// -// QUICTransportParametersInClientHello -// - -QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const uint8_t *buf, size_t len) +void +QUICTransportParameters::_print() const { - this->_initial_version = QUICTypeUtil::read_QUICVersion(buf); - this->_load(buf, len); - - // Print all parameters for (auto &p : this->_parameters) { if (p.second->len() == 0) { Debug("quic_handsahke", "%s: (no value)", QUICDebugNames::transport_parameter_id(p.first)); @@ -319,6 +312,17 @@ QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const } } +// +// QUICTransportParametersInClientHello +// + +QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const uint8_t *buf, size_t len) +{ + this->_initial_version = QUICTypeUtil::read_QUICVersion(buf); + this->_load(buf, len); + this->_print(); +} + void QUICTransportParametersInClientHello::_store(uint8_t *buf, uint16_t *len) const { @@ -351,19 +355,19 @@ QUICTransportParametersInClientHello::_validate_parameters() const // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI)) != this->_parameters.end()) { if (ite->second->len() != 4) { - return -1; + return -2; } if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 1) { - return -1; + return -3; } } if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI)) != this->_parameters.end()) { if (ite->second->len() != 4) { - return -1; + return -4; } if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 3) { - return -1; + return -5; } } @@ -388,6 +392,7 @@ QUICTransportParametersInEncryptedExtensions::QUICTransportParametersInEncrypted this->_versions[i] = QUICTypeUtil::read_QUICVersion(buf + 5 + (i * 4)); } this->_load(buf, len); + this->_print(); } void @@ -494,7 +499,12 @@ QUICTransportParametersHandler::parse(SSL *s, unsigned int ext_type, unsigned in X509 *x, size_t chainidx, int *al, void *parse_arg) { QUICHandshake *hs = static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_hs_index)); - hs->set_transport_parameters(std::make_shared(in, inlen)); + + if (hs->netvc_context() == NET_VCONNECTION_IN) { + hs->set_transport_parameters(std::make_shared(in, inlen)); + } else { + hs->set_transport_parameters(std::make_shared(in, inlen)); + } return 1; } diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 6bb052e791f..a3f8000360b 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -106,6 +106,7 @@ class QUICTransportParameters virtual std::ptrdiff_t _parameters_offset(const uint8_t *buf) const = 0; virtual int _validate_parameters() const; virtual void _store(uint8_t *buf, uint16_t *len) const = 0; + void _print() const; std::map _parameters; }; diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index 520c69ecad7..2825f2d3fae 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -30,7 +30,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") SECTION("OK") { uint8_t buf[] = { - 0x05, 0x06, 0x07, 0x08, // iinitial version + 0x05, 0x06, 0x07, 0x08, // initial version 0x00, 0x1e, // size of parameters 0x00, 0x00, // parameter id 0x00, 0x04, // length of value @@ -77,7 +77,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") SECTION("Duplicate parameters") { uint8_t buf[] = { - 0x05, 0x06, 0x07, 0x08, // iinitial version + 0x05, 0x06, 0x07, 0x08, // initial version 0x00, 0x10, // size of parameters 0x00, 0x00, // parameter id 0x00, 0x04, // length of value @@ -98,7 +98,7 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") uint16_t len; uint8_t expected[] = { - 0x05, 0x06, 0x07, 0x08, // iinitial version + 0x05, 0x06, 0x07, 0x08, // initial version 0x00, 0x22, // size of parameters 0x00, 0x00, // parameter id 0x00, 0x04, // length of value From e6f5c12642537c6d5d5b6a8a9d95d91a48ca9f86 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 10 Jan 2018 11:50:43 +0900 Subject: [PATCH 0302/1313] Format QUICStreamType --- iocore/net/quic/QUICTypes.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 9d9504edace..e8d1d717cf6 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -246,7 +246,13 @@ class QUICStatelessResetToken void _gen_token(uint64_t data); }; -enum class QUICStreamType { CLIENT_BIDI, SERVER_BIDI, CLIENT_UNI, SERVER_UNI, HANDSHAKE }; +enum class QUICStreamType { + CLIENT_BIDI, + SERVER_BIDI, + CLIENT_UNI, + SERVER_UNI, + HANDSHAKE, +}; class QUICTypeUtil { From 56b8ac248f8c45cf63154db896041794a224c67a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 10 Jan 2018 12:31:35 +0900 Subject: [PATCH 0303/1313] Retransmit all lost packets without congestion control --- iocore/net/QUICNetVConnection.cc | 1 + iocore/net/quic/QUICLossDetector.cc | 15 +++++++++++++++ iocore/net/quic/QUICLossDetector.h | 1 + 3 files changed, 17 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 770ebc6dc4a..8744bffe5b9 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -786,6 +786,7 @@ QUICNetVConnection::_packetize_frames() QUICFrameUPtr frame(nullptr, nullptr); bool retransmittable = false; + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); QUICFrameUPtr ack_frame = QUICFrameFactory::create_null_ack_frame(); diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 3b793baaf64..8b55569daaf 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -325,6 +325,7 @@ QUICLossDetector::_on_loss_detection_alarm() void QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_number) { + SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); this->_loss_time = 0; std::map lost_packets; @@ -357,6 +358,12 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num if (!lost_packets.empty()) { this->_cc->on_packets_lost(lost_packets); for (auto lost_packet : lost_packets) { + // ADDITIONAL CODE + // Not sure how we can get feedback from congestion control and when we should retransmit the lost packets but we need to send + // them somewhere. + // I couldn't find the place so just send them here for now. + this->_retransmit_lost_packet(*lost_packet.second.packet); + // END OF ADDITIONAL CODE this->_remove_from_sent_packet_list(lost_packet.first); } } @@ -416,6 +423,14 @@ QUICLossDetector::_send_two_packets() // ===== Functions below are helper functions ===== +void +QUICLossDetector::_retransmit_lost_packet(const QUICPacket &packet) +{ + SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + this->_transmitter->retransmit_packet(packet); +} + std::set QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame) { diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 94b707de310..6b253c9f3f8 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -125,6 +125,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _detect_lost_packets(QUICPacketNumber largest_acked); void _set_loss_detection_alarm(); void _on_loss_detection_alarm(); + void _retransmit_lost_packet(const QUICPacket &packet); std::set _determine_newly_acked_packets(const QUICAckFrame &ack_frame); From 24c99bcdb1d988d6aed3b131e4e2dafc3ff1531d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 10 Jan 2018 14:15:49 +0900 Subject: [PATCH 0304/1313] Add some command line arguments on quic client --- cmd/traffic_quic/traffic_quic.cc | 45 ++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index a38289b9365..0de075432fa 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -26,7 +26,9 @@ #include "P_QUICNetProcessor.h" #include "ts/ink_string.h" +#include "ts/ink_args.h" #include "ts/I_Layout.h" +#include "ts/I_Version.h" #define THREADS 1 #define DIAGS_LOG_FILE "diags.log" @@ -105,11 +107,11 @@ class QUICClient : public Continuation { public: QUICClient() : Continuation(new_ProxyMutex()) { SET_HANDLER(&QUICClient::state_http_server_open); }; - void start(); + void start(const char *host, int port); int state_http_server_open(int event, void *data); }; -// HttpSM::state_http_server_open(int event, void *data) +// Similar to HttpSM::state_http_server_open(int event, void *data) int QUICClient::state_http_server_open(int event, void *data) { @@ -131,14 +133,14 @@ QUICClient::state_http_server_open(int event, void *data) return 0; } -// TODO: ip:port void -QUICClient::start() +QUICClient::start(const char * /* remote_addr */, int remote_port) { + // TODO: getdddrinfo sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = htons(4433); + addr.sin_port = htons(remote_port); NetVCOptions opt; opt.ip_proto = NetVCOptions::USE_UDP; @@ -149,11 +151,37 @@ QUICClient::start() quic_NetProcessor.connect_re(this, reinterpret_cast(&addr), &opt); } +// TODO: Support QUIC version, cipher suite ...etc +// TODO: Support qdrive tests +// https://github.com/ekr/qdrive +// https://github.com/mcmanus/mozquic/tree/master/tests/qdrive int -main(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */) +main(int argc, const char **argv) { + // Before accessing file system initialize Layout engine Layout::create(); - init_diags("quic|udp", nullptr); + + // Set up the application version info + AppVersionInfo appVersionInfo; + appVersionInfo.setup(PACKAGE_NAME, "traffic_quic", PACKAGE_VERSION, __DATE__, __TIME__, BUILD_MACHINE, BUILD_PERSON, ""); + + char addr[1024] = ""; + int port = 4433; + char debug_tags[1024] = ""; + + const ArgumentDescription argument_descriptions[] = { + {"addr", 'a', "Address", "S1023", addr, nullptr, nullptr}, + {"port", 'p', "Port", "I", &port, nullptr, nullptr}, + {"debug", 'T', "Vertical-bar-separated Debug Tags", "S1023", debug_tags, nullptr, nullptr}, + HELP_ARGUMENT_DESCRIPTION(), + VERSION_ARGUMENT_DESCRIPTION(), + RUNROOT_ARGUMENT_DESCRIPTION(), + }; + + // Process command line arguments and dump into variables + process_args(&appVersionInfo, argument_descriptions, countof(argument_descriptions), argv); + + init_diags(debug_tags, nullptr); RecProcessInit(RECM_STAND_ALONE); SSLInitializeLibrary(); @@ -168,11 +196,12 @@ main(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */) main_thread->set_specific(); QUICClient client; - client.start(); + client.start(addr, port); main_thread->execute(); } +// FIXME: remove stub // // stub // From cb4ea64f415c6e5030e74792c680d4adeeb6c2c2 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 10 Jan 2018 14:27:35 +0900 Subject: [PATCH 0305/1313] Resolve a deadlock --- iocore/net/quic/QUICLossDetector.cc | 27 +++++++++++++++------------ iocore/net/quic/QUICLossDetector.h | 2 ++ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 8b55569daaf..93aa5a85c86 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -42,7 +42,8 @@ constexpr static ink_hrtime DEFAULT_INITIAL_RTT = HRTIME_MSECONDS(100); QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICCongestionController *cc) : _transmitter(transmitter), _cc(cc) { - this->mutex = new_ProxyMutex(); + this->mutex = new_ProxyMutex(); + this->_loss_detection_mutex = new_ProxyMutex(); if (this->_time_loss_detection) { this->_reordering_threshold = UINT32_MAX; @@ -69,7 +70,7 @@ QUICLossDetector::event_handler(int event, Event *edata) break; } case QUIC_EVENT_LD_SHUTDOWN: { - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); QUICLDDebug("Shutdown"); if (this->_loss_detection_alarm) { @@ -141,7 +142,7 @@ void QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes, QUICPacketUPtr packet) { - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); this->_time_of_last_sent_packet = Thread::get_hrtime(); this->_largest_sent_packet = packet_number; // FIXME Should we really keep actual packet object? @@ -158,7 +159,8 @@ QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_ack_on void QUICLossDetector::_on_ack_received(const std::shared_ptr &ack_frame) { - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); this->_largest_acked_packet = ack_frame->largest_acknowledged(); // If the largest acked is newly acked, update the RTT. auto pi = this->_sent_packets.find(ack_frame->largest_acknowledged()); @@ -220,7 +222,8 @@ QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICP void QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size) { - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number); this->_cc->on_packet_acked(acked_packet_number, acked_packet_size); // If a packet sent prior to RTO was acked, then the RTO @@ -326,7 +329,7 @@ void QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_number) { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); this->_loss_time = 0; std::map lost_packets; double delay_until_lost = INFINITY; @@ -375,7 +378,7 @@ void QUICLossDetector::_retransmit_handshake_packets() { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); std::set retransmitted_handshake_packets; for (auto &info : this->_sent_packets) { @@ -395,7 +398,7 @@ void QUICLossDetector::_send_one_packet() { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); if (this->_transmitter->transmit_packet() < 1) { auto ite = this->_sent_packets.rbegin(); if (ite != this->_sent_packets.rend()) { @@ -408,7 +411,7 @@ void QUICLossDetector::_send_two_packets() { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); auto ite = this->_sent_packets.rbegin(); if (ite != this->_sent_packets.rend()) { this->_transmitter->retransmit_packet(*ite->second->packet); @@ -427,7 +430,7 @@ void QUICLossDetector::_retransmit_lost_packet(const QUICPacket &packet) { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); this->_transmitter->retransmit_packet(packet); } @@ -454,7 +457,7 @@ QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame) void QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr packet_info) { - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // Add to the list this->_sent_packets.insert(std::pair>(packet_number, std::move(packet_info))); @@ -476,7 +479,7 @@ QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, std:: void QUICLossDetector::_remove_from_sent_packet_list(QUICPacketNumber packet_number) { - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // Decrement counters auto ite = this->_sent_packets.find(packet_number); diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 6b253c9f3f8..924f2217392 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -78,6 +78,8 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler QUICPacketNumber largest_acked_packet_number(); private: + Ptr _loss_detection_mutex; + QUICConnectionId _connection_id = 0; bool _time_loss_detection = true; From 4576fc763dab539f4dbe278fc1a92c4f465acfc2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 10 Jan 2018 15:05:15 +0900 Subject: [PATCH 0306/1313] Cleanup QUICTransportParametersHandler::parse --- iocore/net/quic/QUICHandshake.cc | 6 ----- iocore/net/quic/QUICHandshake.h | 1 - iocore/net/quic/QUICTransportParameters.cc | 29 ++++++++++++++-------- iocore/net/quic/QUICTransportParameters.h | 2 -- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index f47b4a2d8f6..a7835107f3b 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -228,12 +228,6 @@ QUICHandshake::remote_transport_parameters() return this->_remote_transport_parameters; } -NetVConnectionContext_t -QUICHandshake::netvc_context() -{ - return this->_netvc_context; -} - int QUICHandshake::state_initial(int event, Event *data) { diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index f6c5f49ada0..1f5fbbd5ef3 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -71,7 +71,6 @@ class QUICHandshake : public QUICApplication void negotiated_application_name(const uint8_t **name, unsigned int *len); std::shared_ptr local_transport_parameters(); std::shared_ptr remote_transport_parameters(); - NetVConnectionContext_t netvc_context(); bool is_version_negotiated(); bool is_completed(); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 846a664b45c..a75895d1719 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -30,6 +30,7 @@ #include "../P_QUICNetVConnection.h" static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; +static constexpr char tag[] = "quic_handshake"; QUICTransportParameters::Value::Value(const uint8_t *data, uint16_t len) : _len(len) { @@ -301,13 +302,13 @@ QUICTransportParameters::_print() const { for (auto &p : this->_parameters) { if (p.second->len() == 0) { - Debug("quic_handsahke", "%s: (no value)", QUICDebugNames::transport_parameter_id(p.first)); + Debug(tag, "%s: (no value)", QUICDebugNames::transport_parameter_id(p.first)); } else if (p.second->len() <= 8) { - Debug("quic_handsahke", "%s: 0x%" PRIx64 " (%" PRIu64 ")", QUICDebugNames::transport_parameter_id(p.first), + Debug(tag, "%s: 0x%" PRIx64 " (%" PRIu64 ")", QUICDebugNames::transport_parameter_id(p.first), QUICTypeUtil::read_nbytes_as_uint(p.second->data(), p.second->len()), QUICTypeUtil::read_nbytes_as_uint(p.second->data(), p.second->len())); } else { - Debug("quic_handsahke", "%s: (long data)", QUICDebugNames::transport_parameter_id(p.first)); + Debug(tag, "%s: (long data)", QUICDebugNames::transport_parameter_id(p.first)); } } } @@ -448,25 +449,25 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const return -1; } } else { - return -1; + return -2; } // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI)) != this->_parameters.end()) { if (ite->second->len() != 4) { - return -1; + return -3; } if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 1) { - return -1; + return -4; } } if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI)) != this->_parameters.end()) { if (ite->second->len() != 4) { - return -1; + return -5; } if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 3) { - return -1; + return -6; } } @@ -500,10 +501,18 @@ QUICTransportParametersHandler::parse(SSL *s, unsigned int ext_type, unsigned in { QUICHandshake *hs = static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_hs_index)); - if (hs->netvc_context() == NET_VCONNECTION_IN) { + switch (context) { + case SSL_EXT_CLIENT_HELLO: { hs->set_transport_parameters(std::make_shared(in, inlen)); - } else { + break; + } + case SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS: { hs->set_transport_parameters(std::make_shared(in, inlen)); + break; + } + default: + // Do nothing + break; } return 1; diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index a3f8000360b..46aa1b4e768 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -154,9 +154,7 @@ class QUICTransportParametersHandler static int add(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char **out, size_t *outlen, X509 *x, size_t chainidx, int *al, void *add_arg); - static void free(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *out, void *add_arg); - static int parse(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *in, size_t inlen, X509 *x, size_t chainidx, int *al, void *parse_arg); }; From 23fe5043a1e361ed4b62648175882d469c4d1768 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 12 Jan 2018 16:57:15 +0900 Subject: [PATCH 0307/1313] Set net_config_poll_timeout on quic client --- cmd/traffic_quic/traffic_quic.cc | 33 ++++++++++++++++++--------- iocore/net/QUICNetProcessor.cc | 38 +++++++++++++++++++++++++++----- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index 0de075432fa..6d455524f98 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -106,9 +106,13 @@ init_diags(const char *bdt, const char *bat) class QUICClient : public Continuation { public: - QUICClient() : Continuation(new_ProxyMutex()) { SET_HANDLER(&QUICClient::state_http_server_open); }; - void start(const char *host, int port); + QUICClient(const char *addr, int port) : Continuation(new_ProxyMutex()), _remote_port(port) { SET_HANDLER(&QUICClient::start); }; + void start(); int state_http_server_open(int event, void *data); + +private: + // char *_remote_addr = nullptr; + int _remote_port = 0; }; // Similar to HttpSM::state_http_server_open(int event, void *data) @@ -126,6 +130,10 @@ QUICClient::state_http_server_open(int event, void *data) ink_assert(false); break; } + case NET_EVENT_ACCEPT: { + // do nothing + break; + } default: ink_assert(false); } @@ -134,13 +142,15 @@ QUICClient::state_http_server_open(int event, void *data) } void -QUICClient::start(const char * /* remote_addr */, int remote_port) +QUICClient::start() { + SET_HANDLER(&QUICClient::state_http_server_open); + // TODO: getdddrinfo sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = htons(remote_port); + addr.sin_port = htons(this->_remote_port); NetVCOptions opt; opt.ip_proto = NetVCOptions::USE_UDP; @@ -167,7 +177,7 @@ main(int argc, const char **argv) char addr[1024] = ""; int port = 4433; - char debug_tags[1024] = ""; + char debug_tags[1024] = "quic|udp"; const ArgumentDescription argument_descriptions[] = { {"addr", 'a', "Address", "S1023", addr, nullptr, nullptr}, @@ -184,6 +194,10 @@ main(int argc, const char **argv) init_diags(debug_tags, nullptr); RecProcessInit(RECM_STAND_ALONE); + Thread *main_thread = new EThread; + main_thread->set_specific(); + net_config_poll_timeout = 10; + SSLInitializeLibrary(); SSLConfig::startup(); @@ -192,13 +206,10 @@ main(int argc, const char **argv) udpNet.start(1, stacksize); quic_NetProcessor.start(-1, stacksize); - Thread *main_thread = new EThread; - main_thread->set_specific(); - - QUICClient client; - client.start(addr, port); + QUICClient client(addr, port); + eventProcessor.schedule_in(&client, 1, ET_UDP); - main_thread->execute(); + this_thread()->execute(); } // FIXME: remove stub diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 7decb54dd50..a67cb412fc8 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -110,25 +110,51 @@ QUICNetProcessor::allocate_vc(EThread *t) } Action * -QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *addr, NetVCOptions *opt) +QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, NetVCOptions *opt) { Debug("quic_ps", "connect to server"); EThread *t = cont->mutex->thread_holding; ink_assert(t); + sockaddr_in local_addr; + local_addr.sin_family = AF_INET; + local_addr.sin_addr.s_addr = htonl(INADDR_ANY); + local_addr.sin_port = 0; + + // FIXME: set buffer size + int fd = socketManager.socket(local_addr.sin_family, SOCK_DGRAM, 0); + if (fd < 0) { + return ACTION_IO_ERROR; + } + + int res = fcntl(fd, F_SETFL, O_NONBLOCK); + if (res < 0) { + return ACTION_IO_ERROR; + } + // Setup UDPConnection - // FIXME: use udpNet.CreateUDPSocket - int fd = socket(AF_INET, SOCK_DGRAM, 0); UnixUDPConnection *con = new UnixUDPConnection(fd); + Debug("quic_ps", "con=%p fd=%d", con, fd); + AcceptOptions const accept_opt; + // FIXME: create QUICPacketHandler for Client (origin server side) QUICPacketHandler *packet_handler = new QUICPacketHandler(accept_opt, this->_ssl_ctx); - con->setBinding(addr); + packet_handler->init_accept(t); + packet_handler->action_ = new NetAcceptAction(); + *packet_handler->action_ = cont; + + con->setBinding(reinterpret_cast(&local_addr)); con->bindToThread(packet_handler); PollCont *pc = get_UDPPollCont(con->ethread); PollDescriptor *pd = pc->pollDescriptor; - con->ep.start(pd, con, EVENTIO_READ); + + errno = 0; + res = con->ep.start(pd, con, EVENTIO_READ); + if (res < 0) { + Debug("udpnet", "Error: %s (%d)", strerror(errno), errno); + } // Setup QUICNetVConnection QUICConnectionId cid; @@ -145,7 +171,7 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *addr, NetVCOpti // Connection ID will be changed vc->id = net_next_connection_number(); vc->set_context(NET_VCONNECTION_OUT); - vc->con.setRemote(addr); + vc->con.setRemote(remote_addr); vc->submit_time = Thread::get_hrtime(); vc->mutex = cont->mutex; vc->action_ = cont; From b7885e3d75dd2640a56f9a0a2492abf96403c8b1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 12 Jan 2018 17:52:57 +0900 Subject: [PATCH 0308/1313] Refactor QUICHandshake constructor & start() --- iocore/net/QUICNetVConnection.cc | 12 +++++++----- iocore/net/quic/QUICHandshake.cc | 18 ++++++++++++++---- iocore/net/quic/QUICHandshake.h | 6 ++++++ iocore/net/quic/test/test_QUICHandshake.cc | 5 +---- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8744bffe5b9..9411ded144d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -93,14 +93,16 @@ QUICNetVConnection::startEvent(int /*event ATS_UNUSED */, Event *e) void QUICNetVConnection::start(SSL_CTX *ssl_ctx) { - { + // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not + if (this->direction() == NET_VCONNECTION_IN) { QUICConfig::scoped_config params; this->_reset_token.generate(this->_quic_connection_id, params->server_id()); + this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_reset_token); + } else { + this->_handshake_handler = new QUICHandshake(this, ssl_ctx); + this->_handshake_handler->start(&this->_packet_factory); } - - // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not - this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_reset_token); - this->_application_map = new QUICApplicationMap(); + this->_application_map = new QUICApplicationMap(); this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); this->_crypto = this->_handshake_handler->crypto_module(); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index a7835107f3b..b52efc0f2d8 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -83,8 +83,7 @@ static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token) - : QUICApplication(qc), _reset_token(token) +QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICApplication(qc) { this->_ssl = SSL_new(ssl_ctx); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc); @@ -94,17 +93,28 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless this->_version_negotiator = new QUICVersionNegotiator(); this->_crypto->initialize_key_materials(this->_client_qc->original_connection_id()); - // for client initial - this->_load_local_transport_parameters(QUIC_SUPPORTED_VERSIONS[0]); SET_HANDLER(&QUICHandshake::state_initial); } +QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token) : QUICHandshake(qc, ssl_ctx) +{ + this->_reset_token = token; +} + QUICHandshake::~QUICHandshake() { SSL_free(this->_ssl); } +QUICErrorUPtr +QUICHandshake::start(QUICPacketFactory *packet_factory) +{ + this->_load_local_transport_parameters(QUIC_SUPPORTED_VERSIONS[0]); + packet_factory->set_version(QUIC_SUPPORTED_VERSIONS[0]); + return QUICErrorUPtr(new QUICNoError()); +} + QUICErrorUPtr QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory) { diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 1f5fbbd5ef3..75f2d5d3db7 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -51,9 +51,15 @@ class SSLNextProtocolSet; class QUICHandshake : public QUICApplication { public: + // Constructor for client side + QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx); + // Constructor for server side QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token); ~QUICHandshake(); + // for client side + QUICErrorUPtr start(QUICPacketFactory *packet_factory); + // for server side QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); // States diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc index 71d51af277d..71ea0e65347 100644 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -41,11 +41,8 @@ TEST_CASE("1-RTT handshake ", "[quic]") SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); QUICConnectionId client_conn_id = 0x12345; - // FIXME: remove this. client side stateless reset token doesn't make sense - QUICStatelessResetToken client_token; - client_token.generate(client_conn_id, 0); - QUICHandshake *client = new QUICHandshake(client_qc, client_ssl_ctx, client_token); + QUICHandshake *client = new QUICHandshake(client_qc, client_ssl_ctx); // setup server QUICConnection *server_qc = new MockQUICConnection(NET_VCONNECTION_IN); From a897358589476006deddf729f5b71ec0d340b284 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 12 Jan 2018 18:23:54 +0900 Subject: [PATCH 0309/1313] Send transport parameters on NewSessionTicket messages too --- iocore/net/QUICNetProcessor.cc | 3 +- iocore/net/quic/QUICHandshake.cc | 105 ++++++++++++++------- iocore/net/quic/QUICHandshake.h | 6 +- iocore/net/quic/QUICTransportParameters.cc | 75 ++++++++++++++- iocore/net/quic/QUICTransportParameters.h | 12 +++ 5 files changed, 158 insertions(+), 43 deletions(-) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index a67cb412fc8..31740f511be 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -70,7 +70,8 @@ QUICNetProcessor::start(int, size_t stacksize) SSL_CTX_set_max_proto_version(this->_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_alpn_select_cb(this->_ssl_ctx, QUIC::ssl_select_next_protocol, nullptr); SSL_CTX_add_custom_ext(this->_ssl_ctx, QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID, - SSL_EXT_TLS_ONLY | SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS, + SSL_EXT_TLS_ONLY | SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS | + SSL_EXT_TLS1_3_NEW_SESSION_TICKET, &QUICTransportParametersHandler::add, &QUICTransportParametersHandler::free, nullptr, &QUICTransportParametersHandler::parse, nullptr); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index b52efc0f2d8..d80a6f898ff 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -110,7 +110,7 @@ QUICHandshake::~QUICHandshake() QUICErrorUPtr QUICHandshake::start(QUICPacketFactory *packet_factory) { - this->_load_local_transport_parameters(QUIC_SUPPORTED_VERSIONS[0]); + this->_load_local_client_transport_parameters(QUIC_SUPPORTED_VERSIONS[0]); packet_factory->set_version(QUIC_SUPPORTED_VERSIONS[0]); return QUICErrorUPtr(new QUICNoError()); } @@ -126,7 +126,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet if (initial_packet->version()) { if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { QUICHSDebug("Version negotiation succeeded: %x", initial_packet->version()); - this->_load_local_transport_parameters(initial_packet->version()); + this->_load_local_server_transport_parameters(initial_packet->version()); packet_factory->set_version(this->_version_negotiator->negotiated_version()); } else { this->_client_qc->transmit_packet( @@ -226,10 +226,45 @@ QUICHandshake::set_transport_parameters(std::shared_ptr tp) +{ + // An endpoint MUST treat receipt of duplicate transport parameters as a connection error of type TRANSPORT_PARAMETER_ERROR. + if (!tp->is_valid()) { + QUICHSDebug("Transport parameter is not valid"); + this->_abort_handshake(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR); + return; + } + + this->_remote_transport_parameters = tp; + + // TODO Add client side implementation + ink_assert(false); +} + std::shared_ptr -QUICHandshake::local_transport_parameters() +QUICHandshake::local_transport_parameters(bool with_version) { - return this->_local_transport_parameters; + if (with_version) { + return this->_local_transport_parameters; + } else { + QUICConfig::scoped_config params; + QUICTransportParametersInNewSessionTicket *tp = new QUICTransportParametersInNewSessionTicket(); + + // MUSTs + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); + tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); + tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); + tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN); + + // MAYs + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi_in()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni_in()); + // this->_local_transport_parameters.add(QUICTransportParameterId::OMIT_CONNECTION_ID, {}); + // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); + + return std::unique_ptr(tp); + } } std::shared_ptr @@ -360,45 +395,45 @@ QUICHandshake::state_closed(int event, void *data) { return EVENT_DONE; } - void -QUICHandshake::_load_local_transport_parameters(QUICVersion version) +QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_version) { QUICConfig::scoped_config params; + QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(negotiated_version); + + // MUSTs + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); + tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); + tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); + tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN); + tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); + + // MAYs + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi_in()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni_in()); + // this->_local_transport_parameters.add(QUICTransportParameterId::OMIT_CONNECTION_ID, {}); + // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); + + this->_local_transport_parameters = std::unique_ptr(tp); +} - if (this->_netvc_context == NET_VCONNECTION_IN) { - QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(version); - - // MUSTs - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); - tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); - tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); - - // These two are MUSTs if this is a server - tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN); - tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); - - // MAYs - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi_in()); - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni_in()); - // this->_local_transport_parameters.add(QUICTransportParameterId::OMIT_CONNECTION_ID, {}); - // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); +void +QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_version) +{ + QUICConfig::scoped_config params; - this->_local_transport_parameters = std::unique_ptr(tp); - } else { - QUICTransportParametersInClientHello *tp = new QUICTransportParametersInClientHello(version); + QUICTransportParametersInClientHello *tp = new QUICTransportParametersInClientHello(initial_version); - // MUSTs - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); - tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); - tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_out())); + // MUSTs + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); + tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); + tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_out())); - // MAYs - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi_out()); - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni_out()); + // MAYs + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi_out()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni_out()); - this->_local_transport_parameters = std::unique_ptr(tp); - } + this->_local_transport_parameters = std::unique_ptr(tp); } QUICErrorUPtr diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 75f2d5d3db7..9c2e45072b0 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -75,7 +75,7 @@ class QUICHandshake : public QUICApplication QUICVersion negotiated_version(); const char *negotiated_cipher_suite(); void negotiated_application_name(const uint8_t **name, unsigned int *len); - std::shared_ptr local_transport_parameters(); + std::shared_ptr local_transport_parameters(bool with_version = true); std::shared_ptr remote_transport_parameters(); bool is_version_negotiated(); @@ -83,6 +83,7 @@ class QUICHandshake : public QUICApplication void set_transport_parameters(std::shared_ptr tp); void set_transport_parameters(std::shared_ptr tp); + void set_transport_parameters(std::shared_ptr tp); private: SSL *_ssl = nullptr; @@ -92,7 +93,8 @@ class QUICHandshake : public QUICApplication QUICVersionNegotiator *_version_negotiator = nullptr; - void _load_local_transport_parameters(QUICVersion negotiated_version); + void _load_local_server_transport_parameters(QUICVersion negotiated_version); + void _load_local_client_transport_parameters(QUICVersion initial_version); QUICErrorUPtr _do_handshake(bool initial = false); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index a75895d1719..4a511b20859 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -474,6 +474,69 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const return 0; } +// +// QUICTransportParametersInNewSessionTicket +// + +QUICTransportParametersInNewSessionTicket::QUICTransportParametersInNewSessionTicket(const uint8_t *buf, size_t len) +{ + this->_load(buf, len); + this->_print(); +} + +void +QUICTransportParametersInNewSessionTicket::_store(uint8_t *buf, uint16_t *len) const +{ + // no additional fields defined + len = 0; +} + +std::ptrdiff_t +QUICTransportParametersInNewSessionTicket::_parameters_offset(const uint8_t *buf) const +{ + return 0; +} + +int +QUICTransportParametersInNewSessionTicket::_validate_parameters() const +{ + if (QUICTransportParameters::_validate_parameters() < 0) { + return 0; + } + + decltype(this->_parameters)::const_iterator ite; + + // MUSTs + if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) { + if (ite->second->len() != 2) { + return -1; + } + } else { + return -2; + } + + // MAYs + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI)) != this->_parameters.end()) { + if (ite->second->len() != 4) { + return -3; + } + if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 1) { + return -4; + } + } + + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI)) != this->_parameters.end()) { + if (ite->second->len() != 4) { + return -5; + } + if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 3) { + return -6; + } + } + + return 0; +} + // // QUICTransportParametersHandler // @@ -484,7 +547,8 @@ QUICTransportParametersHandler::add(SSL *s, unsigned int ext_type, unsigned int { QUICHandshake *hs = static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_hs_index)); *out = reinterpret_cast(ats_malloc(TRANSPORT_PARAMETERS_MAXIMUM_SIZE)); - hs->local_transport_parameters()->store(const_cast(*out), reinterpret_cast(outlen)); + bool with_version = (context == SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS); + hs->local_transport_parameters(with_version)->store(const_cast(*out), reinterpret_cast(outlen)); return 1; } @@ -502,14 +566,15 @@ QUICTransportParametersHandler::parse(SSL *s, unsigned int ext_type, unsigned in QUICHandshake *hs = static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_hs_index)); switch (context) { - case SSL_EXT_CLIENT_HELLO: { + case SSL_EXT_CLIENT_HELLO: hs->set_transport_parameters(std::make_shared(in, inlen)); break; - } - case SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS: { + case SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS: hs->set_transport_parameters(std::make_shared(in, inlen)); break; - } + case SSL_EXT_TLS1_3_NEW_SESSION_TICKET: + hs->set_transport_parameters(std::make_shared(in, inlen)); + break; default: // Do nothing break; diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 46aa1b4e768..11bc8b08faa 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -147,6 +147,18 @@ class QUICTransportParametersInEncryptedExtensions : public QUICTransportParamet QUICVersion _versions[256] = {}; }; +class QUICTransportParametersInNewSessionTicket : public QUICTransportParameters +{ +public: + QUICTransportParametersInNewSessionTicket() : QUICTransportParameters(){}; + QUICTransportParametersInNewSessionTicket(const uint8_t *buf, size_t len); + +protected: + std::ptrdiff_t _parameters_offset(const uint8_t *buf) const override; + int _validate_parameters() const override; + void _store(uint8_t *buf, uint16_t *len) const override; +}; + class QUICTransportParametersHandler { public: From fa2c6df6dbfd0c4a03e6de6eb6c55b8995d709aa Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 15 Jan 2018 09:47:12 +0900 Subject: [PATCH 0310/1313] Cleanup QUICHandshake constructor --- iocore/net/quic/QUICHandshake.cc | 22 +++++++++++----------- iocore/net/quic/QUICHandshake.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index d80a6f898ff..d0f2671182d 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -83,25 +83,25 @@ static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICApplication(qc) +QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandshake(qc, ssl_ctx, {0}) +{ +} + +QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token) + : QUICApplication(qc), + _ssl(SSL_new(ssl_ctx)), + _crypto(new QUICCryptoTls(this->_ssl, qc->direction())), + _version_negotiator(new QUICVersionNegotiator()), + _netvc_context(qc->direction()), + _reset_token(token) { - this->_ssl = SSL_new(ssl_ctx); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_hs_index, this); - this->_netvc_context = qc->direction(); - this->_crypto = new QUICCryptoTls(this->_ssl, qc->direction()); - this->_version_negotiator = new QUICVersionNegotiator(); - this->_crypto->initialize_key_materials(this->_client_qc->original_connection_id()); SET_HANDLER(&QUICHandshake::state_initial); } -QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token) : QUICHandshake(qc, ssl_ctx) -{ - this->_reset_token = token; -} - QUICHandshake::~QUICHandshake() { SSL_free(this->_ssl); diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 9c2e45072b0..f6c3973a1c8 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -106,6 +106,6 @@ class QUICHandshake : public QUICApplication int _complete_handshake(); void _abort_handshake(QUICTransErrorCode code); - QUICStatelessResetToken _reset_token; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; + QUICStatelessResetToken _reset_token; }; From 365b4cc97c307050f00805b6834d668cdb8f9558 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 15 Jan 2018 11:03:36 +0900 Subject: [PATCH 0311/1313] Divide traffic_quic.cc --- cmd/traffic_quic/Makefile.am | 3 +- cmd/traffic_quic/diags.h | 96 ++++++++++++++++++++++ cmd/traffic_quic/quic_client.cc | 70 ++++++++++++++++ cmd/traffic_quic/quic_client.h | 40 +++++++++ cmd/traffic_quic/traffic_quic.cc | 134 +------------------------------ 5 files changed, 211 insertions(+), 132 deletions(-) create mode 100644 cmd/traffic_quic/diags.h create mode 100644 cmd/traffic_quic/quic_client.cc create mode 100644 cmd/traffic_quic/quic_client.h diff --git a/cmd/traffic_quic/Makefile.am b/cmd/traffic_quic/Makefile.am index a737ade18b6..fdca0568e43 100644 --- a/cmd/traffic_quic/Makefile.am +++ b/cmd/traffic_quic/Makefile.am @@ -37,6 +37,7 @@ traffic_quic_LDFLAGS = \ @AM_LDFLAGS@ traffic_quic_SOURCES = \ + quic_client.cc \ traffic_quic.cc traffic_quic_LDADD = \ @@ -46,9 +47,9 @@ traffic_quic_LDADD = \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/proxy/ParentSelectionStrategy.o \ $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/lib/luajit/src/libluajit.a \ + $(top_builddir)/proxy/ParentSelectionStrategy.o \ @LIBTCL@ \ @HWLOC_LIBS@ \ @OPENSSL_LIBS@ diff --git a/cmd/traffic_quic/diags.h b/cmd/traffic_quic/diags.h new file mode 100644 index 00000000000..21c4e73a6f2 --- /dev/null +++ b/cmd/traffic_quic/diags.h @@ -0,0 +1,96 @@ +/** @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. + */ + +// copy from iocore/utils/diags.i +#pragma once + +#include "ts/Diags.h" + +#define DIAGS_LOG_FILE "diags.log" + +static void +reconfigure_diags() +{ + int i; + DiagsConfigState c; + + // initial value set to 0 or 1 based on command line tags + c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != nullptr); + c.enabled[DiagsTagType_Action] = (diags->base_action_tags != nullptr); + + c.enabled[DiagsTagType_Debug] = 1; + c.enabled[DiagsTagType_Action] = 1; + diags->show_location = SHOW_LOCATION_ALL; + + // read output routing values + for (i = 0; i < DL_Status; i++) { + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 1; + c.outputs[i].to_syslog = 0; + c.outputs[i].to_diagslog = 0; + } + + for (i = DL_Status; i < DiagsLevel_Count; i++) { + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 0; + c.outputs[i].to_syslog = 0; + c.outputs[i].to_diagslog = 1; + } + + ////////////////////////////// + // clear out old tag tables // + ////////////////////////////// + + diags->deactivate_all(DiagsTagType_Debug); + diags->deactivate_all(DiagsTagType_Action); + + ////////////////////////////////////////////////////////////////////// + // add new tag tables + ////////////////////////////////////////////////////////////////////// + + if (diags->base_debug_tags) + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + if (diags->base_action_tags) + diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); + +//////////////////////////////////// +// change the diags config values // +//////////////////////////////////// +#if !defined(__GNUC__) && !defined(hpux) + diags->config = c; +#else + memcpy(((void *)&diags->config), ((void *)&c), sizeof(DiagsConfigState)); +#endif +} + +static void +init_diags(const char *bdt, const char *bat) +{ + char diags_logpath[500]; + strcpy(diags_logpath, DIAGS_LOG_FILE); + + diags = new Diags("Client", bdt, bat, new BaseLogFile(diags_logpath)); + Status("opened %s", diags_logpath); + + reconfigure_diags(); +} diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc new file mode 100644 index 00000000000..7225cfe3a6c --- /dev/null +++ b/cmd/traffic_quic/quic_client.cc @@ -0,0 +1,70 @@ +/** @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 "quic_client.h" + +// Similar to HttpSM::state_http_server_open(int event, void *data) +int +QUICClient::state_http_server_open(int event, void *data) +{ + switch (event) { + case NET_EVENT_OPEN: { + // TODO: create ProxyServerSession / ProxyServerTransaction + // TODO: send HTTP/0.9 message + Debug("quic_client", "start proxy server ssn/txn"); + break; + } + case NET_EVENT_OPEN_FAILED: { + ink_assert(false); + break; + } + case NET_EVENT_ACCEPT: { + // do nothing + break; + } + default: + ink_assert(false); + } + + return 0; +} + +void +QUICClient::start() +{ + SET_HANDLER(&QUICClient::state_http_server_open); + + // TODO: getdddrinfo + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_port = htons(this->_remote_port); + + NetVCOptions opt; + opt.ip_proto = NetVCOptions::USE_UDP; + opt.ip_family = addr.sin_family; + + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + + quic_NetProcessor.connect_re(this, reinterpret_cast(&addr), &opt); +} diff --git a/cmd/traffic_quic/quic_client.h b/cmd/traffic_quic/quic_client.h new file mode 100644 index 00000000000..715d72a2311 --- /dev/null +++ b/cmd/traffic_quic/quic_client.h @@ -0,0 +1,40 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "I_EventSystem.h" +#include "I_NetVConnection.h" +#include "P_QUICNetProcessor.h" + +class QUICClient : public Continuation +{ +public: + QUICClient(const char *addr, int port) : Continuation(new_ProxyMutex()), _remote_port(port) { SET_HANDLER(&QUICClient::start); }; + void start(); + int state_http_server_open(int event, void *data); + +private: + // char *_remote_addr = nullptr; + int _remote_port = 0; +}; diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index 6d455524f98..88450d5f7a3 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -21,146 +21,18 @@ * limitations under the License. */ -#include "I_EventSystem.h" -#include "I_NetVConnection.h" -#include "P_QUICNetProcessor.h" - #include "ts/ink_string.h" #include "ts/ink_args.h" #include "ts/I_Layout.h" #include "ts/I_Version.h" +#include "diags.h" +#include "quic_client.h" + #define THREADS 1 -#define DIAGS_LOG_FILE "diags.log" constexpr size_t stacksize = 1048576; -// copy from iocore/utils/diags.i -static void -reconfigure_diags() -{ - int i; - DiagsConfigState c; - - // initial value set to 0 or 1 based on command line tags - c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != nullptr); - c.enabled[DiagsTagType_Action] = (diags->base_action_tags != nullptr); - - c.enabled[DiagsTagType_Debug] = 1; - c.enabled[DiagsTagType_Action] = 1; - diags->show_location = SHOW_LOCATION_ALL; - - // read output routing values - for (i = 0; i < DL_Status; i++) { - c.outputs[i].to_stdout = 0; - c.outputs[i].to_stderr = 1; - c.outputs[i].to_syslog = 0; - c.outputs[i].to_diagslog = 0; - } - - for (i = DL_Status; i < DiagsLevel_Count; i++) { - c.outputs[i].to_stdout = 0; - c.outputs[i].to_stderr = 0; - c.outputs[i].to_syslog = 0; - c.outputs[i].to_diagslog = 1; - } - - ////////////////////////////// - // clear out old tag tables // - ////////////////////////////// - - diags->deactivate_all(DiagsTagType_Debug); - diags->deactivate_all(DiagsTagType_Action); - - ////////////////////////////////////////////////////////////////////// - // add new tag tables - ////////////////////////////////////////////////////////////////////// - - if (diags->base_debug_tags) - diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); - if (diags->base_action_tags) - diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); - -//////////////////////////////////// -// change the diags config values // -//////////////////////////////////// -#if !defined(__GNUC__) && !defined(hpux) - diags->config = c; -#else - memcpy(((void *)&diags->config), ((void *)&c), sizeof(DiagsConfigState)); -#endif -} - -static void -init_diags(const char *bdt, const char *bat) -{ - char diags_logpath[500]; - strcpy(diags_logpath, DIAGS_LOG_FILE); - - diags = new Diags("Client", bdt, bat, new BaseLogFile(diags_logpath)); - Status("opened %s", diags_logpath); - - reconfigure_diags(); -} - -class QUICClient : public Continuation -{ -public: - QUICClient(const char *addr, int port) : Continuation(new_ProxyMutex()), _remote_port(port) { SET_HANDLER(&QUICClient::start); }; - void start(); - int state_http_server_open(int event, void *data); - -private: - // char *_remote_addr = nullptr; - int _remote_port = 0; -}; - -// Similar to HttpSM::state_http_server_open(int event, void *data) -int -QUICClient::state_http_server_open(int event, void *data) -{ - switch (event) { - case NET_EVENT_OPEN: { - // TODO: create ProxyServerSession / ProxyServerTransaction - // TODO: send HTTP/0.9 message - Debug("quic_client", "start proxy server ssn/txn"); - break; - } - case NET_EVENT_OPEN_FAILED: { - ink_assert(false); - break; - } - case NET_EVENT_ACCEPT: { - // do nothing - break; - } - default: - ink_assert(false); - } - - return 0; -} - -void -QUICClient::start() -{ - SET_HANDLER(&QUICClient::state_http_server_open); - - // TODO: getdddrinfo - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = htons(this->_remote_port); - - NetVCOptions opt; - opt.ip_proto = NetVCOptions::USE_UDP; - opt.ip_family = addr.sin_family; - - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - - quic_NetProcessor.connect_re(this, reinterpret_cast(&addr), &opt); -} - // TODO: Support QUIC version, cipher suite ...etc // TODO: Support qdrive tests // https://github.com/ekr/qdrive From a149a1f251e54a0904e38906459bacf8dae38278 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 15 Jan 2018 12:00:04 +0900 Subject: [PATCH 0312/1313] Support taking address and port on traffic_quic cmd --- cmd/traffic_quic/quic_client.cc | 58 +++++++++++++++++++++----------- cmd/traffic_quic/quic_client.h | 12 +++++-- cmd/traffic_quic/traffic_quic.cc | 6 ++-- iocore/net/QUICNetProcessor.cc | 6 ++-- 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc index 7225cfe3a6c..ec53e04be57 100644 --- a/cmd/traffic_quic/quic_client.cc +++ b/cmd/traffic_quic/quic_client.cc @@ -23,6 +23,44 @@ #include "quic_client.h" +QUICClient::~QUICClient() +{ + freeaddrinfo(this->_remote_addr_info); +} + +void +QUICClient::start() +{ + SET_HANDLER(&QUICClient::state_http_server_open); + + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + + int res = getaddrinfo(this->_remote_addr, this->_remote_port, &hints, &this->_remote_addr_info); + if (res < 0) { + Debug("quic_client", "Error: %s (%d)", strerror(errno), errno); + return; + } + + for (struct addrinfo *info = this->_remote_addr_info; info != nullptr; info = info->ai_next) { + NetVCOptions opt; + opt.ip_proto = NetVCOptions::USE_UDP; + opt.ip_family = info->ai_family; + + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + + Action *action = quic_NetProcessor.connect_re(this, info->ai_addr, &opt); + if (action == ACTION_RESULT_DONE) { + break; + } + } +} + // Similar to HttpSM::state_http_server_open(int event, void *data) int QUICClient::state_http_server_open(int event, void *data) @@ -48,23 +86,3 @@ QUICClient::state_http_server_open(int event, void *data) return 0; } - -void -QUICClient::start() -{ - SET_HANDLER(&QUICClient::state_http_server_open); - - // TODO: getdddrinfo - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = htons(this->_remote_port); - - NetVCOptions opt; - opt.ip_proto = NetVCOptions::USE_UDP; - opt.ip_family = addr.sin_family; - - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - - quic_NetProcessor.connect_re(this, reinterpret_cast(&addr), &opt); -} diff --git a/cmd/traffic_quic/quic_client.h b/cmd/traffic_quic/quic_client.h index 715d72a2311..05d0c47581d 100644 --- a/cmd/traffic_quic/quic_client.h +++ b/cmd/traffic_quic/quic_client.h @@ -30,11 +30,17 @@ class QUICClient : public Continuation { public: - QUICClient(const char *addr, int port) : Continuation(new_ProxyMutex()), _remote_port(port) { SET_HANDLER(&QUICClient::start); }; + QUICClient(const char *addr, const char *port) : Continuation(new_ProxyMutex()), _remote_addr(addr), _remote_port(port) + { + SET_HANDLER(&QUICClient::start); + }; + ~QUICClient(); + void start(); int state_http_server_open(int event, void *data); private: - // char *_remote_addr = nullptr; - int _remote_port = 0; + const char *_remote_addr; + const char *_remote_port; + struct addrinfo *_remote_addr_info = nullptr; }; diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index 88450d5f7a3..f153e8f244b 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -47,13 +47,13 @@ main(int argc, const char **argv) AppVersionInfo appVersionInfo; appVersionInfo.setup(PACKAGE_NAME, "traffic_quic", PACKAGE_VERSION, __DATE__, __TIME__, BUILD_MACHINE, BUILD_PERSON, ""); - char addr[1024] = ""; - int port = 4433; + char addr[1024] = "127.0.0.1"; + char port[16] = "4433"; char debug_tags[1024] = "quic|udp"; const ArgumentDescription argument_descriptions[] = { {"addr", 'a', "Address", "S1023", addr, nullptr, nullptr}, - {"port", 'p', "Port", "I", &port, nullptr, nullptr}, + {"port", 'p', "Port", "S15", port, nullptr, nullptr}, {"debug", 'T', "Vertical-bar-separated Debug Tags", "S1023", debug_tags, nullptr, nullptr}, HELP_ARGUMENT_DESCRIPTION(), VERSION_ARGUMENT_DESCRIPTION(), diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 31740f511be..01a44620dbf 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -119,7 +119,7 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne ink_assert(t); sockaddr_in local_addr; - local_addr.sin_family = AF_INET; + local_addr.sin_family = remote_addr->sa_family; local_addr.sin_addr.s_addr = htonl(INADDR_ANY); local_addr.sin_port = 0; @@ -142,7 +142,7 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne // FIXME: create QUICPacketHandler for Client (origin server side) QUICPacketHandler *packet_handler = new QUICPacketHandler(accept_opt, this->_ssl_ctx); packet_handler->init_accept(t); - packet_handler->action_ = new NetAcceptAction(); + packet_handler->action_ = new NetAcceptAction(); *packet_handler->action_ = cont; con->setBinding(reinterpret_cast(&local_addr)); @@ -152,7 +152,7 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne PollDescriptor *pd = pc->pollDescriptor; errno = 0; - res = con->ep.start(pd, con, EVENTIO_READ); + res = con->ep.start(pd, con, EVENTIO_READ); if (res < 0) { Debug("udpnet", "Error: %s (%d)", strerror(errno), errno); } From bf8cf5f1fdfd695f46191e9d97ebbbb00724302f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 15 Jan 2018 12:53:14 +0900 Subject: [PATCH 0313/1313] Call default constructor of QUICStatelessResetToken --- iocore/net/quic/QUICHandshake.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index d0f2671182d..b700eb30726 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -83,7 +83,7 @@ static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandshake(qc, ssl_ctx, {0}) +QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandshake(qc, ssl_ctx, {}) { } From 1f37f7ba8a3813dd553539a0d71d996acf9501f9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 15 Jan 2018 13:04:15 +0900 Subject: [PATCH 0314/1313] Add draining state to QUICNetVConnection --- iocore/net/P_QUICNetVConnection.h | 15 ++++- iocore/net/QUICNetVConnection.cc | 91 ++++++++++++++++++++++++++++++- iocore/net/quic/QUICDebugNames.cc | 2 + iocore/net/quic/QUICEvents.h | 1 + iocore/net/quic/QUICTypes.h | 3 +- 5 files changed, 109 insertions(+), 3 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 7fdb83db2f7..e67fc37f2b4 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -124,11 +124,17 @@ class SSLNextProtocolSet; * | WRITE: * | _state_common_send_packet() * v + * state_connection_draining() (If closing passively) + * | READ: + * | _state_connection_established_process_packet() + * | WRITE: + * | Do nothing + * v * state_connection_close() * READ: * Do nothing * WRITE: - * _state_common_send_packet() + * Do nothing **/ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection { @@ -150,6 +156,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection int state_handshake(int event, Event *data); int state_connection_established(int event, Event *data); int state_connection_closing(int event, Event *data); + int state_connection_draining(int event, Event *data); int state_connection_closed(int event, Event *data); void start(SSL_CTX *); void push_packet(UDPPacket *packet); @@ -249,6 +256,11 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _close_packet_write_ready(Event *data); Event *_packet_write_ready = nullptr; + void _schedule_draining_timeout(ink_hrtime interval); + void _unschedule_draining_timeout(); + void _close_draining_timeout(Event *data); + Event *_draining_timeout = nullptr; + uint32_t _transmit_packet(QUICPacketUPtr); void _transmit_frame(QUICFrameUPtr); @@ -280,6 +292,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _switch_to_handshake_state(); void _switch_to_established_state(); void _switch_to_closing_state(QUICConnectionErrorUPtr error); + void _switch_to_draining_state(QUICConnectionErrorUPtr error); void _switch_to_close_state(); void _handle_idle_timeout(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 9411ded144d..9cacd78c1fb 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -24,6 +24,7 @@ #include #include "ts/ink_config.h" +#include "ts/ink_std_compat.h" #include "ts/EventNotify.h" #include "records/I_RecHttp.h" #include "ts/Diags.h" @@ -357,8 +358,10 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) case QUICFrameType::BLOCKED: // BLOCKED frame is for debugging. Nothing to do here. break; + case QUICFrameType::APPLICATION_CLOSE: case QUICFrameType::CONNECTION_CLOSE: - this->_switch_to_close_state(); + this->_switch_to_draining_state(QUICConnectionErrorUPtr( + new QUICConnectionError(std::static_pointer_cast(frame)->error_code()))); break; default: QUICConDebug("Unexpected frame type: %02x", static_cast(frame->type())); @@ -504,6 +507,51 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) return EVENT_DONE; } +int +QUICNetVConnection::state_connection_draining(int event, Event *data) +{ + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + bool can_switch_to_close_state = false; + + // This states SHOULD persist for three times the + // current Retransmission Timeout (RTO) interval as defined in + // [QUIC-RECOVERY]. + + // TODO The draining period should be obtained from QUICLossDetector since it is the only component that knows the RTO interval. + // Use 3 times kkMinRTOTimeout(200ms) for now. + this->_schedule_draining_timeout(HRTIME_MSECONDS(3 * 200)); + + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + switch (event) { + case QUIC_EVENT_PACKET_READ_READY: + if (this->_handshake_handler && this->_handshake_handler->is_completed()) { + error = this->_state_common_receive_packet(); + // TODO receiving a closing frame is sufficient confirmation + // can_switch_to_close_state = true; + } else { + // FIXME Just ignore for now but it has to be acked (GitHub#2609) + } + break; + case QUIC_EVENT_PACKET_WRITE_READY: + // Do not send any packets in this state. + // This should be the only difference between this and closing_state. + this->_close_packet_write_ready(data); + break; + case QUIC_EVENT_DRAINING_TIMEOUT: + can_switch_to_close_state = true; + break; + default: + QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); + } + + // FIXME Enter closed state if CONNECTION_CLOSE was ACKed and draining period end + if (can_switch_to_close_state) { + this->_switch_to_close_state(); + } + + return EVENT_DONE; +} + int QUICNetVConnection::state_connection_closed(int event, Event *data) { @@ -511,6 +559,7 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) switch (event) { case QUIC_EVENT_SHUTDOWN: { this->_unschedule_packet_write_ready(); + this->_unschedule_draining_timeout(); this->next_inactivity_timeout_at = 0; this->next_activity_timeout_at = 0; @@ -1017,6 +1066,31 @@ QUICNetVConnection::_close_packet_write_ready(Event *data) this->_packet_write_ready = nullptr; } +void +QUICNetVConnection::_schedule_draining_timeout(ink_hrtime interval) +{ + if (!this->_draining_timeout) { + QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_DRAINING_TIMEOUT)); + this->_draining_timeout = this_ethread()->schedule_in_local(this, interval, QUIC_EVENT_DRAINING_TIMEOUT); + } +} + +void +QUICNetVConnection::_unschedule_draining_timeout() +{ + if (this->_draining_timeout) { + this->_draining_timeout->cancel(); + this->_draining_timeout = nullptr; + } +} + +void +QUICNetVConnection::_close_draining_timeout(Event *data) +{ + ink_assert(this->_draining_timeout == data); + this->_draining_timeout = nullptr; +} + int QUICNetVConnection::_complete_handshake_if_possible() { @@ -1091,6 +1165,21 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); } +void +QUICNetVConnection::_switch_to_draining_state(QUICConnectionErrorUPtr error) +{ + if (this->_complete_handshake_if_possible() != 0) { + QUICConDebug("Switching state without handshake completion"); + } + if (error->msg) { + QUICConDebug("Reason: %.*s", static_cast(strlen(error->msg)), error->msg); + } else { + QUICConDebug("Reason was not provided"); + } + QUICConDebug("Enter state_connection_draining"); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_draining); +} + void QUICNetVConnection::_switch_to_close_state() { diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index e7e8751780a..b85769c5b5c 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -148,6 +148,8 @@ QUICDebugNames::quic_event(int event) return "QUIC_EVENT_PACKET_READ_READY"; case QUIC_EVENT_PACKET_WRITE_READY: return "QUIC_EVENT_PACKET_WRITE_READY"; + case QUIC_EVENT_DRAINING_TIMEOUT: + return "QUIC_EVENT_DRAINING_TIMEOUT"; case QUIC_EVENT_SHUTDOWN: return "QUIC_EVENT_SHUTDOWN"; case QUIC_EVENT_LD_SHUTDOWN: diff --git a/iocore/net/quic/QUICEvents.h b/iocore/net/quic/QUICEvents.h index b3273ce43cb..71b2bc98641 100644 --- a/iocore/net/quic/QUICEvents.h +++ b/iocore/net/quic/QUICEvents.h @@ -29,6 +29,7 @@ enum { QUIC_EVENT_PACKET_READ_READY = QUIC_EVENT_EVENTS_START, QUIC_EVENT_PACKET_WRITE_READY, + QUIC_EVENT_DRAINING_TIMEOUT, QUIC_EVENT_SHUTDOWN, QUIC_EVENT_LD_SHUTDOWN, }; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index e8d1d717cf6..912a82a318a 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -146,7 +146,8 @@ enum class QUICTransErrorCode : uint16_t { }; // Application Protocol Error Codes defined in application -using QUICAppErrorCode = uint16_t; +using QUICAppErrorCode = uint16_t; +constexpr uint16_t QUIC_APP_ERROR_CODE_STOPPING = 0; class QUICError { From e9c5e429189e3b325f017dd2d3ae329e3d5d7939 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 15 Jan 2018 14:42:04 +0900 Subject: [PATCH 0315/1313] Fix a bug that draining state can cause BAD_ACCESS --- iocore/net/QUICNetVConnection.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 9cacd78c1fb..e085ab3e997 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -538,6 +538,7 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) this->_close_packet_write_ready(data); break; case QUIC_EVENT_DRAINING_TIMEOUT: + this->_close_draining_timeout(data); can_switch_to_close_state = true; break; default: From 06986e42ebb5600ff14b25d7db08a99edf301e74 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 15 Jan 2018 14:42:39 +0900 Subject: [PATCH 0316/1313] use this_ethread() instead of eventProcessor --- iocore/net/QUICNetVConnection.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e085ab3e997..473133e04f0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1045,7 +1045,7 @@ QUICNetVConnection::_schedule_packet_write_ready() SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); if (!this->_packet_write_ready) { QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); - this->_packet_write_ready = eventProcessor.schedule_imm(this, ET_CALL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + this->_packet_write_ready = this_ethread()->schedule_imm(this, QUIC_EVENT_PACKET_WRITE_READY, nullptr); } } From 56fa13fdd531561ecec4e2e643dc3bc7f79d2a63 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 15 Jan 2018 16:21:01 +0900 Subject: [PATCH 0317/1313] Switch to draining state on idle timeout --- iocore/net/QUICNetVConnection.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 473133e04f0..df1afe14bd4 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -513,14 +513,6 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); bool can_switch_to_close_state = false; - // This states SHOULD persist for three times the - // current Retransmission Timeout (RTO) interval as defined in - // [QUIC-RECOVERY]. - - // TODO The draining period should be obtained from QUICLossDetector since it is the only component that knows the RTO interval. - // Use 3 times kkMinRTOTimeout(200ms) for now. - this->_schedule_draining_timeout(HRTIME_MSECONDS(3 * 200)); - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: @@ -1179,6 +1171,14 @@ QUICNetVConnection::_switch_to_draining_state(QUICConnectionErrorUPtr error) } QUICConDebug("Enter state_connection_draining"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_draining); + + // This states SHOULD persist for three times the + // current Retransmission Timeout (RTO) interval as defined in + // [QUIC-RECOVERY]. + + // TODO The draining period should be obtained from QUICLossDetector since it is the only component that knows the RTO interval. + // Use 3 times kkMinRTOTimeout(200ms) for now. + this->_schedule_draining_timeout(HRTIME_MSECONDS(3 * 200)); } void @@ -1196,7 +1196,7 @@ void QUICNetVConnection::_handle_idle_timeout() { this->remove_from_active_queue(); - this->close(std::make_unique(QUICTransErrorCode::NO_ERROR, "Idle Timeout")); + this->_switch_to_draining_state(std::make_unique(QUICTransErrorCode::NO_ERROR, "Idle Timeout")); // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application } From dbb740f141d97b882ca8e9512586a41fecc7b231 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 15 Jan 2018 16:56:04 +0900 Subject: [PATCH 0318/1313] Fix condition of ssl extention context on adding Transport Parameters --- iocore/net/quic/QUICTransportParameters.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 4a511b20859..c3c25c4813c 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -547,7 +547,7 @@ QUICTransportParametersHandler::add(SSL *s, unsigned int ext_type, unsigned int { QUICHandshake *hs = static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_hs_index)); *out = reinterpret_cast(ats_malloc(TRANSPORT_PARAMETERS_MAXIMUM_SIZE)); - bool with_version = (context == SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS); + bool with_version = (context != SSL_EXT_TLS1_3_NEW_SESSION_TICKET); hs->local_transport_parameters(with_version)->store(const_cast(*out), reinterpret_cast(outlen)); return 1; From e2dc349fc37276fbd166028cc3000cd92e4d1194 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 15 Jan 2018 16:58:42 +0900 Subject: [PATCH 0319/1313] Divide QUICPacketHandler into QUICPacketHandlerIn (incoming conn) and QUICPacketHandlerOut (outgoing conn) --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/P_QUICPacketHandler.h | 57 +++++++-- iocore/net/QUICNetProcessor.cc | 15 +-- iocore/net/QUICPacketHandler.cc | 184 +++++++++++++++++++++--------- 4 files changed, 184 insertions(+), 74 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e67fc37f2b4..a040ca29972 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -87,7 +87,7 @@ typedef enum { // ////////////////////////////////////////////////////////////////// -struct QUICPacketHandler; +class QUICPacketHandler; class QUICLossDetector; class SSLNextProtocolSet; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 564dbbad331..2205a800c90 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -31,24 +31,65 @@ class QUICNetVConnection; class QUICPacket; -struct QUICPacketHandler : public NetAccept { +class QUICPacketHandler +{ public: - QUICPacketHandler(const NetProcessor::AcceptOptions &opt, SSL_CTX *); - virtual ~QUICPacketHandler(); + virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc) = 0; + virtual void registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc) = 0; +protected: + static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu); + static bool _read_connection_id(QUICConnectionId &cid, IOBufferBlock *block); + + virtual void _recv_packet(int event, UDPPacket *udpPacket) = 0; +}; + +/* + * @class QUICPacketHanderIn + * @brief QUIC Packet Handler for incoming connections + */ +class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler +{ +public: + QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, SSL_CTX *); + ~QUICPacketHandlerIn(); + + // NetAccept virtual NetProcessor *getNetProcessor() const override; virtual NetAccept *clone() const override; virtual int acceptEvent(int event, void *e) override; void init_accept(EThread *t) override; - void send_packet(const QUICPacket &packet, QUICNetVConnection *vc); - void send_packet(const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu); - void registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc); + // QUICPacketHandler + virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc) override; + virtual void registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc) override; private: - void _recv_packet(int event, UDPPacket *udpPacket); - bool _read_connection_id(QUICConnectionId &cid, IOBufferBlock *block); + void _recv_packet(int event, UDPPacket *udp_packet) override; Map _connections; SSL_CTX *_ssl_ctx; }; + +/* + * @class QUICPacketHanderOut + * @brief QUIC Packet Handler for outgoing connections + */ +class QUICPacketHandlerOut : public Continuation, public QUICPacketHandler +{ +public: + QUICPacketHandlerOut(); + ~QUICPacketHandlerOut(){}; + + void init(QUICNetVConnection *vc); + int event_handler(int event, Event *data); + + // QUICPacketHandler + virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc) override; + virtual void registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc) override; + +private: + void _recv_packet(int event, UDPPacket *udp_packet) override; + + QUICNetVConnection *_vc = nullptr; +}; diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 01a44620dbf..ff6bcf23fff 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -20,14 +20,14 @@ */ #include "ts/ink_config.h" +#include "ts/I_Layout.h" #include "P_Net.h" -#include "ts/I_Layout.h" #include "I_RecHttp.h" + #include "QUICGlobals.h" #include "QUICConfig.h" #include "QUICTransportParameters.h" -// #include "P_QUICUtils.h" // // Global Data @@ -89,7 +89,7 @@ QUICNetProcessor::start(int, size_t stacksize) NetAccept * QUICNetProcessor::createNetAccept(const NetProcessor::AcceptOptions &opt) { - return (NetAccept *)new QUICPacketHandler(opt, this->_ssl_ctx); + return (NetAccept *)new QUICPacketHandlerIn(opt, this->_ssl_ctx); } NetVConnection * @@ -138,13 +138,7 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne UnixUDPConnection *con = new UnixUDPConnection(fd); Debug("quic_ps", "con=%p fd=%d", con, fd); - AcceptOptions const accept_opt; - // FIXME: create QUICPacketHandler for Client (origin server side) - QUICPacketHandler *packet_handler = new QUICPacketHandler(accept_opt, this->_ssl_ctx); - packet_handler->init_accept(t); - packet_handler->action_ = new NetAcceptAction(); - *packet_handler->action_ = cont; - + QUICPacketHandlerOut *packet_handler = new QUICPacketHandlerOut(); con->setBinding(reinterpret_cast(&local_addr)); con->bindToThread(packet_handler); @@ -162,6 +156,7 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne cid.randomize(); QUICNetVConnection *vc = static_cast(this->allocate_vc(t)); vc->init(cid, con, packet_handler); + packet_handler->init(vc); if (opt) { vc->options = *opt; diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index e07dec5d78e..12e3cc4f73b 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -27,32 +27,78 @@ #include "QUICDebugNames.h" #include "QUICEvents.h" -QUICPacketHandler::QUICPacketHandler(const NetProcessor::AcceptOptions &opt, SSL_CTX *ctx) : NetAccept(opt), _ssl_ctx(ctx) +// +// QUICPacketHandler +// +void +QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu) +{ + size_t udp_len; + Ptr udp_payload(new_IOBufferBlock()); + udp_payload->alloc(iobuffer_size_to_index(pmtu)); + packet.store(reinterpret_cast(udp_payload->end()), &udp_len); + udp_payload->fill(udp_len); + + UDPPacket *udp_packet = new_UDPPacket(addr, 0, udp_payload); + + // NOTE: p will be enqueued to udpOutQueue of UDPNetHandler + ip_port_text_buffer ipb; + Debug("quic_sec", "[%" PRIx64 "] send %s packet to %s, size=%" PRId64, static_cast(packet.connection_id()), + QUICDebugNames::packet_type(packet.type()), ats_ip_nptop(&udp_packet->to.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); + + udp_con->send(c, udp_packet); +} + +// TODO: Integrate with QUICPacketHeader::connection_id() +bool +QUICPacketHandler::_read_connection_id(QUICConnectionId &cid, IOBufferBlock *block) +{ + const uint8_t *buf = reinterpret_cast(block->buf()); + const uint8_t cid_offset = 1; + const uint8_t cid_len = 8; + + if (QUICTypeUtil::has_long_header(buf)) { + cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); + } else { + if (QUICTypeUtil::has_connection_id(buf)) { + cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); + } else { + return false; + } + } + + return true; +} + +// +// QUICPacketHandlerIn +// +QUICPacketHandlerIn::QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, SSL_CTX *ctx) : NetAccept(opt), _ssl_ctx(ctx) { this->mutex = new_ProxyMutex(); } -QUICPacketHandler::~QUICPacketHandler() +QUICPacketHandlerIn::~QUICPacketHandlerIn() { } NetProcessor * -QUICPacketHandler::getNetProcessor() const +QUICPacketHandlerIn::getNetProcessor() const { return &quic_NetProcessor; } NetAccept * -QUICPacketHandler::clone() const +QUICPacketHandlerIn::clone() const { NetAccept *na; - na = new QUICPacketHandler(opt, this->_ssl_ctx); + na = new QUICPacketHandlerIn(opt, this->_ssl_ctx); *na = *this; return na; } int -QUICPacketHandler::acceptEvent(int event, void *data) +QUICPacketHandlerIn::acceptEvent(int event, void *data) { // NetVConnection *netvc; ink_release_assert(event == NET_EVENT_DATAGRAM_OPEN || event == NET_EVENT_DATAGRAM_READ_READY || @@ -84,43 +130,22 @@ QUICPacketHandler::acceptEvent(int event, void *data) } void -QUICPacketHandler::init_accept(EThread *t = nullptr) +QUICPacketHandlerIn::init_accept(EThread *t = nullptr) { - SET_HANDLER(&QUICPacketHandler::acceptEvent); -} - -// TODO: Integrate with QUICPacketHeader::connection_id() -bool -QUICPacketHandler::_read_connection_id(QUICConnectionId &cid, IOBufferBlock *block) -{ - const uint8_t *buf = reinterpret_cast(block->buf()); - const uint8_t cid_offset = 1; - const uint8_t cid_len = 8; - - if (QUICTypeUtil::has_long_header(buf)) { - cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); - } else { - if (QUICTypeUtil::has_connection_id(buf)) { - cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); - } else { - return false; - } - } - - return true; + SET_HANDLER(&QUICPacketHandlerIn::acceptEvent); } void -QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) +QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) { - IOBufferBlock *block = udpPacket->getIOBlockChain(); + IOBufferBlock *block = udp_packet->getIOBlockChain(); QUICConnectionId cid; bool res = this->_read_connection_id(cid, block); ip_port_text_buffer ipb; Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), - ats_ip_nptop(&udpPacket->from.sa, ipb, sizeof(ipb)), udpPacket->getPktLength()); + ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); QUICNetVConnection *vc = nullptr; if (res) { @@ -132,7 +157,7 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) if (!vc) { Connection con; - con.setRemote(&udpPacket->from.sa); + con.setRemote(&udp_packet->from.sa); // Send stateless reset if the packet is not a initial packet if (!QUICTypeUtil::has_long_header(reinterpret_cast(block->buf()))) { @@ -142,14 +167,14 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) token.generate(cid, params->server_id()); } auto packet = QUICPacketFactory::create_stateless_reset_packet(cid, token); - this->send_packet(*packet, udpPacket->getConnection(), con.addr, 1200); + this->_send_packet(this, *packet, udp_packet->getConnection(), con.addr, 1200); return; } // Create a new NetVConnection - vc = - static_cast(getNetProcessor()->allocate_vc(((UnixUDPConnection *)udpPacket->getConnection())->ethread)); - vc->init(cid, udpPacket->getConnection(), this); + vc = static_cast( + getNetProcessor()->allocate_vc(((UnixUDPConnection *)udp_packet->getConnection())->ethread)); + vc->init(cid, udp_packet->getConnection(), this); vc->id = net_next_connection_number(); vc->con.move(con); vc->submit_time = Thread::get_hrtime(); @@ -160,7 +185,7 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) vc->read.triggered = 1; vc->start(this->_ssl_ctx); vc->options.ip_proto = NetVCOptions::USE_UDP; - vc->options.ip_family = udpPacket->from.sa.sa_family; + vc->options.ip_family = udp_packet->from.sa.sa_family; this->_connections.put(cid, vc); this->action_->continuation->handleEvent(NET_EVENT_ACCEPT, vc); @@ -172,14 +197,14 @@ QUICPacketHandler::_recv_packet(int event, UDPPacket *udpPacket) // QUICNetVConnections are going to be freed by QUICNetHandler // vc->free(vc->thread); } else { - vc->push_packet(udpPacket); + vc->push_packet(udp_packet); eventProcessor.schedule_imm(vc, ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr); } } // TODO: Should be called via eventProcessor? void -QUICPacketHandler::send_packet(const QUICPacket &packet, QUICNetVConnection *vc) +QUICPacketHandlerIn::send_packet(const QUICPacket &packet, QUICNetVConnection *vc) { // TODO: remove a connection which is created by Client Initial // or update key to new one @@ -187,30 +212,79 @@ QUICPacketHandler::send_packet(const QUICPacket &packet, QUICNetVConnection *vc) this->_connections.put(packet.connection_id(), vc); } - this->send_packet(packet, vc->get_udp_con(), vc->con.addr, vc->pmtu()); + this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu()); } void -QUICPacketHandler::send_packet(const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu) +QUICPacketHandlerIn::registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc) { - size_t udp_len; - Ptr udp_payload(new_IOBufferBlock()); - udp_payload->alloc(iobuffer_size_to_index(pmtu)); - packet.store(reinterpret_cast(udp_payload->end()), &udp_len); - udp_payload->fill(udp_len); + this->_connections.put(id, vc); +} - UDPPacket *udpPkt = new_UDPPacket(addr, 0, udp_payload); +// +// QUICPacketHandlerOut +// +QUICPacketHandlerOut::QUICPacketHandlerOut() : Continuation(new_ProxyMutex()) +{ + SET_HANDLER(&QUICPacketHandlerOut::event_handler); +} - // NOTE: p will be enqueued to udpOutQueue of UDPNetHandler - ip_port_text_buffer ipb; - Debug("quic_sec", "[%" PRIx64 "] send %s packet to %s, size=%" PRId64, static_cast(packet.connection_id()), - QUICDebugNames::packet_type(packet.type()), ats_ip_nptop(&udpPkt->to.sa, ipb, sizeof(ipb)), udpPkt->getPktLength()); +void +QUICPacketHandlerOut::init(QUICNetVConnection *vc) +{ + this->_vc = vc; +} - udp_con->send(this, udpPkt); +int +QUICPacketHandlerOut::event_handler(int event, Event *data) +{ + switch (event) { + case NET_EVENT_DATAGRAM_OPEN: { + // Nothing to do. + return EVENT_CONT; + } + case NET_EVENT_DATAGRAM_READ_READY: { + Queue *queue = (Queue *)data; + UDPPacket *packet_r; + while ((packet_r = queue->dequeue())) { + this->_recv_packet(event, packet_r); + } + return EVENT_CONT; + } + default: + Debug("quic_ph", "Unknown Event (%d)", event); + + break; + } + + return EVENT_DONE; } void -QUICPacketHandler::registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc) +QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection *vc) { - this->_connections.put(id, vc); + this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu()); +} + +void +QUICPacketHandlerOut::registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc) +{ + // do nothing + ink_assert(false); +} + +void +QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet) +{ + IOBufferBlock *block = udp_packet->getIOBlockChain(); + + QUICConnectionId cid; + this->_read_connection_id(cid, block); + + ip_port_text_buffer ipb; + Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), + ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); + + this->_vc->push_packet(udp_packet); + eventProcessor.schedule_imm(this->_vc, ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr); } From c147874b6c051944845be9931ef13f9a304f8968 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 15 Jan 2018 17:07:00 +0900 Subject: [PATCH 0320/1313] Draining period and closing period can share the same timer --- iocore/net/P_QUICNetVConnection.h | 8 +++--- iocore/net/QUICNetVConnection.cc | 48 +++++++++++++++++-------------- iocore/net/quic/QUICDebugNames.cc | 4 +-- iocore/net/quic/QUICEvents.h | 2 +- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index a040ca29972..d076fd3988f 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -256,10 +256,10 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _close_packet_write_ready(Event *data); Event *_packet_write_ready = nullptr; - void _schedule_draining_timeout(ink_hrtime interval); - void _unschedule_draining_timeout(); - void _close_draining_timeout(Event *data); - Event *_draining_timeout = nullptr; + void _schedule_closing_timeout(ink_hrtime interval); + void _unschedule_closing_timeout(); + void _close_closing_timeout(Event *data); + Event *_closing_timeout = nullptr; uint32_t _transmit_packet(QUICPacketUPtr); void _transmit_frame(QUICFrameUPtr); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index df1afe14bd4..582d3724ec9 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -479,28 +479,33 @@ int QUICNetVConnection::state_connection_closing(int event, Event *data) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + bool can_switch_to_close_state = false; QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { - case QUIC_EVENT_PACKET_READ_READY: { + case QUIC_EVENT_PACKET_READ_READY: if (this->_handshake_handler && this->_handshake_handler->is_completed()) { error = this->_state_common_receive_packet(); + // TODO receiving a closing frame is sufficient confirmation + // can_switch_to_close_state = true; } else { // FIXME Just ignore for now but it has to be acked (GitHub#2609) } break; - } - case QUIC_EVENT_PACKET_WRITE_READY: { + case QUIC_EVENT_PACKET_WRITE_READY: this->_close_packet_write_ready(data); + // FIXME Only closing frames are allowed to send this->_state_common_send_packet(); break; - } + case QUIC_EVENT_CLOSING_TIMEOUT: + this->_close_closing_timeout(data); + can_switch_to_close_state = true; + break; default: QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); } - // FIXME Enter closed state if CONNECTION_CLOSE was ACKed and draining period end - if (true) { + if (can_switch_to_close_state) { this->_switch_to_close_state(); } @@ -529,15 +534,14 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) // This should be the only difference between this and closing_state. this->_close_packet_write_ready(data); break; - case QUIC_EVENT_DRAINING_TIMEOUT: - this->_close_draining_timeout(data); + case QUIC_EVENT_CLOSING_TIMEOUT: + this->_close_closing_timeout(data); can_switch_to_close_state = true; break; default: QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); } - // FIXME Enter closed state if CONNECTION_CLOSE was ACKed and draining period end if (can_switch_to_close_state) { this->_switch_to_close_state(); } @@ -552,7 +556,7 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) switch (event) { case QUIC_EVENT_SHUTDOWN: { this->_unschedule_packet_write_ready(); - this->_unschedule_draining_timeout(); + this->_unschedule_closing_timeout(); this->next_inactivity_timeout_at = 0; this->next_activity_timeout_at = 0; @@ -1060,28 +1064,28 @@ QUICNetVConnection::_close_packet_write_ready(Event *data) } void -QUICNetVConnection::_schedule_draining_timeout(ink_hrtime interval) +QUICNetVConnection::_schedule_closing_timeout(ink_hrtime interval) { - if (!this->_draining_timeout) { - QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_DRAINING_TIMEOUT)); - this->_draining_timeout = this_ethread()->schedule_in_local(this, interval, QUIC_EVENT_DRAINING_TIMEOUT); + if (!this->_closing_timeout) { + QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_CLOSING_TIMEOUT)); + this->_closing_timeout = this_ethread()->schedule_in_local(this, interval, QUIC_EVENT_CLOSING_TIMEOUT); } } void -QUICNetVConnection::_unschedule_draining_timeout() +QUICNetVConnection::_unschedule_closing_timeout() { - if (this->_draining_timeout) { - this->_draining_timeout->cancel(); - this->_draining_timeout = nullptr; + if (this->_closing_timeout) { + this->_closing_timeout->cancel(); + this->_closing_timeout = nullptr; } } void -QUICNetVConnection::_close_draining_timeout(Event *data) +QUICNetVConnection::_close_closing_timeout(Event *data) { - ink_assert(this->_draining_timeout == data); - this->_draining_timeout = nullptr; + ink_assert(this->_closing_timeout == data); + this->_closing_timeout = nullptr; } int @@ -1178,7 +1182,7 @@ QUICNetVConnection::_switch_to_draining_state(QUICConnectionErrorUPtr error) // TODO The draining period should be obtained from QUICLossDetector since it is the only component that knows the RTO interval. // Use 3 times kkMinRTOTimeout(200ms) for now. - this->_schedule_draining_timeout(HRTIME_MSECONDS(3 * 200)); + this->_schedule_closing_timeout(HRTIME_MSECONDS(3 * 200)); } void diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index b85769c5b5c..a35f47668e1 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -148,8 +148,8 @@ QUICDebugNames::quic_event(int event) return "QUIC_EVENT_PACKET_READ_READY"; case QUIC_EVENT_PACKET_WRITE_READY: return "QUIC_EVENT_PACKET_WRITE_READY"; - case QUIC_EVENT_DRAINING_TIMEOUT: - return "QUIC_EVENT_DRAINING_TIMEOUT"; + case QUIC_EVENT_CLOSING_TIMEOUT: + return "QUIC_EVENT_CLOSING_TIMEOUT"; case QUIC_EVENT_SHUTDOWN: return "QUIC_EVENT_SHUTDOWN"; case QUIC_EVENT_LD_SHUTDOWN: diff --git a/iocore/net/quic/QUICEvents.h b/iocore/net/quic/QUICEvents.h index 71b2bc98641..c3f9b446263 100644 --- a/iocore/net/quic/QUICEvents.h +++ b/iocore/net/quic/QUICEvents.h @@ -29,7 +29,7 @@ enum { QUIC_EVENT_PACKET_READ_READY = QUIC_EVENT_EVENTS_START, QUIC_EVENT_PACKET_WRITE_READY, - QUIC_EVENT_DRAINING_TIMEOUT, + QUIC_EVENT_CLOSING_TIMEOUT, QUIC_EVENT_SHUTDOWN, QUIC_EVENT_LD_SHUTDOWN, }; From 54a24da4aaee498acb955a4a54409fb5d859489e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 15 Jan 2018 17:34:23 +0900 Subject: [PATCH 0321/1313] Switch to close state on receiving a closing frame on draining state or closing state --- iocore/net/QUICNetVConnection.cc | 45 ++++++++++++-------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 582d3724ec9..2f20b94eff0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -360,8 +360,13 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) break; case QUICFrameType::APPLICATION_CLOSE: case QUICFrameType::CONNECTION_CLOSE: - this->_switch_to_draining_state(QUICConnectionErrorUPtr( - new QUICConnectionError(std::static_pointer_cast(frame)->error_code()))); + if (this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closing) || + this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_draining)) { + this->_switch_to_close_state(); + } else { + this->_switch_to_draining_state(QUICConnectionErrorUPtr( + new QUICConnectionError(std::static_pointer_cast(frame)->error_code()))); + } break; default: QUICConDebug("Unexpected frame type: %02x", static_cast(frame->type())); @@ -479,36 +484,27 @@ int QUICNetVConnection::state_connection_closing(int event, Event *data) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - bool can_switch_to_close_state = false; QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: - if (this->_handshake_handler && this->_handshake_handler->is_completed()) { - error = this->_state_common_receive_packet(); - // TODO receiving a closing frame is sufficient confirmation - // can_switch_to_close_state = true; - } else { - // FIXME Just ignore for now but it has to be acked (GitHub#2609) - } + error = this->_state_common_receive_packet(); break; case QUIC_EVENT_PACKET_WRITE_READY: this->_close_packet_write_ready(data); - // FIXME Only closing frames are allowed to send + // FIXME During the closing period, an endpoint that sends a + // closing frame SHOULD respond to any packet that it receives with + // another packet containing a closing frame. this->_state_common_send_packet(); break; case QUIC_EVENT_CLOSING_TIMEOUT: this->_close_closing_timeout(data); - can_switch_to_close_state = true; + this->_switch_to_close_state(); break; default: QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); } - if (can_switch_to_close_state) { - this->_switch_to_close_state(); - } - return EVENT_DONE; } @@ -516,18 +512,11 @@ int QUICNetVConnection::state_connection_draining(int event, Event *data) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - bool can_switch_to_close_state = false; QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: - if (this->_handshake_handler && this->_handshake_handler->is_completed()) { - error = this->_state_common_receive_packet(); - // TODO receiving a closing frame is sufficient confirmation - // can_switch_to_close_state = true; - } else { - // FIXME Just ignore for now but it has to be acked (GitHub#2609) - } + error = this->_state_common_receive_packet(); break; case QUIC_EVENT_PACKET_WRITE_READY: // Do not send any packets in this state. @@ -536,16 +525,12 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) break; case QUIC_EVENT_CLOSING_TIMEOUT: this->_close_closing_timeout(data); - can_switch_to_close_state = true; + this->_switch_to_close_state(); break; default: QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); } - if (can_switch_to_close_state) { - this->_switch_to_close_state(); - } - return EVENT_DONE; } @@ -1188,6 +1173,8 @@ QUICNetVConnection::_switch_to_draining_state(QUICConnectionErrorUPtr error) void QUICNetVConnection::_switch_to_close_state() { + this->_unschedule_closing_timeout(); + if (this->_complete_handshake_if_possible() != 0) { QUICConDebug("Switching state without handshake completion"); } From c8728dbb2f8afdf4974964c257ee6c85c2da72c8 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 16 Jan 2018 10:33:24 +0900 Subject: [PATCH 0322/1313] Create handshake stream via QUICStreamManager on connect --- iocore/net/QUICNetVConnection.cc | 12 ++++++------ iocore/net/quic/QUICStreamManager.cc | 20 ++++++++++++++++++++ iocore/net/quic/QUICStreamManager.h | 3 ++- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2f20b94eff0..3ebf90d7ff4 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -159,12 +159,12 @@ QUICNetVConnection::reenable(VIO *vio) int QUICNetVConnection::connectUp(EThread *t, int fd) { - // create stream 0 - // FIXME: integration w/ QUICStreamManager - QUICStream *stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream(); - stream->init(this, this->connection_id(), STREAM_ID_FOR_HANDSHAKE); - if (!this->_handshake_handler->is_stream_set(stream)) { - this->_handshake_handler->set_stream(stream); + // create stream for handshake + QUICErrorUPtr error = this->_stream_manager->create_client_stream(STREAM_ID_FOR_HANDSHAKE); + if (error->cls != QUICErrorClass::NONE) { + QUICConDebug("Couldn't create stream for handshake"); + + return CONNECT_FAILURE; } // start QUIC handshake diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index c6527ac2eff..a1ed28ce7ec 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -91,6 +91,24 @@ QUICStreamManager::set_max_stream_id(QUICStreamId id) } } +QUICErrorUPtr +QUICStreamManager::create_client_stream(QUICStreamId stream_id) +{ + // TODO: check stream_id + QUICStream *stream = this->_find_or_create_stream(stream_id); + if (!stream) { + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); + } + + QUICApplication *application = this->_app_map->get(stream_id); + + if (!application->is_stream_set(stream)) { + application->set_stream(stream); + } + + return QUICErrorUPtr(new QUICNoError()); +} + QUICErrorUPtr QUICStreamManager::handle_frame(std::shared_ptr frame) { @@ -216,6 +234,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) this->_remote_maximum_stream_id_uni != 0) { return nullptr; } + // TODO Free the stream somewhere stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream(); uint32_t local_max_stream_data = 0; @@ -231,6 +250,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) this->stream_list.push(stream); } + return stream; } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 05be5c86b74..bedb85bb7f4 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -48,6 +48,7 @@ class QUICStreamManager : public QUICFrameHandler void add_total_offset_sent(uint32_t sent_byte); uint32_t stream_count() const; + QUICErrorUPtr create_client_stream(QUICStreamId stream_id); void set_default_application(QUICApplication *app); @@ -58,8 +59,8 @@ class QUICStreamManager : public QUICFrameHandler virtual QUICErrorUPtr handle_frame(std::shared_ptr) override; private: - QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICStream *_find_stream(QUICStreamId id); + QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICErrorUPtr _handle_frame(const std::shared_ptr &); From 010f95eb9b103b99f55a9d8eb5b28e68b43f6309 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 16 Jan 2018 11:53:42 +0900 Subject: [PATCH 0323/1313] Fix Transport Parameter validations and default value of _initial_max_stream_* --- iocore/net/quic/QUICConfig.h | 8 ++-- iocore/net/quic/QUICHandshake.cc | 3 +- iocore/net/quic/QUICTransportParameters.cc | 53 ++++++++++++++-------- iocore/net/quic/QUICTypes.h | 4 +- 4 files changed, 41 insertions(+), 27 deletions(-) diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index c4525a1a6e3..233c035dd40 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -46,10 +46,10 @@ class QUICConfigParams : public ConfigInfo uint32_t _no_activity_timeout_out = 30; uint32_t _initial_max_data = 131072; uint32_t _initial_max_stream_data = 2048; - uint32_t _initial_max_stream_id_bidi_in = 100; - uint32_t _initial_max_stream_id_bidi_out = 101; - uint32_t _initial_max_stream_id_uni_in = 102; - uint32_t _initial_max_stream_id_uni_out = 103; + uint32_t _initial_max_stream_id_bidi_out = 100; + uint32_t _initial_max_stream_id_bidi_in = 101; + uint32_t _initial_max_stream_id_uni_out = 102; + uint32_t _initial_max_stream_id_uni_in = 103; uint32_t _server_id = 0; }; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index b700eb30726..81598e6b69f 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -223,7 +223,8 @@ QUICHandshake::set_transport_parameters(std::shared_ptr_remote_transport_parameters = tp; // TODO Add client side implementation - ink_assert(false); + + return; } void diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index c3c25c4813c..0bffe55e1de 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -125,7 +125,13 @@ QUICTransportParameters::_load(const uint8_t *buf, size_t len) } // Validate parameters - this->_valid = (this->_validate_parameters() == 0); + int res = this->_validate_parameters(); + if (res < 0) { + Debug(tag, "Transport parameter is not valid (err=%d)", res); + this->_valid = false; + } else { + this->_valid = true; + } } int @@ -139,52 +145,53 @@ QUICTransportParameters::_validate_parameters() const return -1; } } else { - return -1; + return -2; } if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_DATA)) != this->_parameters.end()) { if (ite->second->len() != 4) { - return -1; + return -3; } } else { - return -1; + return -4; } if ((ite = this->_parameters.find(QUICTransportParameterId::IDLE_TIMEOUT)) != this->_parameters.end()) { if (ite->second->len() != 2) { - return -1; + return -5; } if (QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 600) { - return -1; + return -6; } } else { - return -1; + return -7; } // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::OMIT_CONNECTION_ID)) != this->_parameters.end()) { if (ite->second->len() != 0) { - return -1; + return -8; } } if ((ite = this->_parameters.find(QUICTransportParameterId::MAX_PACKET_SIZE)) != this->_parameters.end()) { if (ite->second->len() != 2) { - return -1; + return -9; } if (QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) < 1200) { - return -1; + return -10; } } if ((ite = this->_parameters.find(QUICTransportParameterId::ACK_DELAY_EXPONENT)) != this->_parameters.end()) { if (ite->second->len() != 1) { - return -1; + return -11; } if (QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 20) { - return -1; + return -12; } } + return 0; } @@ -358,7 +365,8 @@ QUICTransportParametersInClientHello::_validate_parameters() const if (ite->second->len() != 4) { return -2; } - if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 1) { + if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != + QUICStreamType::CLIENT_BIDI) { return -3; } } @@ -367,7 +375,8 @@ QUICTransportParametersInClientHello::_validate_parameters() const if (ite->second->len() != 4) { return -4; } - if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 3) { + if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != + QUICStreamType::CLIENT_UNI) { return -5; } } @@ -445,7 +454,7 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const // MUSTs if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) { - if (ite->second->len() != 2) { + if (ite->second->len() != QUICStatelessResetToken::LEN) { return -1; } } else { @@ -457,7 +466,8 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const if (ite->second->len() != 4) { return -3; } - if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 1) { + if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != + QUICStreamType::SERVER_BIDI) { return -4; } } @@ -466,7 +476,8 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const if (ite->second->len() != 4) { return -5; } - if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 3) { + if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != + QUICStreamType::SERVER_UNI) { return -6; } } @@ -508,7 +519,7 @@ QUICTransportParametersInNewSessionTicket::_validate_parameters() const // MUSTs if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) { - if (ite->second->len() != 2) { + if (ite->second->len() != QUICStatelessResetToken::LEN) { return -1; } } else { @@ -520,7 +531,8 @@ QUICTransportParametersInNewSessionTicket::_validate_parameters() const if (ite->second->len() != 4) { return -3; } - if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 1) { + if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != + QUICStreamType::SERVER_BIDI) { return -4; } } @@ -529,7 +541,8 @@ QUICTransportParametersInNewSessionTicket::_validate_parameters() const if (ite->second->len() != 4) { return -5; } - if ((QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) & 0x03) != 3) { + if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != + QUICStreamType::SERVER_UNI) { return -6; } } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 912a82a318a..4744cbc7ee1 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -247,8 +247,8 @@ class QUICStatelessResetToken void _gen_token(uint64_t data); }; -enum class QUICStreamType { - CLIENT_BIDI, +enum class QUICStreamType : uint8_t { + CLIENT_BIDI = 0x00, SERVER_BIDI, CLIENT_UNI, SERVER_UNI, From 7972edd073ffe90a5c647d88f7fe8cfab8ca9403 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 16 Jan 2018 12:32:50 +0900 Subject: [PATCH 0324/1313] Check handshake status before connection migration --- iocore/net/QUICNetVConnection.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3ebf90d7ff4..582025d2f95 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -719,7 +719,7 @@ QUICNetVConnection::_state_common_receive_packet() net_activity(this, this_ethread()); // Check connection migration - if (p->connection_id() != this->_quic_connection_id) { + if (this->_handshake_handler->is_completed() && p->connection_id() != this->_quic_connection_id) { for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { AltConnectionInfo &info = this->_alt_quic_connection_ids[i]; if (info.id == p->connection_id()) { From 124c4d7af5ac0c21f6574a3ba5e4ba5b06cfd66d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 16 Jan 2018 14:03:33 +0900 Subject: [PATCH 0325/1313] Rename QUICStreamManager::create_client_stream to QUICStreamManager::create_stream --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICStreamManager.cc | 2 +- iocore/net/quic/QUICStreamManager.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 582025d2f95..45d4163258a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -160,7 +160,7 @@ int QUICNetVConnection::connectUp(EThread *t, int fd) { // create stream for handshake - QUICErrorUPtr error = this->_stream_manager->create_client_stream(STREAM_ID_FOR_HANDSHAKE); + QUICErrorUPtr error = this->_stream_manager->create_stream(STREAM_ID_FOR_HANDSHAKE); if (error->cls != QUICErrorClass::NONE) { QUICConDebug("Couldn't create stream for handshake"); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index a1ed28ce7ec..1f27a7d2b5a 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -92,7 +92,7 @@ QUICStreamManager::set_max_stream_id(QUICStreamId id) } QUICErrorUPtr -QUICStreamManager::create_client_stream(QUICStreamId stream_id) +QUICStreamManager::create_stream(QUICStreamId stream_id) { // TODO: check stream_id QUICStream *stream = this->_find_or_create_stream(stream_id); diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index bedb85bb7f4..37375b4952d 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -48,7 +48,7 @@ class QUICStreamManager : public QUICFrameHandler void add_total_offset_sent(uint32_t sent_byte); uint32_t stream_count() const; - QUICErrorUPtr create_client_stream(QUICStreamId stream_id); + QUICErrorUPtr create_stream(QUICStreamId stream_id); void set_default_application(QUICApplication *app); From af7e1b460fe5f00e5939cc291cd2f2beafdc1a62 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 16 Jan 2018 14:29:58 +0900 Subject: [PATCH 0326/1313] Fix QUICTransportParameters validations of initial_max_stream_id_bidi/uni --- iocore/net/quic/QUICConfig.h | 8 +++---- iocore/net/quic/QUICTransportParameters.cc | 27 ++++++++++++---------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 233c035dd40..c4525a1a6e3 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -46,10 +46,10 @@ class QUICConfigParams : public ConfigInfo uint32_t _no_activity_timeout_out = 30; uint32_t _initial_max_data = 131072; uint32_t _initial_max_stream_data = 2048; - uint32_t _initial_max_stream_id_bidi_out = 100; - uint32_t _initial_max_stream_id_bidi_in = 101; - uint32_t _initial_max_stream_id_uni_out = 102; - uint32_t _initial_max_stream_id_uni_in = 103; + uint32_t _initial_max_stream_id_bidi_in = 100; + uint32_t _initial_max_stream_id_bidi_out = 101; + uint32_t _initial_max_stream_id_uni_in = 102; + uint32_t _initial_max_stream_id_uni_out = 103; uint32_t _server_id = 0; }; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 0bffe55e1de..5a15b875e17 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -349,8 +349,9 @@ QUICTransportParametersInClientHello::_parameters_offset(const uint8_t *) const int QUICTransportParametersInClientHello::_validate_parameters() const { - if (QUICTransportParameters::_validate_parameters() < 0) { - return 0; + int res = QUICTransportParameters::_validate_parameters(); + if (res < 0) { + return res - 100; } decltype(this->_parameters)::const_iterator ite; @@ -366,7 +367,7 @@ QUICTransportParametersInClientHello::_validate_parameters() const return -2; } if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != - QUICStreamType::CLIENT_BIDI) { + QUICStreamType::SERVER_BIDI) { return -3; } } @@ -376,7 +377,7 @@ QUICTransportParametersInClientHello::_validate_parameters() const return -4; } if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != - QUICStreamType::CLIENT_UNI) { + QUICStreamType::SERVER_UNI) { return -5; } } @@ -446,8 +447,9 @@ QUICTransportParametersInEncryptedExtensions::_parameters_offset(const uint8_t * int QUICTransportParametersInEncryptedExtensions::_validate_parameters() const { - if (QUICTransportParameters::_validate_parameters() < 0) { - return 0; + int res = QUICTransportParameters::_validate_parameters(); + if (res < 0) { + return res - 100; } decltype(this->_parameters)::const_iterator ite; @@ -467,7 +469,7 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const return -3; } if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != - QUICStreamType::SERVER_BIDI) { + QUICStreamType::CLIENT_BIDI) { return -4; } } @@ -477,7 +479,7 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const return -5; } if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != - QUICStreamType::SERVER_UNI) { + QUICStreamType::CLIENT_UNI) { return -6; } } @@ -511,8 +513,9 @@ QUICTransportParametersInNewSessionTicket::_parameters_offset(const uint8_t *buf int QUICTransportParametersInNewSessionTicket::_validate_parameters() const { - if (QUICTransportParameters::_validate_parameters() < 0) { - return 0; + int res = QUICTransportParameters::_validate_parameters(); + if (res < 0) { + return res - 100; } decltype(this->_parameters)::const_iterator ite; @@ -532,7 +535,7 @@ QUICTransportParametersInNewSessionTicket::_validate_parameters() const return -3; } if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != - QUICStreamType::SERVER_BIDI) { + QUICStreamType::CLIENT_BIDI) { return -4; } } @@ -542,7 +545,7 @@ QUICTransportParametersInNewSessionTicket::_validate_parameters() const return -5; } if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != - QUICStreamType::SERVER_UNI) { + QUICStreamType::CLIENT_UNI) { return -6; } } From aa724876b275ade448747980ae8291dc07d13baa Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 16 Jan 2018 14:33:20 +0900 Subject: [PATCH 0327/1313] Respond with a closing frame on closing state --- iocore/net/P_QUICNetVConnection.h | 2 ++ iocore/net/QUICNetVConnection.cc | 29 +++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index d076fd3988f..e63f34a0dc8 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -279,6 +279,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICErrorUPtr _state_connection_established_process_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_common_receive_packet(); QUICErrorUPtr _state_common_send_packet(); + QUICErrorUPtr _state_closing_send_packet(); Ptr _packet_transmitter_mutex; Ptr _frame_transmitter_mutex; @@ -298,6 +299,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _handle_idle_timeout(); void _update_alt_connection_ids(uint8_t chosen); + QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet(); QUICStatelessResetToken _reset_token; }; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 45d4163258a..87e9c0e8f08 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -492,10 +492,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) break; case QUIC_EVENT_PACKET_WRITE_READY: this->_close_packet_write_ready(data); - // FIXME During the closing period, an endpoint that sends a - // closing frame SHOULD respond to any packet that it receives with - // another packet containing a closing frame. - this->_state_common_send_packet(); + this->_state_closing_send_packet(); break; case QUIC_EVENT_CLOSING_TIMEOUT: this->_close_closing_timeout(data); @@ -769,6 +766,18 @@ QUICNetVConnection::_state_common_send_packet() return QUICErrorUPtr(new QUICNoError()); } +QUICErrorUPtr +QUICNetVConnection::_state_closing_send_packet() +{ + // During the closing period, an endpoint that sends a + // closing frame SHOULD respond to any packet that it receives with + // another packet containing a closing frame. To minimize the state + // that an endpoint maintains for a closing connection, endpoints MAY + // send the exact same packet. + this->_packet_handler->send_packet(*this->_the_final_packet, this); + return QUICErrorUPtr(new QUICNoError()); +} + // Store frame data to buffer for packet. When remaining buffer is too small to store frame data or packet type is different from // previous one, build packet and transmit it. After that, allocate new buffer. void @@ -802,6 +811,15 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans frame->store(buf.get() + len, &l); len += l; + if (frame->type() == QUICFrameType::CONNECTION_CLOSE || frame->type() == QUICFrameType::APPLICATION_CLOSE) { + this->_transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, previous_packet_type)); + retransmittable = false; + len = 0; + buf = ats_unique_malloc(max_size); + frame->store(buf.get(), &l); + this->_the_final_packet = this->_build_packet(std::move(buf), l, false); + } + return; } @@ -836,6 +854,9 @@ QUICNetVConnection::_packetize_frames() frame = std::move(this->_frame_send_queue.front()); this->_frame_send_queue.pop(); this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + if (this->_the_final_packet) { + return; + } } while (this->_stream_frame_send_queue.size() > 0) { From abab45200c76b5afb7b4d01e811c95011a5284ef Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 16 Jan 2018 15:20:03 +0900 Subject: [PATCH 0328/1313] Implement PONG --- iocore/net/QUICNetVConnection.cc | 5 +++++ iocore/net/quic/QUICFrame.cc | 22 ++++++++++++++++++++++ iocore/net/quic/QUICFrame.h | 10 ++++++++++ 3 files changed, 37 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 87e9c0e8f08..21ccc2963d1 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -354,6 +354,11 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) this->_remote_flow_controller->current_limit()); this->_schedule_packet_write_ready(); + break; + case QUICFrameType::PING: + if (std::static_pointer_cast(frame)->data_length() > 0) { + this->transmit_frame(QUICFrameFactory::create_pong_frame(*std::static_pointer_cast(frame))); + } break; case QUICFrameType::BLOCKED: // BLOCKED frame is for debugging. Nothing to do here. diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 252d57c4b2f..f7445ee13bf 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1898,6 +1898,28 @@ QUICFrameFactory::create_max_stream_data_frame(QUICStreamId stream_id, uint64_t return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); } +std::unique_ptr +QUICFrameFactory::create_ping_frame(const uint8_t *data, size_t data_len) +{ + ats_unique_buf buf = ats_unique_malloc(data_len); + memcpy(buf.get(), data, data_len); + + QUICPingFrame *frame = quicPingFrameAllocator.alloc(); + new (frame) QUICPingFrame(std::move(buf), data_len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_ping_frame); +} + +std::unique_ptr +QUICFrameFactory::create_pong_frame(const QUICPingFrame &ping_frame) +{ + ats_unique_buf buf = ats_unique_malloc(ping_frame.data_length()); + memcpy(buf.get(), ping_frame.data(), ping_frame.data_length()); + + QUICPongFrame *frame = quicPongFrameAllocator.alloc(); + new (frame) QUICPongFrame(std::move(buf), ping_frame.data_length()); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_pong_frame); +} + std::unique_ptr QUICFrameFactory::create_blocked_frame(QUICOffset offset) { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 342defadf91..0cc90d5c012 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -752,6 +752,16 @@ class QUICFrameFactory static std::unique_ptr create_max_stream_data_frame(QUICStreamId stream_id, uint64_t maximum_stream_data); + /* + * Creates a PING frame + */ + static std::unique_ptr create_ping_frame(const uint8_t *data, size_t data_len); + + /* + * Creates a PONG frame + */ + static std::unique_ptr create_pong_frame(const QUICPingFrame &ping_frame); + /* * Creates a BLOCKED frame. */ From 24b104f01261c6ac8dd5b7c5d1885fe066a4d315 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 17 Jan 2018 01:11:36 +0900 Subject: [PATCH 0329/1313] Prepare for adding stats Currently proxy.process.quic.total_packets_sent is the only stat. --- iocore/net/QUICNetVConnection.cc | 3 +++ iocore/net/quic/QUICGlobals.cc | 17 +++++++++++++++++ iocore/net/quic/QUICGlobals.h | 4 ++++ proxy/hq/HQ.cc | 4 ++-- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 21ccc2963d1..8ecd953b463 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -36,6 +36,7 @@ #include "P_SSLNextProtocolSet.h" +#include "QUICStats.h" #include "QUICConfig.h" #include "QUICDebugNames.h" #include "QUICEvents.h" @@ -761,10 +762,12 @@ QUICNetVConnection::_state_common_send_packet() QUICPacket *packet; SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); + uint32_t packet_count = this->_packet_send_queue.size; while ((packet = this->_packet_send_queue.dequeue()) != nullptr) { this->_packet_handler->send_packet(*packet, this); this->_loss_detector->on_packet_sent(QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet)); } + QUIC_INCREMENT_DYN_STAT_EX(quic_total_packets_sent_stat, packet_count); net_activity(this, this_ethread()); diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index ca45f67a054..ebc5e6e1d5d 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -23,9 +23,12 @@ #include #include "QUICGlobals.h" +#include "QUICStats.h" #include "QUICConnection.h" #include "P_SSLNextProtocolSet.h" +RecRawStatBlock *quic_rsb; + int QUIC::ssl_quic_qc_index = -1; int QUIC::ssl_quic_hs_index = -1; @@ -46,3 +49,17 @@ QUIC::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned cha *outlen = 0; return SSL_TLSEXT_ERR_NOACK; } + +void +QUIC::_register_stats() +{ + quic_rsb = RecAllocateRawStatBlock(static_cast(quic_stat_count)); + + // Transfered packet counts + RecRegisterRawStat(quic_rsb, RECT_PROCESS, "proxy.process.quic.total_packets_sent", RECD_INT, RECP_PERSISTENT, + static_cast(quic_total_packets_sent_stat), RecRawStatSyncSum); + // RecRegisterRawStat(quic_rsb, RECT_PROCESS, "proxy.process.quic.total_packets_retransmitted", RECD_INT, RECP_PERSISTENT, + // static_cast(quic_total_packets_retransmitted_stat), RecRawStatSyncSum); + // RecRegisterRawStat(quic_rsb, RECT_PROCESS, "proxy.process.quic.total_packets_received", RECD_INT, RECP_PERSISTENT, + // static_cast(quic_total_packets_received_stat), RecRawStatSyncSum); +} diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h index 1af0f733a37..c4b52689ca4 100644 --- a/iocore/net/quic/QUICGlobals.h +++ b/iocore/net/quic/QUICGlobals.h @@ -31,6 +31,7 @@ class QUIC static void init() { + QUIC::_register_stats(); ssl_quic_qc_index = SSL_get_ex_new_index(0, (void *)"QUICConnection index", nullptr, nullptr, nullptr); ssl_quic_hs_index = SSL_get_ex_new_index(0, (void *)"QUICHandshake index", nullptr, nullptr, nullptr); } @@ -40,4 +41,7 @@ class QUIC // SSL callbacks static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen, void *); + +private: + static void _register_stats(); }; diff --git a/proxy/hq/HQ.cc b/proxy/hq/HQ.cc index 1797a866770..1282a1ad824 100644 --- a/proxy/hq/HQ.cc +++ b/proxy/hq/HQ.cc @@ -23,10 +23,10 @@ #include "HQ.h" -RecRawStatBlock *quic_rsb; +RecRawStatBlock *hq_rsb; void HQ::init() { - quic_rsb = RecAllocateRawStatBlock(static_cast(HQ_N_STATS)); + hq_rsb = RecAllocateRawStatBlock(static_cast(HQ_N_STATS)); } From 2f954c6eaa6c0ec07025830af8160ffd5269ded3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 17 Jan 2018 10:18:23 +0900 Subject: [PATCH 0330/1313] Add QUICStats.h --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICGlobals.cc | 4 +-- iocore/net/quic/QUICStats.h | 43 ++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 iocore/net/quic/QUICStats.h diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8ecd953b463..9882b43dabe 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -767,7 +767,7 @@ QUICNetVConnection::_state_common_send_packet() this->_packet_handler->send_packet(*packet, this); this->_loss_detector->on_packet_sent(QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet)); } - QUIC_INCREMENT_DYN_STAT_EX(quic_total_packets_sent_stat, packet_count); + QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, packet_count); net_activity(this, this_ethread()); diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index ebc5e6e1d5d..7627a2e91b8 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -53,11 +53,11 @@ QUIC::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned cha void QUIC::_register_stats() { - quic_rsb = RecAllocateRawStatBlock(static_cast(quic_stat_count)); + quic_rsb = RecAllocateRawStatBlock(static_cast(QUICStats::count)); // Transfered packet counts RecRegisterRawStat(quic_rsb, RECT_PROCESS, "proxy.process.quic.total_packets_sent", RECD_INT, RECP_PERSISTENT, - static_cast(quic_total_packets_sent_stat), RecRawStatSyncSum); + static_cast(QUICStats::total_packets_sent_stat), RecRawStatSyncSum); // RecRegisterRawStat(quic_rsb, RECT_PROCESS, "proxy.process.quic.total_packets_retransmitted", RECD_INT, RECP_PERSISTENT, // static_cast(quic_total_packets_retransmitted_stat), RecRawStatSyncSum); // RecRegisterRawStat(quic_rsb, RECT_PROCESS, "proxy.process.quic.total_packets_received", RECD_INT, RECP_PERSISTENT, diff --git a/iocore/net/quic/QUICStats.h b/iocore/net/quic/QUICStats.h new file mode 100644 index 00000000000..51dcff2623c --- /dev/null +++ b/iocore/net/quic/QUICStats.h @@ -0,0 +1,43 @@ +/** @file + * + * QUIC Stats + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "records/I_RecProcess.h" + +extern RecRawStatBlock *quic_rsb; + +enum class QUICStats { + total_packets_sent_stat, + count, +}; + +#define QUIC_INCREMENT_DYN_STAT(x) RecIncrRawStat(quic_rsb, nullptr, (int)x, 1) +#define QUIC_DECREMENT_DYN_STAT(x) RecIncrRawStat(quic_rsb, nullptr, (int)x, -1) +#define QUIC_SET_COUNT_DYN_STAT(x, count) RecSetRawStatCount(quic_rsb, x, count) +#define QUIC_INCREMENT_DYN_STAT_EX(x, y) RecIncrRawStat(quic_rsb, nullptr, (int)x, y) +#define QUIC_CLEAR_DYN_STAT(x) \ + do { \ + RecSetRawStatSum(quic_rsb, (x), 0); \ + RecSetRawStatCount(quic_rsb, (x), 0); \ + } while (0) From 1a8b894ecc0abdb760c745c631ecd44d484713c0 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 17 Jan 2018 10:20:47 +0900 Subject: [PATCH 0331/1313] Include headers at an apropriate place --- iocore/net/quic/QUICConnection.h | 1 - iocore/net/quic/QUICHandshake.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index e236c82bf70..c2df2f39330 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -28,7 +28,6 @@ #include "QUICPacketTransmitter.h" #include "QUICFrameTransmitter.h" #include "QUICFrameHandler.h" -#include "QUICTransportParameters.h" class QUICApplication; class QUICStreamManager; diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index f6c3973a1c8..99eda1509a2 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -25,6 +25,7 @@ #include "QUICConnection.h" #include "QUICApplication.h" +#include "QUICTransportParameters.h" /** * @class QUICHandshake From 4e3fa10bb1feb9ed63ff0246ffc67ef602053d3d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 17 Jan 2018 10:43:44 +0900 Subject: [PATCH 0332/1313] Remove an unused variable --- iocore/net/P_QUICNetVConnection.h | 1 - iocore/net/QUICNetVConnection.cc | 1 - 2 files changed, 2 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e63f34a0dc8..6a46e45ec52 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -230,7 +230,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // TODO: use custom allocator and make them std::unique_ptr or std::shared_ptr // or make them just member variables. - QUICVersionNegotiator *_version_negotiator = nullptr; QUICHandshake *_handshake_handler = nullptr; QUICCrypto *_crypto = nullptr; QUICLossDetector *_loss_detector = nullptr; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 9882b43dabe..69f01158ee1 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -132,7 +132,6 @@ QUICNetVConnection::free(EThread *t) this->_packet_handler = nullptr; _unschedule_packet_write_ready(); - delete this->_version_negotiator; delete this->_handshake_handler; delete this->_application_map; delete this->_crypto; From f884b3f05751e4e6c257ab53ac94f2938543b7da Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 17 Jan 2018 09:47:22 +0900 Subject: [PATCH 0333/1313] Fix error handling of handshake --- iocore/net/quic/QUICCrypto.cc | 27 +++++-------- iocore/net/quic/QUICCrypto.h | 2 +- iocore/net/quic/QUICCryptoTls.h | 2 +- iocore/net/quic/QUICHandshake.cc | 69 +++++++++++++++++++++++--------- iocore/net/quic/QUICHandshake.h | 2 +- 5 files changed, 62 insertions(+), 40 deletions(-) diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index c997c17bf44..fcba8ca970d 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -116,11 +116,12 @@ QUICCryptoTls::~QUICCryptoTls() delete this->_server_pp; } -bool +int QUICCryptoTls::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) { ink_assert(this->_ssl != nullptr); + // TODO: directly read/write from VIO BIO *rbio = BIO_new(BIO_s_mem()); BIO *wbio = BIO_new(BIO_s_mem()); if (in != nullptr || in_len != 0) { @@ -128,11 +129,12 @@ QUICCryptoTls::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, cons } SSL_set_bio(this->_ssl, rbio, wbio); + int err = SSL_ERROR_NONE; if (!SSL_is_init_finished(this->_ssl)) { ERR_clear_error(); int ret = SSL_do_handshake(this->_ssl); if (ret <= 0) { - int err = SSL_get_error(this->_ssl, ret); + err = SSL_get_error(this->_ssl, ret); switch (err) { case SSL_ERROR_WANT_READ: @@ -142,26 +144,17 @@ QUICCryptoTls::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, cons char err_buf[256] = {0}; ERR_error_string_n(err, err_buf, sizeof(err_buf)); Debug(tag, "Handshake error: %s (%d)", err_buf, err); - return false; + return err; } } - } - // OpenSSL doesn't have BIO_mem_contents - // const uint8_t *buf; - // if (!BIO_mem_contents(wbio, &buf, &out_len)) { - // return false; - // } - // if (out_len <= 0) { - // return false; - // } - - out_len = BIO_read(wbio, out, max_out_len); - if (out_len <= 0) { - return false; + out_len = BIO_ctrl_pending(wbio); + if (out_len > 0) { + BIO_read(wbio, out, max_out_len); + } } - return true; + return err; } bool diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICCrypto.h index 5c57083d59e..6e9f048527b 100644 --- a/iocore/net/quic/QUICCrypto.h +++ b/iocore/net/quic/QUICCrypto.h @@ -48,7 +48,7 @@ class QUICCrypto QUICCrypto(){}; virtual ~QUICCrypto(){}; - virtual bool handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) = 0; + virtual int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) = 0; virtual bool is_handshake_finished() const = 0; virtual int initialize_key_materials(QUICConnectionId cid) = 0; virtual int update_key_materials() = 0; diff --git a/iocore/net/quic/QUICCryptoTls.h b/iocore/net/quic/QUICCryptoTls.h index b26ec4314fb..884992a0fde 100644 --- a/iocore/net/quic/QUICCryptoTls.h +++ b/iocore/net/quic/QUICCryptoTls.h @@ -42,7 +42,7 @@ class QUICCryptoTls : public QUICCrypto QUICCryptoTls(SSL *ssl, NetVConnectionContext_t nvc_ctx); ~QUICCryptoTls(); - bool handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override; + int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override; bool is_handshake_finished() const override; int initialize_key_materials(QUICConnectionId cid) override; int update_key_materials() override; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 81598e6b69f..03a453ca491 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -437,7 +437,7 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi this->_local_transport_parameters = std::unique_ptr(tp); } -QUICErrorUPtr +int QUICHandshake::_do_handshake(bool initial) { // TODO: pass stream_io @@ -453,37 +453,42 @@ QUICHandshake::_do_handshake(bool initial) if (in_len <= 0) { QUICHSDebug("No message"); - return QUICErrorUPtr(new QUICNoError()); + return SSL_ERROR_NONE; } I_WANNA_DUMP_THIS_BUF(in, in_len); } uint8_t out[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t out_len = 0; - bool result = false; - result = this->_crypto->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, in, in_len); + int result = this->_crypto->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, in, in_len); - if (result) { + if (out_len > 0) { I_WANNA_DUMP_THIS_BUF(out, static_cast(out_len)); stream_io->write(out, out_len); - - return QUICErrorUPtr(new QUICNoError()); - } else { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); } + + return result; } QUICErrorUPtr QUICHandshake::_process_initial() { QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); - QUICErrorUPtr error = _do_handshake(true); + int result = _do_handshake(true); + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - if (error->cls == QUICErrorClass::NONE) { + switch (result) { + case SSL_ERROR_WANT_READ: { QUICHSDebug("Enter state_key_exchange"); SET_HANDLER(&QUICHandshake::state_key_exchange); stream_io->write_reenable(); + stream_io->read_reenable(); + + break; + } + default: + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); } return error; @@ -493,15 +498,21 @@ QUICErrorUPtr QUICHandshake::_process_client_hello() { QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); - QUICErrorUPtr error = _do_handshake(); + int result = _do_handshake(); + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - if (error->cls == QUICErrorClass::NONE) { + switch (result) { + case SSL_ERROR_WANT_READ: { QUICHSDebug("Enter state_auth"); SET_HANDLER(&QUICHandshake::state_auth); stream_io->write_reenable(); - } else { stream_io->read_reenable(); + + break; + } + default: + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); } return error; @@ -511,17 +522,26 @@ QUICErrorUPtr QUICHandshake::_process_server_hello() { QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); - QUICErrorUPtr error = _do_handshake(); + int result = _do_handshake(); + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - if (error->cls == QUICErrorClass::NONE) { + switch (result) { + case SSL_ERROR_NONE: { int res = this->_complete_handshake(); if (res) { stream_io->write_reenable(); } else { this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); } - } else { + + break; + } + case SSL_ERROR_WANT_READ: { stream_io->read_reenable(); + break; + } + default: + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); } return error; @@ -531,17 +551,26 @@ QUICErrorUPtr QUICHandshake::_process_finished() { QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); - QUICErrorUPtr error = _do_handshake(); + int result = _do_handshake(); + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - if (error->cls == QUICErrorClass::NONE) { + switch (result) { + case SSL_ERROR_NONE: { int res = this->_complete_handshake(); if (res) { stream_io->write_reenable(); } else { this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); } - } else { + + break; + } + case SSL_ERROR_WANT_READ: { stream_io->read_reenable(); + break; + } + default: + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); } return error; diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 99eda1509a2..4a83225affa 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -97,7 +97,7 @@ class QUICHandshake : public QUICApplication void _load_local_server_transport_parameters(QUICVersion negotiated_version); void _load_local_client_transport_parameters(QUICVersion initial_version); - QUICErrorUPtr _do_handshake(bool initial = false); + int _do_handshake(bool initial = false); QUICErrorUPtr _process_initial(); QUICErrorUPtr _process_client_hello(); From 1afd5a880a4acca0460d69f0b07c291b4dc70901 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 17 Jan 2018 09:49:57 +0900 Subject: [PATCH 0334/1313] Add in/out checks after handshake --- iocore/net/QUICNetVConnection.cc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 69f01158ee1..b5962ead4f4 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -170,7 +170,6 @@ QUICNetVConnection::connectUp(EThread *t, int fd) // start QUIC handshake this->_handshake_handler->handleEvent(VC_EVENT_WRITE_READY, nullptr); - // action_.continuation->handleEvent(NET_EVENT_OPEN, this); return CONNECT_SUCCESS; } @@ -1123,11 +1122,15 @@ QUICNetVConnection::_complete_handshake_if_possible() app_name_len = IP_PROTO_TAG_HTTP_QUIC.size(); } - Continuation *endpoint = this->_next_protocol_set->findEndpoint(app_name, app_name_len); - if (endpoint == nullptr) { - this->_handle_error(QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR))); + if (netvc_context == NET_VCONNECTION_IN) { + Continuation *endpoint = this->_next_protocol_set->findEndpoint(app_name, app_name_len); + if (endpoint == nullptr) { + this->_handle_error(QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR))); + } else { + endpoint->handleEvent(NET_EVENT_ACCEPT, this); + } } else { - endpoint->handleEvent(NET_EVENT_ACCEPT, this); + this->action_.continuation->handleEvent(NET_EVENT_OPEN, this); } return 0; @@ -1148,7 +1151,9 @@ QUICNetVConnection::_switch_to_established_state() QUICConDebug("%s", this->_handshake_handler->negotiated_cipher_suite()); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); - this->_update_alt_connection_ids(countof(this->_alt_quic_connection_ids) - 1); + if (netvc_context == NET_VCONNECTION_IN) { + this->_update_alt_connection_ids(countof(this->_alt_quic_connection_ids) - 1); + } } else { // Illegal state change ink_assert(!"Handshake has to be completed"); From 871fa49fe1b91a0f62740163aed26e558cead417 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 17 Jan 2018 14:04:45 +0900 Subject: [PATCH 0335/1313] Ignore Initial and Handshake packet after handshake completed --- iocore/net/QUICNetVConnection.cc | 7 +++++++ iocore/net/quic/QUICPacket.cc | 12 ++++++++---- iocore/net/quic/QUICTypes.h | 1 + 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b5962ead4f4..78dcad48955 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -716,7 +716,10 @@ QUICNetVConnection::_state_common_receive_packet() return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); } else if (result == QUICPacketCreationResult::NOT_READY) { return QUICErrorUPtr(new QUICNoError()); + } else if (result == QUICPacketCreationResult::IGNORED) { + return QUICErrorUPtr(new QUICNoError()); } + net_activity(this, this_ethread()); // Check connection migration @@ -1034,6 +1037,10 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) // Retry later this->_packet_recv_queue.enqueue(udp_packet); this_ethread()->schedule_in_local(this, HRTIME_MSECONDS(10), QUIC_EVENT_PACKET_READ_READY); + } else if (result == QUICPacketCreationResult::IGNORED) { + QUICConDebug("Ignore to decrypt the packet"); + + udp_packet->free(); } else { udp_packet->free(); if (result == QUICPacketCreationResult::SUCCESS) { diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index ba775776248..4d42fcb5cef 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -666,11 +666,15 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ break; case QUICPacketType::INITIAL: case QUICPacketType::HANDSHAKE: - if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { - result = QUICPacketCreationResult::SUCCESS; + if (!this->_crypto->is_handshake_finished()) { + if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), + header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { + result = QUICPacketCreationResult::SUCCESS; + } else { + result = QUICPacketCreationResult::FAILED; + } } else { - result = QUICPacketCreationResult::FAILED; + result = QUICPacketCreationResult::IGNORED; } break; default: diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 4744cbc7ee1..5f32dbb7724 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -120,6 +120,7 @@ enum class QUICPacketCreationResult { SUCCESS, FAILED, NOT_READY, + IGNORED, }; enum class QUICErrorClass { From 997c57b47d78cdddbf2e30fc37e05b98786950a2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 17 Jan 2018 14:06:22 +0900 Subject: [PATCH 0336/1313] Add null packet check before sending packet --- iocore/net/QUICNetVConnection.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 78dcad48955..b09f2351349 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -783,7 +783,9 @@ QUICNetVConnection::_state_closing_send_packet() // another packet containing a closing frame. To minimize the state // that an endpoint maintains for a closing connection, endpoints MAY // send the exact same packet. - this->_packet_handler->send_packet(*this->_the_final_packet, this); + if (this->_the_final_packet) { + this->_packet_handler->send_packet(*this->_the_final_packet, this); + } return QUICErrorUPtr(new QUICNoError()); } From 2b002aabe93ecc6eaa1cd71b06d02b5243d34f2d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 17 Jan 2018 17:03:07 +0900 Subject: [PATCH 0337/1313] Complete handshake after sending finished --- iocore/net/P_QUICNetVConnection.h | 3 +-- iocore/net/QUICNetVConnection.cc | 31 ++++++++++++++++++-------- iocore/net/QUICPacketHandler.cc | 4 ++++ iocore/net/quic/QUICConnection.h | 5 +++++ iocore/net/quic/QUICEvents.h | 1 + iocore/net/quic/QUICHandshake.cc | 36 +++++++++++++++++++------------ 6 files changed, 55 insertions(+), 25 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 6a46e45ec52..5b47b750ac9 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -176,6 +176,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // QUICConnection QUICConnectionId original_connection_id() override; QUICConnectionId connection_id() override; + void reset_connection_id(QUICConnectionId cid) override; uint32_t maximum_quic_packet_size() override; uint32_t minimum_quic_packet_size() override; uint32_t maximum_stream_frame_data_size() override; @@ -248,8 +249,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection std::queue _frame_send_queue; std::queue _stream_frame_send_queue; - bool _is_initial = true; - void _schedule_packet_write_ready(); void _unschedule_packet_write_ready(); void _close_packet_write_ready(Event *data); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b09f2351349..3a64bca6467 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -185,6 +185,12 @@ QUICNetVConnection::connection_id() return this->_quic_connection_id; } +void +QUICNetVConnection::reset_connection_id(QUICConnectionId cid) +{ + this->_quic_connection_id = cid; +} + uint32_t QUICNetVConnection::pmtu() { @@ -947,15 +953,23 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi std::move(buf), len, retransmittable); break; default: - if (this->_handshake_handler && this->_handshake_handler->is_completed()) { - packet = this->_packet_factory.create_server_protected_packet(this->_quic_connection_id, this->largest_acked_packet_number(), - std::move(buf), len, retransmittable); - } else { - // FIXME: remove this flag - if (this->get_context() == NET_VCONNECTION_OUT && this->_is_initial) { - this->_is_initial = false; - packet = this->_packet_factory.create_initial_packet( + if (this->get_context() == NET_VCONNECTION_OUT) { + if (this->_handshake_handler->handler == reinterpret_cast(&QUICHandshake::state_initial)) { + packet = this->_packet_factory.create_initial_packet( this->_original_quic_connection_id, this->largest_acked_packet_number(), QUIC_SUPPORTED_VERSIONS[0], std::move(buf), len); + this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); + } else if (this->_handshake_handler->handler == reinterpret_cast(&QUICHandshake::state_key_exchange)) { + packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), + std::move(buf), len, retransmittable); + this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); + } else { + packet = this->_packet_factory.create_server_protected_packet( + this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); + } + } else { + if (this->_handshake_handler && this->_handshake_handler->is_completed()) { + packet = this->_packet_factory.create_server_protected_packet( + this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); } else { packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); @@ -1157,7 +1171,6 @@ QUICNetVConnection::_switch_to_established_state() { if (this->_complete_handshake_if_possible() == 0) { QUICConDebug("Enter state_connection_established"); - QUICConDebug("%s", this->_handshake_handler->negotiated_cipher_suite()); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); if (netvc_context == NET_VCONNECTION_IN) { diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 12e3cc4f73b..0dac684a554 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -285,6 +285,10 @@ QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet) Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); + if (this->_vc->connection_id() != cid) { + this->_vc->reset_connection_id(cid); + } + this->_vc->push_packet(udp_packet); eventProcessor.schedule_imm(this->_vc, ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr); } diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index c2df2f39330..98d7abd8b50 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -39,6 +39,11 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter virtual QUICConnectionId original_connection_id() = 0; virtual QUICConnectionId connection_id() = 0; + /* + * Server chooses a new value for the connection ID and client needs to reset it. + */ + virtual void reset_connection_id(QUICConnectionId cid) = 0; + /* * Retruns the maximum packet size at the time called * diff --git a/iocore/net/quic/QUICEvents.h b/iocore/net/quic/QUICEvents.h index c3f9b446263..ffbb3b47abb 100644 --- a/iocore/net/quic/QUICEvents.h +++ b/iocore/net/quic/QUICEvents.h @@ -29,6 +29,7 @@ enum { QUIC_EVENT_PACKET_READ_READY = QUIC_EVENT_EVENTS_START, QUIC_EVENT_PACKET_WRITE_READY, + QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, QUIC_EVENT_CLOSING_TIMEOUT, QUIC_EVENT_SHUTDOWN, QUIC_EVENT_LD_SHUTDOWN, diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 03a453ca491..e4612c39842 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -21,16 +21,19 @@ * limitations under the License. */ -#include "QUICGlobals.h" #include "QUICHandshake.h" -#include "QUICCryptoTls.h" #include -#include "QUICVersionNegotiator.h" -#include "QUICConfig.h" + #include "P_SSLNextProtocolSet.h" #include "P_VConnection.h" +#include "QUICCryptoTls.h" +#include "QUICEvents.h" +#include "QUICGlobals.h" +#include "QUICVersionNegotiator.h" +#include "QUICConfig.h" + static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; #define QUICHSDebug(fmt, ...) \ @@ -281,6 +284,11 @@ QUICHandshake::state_initial(int event, Event *data) QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { + case QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE: { + QUICHSDebug("Enter state_key_exchange"); + SET_HANDLER(&QUICHandshake::state_key_exchange); + break; + } case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { if (this->_netvc_context == NET_VCONNECTION_IN) { @@ -319,6 +327,14 @@ QUICHandshake::state_key_exchange(int event, Event *data) QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { + case QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE: { + int res = this->_complete_handshake(); + if (!res) { + this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); + } + + break; + } case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { ink_assert(this->_netvc_context == NET_VCONNECTION_OUT); @@ -479,9 +495,6 @@ QUICHandshake::_process_initial() switch (result) { case SSL_ERROR_WANT_READ: { - QUICHSDebug("Enter state_key_exchange"); - SET_HANDLER(&QUICHandshake::state_key_exchange); - stream_io->write_reenable(); stream_io->read_reenable(); @@ -527,13 +540,7 @@ QUICHandshake::_process_server_hello() switch (result) { case SSL_ERROR_NONE: { - int res = this->_complete_handshake(); - if (res) { - stream_io->write_reenable(); - } else { - this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); - } - + stream_io->write_reenable(); break; } case SSL_ERROR_WANT_READ: { @@ -581,6 +588,7 @@ QUICHandshake::_complete_handshake() { QUICHSDebug("Enter state_complete"); SET_HANDLER(&QUICHandshake::state_complete); + QUICHSDebug("%s", this->negotiated_cipher_suite()); int res = this->_crypto->update_key_materials(); if (res) { From 6d75bb178ffc16cfe9ad78c41d1687d4123f52d2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 19 Jan 2018 10:19:49 +0900 Subject: [PATCH 0338/1313] Allocate QUICNetVConnection by ClassAllocator --- iocore/net/QUICPacketHandler.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 0dac684a554..b4c32efcb8b 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -172,8 +172,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) } // Create a new NetVConnection - vc = static_cast( - getNetProcessor()->allocate_vc(((UnixUDPConnection *)udp_packet->getConnection())->ethread)); + vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); vc->init(cid, udp_packet->getConnection(), this); vc->id = net_next_connection_number(); vc->con.move(con); From c041e55ae46f785df472922745083e04e2318f52 Mon Sep 17 00:00:00 2001 From: Leif Hedstrom Date: Fri, 19 Jan 2018 10:33:43 +0900 Subject: [PATCH 0339/1313] Fix a compiler warning for now --- iocore/net/quic/QUICTransportParameters.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 5a15b875e17..d7c88896f48 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -501,7 +501,7 @@ void QUICTransportParametersInNewSessionTicket::_store(uint8_t *buf, uint16_t *len) const { // no additional fields defined - len = 0; + *len = 0; } std::ptrdiff_t From ea129d3ff4476c9f2509ccc32e6ae52817e515f9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 19 Jan 2018 16:21:48 +0900 Subject: [PATCH 0340/1313] Disable TLP for now TLP causes infinite retransmission & acknowledge loop somehow. Disable this as a workaround for next interop. --- iocore/net/quic/QUICLossDetector.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 93aa5a85c86..4a6bf4d615e 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -309,7 +309,8 @@ QUICLossDetector::_on_loss_detection_alarm() } else if (this->_tlp_count < MAX_TLPS) { // Tail Loss Probe. QUICLDDebug("TLP"); - this->_send_one_packet(); + // FIXME TLP causes inifinite loop somehow + // this->_send_one_packet(); this->_tlp_count++; } else { // RTO. From e9619720ce62bf20ed3c4ce3d271626a61fd2828 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 19 Jan 2018 16:33:24 +0900 Subject: [PATCH 0341/1313] Use UDPNetProcessor::CreateUDPSocket() --- iocore/net/QUICNetProcessor.cc | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index ff6bcf23fff..2c109427a99 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -118,20 +118,15 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne EThread *t = cont->mutex->thread_holding; ink_assert(t); - sockaddr_in local_addr; - local_addr.sin_family = remote_addr->sa_family; - local_addr.sin_addr.s_addr = htonl(INADDR_ANY); - local_addr.sin_port = 0; - - // FIXME: set buffer size - int fd = socketManager.socket(local_addr.sin_family, SOCK_DGRAM, 0); - if (fd < 0) { - return ACTION_IO_ERROR; - } - - int res = fcntl(fd, F_SETFL, O_NONBLOCK); - if (res < 0) { - return ACTION_IO_ERROR; + sockaddr local_addr; + int local_addr_len; + local_addr.sa_family = remote_addr->sa_family; + + int fd; + Action *status; + bool result = udpNet.CreateUDPSocket(&fd, remote_addr, &local_addr, &local_addr_len, &status, 1048576, 1048576); + if (!result) { + return status; } // Setup UDPConnection @@ -145,8 +140,8 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne PollCont *pc = get_UDPPollCont(con->ethread); PollDescriptor *pd = pc->pollDescriptor; - errno = 0; - res = con->ep.start(pd, con, EVENTIO_READ); + errno = 0; + int res = con->ep.start(pd, con, EVENTIO_READ); if (res < 0) { Debug("udpnet", "Error: %s (%d)", strerror(errno), errno); } From 56ab5ab706d0542f8924f082667e45d2499f88f3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 22 Jan 2018 09:31:36 +1100 Subject: [PATCH 0342/1313] Print QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE event --- iocore/net/quic/QUICDebugNames.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index a35f47668e1..088cd0b2f64 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -148,6 +148,8 @@ QUICDebugNames::quic_event(int event) return "QUIC_EVENT_PACKET_READ_READY"; case QUIC_EVENT_PACKET_WRITE_READY: return "QUIC_EVENT_PACKET_WRITE_READY"; + case QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE: + return "QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE"; case QUIC_EVENT_CLOSING_TIMEOUT: return "QUIC_EVENT_CLOSING_TIMEOUT"; case QUIC_EVENT_SHUTDOWN: From f5b039539d13debe891b821afeb1dbeb709caa74 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 22 Jan 2018 09:59:12 +1100 Subject: [PATCH 0343/1313] Print event number --- iocore/net/QUICNetVConnection.cc | 10 +++++----- iocore/net/quic/QUICHandshake.cc | 8 ++++---- iocore/net/quic/QUICStream.cc | 8 ++++---- proxy/hq/HQClientTransaction.cc | 8 ++++---- proxy/hq/QUICSimpleApp.cc | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3a64bca6467..aec2fb28541 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -448,7 +448,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) this->_handle_idle_timeout(); break; default: - QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); + QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); } if (error->cls != QUICErrorClass::NONE) { @@ -479,7 +479,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) break; } default: - QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); + QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); } if (error->cls != QUICErrorClass::NONE) { @@ -509,7 +509,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) this->_switch_to_close_state(); break; default: - QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); + QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); } return EVENT_DONE; @@ -535,7 +535,7 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) this->_switch_to_close_state(); break; default: - QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); + QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); } return EVENT_DONE; @@ -566,7 +566,7 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) break; } default: - QUICConDebug("Unexpected event: %s", QUICDebugNames::quic_event(event)); + QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); } return EVENT_DONE; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index e4612c39842..44a172a4c02 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -280,7 +280,7 @@ QUICHandshake::remote_transport_parameters() int QUICHandshake::state_initial(int event, Event *data) { - QUICHSDebug("%s", get_vc_event_name(event)); + QUICHSDebug("%s (%d)", get_vc_event_name(event), event); QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { @@ -323,7 +323,7 @@ QUICHandshake::state_initial(int event, Event *data) int QUICHandshake::state_key_exchange(int event, Event *data) { - QUICHSDebug("%s", get_vc_event_name(event)); + QUICHSDebug("%s (%d)", get_vc_event_name(event), event); QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { @@ -363,7 +363,7 @@ QUICHandshake::state_key_exchange(int event, Event *data) int QUICHandshake::state_auth(int event, Event *data) { - QUICHSDebug("%s", get_vc_event_name(event)); + QUICHSDebug("%s (%d)", get_vc_event_name(event), event); QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { @@ -401,7 +401,7 @@ QUICHandshake::state_address_validation(int event, void *data) int QUICHandshake::state_complete(int event, void *data) { - QUICHSDebug("%s", get_vc_event_name(event)); + QUICHSDebug("%s (%d)", get_vc_event_name(event), event); QUICHSDebug("Got an event on complete state. Ignoring it for now."); return EVENT_DONE; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index c2370d1c12e..071da7e8538 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -94,7 +94,7 @@ QUICStream::final_offset() int QUICStream::state_stream_open(int event, void *data) { - QUICStreamDebug("%s", get_vc_event_name(event)); + QUICStreamDebug("%s (%d)", get_vc_event_name(event), event); QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); switch (event) { @@ -154,7 +154,7 @@ QUICStream::state_stream_open(int event, void *data) int QUICStream::state_stream_closed(int event, void *data) { - QUICStreamDebug("%s", get_vc_event_name(event)); + QUICStreamDebug("%s (%d)", get_vc_event_name(event), event); switch (event) { case VC_EVENT_READ_READY: @@ -400,7 +400,7 @@ QUICStream::_signal_read_event() this_ethread()->schedule_imm(this->_read_vio._cont, event, &this->_read_vio); } - QUICStreamDebug("%s", get_vc_event_name(event)); + QUICStreamDebug("%s (%d)", get_vc_event_name(event), event); } /** @@ -422,7 +422,7 @@ QUICStream::_signal_write_event() this_ethread()->schedule_imm(this->_write_vio._cont, event, &this->_write_vio); } - QUICStreamDebug("%s", get_vc_event_name(event)); + QUICStreamDebug("%s (%d)", get_vc_event_name(event), event); } int64_t diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 168dbaeb565..83b88f1f073 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -94,7 +94,7 @@ int HQClientTransaction::state_stream_open(int event, void *edata) { // TODO: should check recursive call? - HQTransDebug("%s", get_vc_event_name(event)); + HQTransDebug("%s (%d)", get_vc_event_name(event), event); switch (event) { case VC_EVENT_READ_READY: @@ -136,7 +136,7 @@ HQClientTransaction::state_stream_open(int event, void *edata) int HQClientTransaction::state_stream_closed(int event, void *data) { - HQTransDebug("%s", get_vc_event_name(event)); + HQTransDebug("%s (%d)", get_vc_event_name(event), event); switch (event) { case VC_EVENT_READ_READY: @@ -318,7 +318,7 @@ HQClientTransaction::_signal_read_event() this_ethread()->schedule_imm(this->_read_vio._cont, event, &this->_read_vio); } - HQTransDebug("%s", get_vc_event_name(event)); + HQTransDebug("%s (%d)", get_vc_event_name(event), event); } /** @@ -339,7 +339,7 @@ HQClientTransaction::_signal_write_event() this_ethread()->schedule_imm(this->_write_vio._cont, event, &this->_write_vio); } - HQTransDebug("%s", get_vc_event_name(event)); + HQTransDebug("%s (%d)", get_vc_event_name(event), event); } // Convert HTTP/0.9 to HTTP/1.1 diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index 502a1d0faf0..3002e76bc05 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -55,7 +55,7 @@ QUICSimpleApp::~QUICSimpleApp() int QUICSimpleApp::main_event_handler(int event, Event *data) { - Debug(tag, "%s", get_vc_event_name(event)); + Debug(tag, "%s (%d)", get_vc_event_name(event), event); VIO *vio = reinterpret_cast(data); QUICStreamIO *stream_io = this->_find_stream_io(vio); From b0c77cd5a5831d0601434db2e4f8044a09b08fab Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 22 Jan 2018 10:53:04 +1100 Subject: [PATCH 0344/1313] Fill the unused field of Version Negotiation Packet with random value --- iocore/net/quic/QUICPacket.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 4d42fcb5cef..0fc20dfe00b 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -239,6 +239,9 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const *len = 0; buf[0] = 0x80; buf[0] += static_cast(this->_type); + if (this->_type == QUICPacketType::VERSION_NEGOTIATION) { + buf[0] |= rand(); + } *len += 1; QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, buf + *len, &n); From 2c7ebfb7282ba0064c33af5eddc2fda77a76ce19 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 22 Jan 2018 14:55:13 +1100 Subject: [PATCH 0345/1313] Print retransmission alarm in millisecond --- iocore/net/quic/QUICLossDetector.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 4a6bf4d615e..e12f937ccf3 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -289,7 +289,7 @@ QUICLossDetector::_set_loss_detection_alarm() } else { this->_loss_detection_alarm_at = this->_time_of_last_sent_packet + alarm_duration; } - QUICLDDebug("Loss detection alarm has been set to %" PRId64, alarm_duration); + QUICLDDebug("Loss detection alarm has been set to %" PRId64 "ms", alarm_duration / HRTIME_MSECOND); if (!this->_loss_detection_alarm) { this->_loss_detection_alarm = eventProcessor.schedule_every(this, HRTIME_MSECONDS(25)); From 9549f57290fb9d44ba7f175ba18834d3bdd248cd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 22 Jan 2018 15:43:14 +1100 Subject: [PATCH 0346/1313] Deactivate QUICNetVC on closing state --- iocore/net/QUICNetVConnection.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index aec2fb28541..e30c3247ded 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1198,6 +1198,9 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) } else { this->transmit_frame(QUICFrameFactory::create_connection_close_frame(std::move(error))); } + + this->remove_from_active_queue(); + QUICConDebug("Enter state_connection_closing"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); } From 77badcf9df125dd2c3129dbabc02b773a2f26195 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 22 Jan 2018 16:00:39 +1100 Subject: [PATCH 0347/1313] Fix a bug that retransmission timer wasn't reset correctly --- iocore/net/quic/QUICLossDetector.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index e12f937ccf3..74db01f7ff2 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -65,6 +65,7 @@ QUICLossDetector::event_handler(int event, Event *edata) switch (event) { case EVENT_INTERVAL: { if (this->_loss_detection_alarm_at <= Thread::get_hrtime()) { + this->_loss_detection_alarm_at = 0; this->_on_loss_detection_alarm(); } break; From 163e3a7d518bd0e71d4010636d1ec7f492b13b94 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 23 Jan 2018 01:21:56 +1100 Subject: [PATCH 0348/1313] Add QUIC CID to HQ logs --- proxy/hq/HQClientTransaction.cc | 5 ++--- proxy/hq/HQSessionAccept.cc | 3 ++- proxy/hq/QUICSimpleApp.cc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 83b88f1f073..52ebffeb457 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -28,9 +28,8 @@ #include "HQClientSession.h" #include "HttpSM.h" -// XXX this->parent->connection_id() is Session ID of HQClientSession. Should this be QUIC Connection ID? #define HQTransDebug(fmt, ...) \ - Debug("hq_trans", "[%" PRId64 "] [%" PRIx32 "] " fmt, this->parent->connection_id(), this->get_transaction_id(), ##__VA_ARGS__) + Debug("hq_trans", "[%" PRIx64 "] [%" PRIx32 "] " fmt, static_cast(static_cast(reinterpret_cast(this->parent->get_netvc()))->connection_id()), this->get_transaction_id(), ##__VA_ARGS__) // static void // dump_io_buffer(IOBufferReader *reader) @@ -126,7 +125,7 @@ HQClientTransaction::state_stream_open(int event, void *edata) break; } default: - Debug("hq_trans", "Unknown event %d", event); + HQTransDebug("Unknown event %d", event); ink_assert(false); } diff --git a/proxy/hq/HQSessionAccept.cc b/proxy/hq/HQSessionAccept.cc index a0533981816..ce1aa6a64cc 100644 --- a/proxy/hq/HQSessionAccept.cc +++ b/proxy/hq/HQSessionAccept.cc @@ -52,7 +52,8 @@ HQSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader if (is_debug_tag_set("quic_seq")) { ip_port_text_buffer ipb; - Debug("quic_seq", "[HQSessionAccept:mainEvent %p] accepted connection from %s transport type = %d", netvc, + Debug("quic_seq", "[%" PRIx64 "] accepted connection from %s transport type = %d", + static_cast(static_cast(static_cast(netvc))->connection_id()), ats_ip_nptop(client_ip, ipb, sizeof(ipb)), netvc->attributes); } diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index 3002e76bc05..054075d6a2d 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -55,13 +55,13 @@ QUICSimpleApp::~QUICSimpleApp() int QUICSimpleApp::main_event_handler(int event, Event *data) { - Debug(tag, "%s (%d)", get_vc_event_name(event), event); + Debug(tag, "[%" PRIx64 "] %s (%d)", static_cast(this->_client_qc->connection_id()), get_vc_event_name(event), event); VIO *vio = reinterpret_cast(data); QUICStreamIO *stream_io = this->_find_stream_io(vio); if (stream_io == nullptr) { - Debug(tag, "Unknown Stream"); + Debug(tag, "[%" PRIx64 "] Unknown Stream", static_cast(this->_client_qc->connection_id())); return -1; } From 75812607fa50f5b165159cc0f9662e65d52a0311 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 23 Jan 2018 01:51:56 +1100 Subject: [PATCH 0349/1313] Add QUIC CID to quic_app logs --- iocore/net/quic/QUICApplication.cc | 2 +- iocore/net/quic/QUICApplication.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index b0ab67e976a..2bc9775c410 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -156,7 +156,7 @@ QUICApplication::reenable(QUICStream *stream) stream_io->read_reenable(); stream_io->write_reenable(); } else { - Debug(tag, "Unknown Stream, id: %" PRIx64, stream->id()); + Debug(tag, "[%" PRIx64 "] Unknown Stream, id: %" PRIx64, static_cast(this->_client_qc->connection_id()), stream->id()); } return; diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index f2a47e161ef..cbffb955555 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -26,9 +26,9 @@ #include "../../eventsystem/I_EventSystem.h" #include "../../eventsystem/I_IOBuffer.h" #include "QUICTypes.h" +#include "QUICConnection.h" #include "QUICStream.h" -class QUICConnection; class QUICApplication; /** From 5a363861f812bfa4b2a0ed3775a011d2334739ca Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 23 Jan 2018 01:52:30 +1100 Subject: [PATCH 0350/1313] Print server generated CID on LossDetecotr logs --- iocore/net/quic/QUICLossDetector.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 74db01f7ff2..867408c3fb3 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -118,7 +118,7 @@ QUICLossDetector::largest_acked_packet_number() void QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) { - if (this->_connection_id == 0) { + if (this->_connection_id == 0 && packet->type() != QUICPacketType::VERSION_NEGOTIATION) { this->_connection_id = packet->connection_id(); } From 66f1fc25205bd02f666bc151871004ee73dc0f5a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 23 Jan 2018 13:43:36 +1100 Subject: [PATCH 0351/1313] Don't decrypt packets that have unsupported version --- iocore/net/quic/QUICApplication.cc | 3 ++- iocore/net/quic/QUICPacket.cc | 15 +++++++++++++++ iocore/net/quic/QUICTypes.cc | 11 +++++++++++ iocore/net/quic/QUICTypes.h | 1 + iocore/net/quic/QUICVersionNegotiator.cc | 15 ++------------- iocore/net/quic/QUICVersionNegotiator.h | 2 -- 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 2bc9775c410..e2d73bfe34f 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -156,7 +156,8 @@ QUICApplication::reenable(QUICStream *stream) stream_io->read_reenable(); stream_io->write_reenable(); } else { - Debug(tag, "[%" PRIx64 "] Unknown Stream, id: %" PRIx64, static_cast(this->_client_qc->connection_id()), stream->id()); + Debug(tag, "[%" PRIx64 "] Unknown Stream, id: %" PRIx64, static_cast(this->_client_qc->connection_id()), + stream->id()); } return; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 0fc20dfe00b..097a67e532c 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -668,6 +668,21 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ } break; case QUICPacketType::INITIAL: + if (!this->_crypto->is_handshake_finished()) { + if (QUICTypeUtil::is_supported_version(header->version())) { + if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), + header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { + result = QUICPacketCreationResult::SUCCESS; + } else { + result = QUICPacketCreationResult::FAILED; + } + } else { + result = QUICPacketCreationResult::SUCCESS; + } + } else { + result = QUICPacketCreationResult::IGNORED; + } + break; case QUICPacketType::HANDSHAKE: if (!this->_crypto->is_handshake_finished()) { if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 045b2c9a307..399df5cc6d1 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -41,6 +41,17 @@ QUICTypeUtil::has_connection_id(const uint8_t *buf) return (buf[0] & 0x40) == 0; } +bool +QUICTypeUtil::is_supported_version(QUICVersion version) +{ + for (auto v : QUIC_SUPPORTED_VERSIONS) { + if (v == version) { + return true; + } + } + return false; +} + QUICStreamType QUICTypeUtil::detect_stream_type(QUICStreamId id) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 5f32dbb7724..384c13bc848 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -261,6 +261,7 @@ class QUICTypeUtil public: static bool has_long_header(const uint8_t *buf); static bool has_connection_id(const uint8_t *buf); + static bool is_supported_version(QUICVersion version); static QUICStreamType detect_stream_type(QUICStreamId id); static QUICConnectionId read_QUICConnectionId(const uint8_t *buf, uint8_t n); diff --git a/iocore/net/quic/QUICVersionNegotiator.cc b/iocore/net/quic/QUICVersionNegotiator.cc index eba42c2985a..2329c31efbc 100644 --- a/iocore/net/quic/QUICVersionNegotiator.cc +++ b/iocore/net/quic/QUICVersionNegotiator.cc @@ -33,7 +33,7 @@ QUICVersionNegotiator::status() QUICVersionNegotiationStatus QUICVersionNegotiator::negotiate(const QUICPacket *initial_packet) { - if (this->_is_supported(initial_packet->version())) { + if (QUICTypeUtil::is_supported_version(initial_packet->version())) { this->_status = QUICVersionNegotiationStatus::NEGOTIATED; this->_negotiated_version = initial_packet->version(); } @@ -46,7 +46,7 @@ QUICVersionNegotiator::validate(const QUICTransportParametersInClientHello *tp) if (this->_negotiated_version == tp->initial_version()) { this->_status = QUICVersionNegotiationStatus::VALIDATED; } else { - if (this->_is_supported(tp->initial_version())) { + if (QUICTypeUtil::is_supported_version(tp->initial_version())) { this->_status = QUICVersionNegotiationStatus::FAILED; this->_negotiated_version = 0; } else { @@ -61,14 +61,3 @@ QUICVersionNegotiator::negotiated_version() { return this->_negotiated_version; } - -bool -QUICVersionNegotiator::_is_supported(QUICVersion version) -{ - for (auto v : QUIC_SUPPORTED_VERSIONS) { - if (v == version) { - return true; - } - } - return false; -} diff --git a/iocore/net/quic/QUICVersionNegotiator.h b/iocore/net/quic/QUICVersionNegotiator.h index 576b6256c39..651a7db51c4 100644 --- a/iocore/net/quic/QUICVersionNegotiator.h +++ b/iocore/net/quic/QUICVersionNegotiator.h @@ -42,6 +42,4 @@ class QUICVersionNegotiator private: QUICVersion _negotiated_version = 0; QUICVersionNegotiationStatus _status = QUICVersionNegotiationStatus::NOT_NEGOTIATED; - - bool _is_supported(QUICVersion version); }; From 4f55b160ae66f6ecb7fe34b9b6c060fc4ccb3c5b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 23 Jan 2018 14:04:23 +1100 Subject: [PATCH 0352/1313] Add a log for binidng client generated CID and server generated CID --- iocore/net/QUICNetVConnection.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e30c3247ded..57e4f06ee86 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -69,6 +69,8 @@ QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, this->_packet_handler = packet_handler; this->_original_quic_connection_id = original_cid; this->_quic_connection_id.randomize(); + QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(this->_original_quic_connection_id), + static_cast(this->_quic_connection_id)); } VIO * From b62739606baf7508531270ec16c09fc599370700 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 24 Jan 2018 09:23:27 +1100 Subject: [PATCH 0353/1313] Check SSL_is_init_finished() before complete handshake --- iocore/net/quic/QUICHandshake.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 44a172a4c02..78009c9be5f 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -328,9 +328,12 @@ QUICHandshake::state_key_exchange(int event, Event *data) QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE: { - int res = this->_complete_handshake(); - if (!res) { - this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); + QUICCryptoTls *crypto_tls = dynamic_cast(this->_crypto); + if (crypto_tls && SSL_is_init_finished(crypto_tls->ssl_handle())) { + int res = this->_complete_handshake(); + if (!res) { + this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); + } } break; @@ -338,8 +341,6 @@ QUICHandshake::state_key_exchange(int event, Event *data) case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { ink_assert(this->_netvc_context == NET_VCONNECTION_OUT); - - // FIXME: client could recv ServerHello and HelloRetryRequest error = this->_process_server_hello(); break; } @@ -544,6 +545,8 @@ QUICHandshake::_process_server_hello() break; } case SSL_ERROR_WANT_READ: { + // FIXME: check if write_reenable should be called or not + stream_io->write_reenable(); stream_io->read_reenable(); break; } From 9d47df294e2ea29a33dc91b89be936c6df1b8c27 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 25 Jan 2018 14:45:15 +1100 Subject: [PATCH 0354/1313] Allow empty Stream Data with FIN bit --- iocore/net/quic/QUICIncomingFrameBuffer.cc | 2 +- iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index ba9cc5128c8..a00d6d78581 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -128,7 +128,7 @@ QUICIncomingFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, this->_fin_offset = offset + len; - if (this->_max_offset >= this->_fin_offset) { + if (this->_max_offset > this->_fin_offset) { return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::FINAL_OFFSET_ERROR)); } diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 5652ba3d55b..1f6c337cd4e 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -72,6 +72,18 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); } + SECTION("Pure FIN") + { + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); + std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 0, 1, 1024, true); + + err = buffer.insert(stream1_frame_0_r); + CHECK(err->cls == QUICErrorClass::NONE); + + err = buffer.insert(stream1_frame_1_r); + CHECK(err->cls == QUICErrorClass::NONE); + } + delete stream; } From 186ddfbc19c4dfb4e6a0fdadc35857a2c85f5f86 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sat, 27 Jan 2018 21:54:30 +0900 Subject: [PATCH 0355/1313] clang-format --- proxy/hq/HQClientTransaction.cc | 7 +++++-- proxy/hq/HQSessionAccept.cc | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 52ebffeb457..779210d457b 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -28,8 +28,11 @@ #include "HQClientSession.h" #include "HttpSM.h" -#define HQTransDebug(fmt, ...) \ - Debug("hq_trans", "[%" PRIx64 "] [%" PRIx32 "] " fmt, static_cast(static_cast(reinterpret_cast(this->parent->get_netvc()))->connection_id()), this->get_transaction_id(), ##__VA_ARGS__) +#define HQTransDebug(fmt, ...) \ + Debug("hq_trans", "[%" PRIx64 "] [%" PRIx32 "] " fmt, \ + static_cast( \ + static_cast(reinterpret_cast(this->parent->get_netvc()))->connection_id()), \ + this->get_transaction_id(), ##__VA_ARGS__) // static void // dump_io_buffer(IOBufferReader *reader) diff --git a/proxy/hq/HQSessionAccept.cc b/proxy/hq/HQSessionAccept.cc index ce1aa6a64cc..75d8982fb4e 100644 --- a/proxy/hq/HQSessionAccept.cc +++ b/proxy/hq/HQSessionAccept.cc @@ -53,7 +53,7 @@ HQSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader ip_port_text_buffer ipb; Debug("quic_seq", "[%" PRIx64 "] accepted connection from %s transport type = %d", - static_cast(static_cast(static_cast(netvc))->connection_id()), + static_cast(static_cast(static_cast(netvc))->connection_id()), ats_ip_nptop(client_ip, ipb, sizeof(ipb)), netvc->attributes); } From e3ad67a5094a768705c473eefd3b5afddfc69792 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sat, 27 Jan 2018 23:48:59 +0900 Subject: [PATCH 0356/1313] Remove QUICConnection::reset_connection_id() --- iocore/net/P_QUICNetVConnection.h | 1 - iocore/net/P_QUICPacketHandler.h | 2 +- iocore/net/QUICNetVConnection.cc | 19 +++++++++----- iocore/net/QUICPacketHandler.cc | 43 +++++++++---------------------- iocore/net/quic/QUICConnection.h | 5 ---- iocore/net/quic/QUICPacket.cc | 16 ++++++++++++ iocore/net/quic/QUICPacket.h | 2 ++ iocore/net/quic/QUICTypes.cc | 2 +- 8 files changed, 45 insertions(+), 45 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 5b47b750ac9..a6e2b883966 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -176,7 +176,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // QUICConnection QUICConnectionId original_connection_id() override; QUICConnectionId connection_id() override; - void reset_connection_id(QUICConnectionId cid) override; uint32_t maximum_quic_packet_size() override; uint32_t minimum_quic_packet_size() override; uint32_t maximum_stream_frame_data_size() override; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 2205a800c90..8fce95660ef 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -39,7 +39,7 @@ class QUICPacketHandler protected: static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu); - static bool _read_connection_id(QUICConnectionId &cid, IOBufferBlock *block); + static QUICConnectionId _read_connection_id(IOBufferBlock *block); virtual void _recv_packet(int event, UDPPacket *udpPacket) = 0; }; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 57e4f06ee86..d9406032a35 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -187,12 +187,6 @@ QUICNetVConnection::connection_id() return this->_quic_connection_id; } -void -QUICNetVConnection::reset_connection_id(QUICConnectionId cid) -{ - this->_quic_connection_id = cid; -} - uint32_t QUICNetVConnection::pmtu() { @@ -1038,6 +1032,19 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) result = QUICPacketCreationResult::NOT_READY; return quic_packet; } + + if (this->direction() == NET_VCONNECTION_OUT) { + // Reset CID if a server sent back a new CID + // FIXME This should happen only once + IOBufferBlock *block = udp_packet->getIOBlockChain(); + if (QUICTypeUtil::has_connection_id(reinterpret_cast(block->buf()))) { + QUICConnectionId cid = QUICPacket::connection_id(reinterpret_cast(block->buf())); + if (this->_quic_connection_id != cid) { + this->_quic_connection_id = cid; + } + } + } + net_activity(this, this_ethread()); // Create a QUIC packet diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index b4c32efcb8b..bdbd26145b4 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -49,25 +49,11 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo udp_con->send(c, udp_packet); } -// TODO: Integrate with QUICPacketHeader::connection_id() -bool -QUICPacketHandler::_read_connection_id(QUICConnectionId &cid, IOBufferBlock *block) +QUICConnectionId +QUICPacketHandler::_read_connection_id(IOBufferBlock *block) { - const uint8_t *buf = reinterpret_cast(block->buf()); - const uint8_t cid_offset = 1; - const uint8_t cid_len = 8; - - if (QUICTypeUtil::has_long_header(buf)) { - cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); - } else { - if (QUICTypeUtil::has_connection_id(buf)) { - cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); - } else { - return false; - } - } - - return true; + const uint8_t *buf = reinterpret_cast(block->buf()); + return QUICPacket::connection_id(buf); } // @@ -141,19 +127,19 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) IOBufferBlock *block = udp_packet->getIOBlockChain(); QUICConnectionId cid; - bool res = this->_read_connection_id(cid, block); + if (QUICTypeUtil::has_connection_id(reinterpret_cast(block->buf()))) { + cid = this->_read_connection_id(block); + } else { + // TODO: find cid from five tuples + ink_assert(false); + } ip_port_text_buffer ipb; Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); QUICNetVConnection *vc = nullptr; - if (res) { - vc = this->_connections.get(cid); - } else { - // TODO: find vc from five tuples - ink_assert(false); - } + vc = this->_connections.get(cid); if (!vc) { Connection con; @@ -277,17 +263,12 @@ QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet) { IOBufferBlock *block = udp_packet->getIOBlockChain(); - QUICConnectionId cid; - this->_read_connection_id(cid, block); + QUICConnectionId cid = this->_read_connection_id(block); ip_port_text_buffer ipb; Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); - if (this->_vc->connection_id() != cid) { - this->_vc->reset_connection_id(cid); - } - this->_vc->push_packet(udp_packet); eventProcessor.schedule_imm(this->_vc, ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr); } diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 98d7abd8b50..c2df2f39330 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -39,11 +39,6 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter virtual QUICConnectionId original_connection_id() = 0; virtual QUICConnectionId connection_id() = 0; - /* - * Server chooses a new value for the connection ID and client needs to reset it. - */ - virtual void reset_connection_id(QUICConnectionId cid) = 0; - /* * Retruns the maximum packet size at the time called * diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 097a67e532c..10c53475156 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -629,6 +629,22 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si return true; } +QUICConnectionId +QUICPacket::connection_id(const uint8_t *buf) +{ + constexpr uint8_t cid_offset = 1; + constexpr uint8_t cid_len = 8; + QUICConnectionId cid; + if (QUICTypeUtil::has_long_header(buf)) { + cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); + } else { + ink_assert(QUICTypeUtil::has_connection_id(buf)); + cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); + } + + return cid; +} + // // QUICPacketFactory // diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index a392eb5749d..a7d554d7234 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -220,6 +220,8 @@ class QUICPacket const uint8_t *payload() const; bool is_retransmittable() const; + static QUICConnectionId connection_id(const uint8_t *packet); + /* * Size of whole QUIC packet (header + payload + integrity check) */ diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 399df5cc6d1..a622bd5a241 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -38,7 +38,7 @@ QUICTypeUtil::has_long_header(const uint8_t *buf) bool QUICTypeUtil::has_connection_id(const uint8_t *buf) { - return (buf[0] & 0x40) == 0; + return ((buf[0] & 0x80) != 0) || ((buf[0] & 0x40) == 0); } bool From 90ea93d5e7cc0a2f79075067ea155118a0380c90 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sun, 28 Jan 2018 00:33:36 +0900 Subject: [PATCH 0357/1313] Make tests compilable --- iocore/net/quic/Mock.h | 2 +- iocore/net/quic/test/Makefile.am | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index a25fea87127..5b446cb167f 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -453,7 +453,7 @@ class MockQUICCrypto : public QUICCrypto public: MockQUICCrypto() : QUICCrypto() {} - bool + int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override { return true; diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 7c9a3038576..51c1c1912dc 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -363,6 +363,8 @@ test_QUICCrypto_LDADD = \ @OPENSSL_LIBS@ \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a test_QUICCrypto_SOURCES = \ From 3420f3eb702c7eb7cbb3e57e4988b2e8bcded1d6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sun, 28 Jan 2018 00:33:57 +0900 Subject: [PATCH 0358/1313] Fix tests for TransportParameters --- iocore/net/quic/test/test_QUICTransportParameters.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index 2825f2d3fae..cc737145bdc 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -43,7 +43,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") 0x0a, 0x0b, 0x0c, 0x0d, // value 0x00, 0x03, // parameter id 0x00, 0x02, // length of value - 0xab, 0xcd, // value + 0x01, 0x23, // value }; QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf)); @@ -67,7 +67,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") data = params_in_ch.getAsBytes(QUICTransportParameterId::IDLE_TIMEOUT, len); CHECK(len == 2); - CHECK(memcmp(data, "\xab\xcd", 2) == 0); + CHECK(memcmp(data, "\x01\x23", 2) == 0); data = params_in_ch.getAsBytes(QUICTransportParameterId::MAX_PACKET_SIZE, len); CHECK(len == 0); @@ -145,7 +145,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") 0x12, 0x34, 0x56, 0x78, // value 0x00, 0x03, // parameter id 0x00, 0x02, // length of value - 0x0a, 0x0b, // value + 0x01, 0x23, // value 0x00, 0x06, // parameter id 0x00, 0x10, // length of value 0x00, 0x10, 0x20, 0x30, // value @@ -168,7 +168,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") data = params_in_ee.getAsBytes(QUICTransportParameterId::IDLE_TIMEOUT, len); CHECK(len == 2); - CHECK(memcmp(data, "\x0a\x0b", 2) == 0); + CHECK(memcmp(data, "\x01\x23", 2) == 0); data = params_in_ee.getAsBytes(QUICTransportParameterId::STATELESS_RESET_TOKEN, len); CHECK(len == 16); From 8be2071db8fec2d9e2f03ce7828e0e99afd14dd0 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 27 Jan 2018 12:14:57 +0800 Subject: [PATCH 0359/1313] Replace INK_MD5 since c93790a merged --- iocore/net/quic/QUICTypes.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index a622bd5a241..1b4c87ff0e6 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -203,16 +203,16 @@ QUICTypeUtil::write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size void QUICStatelessResetToken::_gen_token(uint64_t data) { - INK_MD5 _md5; + CryptoHash _hash; static constexpr char STATELESS_RESET_TOKEN_KEY[] = "stateless_token_reset_key"; - MD5Context ctx; + CryptoContext ctx; ctx.update(STATELESS_RESET_TOKEN_KEY, strlen(STATELESS_RESET_TOKEN_KEY)); ctx.update(reinterpret_cast(&data), 8); - ctx.finalize(_md5); + ctx.finalize(_hash); size_t dummy; - QUICTypeUtil::write_uint_as_nbytes(_md5.u64[0], 8, _token, &dummy); - QUICTypeUtil::write_uint_as_nbytes(_md5.u64[1], 8, _token + 8, &dummy); + QUICTypeUtil::write_uint_as_nbytes(_hash.u64[0], 8, _token, &dummy); + QUICTypeUtil::write_uint_as_nbytes(_hash.u64[1], 8, _token + 8, &dummy); } uint16_t From ce3d7c30263edb588c8fc77b165733d5d0aab856 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sun, 28 Jan 2018 23:48:24 +0900 Subject: [PATCH 0360/1313] Manage connection table from QUICNetVConnection side PacketHandler doesn't have enough information to manage CID-Connection mapping. QUICNetVConnections take care of the mapping by themselves, and PacketHandler only lookups the mapping. --- iocore/net/P_QUICNetVConnection.h | 8 ++- iocore/net/P_QUICPacketHandler.h | 8 +-- iocore/net/QUICNetVConnection.cc | 15 ++++- iocore/net/QUICPacketHandler.cc | 64 ++++++++----------- iocore/net/quic/Makefile.am | 1 + iocore/net/quic/Mock.h | 11 ++++ iocore/net/quic/QUICConnection.h | 3 + iocore/net/quic/QUICConnectionTable.cc | 58 ++++++++++++++++++ iocore/net/quic/QUICConnectionTable.h | 71 ++++++++++++++++++++++ iocore/net/quic/QUICTransportParameters.cc | 2 +- 10 files changed, 189 insertions(+), 52 deletions(-) create mode 100644 iocore/net/quic/QUICConnectionTable.cc create mode 100644 iocore/net/quic/QUICConnectionTable.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index a6e2b883966..a82c37bd297 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -43,6 +43,7 @@ #include "ts/List.h" #include "quic/QUICConnection.h" +#include "quic/QUICConnectionTable.h" #include "quic/QUICVersionNegotiator.h" #include "quic/QUICPacket.h" #include "quic/QUICFrame.h" @@ -142,7 +143,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection public: QUICNetVConnection() {} - void init(QUICConnectionId cid, UDPConnection *, QUICPacketHandler *); + void init(QUICConnectionId original_cid, UDPConnection *, QUICPacketHandler *, QUICConnectionTable *ctable = nullptr); // UnixNetVConnection void reenable(VIO *vio) override; @@ -159,7 +160,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection int state_connection_draining(int event, Event *data); int state_connection_closed(int event, Event *data); void start(SSL_CTX *); - void push_packet(UDPPacket *packet); void free(EThread *t) override; UDPConnection *get_udp_con(); @@ -171,7 +171,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // QUICNetVConnection void registerNextProtocolSet(SSLNextProtocolSet *s); - bool is_closed(); // QUICConnection QUICConnectionId original_connection_id() override; @@ -186,6 +185,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void close(QUICConnectionErrorUPtr error) override; QUICPacketNumber largest_received_packet_number() override; QUICPacketNumber largest_acked_packet_number() override; + void handle_received_packet(UDPPacket *packet) override; + bool is_closed() override; // QUICConnection (QUICPacketTransmitter) virtual uint32_t transmit_packet(QUICPacketUPtr packet) override; @@ -238,6 +239,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICCongestionController *_congestion_controller = nullptr; QUICRemoteFlowController *_remote_flow_controller = nullptr; QUICLocalFlowController *_local_flow_controller = nullptr; + QUICConnectionTable *_ctable = nullptr; CountQueue _packet_recv_queue; CountQueue _packet_send_queue; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 8fce95660ef..84d43b84a11 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -27,6 +27,7 @@ #include "P_Connection.h" #include "P_NetAccept.h" #include "quic/QUICTypes.h" +#include "quic/QUICConnectionTable.h" class QUICNetVConnection; class QUICPacket; @@ -34,8 +35,7 @@ class QUICPacket; class QUICPacketHandler { public: - virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc) = 0; - virtual void registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc) = 0; + virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc) = 0; protected: static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu); @@ -62,12 +62,11 @@ class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler // QUICPacketHandler virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc) override; - virtual void registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc) override; private: void _recv_packet(int event, UDPPacket *udp_packet) override; - Map _connections; + QUICConnectionTable _ctable; SSL_CTX *_ssl_ctx; }; @@ -86,7 +85,6 @@ class QUICPacketHandlerOut : public Continuation, public QUICPacketHandler // QUICPacketHandler virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc) override; - virtual void registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc) override; private: void _recv_packet(int event, UDPPacket *udp_packet) override; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index d9406032a35..7af225527d7 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -60,7 +60,8 @@ ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); // XXX This might be called on ET_UDP thread void -QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, QUICPacketHandler *packet_handler) +QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, QUICPacketHandler *packet_handler, + QUICConnectionTable *ctable) { SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_pre_handshake); this->_packet_transmitter_mutex = new_ProxyMutex(); @@ -69,6 +70,8 @@ QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, this->_packet_handler = packet_handler; this->_original_quic_connection_id = original_cid; this->_quic_connection_id.randomize(); + this->_ctable = ctable; + this->_ctable->insert(this->_quic_connection_id, this); QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(this->_original_quic_connection_id), static_cast(this->_quic_connection_id)); } @@ -130,6 +133,12 @@ QUICNetVConnection::free(EThread *t) { QUICConDebug("Free connection"); + this->_ctable->erase(this->_original_quic_connection_id, this); + this->_ctable->erase(this->_quic_connection_id, this); + for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { + this->_ctable->erase(this->_alt_quic_connection_ids[i].id, this); + } + this->_udp_con = nullptr; this->_packet_handler = nullptr; _unschedule_packet_write_ready(); @@ -292,7 +301,7 @@ QUICNetVConnection::get_packet_transmitter_mutex() } void -QUICNetVConnection::push_packet(UDPPacket *packet) +QUICNetVConnection::handle_received_packet(UDPPacket *packet) { this->_packet_recv_queue.enqueue(packet); } @@ -1276,10 +1285,10 @@ QUICNetVConnection::_update_alt_connection_ids(uint8_t chosen) conn_id.randomize(); token.generate(conn_id, params->server_id()); this->_alt_quic_connection_ids[index] = {this->_alt_quic_connection_id_seq_num + i, conn_id, token}; - this->_packet_handler->registerAltConnectionId(conn_id, this); this->transmit_frame(QUICFrameFactory::create_new_connection_id_frame(this->_alt_quic_connection_ids[index].seq_num, this->_alt_quic_connection_ids[index].id, this->_alt_quic_connection_ids[index].token)); + this->_ctable->insert(conn_id, this); } this->_alt_quic_connection_id_seq_num += count; } diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index bdbd26145b4..e60b442afcf 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -126,27 +126,28 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) { IOBufferBlock *block = udp_packet->getIOBlockChain(); - QUICConnectionId cid; - if (QUICTypeUtil::has_connection_id(reinterpret_cast(block->buf()))) { - cid = this->_read_connection_id(block); - } else { - // TODO: find cid from five tuples - ink_assert(false); + if (is_debug_tag_set("quic_sec")) { + ip_port_text_buffer ipb; + if (QUICTypeUtil::has_connection_id(reinterpret_cast(block->buf()))) { + QUICConnectionId cid = this->_read_connection_id(block); + Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), + ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); + } else { + Debug("quic_sec", "received packet from %s, size=%" PRId64 "without CID", + ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); + } } - ip_port_text_buffer ipb; - Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), - ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); - - QUICNetVConnection *vc = nullptr; - vc = this->_connections.get(cid); + QUICConnection *qc = + this->_ctable.lookup(reinterpret_cast(block->buf()), {udp_packet->from, udp_packet->to, SOCK_DGRAM}); - if (!vc) { + if (!qc) { Connection con; con.setRemote(&udp_packet->from.sa); // Send stateless reset if the packet is not a initial packet if (!QUICTypeUtil::has_long_header(reinterpret_cast(block->buf()))) { + QUICConnectionId cid = this->_read_connection_id(block); QUICStatelessResetToken token; { QUICConfig::scoped_config params; @@ -158,8 +159,9 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) } // Create a new NetVConnection - vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); - vc->init(cid, udp_packet->getConnection(), this); + QUICConnectionId original_cid = this->_read_connection_id(block); + QUICNetVConnection *vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); + vc->init(original_cid, udp_packet->getConnection(), this, &this->_ctable); vc->id = net_next_connection_number(); vc->con.move(con); vc->submit_time = Thread::get_hrtime(); @@ -172,18 +174,19 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) vc->options.ip_proto = NetVCOptions::USE_UDP; vc->options.ip_family = udp_packet->from.sa.sa_family; - this->_connections.put(cid, vc); this->action_->continuation->handleEvent(NET_EVENT_ACCEPT, vc); + qc = vc; } - if (vc->is_closed()) { - this->_connections.put(vc->connection_id(), nullptr); + if (qc->is_closed()) { + this->_ctable.erase(qc->connection_id(), qc); // FIXME QUICNetVConnection is NOT freed to prevent crashes. #2674 // QUICNetVConnections are going to be freed by QUICNetHandler // vc->free(vc->thread); } else { - vc->push_packet(udp_packet); - eventProcessor.schedule_imm(vc, ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr); + qc->handle_received_packet(udp_packet); + // FIXME This cast is temporal. It'll be removed when we introduce QUICNetHandler. + eventProcessor.schedule_imm(static_cast(qc), ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr); } } @@ -191,21 +194,9 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) void QUICPacketHandlerIn::send_packet(const QUICPacket &packet, QUICNetVConnection *vc) { - // TODO: remove a connection which is created by Client Initial - // or update key to new one - if (!this->_connections.get(packet.connection_id())) { - this->_connections.put(packet.connection_id(), vc); - } - this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu()); } -void -QUICPacketHandlerIn::registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc) -{ - this->_connections.put(id, vc); -} - // // QUICPacketHandlerOut // @@ -251,13 +242,6 @@ QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection * this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu()); } -void -QUICPacketHandlerOut::registerAltConnectionId(QUICConnectionId id, QUICNetVConnection *vc) -{ - // do nothing - ink_assert(false); -} - void QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet) { @@ -269,6 +253,6 @@ QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet) Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); - this->_vc->push_packet(udp_packet); + 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 62df5dd2613..9201472c221 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -62,6 +62,7 @@ libquic_a_SOURCES = \ $(QUICKeyGenerator_impl) \ QUICKeyGenerator.cc \ QUICTransportParameters.cc \ + QUICConnectionTable.cc \ QUICAckFrameCreator.cc \ QUICConfig.cc \ QUICDebugNames.cc \ diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 5b446cb167f..5a5aa76e705 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -261,6 +261,17 @@ class MockQUICConnection : public QUICConnection return &_stream_manager; } + bool + is_closed() override + { + return false; + } + + void + handle_received_packet(UDPPacket *) override + { + } + int _transmit_count = 0; int _retransmit_count = 0; Ptr _mutex; diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index c2df2f39330..afcade0633b 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -31,6 +31,7 @@ class QUICApplication; class QUICStreamManager; +class UDPPacket; class SSLNextProtocolSet; class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler @@ -62,4 +63,6 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter virtual void close(QUICConnectionErrorUPtr error) = 0; virtual QUICPacketNumber largest_received_packet_number() = 0; virtual QUICPacketNumber largest_acked_packet_number() = 0; + virtual void handle_received_packet(UDPPacket *packeet) = 0; + virtual bool is_closed() = 0; }; diff --git a/iocore/net/quic/QUICConnectionTable.cc b/iocore/net/quic/QUICConnectionTable.cc new file mode 100644 index 00000000000..ce48a8a9c2c --- /dev/null +++ b/iocore/net/quic/QUICConnectionTable.cc @@ -0,0 +1,58 @@ +/** @file + + QUICConnectionTable + + @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 "QUICConnectionTable.h" + +int +QUICConnectionTable::insert(QUICConnectionId cid, QUICConnection *connection) +{ + this->_connections.put(cid, connection); + // if (this->_cids.get(connection->endpoint()) == nullptr) { + // this->_cids.put(connection->endpoint(), cid); + // } + return 0; +} + +void +QUICConnectionTable::erase(QUICConnectionId cid, QUICConnection *connection) +{ + ink_assert(this->_connections.get(cid) == connection); + // if (this->_cids.get(connection->endpoint(), connection->connection_id()) == cid) { + // this->_cids.put(connection->endpoint(), nullptr); + // } + this->_connections.put(cid, nullptr); +} + +QUICConnection * +QUICConnectionTable::lookup(const uint8_t *packet, QUICFiveTuple endpoint) +{ + QUICConnectionId cid; + if (QUICTypeUtil::has_connection_id(packet)) { + cid = QUICPacket::connection_id(packet); + } else { + // TODO: find cid with five tuples + // cid = this->_cids.get(endpoint); + ink_assert(false); + } + return this->_connections.get(cid); +} diff --git a/iocore/net/quic/QUICConnectionTable.h b/iocore/net/quic/QUICConnectionTable.h new file mode 100644 index 00000000000..6bc4b75cd63 --- /dev/null +++ b/iocore/net/quic/QUICConnectionTable.h @@ -0,0 +1,71 @@ +/** @file + * + * QUICConnectionTable + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICTypes.h" +#include "QUICConnection.h" +#include "ts/Map.h" + +class QUICFiveTuple +{ +public: + QUICFiveTuple(IpEndpoint src, IpEndpoint dst, int protocol) + { + // FIXME Generate a hash code + this->_hash_code = src.port() + dst.port() + protocol; + } + +private: + uint64_t _hash_code = 0; +}; + +class QUICConnectionTable +{ +public: + /* + * Insert an entry + * + * Return 1 if it is the only connection or the first connection from the endpoint. + */ + int insert(QUICConnectionId cid, QUICConnection *connection); + + /* + * Remove an entry + * + * Fails if CID is not associated to a specified connection + */ + void erase(QUICConnectionId cid, QUICConnection *connection); + + /* + * Lookup QUICConnection + * + * If packet doesn't have CID, 5-tuple(endpoint) will be used to lookup CID. + */ + QUICConnection *lookup(const uint8_t *packet, QUICFiveTuple endpoint); + +private: + // FIXME Use another map impl. that has good support for concurrent access + Map _connections; + // Map _cids; +}; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index d7c88896f48..f2b03cb47a6 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -26,8 +26,8 @@ #include "QUICGlobals.h" #include "QUICTransportParameters.h" #include "QUICConnection.h" +#include "QUICHandshake.h" #include "QUICDebugNames.h" -#include "../P_QUICNetVConnection.h" static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; static constexpr char tag[] = "quic_handshake"; From 4e7658ba62614bc982362820a06c69f7d0675862 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 30 Jan 2018 12:27:27 +0900 Subject: [PATCH 0361/1313] [QUIC Client] Load params from records.config --- cmd/traffic_quic/traffic_quic.cc | 5 +++++ iocore/net/QUICNetVConnection.cc | 7 +++++-- iocore/net/quic/QUICConfig.cc | 2 ++ iocore/net/quic/QUICConfig.h | 13 +++++++------ mgmt/RecordsConfig.cc | 10 +++++++++- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index f153e8f244b..5e483491d7c 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -26,6 +26,8 @@ #include "ts/I_Layout.h" #include "ts/I_Version.h" +#include "RecordsConfig.h" + #include "diags.h" #include "quic_client.h" @@ -65,6 +67,9 @@ main(int argc, const char **argv) init_diags(debug_tags, nullptr); RecProcessInit(RECM_STAND_ALONE); + LibRecordsConfigInit(); + + Debug("quic_client", "Load configs from %s", RecConfigReadConfigDir().c_str()); Thread *main_thread = new EThread; main_thread->set_specific(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 7af225527d7..3967513b74c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -70,8 +70,11 @@ QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, this->_packet_handler = packet_handler; this->_original_quic_connection_id = original_cid; this->_quic_connection_id.randomize(); - this->_ctable = ctable; - this->_ctable->insert(this->_quic_connection_id, this); + // PacketHandler for out going connection doesn't have connection table + if (ctable) { + this->_ctable = ctable; + this->_ctable->insert(this->_quic_connection_id, this); + } QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(this->_original_quic_connection_id), static_cast(this->_quic_connection_id)); } diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 61e74111ead..a3ff6eccff6 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -35,6 +35,8 @@ QUICConfigParams::initialize() { REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_in, "proxy.config.quic.no_activity_timeout_in"); REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_out, "proxy.config.quic.no_activity_timeout_out"); + REC_EstablishStaticConfigInt32U(this->_initial_max_data, "proxy.config.quic.initial_max_data"); + REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data, "proxy.config.quic.initial_max_stream_data"); REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); } diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index c4525a1a6e3..0371774f096 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -41,16 +41,17 @@ class QUICConfigParams : public ConfigInfo uint32_t server_id() const; private: - // FIXME Fill appropriate values - uint32_t _no_activity_timeout_in = 30; - uint32_t _no_activity_timeout_out = 30; - uint32_t _initial_max_data = 131072; - uint32_t _initial_max_stream_data = 2048; + // FIXME Fill appropriate default values in RecordsConfig.cc + uint32_t _no_activity_timeout_in = 0; + uint32_t _no_activity_timeout_out = 0; + uint32_t _initial_max_data = 0; + uint32_t _initial_max_stream_data = 0; + uint32_t _server_id = 0; + uint32_t _initial_max_stream_id_bidi_in = 100; uint32_t _initial_max_stream_id_bidi_out = 101; uint32_t _initial_max_stream_id_uni_in = 102; uint32_t _initial_max_stream_id_uni_out = 103; - uint32_t _server_id = 0; }; class QUICConfig diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 11a062a12bf..8cf3feed40f 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -201,7 +201,7 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.diags.debug.tags", RECD_STRING, "http|dns", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , - {RECT_CONFIG, "proxy.config.diags.debug.client_ip", RECD_STRING, NULL, RECU_DYNAMIC, RR_NULL, RECC_NULL, NULL, RECA_NULL} + {RECT_CONFIG, "proxy.config.diags.debug.client_ip", RECD_STRING, NULL, RECU_DYNAMIC, RR_NULL, RECC_NULL, NULL, RECA_NULL} , {RECT_CONFIG, "proxy.config.diags.action.enabled", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , @@ -1316,6 +1316,14 @@ static const RecordElement RecordsConfig[] = //############ {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_in", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_out", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_data", RECD_INT, "131072", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data", RECD_INT, "2048", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.server_id", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , //# Add LOCAL Records Here {RECT_LOCAL, "proxy.local.incoming_ip_to_bind", RECD_STRING, nullptr, RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL} From d313bbaee52e2d7b26c5d8fd8906a6836744fd7a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 30 Jan 2018 16:48:18 +0900 Subject: [PATCH 0362/1313] Print TLS Version on debug log --- iocore/net/QUICNetProcessor.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 2c109427a99..cfb3b9e3056 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -58,6 +58,11 @@ QUICNetProcessor::start(int, size_t stacksize) // QUICInitializeLibrary(); QUICConfig::startup(); +#ifdef TLS1_3_VERSION_DRAFT_TXT + // FIXME: remove this when TLS1_3_VERSION_DRAFT_TXT is removed + Debug("quic_ps", "%s", TLS1_3_VERSION_DRAFT_TXT); +#endif + // Acquire a QUICConfigParams instance *after* we start QUIC up. // QUICConfig::scoped_config params; @@ -68,6 +73,7 @@ QUICNetProcessor::start(int, size_t stacksize) this->_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(this->_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(this->_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_alpn_select_cb(this->_ssl_ctx, QUIC::ssl_select_next_protocol, nullptr); SSL_CTX_add_custom_ext(this->_ssl_ctx, QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID, SSL_EXT_TLS_ONLY | SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS | From 150c1e0cfb1ab8dcefa3a24c1085fb6b270eef4e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 30 Jan 2018 16:49:01 +0900 Subject: [PATCH 0363/1313] Fix tests for QUICCrypto --- iocore/net/quic/test/test_QUICCrypto.cc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/test/test_QUICCrypto.cc b/iocore/net/quic/test/test_QUICCrypto.cc index 0720b3312b6..aea6249ab4e 100644 --- a/iocore/net/quic/test/test_QUICCrypto.cc +++ b/iocore/net/quic/test/test_QUICCrypto.cc @@ -77,28 +77,31 @@ TEST_CASE("QUICCrypto Cleartext", "[quic]") // Client Hello uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t client_hello_len = 0; - CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0)); + CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); std::cout << "Client Hello" << std::endl; print_hex(client_hello, client_hello_len); // Server Hello uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t server_hello_len = 0; - CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len)); + CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == + SSL_ERROR_WANT_READ); std::cout << "Server Hello" << std::endl; print_hex(server_hello, server_hello_len); // Client Fnished uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t client_finished_len = 0; - CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len)); + CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == + SSL_ERROR_NONE); std::cout << "Client Finished" << std::endl; print_hex(client_finished, client_finished_len); // Post Handshake Msg uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t post_handshake_msg_len = 0; - CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, client_finished_len)); + CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, + client_finished_len) == SSL_ERROR_NONE); std::cout << "Post Handshake Message" << std::endl; print_hex(post_handshake_msg, post_handshake_msg_len); @@ -163,28 +166,31 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") // Client Hello uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t client_hello_len = 0; - CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0)); + CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); std::cout << "Client Hello" << std::endl; print_hex(client_hello, client_hello_len); // Server Hello uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t server_hello_len = 0; - CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len)); + CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == + SSL_ERROR_WANT_READ); std::cout << "Server Hello" << std::endl; print_hex(server_hello, server_hello_len); // Client Fnished uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t client_finished_len = 0; - CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len)); + CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == + SSL_ERROR_NONE); std::cout << "Client Finished" << std::endl; print_hex(client_finished, client_finished_len); // Post Handshake Msg uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t post_handshake_msg_len = 0; - CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, client_finished_len)); + CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, + client_finished_len) == SSL_ERROR_NONE); std::cout << "Post Handshake Message" << std::endl; print_hex(post_handshake_msg, post_handshake_msg_len); From 3f4fe3d4d28d33e6fc67df14d1600d89ff32e65f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 30 Jan 2018 16:54:00 +0900 Subject: [PATCH 0364/1313] Fix tests for QUICHandshake --- iocore/net/quic/test/test_QUICHandshake.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc index 71ea0e65347..5c2ad1511a0 100644 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -75,6 +75,7 @@ TEST_CASE("1-RTT handshake ", "[quic]") // ClientHello client->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream_io->transfer() > 0); + client->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); // ServerHello server->handleEvent(VC_EVENT_READ_READY, nullptr); @@ -82,6 +83,7 @@ TEST_CASE("1-RTT handshake ", "[quic]") client->handleEvent(VC_EVENT_READ_READY, nullptr); CHECK(stream_io->transfer() > 0); + client->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); // Finished server->handleEvent(VC_EVENT_READ_READY, nullptr); From 14dc16cc951b99f312f209e546ea4ce139c5b4f5 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 1 Feb 2018 10:13:41 +0900 Subject: [PATCH 0365/1313] Write debug logs in stderr when unit tests run --- iocore/net/quic/test/event_processor_main.cc | 10 +++++++--- iocore/net/quic/test/main.cc | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/test/event_processor_main.cc b/iocore/net/quic/test/event_processor_main.cc index fbfead65285..9132a389de2 100644 --- a/iocore/net/quic/test/event_processor_main.cc +++ b/iocore/net/quic/test/event_processor_main.cc @@ -27,9 +27,8 @@ #include "catch.hpp" #include "I_EventSystem.h" -#include "ts/ink_string.h" #include "ts/I_Layout.h" -#include "diags.i" +#include "ts/Diags.h" #define TEST_THREADS 1 @@ -39,8 +38,13 @@ struct EventProcessorListener : Catch::TestEventListenerBase { virtual void testRunStarting(Catch::TestRunInfo const &testRunInfo) override { + BaseLogFile *base_log_file = new BaseLogFile("stderr"); + diags = new Diags(testRunInfo.name.c_str(), "" /* tags */, "" /* actions */, base_log_file); + diags->activate_taglist("vv_quic|quic", DiagsTagType_Debug); + diags->config.enabled[DiagsTagType_Debug] = true; + diags->show_location = SHOW_LOCATION_DEBUG; + Layout::create(); - init_diags("", nullptr); RecProcessInit(RECM_STAND_ALONE); ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); diff --git a/iocore/net/quic/test/main.cc b/iocore/net/quic/test/main.cc index 213dec81c72..f611f5e04e1 100644 --- a/iocore/net/quic/test/main.cc +++ b/iocore/net/quic/test/main.cc @@ -25,3 +25,20 @@ // https://github.com/philsquared/Catch/blob/master/docs/slow-compiles.md #define CATCH_CONFIG_MAIN #include "catch.hpp" + +#include "ts/Diags.h" + +struct EventProcessorListener : Catch::TestEventListenerBase { + using TestEventListenerBase::TestEventListenerBase; // inherit constructor + + virtual void + testRunStarting(Catch::TestRunInfo const &testRunInfo) override + { + BaseLogFile *base_log_file = new BaseLogFile("stderr"); + diags = new Diags(testRunInfo.name.c_str(), "" /* tags */, "" /* actions */, base_log_file); + diags->activate_taglist("vv_quic|quic", DiagsTagType_Debug); + diags->config.enabled[DiagsTagType_Debug] = true; + diags->show_location = SHOW_LOCATION_DEBUG; + } +}; +CATCH_REGISTER_LISTENER(EventProcessorListener); From 7452dc21dfd2410ef30e510551134ed45d8fd09d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 1 Feb 2018 10:14:29 +0900 Subject: [PATCH 0366/1313] Cleanup test_QUICCrypto --- iocore/net/quic/test/test_QUICCrypto.cc | 63 +++++++------------------ 1 file changed, 17 insertions(+), 46 deletions(-) diff --git a/iocore/net/quic/test/test_QUICCrypto.cc b/iocore/net/quic/test/test_QUICCrypto.cc index aea6249ab4e..e0a2b725401 100644 --- a/iocore/net/quic/test/test_QUICCrypto.cc +++ b/iocore/net/quic/test/test_QUICCrypto.cc @@ -74,39 +74,8 @@ TEST_CASE("QUICCrypto Cleartext", "[quic]") SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); QUICCrypto *server = new QUICCryptoTls(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); - // Client Hello - uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t client_hello_len = 0; - CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); - std::cout << "Client Hello" << std::endl; - print_hex(client_hello, client_hello_len); - - // Server Hello - uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t server_hello_len = 0; - CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == - SSL_ERROR_WANT_READ); - std::cout << "Server Hello" << std::endl; - print_hex(server_hello, server_hello_len); - - // Client Fnished - uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t client_finished_len = 0; - CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == - SSL_ERROR_NONE); - std::cout << "Client Finished" << std::endl; - print_hex(client_finished, client_finished_len); - - // Post Handshake Msg - uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t post_handshake_msg_len = 0; - CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, - client_finished_len) == SSL_ERROR_NONE); - std::cout << "Post Handshake Message" << std::endl; - print_hex(post_handshake_msg, post_handshake_msg_len); - - CHECK(client->initialize_key_materials(0x8394c8f03e515708)); - CHECK(server->initialize_key_materials(0x8394c8f03e515708)); + CHECK(client->initialize_key_materials(0x8394c8f03e515700)); + CHECK(server->initialize_key_materials(0x8394c8f03e515700)); // encrypt - decrypt uint8_t original[] = { @@ -119,7 +88,7 @@ TEST_CASE("QUICCrypto Cleartext", "[quic]") uint8_t ad[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; // client (encrypt) - server (decrypt) - std::cout << "Original Text" << std::endl; + std::cout << "### Original Text" << std::endl; print_hex(original, sizeof(original)); uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead @@ -127,14 +96,14 @@ TEST_CASE("QUICCrypto Cleartext", "[quic]") CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), QUICKeyPhase::CLEARTEXT)); - std::cout << "Encrypted Text" << std::endl; + std::cout << "### Encrypted Text" << std::endl; print_hex(cipher, cipher_len); uint8_t plain[128] = {0}; size_t plain_len = 0; CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::CLEARTEXT)); - std::cout << "Decrypted Text" << std::endl; + std::cout << "### Decrypted Text" << std::endl; print_hex(plain, plain_len); CHECK(sizeof(original) == (plain_len)); @@ -163,11 +132,14 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); QUICCrypto *server = new QUICCryptoTls(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + CHECK(client->initialize_key_materials(0x8394c8f03e515708)); + CHECK(server->initialize_key_materials(0x8394c8f03e515708)); + // Client Hello uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t client_hello_len = 0; CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); - std::cout << "Client Hello" << std::endl; + std::cout << "### Client Hello" << std::endl; print_hex(client_hello, client_hello_len); // Server Hello @@ -175,7 +147,7 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") size_t server_hello_len = 0; CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == SSL_ERROR_WANT_READ); - std::cout << "Server Hello" << std::endl; + std::cout << "### Server Hello" << std::endl; print_hex(server_hello, server_hello_len); // Client Fnished @@ -183,20 +155,19 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") size_t client_finished_len = 0; CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == SSL_ERROR_NONE); - std::cout << "Client Finished" << std::endl; + std::cout << "### Client Finished" << std::endl; print_hex(client_finished, client_finished_len); + CHECK(client->update_key_materials()); + // Post Handshake Msg uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t post_handshake_msg_len = 0; CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, client_finished_len) == SSL_ERROR_NONE); - std::cout << "Post Handshake Message" << std::endl; + std::cout << "### Post Handshake Message" << std::endl; print_hex(post_handshake_msg, post_handshake_msg_len); - CHECK(client->initialize_key_materials(0x8394c8f03e515708)); - CHECK(server->initialize_key_materials(0x8394c8f03e515708)); - CHECK(client->update_key_materials()); CHECK(server->update_key_materials()); // encrypt - decrypt @@ -210,7 +181,7 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") uint8_t ad[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; // client (encrypt) - server (decrypt) - std::cout << "Original Text" << std::endl; + std::cout << "### Original Text" << std::endl; print_hex(original, sizeof(original)); uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead @@ -218,14 +189,14 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); - std::cout << "Encrypted Text" << std::endl; + std::cout << "### Encrypted Text" << std::endl; print_hex(cipher, cipher_len); uint8_t plain[128] = {0}; size_t plain_len = 0; CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); - std::cout << "Decrypted Text" << std::endl; + std::cout << "### Decrypted Text" << std::endl; print_hex(plain, plain_len); CHECK(sizeof(original) == (plain_len)); From 56bf2d39e085a183a751c1e50a654b6c48108643 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 1 Feb 2018 11:01:19 +0900 Subject: [PATCH 0367/1313] Add QUICCrypto::is_key_derived() --- iocore/net/quic/Mock.h | 6 ++++++ iocore/net/quic/QUICCrypto.cc | 6 ++++++ iocore/net/quic/QUICCrypto.h | 1 + iocore/net/quic/QUICCryptoTls.h | 1 + iocore/net/quic/QUICHandshake.cc | 3 +-- iocore/net/quic/QUICPacket.cc | 6 +++--- 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 5a5aa76e705..50697e3fb5c 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -476,6 +476,12 @@ class MockQUICCrypto : public QUICCrypto return true; } + bool + is_key_derived() const override + { + return true; + } + int initialize_key_materials(QUICConnectionId cid) override { diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index fcba8ca970d..a09c5d68325 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -159,6 +159,12 @@ QUICCryptoTls::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, cons bool QUICCryptoTls::is_handshake_finished() const +{ + return SSL_is_init_finished(this->_ssl); +} + +bool +QUICCryptoTls::is_key_derived() const { return (this->_client_pp->key_phase() != QUICKeyPhase::CLEARTEXT && this->_server_pp->key_phase() != QUICKeyPhase::CLEARTEXT); } diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICCrypto.h index 6e9f048527b..6ab434f62fd 100644 --- a/iocore/net/quic/QUICCrypto.h +++ b/iocore/net/quic/QUICCrypto.h @@ -50,6 +50,7 @@ class QUICCrypto virtual int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) = 0; virtual bool is_handshake_finished() const = 0; + virtual bool is_key_derived() const = 0; virtual int initialize_key_materials(QUICConnectionId cid) = 0; virtual int update_key_materials() = 0; virtual bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, diff --git a/iocore/net/quic/QUICCryptoTls.h b/iocore/net/quic/QUICCryptoTls.h index 884992a0fde..c42ec26fd7e 100644 --- a/iocore/net/quic/QUICCryptoTls.h +++ b/iocore/net/quic/QUICCryptoTls.h @@ -44,6 +44,7 @@ class QUICCryptoTls : public QUICCrypto int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override; bool is_handshake_finished() const override; + bool is_key_derived() const override; int initialize_key_materials(QUICConnectionId cid) override; int update_key_materials() override; bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 78009c9be5f..3f48a6d53db 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -328,8 +328,7 @@ QUICHandshake::state_key_exchange(int event, Event *data) QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE: { - QUICCryptoTls *crypto_tls = dynamic_cast(this->_crypto); - if (crypto_tls && SSL_is_init_finished(crypto_tls->ssl_handle())) { + if (this->_crypto->is_handshake_finished()) { int res = this->_complete_handshake(); if (!res) { this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 10c53475156..114eb6eabcb 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -672,7 +672,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ result = QUICPacketCreationResult::SUCCESS; break; case QUICPacketType::PROTECTED: - if (this->_crypto->is_handshake_finished()) { + if (this->_crypto->is_key_derived()) { if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { result = QUICPacketCreationResult::SUCCESS; @@ -684,7 +684,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ } break; case QUICPacketType::INITIAL: - if (!this->_crypto->is_handshake_finished()) { + if (!this->_crypto->is_key_derived()) { if (QUICTypeUtil::is_supported_version(header->version())) { if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { @@ -700,7 +700,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ } break; case QUICPacketType::HANDSHAKE: - if (!this->_crypto->is_handshake_finished()) { + if (!this->_crypto->is_key_derived()) { if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { result = QUICPacketCreationResult::SUCCESS; From a0beeed6a9a7cf52e737191b75728c81ed05beae Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 2 Feb 2018 08:13:46 +0800 Subject: [PATCH 0368/1313] initialize `opts` to create udp connection with correct local addr --- cmd/traffic_quic/quic_client.cc | 6 ++++-- iocore/net/QUICNetProcessor.cc | 24 +++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc index ec53e04be57..c42410cbd8d 100644 --- a/cmd/traffic_quic/quic_client.cc +++ b/cmd/traffic_quic/quic_client.cc @@ -49,8 +49,10 @@ QUICClient::start() for (struct addrinfo *info = this->_remote_addr_info; info != nullptr; info = info->ai_next) { NetVCOptions opt; - opt.ip_proto = NetVCOptions::USE_UDP; - opt.ip_family = info->ai_family; + opt.ip_proto = NetVCOptions::USE_UDP; + opt.ip_family = info->ai_family; + opt.socket_recv_bufsize = 1048576; + opt.socket_send_bufsize = 1048576; SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index cfb3b9e3056..8dc335f6653 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -120,18 +120,21 @@ Action * QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, NetVCOptions *opt) { Debug("quic_ps", "connect to server"); - EThread *t = cont->mutex->thread_holding; ink_assert(t); + QUICNetVConnection *vc = static_cast(this->allocate_vc(t)); - sockaddr local_addr; - int local_addr_len; - local_addr.sa_family = remote_addr->sa_family; + if (opt) { + vc->options = *opt; + } else { + opt = &vc->options; + } int fd; Action *status; - bool result = udpNet.CreateUDPSocket(&fd, remote_addr, &local_addr, &local_addr_len, &status, 1048576, 1048576); + bool result = udpNet.CreateUDPSocket(&fd, remote_addr, &status, *opt); if (!result) { + vc->free(t); return status; } @@ -140,7 +143,9 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne Debug("quic_ps", "con=%p fd=%d", con, fd); QUICPacketHandlerOut *packet_handler = new QUICPacketHandlerOut(); - con->setBinding(reinterpret_cast(&local_addr)); + if (opt->local_ip.isValid()) { + con->setBinding(opt->local_ip, opt->local_port); + } con->bindToThread(packet_handler); PollCont *pc = get_UDPPollCont(con->ethread); @@ -155,16 +160,9 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne // Setup QUICNetVConnection QUICConnectionId cid; cid.randomize(); - QUICNetVConnection *vc = static_cast(this->allocate_vc(t)); vc->init(cid, con, packet_handler); packet_handler->init(vc); - if (opt) { - vc->options = *opt; - } else { - opt = &vc->options; - } - // Connection ID will be changed vc->id = net_next_connection_number(); vc->set_context(NET_VCONNECTION_OUT); From d9a5b22299a8d9dbcc1d7231ae806ab692669166 Mon Sep 17 00:00:00 2001 From: Oknet Xu Date: Sun, 28 Jan 2018 17:55:16 +0800 Subject: [PATCH 0369/1313] Add QUICPollCont --- iocore/net/I_UDPPacket.h | 6 ++ iocore/net/P_QUICNet.h | 60 ++++++++++++++ iocore/net/P_QUICNetProcessor.h | 2 + iocore/net/P_QUICNetVConnection.h | 2 + iocore/net/P_UnixNet.h | 24 +++++- iocore/net/QUICNet.cc | 125 ++++++++++++++++++++++++++++++ iocore/net/QUICNetVConnection.cc | 50 +++++++++++- iocore/net/QUICPacketHandler.cc | 23 +++--- 8 files changed, 274 insertions(+), 18 deletions(-) create mode 100644 iocore/net/P_QUICNet.h create mode 100644 iocore/net/QUICNet.cc diff --git a/iocore/net/I_UDPPacket.h b/iocore/net/I_UDPPacket.h index df899ff389d..271a2502e1a 100644 --- a/iocore/net/I_UDPPacket.h +++ b/iocore/net/I_UDPPacket.h @@ -62,6 +62,12 @@ class UDPPacket IpEndpoint to; // what address to send to int from_size; + typedef union udppacket_data { + void *ptr; + uint32_t u32; + uint64_t u64; + } udppacket_data_t; + udppacket_data_t data; LINK(UDPPacket, link); }; diff --git a/iocore/net/P_QUICNet.h b/iocore/net/P_QUICNet.h new file mode 100644 index 00000000000..fba0e96694d --- /dev/null +++ b/iocore/net/P_QUICNet.h @@ -0,0 +1,60 @@ +/** @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. + */ + +#ifndef __P_QUICNET_H__ +#define __P_QUICNET_H__ + +#include + +#include "ts/ink_platform.h" + +#include "P_Net.h" +class NetHandler; +typedef int (NetHandler::*NetContHandler)(int, void *); + +struct QUICPollCont : public Continuation { + NetHandler *net_handler; + PollDescriptor *pollDescriptor; + + QUICPollCont(Ptr &m); + QUICPollCont(Ptr &m, NetHandler *nh); + ~QUICPollCont(); + int pollEvent(int, Event *); + +public: + // Atomic Queue to save incoming packets + ASLL(UDPPacketInternal, alink) inQueue; + + // Internal Queue to save Long Header Packet + Que(UDPPacket, link) longInQueue; + // Internal Queue to save Short Header Packet + Que(UDPPacket, link) shortInQueue; +}; + +static inline QUICPollCont * +get_QUICPollCont(EThread *t) +{ + return (QUICPollCont *)ETHREAD_GET_PTR(t, quic_NetProcessor.quicPollCont_offset); +} + +#endif diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h index 29720609a00..2b7eb10f48c 100644 --- a/iocore/net/P_QUICNetProcessor.h +++ b/iocore/net/P_QUICNetProcessor.h @@ -67,6 +67,8 @@ class QUICNetProcessor : public UnixNetProcessor Action *main_accept(Continuation *cont, SOCKET fd, AcceptOptions const &opt) override; + off_t quicPollCont_offset; + private: QUICNetProcessor(const QUICNetProcessor &); QUICNetProcessor &operator=(const QUICNetProcessor &); diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index a82c37bd297..4e999d95d8c 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -302,4 +302,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICStatelessResetToken _reset_token; }; +typedef int (QUICNetVConnection::*QUICNetVConnHandler)(int, void *); + extern ClassAllocator quicNetVCAllocator; diff --git a/iocore/net/P_UnixNet.h b/iocore/net/P_UnixNet.h index 6c69bd35957..6b9ad5f72c5 100644 --- a/iocore/net/P_UnixNet.h +++ b/iocore/net/P_UnixNet.h @@ -575,8 +575,15 @@ EventIO::start(EventLoop l, NetAccept *vc, int events) TS_INLINE int EventIO::start(EventLoop l, UnixNetVConnection *vc, int events) { + int r; type = EVENTIO_READWRITE_VC; - return start(l, vc->con.fd, (Continuation *)vc, events); + r = start(l, vc->con.fd, (Continuation *)vc, events); + if (r < 0 && vc->options.ip_proto == NetVCOptions::USE_UDP) { + // Hack for QUICNetVC + return 0; + } else { + return r; + } } TS_INLINE int EventIO::start(EventLoop l, UnixUDPConnection *vc, int events) @@ -611,6 +618,12 @@ EventIO::start(EventLoop l, int afd, Continuation *c, int e) data.c = c; fd = afd; event_loop = l; + // Hack for QUICNetVC: + // quicnetvc->con.fd == NO_FD + // quicnetvc->options.ip_proto == NetVCOptions::USE_UDP + if (afd == NO_FD) { + return -1; + } #if TS_USE_EPOLL struct epoll_event ev; memset(&ev, 0, sizeof(ev)); @@ -643,6 +656,9 @@ EventIO::start(EventLoop l, int afd, Continuation *c, int e) TS_INLINE int EventIO::modify(int e) { + if (fd == NO_FD) { + return 0; + } ink_assert(event_loop); #if TS_USE_EPOLL && !defined(USE_EDGE_TRIGGER) struct epoll_event ev; @@ -722,6 +738,9 @@ EventIO::modify(int e) TS_INLINE int EventIO::refresh(int e) { + if (fd == NO_FD) { + return 0; + } ink_assert(event_loop); #if TS_USE_KQUEUE && defined(USE_EDGE_TRIGGER) e = e & events; @@ -763,6 +782,9 @@ EventIO::refresh(int e) TS_INLINE int EventIO::stop() { + if (fd == NO_FD) { + return 0; + } if (event_loop) { int retval = 0; #if TS_USE_EPOLL diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc new file mode 100644 index 00000000000..c40121fb70d --- /dev/null +++ b/iocore/net/QUICNet.cc @@ -0,0 +1,125 @@ +/** @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 "P_Net.h" + +QUICPollCont::QUICPollCont(Ptr &m) + : Continuation(m.get()), net_handler(nullptr) +{ + SET_HANDLER(&PollCont::pollEvent); +} + +QUICPollCont::QUICPollCont(Ptr &m, NetHandler *nh) + : Continuation(m.get()), net_handler(nh) +{ + SET_HANDLER(&QUICPollCont::pollEvent); +} + +QUICPollCont::~QUICPollCont() +{ +} + +// +// QUICPollCont continuation which traverse the inQueue(ASLL) +// and create new QUICNetVC for Initial Packet, +// and push the triggered QUICNetVC into enable list. +// +int +QUICPollCont::pollEvent(int, Event *) +{ + UnixUDPConnection *uc; + QUICPacketHandler *ph; + QUICNetVConnection *vc; + QUICConnectionId cid; + uint8_t *buf; + uint8_t ptype; + UDPPacket *packet_r; + UDPPacketInternal *p = nullptr; + NetHandler *nh = get_NetHandler(t); + + // Process the ASLL + SList(UDPPacketInternal, alink) aq(inQueue.popall()); + Queue result; + while ((p = aq.pop())) { + result.push(p); + } + + while ((p = result.pop())) { + uc = static_cast(p->getConnection()); + ph = static_cast(uc->continuation); + vc = static_cast(p->data.ptr); + buf = (uint8_t *)p->getIOBlockChain()->buf(); + cid = QUICPacket::connection_id(buf) + if (buf[0] & 0x80) { // Long Header Packet with Connection ID, has a valid type value. + ptype = buf[0] & 0x7f; + if (ptype == QUICPacketType::INITIAL) { // Initial Packet + vc->read.triggered = 1; + vc->push_packet(p); + // reschedule the vc and callback vc->acceptEvent + this_ethread()->schedule_imm(vc); + } elseif (ptype == QUICPacketType::ZERO_RTT_PROTECTED) { // 0-RTT Packet + // TODO: + } elseif (ptype == QUICPacketType::HANDSHAKE) { // Handshake Packet + if (vc) { + vc->read.triggered = 1; + vc->push_packet(p); + } else { + longInQueue.push(p); + } + } else { + ink_assert(!"not reached!"); + } + } elseif (buf[0] & 0x40) { // Short Header Packet with Connection ID, has a valid type value. + if (vc) { + vc->read.triggered = 1; + vc->push_packet(p); + } else { + shortInQueue.push(p); + } + } else { + ink_assert(!"not reached!"); + } + + // Push QUICNetVC into nethandler's enabled list + if (vc != nullptr) { + int isin = ink_atomic_swap(&vc->read.in_enabled_list, 1); + if (!isin) { + nh->read_enable_list.push(vc); + } + } + } + + return EVENT_CONT; +} + +void +initialize_thread_for_quic_net(EThread *thread) +{ + NetHandler *nh = get_NetHandler(thread); + QUICPollCont *quicpc = get_QUICPollCont(thread); + + new ((ink_dummy_for_new *)quicpc) QUICPollCont(thread->mutex, nh); + + thread->schedule_every(quicpc, -9); +} + diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3967513b74c..b0088c851f1 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -63,7 +63,7 @@ void QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, QUICPacketHandler *packet_handler, QUICConnectionTable *ctable) { - SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_pre_handshake); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::acceptEvent); this->_packet_transmitter_mutex = new_ProxyMutex(); this->_frame_transmitter_mutex = new_ProxyMutex(); this->_udp_con = udp_con; @@ -93,6 +93,51 @@ QUICNetVConnection::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader return nullptr; } +int +QUICNetVConnection::acceptEvent(int event, Event *e) +{ + EThread *t = (e == nullptr) ? this_ethread() : e->ethread; + NetHandler *h = get_NetHandler(t); + + MUTEX_TRY_LOCK(lock, h->mutex, t); + if (!lock.is_locked()) { + if (event == EVENT_NONE) { + t->schedule_in(this, HRTIME_MSECONDS(net_retry_delay)); + return EVENT_DONE; + } else { + e->schedule_in(HRTIME_MSECONDS(net_retry_delay)); + return EVENT_CONT; + } + } + + thread = t; + + // Send this NetVC to NetHandler and start to polling read & write event. + if (h->startIO(this) < 0) { + free(t); + return EVENT_DONE; + } + + // Handshake callback handler. + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_pre_handshake); + + // Send this netvc to InactivityCop. + nh->startCop(this); + + if (inactivity_timeout_in) { + set_inactivity_timeout(inactivity_timeout_in); + } else { + set_inactivity_timeout(0); + } + + if (active_timeout_in) { + set_active_timeout(active_timeout_in); + } + + action_.continuation->handleEvent(NET_EVENT_ACCEPT, this); + return EVENT_DONE; +} + int QUICNetVConnection::startEvent(int /*event ATS_UNUSED */, Event *e) { @@ -589,8 +634,7 @@ QUICNetVConnection::get_udp_con() void QUICNetVConnection::net_read_io(NetHandler *nh, EThread *lthread) { - ink_assert(false); - + this->handleEvent(QUIC_EVENT_PACKET_READ_READY, nullptr); return; } diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index e60b442afcf..8ac76c0ea9c 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -124,6 +124,7 @@ QUICPacketHandlerIn::init_accept(EThread *t = nullptr) void QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) { + EThread *eth; IOBufferBlock *block = udp_packet->getIOBlockChain(); if (is_debug_tag_set("quic_sec")) { @@ -158,6 +159,8 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) return; } + eth = eventProcessor.assign_thread(ET_NET); + // Create a new NetVConnection QUICConnectionId original_cid = this->_read_connection_id(block); QUICNetVConnection *vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); @@ -165,29 +168,21 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) vc->id = net_next_connection_number(); vc->con.move(con); vc->submit_time = Thread::get_hrtime(); - vc->mutex = this->mutex; + vc->thread = eth; + vc->mutex = new_ProxyMutex(); vc->action_ = *this->action_; vc->set_is_transparent(this->opt.f_inbound_transparent); vc->set_context(NET_VCONNECTION_IN); - vc->read.triggered = 1; - vc->start(this->_ssl_ctx); vc->options.ip_proto = NetVCOptions::USE_UDP; vc->options.ip_family = udp_packet->from.sa.sa_family; - this->action_->continuation->handleEvent(NET_EVENT_ACCEPT, vc); qc = vc; } - if (qc->is_closed()) { - this->_ctable.erase(qc->connection_id(), qc); - // FIXME QUICNetVConnection is NOT freed to prevent crashes. #2674 - // QUICNetVConnections are going to be freed by QUICNetHandler - // vc->free(vc->thread); - } else { - qc->handle_received_packet(udp_packet); - // FIXME This cast is temporal. It'll be removed when we introduce QUICNetHandler. - eventProcessor.schedule_imm(static_cast(qc), ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr); - } + // Push the packet into QUICPollCont + udp_packet->data.ptr = vc; + get_QUICPollCont(eth)->inQueue.push(udp_packet); + } // TODO: Should be called via eventProcessor? From c85f903a11d12b4e1505bd68603f2c157805c4a8 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sun, 28 Jan 2018 21:22:41 +0800 Subject: [PATCH 0370/1313] complete pollcont --- cmd/traffic_quic/quic_client.h | 1 + cmd/traffic_quic/traffic_quic.cc | 2 + iocore/net/I_UDPPacket.h | 2 +- iocore/net/Makefile.am | 2 + iocore/net/P_Net.h | 1 + iocore/net/P_QUICNet.h | 6 ++ iocore/net/P_QUICNetProcessor.h | 1 + iocore/net/P_QUICNetVConnection.h | 3 + iocore/net/QUICNet.cc | 141 ++++++++++++++++++------------ iocore/net/QUICNetProcessor.cc | 10 +++ iocore/net/QUICNetVConnection.cc | 1 + iocore/net/QUICPacketHandler.cc | 14 ++- proxy/Main.cc | 4 + 13 files changed, 129 insertions(+), 59 deletions(-) diff --git a/cmd/traffic_quic/quic_client.h b/cmd/traffic_quic/quic_client.h index 05d0c47581d..575d7a18c41 100644 --- a/cmd/traffic_quic/quic_client.h +++ b/cmd/traffic_quic/quic_client.h @@ -23,6 +23,7 @@ #pragma once +#include "P_Net.h" #include "I_EventSystem.h" #include "I_NetVConnection.h" #include "P_QUICNetProcessor.h" diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index 5e483491d7c..19ea9c2f533 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -78,6 +78,8 @@ main(int argc, const char **argv) SSLInitializeLibrary(); SSLConfig::startup(); + quic_NetProcessor.init(); + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); eventProcessor.start(THREADS); udpNet.start(1, stacksize); diff --git a/iocore/net/I_UDPPacket.h b/iocore/net/I_UDPPacket.h index 271a2502e1a..fd047e56b97 100644 --- a/iocore/net/I_UDPPacket.h +++ b/iocore/net/I_UDPPacket.h @@ -63,7 +63,7 @@ class UDPPacket int from_size; typedef union udppacket_data { - void *ptr; + void *ptr; uint32_t u32; uint64_t u64; } udppacket_data_t; diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am index b044e80c34e..f32cc13678a 100644 --- a/iocore/net/Makefile.am +++ b/iocore/net/Makefile.am @@ -162,10 +162,12 @@ libinknet_a_SOURCES = \ if ENABLE_QUIC libinknet_a_SOURCES += \ P_QUICPacketHandler.h \ + P_QUICNet.h \ P_QUICNetProcessor.h \ P_QUICNetVConnection.h \ P_QUICNextProtocolAccept.h \ QUICPacketHandler.cc \ + QUICNet.cc \ QUICNetProcessor.cc \ QUICNetVConnection.cc \ QUICNextProtocolAccept.cc diff --git a/iocore/net/P_Net.h b/iocore/net/P_Net.h index 0a7a502a3ea..38504ee0c0a 100644 --- a/iocore/net/P_Net.h +++ b/iocore/net/P_Net.h @@ -113,6 +113,7 @@ extern RecRawStatBlock *net_rsb; #include "P_QUICNetVConnection.h" #include "P_QUICNetProcessor.h" #include "P_QUICPacketHandler.h" +#include "P_QUICNet.h" #endif // #include "P_QUICCertLookup.h" diff --git a/iocore/net/P_QUICNet.h b/iocore/net/P_QUICNet.h index fba0e96694d..7231207885e 100644 --- a/iocore/net/P_QUICNet.h +++ b/iocore/net/P_QUICNet.h @@ -32,6 +32,8 @@ class NetHandler; typedef int (NetHandler::*NetContHandler)(int, void *); +void initialize_thread_for_quic_net(EThread *thread); + struct QUICPollCont : public Continuation { NetHandler *net_handler; PollDescriptor *pollDescriptor; @@ -49,6 +51,10 @@ struct QUICPollCont : public Continuation { Que(UDPPacket, link) longInQueue; // Internal Queue to save Short Header Packet Que(UDPPacket, link) shortInQueue; + +private: + void _process_short_header_packet(UDPPacketInternal *p, NetHandler *nh); + void _process_long_header_packet(UDPPacketInternal *p, NetHandler *nh); }; static inline QUICPollCont * diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h index 2b7eb10f48c..c9d6c2adfb5 100644 --- a/iocore/net/P_QUICNetProcessor.h +++ b/iocore/net/P_QUICNetProcessor.h @@ -56,6 +56,7 @@ class QUICNetProcessor : public UnixNetProcessor QUICNetProcessor(); virtual ~QUICNetProcessor(); + void init() override; virtual int start(int, size_t stacksize) override; void cleanup(); // TODO: refactoring NetProcessor::connect_re and UnixNetProcessor::connect_re_internal diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 4e999d95d8c..8f4d7e56656 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -145,6 +145,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICNetVConnection() {} void init(QUICConnectionId original_cid, UDPConnection *, QUICPacketHandler *, QUICConnectionTable *ctable = nullptr); + // accept new conn_id + int acceptEvent(int event, Event *e); + // UnixNetVConnection void reenable(VIO *vio) override; VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override; diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index c40121fb70d..3e730afcf18 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -23,14 +23,12 @@ #include "P_Net.h" -QUICPollCont::QUICPollCont(Ptr &m) - : Continuation(m.get()), net_handler(nullptr) +QUICPollCont::QUICPollCont(Ptr &m) : Continuation(m.get()), net_handler(nullptr) { - SET_HANDLER(&PollCont::pollEvent); + SET_HANDLER(&QUICPollCont::pollEvent); } -QUICPollCont::QUICPollCont(Ptr &m, NetHandler *nh) - : Continuation(m.get()), net_handler(nh) +QUICPollCont::QUICPollCont(Ptr &m, NetHandler *nh) : Continuation(m.get()), net_handler(nh) { SET_HANDLER(&QUICPollCont::pollEvent); } @@ -39,6 +37,83 @@ QUICPollCont::~QUICPollCont() { } +void +QUICPollCont::_process_long_header_packet(UDPPacketInternal *p, NetHandler *nh) +{ + QUICNetVConnection *vc; + QUICPacketType ptype; + uint8_t *buf; + + // FIXME: VC is nullptr ? + vc = static_cast(p->data.ptr); + buf = (uint8_t *)p->getIOBlockChain()->buf(); + if (!QUICTypeUtil::has_connection_id(reinterpret_cast(buf))) { + // TODO: Some packets may not have connection id + p->free(); + return; + } + + ptype = static_cast(buf[0] & 0x7f); + switch (ptype) { + case QUICPacketType::INITIAL: + vc->read.triggered = 1; + vc->handle_received_packet(p); + this->mutex->thread_holding->schedule_imm(vc); + return; + case QUICPacketType::ZERO_RTT_PROTECTED: + // TODO:: do something ? + // break; + case QUICPacketType::HANDSHAKE: + default: + // Just Pass Through + if (vc) { + vc->read.triggered = 1; + vc->handle_received_packet(p); + } else { + longInQueue.push(p); + } + + // Push QUICNetVC into nethandler's enabled list + if (vc != nullptr) { + int isin = ink_atomic_swap(&vc->read.in_enabled_list, 1); + if (!isin) { + nh->read_enable_list.push(vc); + } + } + break; + } +} + +void +QUICPollCont::_process_short_header_packet(UDPPacketInternal *p, NetHandler *nh) +{ + QUICNetVConnection *vc; + uint8_t *buf; + + vc = static_cast(p->data.ptr); + buf = (uint8_t *)p->getIOBlockChain()->buf(); + if (!QUICTypeUtil::has_connection_id(reinterpret_cast(buf))) { + // TODO: Some packets may not have connection id + p->free(); + return; + } + + if (vc) { + vc->read.triggered = 1; + vc->handle_received_packet(p); + } else { + shortInQueue.push(p); + } + + // Push QUICNetVC into nethandler's enabled list + if (vc != nullptr) { + int isin = ink_atomic_swap(&vc->read.in_enabled_list, 1); + if (!isin) { + nh->read_enable_list.push(vc); + } + } +} + // // QUICPollCont continuation which traverse the inQueue(ASLL) // and create new QUICNetVC for Initial Packet, @@ -47,15 +122,10 @@ QUICPollCont::~QUICPollCont() int QUICPollCont::pollEvent(int, Event *) { - UnixUDPConnection *uc; - QUICPacketHandler *ph; - QUICNetVConnection *vc; - QUICConnectionId cid; + ink_assert(this->mutex->thread_holding == this_thread()); uint8_t *buf; - uint8_t ptype; - UDPPacket *packet_r; UDPPacketInternal *p = nullptr; - NetHandler *nh = get_NetHandler(t); + NetHandler *nh = get_NetHandler(this->mutex->thread_holding); // Process the ASLL SList(UDPPacketInternal, alink) aq(inQueue.popall()); @@ -65,50 +135,14 @@ QUICPollCont::pollEvent(int, Event *) } while ((p = result.pop())) { - uc = static_cast(p->getConnection()); - ph = static_cast(uc->continuation); - vc = static_cast(p->data.ptr); buf = (uint8_t *)p->getIOBlockChain()->buf(); - cid = QUICPacket::connection_id(buf) - if (buf[0] & 0x80) { // Long Header Packet with Connection ID, has a valid type value. - ptype = buf[0] & 0x7f; - if (ptype == QUICPacketType::INITIAL) { // Initial Packet - vc->read.triggered = 1; - vc->push_packet(p); - // reschedule the vc and callback vc->acceptEvent - this_ethread()->schedule_imm(vc); - } elseif (ptype == QUICPacketType::ZERO_RTT_PROTECTED) { // 0-RTT Packet - // TODO: - } elseif (ptype == QUICPacketType::HANDSHAKE) { // Handshake Packet - if (vc) { - vc->read.triggered = 1; - vc->push_packet(p); - } else { - longInQueue.push(p); - } - } else { - ink_assert(!"not reached!"); - } - } elseif (buf[0] & 0x40) { // Short Header Packet with Connection ID, has a valid type value. - if (vc) { - vc->read.triggered = 1; - vc->push_packet(p); - } else { - shortInQueue.push(p); - } - } else { - ink_assert(!"not reached!"); - } - - // Push QUICNetVC into nethandler's enabled list - if (vc != nullptr) { - int isin = ink_atomic_swap(&vc->read.in_enabled_list, 1); - if (!isin) { - nh->read_enable_list.push(vc); - } + if (QUICTypeUtil::has_long_header(buf)) { // Long Header Packet with Connection ID, has a valid type value. + this->_process_long_header_packet(p, nh); + } else { // Short Header Packet with Connection ID, has a valid type value. + this->_process_short_header_packet(p, nh); } } - + return EVENT_CONT; } @@ -122,4 +156,3 @@ initialize_thread_for_quic_net(EThread *thread) thread->schedule_every(quicpc, -9); } - diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 8dc335f6653..da372c62550 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -50,6 +50,16 @@ QUICNetProcessor::cleanup() SSL_CTX_free(this->_ssl_ctx); } +void +QUICNetProcessor::init() +{ + // first we allocate a QUICPollCont. + this->quicPollCont_offset = eventProcessor.allocate(sizeof(QUICPollCont)); + + // schedule event + eventProcessor.schedule_spawn(&initialize_thread_for_quic_net, ET_NET); +} + int QUICNetProcessor::start(int, size_t stacksize) { diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b0088c851f1..e71c109161f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -117,6 +117,7 @@ QUICNetVConnection::acceptEvent(int event, Event *e) free(t); return EVENT_DONE; } + this->read.enabled = 1; // Handshake callback handler. SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_pre_handshake); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 8ac76c0ea9c..a09c3941f5e 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -125,7 +125,8 @@ void QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) { EThread *eth; - IOBufferBlock *block = udp_packet->getIOBlockChain(); + QUICNetVConnection *vc = nullptr; + IOBufferBlock *block = udp_packet->getIOBlockChain(); if (is_debug_tag_set("quic_sec")) { ip_port_text_buffer ipb; @@ -163,7 +164,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // Create a new NetVConnection QUICConnectionId original_cid = this->_read_connection_id(block); - QUICNetVConnection *vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); + vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); vc->init(original_cid, udp_packet->getConnection(), this, &this->_ctable); vc->id = net_next_connection_number(); vc->con.move(con); @@ -173,16 +174,21 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) vc->action_ = *this->action_; vc->set_is_transparent(this->opt.f_inbound_transparent); vc->set_context(NET_VCONNECTION_IN); + vc->read.triggered = 1; + vc->start(this->_ssl_ctx); vc->options.ip_proto = NetVCOptions::USE_UDP; vc->options.ip_family = udp_packet->from.sa.sa_family; qc = vc; + } else { + vc = static_cast(qc); + eth = vc->thread; } // Push the packet into QUICPollCont udp_packet->data.ptr = vc; - get_QUICPollCont(eth)->inQueue.push(udp_packet); - + // should we use dynamic_cast ?? + get_QUICPollCont(eth)->inQueue.push(static_cast(udp_packet)); } // TODO: Should be called via eventProcessor? diff --git a/proxy/Main.cc b/proxy/Main.cc index 5e36c0e16df..5614444ba0f 100644 --- a/proxy/Main.cc +++ b/proxy/Main.cc @@ -1800,6 +1800,10 @@ main(int /* argc ATS_UNUSED */, const char **argv) // Do the inits for NetProcessors that use ET_NET threads. MUST be before starting those threads. netProcessor.init(); init_HttpProxyServer(); +#if TS_USE_QUIC == 1 + // OK, pushing a spawn scheduling here + quic_NetProcessor.init(); +#endif // !! ET_NET threads start here !! // This means any spawn scheduling must be done before this point. From 5c219098a1ebc2d66b3e627b532079ccb3e976f1 Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 31 Jan 2018 14:35:20 +0800 Subject: [PATCH 0371/1313] [QUIC Client] fix the quic client --- cmd/traffic_quic/traffic_quic.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index 19ea9c2f533..9749ce19900 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -74,10 +74,12 @@ main(int argc, const char **argv) Thread *main_thread = new EThread; main_thread->set_specific(); net_config_poll_timeout = 10; + ink_net_init(makeModuleVersion(1, 0, PRIVATE_MODULE_HEADER)); SSLInitializeLibrary(); SSLConfig::startup(); + netProcessor.init(); quic_NetProcessor.init(); ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); @@ -120,7 +122,7 @@ DNSConnection::trigger() void StatPagesManager::register_http(char const *, Action *(*)(Continuation *, HTTPHdr *)) { - ink_assert(false); + // ink_assert(false); } #include "ParentSelection.h" From 04dfc12f56e034d041789a3d2ebbbdf069a10f44 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 3 Feb 2018 08:59:27 +0800 Subject: [PATCH 0372/1313] Add syscall into EventIO for qvc to avoid system call --- iocore/net/P_UDPNet.h | 2 ++ iocore/net/P_UnixNet.h | 33 ++++++++++++++++---------------- iocore/net/QUICNet.cc | 2 +- iocore/net/QUICNetProcessor.cc | 2 ++ iocore/net/QUICNetVConnection.cc | 1 + iocore/net/UnixUDPNet.cc | 4 ++-- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/iocore/net/P_UDPNet.h b/iocore/net/P_UDPNet.h index 599b6af6068..52de3b8b0ef 100644 --- a/iocore/net/P_UDPNet.h +++ b/iocore/net/P_UDPNet.h @@ -59,6 +59,8 @@ extern UDPNetProcessorInternal udpNetInternal; #define SLOT_TIME HRTIME_MSECONDS(SLOT_TIME_MSEC) #define N_SLOTS 2048 +constexpr int UDP_PERIOD = 9; + class PacketQueue { public: diff --git a/iocore/net/P_UnixNet.h b/iocore/net/P_UnixNet.h index 6b9ad5f72c5..ab45b663017 100644 --- a/iocore/net/P_UnixNet.h +++ b/iocore/net/P_UnixNet.h @@ -83,6 +83,7 @@ struct EventIO { int events = 0; #endif EventLoop event_loop = nullptr; + bool syscall = true; int type = 0; union { Continuation *c; @@ -575,15 +576,8 @@ EventIO::start(EventLoop l, NetAccept *vc, int events) TS_INLINE int EventIO::start(EventLoop l, UnixNetVConnection *vc, int events) { - int r; type = EVENTIO_READWRITE_VC; - r = start(l, vc->con.fd, (Continuation *)vc, events); - if (r < 0 && vc->options.ip_proto == NetVCOptions::USE_UDP) { - // Hack for QUICNetVC - return 0; - } else { - return r; - } + return start(l, vc->con.fd, (Continuation *)vc, events); } TS_INLINE int EventIO::start(EventLoop l, UnixUDPConnection *vc, int events) @@ -594,6 +588,10 @@ EventIO::start(EventLoop l, UnixUDPConnection *vc, int events) TS_INLINE int EventIO::close() { + if (!this->syscall) { + return 0; + } + stop(); switch (type) { default: @@ -615,15 +613,13 @@ EventIO::close() TS_INLINE int EventIO::start(EventLoop l, int afd, Continuation *c, int e) { + if (!this->syscall) { + return 0; + } + data.c = c; fd = afd; event_loop = l; - // Hack for QUICNetVC: - // quicnetvc->con.fd == NO_FD - // quicnetvc->options.ip_proto == NetVCOptions::USE_UDP - if (afd == NO_FD) { - return -1; - } #if TS_USE_EPOLL struct epoll_event ev; memset(&ev, 0, sizeof(ev)); @@ -656,9 +652,10 @@ EventIO::start(EventLoop l, int afd, Continuation *c, int e) TS_INLINE int EventIO::modify(int e) { - if (fd == NO_FD) { + if (!this->syscall) { return 0; } + ink_assert(event_loop); #if TS_USE_EPOLL && !defined(USE_EDGE_TRIGGER) struct epoll_event ev; @@ -738,9 +735,10 @@ EventIO::modify(int e) TS_INLINE int EventIO::refresh(int e) { - if (fd == NO_FD) { + if (!this->syscall) { return 0; } + ink_assert(event_loop); #if TS_USE_KQUEUE && defined(USE_EDGE_TRIGGER) e = e & events; @@ -782,9 +780,10 @@ EventIO::refresh(int e) TS_INLINE int EventIO::stop() { - if (fd == NO_FD) { + if (!this->syscall) { return 0; } + if (event_loop) { int retval = 0; #if TS_USE_EPOLL diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index 3e730afcf18..33763b8a98a 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -154,5 +154,5 @@ initialize_thread_for_quic_net(EThread *thread) new ((ink_dummy_for_new *)quicpc) QUICPollCont(thread->mutex, nh); - thread->schedule_every(quicpc, -9); + thread->schedule_every(quicpc, -UDP_PERIOD); } diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index da372c62550..1064bd79bdc 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -181,6 +181,8 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne vc->mutex = cont->mutex; vc->action_ = cont; + SET_CONTINUATION_HANDLER(vc, &QUICNetVConnection::state_pre_handshake); + vc->start(this->_ssl_ctx); vc->connectUp(t, NO_FD); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e71c109161f..ee1d16f2482 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -70,6 +70,7 @@ QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, this->_packet_handler = packet_handler; this->_original_quic_connection_id = original_cid; this->_quic_connection_id.randomize(); + this->ep.syscall = false; // PacketHandler for out going connection doesn't have connection table if (ctable) { this->_ctable = ctable; diff --git a/iocore/net/UnixUDPNet.cc b/iocore/net/UnixUDPNet.cc index 5a682062463..d5004fe8861 100644 --- a/iocore/net/UnixUDPNet.cc +++ b/iocore/net/UnixUDPNet.cc @@ -86,7 +86,7 @@ initialize_thread_for_udp_net(EThread *thread) REC_ReadConfigInt32(g_udp_numSendRetries, "proxy.config.udp.send_retries"); g_udp_numSendRetries = g_udp_numSendRetries < 0 ? 0 : g_udp_numSendRetries; - thread->schedule_every(get_UDPPollCont(thread), -9); + thread->schedule_every(get_UDPPollCont(thread), -UDP_PERIOD); thread->schedule_imm(get_UDPNetHandler(thread)); } @@ -923,7 +923,7 @@ UDPNetHandler::startNetEvent(int event, Event *e) (void)event; SET_HANDLER((UDPNetContHandler)&UDPNetHandler::mainNetEvent); trigger_event = e; - e->schedule_every(-HRTIME_MSECONDS(9)); + e->schedule_every(-HRTIME_MSECONDS(UDP_PERIOD)); return EVENT_CONT; } From 35abc38261e68d3d3ba7ffc9730f43f071387ac7 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 3 Feb 2018 11:04:14 +0800 Subject: [PATCH 0373/1313] connect_re processed by nethandler --- cmd/traffic_quic/quic_client.cc | 1 + cmd/traffic_quic/traffic_quic.cc | 2 +- iocore/net/QUICNetProcessor.cc | 24 ++++++++++++++++++++-- iocore/net/QUICNetVConnection.cc | 34 ++++++++++++++++++++++++++++++-- iocore/net/UnixUDPNet.cc | 2 +- 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc index c42410cbd8d..d6a7176c508 100644 --- a/cmd/traffic_quic/quic_client.cc +++ b/cmd/traffic_quic/quic_client.cc @@ -51,6 +51,7 @@ QUICClient::start() NetVCOptions opt; opt.ip_proto = NetVCOptions::USE_UDP; opt.ip_family = info->ai_family; + opt.etype = ET_NET; opt.socket_recv_bufsize = 1048576; opt.socket_send_bufsize = 1048576; diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index 9749ce19900..c46e80f4d49 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -88,7 +88,7 @@ main(int argc, const char **argv) quic_NetProcessor.start(-1, stacksize); QUICClient client(addr, port); - eventProcessor.schedule_in(&client, 1, ET_UDP); + eventProcessor.schedule_in(&client, 1, ET_NET); this_thread()->execute(); } diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 1064bd79bdc..979af876c56 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -123,6 +123,7 @@ QUICNetProcessor::allocate_vc(EThread *t) } } + vc->ep.syscall = false; return vc; } @@ -181,10 +182,29 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne vc->mutex = cont->mutex; vc->action_ = cont; - SET_CONTINUATION_HANDLER(vc, &QUICNetVConnection::state_pre_handshake); + SET_CONTINUATION_HANDLER(vc, &QUICNetVConnection::startEvent); vc->start(this->_ssl_ctx); - vc->connectUp(t, NO_FD); + + if (t->is_event_type(opt->etype)) { + MUTEX_TRY_LOCK(lock, cont->mutex, t); + if (lock.is_locked()) { + MUTEX_TRY_LOCK(lock2, get_NetHandler(t)->mutex, t); + if (lock2.is_locked()) { + vc->connectUp(t, NO_FD); + return ACTION_RESULT_DONE; + } + } + } + + // Try to stay on the current thread if it is the right type + if (t->is_event_type(opt->etype)) { + t->schedule_imm(vc); + } else { // Otherwise, pass along to another thread of the right type + eventProcessor.schedule_imm(vc, opt->etype); + } + + // vc->connectUp(t, NO_FD); return ACTION_RESULT_DONE; } diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ee1d16f2482..dc8823f3ff7 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -70,7 +70,6 @@ QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, this->_packet_handler = packet_handler; this->_original_quic_connection_id = original_cid; this->_quic_connection_id.randomize(); - this->ep.syscall = false; // PacketHandler for out going connection doesn't have connection table if (ctable) { this->_ctable = ctable; @@ -118,6 +117,8 @@ QUICNetVConnection::acceptEvent(int event, Event *e) free(t); return EVENT_DONE; } + + // FIXME: complete do_io_xxxx instead this->read.enabled = 1; // Handshake callback handler. @@ -141,8 +142,21 @@ QUICNetVConnection::acceptEvent(int event, Event *e) } int -QUICNetVConnection::startEvent(int /*event ATS_UNUSED */, Event *e) +QUICNetVConnection::startEvent(int event, Event *e) { + ink_assert(event == EVENT_IMMEDIATE); + MUTEX_TRY_LOCK(lock, get_NetHandler(e->ethread)->mutex, e->ethread); + if (!lock.is_locked()) { + e->schedule_in(HRTIME_MSECONDS(net_retry_delay)); + return EVENT_CONT; + } + + if (!action_.cancelled) { + this->connectUp(e->ethread, NO_FD); + } else { + this->free(e->ethread); + } + return EVENT_DONE; } @@ -220,6 +234,17 @@ QUICNetVConnection::reenable(VIO *vio) int QUICNetVConnection::connectUp(EThread *t, int fd) { + int res = 0; + NetHandler *nh = get_NetHandler(t); + this->thread = this_ethread(); + ink_assert(nh->mutex->thread_holding == this->thread); + + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_pre_handshake); + + if ((res = nh->startIO(this)) < 0) { + // FIXME: startIO only return 0 now! what should we do if it failed ? + } + // create stream for handshake QUICErrorUPtr error = this->_stream_manager->create_stream(STREAM_ID_FOR_HANDSHAKE); if (error->cls != QUICErrorClass::NONE) { @@ -228,6 +253,11 @@ QUICNetVConnection::connectUp(EThread *t, int fd) return CONNECT_FAILURE; } + nh->startCop(this); + + // FIXME: complete do_io_xxxx instead + this->read.enabled = 1; + // start QUIC handshake this->_handshake_handler->handleEvent(VC_EVENT_WRITE_READY, nullptr); diff --git a/iocore/net/UnixUDPNet.cc b/iocore/net/UnixUDPNet.cc index d5004fe8861..e3891b8ff4b 100644 --- a/iocore/net/UnixUDPNet.cc +++ b/iocore/net/UnixUDPNet.cc @@ -86,7 +86,7 @@ initialize_thread_for_udp_net(EThread *thread) REC_ReadConfigInt32(g_udp_numSendRetries, "proxy.config.udp.send_retries"); g_udp_numSendRetries = g_udp_numSendRetries < 0 ? 0 : g_udp_numSendRetries; - thread->schedule_every(get_UDPPollCont(thread), -UDP_PERIOD); + thread->schedule_every(get_UDPPollCont(thread), -HRTIME_MSECONDS(UDP_PERIOD)); thread->schedule_imm(get_UDPNetHandler(thread)); } From ba5ff998aef294820ea59c1d4363c5d9a423a56f Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 6 Feb 2018 14:01:38 +0800 Subject: [PATCH 0374/1313] add QUICPollEvent to packet UDPPacket and QVC --- iocore/net/I_UDPPacket.h | 6 ---- iocore/net/P_QUICNet.h | 28 ++++++++++++++---- iocore/net/QUICNet.cc | 52 ++++++++++++++++++++------------- iocore/net/QUICPacketHandler.cc | 12 +++++--- 4 files changed, 62 insertions(+), 36 deletions(-) diff --git a/iocore/net/I_UDPPacket.h b/iocore/net/I_UDPPacket.h index fd047e56b97..df899ff389d 100644 --- a/iocore/net/I_UDPPacket.h +++ b/iocore/net/I_UDPPacket.h @@ -62,12 +62,6 @@ class UDPPacket IpEndpoint to; // what address to send to int from_size; - typedef union udppacket_data { - void *ptr; - uint32_t u32; - uint64_t u64; - } udppacket_data_t; - udppacket_data_t data; LINK(UDPPacket, link); }; diff --git a/iocore/net/P_QUICNet.h b/iocore/net/P_QUICNet.h index 7231207885e..297ddbe3521 100644 --- a/iocore/net/P_QUICNet.h +++ b/iocore/net/P_QUICNet.h @@ -29,11 +29,28 @@ #include "ts/ink_platform.h" #include "P_Net.h" + class NetHandler; typedef int (NetHandler::*NetContHandler)(int, void *); void initialize_thread_for_quic_net(EThread *thread); +struct QUICPollEvent { + typedef union data_t { + void *ptr; + uint32_t u32; + uint64_t u64; + } data_t; + + void free(); + + data_t data; + UDPPacketInternal *packet; + + SLINK(QUICPollEvent, alink); + LINK(QUICPollEvent, link); +}; + struct QUICPollCont : public Continuation { NetHandler *net_handler; PollDescriptor *pollDescriptor; @@ -45,16 +62,16 @@ struct QUICPollCont : public Continuation { public: // Atomic Queue to save incoming packets - ASLL(UDPPacketInternal, alink) inQueue; + ASLL(QUICPollEvent, alink) inQueue; // Internal Queue to save Long Header Packet - Que(UDPPacket, link) longInQueue; + Que(UDPPacketInternal, link) longInQueue; // Internal Queue to save Short Header Packet - Que(UDPPacket, link) shortInQueue; + Que(UDPPacketInternal, link) shortInQueue; private: - void _process_short_header_packet(UDPPacketInternal *p, NetHandler *nh); - void _process_long_header_packet(UDPPacketInternal *p, NetHandler *nh); + void _process_short_header_packet(QUICPollEvent *e, NetHandler *nh); + void _process_long_header_packet(QUICPollEvent *e, NetHandler *nh); }; static inline QUICPollCont * @@ -63,4 +80,5 @@ get_QUICPollCont(EThread *t) return (QUICPollCont *)ETHREAD_GET_PTR(t, quic_NetProcessor.quicPollCont_offset); } +extern ClassAllocator quicPollEventAllocator; #endif diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index 33763b8a98a..68c3bee11c1 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -23,6 +23,14 @@ #include "P_Net.h" +ClassAllocator quicPollEventAllocator("quicPollEvent"); + +void +QUICPollEvent::free() +{ + quicPollEventAllocator.free(this); +} + QUICPollCont::QUICPollCont(Ptr &m) : Continuation(m.get()), net_handler(nullptr) { SET_HANDLER(&QUICPollCont::pollEvent); @@ -38,15 +46,16 @@ QUICPollCont::~QUICPollCont() } void -QUICPollCont::_process_long_header_packet(UDPPacketInternal *p, NetHandler *nh) +QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) { - QUICNetVConnection *vc; - QUICPacketType ptype; uint8_t *buf; - + QUICPacketType ptype; + UDPPacketInternal *p = e->packet; // FIXME: VC is nullptr ? - vc = static_cast(p->data.ptr); - buf = (uint8_t *)p->getIOBlockChain()->buf(); + QUICNetVConnection *vc = static_cast(e->data.ptr); + buf = (uint8_t *)p->getIOBlockChain()->buf(); + + e->free(); if (!QUICTypeUtil::has_connection_id(reinterpret_cast(buf))) { // TODO: Some packets may not have connection id p->free(); @@ -85,13 +94,14 @@ QUICPollCont::_process_long_header_packet(UDPPacketInternal *p, NetHandler *nh) } void -QUICPollCont::_process_short_header_packet(UDPPacketInternal *p, NetHandler *nh) +QUICPollCont::_process_short_header_packet(QUICPollEvent *e, NetHandler *nh) { - QUICNetVConnection *vc; uint8_t *buf; + UDPPacketInternal *p = e->packet; + QUICNetVConnection *vc = static_cast(e->data.ptr); + buf = (uint8_t *)p->getIOBlockChain()->buf(); - vc = static_cast(p->data.ptr); - buf = (uint8_t *)p->getIOBlockChain()->buf(); + e->free(); if (!QUICTypeUtil::has_connection_id(reinterpret_cast(buf))) { // TODO: Some packets may not have connection id p->free(); @@ -124,22 +134,22 @@ QUICPollCont::pollEvent(int, Event *) { ink_assert(this->mutex->thread_holding == this_thread()); uint8_t *buf; - UDPPacketInternal *p = nullptr; - NetHandler *nh = get_NetHandler(this->mutex->thread_holding); + QUICPollEvent *e; + NetHandler *nh = get_NetHandler(this->mutex->thread_holding); // Process the ASLL - SList(UDPPacketInternal, alink) aq(inQueue.popall()); - Queue result; - while ((p = aq.pop())) { - result.push(p); + SList(QUICPollEvent, link) aq(inQueue.popall()); + Queue result; + while ((e = aq.pop())) { + result.push(e); } - while ((p = result.pop())) { - buf = (uint8_t *)p->getIOBlockChain()->buf(); + while ((e = result.pop())) { + buf = (uint8_t *)e->packet->getIOBlockChain()->buf(); if (QUICTypeUtil::has_long_header(buf)) { // Long Header Packet with Connection ID, has a valid type value. - this->_process_long_header_packet(p, nh); + this->_process_long_header_packet(e, nh); } else { // Short Header Packet with Connection ID, has a valid type value. - this->_process_short_header_packet(p, nh); + this->_process_short_header_packet(e, nh); } } @@ -154,5 +164,5 @@ initialize_thread_for_quic_net(EThread *thread) new ((ink_dummy_for_new *)quicpc) QUICPollCont(thread->mutex, nh); - thread->schedule_every(quicpc, -UDP_PERIOD); + thread->schedule_every(quicpc, -HRTIME_MSECONDS(UDP_PERIOD)); } diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index a09c3941f5e..5eb99662816 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -124,7 +124,8 @@ QUICPacketHandlerIn::init_accept(EThread *t = nullptr) void QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) { - EThread *eth; + EThread *eth = nullptr; + QUICPollEvent *qe = nullptr; QUICNetVConnection *vc = nullptr; IOBufferBlock *block = udp_packet->getIOBlockChain(); @@ -185,10 +186,13 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) eth = vc->thread; } - // Push the packet into QUICPollCont - udp_packet->data.ptr = vc; + qe = quicPollEventAllocator.alloc(); + + qe->data.ptr = vc; // should we use dynamic_cast ?? - get_QUICPollCont(eth)->inQueue.push(static_cast(udp_packet)); + qe->packet = static_cast(udp_packet); + // Push the packet into QUICPollCont + get_QUICPollCont(eth)->inQueue.push(qe); } // TODO: Should be called via eventProcessor? From 0b78de52fc25f8d4cd79348f894d6104faa26d17 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 13 Feb 2018 18:46:37 +0800 Subject: [PATCH 0375/1313] introduce init function to initailize QUICPollEvent --- iocore/net/P_QUICNet.h | 17 +++++------------ iocore/net/QUICNet.cc | 31 ++++++++++++++++--------------- iocore/net/QUICPacketHandler.cc | 4 +--- 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/iocore/net/P_QUICNet.h b/iocore/net/P_QUICNet.h index 297ddbe3521..a150cb774e7 100644 --- a/iocore/net/P_QUICNet.h +++ b/iocore/net/P_QUICNet.h @@ -36,16 +36,10 @@ typedef int (NetHandler::*NetContHandler)(int, void *); void initialize_thread_for_quic_net(EThread *thread); struct QUICPollEvent { - typedef union data_t { - void *ptr; - uint32_t u32; - uint64_t u64; - } data_t; - - void free(); - - data_t data; + QUICConnection *con; UDPPacketInternal *packet; + void init(QUICConnection *con, UDPPacketInternal *packet); + void free(); SLINK(QUICPollEvent, alink); LINK(QUICPollEvent, link); @@ -64,10 +58,9 @@ struct QUICPollCont : public Continuation { // Atomic Queue to save incoming packets ASLL(QUICPollEvent, alink) inQueue; +private: // Internal Queue to save Long Header Packet - Que(UDPPacketInternal, link) longInQueue; - // Internal Queue to save Short Header Packet - Que(UDPPacketInternal, link) shortInQueue; + Que(UDPPacketInternal, link) _longInQueue; private: void _process_short_header_packet(QUICPollEvent *e, NetHandler *nh); diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index 68c3bee11c1..ecbc546a774 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -25,6 +25,13 @@ ClassAllocator quicPollEventAllocator("quicPollEvent"); +void +QUICPollEvent::init(QUICConnection *con, UDPPacketInternal *packet) +{ + this->con = con; + this->packet = packet; +} + void QUICPollEvent::free() { @@ -52,7 +59,7 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) QUICPacketType ptype; UDPPacketInternal *p = e->packet; // FIXME: VC is nullptr ? - QUICNetVConnection *vc = static_cast(e->data.ptr); + QUICNetVConnection *vc = static_cast(e->con); buf = (uint8_t *)p->getIOBlockChain()->buf(); e->free(); @@ -79,7 +86,7 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) vc->read.triggered = 1; vc->handle_received_packet(p); } else { - longInQueue.push(p); + this->_longInQueue.push(p); } // Push QUICNetVC into nethandler's enabled list @@ -98,7 +105,7 @@ QUICPollCont::_process_short_header_packet(QUICPollEvent *e, NetHandler *nh) { uint8_t *buf; UDPPacketInternal *p = e->packet; - QUICNetVConnection *vc = static_cast(e->data.ptr); + QUICNetVConnection *vc = static_cast(e->con); buf = (uint8_t *)p->getIOBlockChain()->buf(); e->free(); @@ -108,19 +115,13 @@ QUICPollCont::_process_short_header_packet(QUICPollEvent *e, NetHandler *nh) return; } - if (vc) { - vc->read.triggered = 1; - vc->handle_received_packet(p); - } else { - shortInQueue.push(p); - } + vc->read.triggered = 1; + vc->handle_received_packet(p); // Push QUICNetVC into nethandler's enabled list - if (vc != nullptr) { - int isin = ink_atomic_swap(&vc->read.in_enabled_list, 1); - if (!isin) { - nh->read_enable_list.push(vc); - } + int isin = ink_atomic_swap(&vc->read.in_enabled_list, 1); + if (!isin) { + nh->read_enable_list.push(vc); } } @@ -138,7 +139,7 @@ QUICPollCont::pollEvent(int, Event *) NetHandler *nh = get_NetHandler(this->mutex->thread_holding); // Process the ASLL - SList(QUICPollEvent, link) aq(inQueue.popall()); + SList(QUICPollEvent, alink) aq(inQueue.popall()); Queue result; while ((e = aq.pop())) { result.push(e); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 5eb99662816..6bf37e778ab 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -188,9 +188,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) qe = quicPollEventAllocator.alloc(); - qe->data.ptr = vc; - // should we use dynamic_cast ?? - qe->packet = static_cast(udp_packet); + qe->init(qc, static_cast(udp_packet)); // Push the packet into QUICPollCont get_QUICPollCont(eth)->inQueue.push(qe); } From fa5100060a43d95ec8df9c3b67ca9fa3388b141a Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 13 Feb 2018 18:14:13 +0800 Subject: [PATCH 0376/1313] drain all of udp packets and make sure PollCont run before UDPNetHandler --- iocore/net/P_UDPNet.h | 3 +- iocore/net/QUICNetVConnection.cc | 111 ++++++++++++++++++------------- iocore/net/UnixUDPNet.cc | 2 +- 3 files changed, 67 insertions(+), 49 deletions(-) diff --git a/iocore/net/P_UDPNet.h b/iocore/net/P_UDPNet.h index 52de3b8b0ef..ae584abaa76 100644 --- a/iocore/net/P_UDPNet.h +++ b/iocore/net/P_UDPNet.h @@ -59,7 +59,8 @@ extern UDPNetProcessorInternal udpNetInternal; #define SLOT_TIME HRTIME_MSECONDS(SLOT_TIME_MSEC) #define N_SLOTS 2048 -constexpr int UDP_PERIOD = 9; +constexpr int UDP_PERIOD = 9; +constexpr int UDP_NH_PERIOD = UDP_PERIOD + 1; class PacketQueue { diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index dc8823f3ff7..372403ecb2a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -513,14 +513,24 @@ QUICNetVConnection::state_handshake(int event, Event *data) switch (event) { case QUIC_EVENT_PACKET_READ_READY: { QUICPacketCreationResult result; - QUICPacketUPtr packet = this->_dequeue_recv_packet(result); - if (result == QUICPacketCreationResult::NOT_READY) { - error = QUICErrorUPtr(new QUICNoError()); - } else if (result == QUICPacketCreationResult::FAILED) { - error = QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); - } else { - error = this->_state_handshake_process_packet(std::move(packet)); - } + do { + QUICPacketUPtr packet = this->_dequeue_recv_packet(result); + if (result == QUICPacketCreationResult::NOT_READY) { + error = QUICErrorUPtr(new QUICNoError()); + } else if (result == QUICPacketCreationResult::FAILED) { + error = QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); + } else if (result == QUICPacketCreationResult::SUCCESS) { + error = this->_state_handshake_process_packet(std::move(packet)); + } + + // if we complete handshake, switch to establish state + if (this->_handshake_handler && this->_handshake_handler->is_completed()) { + this->_switch_to_established_state(); + return this->handleEvent(event, data); + } + + } while (error->cls == QUICErrorClass::NONE && + (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::IGNORED)); break; } case QUIC_EVENT_PACKET_WRITE_READY: { @@ -801,47 +811,51 @@ QUICNetVConnection::_state_common_receive_packet() QUICPacketCreationResult result; // Receive a QUIC packet - QUICPacketUPtr p = this->_dequeue_recv_packet(result); - if (result == QUICPacketCreationResult::FAILED) { - return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); - } else if (result == QUICPacketCreationResult::NOT_READY) { - return QUICErrorUPtr(new QUICNoError()); - } else if (result == QUICPacketCreationResult::IGNORED) { - return QUICErrorUPtr(new QUICNoError()); - } - - net_activity(this, this_ethread()); + do { + QUICPacketUPtr p = this->_dequeue_recv_packet(result); + if (result == QUICPacketCreationResult::FAILED) { + return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); + } else if (result == QUICPacketCreationResult::NOT_READY) { + return QUICErrorUPtr(new QUICNoError()); + } else if (result == QUICPacketCreationResult::IGNORED) { + continue; + } - // Check connection migration - if (this->_handshake_handler->is_completed() && p->connection_id() != this->_quic_connection_id) { - for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { - AltConnectionInfo &info = this->_alt_quic_connection_ids[i]; - if (info.id == p->connection_id()) { - // Migrate connection - // TODO Address Validation - // TODO Adjust expected packet number with a gap computed based on info.seq_num - // TODO Unregister the old connection id (Should we wait for a while?) - this->_quic_connection_id = info.id; - this->_reset_token = info.token; - this->_update_alt_connection_ids(i); - break; + net_activity(this, this_ethread()); + + // Check connection migration + if (this->_handshake_handler->is_completed() && p->connection_id() != this->_quic_connection_id) { + for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { + AltConnectionInfo &info = this->_alt_quic_connection_ids[i]; + if (info.id == p->connection_id()) { + // Migrate connection + // TODO Address Validation + // TODO Adjust expected packet number with a gap computed based on info.seq_num + // TODO Unregister the old connection id (Should we wait for a while?) + this->_quic_connection_id = info.id; + this->_reset_token = info.token; + this->_update_alt_connection_ids(i); + break; + } } + ink_assert(p->connection_id() == this->_quic_connection_id); } - ink_assert(p->connection_id() == this->_quic_connection_id); - } - // Process the packet - switch (p->type()) { - case QUICPacketType::PROTECTED: - error = this->_state_connection_established_process_packet(std::move(p)); - break; - case QUICPacketType::HANDSHAKE: - // FIXME Just ignore for now but it has to be acked (GitHub#2609) - break; - default: - error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); - break; - } + // Process the packet + switch (p->type()) { + case QUICPacketType::PROTECTED: + error = this->_state_connection_established_process_packet(std::move(p)); + break; + case QUICPacketType::HANDSHAKE: + // FIXME Just ignore for now but it has to be acked (GitHub#2609) + break; + default: + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); + break; + } + + } while (error->cls == QUICErrorClass::NONE && + (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::IGNORED)); return error; } @@ -1147,8 +1161,11 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) quic_packet = this->_packet_factory.create(std::move(pkt), written, this->largest_received_packet_number(), result); if (result == QUICPacketCreationResult::NOT_READY) { QUICConDebug("Not ready to decrypt the packet"); - // Retry later - this->_packet_recv_queue.enqueue(udp_packet); + // FIXME: unordered packet should be buffered and retried + udp_packet->free(); + if (this->_packet_recv_queue.size > 0) { + result = QUICPacketCreationResult::SUCCESS; + } this_ethread()->schedule_in_local(this, HRTIME_MSECONDS(10), QUIC_EVENT_PACKET_READ_READY); } else if (result == QUICPacketCreationResult::IGNORED) { QUICConDebug("Ignore to decrypt the packet"); diff --git a/iocore/net/UnixUDPNet.cc b/iocore/net/UnixUDPNet.cc index e3891b8ff4b..9c75b4e4cf0 100644 --- a/iocore/net/UnixUDPNet.cc +++ b/iocore/net/UnixUDPNet.cc @@ -923,7 +923,7 @@ UDPNetHandler::startNetEvent(int event, Event *e) (void)event; SET_HANDLER((UDPNetContHandler)&UDPNetHandler::mainNetEvent); trigger_event = e; - e->schedule_every(-HRTIME_MSECONDS(UDP_PERIOD)); + e->schedule_every(-HRTIME_MSECONDS(UDP_NH_PERIOD)); return EVENT_CONT; } From e4c3201015f3d62438b7843ad20072b12219f200 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 16 Feb 2018 09:25:05 +0800 Subject: [PATCH 0377/1313] QUIC: Push closed conn into closed queue --- iocore/net/Makefile.am | 2 + iocore/net/P_QUICClosedConCollector.h | 39 ++++++++++++++++ iocore/net/P_QUICNetVConnection.h | 8 ++++ iocore/net/P_QUICPacketHandler.h | 8 ++++ iocore/net/QUICClosedConCollector.cc | 62 ++++++++++++++++++++++++++ iocore/net/QUICNetVConnection.cc | 13 ++++++ iocore/net/QUICPacketHandler.cc | 33 ++++++++++++++ iocore/net/quic/QUICConnectionTable.cc | 7 ++- 8 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 iocore/net/P_QUICClosedConCollector.h create mode 100644 iocore/net/QUICClosedConCollector.cc diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am index f32cc13678a..0bc196f4507 100644 --- a/iocore/net/Makefile.am +++ b/iocore/net/Makefile.am @@ -161,11 +161,13 @@ libinknet_a_SOURCES = \ if ENABLE_QUIC libinknet_a_SOURCES += \ + P_QUICClosedConCollector.h \ P_QUICPacketHandler.h \ P_QUICNet.h \ P_QUICNetProcessor.h \ P_QUICNetVConnection.h \ P_QUICNextProtocolAccept.h \ + QUICClosedConCollector.cc \ QUICPacketHandler.cc \ QUICNet.cc \ QUICNetProcessor.cc \ diff --git a/iocore/net/P_QUICClosedConCollector.h b/iocore/net/P_QUICClosedConCollector.h new file mode 100644 index 00000000000..4484e97e838 --- /dev/null +++ b/iocore/net/P_QUICClosedConCollector.h @@ -0,0 +1,39 @@ +/** @file + This file implements an I/O Processor for network I/O + @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. + */ + +#ifndef _QUIC_CLOSED_CON_COLLECTOR_H_ +#define _QUIC_CLOSED_CON_COLLECTOR_H_ + +#include "P_QUICNetVConnection.h" + +class QUICClosedConCollector : public Continuation +{ +public: + QUICClosedConCollector(); + + int mainEvent(int event, Event *e); + + ASLL(QUICNetVConnection, closed_alink) closedQueue; + +private: + Que(QUICNetVConnection, closed_link) _localClosedQueue; + + void _process_closed_connection(EThread *t); +}; + +#endif diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 8f4d7e56656..a7c7ca03ffd 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -164,6 +164,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection int state_connection_closed(int event, Event *data); void start(SSL_CTX *); void free(EThread *t) override; + void destroy(EThread *t); UDPConnection *get_udp_con(); virtual void net_read_io(NetHandler *nh, EThread *lthread) override; @@ -203,6 +204,13 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection std::vector interests() override; QUICErrorUPtr handle_frame(std::shared_ptr frame) override; + int in_closed_queue = 0; + + bool shouldDestroy(); + + LINK(QUICNetVConnection, closed_link); + SLINK(QUICNetVConnection, closed_alink); + private: class AltConnectionInfo { diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 84d43b84a11..70b3048adc2 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -29,18 +29,26 @@ #include "quic/QUICTypes.h" #include "quic/QUICConnectionTable.h" +class QUICClosedConCollector; class QUICNetVConnection; class QUICPacket; class QUICPacketHandler { public: + QUICPacketHandler(); + ~QUICPacketHandler(); + virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc) = 0; + virtual void close_conenction(QUICNetVConnection *conn); protected: static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu); static QUICConnectionId _read_connection_id(IOBufferBlock *block); + Event *_collector_event = nullptr; + QUICClosedConCollector *_closed_con_collector = nullptr; + virtual void _recv_packet(int event, UDPPacket *udpPacket) = 0; }; diff --git a/iocore/net/QUICClosedConCollector.cc b/iocore/net/QUICClosedConCollector.cc new file mode 100644 index 00000000000..19095fe4909 --- /dev/null +++ b/iocore/net/QUICClosedConCollector.cc @@ -0,0 +1,62 @@ +/** @file + This file implements an I/O Processor for network I/O + @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 "P_QUICClosedConCollector.h" + +QUICClosedConCollector::QUICClosedConCollector() +{ + SET_HANDLER(&QUICClosedConCollector::mainEvent); +} + +int +QUICClosedConCollector::mainEvent(int event, Event *e) +{ + EThread *t = this->mutex->thread_holding; + ink_assert(t == this_thread()); + + this->_process_closed_connection(t); + return 0; +} + +void +QUICClosedConCollector::_process_closed_connection(EThread *t) +{ + ink_release_assert(t != nullptr); + + QUICNetVConnection *qvc; + Que(QUICNetVConnection, closed_link) local_queue; + + while ((qvc = this->_localClosedQueue.pop())) { + if (qvc->shouldDestroy()) { + qvc->free(t); + } else { + local_queue.push(qvc); + } + } + + SList(QUICNetVConnection, closed_alink) aq(this->closedQueue.popall()); + while ((qvc = aq.pop())) { + if (qvc->shouldDestroy()) { + qvc->free(t); + } else { + local_queue.push(qvc); + } + } + + this->_localClosedQueue.append(local_queue); +} diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 372403ecb2a..8ea14610ed8 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -79,6 +79,13 @@ QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, static_cast(this->_quic_connection_id)); } +bool +QUICNetVConnection::shouldDestroy() +{ + // TODO: return this->refcount == 0; + return true; +} + VIO * QUICNetVConnection::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) { @@ -654,6 +661,12 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) // Shutdown loss detector this->_loss_detector->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); + if (this->nh) { + this->nh->stopCop(this); + this->nh->stopIO(this); + } + + this->_packet_handler->close_conenction(this); break; } case QUIC_EVENT_PACKET_WRITE_READY: { diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 6bf37e778ab..2f94cb809b4 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -22,6 +22,7 @@ #include "ts/ink_config.h" #include "P_Net.h" +#include "P_QUICClosedConCollector.h" #include "QUICConfig.h" #include "QUICPacket.h" #include "QUICDebugNames.h" @@ -30,6 +31,34 @@ // // QUICPacketHandler // +QUICPacketHandler::QUICPacketHandler() +{ + this->_closed_con_collector = new QUICClosedConCollector; + this->_closed_con_collector->mutex = new_ProxyMutex(); +} + +QUICPacketHandler::~QUICPacketHandler() +{ + if (this->_collector_event != nullptr) { + this->_collector_event->cancel(); + this->_collector_event = nullptr; + } + + if (this->_closed_con_collector != nullptr) { + delete this->_closed_con_collector; + this->_closed_con_collector = nullptr; + } +} + +void +QUICPacketHandler::close_conenction(QUICNetVConnection *conn) +{ + int isin = ink_atomic_swap(&conn->in_closed_queue, 1); + if (!isin) { + this->_closed_con_collector->closedQueue.push(conn); + } +} + void QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu) { @@ -96,6 +125,10 @@ QUICPacketHandlerIn::acceptEvent(int event, void *data) // Nothing to do. return EVENT_CONT; } else if (event == NET_EVENT_DATAGRAM_READ_READY) { + if (this->_collector_event == nullptr) { + this->_collector_event = this_ethread()->schedule_every(this->_closed_con_collector, HRTIME_MSECONDS(100)); + } + Queue *queue = (Queue *)data; UDPPacket *packet_r; while ((packet_r = queue->dequeue())) { diff --git a/iocore/net/quic/QUICConnectionTable.cc b/iocore/net/quic/QUICConnectionTable.cc index ce48a8a9c2c..eb048d7da7f 100644 --- a/iocore/net/quic/QUICConnectionTable.cc +++ b/iocore/net/quic/QUICConnectionTable.cc @@ -36,7 +36,12 @@ QUICConnectionTable::insert(QUICConnectionId cid, QUICConnection *connection) void QUICConnectionTable::erase(QUICConnectionId cid, QUICConnection *connection) { - ink_assert(this->_connections.get(cid) == connection); + QUICConnection *qc = this->_connections.get(cid); + if (qc == nullptr) { + return; + } + ink_assert(qc == connection); + Debug("quic_ctable", "ctable erase cid: [%" PRIx64 "] ", static_cast(cid)); // if (this->_cids.get(connection->endpoint(), connection->connection_id()) == cid) { // this->_cids.put(connection->endpoint(), nullptr); // } From 365581b4857a16d4153cf984167b564e8599691b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Feb 2018 11:38:37 +0900 Subject: [PATCH 0378/1313] Update QUIC version to draft-09 --- iocore/net/quic/QUICTypes.h | 2 +- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 384c13bc848..8ab52481db4 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -58,7 +58,7 @@ using QUICOffset = uint64_t; // Note: You also need to update tests for VersionNegotiationPacket creation, if you change the number of versions // Prefix for drafts (0xff000000) + draft number constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff000008, + 0xff000009, }; constexpr QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index db29759b0f7..c328abefdc7 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -51,7 +51,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") CHECK(packet->connection_id() == client_initial_packet.connection_id()); CHECK(packet->packet_number() == client_initial_packet.packet_number()); CHECK(packet->version() == 0x00); - CHECK(memcmp(packet->payload(), "\xff\x00\x00\x08", 4) == 0); + CHECK(memcmp(packet->payload(), "\xff\x00\x00\x09", 4) == 0); } TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") From 9e3d6220f37eb5e225aeb4c6f796dfe0549e9fb6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Feb 2018 11:42:31 +0900 Subject: [PATCH 0379/1313] Don't send transport parameters on NEW_SESSION_TIKECT messages --- iocore/net/QUICNetProcessor.cc | 3 +-- iocore/net/quic/QUICHandshake.cc | 23 ++-------------------- iocore/net/quic/QUICHandshake.h | 2 +- iocore/net/quic/QUICTransportParameters.cc | 6 +----- 4 files changed, 5 insertions(+), 29 deletions(-) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 979af876c56..1ab0027e27d 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -86,8 +86,7 @@ QUICNetProcessor::start(int, size_t stacksize) SSL_CTX_set_alpn_select_cb(this->_ssl_ctx, QUIC::ssl_select_next_protocol, nullptr); SSL_CTX_add_custom_ext(this->_ssl_ctx, QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID, - SSL_EXT_TLS_ONLY | SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS | - SSL_EXT_TLS1_3_NEW_SESSION_TICKET, + SSL_EXT_TLS_ONLY | SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS, &QUICTransportParametersHandler::add, &QUICTransportParametersHandler::free, nullptr, &QUICTransportParametersHandler::parse, nullptr); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 3f48a6d53db..9014d8d5026 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -247,28 +247,9 @@ QUICHandshake::set_transport_parameters(std::shared_ptr -QUICHandshake::local_transport_parameters(bool with_version) +QUICHandshake::local_transport_parameters() { - if (with_version) { - return this->_local_transport_parameters; - } else { - QUICConfig::scoped_config params; - QUICTransportParametersInNewSessionTicket *tp = new QUICTransportParametersInNewSessionTicket(); - - // MUSTs - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); - tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); - tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); - tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN); - - // MAYs - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi_in()); - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni_in()); - // this->_local_transport_parameters.add(QUICTransportParameterId::OMIT_CONNECTION_ID, {}); - // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); - - return std::unique_ptr(tp); - } + return this->_local_transport_parameters; } std::shared_ptr diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 4a83225affa..770f172daef 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -76,7 +76,7 @@ class QUICHandshake : public QUICApplication QUICVersion negotiated_version(); const char *negotiated_cipher_suite(); void negotiated_application_name(const uint8_t **name, unsigned int *len); - std::shared_ptr local_transport_parameters(bool with_version = true); + std::shared_ptr local_transport_parameters(); std::shared_ptr remote_transport_parameters(); bool is_version_negotiated(); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index f2b03cb47a6..bf524ecfc6f 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -563,8 +563,7 @@ QUICTransportParametersHandler::add(SSL *s, unsigned int ext_type, unsigned int { QUICHandshake *hs = static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_hs_index)); *out = reinterpret_cast(ats_malloc(TRANSPORT_PARAMETERS_MAXIMUM_SIZE)); - bool with_version = (context != SSL_EXT_TLS1_3_NEW_SESSION_TICKET); - hs->local_transport_parameters(with_version)->store(const_cast(*out), reinterpret_cast(outlen)); + hs->local_transport_parameters()->store(const_cast(*out), reinterpret_cast(outlen)); return 1; } @@ -588,9 +587,6 @@ QUICTransportParametersHandler::parse(SSL *s, unsigned int ext_type, unsigned in case SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS: hs->set_transport_parameters(std::make_shared(in, inlen)); break; - case SSL_EXT_TLS1_3_NEW_SESSION_TICKET: - hs->set_transport_parameters(std::make_shared(in, inlen)); - break; default: // Do nothing break; From b6098434a09a1ad8a86ac6125092a6c8c1827b59 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Feb 2018 11:45:58 +0900 Subject: [PATCH 0380/1313] Update labels for key generation --- iocore/net/quic/QUICKeyGenerator.cc | 8 ++++---- iocore/net/quic/test/test_QUICKeyGenerator.cc | 12 ++++++------ lib/ts/HKDF.cc | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index c07d1370fcc..06ba3b48ae5 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -29,10 +29,10 @@ constexpr static uint8_t QUIC_VERSION_1_SALT[] = { 0xaf, 0xc8, 0x24, 0xec, 0x5f, 0xc7, 0x7e, 0xca, 0x1e, 0x9d, 0x36, 0xf3, 0x7f, 0xb2, 0xd4, 0x65, 0x18, 0xc3, 0x66, 0x39, }; -constexpr static ts::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("QUIC client handshake secret"_sv); -constexpr static ts::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("QUIC server handshake secret"_sv); -constexpr static ts::string_view LABEL_FOR_CLIENT_PP_SECRET("EXPORTER-QUIC client 1-RTT Secret"_sv); -constexpr static ts::string_view LABEL_FOR_SERVER_PP_SECRET("EXPORTER-QUIC server 1-RTT Secret"_sv); +constexpr static ts::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("client hs"_sv); +constexpr static ts::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("server hs"_sv); +constexpr static ts::string_view LABEL_FOR_CLIENT_PP_SECRET("EXPORTER-QUIC client 1rtt"_sv); +constexpr static ts::string_view LABEL_FOR_SERVER_PP_SECRET("EXPORTER-QUIC server 1rtt"_sv); constexpr static ts::string_view LABEL_FOR_KEY("key"_sv); constexpr static ts::string_view LABEL_FOR_IV("iv"_sv); diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index 4930a1ccb8a..f364f0c54a3 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -57,9 +57,9 @@ TEST_CASE("QUICKeyGenerator", "[quic]") QUICKeyGenerator keygen(QUICKeyGenerator::Context::CLIENT); QUICConnectionId cid = 0x8394c8f03e515708; - uint8_t expected_client_key[] = {0x9e, 0xdc, 0x91, 0xd5, 0x51, 0x8c, 0x1e, 0x6b, - 0x2f, 0x80, 0x2b, 0xd1, 0xc8, 0xad, 0x59, 0x23}; - uint8_t expected_client_iv[] = {0x78, 0xc4, 0x90, 0xe2, 0xe4, 0x22, 0x62, 0x0b, 0x4e, 0xc1, 0xce, 0xc3}; + uint8_t expected_client_key[] = {0x6b, 0x6a, 0xbc, 0x50, 0xf7, 0xac, 0x46, 0xd1, + 0x10, 0x8c, 0x19, 0xcc, 0x63, 0x64, 0xbd, 0xe3}; + uint8_t expected_client_iv[] = {0xb1, 0xf9, 0xa7, 0xe2, 0x7c, 0xc2, 0x33, 0xbb, 0x99, 0xe2, 0x03, 0x71}; std::unique_ptr actual_km = keygen.generate(cid); @@ -74,9 +74,9 @@ TEST_CASE("QUICKeyGenerator", "[quic]") QUICKeyGenerator keygen(QUICKeyGenerator::Context::SERVER); QUICConnectionId cid = 0x8394c8f03e515708; - uint8_t expected_server_key[] = {0xa2, 0xaa, 0x67, 0xd4, 0x32, 0x13, 0xba, 0x8d, - 0x55, 0xf5, 0x76, 0x84, 0xb7, 0x1c, 0x0f, 0xc0}; - uint8_t expected_server_iv[] = {0xa2, 0x6a, 0xa2, 0x24, 0x5c, 0x4f, 0x76, 0x24, 0xa9, 0x5b, 0x0a, 0xbd}; + uint8_t expected_server_key[] = {0x9e, 0xe7, 0xe8, 0x57, 0x72, 0x00, 0x59, 0xaf, + 0x30, 0x11, 0xfb, 0x26, 0xe1, 0x21, 0x42, 0xc9}; + uint8_t expected_server_iv[] = {0xd5, 0xee, 0xe8, 0xb5, 0x7c, 0x9e, 0xc7, 0xc4, 0xbe, 0x98, 0x4a, 0xa5}; std::unique_ptr actual_km = keygen.generate(cid); diff --git a/lib/ts/HKDF.cc b/lib/ts/HKDF.cc index 91f5b94860d..5971ce10acf 100644 --- a/lib/ts/HKDF.cc +++ b/lib/ts/HKDF.cc @@ -35,8 +35,8 @@ HKDF::expand_label(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t hkdf_label[0] = (length >> 8) & 0xFF; hkdf_label[1] = length & 0xFF; hkdf_label_len += 2; - // "tls13 " + Label - hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%ctls13 %.*s", static_cast(6 + label_len), + // "QUIC " + Label + hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%cQUIC %.*s", static_cast(5 + label_len), static_cast(label_len), label); // Hash Value hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%c%.*s", static_cast(hash_value_len), From e957bbf555146d5f9f9aa8785f1443d1195c3b11 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Feb 2018 13:55:20 +0900 Subject: [PATCH 0381/1313] Separate out QUIC specific function from ts/HDKF --- iocore/net/quic/Makefile.am | 1 + iocore/net/quic/QUICCrypto.cc | 2 +- lib/ts/HKDF.cc => iocore/net/quic/QUICHKDF.cc | 11 ++++---- iocore/net/quic/QUICKeyGenerator.cc | 27 +++++++++---------- iocore/net/quic/QUICKeyGenerator.h | 16 ++++++----- iocore/net/quic/test/Makefile.am | 9 +++++++ lib/ts/HKDF.h | 6 +---- lib/ts/Makefile.am | 1 - 8 files changed, 39 insertions(+), 34 deletions(-) rename lib/ts/HKDF.cc => iocore/net/quic/QUICHKDF.cc (77%) diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 9201472c221..999f07c4c97 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -61,6 +61,7 @@ libquic_a_SOURCES = \ QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ QUICKeyGenerator.cc \ + QUICHKDF.cc \ QUICTransportParameters.cc \ QUICConnectionTable.cc \ QUICAckFrameCreator.cc \ diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc index a09c5d68325..1e7681f8aa4 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICCrypto.cc @@ -27,10 +27,10 @@ #include #include -#include "ts/HKDF.h" #include "ts/Diags.h" #include "ts/string_view.h" #include "QUICTypes.h" +#include "QUICHKDF.h" constexpr static char tag[] = "quic_crypto"; diff --git a/lib/ts/HKDF.cc b/iocore/net/quic/QUICHKDF.cc similarity index 77% rename from lib/ts/HKDF.cc rename to iocore/net/quic/QUICHKDF.cc index 5971ce10acf..adb2cff2344 100644 --- a/lib/ts/HKDF.cc +++ b/iocore/net/quic/QUICHKDF.cc @@ -20,13 +20,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "HKDF.h" +#include "QUICHKDF.h" #include #include int -HKDF::expand_label(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, - const char *hash_value, size_t hash_value_len, uint16_t length) +QUICHKDF::expand(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, + uint16_t length) { // Create HKDF label uint8_t hkdf_label[512]; // 2 + 255 + 255 @@ -39,9 +39,8 @@ HKDF::expand_label(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%cQUIC %.*s", static_cast(5 + label_len), static_cast(label_len), label); // Hash Value - hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%c%.*s", static_cast(hash_value_len), - static_cast(hash_value_len), hash_value); + hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%c%.*s", 0, 0, ""); - this->expand(dst, dst_len, secret, secret_len, hkdf_label, hkdf_label_len, length); + HKDF::expand(dst, dst_len, secret, secret_len, hkdf_label, hkdf_label_len, length); return 1; } diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 06ba3b48ae5..7f824f70c88 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -24,7 +24,7 @@ #include #include "QUICKeyGenerator.h" #include "ts/ink_assert.h" -#include "ts/HKDF.h" +#include "QUICHKDF.h" constexpr static uint8_t QUIC_VERSION_1_SALT[] = { 0xaf, 0xc8, 0x24, 0xec, 0x5f, 0xc7, 0x7e, 0xca, 0x1e, 0x9d, 0x36, 0xf3, 0x7f, 0xb2, 0xd4, 0x65, 0x18, 0xc3, 0x66, 0x39, @@ -45,7 +45,7 @@ QUICKeyGenerator::generate(QUICConnectionId cid) const EVP_MD *md = EVP_sha256(); uint8_t secret[512]; size_t secret_len = sizeof(secret); - HKDF hkdf(md); + QUICHKDF hkdf(md); switch (this->_ctx) { case Context::CLIENT: @@ -72,7 +72,7 @@ QUICKeyGenerator::generate(SSL *ssl) const EVP_MD *md = _get_handshake_digest(ssl); uint8_t secret[512]; size_t secret_len = sizeof(secret); - HKDF hkdf(md); + QUICHKDF hkdf(md); switch (this->_ctx) { case Context::CLIENT: @@ -91,12 +91,12 @@ QUICKeyGenerator::generate(SSL *ssl) } int -QUICKeyGenerator::_generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, HKDF &hkdf, const uint8_t *secret, +QUICKeyGenerator::_generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher) { // Generate a key and a IV - // key = HKDF-Expand-Label(S, "key", "", key_length) - // iv = HKDF-Expand-Label(S, "iv", "", iv_length) + // key = QHKDF-Expand(S, "key", "", key_length) + // iv = QHKDF-Expand(S, "iv", "", iv_length) this->_generate_key(key, key_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); this->_generate_iv(iv, iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher)); @@ -104,7 +104,7 @@ QUICKeyGenerator::_generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t * } int -QUICKeyGenerator::_generate_cleartext_secret(uint8_t *out, size_t *out_len, HKDF &hkdf, QUICConnectionId cid, const char *label, +QUICKeyGenerator::_generate_cleartext_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid, const char *label, size_t label_len, size_t length) { uint8_t client_connection_id[8]; @@ -118,13 +118,12 @@ QUICKeyGenerator::_generate_cleartext_secret(uint8_t *out, size_t *out_len, HKDF return -1; } - hkdf.expand_label(out, out_len, cleartext_secret, cleartext_secret_len, reinterpret_cast(label), label_len, "", 0, - length); + hkdf.expand(out, out_len, cleartext_secret, cleartext_secret_len, reinterpret_cast(label), label_len, length); return 0; } int -QUICKeyGenerator::_generate_pp_secret(uint8_t *out, size_t *out_len, HKDF &hkdf, SSL *ssl, const char *label, size_t label_len, +QUICKeyGenerator::_generate_pp_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, SSL *ssl, const char *label, size_t label_len, size_t length) { *out_len = length; @@ -141,15 +140,15 @@ QUICKeyGenerator::_generate_pp_secret(uint8_t *out, size_t *out_len, HKDF &hkdf, } int -QUICKeyGenerator::_generate_key(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, +QUICKeyGenerator::_generate_key(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t key_length) const { - return hkdf.expand_label(out, out_len, secret, secret_len, LABEL_FOR_KEY.data(), LABEL_FOR_KEY.length(), "", 0, key_length); + return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_KEY.data(), LABEL_FOR_KEY.length(), key_length); } int -QUICKeyGenerator::_generate_iv(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, +QUICKeyGenerator::_generate_iv(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t iv_length) const { - return hkdf.expand_label(out, out_len, secret, secret_len, LABEL_FOR_IV.data(), LABEL_FOR_IV.length(), "", 0, iv_length); + return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_IV.data(), LABEL_FOR_IV.length(), iv_length); } diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index 31aa62281ef..3dcfdf33028 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -24,7 +24,7 @@ #include #include "QUICTypes.h" -#include "ts/HKDF.h" +#include "QUICHKDF.h" #ifdef OPENSSL_IS_BORINGSSL typedef EVP_AEAD QUIC_EVP_CIPHER; @@ -69,13 +69,15 @@ class QUICKeyGenerator uint8_t _last_secret[256]; size_t _last_secret_len = 0; - int _generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, - const QUIC_EVP_CIPHER *cipher); - int _generate_cleartext_secret(uint8_t *out, size_t *out_len, HKDF &hkdf, QUICConnectionId cid, const char *label, + int _generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, QUICHKDF &hkdf, const uint8_t *secret, + size_t secret_len, const QUIC_EVP_CIPHER *cipher); + int _generate_cleartext_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid, const char *label, size_t label_len, size_t length); - int _generate_pp_secret(uint8_t *out, size_t *out_len, HKDF &hkdf, SSL *ssl, const char *label, size_t label_len, size_t length); - int _generate_key(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t key_length) const; - int _generate_iv(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t iv_length) const; + int _generate_pp_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, SSL *ssl, 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; 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_cleartext() const; diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 51c1c1912dc..bbfdd7b70db 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -133,6 +133,7 @@ test_QUICFrame_SOURCES = \ ../QUICPacket.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ + ../QUICHKDF.cc \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICTypes.cc \ @@ -185,6 +186,7 @@ test_QUICFrameDispatcher_SOURCES = \ $(QUICCrypto_impl) \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ + ../QUICHKDF.cc \ ../../SSLNextProtocolSet.cc test_QUICFrameDispatcher_LDADD = \ @@ -306,6 +308,7 @@ test_QUICTransportParameters_SOURCES = \ $(QUICCrypto_impl) \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ + ../QUICHKDF.cc \ ../QUICStream.cc \ ../QUICIncomingFrameBuffer.cc \ ../QUICStreamState.cc \ @@ -347,6 +350,7 @@ test_QUICKeyGenerator_SOURCES = \ test_QUICKeyGenerator.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ + ../QUICHKDF.cc \ ../QUICTypes.cc # @@ -372,6 +376,7 @@ test_QUICCrypto_SOURCES = \ test_QUICCrypto.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ + ../QUICHKDF.cc \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICCrypto.h \ @@ -437,6 +442,7 @@ test_QUICTypeUtil_SOURCES = \ ../QUICPacket.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ + ../QUICHKDF.cc \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICTypes.cc @@ -472,6 +478,7 @@ test_QUICAckFrameCreator_SOURCES = \ ../QUICDebugNames.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ + ../QUICHKDF.cc \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../../SSLNextProtocolSet.cc @@ -503,6 +510,7 @@ test_QUICVersionNegotiator_SOURCES = \ ../QUICPacket.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ + ../QUICHKDF.cc \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICApplication.cc \ @@ -551,6 +559,7 @@ test_QUICFlowController_SOURCES = \ ../QUICPacket.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ + ../QUICHKDF.cc \ ../QUICCrypto.cc \ $(QUICCrypto_impl) \ ../QUICFrame.cc diff --git a/lib/ts/HKDF.h b/lib/ts/HKDF.h index 290529933db..8bdf0b7c236 100644 --- a/lib/ts/HKDF.h +++ b/lib/ts/HKDF.h @@ -38,11 +38,7 @@ class HKDF int expand(uint8_t *dst, size_t *dst_len, const uint8_t *prk, size_t prk_len, const uint8_t *info, size_t info_len, uint16_t length); - // This function is technically a part of TLS 1.3 - int expand_label(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, - const char *hash_value, size_t hash_value_len, uint16_t length); - -private: +protected: const EVP_MD *_digest = nullptr; EVP_PKEY_CTX *_pctx = nullptr; }; diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am index b6488a33471..18ee5c145b6 100644 --- a/lib/ts/Makefile.am +++ b/lib/ts/Makefile.am @@ -212,7 +212,6 @@ HKDF_impl = HKDF_openssl.cc endif libtsutil_la_SOURCES += \ HKDF.h \ - HKDF.cc \ $(HKDF_impl) endif From f3eaaaa195f628596eb331844692fc546598f663 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Feb 2018 14:25:06 +0900 Subject: [PATCH 0382/1313] Update loss detectin logic to draft-09 --- iocore/net/quic/QUICLossDetector.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 867408c3fb3..560917670c8 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -215,8 +215,9 @@ QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICP this->_smoothed_rtt = latest_rtt; this->_rttvar = latest_rtt / 2.0; } else { - this->_rttvar = 3.0 / 4.0 * this->_rttvar + 1.0 / 4.0 * ABS(this->_smoothed_rtt - latest_rtt); - this->_smoothed_rtt = 7.0 / 8.0 * this->_smoothed_rtt + 1.0 / 8.0 * latest_rtt; + double rttvar_sample = ABS(this->_smoothed_rtt - latest_rtt); + this->_rttvar = 3.0 / 4.0 * this->_rttvar + 1.0 / 4.0 * rttvar_sample; + this->_smoothed_rtt = 7.0 / 8.0 * this->_smoothed_rtt + 1.0 / 8.0 * latest_rtt; } } From 970ca9b52ea07170076408faa8117771f9532cb9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Feb 2018 15:26:53 +0900 Subject: [PATCH 0383/1313] Update HQ version number --- lib/ts/ink_inet.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ts/ink_inet.cc b/lib/ts/ink_inet.cc index e983a9c5d3b..93469233e93 100644 --- a/lib/ts/ink_inet.cc +++ b/lib/ts/ink_inet.cc @@ -45,7 +45,7 @@ const ts::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"_sv); const ts::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"_sv); const ts::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"_sv); const ts::string_view IP_PROTO_TAG_HTTP_2_0("h2"_sv); // HTTP/2 over TLS -const ts::string_view IP_PROTO_TAG_HTTP_QUIC("hq-08"_sv); // HTTP over QUIC +const ts::string_view IP_PROTO_TAG_HTTP_QUIC("hq-09"_sv); // HTTP over QUIC uint32_t ink_inet_addr(const char *s) From 999dde94f5e67d19f5a4c3d8e289a62962606871 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Feb 2018 15:41:06 +0900 Subject: [PATCH 0384/1313] Don't free QUICNetVConnections to avoid crash #3139 --- iocore/net/QUICNetVConnection.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8ea14610ed8..ac371e7317e 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -210,6 +210,7 @@ QUICNetVConnection::free(EThread *t) this->_ctable->erase(this->_alt_quic_connection_ids[i].id, this); } +/* TODO: Uncmment these blocks after refactoring read / write process this->_udp_con = nullptr; this->_packet_handler = nullptr; _unschedule_packet_write_ready(); @@ -230,6 +231,7 @@ QUICNetVConnection::free(EThread *t) } else { THREAD_FREE(this, quicNetVCAllocator, t); } +*/ } void From 39c80096354acf44ed47647bb3f5c8b63bbecd02 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Feb 2018 17:38:25 +0900 Subject: [PATCH 0385/1313] Add QUICHKDF.h --- iocore/net/quic/QUICHKDF.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 iocore/net/quic/QUICHKDF.h diff --git a/iocore/net/quic/QUICHKDF.h b/iocore/net/quic/QUICHKDF.h new file mode 100644 index 00000000000..ea01c80179f --- /dev/null +++ b/iocore/net/quic/QUICHKDF.h @@ -0,0 +1,34 @@ +/** @file + + HKDF utility + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include "ts/HKDF.h" + +class QUICHKDF : public HKDF +{ +public: + QUICHKDF(const EVP_MD *digest) : HKDF(digest) {} + int expand(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, + uint16_t length); +}; From e4effa3a228d7e016d95a97f414402b47508fc8f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 21 Feb 2018 14:31:53 +0900 Subject: [PATCH 0386/1313] Use pragma once --- iocore/net/P_QUICClosedConCollector.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/iocore/net/P_QUICClosedConCollector.h b/iocore/net/P_QUICClosedConCollector.h index 4484e97e838..c8abb6eb949 100644 --- a/iocore/net/P_QUICClosedConCollector.h +++ b/iocore/net/P_QUICClosedConCollector.h @@ -16,8 +16,7 @@ limitations under the License. */ -#ifndef _QUIC_CLOSED_CON_COLLECTOR_H_ -#define _QUIC_CLOSED_CON_COLLECTOR_H_ +#pragma once #include "P_QUICNetVConnection.h" @@ -35,5 +34,3 @@ class QUICClosedConCollector : public Continuation void _process_closed_connection(EThread *t); }; - -#endif From 11a3c6f99bd3ef97ce406c0af62c1f23e59401cc Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 21 Feb 2018 12:19:57 +0800 Subject: [PATCH 0387/1313] QUIC: Sends stateless reset packet if connection is closed --- iocore/net/QUICNetVConnection.cc | 44 ++++++++++++++++---------------- iocore/net/QUICPacketHandler.cc | 34 +++++++++++++----------- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ac371e7317e..8ae50387a62 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -210,28 +210,28 @@ QUICNetVConnection::free(EThread *t) this->_ctable->erase(this->_alt_quic_connection_ids[i].id, this); } -/* TODO: Uncmment these blocks after refactoring read / write process - this->_udp_con = nullptr; - this->_packet_handler = nullptr; - _unschedule_packet_write_ready(); - - delete this->_handshake_handler; - delete this->_application_map; - delete this->_crypto; - delete this->_loss_detector; - delete this->_frame_dispatcher; - delete this->_stream_manager; - delete this->_congestion_controller; - - // TODO: clear member variables like `UnixNetVConnection::free(EThread *t)` - this->mutex.clear(); - - if (from_accept_thread) { - quicNetVCAllocator.free(this); - } else { - THREAD_FREE(this, quicNetVCAllocator, t); - } -*/ + /* TODO: Uncmment these blocks after refactoring read / write process + this->_udp_con = nullptr; + this->_packet_handler = nullptr; + _unschedule_packet_write_ready(); + + delete this->_handshake_handler; + delete this->_application_map; + delete this->_crypto; + delete this->_loss_detector; + delete this->_frame_dispatcher; + delete this->_stream_manager; + delete this->_congestion_controller; + + // TODO: clear member variables like `UnixNetVConnection::free(EThread *t)` + this->mutex.clear(); + + if (from_accept_thread) { + quicNetVCAllocator.free(this); + } else { + THREAD_FREE(this, quicNetVCAllocator, t); + } + */ } void diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 2f94cb809b4..0526a9cc736 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -177,25 +177,30 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) QUICConnection *qc = this->_ctable.lookup(reinterpret_cast(block->buf()), {udp_packet->from, udp_packet->to, SOCK_DGRAM}); - if (!qc) { + vc = static_cast(qc); + // 7.1. Matching Packets to Connections + // A server that discards a packet that cannot be associated with a connection MAY also generate a stateless reset + // Send stateless reset if the packet is not a initial packet or connection is closed. + if ((!vc && !QUICTypeUtil::has_long_header(reinterpret_cast(block->buf()))) || (vc && vc->in_closed_queue)) { Connection con; con.setRemote(&udp_packet->from.sa); - - // Send stateless reset if the packet is not a initial packet - if (!QUICTypeUtil::has_long_header(reinterpret_cast(block->buf()))) { - QUICConnectionId cid = this->_read_connection_id(block); - QUICStatelessResetToken token; - { - QUICConfig::scoped_config params; - token.generate(cid, params->server_id()); - } - auto packet = QUICPacketFactory::create_stateless_reset_packet(cid, token); - this->_send_packet(this, *packet, udp_packet->getConnection(), con.addr, 1200); - return; + QUICConnectionId cid = this->_read_connection_id(block); + QUICStatelessResetToken token; + { + QUICConfig::scoped_config params; + token.generate(cid, params->server_id()); } + auto packet = QUICPacketFactory::create_stateless_reset_packet(cid, token); + this->_send_packet(this, *packet, udp_packet->getConnection(), con.addr, 1200); + udp_packet->free(); + return; + } - eth = eventProcessor.assign_thread(ET_NET); + if (!vc) { + Connection con; + con.setRemote(&udp_packet->from.sa); + eth = eventProcessor.assign_thread(ET_NET); // Create a new NetVConnection QUICConnectionId original_cid = this->_read_connection_id(block); vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); @@ -215,7 +220,6 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) qc = vc; } else { - vc = static_cast(qc); eth = vc->thread; } From 72dc4b76f0951ec5163b1be635d5b2445d53778f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 21 Feb 2018 15:41:44 +0900 Subject: [PATCH 0388/1313] Remove QUICStreamManager::init() --- iocore/net/quic/QUICStream.cc | 75 ++++++++++++++-------------- iocore/net/quic/QUICStream.h | 18 ++++--- iocore/net/quic/QUICStreamManager.cc | 7 +-- 3 files changed, 53 insertions(+), 47 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 071da7e8538..87386b0ebb7 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -36,6 +36,22 @@ Debug("quic_flow_ctrl", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) +QUICStream::QUICStream(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data, + uint64_t send_max_stream_data) + : VConnection(nullptr), + _connection_id(cid), + _id(sid), + _remote_flow_controller(send_max_stream_data, tx, _id), + _local_flow_controller(recv_max_stream_data, tx, _id), + _received_stream_frame_buffer(this), + _tx(tx) +{ + SET_HANDLER(&QUICStream::state_stream_open); + mutex = new_ProxyMutex(); + + this->init_flow_control_params(recv_max_stream_data, send_max_stream_data); +} + QUICStream::~QUICStream() { if (this->_read_event) { @@ -49,33 +65,16 @@ QUICStream::~QUICStream() } } -void -QUICStream::init(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data, - uint64_t send_max_stream_data) -{ - SET_HANDLER(&QUICStream::state_stream_open); - - this->mutex = new_ProxyMutex(); - this->_tx = tx; - this->_connection_id = cid; - this->_id = sid; - this->_remote_flow_controller = new QUICRemoteStreamFlowController(send_max_stream_data, _tx, _id); - this->_local_flow_controller = new QUICLocalStreamFlowController(recv_max_stream_data, _tx, _id); - this->init_flow_control_params(recv_max_stream_data, send_max_stream_data); - - QUICStreamDebug("Initialized"); -} - void QUICStream::init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data) { this->_flow_control_buffer_size = recv_max_stream_data; - this->_local_flow_controller->forward_limit(recv_max_stream_data); - this->_remote_flow_controller->forward_limit(send_max_stream_data); - QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), - this->_local_flow_controller->current_limit()); - QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); + this->_local_flow_controller.forward_limit(recv_max_stream_data); + this->_remote_flow_controller.forward_limit(send_max_stream_data); + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), + this->_local_flow_controller.current_limit()); + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); } QUICStreamId @@ -289,9 +288,9 @@ QUICStream::_write_to_read_vio(const std::shared_ptr &fra int bytes_added = this->_read_vio.buffer.writer()->write(frame->data(), frame->data_length()); this->_read_vio.nbytes += bytes_added; // frame->offset() + frame->data_length() == this->_recv_offset - this->_local_flow_controller->forward_limit(frame->offset() + frame->data_length() + this->_flow_control_buffer_size); - QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), - this->_local_flow_controller->current_limit()); + this->_local_flow_controller.forward_limit(frame->offset() + frame->data_length() + this->_flow_control_buffer_size); + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), + this->_local_flow_controller.current_limit()); this->_state.update_with_received_frame(*frame); } @@ -314,9 +313,9 @@ QUICStream::recv(const std::shared_ptr frame) } // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit - int ret = this->_local_flow_controller->update(frame->offset() + frame->data_length()); - QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), - this->_local_flow_controller->current_limit()); + int ret = this->_local_flow_controller.update(frame->offset() + frame->data_length()); + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), + this->_local_flow_controller.current_limit()); if (ret != 0) { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } @@ -341,9 +340,9 @@ QUICStream::recv(const std::shared_ptr frame) QUICErrorUPtr QUICStream::recv(const std::shared_ptr frame) { - this->_remote_flow_controller->forward_limit(frame->maximum_stream_data()); - QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); + this->_remote_flow_controller.forward_limit(frame->maximum_stream_data()); + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); QUICStreamDebug("restart sending"); int64_t len = this->_process_write_vio(); @@ -464,7 +463,7 @@ QUICStream::_process_write_vio() int64_t len = 0; bool fin = false; - int64_t credit = this->_remote_flow_controller->current_limit() - this->_remote_flow_controller->current_offset(); + int64_t credit = this->_remote_flow_controller.current_limit() - this->_remote_flow_controller.current_offset(); if (credit != 0 && max_size > credit) { max_size = credit; } @@ -484,9 +483,9 @@ QUICStream::_process_write_vio() break; } - int ret = this->_remote_flow_controller->update(this->_send_offset + len); - QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); + int ret = this->_remote_flow_controller.update(this->_send_offset + len); + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); if (ret != 0) { QUICStreamDebug("Flow Controller blocked sending a STREAM frame"); break; @@ -526,11 +525,11 @@ QUICStream::nbytes_to_read() QUICOffset QUICStream::largest_offset_received() { - return this->_local_flow_controller->current_offset(); + return this->_local_flow_controller.current_offset(); } QUICOffset QUICStream::largest_offset_sent() { - return this->_remote_flow_controller->current_offset(); + return this->_remote_flow_controller.current_offset(); } diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index fb713865831..e7e9879819c 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -45,10 +45,16 @@ class QUICStreamManager; class QUICStream : public VConnection { public: - QUICStream() : VConnection(nullptr), _received_stream_frame_buffer(this) {} + QUICStream() + : VConnection(nullptr), + _remote_flow_controller(0, nullptr, 0), + _local_flow_controller(0, nullptr, 0), + _received_stream_frame_buffer(this) + { + } + QUICStream(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data = 0, + uint64_t send_max_stream_data = 0); ~QUICStream(); - void init(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId id, uint64_t recv_max_stream_data = 0, - uint64_t send_max_stream_data = 0); // void start(); int state_stream_open(int event, void *data); int state_stream_closed(int event, void *data); @@ -96,9 +102,9 @@ class QUICStream : public VConnection QUICStreamId _id = 0; QUICOffset _send_offset = 0; - QUICRemoteStreamFlowController *_remote_flow_controller = nullptr; - QUICLocalStreamFlowController *_local_flow_controller = nullptr; - uint64_t _flow_control_buffer_size = 1024; + QUICRemoteStreamFlowController _remote_flow_controller; + QUICLocalStreamFlowController _local_flow_controller; + uint64_t _flow_control_buffer_size = 1024; VIO _read_vio; VIO _write_vio; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 1f27a7d2b5a..ecc12c29358 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -235,8 +235,6 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) return nullptr; } - // TODO Free the stream somewhere - stream = new (THREAD_ALLOC(quicStreamAllocator, this_ethread())) QUICStream(); uint32_t local_max_stream_data = 0; uint32_t remote_max_stream_data = 0; if (this->_local_tp) { @@ -246,7 +244,10 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) QUICConfig::scoped_config params; local_max_stream_data = params->initial_max_stream_data(); } - stream->init(this->_tx, this->_connection_id, stream_id, local_max_stream_data, remote_max_stream_data); + + // TODO Free the stream somewhere + stream = THREAD_ALLOC(quicStreamAllocator, this_ethread()); + new (stream) QUICStream(this->_tx, this->_connection_id, stream_id, local_max_stream_data, remote_max_stream_data); this->stream_list.push(stream); } From a60303a647bec7c718e66f351cd877c7e9f68488 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 21 Feb 2018 16:13:42 +0900 Subject: [PATCH 0389/1313] Update tests --- iocore/net/quic/test/test_QUICFrame.cc | 3 +-- iocore/net/quic/test/test_QUICHandshake.cc | 3 +-- iocore/net/quic/test/test_QUICStream.cc | 15 +++++---------- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index e23dd6af665..3c00ec90e1b 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1099,8 +1099,7 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") { - QUICStream stream; - stream.init(new MockQUICFrameTransmitter(), 0, 0x1234, 0, 0); + QUICStream stream(new MockQUICFrameTransmitter(), 0, 0x1234, 0, 0); std::unique_ptr error = std::unique_ptr(new QUICStreamError(&stream, static_cast(0x01))); std::unique_ptr rst_stream_frame1 = diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc index 5c2ad1511a0..9a5da765321 100644 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -62,9 +62,8 @@ TEST_CASE("1-RTT handshake ", "[quic]") QUICHandshake *server = new QUICHandshake(server_qc, server_ssl_ctx, server_token); // setup stream 0 - QUICStream *stream = new MockQUICStream(); MockQUICFrameTransmitter tx; - stream->init(&tx, conn_id, 0); + QUICStream *stream = new MockQUICStream(); MockQUICStreamIO *stream_io = new MockQUICStreamIO(nullptr, stream); client->set_stream(stream, stream_io); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 00dd32aeff1..8d1dec549cc 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -70,8 +70,7 @@ TEST_CASE("QUICStream", "[quic]") IOBufferReader *reader = read_buffer->alloc_reader(); MockQUICFrameTransmitter tx; - std::unique_ptr stream(new QUICStream()); - stream->init(&tx, 0, stream_id, 1024, 1024); + std::unique_ptr stream(new QUICStream(&tx, 0, stream_id, 1024, 1024)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_1); @@ -97,8 +96,7 @@ TEST_CASE("QUICStream", "[quic]") IOBufferReader *reader = read_buffer->alloc_reader(); MockQUICFrameTransmitter tx; - std::unique_ptr stream(new QUICStream()); - stream->init(&tx, 0, stream_id); + std::unique_ptr stream(new QUICStream(&tx, 0, stream_id)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -124,8 +122,7 @@ TEST_CASE("QUICStream", "[quic]") IOBufferReader *reader = read_buffer->alloc_reader(); MockQUICFrameTransmitter tx; - std::unique_ptr stream(new QUICStream()); - stream->init(&tx, 0, stream_id); + std::unique_ptr stream(new QUICStream(&tx, 0, stream_id)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -155,8 +152,7 @@ TEST_CASE("QUICStream", "[quic]") IOBufferReader *reader = read_buffer->alloc_reader(); MockQUICFrameTransmitter tx; - std::unique_ptr stream(new QUICStream()); - stream->init(&tx, 0, stream_id); + std::unique_ptr stream(new QUICStream(&tx, 0, stream_id)); stream->init_flow_control_params(4096, 4096); stream->do_io_read(nullptr, 0, read_buffer); @@ -193,8 +189,7 @@ TEST_CASE("QUICStream", "[quic]") IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); MockQUICFrameTransmitter tx; - std::unique_ptr stream(new QUICStream()); - stream->init(&tx, 0, stream_id); + std::unique_ptr stream(new QUICStream(&tx, 0, stream_id)); stream->init_flow_control_params(4096, 4096); MockContinuation mock_cont(stream->mutex); stream->do_io_read(nullptr, 0, read_buffer); From 4d58fcd16ff3d0ee5d23710d33dee45b8106f7bc Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 21 Feb 2018 17:04:00 +0900 Subject: [PATCH 0390/1313] Rename QUICCrypto to QUICHandshakeProtocol --- .gitignore | 2 +- iocore/net/P_QUICNetVConnection.h | 4 +- iocore/net/QUICNetVConnection.cc | 6 +- iocore/net/quic/Makefile.am | 8 +-- iocore/net/quic/Mock.h | 4 +- iocore/net/quic/QUICHandshake.cc | 22 +++---- iocore/net/quic/QUICHandshake.h | 4 +- ...QUICCrypto.cc => QUICHandshakeProtocol.cc} | 8 +-- .../{QUICCrypto.h => QUICHandshakeProtocol.h} | 6 +- ....cc => QUICHandshakeProtocol_boringssl.cc} | 2 +- ...sl.cc => QUICHandshakeProtocol_openssl.cc} | 2 +- iocore/net/quic/QUICPacket.cc | 20 +++--- iocore/net/quic/QUICPacket.h | 6 +- .../net/quic/{QUICCryptoTls.h => QUICTLS.h} | 4 +- iocore/net/quic/test/Makefile.am | 64 +++++++++---------- iocore/net/quic/test/test_QUICFrame.cc | 4 +- ...rypto.cc => test_QUICHandshakeProtocol.cc} | 14 ++-- iocore/net/quic/test/test_QUICLossDetector.cc | 4 +- .../net/quic/test/test_QUICPacketFactory.cc | 12 ++-- .../quic/test/test_QUICVersionNegotiator.cc | 4 +- 20 files changed, 100 insertions(+), 100 deletions(-) rename iocore/net/quic/{QUICCrypto.cc => QUICHandshakeProtocol.cc} (98%) rename iocore/net/quic/{QUICCrypto.h => QUICHandshakeProtocol.h} (96%) rename iocore/net/quic/{QUICCrypto_boringssl.cc => QUICHandshakeProtocol_boringssl.cc} (99%) rename iocore/net/quic/{QUICCrypto_openssl.cc => QUICHandshakeProtocol_openssl.cc} (99%) rename iocore/net/quic/{QUICCryptoTls.h => QUICTLS.h} (97%) rename iocore/net/quic/test/{test_QUICCrypto.cc => test_QUICHandshakeProtocol.cc} (93%) diff --git a/.gitignore b/.gitignore index e0560376573..e79029f75ed 100644 --- a/.gitignore +++ b/.gitignore @@ -91,7 +91,7 @@ lib/perl/lib/Apache/TS.pm iocore/net/test_certlookup iocore/net/test_UDPNet iocore/net/quic/test/test_QUICAckFrameCreator -iocore/net/quic/test/test_QUICCrypto +iocore/net/quic/test/test_QUICHandshakeProtocol iocore/net/quic/test/test_QUICFlowController iocore/net/quic/test/test_QUICFrame iocore/net/quic/test/test_QUICFrameDispatcher diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index a7c7ca03ffd..06d713949bb 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -51,7 +51,7 @@ #include "quic/QUICHandshake.h" #include "quic/QUICApplication.h" #include "quic/QUICStream.h" -#include "quic/QUICCrypto.h" +#include "quic/QUICHandshakeProtocol.h" #include "quic/QUICAckFrameCreator.h" #include "quic/QUICLossDetector.h" #include "quic/QUICStreamManager.h" @@ -243,7 +243,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // TODO: use custom allocator and make them std::unique_ptr or std::shared_ptr // or make them just member variables. QUICHandshake *_handshake_handler = nullptr; - QUICCrypto *_crypto = nullptr; + QUICHandshakeProtocol *_hs_protocol = nullptr; QUICLossDetector *_loss_detector = nullptr; QUICFrameDispatcher *_frame_dispatcher = nullptr; QUICStreamManager *_stream_manager = nullptr; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8ae50387a62..cb0beae5473 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -183,9 +183,9 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) this->_application_map = new QUICApplicationMap(); this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); - this->_crypto = this->_handshake_handler->crypto_module(); + this->_hs_protocol = this->_handshake_handler->protocol(); this->_frame_dispatcher = new QUICFrameDispatcher(); - this->_packet_factory.set_crypto_module(this->_crypto); + this->_packet_factory.set_hs_protocol(this->_hs_protocol); // Create frame handlers this->_stream_manager = new QUICStreamManager(this->connection_id(), this, this->_application_map); @@ -217,7 +217,7 @@ QUICNetVConnection::free(EThread *t) delete this->_handshake_handler; delete this->_application_map; - delete this->_crypto; + delete this->_hs_protocol; delete this->_loss_detector; delete this->_frame_dispatcher; delete this->_stream_manager; diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 999f07c4c97..7ff8913a545 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -35,10 +35,10 @@ AM_CPPFLAGS += \ noinst_LIBRARIES = libquic.a if OPENSSL_IS_BORINGSSL -QUICCrypto_impl = QUICCrypto_boringssl.cc +QUICHandshakeProtocol_impl = QUICHandshakeProtocol_boringssl.cc QUICKeyGenerator_impl = QUICKeyGenerator_boringssl.cc else -QUICCrypto_impl = QUICCrypto_openssl.cc +QUICHandshakeProtocol_impl = QUICHandshakeProtocol_openssl.cc QUICKeyGenerator_impl = QUICKeyGenerator_openssl.cc endif @@ -56,8 +56,8 @@ libquic_a_SOURCES = \ QUICStreamState.cc \ QUICStream.cc \ QUICHandshake.cc \ - QUICCrypto.cc \ - $(QUICCrypto_impl) \ + QUICHandshakeProtocol.cc \ + $(QUICHandshakeProtocol_impl) \ QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ QUICKeyGenerator.cc \ diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 50697e3fb5c..fbac3503782 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -459,10 +459,10 @@ class MockQUICStreamIO : public QUICStreamIO } }; -class MockQUICCrypto : public QUICCrypto +class MockQUICHandshakeProtocol : public QUICHandshakeProtocol { public: - MockQUICCrypto() : QUICCrypto() {} + MockQUICHandshakeProtocol() : QUICHandshakeProtocol() {} int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 9014d8d5026..51bdbf28224 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -28,7 +28,7 @@ #include "P_SSLNextProtocolSet.h" #include "P_VConnection.h" -#include "QUICCryptoTls.h" +#include "QUICTLS.h" #include "QUICEvents.h" #include "QUICGlobals.h" #include "QUICVersionNegotiator.h" @@ -93,14 +93,14 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandsha QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token) : QUICApplication(qc), _ssl(SSL_new(ssl_ctx)), - _crypto(new QUICCryptoTls(this->_ssl, qc->direction())), + _hs_protocol(new QUICCryptoTls(this->_ssl, qc->direction())), _version_negotiator(new QUICVersionNegotiator()), _netvc_context(qc->direction()), _reset_token(token) { SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_hs_index, this); - this->_crypto->initialize_key_materials(this->_client_qc->original_connection_id()); + this->_hs_protocol->initialize_key_materials(this->_client_qc->original_connection_id()); SET_HANDLER(&QUICHandshake::state_initial); } @@ -155,10 +155,10 @@ QUICHandshake::is_completed() return this->handler == &QUICHandshake::state_complete; } -QUICCrypto * -QUICHandshake::crypto_module() +QUICHandshakeProtocol * +QUICHandshake::protocol() { - return this->_crypto; + return this->_hs_protocol; } QUICVersion @@ -172,7 +172,7 @@ const char * QUICHandshake::negotiated_cipher_suite() { // FIXME Generalize and remove dynamic_cast - QUICCryptoTls *crypto_tls = dynamic_cast(this->_crypto); + QUICCryptoTls *crypto_tls = dynamic_cast(this->_hs_protocol); if (crypto_tls) { return SSL_get_cipher_name(crypto_tls->ssl_handle()); } @@ -184,7 +184,7 @@ void QUICHandshake::negotiated_application_name(const uint8_t **name, unsigned int *len) { // FIXME Generalize and remove dynamic_cast - QUICCryptoTls *crypto_tls = dynamic_cast(this->_crypto); + QUICCryptoTls *crypto_tls = dynamic_cast(this->_hs_protocol); if (crypto_tls) { SSL_get0_alpn_selected(crypto_tls->ssl_handle(), name, len); } @@ -309,7 +309,7 @@ QUICHandshake::state_key_exchange(int event, Event *data) QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE: { - if (this->_crypto->is_handshake_finished()) { + if (this->_hs_protocol->is_handshake_finished()) { int res = this->_complete_handshake(); if (!res) { this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); @@ -457,7 +457,7 @@ QUICHandshake::_do_handshake(bool initial) uint8_t out[MAX_HANDSHAKE_MSG_LEN] = {0}; size_t out_len = 0; - int result = this->_crypto->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, in, in_len); + int result = this->_hs_protocol->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, in, in_len); if (out_len > 0) { I_WANNA_DUMP_THIS_BUF(out, static_cast(out_len)); @@ -573,7 +573,7 @@ QUICHandshake::_complete_handshake() SET_HANDLER(&QUICHandshake::state_complete); QUICHSDebug("%s", this->negotiated_cipher_suite()); - int res = this->_crypto->update_key_materials(); + int res = this->_hs_protocol->update_key_materials(); if (res) { QUICHSDebug("Keying Materials are exported"); } else { diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 770f172daef..3fd0dfe1d59 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -72,7 +72,7 @@ class QUICHandshake : public QUICApplication int state_closed(int event, void *data); // Getters - QUICCrypto *crypto_module(); + QUICHandshakeProtocol *protocol(); QUICVersion negotiated_version(); const char *negotiated_cipher_suite(); void negotiated_application_name(const uint8_t **name, unsigned int *len); @@ -88,7 +88,7 @@ class QUICHandshake : public QUICApplication private: SSL *_ssl = nullptr; - QUICCrypto *_crypto = nullptr; + QUICHandshakeProtocol *_hs_protocol = nullptr; std::shared_ptr _local_transport_parameters = nullptr; std::shared_ptr _remote_transport_parameters = nullptr; diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICHandshakeProtocol.cc similarity index 98% rename from iocore/net/quic/QUICCrypto.cc rename to iocore/net/quic/QUICHandshakeProtocol.cc index 1e7681f8aa4..6b8063253a4 100644 --- a/iocore/net/quic/QUICCrypto.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -1,6 +1,6 @@ /** @file * - * QUIC Crypto (TLS to Secure QUIC) + * QUIC Handshake Protocol (TLS to Secure QUIC) * * @section license License * @@ -21,7 +21,7 @@ * limitations under the License. */ #include "QUICGlobals.h" -#include "QUICCryptoTls.h" +#include "QUICTLS.h" #include #include @@ -94,9 +94,9 @@ QUICPacketProtection::key_phase() const } // -// QUICCrypto +// QUICHandshakeProtocol // -QUICCryptoTls::QUICCryptoTls(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICCrypto(), _ssl(ssl), _netvc_context(nvc_ctx) +QUICCryptoTls::QUICCryptoTls(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx) { if (this->_netvc_context == NET_VCONNECTION_IN) { SSL_set_accept_state(this->_ssl); diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICHandshakeProtocol.h similarity index 96% rename from iocore/net/quic/QUICCrypto.h rename to iocore/net/quic/QUICHandshakeProtocol.h index 6ab434f62fd..cb73cd90b93 100644 --- a/iocore/net/quic/QUICCrypto.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -42,11 +42,11 @@ class QUICPacketProtection QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; }; -class QUICCrypto +class QUICHandshakeProtocol { public: - QUICCrypto(){}; - virtual ~QUICCrypto(){}; + QUICHandshakeProtocol(){}; + virtual ~QUICHandshakeProtocol(){}; virtual int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) = 0; virtual bool is_handshake_finished() const = 0; diff --git a/iocore/net/quic/QUICCrypto_boringssl.cc b/iocore/net/quic/QUICHandshakeProtocol_boringssl.cc similarity index 99% rename from iocore/net/quic/QUICCrypto_boringssl.cc rename to iocore/net/quic/QUICHandshakeProtocol_boringssl.cc index 4d848fd4c32..1010a8c9c0e 100644 --- a/iocore/net/quic/QUICCrypto_boringssl.cc +++ b/iocore/net/quic/QUICHandshakeProtocol_boringssl.cc @@ -20,7 +20,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "QUICCryptoTls.h" +#include "QUICTLS.h" #include #include diff --git a/iocore/net/quic/QUICCrypto_openssl.cc b/iocore/net/quic/QUICHandshakeProtocol_openssl.cc similarity index 99% rename from iocore/net/quic/QUICCrypto_openssl.cc rename to iocore/net/quic/QUICHandshakeProtocol_openssl.cc index 9eae6b3728f..2325a492429 100644 --- a/iocore/net/quic/QUICCrypto_openssl.cc +++ b/iocore/net/quic/QUICHandshakeProtocol_openssl.cc @@ -20,7 +20,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "QUICCryptoTls.h" +#include "QUICTLS.h" #include #include diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 114eb6eabcb..9f2c9acb56a 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -672,8 +672,8 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ result = QUICPacketCreationResult::SUCCESS; break; case QUICPacketType::PROTECTED: - if (this->_crypto->is_key_derived()) { - if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), + if (this->_hs_protocol->is_key_derived()) { + if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { result = QUICPacketCreationResult::SUCCESS; } else { @@ -684,9 +684,9 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ } break; case QUICPacketType::INITIAL: - if (!this->_crypto->is_key_derived()) { + if (!this->_hs_protocol->is_key_derived()) { if (QUICTypeUtil::is_supported_version(header->version())) { - if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), + if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { result = QUICPacketCreationResult::SUCCESS; } else { @@ -700,8 +700,8 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ } break; case QUICPacketType::HANDSHAKE: - if (!this->_crypto->is_key_derived()) { - if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), + if (!this->_hs_protocol->is_key_derived()) { + if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { result = QUICPacketCreationResult::SUCCESS; } else { @@ -768,7 +768,7 @@ QUICPacketUPtr QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - // TODO Key phase should be picked up from QUICCrypto, probably + // TODO Key phase should be picked up from QUICHandshakeProtocol, probably QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, connection_id, this->_packet_number_generator.next(), base_packet_number, std::move(payload), len); @@ -820,7 +820,7 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header, bool retra size_t cipher_txt_len = 0; QUICPacket *packet = nullptr; - if (this->_crypto->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), + if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, retransmittable); @@ -836,9 +836,9 @@ QUICPacketFactory::set_version(QUICVersion negotiated_version) } void -QUICPacketFactory::set_crypto_module(QUICCrypto *crypto) +QUICPacketFactory::set_hs_protocol(QUICHandshakeProtocol *hs_protocol) { - this->_crypto = crypto; + this->_hs_protocol = hs_protocol; } // diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index a7d554d7234..3bb3307a2ae 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -31,7 +31,7 @@ #include "I_IOBuffer.h" #include "QUICTypes.h" -#include "QUICCrypto.h" +#include "QUICHandshakeProtocol.h" #define QUIC_FIELD_OFFSET_CONNECTION_ID 1 #define QUIC_FIELD_OFFSET_PACKET_NUMBER 4 @@ -306,11 +306,11 @@ class QUICPacketFactory static QUICPacketUPtr create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessResetToken stateless_reset_token); void set_version(QUICVersion negotiated_version); - void set_crypto_module(QUICCrypto *crypto); + void set_hs_protocol(QUICHandshakeProtocol *hs_protocol); private: QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; - QUICCrypto *_crypto = nullptr; + QUICHandshakeProtocol *_hs_protocol = nullptr; QUICPacketNumberGenerator _packet_number_generator; static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeader *header); diff --git a/iocore/net/quic/QUICCryptoTls.h b/iocore/net/quic/QUICTLS.h similarity index 97% rename from iocore/net/quic/QUICCryptoTls.h rename to iocore/net/quic/QUICTLS.h index c42ec26fd7e..ea52733b490 100644 --- a/iocore/net/quic/QUICCryptoTls.h +++ b/iocore/net/quic/QUICTLS.h @@ -34,9 +34,9 @@ #include "I_EventSystem.h" #include "I_NetVConnection.h" -#include "QUICCrypto.h" +#include "QUICHandshakeProtocol.h" -class QUICCryptoTls : public QUICCrypto +class QUICCryptoTls : public QUICHandshakeProtocol { public: QUICCryptoTls(SSL *ssl, NetVConnectionContext_t nvc_ctx); diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index bbfdd7b70db..c0ea1e2fdc0 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -27,7 +27,7 @@ check_PROGRAMS = \ test_QUICStreamManager \ test_QUICTransportParameters \ test_QUICKeyGenerator \ - test_QUICCrypto \ + test_QUICHandshakeProtocol \ test_QUICLossDetector \ test_QUICTypeUtil \ test_QUICAckFrameCreator \ @@ -53,10 +53,10 @@ AM_CPPFLAGS += \ if OPENSSL_IS_BORINGSSL QUICKeyGenerator_impl = ../QUICKeyGenerator_boringssl.cc -QUICCrypto_impl = ../QUICCrypto_boringssl.cc +QUICHandshakeProtocol_impl = ../QUICHandshakeProtocol_boringssl.cc else QUICKeyGenerator_impl = ../QUICKeyGenerator_openssl.cc -QUICCrypto_impl = ../QUICCrypto_openssl.cc +QUICHandshakeProtocol_impl = ../QUICHandshakeProtocol_openssl.cc endif # @@ -72,8 +72,8 @@ test_QUICPacket_SOURCES = \ event_processor_main.cc \ test_QUICPacket.cc \ ../QUICPacket.cc \ - ../QUICCrypto.cc \ - $(QUICCrypto_impl) \ + ../QUICHandshakeProtocol.cc \ + $(QUICHandshakeProtocol_impl) \ ../QUICTypes.cc test_QUICPacket_LDADD = \ @@ -100,8 +100,8 @@ test_QUICPacketFactory_SOURCES = \ event_processor_main.cc \ test_QUICPacketFactory.cc \ ../QUICPacket.cc \ - ../QUICCrypto.cc \ - $(QUICCrypto_impl) \ + ../QUICHandshakeProtocol.cc \ + $(QUICHandshakeProtocol_impl) \ ../QUICTypes.cc test_QUICPacketFactory_LDADD = \ @@ -134,8 +134,8 @@ test_QUICFrame_SOURCES = \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ - ../QUICCrypto.cc \ - $(QUICCrypto_impl) \ + ../QUICHandshakeProtocol.cc \ + $(QUICHandshakeProtocol_impl) \ ../QUICTypes.cc \ ../QUICStream.cc \ ../QUICStreamState.cc \ @@ -182,8 +182,8 @@ test_QUICFrameDispatcher_SOURCES = \ ../QUICTypes.cc \ ../QUICEchoApp.cc \ ../QUICDebugNames.cc \ - ../QUICCrypto.cc \ - $(QUICCrypto_impl) \ + ../QUICHandshakeProtocol.cc \ + $(QUICHandshakeProtocol_impl) \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ @@ -304,8 +304,8 @@ test_QUICTransportParameters_SOURCES = \ ../QUICApplicationMap.cc \ ../QUICHandshake.cc \ ../QUICVersionNegotiator.cc \ - ../QUICCrypto.cc \ - $(QUICCrypto_impl) \ + ../QUICHandshakeProtocol.cc \ + $(QUICHandshakeProtocol_impl) \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ @@ -354,16 +354,16 @@ test_QUICKeyGenerator_SOURCES = \ ../QUICTypes.cc # -# test_QUICCrypto +# test_QUICHandshakeProtocol # -test_QUICCrypto_CPPFLAGS = \ +test_QUICHandshakeProtocol_CPPFLAGS = \ $(AM_CPPFLAGS) -test_QUICCrypto_LDFLAGS = \ +test_QUICHandshakeProtocol_LDFLAGS = \ @AM_LDFLAGS@ \ @OPENSSL_LDFLAGS@ -test_QUICCrypto_LDADD = \ +test_QUICHandshakeProtocol_LDADD = \ @OPENSSL_LIBS@ \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ @@ -371,15 +371,15 @@ test_QUICCrypto_LDADD = \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a -test_QUICCrypto_SOURCES = \ +test_QUICHandshakeProtocol_SOURCES = \ main.cc \ - test_QUICCrypto.cc \ + test_QUICHandshakeProtocol.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ - ../QUICCrypto.cc \ - $(QUICCrypto_impl) \ - ../QUICCrypto.h \ + ../QUICHandshakeProtocol.cc \ + $(QUICHandshakeProtocol_impl) \ + ../QUICHandshakeProtocol.h \ ../QUICTypes.cc \ ../QUICGlobals.cc \ ../../SSLNextProtocolSet.cc @@ -410,8 +410,8 @@ test_QUICLossDetector_SOURCES = \ ../QUICLossDetector.cc \ ../QUICTypes.cc \ ../QUICPacket.cc \ - ../QUICCrypto.cc \ - $(QUICCrypto_impl) \ + ../QUICHandshakeProtocol.cc \ + $(QUICHandshakeProtocol_impl) \ ../QUICFrame.cc # @@ -443,8 +443,8 @@ test_QUICTypeUtil_SOURCES = \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ - ../QUICCrypto.cc \ - $(QUICCrypto_impl) \ + ../QUICHandshakeProtocol.cc \ + $(QUICHandshakeProtocol_impl) \ ../QUICTypes.cc # @@ -479,8 +479,8 @@ test_QUICAckFrameCreator_SOURCES = \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ - ../QUICCrypto.cc \ - $(QUICCrypto_impl) \ + ../QUICHandshakeProtocol.cc \ + $(QUICHandshakeProtocol_impl) \ ../../SSLNextProtocolSet.cc # @@ -511,8 +511,8 @@ test_QUICVersionNegotiator_SOURCES = \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ - ../QUICCrypto.cc \ - $(QUICCrypto_impl) \ + ../QUICHandshakeProtocol.cc \ + $(QUICHandshakeProtocol_impl) \ ../QUICApplication.cc \ ../QUICApplicationMap.cc \ ../QUICHandshake.cc \ @@ -560,8 +560,8 @@ test_QUICFlowController_SOURCES = \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ - ../QUICCrypto.cc \ - $(QUICCrypto_impl) \ + ../QUICHandshakeProtocol.cc \ + $(QUICHandshakeProtocol_impl) \ ../QUICFrame.cc # diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 3c00ec90e1b..4623a9c6000 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1113,8 +1113,8 @@ TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") TEST_CASE("Retransmit", "[quic][frame][retransmit]") { QUICPacketFactory factory; - MockQUICCrypto crypto; - factory.set_crypto_module(&crypto); + MockQUICHandshakeProtocol hs_protocol; + factory.set_hs_protocol(&hs_protocol); QUICPacketUPtr packet = factory.create_server_protected_packet(0x01020304, 0, {nullptr, [](void *p) { ats_free(p); }}, 0, true); SECTION("STREAM frame") diff --git a/iocore/net/quic/test/test_QUICCrypto.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc similarity index 93% rename from iocore/net/quic/test/test_QUICCrypto.cc rename to iocore/net/quic/test/test_QUICHandshakeProtocol.cc index e0a2b725401..0877c21c74e 100644 --- a/iocore/net/quic/test/test_QUICCrypto.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -34,7 +34,7 @@ #include #include "Mock.h" -#include "QUICCryptoTls.h" +#include "QUICTLS.h" static constexpr uint32_t MAX_HANDSHAKE_MSG_LEN = 2048; @@ -56,13 +56,13 @@ print_hex(const uint8_t *v, size_t len) return; } -TEST_CASE("QUICCrypto Cleartext", "[quic]") +TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]") { // Client SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - QUICCrypto *client = new QUICCryptoTls(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + QUICHandshakeProtocol *client = new QUICCryptoTls(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); // Server SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); @@ -72,7 +72,7 @@ TEST_CASE("QUICCrypto Cleartext", "[quic]") SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - QUICCrypto *server = new QUICCryptoTls(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + QUICHandshakeProtocol *server = new QUICCryptoTls(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); CHECK(client->initialize_key_materials(0x8394c8f03e515700)); CHECK(server->initialize_key_materials(0x8394c8f03e515700)); @@ -114,13 +114,13 @@ TEST_CASE("QUICCrypto Cleartext", "[quic]") delete server; } -TEST_CASE("QUICCrypto 1-RTT", "[quic]") +TEST_CASE("QUICHandshakeProtocol 1-RTT", "[quic]") { // Client SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - QUICCrypto *client = new QUICCryptoTls(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + QUICHandshakeProtocol *client = new QUICCryptoTls(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); // Server SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); @@ -130,7 +130,7 @@ TEST_CASE("QUICCrypto 1-RTT", "[quic]") SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - QUICCrypto *server = new QUICCryptoTls(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + QUICHandshakeProtocol *server = new QUICCryptoTls(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); CHECK(client->initialize_key_materials(0x8394c8f03e515708)); CHECK(server->initialize_key_materials(0x8394c8f03e515708)); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 5cfdfc03cb7..1fb01cfc5e3 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -29,9 +29,9 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") { - MockQUICCrypto crypto; + MockQUICHandshakeProtocol hs_protocol; QUICPacketFactory pf; - pf.set_crypto_module(&crypto); + pf.set_hs_protocol(&hs_protocol); QUICAckFrameCreator *afc = new QUICAckFrameCreator(); QUICConnectionId connection_id = 1; diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index c328abefdc7..ba5c5233c6c 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -29,8 +29,8 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") { QUICPacketFactory factory; - MockQUICCrypto crypto; - factory.set_crypto_module(&crypto); + MockQUICHandshakeProtocol hs_protocol; + factory.set_hs_protocol(&hs_protocol); uint8_t client_initial_packet_header[] = { 0x82, // Type @@ -57,8 +57,8 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") { QUICPacketFactory factory; - MockQUICCrypto crypto; - factory.set_crypto_module(&crypto); + MockQUICHandshakeProtocol hs_protocol; + factory.set_hs_protocol(&hs_protocol); factory.set_version(0x11223344); uint8_t raw[] = {0xaa, 0xbb, 0xcc, 0xdd}; @@ -76,8 +76,8 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") { QUICPacketFactory factory; - MockQUICCrypto crypto; - factory.set_crypto_module(&crypto); + MockQUICHandshakeProtocol hs_protocol; + factory.set_hs_protocol(&hs_protocol); QUICStatelessResetToken token; token.generate(12345, 67890); uint8_t expected_output[] = { diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 48cc23d7b5f..ea6d87b8ac2 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -29,8 +29,8 @@ TEST_CASE("QUICVersionNegotiator", "[quic]") { QUICPacketFactory packet_factory; - MockQUICCrypto crypto; - packet_factory.set_crypto_module(&crypto); + MockQUICHandshakeProtocol hs_protocol; + packet_factory.set_hs_protocol(&hs_protocol); QUICVersionNegotiator vn; SECTION("Normal case") From 235252651b7935c928bc13432c87813942e870ba Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 21 Feb 2018 17:27:12 +0900 Subject: [PATCH 0391/1313] Rename QUICCryptoTls to QUICTLS --- iocore/net/quic/Makefile.am | 7 +- iocore/net/quic/QUICHandshake.cc | 14 +- iocore/net/quic/QUICHandshakeProtocol.cc | 260 +--------------- iocore/net/quic/QUICPacket.cc | 11 +- iocore/net/quic/QUICPacket.h | 2 +- iocore/net/quic/QUICTLS.cc | 279 ++++++++++++++++++ iocore/net/quic/QUICTLS.h | 6 +- ...ocol_boringssl.cc => QUICTLS_boringssl.cc} | 22 +- ...Protocol_openssl.cc => QUICTLS_openssl.cc} | 14 +- iocore/net/quic/test/Makefile.am | 37 ++- iocore/net/quic/test/test_QUICHandshake.cc | 2 +- .../quic/test/test_QUICHandshakeProtocol.cc | 8 +- 12 files changed, 348 insertions(+), 314 deletions(-) create mode 100644 iocore/net/quic/QUICTLS.cc rename iocore/net/quic/{QUICHandshakeProtocol_boringssl.cc => QUICTLS_boringssl.cc} (74%) rename iocore/net/quic/{QUICHandshakeProtocol_openssl.cc => QUICTLS_openssl.cc} (88%) diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 7ff8913a545..c8b0c562c5f 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -35,10 +35,10 @@ AM_CPPFLAGS += \ noinst_LIBRARIES = libquic.a if OPENSSL_IS_BORINGSSL -QUICHandshakeProtocol_impl = QUICHandshakeProtocol_boringssl.cc +QUICTLS_impl = QUICTLS_boringssl.cc QUICKeyGenerator_impl = QUICKeyGenerator_boringssl.cc else -QUICHandshakeProtocol_impl = QUICHandshakeProtocol_openssl.cc +QUICTLS_impl = QUICTLS_openssl.cc QUICKeyGenerator_impl = QUICKeyGenerator_openssl.cc endif @@ -57,7 +57,8 @@ libquic_a_SOURCES = \ QUICStream.cc \ QUICHandshake.cc \ QUICHandshakeProtocol.cc \ - $(QUICHandshakeProtocol_impl) \ + QUICTLS.cc \ + $(QUICTLS_impl) \ QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ QUICKeyGenerator.cc \ diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 51bdbf28224..e3a5ce3c46f 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -93,7 +93,7 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandsha QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token) : QUICApplication(qc), _ssl(SSL_new(ssl_ctx)), - _hs_protocol(new QUICCryptoTls(this->_ssl, qc->direction())), + _hs_protocol(new QUICTLS(this->_ssl, qc->direction())), _version_negotiator(new QUICVersionNegotiator()), _netvc_context(qc->direction()), _reset_token(token) @@ -172,9 +172,9 @@ const char * QUICHandshake::negotiated_cipher_suite() { // FIXME Generalize and remove dynamic_cast - QUICCryptoTls *crypto_tls = dynamic_cast(this->_hs_protocol); - if (crypto_tls) { - return SSL_get_cipher_name(crypto_tls->ssl_handle()); + QUICTLS *hs_tls = dynamic_cast(this->_hs_protocol); + if (hs_tls) { + return SSL_get_cipher_name(hs_tls->ssl_handle()); } return nullptr; @@ -184,9 +184,9 @@ void QUICHandshake::negotiated_application_name(const uint8_t **name, unsigned int *len) { // FIXME Generalize and remove dynamic_cast - QUICCryptoTls *crypto_tls = dynamic_cast(this->_hs_protocol); - if (crypto_tls) { - SSL_get0_alpn_selected(crypto_tls->ssl_handle(), name, len); + QUICTLS *hs_tls = dynamic_cast(this->_hs_protocol); + if (hs_tls) { + SSL_get0_alpn_selected(hs_tls->ssl_handle(), name, len); } } diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index 6b8063253a4..29579788949 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -21,31 +21,13 @@ * limitations under the License. */ #include "QUICGlobals.h" -#include "QUICTLS.h" - -#include -#include -#include +#include "QUICHandshakeProtocol.h" #include "ts/Diags.h" #include "ts/string_view.h" #include "QUICTypes.h" #include "QUICHKDF.h" -constexpr static char tag[] = "quic_crypto"; - -static void -to_hex(uint8_t *out, uint8_t *in, int in_len) -{ - for (int i = 0; i < in_len; ++i) { - int u4 = in[i] / 16; - int l4 = in[i] % 16; - out[i * 2] = (u4 < 10) ? ('0' + u4) : ('A' + u4 - 10); - out[i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('A' + l4 - 10); - } - out[in_len * 2] = 0; -} - // // QUICPacketProtection // @@ -92,243 +74,3 @@ QUICPacketProtection::key_phase() const { return this->_key_phase; } - -// -// QUICHandshakeProtocol -// -QUICCryptoTls::QUICCryptoTls(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx) -{ - if (this->_netvc_context == NET_VCONNECTION_IN) { - SSL_set_accept_state(this->_ssl); - } else if (this->_netvc_context == NET_VCONNECTION_OUT) { - SSL_set_connect_state(this->_ssl); - } else { - ink_assert(false); - } - - this->_client_pp = new QUICPacketProtection(); - this->_server_pp = new QUICPacketProtection(); -} - -QUICCryptoTls::~QUICCryptoTls() -{ - delete this->_client_pp; - delete this->_server_pp; -} - -int -QUICCryptoTls::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) -{ - ink_assert(this->_ssl != nullptr); - - // TODO: directly read/write from VIO - BIO *rbio = BIO_new(BIO_s_mem()); - BIO *wbio = BIO_new(BIO_s_mem()); - if (in != nullptr || in_len != 0) { - BIO_write(rbio, in, in_len); - } - SSL_set_bio(this->_ssl, rbio, wbio); - - int err = SSL_ERROR_NONE; - if (!SSL_is_init_finished(this->_ssl)) { - ERR_clear_error(); - int ret = SSL_do_handshake(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, err_buf, sizeof(err_buf)); - Debug(tag, "Handshake error: %s (%d)", err_buf, err); - return err; - } - } - - out_len = BIO_ctrl_pending(wbio); - if (out_len > 0) { - BIO_read(wbio, out, max_out_len); - } - } - - return err; -} - -bool -QUICCryptoTls::is_handshake_finished() const -{ - return SSL_is_init_finished(this->_ssl); -} - -bool -QUICCryptoTls::is_key_derived() const -{ - return (this->_client_pp->key_phase() != QUICKeyPhase::CLEARTEXT && this->_server_pp->key_phase() != QUICKeyPhase::CLEARTEXT); -} - -int -QUICCryptoTls::initialize_key_materials(QUICConnectionId cid) -{ - // Generate keys - uint8_t print_buf[512]; - std::unique_ptr km; - km = this->_keygen_for_client.generate(cid); - if (is_debug_tag_set("vv_quic_crypto")) { - to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "client key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "client iv 0x%s", print_buf); - } - this->_client_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); - - km = this->_keygen_for_server.generate(cid); - if (is_debug_tag_set("vv_quic_crypto")) { - to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "server key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "server iv 0x%s", print_buf); - } - this->_server_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); - - // Update algorithm - this->_aead = _get_evp_aead(); - - return 1; -} - -int -QUICCryptoTls::update_key_materials() -{ - ink_assert(SSL_is_init_finished(this->_ssl)); - // Switch key phase - QUICKeyPhase next_key_phase; - switch (this->_client_pp->key_phase()) { - case QUICKeyPhase::PHASE_0: - next_key_phase = QUICKeyPhase::PHASE_1; - break; - case QUICKeyPhase::PHASE_1: - next_key_phase = QUICKeyPhase::PHASE_0; - break; - case QUICKeyPhase::CLEARTEXT: - next_key_phase = QUICKeyPhase::PHASE_0; - break; - default: - Error("QUICKeyPhase value is undefined"); - ink_assert(false); - next_key_phase = QUICKeyPhase::PHASE_0; - } - - // Generate keys - uint8_t print_buf[512]; - std::unique_ptr km; - km = this->_keygen_for_client.generate(this->_ssl); - if (is_debug_tag_set("vv_quic_crypto")) { - to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "client key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "client iv 0x%s", print_buf); - } - this->_client_pp->set_key(std::move(km), next_key_phase); - km = this->_keygen_for_server.generate(this->_ssl); - if (is_debug_tag_set("vv_quic_crypto")) { - to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "server key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "server iv 0x%s", print_buf); - } - this->_server_pp->set_key(std::move(km), next_key_phase); - - // Update algorithm - this->_aead = _get_evp_aead(); - - return 1; -} - -SSL * -QUICCryptoTls::ssl_handle() -{ - return this->_ssl; -} - -bool -QUICCryptoTls::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const -{ - QUICPacketProtection *pp = nullptr; - - switch (this->_netvc_context) { - case NET_VCONNECTION_IN: { - pp = this->_server_pp; - break; - } - case NET_VCONNECTION_OUT: { - pp = this->_client_pp; - break; - } - default: - ink_assert(false); - return false; - } - - size_t tag_len = this->_get_aead_tag_len(); - return _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, pp->get_key(phase), tag_len); -} - -bool -QUICCryptoTls::decrypt(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, QUICKeyPhase phase) const -{ - QUICPacketProtection *pp = nullptr; - - switch (this->_netvc_context) { - case NET_VCONNECTION_IN: { - pp = this->_client_pp; - break; - } - case NET_VCONNECTION_OUT: { - pp = this->_server_pp; - break; - } - default: - ink_assert(false); - return false; - } - - size_t tag_len = this->_get_aead_tag_len(); - bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, pp->get_key(phase), tag_len); - if (!ret) { - Debug(tag, "Failed to decrypt a packet: pkt_num=%" PRIu64, pkt_num); - } - return ret; -} - -/** - * Example iv_len = 12 - * - * 0 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 (byte) - * +-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | iv | // IV - * +-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |0|0|0|0| pkt num | // network byte order & left-padded with zeros - * +-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | nonce | // nonce = iv xor pkt_num - * +-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - */ -void -QUICCryptoTls::_gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const -{ - nonce_len = iv_len; - memcpy(nonce, iv, iv_len); - - pkt_num = htobe64(pkt_num); - uint8_t *p = reinterpret_cast(&pkt_num); - - for (size_t i = 0; i < 8; ++i) { - nonce[iv_len - 8 + i] ^= p[i]; - } -} diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 9f2c9acb56a..bb505f6099c 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -674,7 +674,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ case QUICPacketType::PROTECTED: if (this->_hs_protocol->is_key_derived()) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->size(), header->key_phase())) { + header->packet_number(), header->buf(), header->size(), header->key_phase())) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -686,8 +686,9 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ case QUICPacketType::INITIAL: if (!this->_hs_protocol->is_key_derived()) { if (QUICTypeUtil::is_supported_version(header->version())) { - if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { + if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + QUICKeyPhase::CLEARTEXT)) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -702,7 +703,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ case QUICPacketType::HANDSHAKE: if (!this->_hs_protocol->is_key_derived()) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { + header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -821,7 +822,7 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header, bool retra QUICPacket *packet = nullptr; if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->size(), header->key_phase())) { + header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, retransmittable); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 3bb3307a2ae..2e52c6e17b1 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -309,7 +309,7 @@ class QUICPacketFactory void set_hs_protocol(QUICHandshakeProtocol *hs_protocol); private: - QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; + QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; QUICHandshakeProtocol *_hs_protocol = nullptr; QUICPacketNumberGenerator _packet_number_generator; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc new file mode 100644 index 00000000000..f6da788f908 --- /dev/null +++ b/iocore/net/quic/QUICTLS.cc @@ -0,0 +1,279 @@ +/** @file + * + * QUIC Handshake Protocol (TLS to Secure QUIC) + * + * @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 "QUICTLS.h" + +#include +#include +#include + +constexpr static char tag[] = "quic_tls"; + +static void +to_hex(uint8_t *out, uint8_t *in, int in_len) +{ + for (int i = 0; i < in_len; ++i) { + int u4 = in[i] / 16; + int l4 = in[i] % 16; + out[i * 2] = (u4 < 10) ? ('0' + u4) : ('A' + u4 - 10); + out[i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('A' + l4 - 10); + } + out[in_len * 2] = 0; +} + +QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx) +{ + if (this->_netvc_context == NET_VCONNECTION_IN) { + SSL_set_accept_state(this->_ssl); + } else if (this->_netvc_context == NET_VCONNECTION_OUT) { + SSL_set_connect_state(this->_ssl); + } else { + ink_assert(false); + } + + this->_client_pp = new QUICPacketProtection(); + this->_server_pp = new QUICPacketProtection(); +} + +QUICTLS::~QUICTLS() +{ + delete this->_client_pp; + delete this->_server_pp; +} + +int +QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) +{ + ink_assert(this->_ssl != nullptr); + + // TODO: directly read/write from VIO + BIO *rbio = BIO_new(BIO_s_mem()); + BIO *wbio = BIO_new(BIO_s_mem()); + if (in != nullptr || in_len != 0) { + BIO_write(rbio, in, in_len); + } + SSL_set_bio(this->_ssl, rbio, wbio); + + int err = SSL_ERROR_NONE; + if (!SSL_is_init_finished(this->_ssl)) { + ERR_clear_error(); + int ret = SSL_do_handshake(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, err_buf, sizeof(err_buf)); + Debug(tag, "Handshake error: %s (%d)", err_buf, err); + return err; + } + } + + out_len = BIO_ctrl_pending(wbio); + if (out_len > 0) { + BIO_read(wbio, out, max_out_len); + } + } + + return err; +} + +bool +QUICTLS::is_handshake_finished() const +{ + return SSL_is_init_finished(this->_ssl); +} + +bool +QUICTLS::is_key_derived() const +{ + return (this->_client_pp->key_phase() != QUICKeyPhase::CLEARTEXT && this->_server_pp->key_phase() != QUICKeyPhase::CLEARTEXT); +} + +int +QUICTLS::initialize_key_materials(QUICConnectionId cid) +{ + // Generate keys + uint8_t print_buf[512]; + std::unique_ptr km; + km = this->_keygen_for_client.generate(cid); + if (is_debug_tag_set("vv_quic_crypto")) { + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "client key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "client iv 0x%s", print_buf); + } + this->_client_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); + + km = this->_keygen_for_server.generate(cid); + if (is_debug_tag_set("vv_quic_crypto")) { + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "server key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "server iv 0x%s", print_buf); + } + this->_server_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); + + // Update algorithm + this->_aead = _get_evp_aead(); + + return 1; +} + +int +QUICTLS::update_key_materials() +{ + ink_assert(SSL_is_init_finished(this->_ssl)); + // Switch key phase + QUICKeyPhase next_key_phase; + switch (this->_client_pp->key_phase()) { + case QUICKeyPhase::PHASE_0: + next_key_phase = QUICKeyPhase::PHASE_1; + break; + case QUICKeyPhase::PHASE_1: + next_key_phase = QUICKeyPhase::PHASE_0; + break; + case QUICKeyPhase::CLEARTEXT: + next_key_phase = QUICKeyPhase::PHASE_0; + break; + default: + Error("QUICKeyPhase value is undefined"); + ink_assert(false); + next_key_phase = QUICKeyPhase::PHASE_0; + } + + // Generate keys + uint8_t print_buf[512]; + std::unique_ptr km; + km = this->_keygen_for_client.generate(this->_ssl); + if (is_debug_tag_set("vv_quic_crypto")) { + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "client key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "client iv 0x%s", print_buf); + } + this->_client_pp->set_key(std::move(km), next_key_phase); + km = this->_keygen_for_server.generate(this->_ssl); + if (is_debug_tag_set("vv_quic_crypto")) { + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "server key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "server iv 0x%s", print_buf); + } + this->_server_pp->set_key(std::move(km), next_key_phase); + + // Update algorithm + this->_aead = _get_evp_aead(); + + return 1; +} + +SSL * +QUICTLS::ssl_handle() +{ + return this->_ssl; +} + +bool +QUICTLS::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const +{ + QUICPacketProtection *pp = nullptr; + + switch (this->_netvc_context) { + case NET_VCONNECTION_IN: { + pp = this->_server_pp; + break; + } + case NET_VCONNECTION_OUT: { + pp = this->_client_pp; + break; + } + default: + ink_assert(false); + return false; + } + + size_t tag_len = this->_get_aead_tag_len(); + return _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, pp->get_key(phase), tag_len); +} + +bool +QUICTLS::decrypt(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, QUICKeyPhase phase) const +{ + QUICPacketProtection *pp = nullptr; + + switch (this->_netvc_context) { + case NET_VCONNECTION_IN: { + pp = this->_client_pp; + break; + } + case NET_VCONNECTION_OUT: { + pp = this->_server_pp; + break; + } + default: + ink_assert(false); + return false; + } + + size_t tag_len = this->_get_aead_tag_len(); + bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, pp->get_key(phase), tag_len); + if (!ret) { + Debug(tag, "Failed to decrypt a packet: pkt_num=%" PRIu64, pkt_num); + } + return ret; +} + +/** + * Example iv_len = 12 + * + * 0 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 (byte) + * +-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | iv | // IV + * +-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0|0|0|0| pkt num | // network byte order & left-padded with zeros + * +-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | nonce | // nonce = iv xor pkt_num + * +-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +void +QUICTLS::_gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const +{ + nonce_len = iv_len; + memcpy(nonce, iv, iv_len); + + pkt_num = htobe64(pkt_num); + uint8_t *p = reinterpret_cast(&pkt_num); + + for (size_t i = 0; i < 8; ++i) { + nonce[iv_len - 8 + i] ^= p[i]; + } +} diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index ea52733b490..20c2a668519 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -36,11 +36,11 @@ #include "I_NetVConnection.h" #include "QUICHandshakeProtocol.h" -class QUICCryptoTls : public QUICHandshakeProtocol +class QUICTLS : public QUICHandshakeProtocol { public: - QUICCryptoTls(SSL *ssl, NetVConnectionContext_t nvc_ctx); - ~QUICCryptoTls(); + QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx); + ~QUICTLS(); int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override; bool is_handshake_finished() const override; diff --git a/iocore/net/quic/QUICHandshakeProtocol_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc similarity index 74% rename from iocore/net/quic/QUICHandshakeProtocol_boringssl.cc rename to iocore/net/quic/QUICTLS_boringssl.cc index 1010a8c9c0e..de441b3cf79 100644 --- a/iocore/net/quic/QUICHandshakeProtocol_boringssl.cc +++ b/iocore/net/quic/QUICTLS_boringssl.cc @@ -29,10 +29,10 @@ #include #include -static constexpr char tag[] = "quic_crypto"; +static constexpr char tag[] = "quic_tls"; const EVP_AEAD * -QUICCryptoTls::_get_evp_aead(const SSL_CIPHER *cipher) const +QUICTLS::_get_evp_aead(const SSL_CIPHER *cipher) const { ink_assert(SSL_CIPHER_is_AEAD(cipher)); @@ -50,14 +50,14 @@ QUICCryptoTls::_get_evp_aead(const SSL_CIPHER *cipher) const } size_t -QUICCryptoTls::_get_aead_tag_len(const SSL_CIPHER * /* cipher */) const +QUICTLS::_get_aead_tag_len(const SSL_CIPHER * /* cipher */) const { return EVP_AEAD_DEFAULT_TAG_LENGTH; } int -QUICCryptoTls::_hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, - size_t label_len, const EVP_MD *digest) const +QUICTLS::_hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, + size_t label_len, const EVP_MD *digest) const { uint8_t info[256] = {0}; size_t info_len = 0; @@ -66,9 +66,9 @@ QUICCryptoTls::_hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *s } bool -QUICCryptoTls::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, - size_t iv_len, size_t tag_len) const +QUICTLS::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, + size_t iv_len, size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; @@ -91,9 +91,9 @@ QUICCryptoTls::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_l } bool -QUICCryptoTls::_decrypt(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, size_t key_len, const uint8_t *iv, - size_t iv_len, size_t tag_len) const +QUICTLS::_decrypt(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, size_t key_len, const uint8_t *iv, + size_t iv_len, size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; diff --git a/iocore/net/quic/QUICHandshakeProtocol_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc similarity index 88% rename from iocore/net/quic/QUICHandshakeProtocol_openssl.cc rename to iocore/net/quic/QUICTLS_openssl.cc index 2325a492429..7dafc652fb3 100644 --- a/iocore/net/quic/QUICHandshakeProtocol_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -28,10 +28,10 @@ #include #include -static constexpr char tag[] = "quic_crypto"; +static constexpr char tag[] = "quic_tls"; const EVP_CIPHER * -QUICCryptoTls::_get_evp_aead() const +QUICTLS::_get_evp_aead() const { if (this->is_handshake_finished()) { switch (SSL_CIPHER_get_id(SSL_get_current_cipher(this->_ssl))) { @@ -54,7 +54,7 @@ QUICCryptoTls::_get_evp_aead() const } size_t -QUICCryptoTls::_get_aead_tag_len() const +QUICTLS::_get_aead_tag_len() const { if (this->is_handshake_finished()) { switch (SSL_CIPHER_get_id(SSL_get_current_cipher(this->_ssl))) { @@ -77,8 +77,8 @@ QUICCryptoTls::_get_aead_tag_len() const } bool -QUICCryptoTls::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const +QUICTLS::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; @@ -126,8 +126,8 @@ QUICCryptoTls::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_l } bool -QUICCryptoTls::_decrypt(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 KeyMaterial &km, size_t tag_len) const +QUICTLS::_decrypt(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 KeyMaterial &km, size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index c0ea1e2fdc0..d0b482ed769 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -53,10 +53,10 @@ AM_CPPFLAGS += \ if OPENSSL_IS_BORINGSSL QUICKeyGenerator_impl = ../QUICKeyGenerator_boringssl.cc -QUICHandshakeProtocol_impl = ../QUICHandshakeProtocol_boringssl.cc +QUICTLS_impl = ../QUICTLS_boringssl.cc else QUICKeyGenerator_impl = ../QUICKeyGenerator_openssl.cc -QUICHandshakeProtocol_impl = ../QUICHandshakeProtocol_openssl.cc +QUICTLS_impl = ../QUICTLS_openssl.cc endif # @@ -73,7 +73,8 @@ test_QUICPacket_SOURCES = \ test_QUICPacket.cc \ ../QUICPacket.cc \ ../QUICHandshakeProtocol.cc \ - $(QUICHandshakeProtocol_impl) \ + ../QUICTLS.cc \ + $(QUICTLS_impl) \ ../QUICTypes.cc test_QUICPacket_LDADD = \ @@ -101,7 +102,8 @@ test_QUICPacketFactory_SOURCES = \ test_QUICPacketFactory.cc \ ../QUICPacket.cc \ ../QUICHandshakeProtocol.cc \ - $(QUICHandshakeProtocol_impl) \ + ../QUICTLS.cc \ + $(QUICTLS_impl) \ ../QUICTypes.cc test_QUICPacketFactory_LDADD = \ @@ -135,7 +137,8 @@ test_QUICFrame_SOURCES = \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ ../QUICHandshakeProtocol.cc \ - $(QUICHandshakeProtocol_impl) \ + ../QUICTLS.cc \ + $(QUICTLS_impl) \ ../QUICTypes.cc \ ../QUICStream.cc \ ../QUICStreamState.cc \ @@ -183,7 +186,8 @@ test_QUICFrameDispatcher_SOURCES = \ ../QUICEchoApp.cc \ ../QUICDebugNames.cc \ ../QUICHandshakeProtocol.cc \ - $(QUICHandshakeProtocol_impl) \ + ../QUICTLS.cc \ + $(QUICTLS_impl) \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ @@ -305,7 +309,8 @@ test_QUICTransportParameters_SOURCES = \ ../QUICHandshake.cc \ ../QUICVersionNegotiator.cc \ ../QUICHandshakeProtocol.cc \ - $(QUICHandshakeProtocol_impl) \ + ../QUICTLS.cc \ + $(QUICTLS_impl) \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ @@ -378,7 +383,8 @@ test_QUICHandshakeProtocol_SOURCES = \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ ../QUICHandshakeProtocol.cc \ - $(QUICHandshakeProtocol_impl) \ + ../QUICTLS.cc \ + $(QUICTLS_impl) \ ../QUICHandshakeProtocol.h \ ../QUICTypes.cc \ ../QUICGlobals.cc \ @@ -411,7 +417,8 @@ test_QUICLossDetector_SOURCES = \ ../QUICTypes.cc \ ../QUICPacket.cc \ ../QUICHandshakeProtocol.cc \ - $(QUICHandshakeProtocol_impl) \ + ../QUICTLS.cc \ + $(QUICTLS_impl) \ ../QUICFrame.cc # @@ -444,7 +451,8 @@ test_QUICTypeUtil_SOURCES = \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ ../QUICHandshakeProtocol.cc \ - $(QUICHandshakeProtocol_impl) \ + ../QUICTLS.cc \ + $(QUICTLS_impl) \ ../QUICTypes.cc # @@ -480,7 +488,8 @@ test_QUICAckFrameCreator_SOURCES = \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ ../QUICHandshakeProtocol.cc \ - $(QUICHandshakeProtocol_impl) \ + ../QUICTLS.cc \ + $(QUICTLS_impl) \ ../../SSLNextProtocolSet.cc # @@ -512,7 +521,8 @@ test_QUICVersionNegotiator_SOURCES = \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ ../QUICHandshakeProtocol.cc \ - $(QUICHandshakeProtocol_impl) \ + ../QUICTLS.cc \ + $(QUICTLS_impl) \ ../QUICApplication.cc \ ../QUICApplicationMap.cc \ ../QUICHandshake.cc \ @@ -561,7 +571,8 @@ test_QUICFlowController_SOURCES = \ $(QUICKeyGenerator_impl) \ ../QUICHKDF.cc \ ../QUICHandshakeProtocol.cc \ - $(QUICHandshakeProtocol_impl) \ + ../QUICTLS.cc \ + $(QUICTLS_impl) \ ../QUICFrame.cc # diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc index 9a5da765321..15a342d36b3 100644 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -63,7 +63,7 @@ TEST_CASE("1-RTT handshake ", "[quic]") // setup stream 0 MockQUICFrameTransmitter tx; - QUICStream *stream = new MockQUICStream(); + QUICStream *stream = new MockQUICStream(); MockQUICStreamIO *stream_io = new MockQUICStreamIO(nullptr, stream); client->set_stream(stream, stream_io); diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 0877c21c74e..789dd0f386c 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -62,7 +62,7 @@ TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]") SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - QUICHandshakeProtocol *client = new QUICCryptoTls(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); // Server SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); @@ -72,7 +72,7 @@ TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]") SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - QUICHandshakeProtocol *server = new QUICCryptoTls(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); CHECK(client->initialize_key_materials(0x8394c8f03e515700)); CHECK(server->initialize_key_materials(0x8394c8f03e515700)); @@ -120,7 +120,7 @@ TEST_CASE("QUICHandshakeProtocol 1-RTT", "[quic]") SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - QUICHandshakeProtocol *client = new QUICCryptoTls(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); // Server SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); @@ -130,7 +130,7 @@ TEST_CASE("QUICHandshakeProtocol 1-RTT", "[quic]") SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - QUICHandshakeProtocol *server = new QUICCryptoTls(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); CHECK(client->initialize_key_materials(0x8394c8f03e515708)); CHECK(server->initialize_key_materials(0x8394c8f03e515708)); From aea4c6c2c9109745554733ceb17c0b754ead3ab0 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 21 Feb 2018 11:26:15 +0900 Subject: [PATCH 0392/1313] Prevent logs for unexpected events on EVENT_IMMEDIATE --- iocore/net/QUICNetVConnection.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index cb0beae5473..1e10a76e3bb 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -612,6 +612,9 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) this->_close_closing_timeout(data); this->_switch_to_close_state(); break; + case EVENT_IMMEDIATE: + // nothing to do (maybe) + break; default: QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); } @@ -638,6 +641,9 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) this->_close_closing_timeout(data); this->_switch_to_close_state(); break; + case EVENT_IMMEDIATE: + // nothing to do (maybe) + break; default: QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); } From f8a968bc780fc698ae9b909f61f8c52fdc459a00 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 22 Feb 2018 10:20:45 +0900 Subject: [PATCH 0393/1313] Set max_early_data to 0xFFFFFFFF --- iocore/net/QUICNetProcessor.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 1ab0027e27d..3e9410a18f7 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -85,6 +85,7 @@ QUICNetProcessor::start(int, size_t stacksize) SSL_CTX_set_max_proto_version(this->_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_alpn_select_cb(this->_ssl_ctx, QUIC::ssl_select_next_protocol, nullptr); + SSL_CTX_set_max_early_data(this->_ssl_ctx, UINT32_C(0xFFFFFFFF)); SSL_CTX_add_custom_ext(this->_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, From 54853e1453af9f4a3dec67a7cf829835093427e6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 22 Feb 2018 12:21:53 +0900 Subject: [PATCH 0394/1313] clang-format --- iocore/net/QUICNetProcessor.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 3e9410a18f7..3d7e470da1f 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -85,7 +85,7 @@ QUICNetProcessor::start(int, size_t stacksize) SSL_CTX_set_max_proto_version(this->_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_alpn_select_cb(this->_ssl_ctx, QUIC::ssl_select_next_protocol, nullptr); - SSL_CTX_set_max_early_data(this->_ssl_ctx, UINT32_C(0xFFFFFFFF)); + SSL_CTX_set_max_early_data(this->_ssl_ctx, UINT32_C(0xFFFFFFFF)); SSL_CTX_add_custom_ext(this->_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, From 1f2013e10574380c1c2880d4e2bcf4f46c9730b1 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 22 Feb 2018 10:02:51 +0800 Subject: [PATCH 0395/1313] QUIC: Fix Unexpected event on state_connection_closing --- iocore/net/QUICNetVConnection.cc | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 1e10a76e3bb..25d92cd5705 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -612,11 +612,9 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) this->_close_closing_timeout(data); this->_switch_to_close_state(); break; - case EVENT_IMMEDIATE: - // nothing to do (maybe) - break; default: QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); + ink_assert(false); } return EVENT_DONE; @@ -641,11 +639,9 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) this->_close_closing_timeout(data); this->_switch_to_close_state(); break; - case EVENT_IMMEDIATE: - // nothing to do (maybe) - break; default: QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); + ink_assert(false); } return EVENT_DONE; @@ -1335,9 +1331,18 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) } this->remove_from_active_queue(); + this->set_inactivity_timeout(0); QUICConDebug("Enter state_connection_closing"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); + + // This states SHOULD persist for three times the + // current Retransmission Timeout (RTO) interval as defined in + // [QUIC-RECOVERY]. + + // TODO The closing period should be obtained from QUICLossDetector since it is the only component that knows the RTO interval. + // Use 3 times kkMinRTOTimeout(200ms) for now. + this->_schedule_closing_timeout(HRTIME_MSECONDS(3 * 200)); } void @@ -1351,6 +1356,10 @@ QUICNetVConnection::_switch_to_draining_state(QUICConnectionErrorUPtr error) } else { QUICConDebug("Reason was not provided"); } + + this->remove_from_active_queue(); + this->set_inactivity_timeout(0); + QUICConDebug("Enter state_connection_draining"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_draining); From 6706e60b8c49c64df3c42d4ff415d2986bee02af Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 22 Feb 2018 12:34:28 +0900 Subject: [PATCH 0396/1313] Return CreationResult::IGNOER when keys for decryption are not ready --- iocore/net/QUICNetVConnection.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 25d92cd5705..bae9e019d1f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1181,7 +1181,7 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) // FIXME: unordered packet should be buffered and retried udp_packet->free(); if (this->_packet_recv_queue.size > 0) { - result = QUICPacketCreationResult::SUCCESS; + result = QUICPacketCreationResult::IGNORED; } this_ethread()->schedule_in_local(this, HRTIME_MSECONDS(10), QUIC_EVENT_PACKET_READ_READY); } else if (result == QUICPacketCreationResult::IGNORED) { From 4f0255b9c6ec46c1c775a25da452f70e25465a89 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 23 Feb 2018 09:25:33 +0800 Subject: [PATCH 0397/1313] QUIC: remove useless scheduling event --- iocore/net/QUICNetVConnection.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index bae9e019d1f..6df7a20effa 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1183,7 +1183,6 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) if (this->_packet_recv_queue.size > 0) { result = QUICPacketCreationResult::IGNORED; } - this_ethread()->schedule_in_local(this, HRTIME_MSECONDS(10), QUIC_EVENT_PACKET_READ_READY); } else if (result == QUICPacketCreationResult::IGNORED) { QUICConDebug("Ignore to decrypt the packet"); From 73d0ad369de49adf1480c08255594f1a9cdaeb19 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 23 Feb 2018 11:13:29 +0900 Subject: [PATCH 0398/1313] Don't decrypt packets that have unsupported versions --- iocore/net/QUICNetVConnection.cc | 34 +++++++------ iocore/net/quic/QUICPacket.cc | 87 ++++++++++++++++++-------------- iocore/net/quic/QUICTypes.h | 1 + 3 files changed, 68 insertions(+), 54 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6df7a20effa..e181afc9ad7 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -528,7 +528,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) error = QUICErrorUPtr(new QUICNoError()); } else if (result == QUICPacketCreationResult::FAILED) { error = QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); - } else if (result == QUICPacketCreationResult::SUCCESS) { + } else if (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::UNSUPPORTED) { error = this->_state_handshake_process_packet(std::move(packet)); } @@ -1175,26 +1175,30 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) written += b->read_avail(); b = b->next.get(); } + udp_packet->free(); + quic_packet = this->_packet_factory.create(std::move(pkt), written, this->largest_received_packet_number(), result); - if (result == QUICPacketCreationResult::NOT_READY) { + switch (result) { + case QUICPacketCreationResult::NOT_READY: QUICConDebug("Not ready to decrypt the packet"); // FIXME: unordered packet should be buffered and retried - udp_packet->free(); if (this->_packet_recv_queue.size > 0) { result = QUICPacketCreationResult::IGNORED; } - } else if (result == QUICPacketCreationResult::IGNORED) { - QUICConDebug("Ignore to decrypt the packet"); - - udp_packet->free(); - } else { - udp_packet->free(); - if (result == QUICPacketCreationResult::SUCCESS) { - QUICConDebug("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), - quic_packet->packet_number(), quic_packet->size()); - } else { - QUICConDebug("Failed to decrypt the packet"); - } + break; + case QUICPacketCreationResult::IGNORED: + QUICConDebug("Ignored"); + break; + case QUICPacketCreationResult::UNSUPPORTED: + QUICConDebug("Unsupported version"); + break; + case QUICPacketCreationResult::SUCCESS: + QUICConDebug("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), + quic_packet->packet_number(), quic_packet->size()); + break; + default: + QUICConDebug("Failed to decrypt the packet"); + break; } return quic_packet; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index bb505f6099c..a085d9b3e38 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -663,29 +663,52 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ QUICPacketHeader *header = QUICPacketHeader::load(buf.release(), len, base_packet_number); - switch (header->type()) { - case QUICPacketType::VERSION_NEGOTIATION: - case QUICPacketType::STATELESS_RESET: - // These packets are unprotected. Just copy the payload + if (header->has_version() && !QUICTypeUtil::is_supported_version(header->version())) { + // We can't decrypt packets that have unknown versions + result = QUICPacketCreationResult::UNSUPPORTED; memcpy(plain_txt.get(), header->payload(), header->payload_size()); plain_txt_len = header->payload_size(); - result = QUICPacketCreationResult::SUCCESS; - break; - case QUICPacketType::PROTECTED: - if (this->_hs_protocol->is_key_derived()) { - if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->size(), header->key_phase())) { - result = QUICPacketCreationResult::SUCCESS; + } else { + switch (header->type()) { + case QUICPacketType::VERSION_NEGOTIATION: + case QUICPacketType::STATELESS_RESET: + // 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->_hs_protocol->is_key_derived()) { + if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + header->key_phase())) { + result = QUICPacketCreationResult::SUCCESS; + } else { + result = QUICPacketCreationResult::FAILED; + } } else { - result = QUICPacketCreationResult::FAILED; + result = QUICPacketCreationResult::NOT_READY; } - } else { - result = QUICPacketCreationResult::NOT_READY; - } - break; - case QUICPacketType::INITIAL: - if (!this->_hs_protocol->is_key_derived()) { - if (QUICTypeUtil::is_supported_version(header->version())) { + break; + case QUICPacketType::INITIAL: + if (!this->_hs_protocol->is_key_derived()) { + if (QUICTypeUtil::is_supported_version(header->version())) { + if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + QUICKeyPhase::CLEARTEXT)) { + result = QUICPacketCreationResult::SUCCESS; + } else { + result = QUICPacketCreationResult::FAILED; + } + } else { + result = QUICPacketCreationResult::SUCCESS; + } + } else { + result = QUICPacketCreationResult::IGNORED; + } + break; + case QUICPacketType::HANDSHAKE: + if (!this->_hs_protocol->is_key_derived()) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { @@ -694,31 +717,17 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ result = QUICPacketCreationResult::FAILED; } } else { - result = QUICPacketCreationResult::SUCCESS; - } - } else { - result = QUICPacketCreationResult::IGNORED; - } - break; - case QUICPacketType::HANDSHAKE: - if (!this->_hs_protocol->is_key_derived()) { - if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { - result = QUICPacketCreationResult::SUCCESS; - } else { - result = QUICPacketCreationResult::FAILED; + result = QUICPacketCreationResult::IGNORED; } - } else { - result = QUICPacketCreationResult::IGNORED; + break; + default: + result = QUICPacketCreationResult::FAILED; + break; } - break; - default: - result = QUICPacketCreationResult::FAILED; - break; } QUICPacket *packet = nullptr; - if (result == QUICPacketCreationResult::SUCCESS) { + if (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::UNSUPPORTED) { packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(header, std::move(plain_txt), plain_txt_len); } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 8ab52481db4..5f01a084884 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -121,6 +121,7 @@ enum class QUICPacketCreationResult { FAILED, NOT_READY, IGNORED, + UNSUPPORTED, }; enum class QUICErrorClass { From 532e9dd14d1c3c44b58d4853afaed2d2dd1af045 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 23 Feb 2018 10:22:47 +0800 Subject: [PATCH 0399/1313] QUIC: Send close frame packet when we are in close period --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 06d713949bb..59677de2a6c 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -288,6 +288,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_connection_established_process_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_common_receive_packet(); + QUICErrorUPtr _state_connection_closing_and_draining_receive_packet(); QUICErrorUPtr _state_common_send_packet(); QUICErrorUPtr _state_closing_send_packet(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e181afc9ad7..708a3e09bb9 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -602,7 +602,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: - error = this->_state_common_receive_packet(); + error = this->_state_connection_closing_and_draining_receive_packet(); break; case QUIC_EVENT_PACKET_WRITE_READY: this->_close_packet_write_ready(data); @@ -628,7 +628,7 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: - error = this->_state_common_receive_packet(); + error = this->_state_connection_closing_and_draining_receive_packet(); break; case QUIC_EVENT_PACKET_WRITE_READY: // Do not send any packets in this state. @@ -876,6 +876,24 @@ QUICNetVConnection::_state_common_receive_packet() return error; } +QUICErrorUPtr +QUICNetVConnection::_state_connection_closing_and_draining_receive_packet() +{ + QUICPacketCreationResult result; + QUICPacketUPtr packet = this->_dequeue_recv_packet(result); + if (result == QUICPacketCreationResult::SUCCESS) { + this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); + this->_schedule_packet_write_ready(); + } + + if (this->_packet_recv_queue.size > 0) { + // FIXME: scheduling new event to ensure the closed frame could be sent. + this_ethread()->schedule_in_local(this, HRTIME_MSECONDS(10), QUIC_EVENT_PACKET_READ_READY); + } + + return QUICErrorUPtr(new QUICNoError()); +} + QUICErrorUPtr QUICNetVConnection::_state_common_send_packet() { From 29cb75274ebb23ed37d1c370c70a9468a6231e24 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 23 Feb 2018 13:40:18 +0800 Subject: [PATCH 0400/1313] QUIC: clean the inactive timeout in closing and draining state --- iocore/net/QUICNetVConnection.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 708a3e09bb9..50f4dc284b1 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -522,6 +522,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) switch (event) { case QUIC_EVENT_PACKET_READ_READY: { QUICPacketCreationResult result; + net_activity(this, this_ethread()); do { QUICPacketUPtr packet = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::NOT_READY) { @@ -828,6 +829,7 @@ QUICNetVConnection::_state_common_receive_packet() QUICPacketCreationResult result; // Receive a QUIC packet + net_activity(this, this_ethread()); do { QUICPacketUPtr p = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::FAILED) { @@ -838,8 +840,6 @@ QUICNetVConnection::_state_common_receive_packet() continue; } - net_activity(this, this_ethread()); - // Check connection migration if (this->_handshake_handler->is_completed() && p->connection_id() != this->_quic_connection_id) { for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { @@ -1182,8 +1182,6 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) } } - net_activity(this, this_ethread()); - // Create a QUIC packet ats_unique_buf pkt = ats_unique_malloc(udp_packet->getPktLength()); IOBufferBlock *b = udp_packet->getIOBlockChain(); From 4925d9af45ee240e73f725acad384e966a4e5720 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 27 Feb 2018 14:29:54 +0900 Subject: [PATCH 0401/1313] Notify packet arrival with QUIC_EVENT_PACKET_READ_READY Calling schedule_imm without specifying event implicitly use EVENT_IMMEDIATE, and it confuses QUICNetVC because the event is also used for inactive timeout. --- iocore/net/QUICNet.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index ecbc546a774..68bcc9e7c5c 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -22,6 +22,7 @@ */ #include "P_Net.h" +#include "quic/QUICEvents.h" ClassAllocator quicPollEventAllocator("quicPollEvent"); @@ -74,7 +75,7 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) case QUICPacketType::INITIAL: vc->read.triggered = 1; vc->handle_received_packet(p); - this->mutex->thread_holding->schedule_imm(vc); + this->mutex->thread_holding->schedule_imm(vc, QUIC_EVENT_PACKET_READ_READY); return; case QUICPacketType::ZERO_RTT_PROTECTED: // TODO:: do something ? From 8a7696cacff20c68b3f04345b88239e03e2e135b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 27 Feb 2018 15:40:00 +0900 Subject: [PATCH 0402/1313] Ignore 0-RTT Protected packets for now --- iocore/net/quic/QUICPacket.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index a085d9b3e38..a14140d0542 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -720,6 +720,10 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ result = QUICPacketCreationResult::IGNORED; } break; + case QUICPacketType::ZERO_RTT_PROTECTED: + // TODO Support 0-RTT + result = QUICPacketCreationResult::IGNORED; + break; default: result = QUICPacketCreationResult::FAILED; break; From 4f68ac7e5f293e2bd1afa9af3bad79b22028e817 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 27 Feb 2018 13:53:01 +0800 Subject: [PATCH 0403/1313] QUIC: Ensure only first initial packet could enter QVC::acceptEvent --- iocore/net/QUICNet.cc | 10 ++++++---- iocore/net/QUICPacketHandler.cc | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index 68bcc9e7c5c..e153c35eeb8 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -73,10 +73,12 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) ptype = static_cast(buf[0] & 0x7f); switch (ptype) { case QUICPacketType::INITIAL: - vc->read.triggered = 1; - vc->handle_received_packet(p); - this->mutex->thread_holding->schedule_imm(vc, QUIC_EVENT_PACKET_READ_READY); - return; + if (!vc->read.triggered) { + vc->read.triggered = 1; + vc->handle_received_packet(p); + vc->handleEvent(QUIC_EVENT_PACKET_READ_READY, nullptr); + return; + } case QUICPacketType::ZERO_RTT_PROTECTED: // TODO:: do something ? // break; diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 0526a9cc736..49ae71198eb 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -213,7 +213,6 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) vc->action_ = *this->action_; vc->set_is_transparent(this->opt.f_inbound_transparent); vc->set_context(NET_VCONNECTION_IN); - vc->read.triggered = 1; vc->start(this->_ssl_ctx); vc->options.ip_proto = NetVCOptions::USE_UDP; vc->options.ip_family = udp_packet->from.sa.sa_family; From 1eba7ea33c0a710bb27828329dac55393525fd93 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 22 Feb 2018 17:19:16 +0800 Subject: [PATCH 0404/1313] QUIC: Insert client selected connection id into ctable --- iocore/net/QUICNetVConnection.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 50f4dc284b1..f123c43d8f9 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -74,6 +74,7 @@ QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, if (ctable) { this->_ctable = ctable; this->_ctable->insert(this->_quic_connection_id, this); + this->_ctable->insert(this->_original_quic_connection_id, this); } QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(this->_original_quic_connection_id), static_cast(this->_quic_connection_id)); From 358718497de8dcd6ded3a9d1e0f9206fd7bbef83 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 2 Mar 2018 14:45:27 +0900 Subject: [PATCH 0405/1313] Add debug log in QUICLossDetector::_detect_lost_packets() --- iocore/net/quic/QUICLossDetector.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 560917670c8..eae580da86b 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -351,8 +351,13 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num ink_hrtime time_since_sent = Thread::get_hrtime() - unacked.second->time; uint64_t packet_delta = largest_acked_packet_number - unacked.second->packet_number; if (time_since_sent > delay_until_lost) { + QUICLDDebug("Lost: time since sent is too long (sent=%" PRId64 ", delay=%lf, fraction=%lf, lrtt=%" PRId64 ", srtt=%" PRId64 + ")", + time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, this->_smoothed_rtt); lost_packets.insert({unacked.first, *unacked.second}); } else if (packet_delta > this->_reordering_threshold) { + QUICLDDebug("Lost: packet delta is too large (largest=%" PRId64 " unacked=%" PRId64 " threshold=%" PRId32 ")", + largest_acked_packet_number, unacked.second->packet_number, this->_reordering_threshold); lost_packets.insert({unacked.first, *unacked.second}); } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) { this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent; From e6b552872ba68acf235577b656752af7b2278713 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 1 Mar 2018 20:57:54 +0900 Subject: [PATCH 0406/1313] Clear SSL_OP_ENABLE_MIDDLEBOX_COMPAT option of OpenSSL --- iocore/net/QUICNetProcessor.cc | 3 +++ iocore/net/quic/test/test_QUICHandshake.cc | 2 ++ iocore/net/quic/test/test_QUICHandshakeProtocol.cc | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 3d7e470da1f..ed329b4c9a2 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -84,6 +84,9 @@ QUICNetProcessor::start(int, size_t stacksize) SSL_CTX_set_min_proto_version(this->_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(this->_ssl_ctx, TLS1_3_VERSION); + // FIXME: OpenSSL (1.1.1-alpha) enable this option by default. But this shoule be removed when OpenSSL disable this by default. + SSL_CTX_clear_options(this->_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + SSL_CTX_set_alpn_select_cb(this->_ssl_ctx, QUIC::ssl_select_next_protocol, nullptr); SSL_CTX_set_max_early_data(this->_ssl_ctx, UINT32_C(0xFFFFFFFF)); SSL_CTX_add_custom_ext(this->_ssl_ctx, QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID, diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc index 15a342d36b3..daada593a4a 100644 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -39,6 +39,7 @@ TEST_CASE("1-RTT handshake ", "[quic]") SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); QUICConnectionId client_conn_id = 0x12345; @@ -50,6 +51,7 @@ TEST_CASE("1-RTT handshake ", "[quic]") SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 789dd0f386c..07360678e1d 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -62,12 +62,14 @@ TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]") SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); // Server SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); @@ -120,12 +122,14 @@ TEST_CASE("QUICHandshakeProtocol 1-RTT", "[quic]") SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); // Server SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); From 1d7d681cd5a6da686d88f066ce3897ad1a0b8c53 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 2 Mar 2018 14:13:07 +0800 Subject: [PATCH 0407/1313] QUIC: Ensure switch to closed state once --- iocore/net/QUICNetVConnection.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index f123c43d8f9..fcf57cf2d25 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -465,13 +465,16 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) break; case QUICFrameType::APPLICATION_CLOSE: case QUICFrameType::CONNECTION_CLOSE: - if (this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closing) || + if (this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closed) || this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_draining)) { - this->_switch_to_close_state(); - } else { - this->_switch_to_draining_state(QUICConnectionErrorUPtr( - new QUICConnectionError(std::static_pointer_cast(frame)->error_code()))); + return error; } + + // 7.9.1. Closing and Draining Connection States + // An endpoint MAY transition from the closing period to the draining period if it can confirm that its peer is also closing or + // draining. Receiving a closing frame is sufficient confirmation, as is receiving a stateless reset. + this->_switch_to_draining_state(QUICConnectionErrorUPtr( + new QUICConnectionError(std::static_pointer_cast(frame)->error_code()))); break; default: QUICConDebug("Unexpected frame type: %02x", static_cast(frame->type())); From b3759a9addf8709c0552cbc282f048f8bbda8614 Mon Sep 17 00:00:00 2001 From: Jordy Liu Date: Sat, 3 Mar 2018 17:39:14 +0800 Subject: [PATCH 0408/1313] Using MT_hashtable for VC lookup. --- iocore/net/P_QUICPacketHandler.h | 2 +- iocore/net/QUICPacketHandler.cc | 9 ++++-- iocore/net/quic/QUICConfig.cc | 10 ++++++- iocore/net/quic/QUICConfig.h | 3 +- iocore/net/quic/QUICConnectionTable.cc | 39 +++++++++++++++----------- iocore/net/quic/QUICConnectionTable.h | 14 +++++---- mgmt/RecordsConfig.cc | 2 ++ 7 files changed, 52 insertions(+), 27 deletions(-) diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 70b3048adc2..886ce707fdf 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -74,7 +74,7 @@ class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler private: void _recv_packet(int event, UDPPacket *udp_packet) override; - QUICConnectionTable _ctable; + QUICConnectionTable *_ctable = nullptr; SSL_CTX *_ssl_ctx; }; diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 49ae71198eb..256100514e3 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -91,10 +91,15 @@ QUICPacketHandler::_read_connection_id(IOBufferBlock *block) QUICPacketHandlerIn::QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, SSL_CTX *ctx) : NetAccept(opt), _ssl_ctx(ctx) { this->mutex = new_ProxyMutex(); + // create Connection Table + QUICConfig::scoped_config params; + _ctable = new QUICConnectionTable(params->connection_table_size()); } QUICPacketHandlerIn::~QUICPacketHandlerIn() { + // TODO: clear all values before destory the table. + delete _ctable; } NetProcessor * @@ -175,7 +180,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) } QUICConnection *qc = - this->_ctable.lookup(reinterpret_cast(block->buf()), {udp_packet->from, udp_packet->to, SOCK_DGRAM}); + this->_ctable->lookup(reinterpret_cast(block->buf()), {udp_packet->from, udp_packet->to, SOCK_DGRAM}); vc = static_cast(qc); // 7.1. Matching Packets to Connections @@ -204,7 +209,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // Create a new NetVConnection QUICConnectionId original_cid = this->_read_connection_id(block); vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); - vc->init(original_cid, udp_packet->getConnection(), this, &this->_ctable); + vc->init(original_cid, udp_packet->getConnection(), this, this->_ctable); vc->id = net_next_connection_number(); vc->con.move(con); vc->submit_time = Thread::get_hrtime(); diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index a3ff6eccff6..8bcf9c99c4e 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -25,7 +25,8 @@ #include -int QUICConfig::_config_id = 0; +int QUICConfig::_config_id = 0; +int QUICConfigParams::_connection_table_size = 65521; // // QUICConfigParams @@ -38,6 +39,7 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_initial_max_data, "proxy.config.quic.initial_max_data"); REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data, "proxy.config.quic.initial_max_stream_data"); REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); + REC_EstablishStaticConfigInt32(_connection_table_size, "proxy.config.quic.connection_table.size"); } uint32_t @@ -58,6 +60,12 @@ QUICConfigParams::server_id() const return this->_server_id; } +int +QUICConfigParams::connection_table_size() +{ + return _connection_table_size; +} + uint32_t QUICConfigParams::initial_max_data() const { diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 0371774f096..a7a4f60ecc2 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -24,7 +24,6 @@ #pragma once #include "ProxyConfig.h" - class QUICConfigParams : public ConfigInfo { public: @@ -39,6 +38,7 @@ class QUICConfigParams : public ConfigInfo uint32_t initial_max_stream_id_uni_in() const; uint32_t initial_max_stream_id_uni_out() const; uint32_t server_id() const; + static int connection_table_size(); private: // FIXME Fill appropriate default values in RecordsConfig.cc @@ -47,6 +47,7 @@ class QUICConfigParams : public ConfigInfo uint32_t _initial_max_data = 0; uint32_t _initial_max_stream_data = 0; uint32_t _server_id = 0; + static int _connection_table_size; uint32_t _initial_max_stream_id_bidi_in = 100; uint32_t _initial_max_stream_id_bidi_out = 101; diff --git a/iocore/net/quic/QUICConnectionTable.cc b/iocore/net/quic/QUICConnectionTable.cc index eb048d7da7f..5f860b046fc 100644 --- a/iocore/net/quic/QUICConnectionTable.cc +++ b/iocore/net/quic/QUICConnectionTable.cc @@ -23,29 +23,35 @@ #include "QUICConnectionTable.h" -int +QUICConnectionTable::~QUICConnectionTable() +{ + // TODO: clear all values. +} + +QUICConnection * QUICConnectionTable::insert(QUICConnectionId cid, QUICConnection *connection) { - this->_connections.put(cid, connection); - // if (this->_cids.get(connection->endpoint()) == nullptr) { - // this->_cids.put(connection->endpoint(), cid); - // } - return 0; + SCOPED_MUTEX_LOCK(lock, _connections.lock_for_key(cid), this_ethread()); + // To check whether the return value is nullptr by caller in case memory leak. + // The return value isn't nullptr, the new value will take up the slot and return old value. + return _connections.insert_entry(cid, connection); } void QUICConnectionTable::erase(QUICConnectionId cid, QUICConnection *connection) { - QUICConnection *qc = this->_connections.get(cid); - if (qc == nullptr) { - return; + SCOPED_MUTEX_LOCK(lock, _connections.lock_for_key(cid), this_ethread()); + QUICConnection *ret_connection = _connections.remove_entry(cid); + if (ret_connection) { + ink_assert(ret_connection == connection); } - ink_assert(qc == connection); - Debug("quic_ctable", "ctable erase cid: [%" PRIx64 "] ", static_cast(cid)); - // if (this->_cids.get(connection->endpoint(), connection->connection_id()) == cid) { - // this->_cids.put(connection->endpoint(), nullptr); - // } - this->_connections.put(cid, nullptr); +} + +QUICConnection * +QUICConnectionTable::erase(QUICConnectionId cid) +{ + SCOPED_MUTEX_LOCK(lock, _connections.lock_for_key(cid), this_ethread()); + return _connections.remove_entry(cid); } QUICConnection * @@ -59,5 +65,6 @@ QUICConnectionTable::lookup(const uint8_t *packet, QUICFiveTuple endpoint) // cid = this->_cids.get(endpoint); ink_assert(false); } - return this->_connections.get(cid); + SCOPED_MUTEX_LOCK(lock, _connections.lock_for_key(cid), this_ethread()); + return _connections.lookup_entry(cid); } diff --git a/iocore/net/quic/QUICConnectionTable.h b/iocore/net/quic/QUICConnectionTable.h index 6bc4b75cd63..0ead233d6cf 100644 --- a/iocore/net/quic/QUICConnectionTable.h +++ b/iocore/net/quic/QUICConnectionTable.h @@ -25,7 +25,7 @@ #include "QUICTypes.h" #include "QUICConnection.h" -#include "ts/Map.h" +#include "ts/MT_hashtable.h" class QUICFiveTuple { @@ -43,12 +43,15 @@ class QUICFiveTuple class QUICConnectionTable { public: + QUICConnectionTable(int hash_table_size = 65521) : _connections(hash_table_size) {} + ~QUICConnectionTable(); /* * Insert an entry * - * Return 1 if it is the only connection or the first connection from the endpoint. + * Return zero if it is the only connection or the first connection from the endpoint. + * Caller is responsible for memory management. */ - int insert(QUICConnectionId cid, QUICConnection *connection); + QUICConnection *insert(QUICConnectionId cid, QUICConnection *connection); /* * Remove an entry @@ -56,6 +59,7 @@ class QUICConnectionTable * Fails if CID is not associated to a specified connection */ void erase(QUICConnectionId cid, QUICConnection *connection); + QUICConnection *erase(QUICConnectionId cid); /* * Lookup QUICConnection @@ -65,7 +69,5 @@ class QUICConnectionTable QUICConnection *lookup(const uint8_t *packet, QUICFiveTuple endpoint); private: - // FIXME Use another map impl. that has good support for concurrent access - Map _connections; - // Map _cids; + MTHashTable _connections; }; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index b6b3172f278..4f39a424620 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1326,6 +1326,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.server_id", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.connection_table.size", RECD_INT, "65521", RECU_RESTART_TS, RR_NULL, RECC_INT, "[1-536870909]", RECA_NULL} + , //# Add LOCAL Records Here {RECT_LOCAL, "proxy.local.incoming_ip_to_bind", RECD_STRING, nullptr, RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL} From c3af882434fd279e82e5534a55f2faded535e957 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 5 Mar 2018 08:31:34 +0800 Subject: [PATCH 0409/1313] QUIC: Mem leaking with QUICPacketHeader --- iocore/net/quic/QUICPacket.cc | 81 ++++++++++++++++++----------------- iocore/net/quic/QUICPacket.h | 78 +++++++++++++++++++++++---------- 2 files changed, 98 insertions(+), 61 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index a14140d0542..a76d068243a 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -61,52 +61,54 @@ QUICPacketHeader::packet_size() const return this->_buf_len; } -QUICPacketHeader * +QUICPacketHeaderUPtr QUICPacketHeader::load(const uint8_t *buf, size_t len, QUICPacketNumber base) { + QUICPacketHeaderUPtr header = QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header); if (QUICTypeUtil::has_long_header(buf)) { QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); new (long_header) QUICPacketLongHeader(buf, len, base); - return long_header; + header = QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); } else { QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); new (short_header) QUICPacketShortHeader(buf, len, base); - return short_header; + header = QUICPacketHeaderUPtr(short_header, &QUICPacketHeaderDeleter::delete_short_header); } + return std::move(header); } -QUICPacketHeader * +QUICPacketHeaderUPtr QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len) { QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); new (long_header) QUICPacketLongHeader(type, connection_id, packet_number, base_packet_number, version, std::move(payload), len); - return long_header; + return QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); } -QUICPacketHeader * +QUICPacketHeaderUPtr QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len) { QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); new (short_header) QUICPacketShortHeader(type, key_phase, packet_number, base_packet_number, std::move(payload), len); - return short_header; + return QUICPacketHeaderUPtr(short_header, &QUICPacketHeaderDeleter::delete_short_header); } -QUICPacketHeader * +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) { QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); new (short_header) QUICPacketShortHeader(type, key_phase, connection_id, packet_number, base_packet_number, std::move(payload), len); - return short_header; + return QUICPacketHeaderUPtr(short_header, &QUICPacketHeaderDeleter::delete_short_header); } -QUICPacketHeader * +QUICPacketHeaderUPtr QUICPacketHeader::clone() const { - return nullptr; + return QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header); } // @@ -473,16 +475,20 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const // QUICPacket // -QUICPacket::QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len) +QUICPacket::QUICPacket() { - this->_header = header; +} + +QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len) +{ + this->_header = std::move(header); this->_payload = std::move(payload); this->_payload_size = payload_len; } -QUICPacket::QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len, bool retransmittable) +QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable) { - this->_header = header; + this->_header = std::move(header); this->_payload = std::move(payload); this->_payload_size = payload_len; this->_is_retransmittable = retransmittable; @@ -490,11 +496,7 @@ QUICPacket::QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t QUICPacket::~QUICPacket() { - if (this->_header->has_version()) { - quicPacketLongHeaderAllocator.free(static_cast(this->_header)); - } else { - quicPacketShortHeaderAllocator.free(static_cast(this->_header)); - } + this->_header = nullptr; } /** @@ -522,7 +524,7 @@ QUICPacket::packet_number() const const QUICPacketHeader * QUICPacket::header() const { - return this->_header; + return this->_header.get(); } const uint8_t * @@ -661,7 +663,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ ats_unique_buf plain_txt = ats_unique_malloc(max_plain_txt_len); size_t plain_txt_len = 0; - QUICPacketHeader *header = QUICPacketHeader::load(buf.release(), len, base_packet_number); + QUICPacketHeaderUPtr header = QUICPacketHeader::load(buf.release(), len, base_packet_number); if (header->has_version() && !QUICTypeUtil::is_supported_version(header->version())) { // We can't decrypt packets that have unknown versions @@ -733,7 +735,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ QUICPacket *packet = nullptr; if (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::UNSUPPORTED) { packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(header, std::move(plain_txt), plain_txt_len); + new (packet) QUICPacket(std::move(header), std::move(plain_txt), plain_txt_len); } return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); @@ -752,30 +754,31 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se p += n; } - QUICPacketHeader *header = + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), packet_sent_by_client->packet_number(), base_packet_number, 0x00, std::move(versions), len); - return QUICPacketFactory::_create_unprotected_packet(header); + return QUICPacketFactory::_create_unprotected_packet(std::move(header)); } QUICPacketUPtr QUICPacketFactory::create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len) { - QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::INITIAL, connection_id, this->_packet_number_generator.next(), - base_packet_number, version, std::move(payload), len); - return this->_create_encrypted_packet(header, true); + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::INITIAL, connection_id, this->_packet_number_generator.next(), base_packet_number, + version, std::move(payload), len); + return this->_create_encrypted_packet(std::move(header), true); } QUICPacketUPtr QUICPacketFactory::create_handshake_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - QUICPacketHeader *header = + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, connection_id, this->_packet_number_generator.next(), base_packet_number, this->_version, std::move(payload), len); - return this->_create_encrypted_packet(header, retransmittable); + return this->_create_encrypted_packet(std::move(header), retransmittable); } QUICPacketUPtr @@ -783,10 +786,10 @@ QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id ats_unique_buf payload, size_t len, bool retransmittable) { // TODO Key phase should be picked up from QUICHandshakeProtocol, probably - QUICPacketHeader *header = + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, connection_id, this->_packet_number_generator.next(), base_packet_number, std::move(payload), len); - return this->_create_encrypted_packet(header, retransmittable); + return this->_create_encrypted_packet(std::move(header), retransmittable); } QUICPacketUPtr @@ -807,26 +810,26 @@ QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, memcpy(naked_payload + payload_len - 16, stateless_reset_token.buf(), 16); // KeyPhase won't be used - QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::STATELESS_RESET, QUICKeyPhase::CLEARTEXT, connection_id, - random_packet_number, 0, std::move(payload), payload_len); - return QUICPacketFactory::_create_unprotected_packet(header); + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::STATELESS_RESET, QUICKeyPhase::CLEARTEXT, connection_id, + random_packet_number, 0, std::move(payload), payload_len); + return QUICPacketFactory::_create_unprotected_packet(std::move(header)); } QUICPacketUPtr -QUICPacketFactory::_create_unprotected_packet(QUICPacketHeader *header) +QUICPacketFactory::_create_unprotected_packet(QUICPacketHeaderUPtr header) { ats_unique_buf cleartext = ats_unique_malloc(2048); size_t cleartext_len = header->payload_size(); memcpy(cleartext.get(), header->payload(), cleartext_len); QUICPacket *packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(header, std::move(cleartext), cleartext_len, false); + new (packet) QUICPacket(std::move(header), std::move(cleartext), cleartext_len, false); return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } QUICPacketUPtr -QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header, bool retransmittable) +QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable) { // TODO: use pmtu of UnixNetVConnection size_t max_cipher_txt_len = 2048; @@ -837,7 +840,7 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeader *header, bool retra if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(header, std::move(cipher_txt), cipher_txt_len, retransmittable); + new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable); } return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 2e52c6e17b1..6c367c4d60c 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -37,6 +37,18 @@ #define QUIC_FIELD_OFFSET_PACKET_NUMBER 4 #define QUIC_FIELD_OFFSET_PAYLOAD 5 +class QUICPacketHeader; +class QUICPacket; +class QUICPacketLongHeader; +class QUICPacketShortHeader; + +extern ClassAllocator quicPacketAllocator; +extern ClassAllocator quicPacketLongHeaderAllocator; +extern ClassAllocator quicPacketShortHeaderAllocator; + +using QUICPacketHeaderDeleterFunc = void (*)(QUICPacketHeader *p); +using QUICPacketHeaderUPtr = std::unique_ptr; + class QUICPacketHeader { public: @@ -79,7 +91,7 @@ class QUICPacketHeader */ virtual void store(uint8_t *buf, size_t *len) const = 0; - QUICPacketHeader *clone() const; + QUICPacketHeaderUPtr clone() const; virtual bool has_key_phase() const = 0; virtual bool has_connection_id() const = 0; @@ -92,32 +104,32 @@ class QUICPacketHeader * * This creates either a QUICPacketShortHeader or a QUICPacketLongHeader. */ - static QUICPacketHeader *load(const uint8_t *buf, size_t len, QUICPacketNumber base); + static QUICPacketHeaderUPtr load(const uint8_t *buf, size_t len, QUICPacketNumber base); /* * Build a QUICPacketHeader * * This creates a QUICPacketLongHeader. */ - static QUICPacketHeader *build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); + static QUICPacketHeaderUPtr build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); /* * Build a QUICPacketHeader * * This creates a QUICPacketShortHeader that contains a ConnectionID. */ - static QUICPacketHeader *build(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len); + static QUICPacketHeaderUPtr build(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len); /* * Build a QUICPacketHeader * * This creates a QUICPacketShortHeader that doesn't contain a ConnectionID.. */ - static QUICPacketHeader *build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId connection_id, - QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, - size_t len); + 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); protected: QUICPacketHeader(){}; @@ -188,10 +200,36 @@ class QUICPacketShortHeader : public QUICPacketHeader QUICPacketShortHeaderType _packet_number_type = QUICPacketShortHeaderType::UNINITIALIZED; }; +class QUICPacketHeaderDeleter +{ +public: + static void + delete_null_header(QUICPacketHeader *header) + { + ink_assert(header == nullptr); + } + + static void + delete_long_header(QUICPacketHeader *header) + { + QUICPacketLongHeader *long_header = dynamic_cast(header); + ink_assert(long_header != nullptr); + quicPacketLongHeaderAllocator.free(long_header); + } + + static void + delete_short_header(QUICPacketHeader *header) + { + QUICPacketShortHeader *short_header = dynamic_cast(header); + ink_assert(short_header != nullptr); + quicPacketShortHeaderAllocator.free(short_header); + } +}; + class QUICPacket { public: - QUICPacket(){}; + QUICPacket(); /* * Creates a QUICPacket with a QUICPacketHeader and a buffer that contains payload @@ -199,7 +237,7 @@ class QUICPacket * 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. */ - QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len); + QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len); /* * Creates a QUICPacket with a QUICPacketHeader, a buffer that contains payload and a flag that indicates whether the packet is @@ -208,7 +246,7 @@ class QUICPacket * 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. */ - QUICPacket(QUICPacketHeader *header, ats_unique_buf payload, size_t payload_len, bool retransmittable); + QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable); ~QUICPacket(); @@ -249,10 +287,10 @@ class QUICPacket LINK(QUICPacket, link); private: - QUICPacketHeader *_header; - ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); - size_t _payload_size = 0; - bool _is_retransmittable = false; + QUICPacketHeaderUPtr _header = QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header); + ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); + size_t _payload_size = 0; + bool _is_retransmittable = false; }; class QUICPacketNumberGenerator @@ -269,10 +307,6 @@ class QUICPacketNumberGenerator using QUICPacketDeleterFunc = void (*)(QUICPacket *p); using QUICPacketUPtr = std::unique_ptr; -extern ClassAllocator quicPacketAllocator; -extern ClassAllocator quicPacketLongHeaderAllocator; -extern ClassAllocator quicPacketShortHeaderAllocator; - class QUICPacketDeleter { public: @@ -313,6 +347,6 @@ class QUICPacketFactory QUICHandshakeProtocol *_hs_protocol = nullptr; QUICPacketNumberGenerator _packet_number_generator; - static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeader *header); - QUICPacketUPtr _create_encrypted_packet(QUICPacketHeader *header, bool retransmittable); + static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeaderUPtr header); + QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable); }; From 9fa21b09e8f643b8b8f6cfbcdbaaef77b0db00ce Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 5 Mar 2018 11:58:42 +0900 Subject: [PATCH 0410/1313] Don't use std::move when return --- iocore/net/quic/QUICPacket.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index a76d068243a..62cfa176d51 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -74,7 +74,7 @@ QUICPacketHeader::load(const uint8_t *buf, size_t len, QUICPacketNumber base) new (short_header) QUICPacketShortHeader(buf, len, base); header = QUICPacketHeaderUPtr(short_header, &QUICPacketHeaderDeleter::delete_short_header); } - return std::move(header); + return header; } QUICPacketHeaderUPtr From 50476f0ccab5bcbfff5efa56ca3a1232cbb7977a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 5 Mar 2018 11:58:56 +0900 Subject: [PATCH 0411/1313] Don't use raw pointer for QUICPacketHeader --- iocore/net/QUICNetVConnection.cc | 4 ++-- iocore/net/quic/QUICPacket.cc | 4 ++-- iocore/net/quic/QUICPacket.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index fcf57cf2d25..7a712d7643f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -362,8 +362,8 @@ QUICNetVConnection::retransmit_packet(const QUICPacket &packet) ink_assert(packet.type() != QUICPacketType::VERSION_NEGOTIATION && packet.type() != QUICPacketType::UNINITIALIZED); // Get payload from a header because packet.payload() is encrypted - uint16_t size = packet.header()->payload_size(); - const uint8_t *payload = packet.header()->payload(); + uint16_t size = packet.header().payload_size(); + const uint8_t *payload = packet.header().payload(); QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); uint16_t cursor = 0; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 62cfa176d51..372c24f09fb 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -521,10 +521,10 @@ QUICPacket::packet_number() const return this->_header->packet_number(); } -const QUICPacketHeader * +const QUICPacketHeader & QUICPacket::header() const { - return this->_header.get(); + return *this->_header; } const uint8_t * diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 6c367c4d60c..6992b792332 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -254,7 +254,7 @@ class QUICPacket QUICConnectionId connection_id() const; QUICPacketNumber packet_number() const; QUICVersion version() const; - const QUICPacketHeader *header() const; + const QUICPacketHeader &header() const; const uint8_t *payload() const; bool is_retransmittable() const; From 8004b3768733a9dba99b59871e6fa681e026d516 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 5 Mar 2018 14:43:09 +0900 Subject: [PATCH 0412/1313] Retransmit all handshake packets Because of this block, handshake packets might not be retransmitted actually if protected packets are already in the list. --- iocore/net/quic/QUICLossDetector.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index eae580da86b..a4f0bb2908b 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -390,9 +390,6 @@ QUICLossDetector::_retransmit_handshake_packets() std::set retransmitted_handshake_packets; for (auto &info : this->_sent_packets) { - if (!info.second->handshake) { - break; - } retransmitted_handshake_packets.insert(info.first); this->_transmitter->retransmit_packet(*info.second->packet); } From 499a39bc5f9764801f6f68f79d93a5b38ad2af04 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 6 Mar 2018 14:16:36 +0900 Subject: [PATCH 0413/1313] Read and discard early data --- iocore/net/quic/QUICTLS.cc | 17 +++++++++++++++++ iocore/net/quic/QUICTLS.h | 3 +++ 2 files changed, 20 insertions(+) diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index f6da788f908..c0a65e6a833 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -76,6 +76,10 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint int err = SSL_ERROR_NONE; if (!SSL_is_init_finished(this->_ssl)) { + if (!this->_early_data_processed && this->_read_early_data() == 1) { + Debug(tag, "Early data processed"); + this->_early_data_processed = true; + } ERR_clear_error(); int ret = SSL_do_handshake(this->_ssl); if (ret <= 0) { @@ -192,6 +196,19 @@ QUICTLS::update_key_materials() return 1; } +int +QUICTLS::_read_early_data() +{ + uint8_t early_data[8]; + size_t early_data_len = 0; + int ret = 0; + do { + ERR_clear_error(); + ret = SSL_read_early_data(this->_ssl, early_data, sizeof(early_data), &early_data_len); + } while (ret == SSL_READ_EARLY_DATA_SUCCESS); + return ret == SSL_READ_EARLY_DATA_FINISH ? 1 : 0; +} + SSL * QUICTLS::ssl_handle() { diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 20c2a668519..8aee9665817 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -80,4 +80,7 @@ class QUICTLS : public QUICHandshakeProtocol QUICPacketProtection *_client_pp = nullptr; QUICPacketProtection *_server_pp = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; + + bool _early_data_processed = false; + int _read_early_data(); }; From aea566de628622436347fbcf7080b0585ab7e7a9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 7 Mar 2018 15:42:52 +0900 Subject: [PATCH 0414/1313] Fix warnings on compile with gcc --- iocore/net/QUICNet.cc | 2 +- proxy/hq/QUICSimpleApp.cc | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index e153c35eeb8..5bc97612cf2 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -77,8 +77,8 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) vc->read.triggered = 1; vc->handle_received_packet(p); vc->handleEvent(QUIC_EVENT_PACKET_READ_READY, nullptr); - return; } + return; case QUICPacketType::ZERO_RTT_PROTECTED: // TODO:: do something ? // break; diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index 054075d6a2d..36fd7d7b5a9 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -70,7 +70,7 @@ QUICSimpleApp::main_event_handler(int event, Event *data) switch (event) { case VC_EVENT_READ_READY: - case VC_EVENT_READ_COMPLETE: { + case VC_EVENT_READ_COMPLETE: if (stream_io->is_read_avail_more_than(0)) { if (txn == nullptr) { txn = new HQClientTransaction(this->_client_session, stream_io); @@ -80,24 +80,20 @@ QUICSimpleApp::main_event_handler(int event, Event *data) } else { txn->handleEvent(event); } - break; } - } + break; case VC_EVENT_WRITE_READY: - case VC_EVENT_WRITE_COMPLETE: { + case VC_EVENT_WRITE_COMPLETE: if (txn != nullptr) { txn->handleEvent(event); } - break; - } case VC_EVENT_EOS: case VC_EVENT_ERROR: case VC_EVENT_INACTIVITY_TIMEOUT: - case VC_EVENT_ACTIVE_TIMEOUT: { + case VC_EVENT_ACTIVE_TIMEOUT: ink_assert(false); break; - } default: break; } From 387323abc755f79317576fc717a64591f78640f3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 7 Mar 2018 17:34:07 +0900 Subject: [PATCH 0415/1313] Fix a buffer overflow --- iocore/net/quic/QUICFlowController.cc | 7 ++++++- iocore/net/quic/QUICStream.cc | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 66f9de92e13..7fac445a2ca 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -37,7 +37,12 @@ QUICFlowController::current_offset() QUICOffset QUICFlowController::current_limit() { - return this->_limit; + // if _limit is 0, the limit is not set yet. + if (this->_limit) { + return this->_limit; + } else { + return UINT64_MAX; + } } int diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 87386b0ebb7..195ed4c34ad 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -463,7 +463,7 @@ QUICStream::_process_write_vio() int64_t len = 0; bool fin = false; - int64_t credit = this->_remote_flow_controller.current_limit() - this->_remote_flow_controller.current_offset(); + uint64_t credit = this->_remote_flow_controller.current_limit() - this->_remote_flow_controller.current_offset(); if (credit != 0 && max_size > credit) { max_size = credit; } From fe1335fa69998e8798e3279ab528a2d32e16994a Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 9 Mar 2018 08:25:21 +0800 Subject: [PATCH 0416/1313] QUIC: Add default TCL path --- cmd/traffic_quic/Makefile.am | 1 + iocore/net/quic/Makefile.am | 1 + proxy/hq/Makefile.am | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/traffic_quic/Makefile.am b/cmd/traffic_quic/Makefile.am index fdca0568e43..b9407788f1d 100644 --- a/cmd/traffic_quic/Makefile.am +++ b/cmd/traffic_quic/Makefile.am @@ -28,6 +28,7 @@ AM_CPPFLAGS += \ -I$(abs_top_srcdir)/proxy/http \ -I$(abs_top_srcdir)/proxy/logging \ -I$(abs_top_srcdir)/proxy/shared \ + $(TS_INCLUDES) \ @OPENSSL_INCLUDES@ traffic_quic_CPPFLAGS = \ diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index c8b0c562c5f..63636734baf 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -30,6 +30,7 @@ AM_CPPFLAGS += \ -I$(abs_top_srcdir)/proxy/hq \ -I$(abs_top_srcdir)/mgmt \ -I$(abs_top_srcdir)/mgmt/utils \ + $(TS_INCLUDES) \ @OPENSSL_INCLUDES@ noinst_LIBRARIES = libquic.a diff --git a/proxy/hq/Makefile.am b/proxy/hq/Makefile.am index dd962ab6d52..e0d900b446d 100644 --- a/proxy/hq/Makefile.am +++ b/proxy/hq/Makefile.am @@ -30,7 +30,8 @@ AM_CPPFLAGS += \ -I$(abs_top_srcdir)/proxy/http \ -I$(abs_top_srcdir)/proxy/hdrs \ -I$(abs_top_srcdir)/proxy/shared \ - -I$(abs_top_srcdir)/proxy/http/remap + -I$(abs_top_srcdir)/proxy/http/remap \ + $(TS_INCLUDES) noinst_LIBRARIES = libhq.a From 2da95412be31c7cc43b4c0fbde18ab856b995d3c Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 9 Mar 2018 09:01:20 +0800 Subject: [PATCH 0417/1313] QUIC: free the retransmision initial packet --- iocore/net/QUICNet.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index 5bc97612cf2..14becbe08e9 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -77,6 +77,8 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) vc->read.triggered = 1; vc->handle_received_packet(p); vc->handleEvent(QUIC_EVENT_PACKET_READ_READY, nullptr); + } else { + p->free(); } return; case QUICPacketType::ZERO_RTT_PROTECTED: From f8aa0dfc4c5077a101bbba928cf21278df14a09d Mon Sep 17 00:00:00 2001 From: scw00 Date: Sun, 11 Mar 2018 08:47:52 +0800 Subject: [PATCH 0418/1313] QUIC: Make sure only schedule one event when close connection --- iocore/net/P_QUICNetVConnection.h | 5 +++++ iocore/net/QUICNetVConnection.cc | 28 +++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 59677de2a6c..c787e65ae56 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -271,6 +271,11 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _close_closing_timeout(Event *data); Event *_closing_timeout = nullptr; + void _schedule_closed_event(); + void _unschedule_closed_event(); + void _close_closed_event(Event *data); + Event *_closed_event = nullptr; + uint32_t _transmit_packet(QUICPacketUPtr); void _transmit_frame(QUICFrameUPtr); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 7a712d7643f..95e52efc1de 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -660,6 +660,7 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) case QUIC_EVENT_SHUTDOWN: { this->_unschedule_packet_write_ready(); this->_unschedule_closing_timeout(); + this->_close_closed_event(data); this->next_inactivity_timeout_at = 0; this->next_activity_timeout_at = 0; @@ -1277,6 +1278,31 @@ QUICNetVConnection::_close_closing_timeout(Event *data) this->_closing_timeout = nullptr; } +void +QUICNetVConnection::_schedule_closed_event() +{ + if (!this->_closed_event) { + QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_SHUTDOWN)); + this->_closed_event = this_ethread()->schedule_imm(this, QUIC_EVENT_SHUTDOWN, nullptr); + } +} + +void +QUICNetVConnection::_unschedule_closed_event() +{ + if (!this->_closed_event) { + this->_closed_event->cancel(); + this->_closed_event = nullptr; + } +} + +void +QUICNetVConnection::_close_closed_event(Event *data) +{ + ink_assert(this->_closed_event == data); + this->_closed_event = nullptr; +} + int QUICNetVConnection::_complete_handshake_if_possible() { @@ -1405,7 +1431,7 @@ QUICNetVConnection::_switch_to_close_state() } QUICConDebug("Enter state_connection_closed"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closed); - this_ethread()->schedule_imm(this, QUIC_EVENT_SHUTDOWN, nullptr); + this->_schedule_closed_event(); } void From 429f0ac1e08fb6f9b1c05903aec1e95d8c279a73 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 12 Mar 2018 14:25:53 +0900 Subject: [PATCH 0419/1313] Fix a build issue --- cmd/traffic_quic/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/traffic_quic/Makefile.am b/cmd/traffic_quic/Makefile.am index b9407788f1d..9876c69a20f 100644 --- a/cmd/traffic_quic/Makefile.am +++ b/cmd/traffic_quic/Makefile.am @@ -42,6 +42,7 @@ traffic_quic_SOURCES = \ traffic_quic.cc traffic_quic_LDADD = \ + $(top_builddir)/iocore/aio/libinkaio.a \ $(top_builddir)/iocore/net/libinknet.a \ $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ From ad869730cb5e3e24ca4e2b4f87542e13e1649130 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 12 Mar 2018 14:26:25 +0900 Subject: [PATCH 0420/1313] Fix a buffer overflow on creating a stateless reset packet --- iocore/net/quic/QUICPacket.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 372c24f09fb..2646e891f82 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -798,7 +798,7 @@ QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, std::random_device rnd; uint8_t random_packet_number = static_cast(rnd() & 0xFF); - size_t payload_len = static_cast(rnd() & 0xFF); + size_t payload_len = static_cast((rnd() & 0xFF) | 16); // Mimimum length has to be 16 ats_unique_buf payload = ats_unique_malloc(payload_len + 16); uint8_t *naked_payload = payload.get(); From 47289d2a581b9800d630d3425b789975bceaf6b7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 7 Mar 2018 11:45:21 +0900 Subject: [PATCH 0421/1313] Support QUIC 0-RTT --- iocore/net/P_QUICNetVConnection.h | 3 ++ iocore/net/QUICNetVConnection.cc | 53 ++++++++++++++-------- iocore/net/quic/QUICHandshake.cc | 22 +++++++-- iocore/net/quic/QUICHandshakeProtocol.cc | 15 ++++-- iocore/net/quic/QUICHandshakeProtocol.h | 5 +- iocore/net/quic/QUICKeyGenerator.cc | 28 ++++++++++++ iocore/net/quic/QUICKeyGenerator.h | 3 ++ iocore/net/quic/QUICPacket.cc | 24 ++++++++-- iocore/net/quic/QUICTLS.cc | 58 ++++++++++++++++++++---- iocore/net/quic/QUICTLS.h | 3 +- iocore/net/quic/QUICTypes.h | 1 + 11 files changed, 169 insertions(+), 46 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index c787e65ae56..781ee3c862f 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -312,6 +312,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _switch_to_draining_state(QUICConnectionErrorUPtr error); void _switch_to_close_state(); + bool _application_started = false; + void _start_application(); + void _handle_idle_timeout(); void _update_alt_connection_ids(uint8_t chosen); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 95e52efc1de..a6859daa2db 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -817,8 +817,8 @@ QUICNetVConnection::_state_handshake_process_client_cleartext_packet(QUICPacketU QUICErrorUPtr QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet) { - // TODO: Not sure what we have to do - return QUICErrorUPtr(new QUICNoError()); + this->_start_application(); + return this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); } QUICErrorUPtr @@ -945,6 +945,9 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans QUICRetransmissionFrame *rf = dynamic_cast(frame.get()); if (rf) { current_packet_type = rf->packet_type(); + } else if (frame->type() == QUICFrameType::STREAM && + static_cast(frame.get())->stream_id() != STREAM_ID_FOR_HANDSHAKE) { + current_packet_type = QUICPacketType::PROTECTED; } else { current_packet_type = QUICPacketType::UNINITIALIZED; } @@ -1090,6 +1093,10 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); break; + case QUICPacketType::PROTECTED: + packet = this->_packet_factory.create_server_protected_packet(this->_quic_connection_id, this->largest_acked_packet_number(), + std::move(buf), len, retransmittable); + break; default: if (this->get_context() == NET_VCONNECTION_OUT) { if (this->_handshake_handler->handler == reinterpret_cast(&QUICHandshake::state_initial)) { @@ -1317,26 +1324,36 @@ QUICNetVConnection::_complete_handshake_if_possible() this->_init_flow_control_params(this->_handshake_handler->local_transport_parameters(), this->_handshake_handler->remote_transport_parameters()); - const uint8_t *app_name; - unsigned int app_name_len = 0; - this->_handshake_handler->negotiated_application_name(&app_name, &app_name_len); - if (app_name == nullptr) { - app_name = reinterpret_cast(IP_PROTO_TAG_HTTP_QUIC.data()); - app_name_len = IP_PROTO_TAG_HTTP_QUIC.size(); - } + this->_start_application(); + + return 0; +} + +void +QUICNetVConnection::_start_application() +{ + if (!this->_application_started) { + this->_application_started = true; + + const uint8_t *app_name; + unsigned int app_name_len = 0; + this->_handshake_handler->negotiated_application_name(&app_name, &app_name_len); + if (app_name == nullptr) { + app_name = reinterpret_cast(IP_PROTO_TAG_HTTP_QUIC.data()); + app_name_len = IP_PROTO_TAG_HTTP_QUIC.size(); + } - if (netvc_context == NET_VCONNECTION_IN) { - Continuation *endpoint = this->_next_protocol_set->findEndpoint(app_name, app_name_len); - if (endpoint == nullptr) { - this->_handle_error(QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR))); + if (netvc_context == NET_VCONNECTION_IN) { + Continuation *endpoint = this->_next_protocol_set->findEndpoint(app_name, app_name_len); + if (endpoint == nullptr) { + this->_handle_error(QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR))); + } else { + endpoint->handleEvent(NET_EVENT_ACCEPT, this); + } } else { - endpoint->handleEvent(NET_EVENT_ACCEPT, this); + this->action_.continuation->handleEvent(NET_EVENT_OPEN, this); } - } else { - this->action_.continuation->handleEvent(NET_EVENT_OPEN, this); } - - return 0; } void diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index e3a5ce3c46f..d71e8c4021c 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -464,6 +464,15 @@ QUICHandshake::_do_handshake(bool initial) stream_io->write(out, out_len); } + if (!this->_hs_protocol->is_key_derived(QUICKeyPhase::PHASE_0)) { + int res = this->_hs_protocol->update_key_materials(); + if (res) { + QUICHSDebug("Keying Materials are exported"); + } else { + QUICHSDebug("Failed to export Keying Materials"); + } + } + return result; } @@ -573,11 +582,14 @@ QUICHandshake::_complete_handshake() SET_HANDLER(&QUICHandshake::state_complete); QUICHSDebug("%s", this->negotiated_cipher_suite()); - int res = this->_hs_protocol->update_key_materials(); - if (res) { - QUICHSDebug("Keying Materials are exported"); - } else { - QUICHSDebug("Failed to export Keying Materials"); + int res = 1; + if (!this->_hs_protocol->is_key_derived(QUICKeyPhase::PHASE_0)) { + res = this->_hs_protocol->update_key_materials(); + if (res) { + QUICHSDebug("Keying Materials are exported"); + } else { + QUICHSDebug("Failed to export Keying Materials"); + } } return res; diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index 29579788949..4cb7a1008c8 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -50,23 +50,28 @@ QUICPacketProtection::set_key(std::unique_ptr km, QUICKeyPhase phas case QUICKeyPhase::CLEARTEXT: this->_cleartext_key = std::move(km); break; + case QUICKeyPhase::ZERORTT: + this->_zerortt_key = std::move(km); + break; } } -const KeyMaterial & +const KeyMaterial * QUICPacketProtection::get_key(QUICKeyPhase phase) const { switch (phase) { case QUICKeyPhase::PHASE_0: - return *this->_phase_0_key; + return this->_phase_0_key.get(); case QUICKeyPhase::PHASE_1: - return *this->_phase_1_key; + return this->_phase_1_key.get(); case QUICKeyPhase::CLEARTEXT: - return *this->_cleartext_key; + return this->_cleartext_key.get(); + case QUICKeyPhase::ZERORTT: + return this->_zerortt_key.get(); } ink_release_assert(!"Bad phase"); - return *this->_cleartext_key; + return nullptr; } QUICKeyPhase diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index cb73cd90b93..13c45a48f33 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -32,10 +32,11 @@ class QUICPacketProtection QUICPacketProtection(){}; ~QUICPacketProtection(); void set_key(std::unique_ptr km, QUICKeyPhase phase); - const KeyMaterial &get_key(QUICKeyPhase phase) const; + const KeyMaterial *get_key(QUICKeyPhase phase) const; QUICKeyPhase key_phase() const; private: + std::unique_ptr _zerortt_key = nullptr; std::unique_ptr _cleartext_key = nullptr; std::unique_ptr _phase_0_key = nullptr; std::unique_ptr _phase_1_key = nullptr; @@ -50,7 +51,7 @@ class QUICHandshakeProtocol virtual int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) = 0; virtual bool is_handshake_finished() const = 0; - virtual bool is_key_derived() const = 0; + virtual bool is_key_derived(QUICKeyPhase key_phase) const = 0; virtual int initialize_key_materials(QUICConnectionId cid) = 0; virtual int update_key_materials() = 0; virtual bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 7f824f70c88..9cd1f3792d4 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -31,6 +31,7 @@ constexpr static uint8_t QUIC_VERSION_1_SALT[] = { }; constexpr static ts::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("client hs"_sv); constexpr static ts::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("server hs"_sv); +constexpr static ts::string_view LABEL_FOR_CLIENT_0RTT_SECRET("EXPORTER-QUIC 0rtt"_sv); constexpr static ts::string_view LABEL_FOR_CLIENT_PP_SECRET("EXPORTER-QUIC client 1rtt"_sv); constexpr static ts::string_view LABEL_FOR_SERVER_PP_SECRET("EXPORTER-QUIC server 1rtt"_sv); constexpr static ts::string_view LABEL_FOR_KEY("key"_sv); @@ -63,6 +64,23 @@ QUICKeyGenerator::generate(QUICConnectionId cid) return km; } +std::unique_ptr +QUICKeyGenerator::generate_0rtt(SSL *ssl) +{ + std::unique_ptr km = std::make_unique(); + + const QUIC_EVP_CIPHER *cipher = this->_get_cipher_for_protected_packet(ssl); + const EVP_MD *md = _get_handshake_digest(ssl); + uint8_t secret[512]; + size_t secret_len = sizeof(secret); + QUICHKDF hkdf(md); + + this->_generate_0rtt_secret(secret, &secret_len, hkdf, ssl, EVP_MD_size(md)); + this->_generate(km->key, &km->key_len, km->iv, &km->iv_len, hkdf, secret, secret_len, cipher); + + return km; +} + std::unique_ptr QUICKeyGenerator::generate(SSL *ssl) { @@ -139,6 +157,16 @@ QUICKeyGenerator::_generate_pp_secret(uint8_t *out, size_t *out_len, QUICHKDF &h return 0; } +int +QUICKeyGenerator::_generate_0rtt_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, SSL *ssl, size_t length) +{ + *out_len = length; + SSL_export_keying_material_early(ssl, out, *out_len, LABEL_FOR_CLIENT_0RTT_SECRET.data(), LABEL_FOR_CLIENT_0RTT_SECRET.length(), + reinterpret_cast(""), 0); + + return 0; +} + int QUICKeyGenerator::_generate_key(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t key_length) const diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index 3dcfdf33028..7eafded7260 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -63,6 +63,8 @@ class QUICKeyGenerator */ std::unique_ptr generate(SSL *ssl); + std::unique_ptr generate_0rtt(SSL *ssl); + private: Context _ctx = Context::SERVER; @@ -75,6 +77,7 @@ class QUICKeyGenerator size_t label_len, size_t length); int _generate_pp_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, SSL *ssl, const char *label, size_t label_len, size_t length); + int _generate_0rtt_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, SSL *ssl, size_t length); int _generate_key(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t key_length) const; int _generate_iv(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t iv_length) const; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 2646e891f82..b52abc955c7 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -24,6 +24,7 @@ #include #include #include "QUICPacket.h" +#include "QUICDebugNames.h" ClassAllocator quicPacketAllocator("quicPacketAllocator"); ClassAllocator quicPacketLongHeaderAllocator("quicPacketLongHeaderAllocator"); @@ -671,6 +672,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ memcpy(plain_txt.get(), header->payload(), header->payload_size()); plain_txt_len = header->payload_size(); } else { + Debug("quic_packet", "Decrypting %s packet", QUICDebugNames::packet_type(header->type())); switch (header->type()) { case QUICPacketType::VERSION_NEGOTIATION: case QUICPacketType::STATELESS_RESET: @@ -680,7 +682,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ result = QUICPacketCreationResult::SUCCESS; break; case QUICPacketType::PROTECTED: - if (this->_hs_protocol->is_key_derived()) { + if (this->_hs_protocol->is_key_derived(header->key_phase())) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { @@ -693,7 +695,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ } break; case QUICPacketType::INITIAL: - if (!this->_hs_protocol->is_key_derived()) { + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::CLEARTEXT)) { if (QUICTypeUtil::is_supported_version(header->version())) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), @@ -710,7 +712,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ } break; case QUICPacketType::HANDSHAKE: - if (!this->_hs_protocol->is_key_derived()) { + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::CLEARTEXT)) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { @@ -723,8 +725,17 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ } break; case QUICPacketType::ZERO_RTT_PROTECTED: - // TODO Support 0-RTT - result = QUICPacketCreationResult::IGNORED; + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::ZERORTT)) { + if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + QUICKeyPhase::ZERORTT)) { + result = QUICPacketCreationResult::SUCCESS; + } else { + result = QUICPacketCreationResult::IGNORED; + } + } else { + result = QUICPacketCreationResult::NOT_READY; + } break; default: result = QUICPacketCreationResult::FAILED; @@ -836,11 +847,14 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool re ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); size_t cipher_txt_len = 0; + Debug("quic_packet", "Encrypting %s packet", QUICDebugNames::packet_type(header->type())); QUICPacket *packet = nullptr; if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable); + } else { + Debug("quic_packet", "Failed to encrypt a packet"); } return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index c0a65e6a833..67a6942e34f 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -76,9 +76,14 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint int err = SSL_ERROR_NONE; if (!SSL_is_init_finished(this->_ssl)) { - if (!this->_early_data_processed && this->_read_early_data() == 1) { - Debug(tag, "Early data processed"); - this->_early_data_processed = true; + if (!this->_early_data_processed) { + if (this->_read_early_data()) { + Debug(tag, "Early data processed"); + this->_early_data_processed = true; + } + if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT) && SSL_get_early_data_status(this->_ssl) == SSL_EARLY_DATA_ACCEPTED) { + this->_generate_0rtt_key(); + } } ERR_clear_error(); int ret = SSL_do_handshake(this->_ssl); @@ -113,9 +118,13 @@ QUICTLS::is_handshake_finished() const } bool -QUICTLS::is_key_derived() const +QUICTLS::is_key_derived(QUICKeyPhase key_phase) const { - return (this->_client_pp->key_phase() != QUICKeyPhase::CLEARTEXT && this->_server_pp->key_phase() != QUICKeyPhase::CLEARTEXT); + if (key_phase == QUICKeyPhase::ZERORTT) { + return this->_client_pp->get_key(QUICKeyPhase::ZERORTT); + } else { + return this->_client_pp->get_key(key_phase) && this->_server_pp->get_key(key_phase); + } } int @@ -151,7 +160,6 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) int QUICTLS::update_key_materials() { - ink_assert(SSL_is_init_finished(this->_ssl)); // Switch key phase QUICKeyPhase next_key_phase; switch (this->_client_pp->key_phase()) { @@ -164,6 +172,9 @@ QUICTLS::update_key_materials() case QUICKeyPhase::CLEARTEXT: next_key_phase = QUICKeyPhase::PHASE_0; break; + case QUICKeyPhase::ZERORTT: + next_key_phase = QUICKeyPhase::PHASE_0; + break; default: Error("QUICKeyPhase value is undefined"); ink_assert(false); @@ -202,13 +213,31 @@ QUICTLS::_read_early_data() uint8_t early_data[8]; size_t early_data_len = 0; int ret = 0; + do { ERR_clear_error(); ret = SSL_read_early_data(this->_ssl, early_data, sizeof(early_data), &early_data_len); } while (ret == SSL_READ_EARLY_DATA_SUCCESS); + return ret == SSL_READ_EARLY_DATA_FINISH ? 1 : 0; } +void +QUICTLS::_generate_0rtt_key() +{ + // Generate key material for 0-RTT + std::unique_ptr km; + km = this->_keygen_for_client.generate_0rtt(this->_ssl); + if (is_debug_tag_set("vv_quic_crypto")) { + uint8_t print_buf[512]; + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "0rtt key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "0rtt iv 0x%s", print_buf); + } + this->_client_pp->set_key(std::move(km), QUICKeyPhase::ZERORTT); +} + SSL * QUICTLS::ssl_handle() { @@ -235,8 +264,13 @@ QUICTLS::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, con return false; } - size_t tag_len = this->_get_aead_tag_len(); - return _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, pp->get_key(phase), tag_len); + size_t tag_len = this->_get_aead_tag_len(); + const KeyMaterial *km = pp->get_key(phase); + if (!km) { + return false; + } + + return _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, *km, tag_len); } bool @@ -259,8 +293,12 @@ QUICTLS::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const return false; } - size_t tag_len = this->_get_aead_tag_len(); - bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, pp->get_key(phase), tag_len); + size_t tag_len = this->_get_aead_tag_len(); + const KeyMaterial *km = pp->get_key(phase); + if (!km) { + return false; + } + bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, *km, tag_len); if (!ret) { Debug(tag, "Failed to decrypt a packet: pkt_num=%" PRIu64, pkt_num); } diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 8aee9665817..0ac7c10abbb 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -44,7 +44,7 @@ class QUICTLS : public QUICHandshakeProtocol int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override; bool is_handshake_finished() const override; - bool is_key_derived() const override; + bool is_key_derived(QUICKeyPhase key_phase) const override; int initialize_key_materials(QUICConnectionId cid) override; int update_key_materials() override; bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, @@ -83,4 +83,5 @@ class QUICTLS : public QUICHandshakeProtocol bool _early_data_processed = false; int _read_early_data(); + void _generate_0rtt_key(); }; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 5f01a084884..255b57796ff 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -114,6 +114,7 @@ enum class QUICKeyPhase : int { PHASE_0 = 0, PHASE_1, CLEARTEXT, + ZERORTT, }; enum class QUICPacketCreationResult { From 3f85b668c732baf2b354f95351ca5d374df243e7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 12 Mar 2018 16:24:32 +0900 Subject: [PATCH 0422/1313] Fix memory leaks under iocore/net/quic --- iocore/net/quic/QUICFrame.cc | 3 +++ iocore/net/quic/QUICFrame.h | 16 ++++++++++++++++ iocore/net/quic/QUICPacket.cc | 34 +++++++++++++++++----------------- iocore/net/quic/QUICPacket.h | 19 ++++++++++++++----- 4 files changed, 50 insertions(+), 22 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index f7445ee13bf..92fd9612368 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -332,6 +332,9 @@ void QUICAckFrame::reset(const uint8_t *buf, size_t len) { QUICFrame::reset(buf, len); + if (this->_ack_block_section) { + delete this->_ack_block_section; + } this->_ack_block_section = new AckBlockSection(buf + this->_get_ack_block_section_offset(), this->ack_block_count()); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 0cc90d5c012..6d2044e8d7a 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -587,6 +587,7 @@ class QUICFrameDeleter static void delete_stream_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicStreamFrameAllocator.free(static_cast(frame)); } @@ -600,90 +601,105 @@ class QUICFrameDeleter static void delete_padding_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicPaddingFrameAllocator.free(static_cast(frame)); } static void delete_rst_stream_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicRstStreamFrameAllocator.free(static_cast(frame)); } static void delete_connection_close_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicConnectionCloseFrameAllocator.free(static_cast(frame)); } static void delete_application_close_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicApplicationCloseFrameAllocator.free(static_cast(frame)); } static void delete_max_data_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicMaxDataFrameAllocator.free(static_cast(frame)); } static void delete_max_stream_data_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicMaxStreamDataFrameAllocator.free(static_cast(frame)); } static void delete_max_stream_id_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicMaxStreamIdFrameAllocator.free(static_cast(frame)); } static void delete_ping_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicPingFrameAllocator.free(static_cast(frame)); } static void delete_blocked_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicBlockedFrameAllocator.free(static_cast(frame)); } static void delete_stream_blocked_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicStreamBlockedFrameAllocator.free(static_cast(frame)); } static void delete_stream_id_blocked_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicStreamIdBlockedFrameAllocator.free(static_cast(frame)); } static void delete_new_connection_id_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicNewConnectionIdFrameAllocator.free(static_cast(frame)); } static void delete_stop_sending_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicStopSendingFrameAllocator.free(static_cast(frame)); } static void delete_pong_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicPongFrameAllocator.free(static_cast(frame)); } static void delete_retransmission_frame(QUICFrame *frame) { + frame->~QUICFrame(); quicRetransmissionFrameAllocator.free(static_cast(frame)); } }; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index b52abc955c7..1fcc8a2cb9e 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -47,7 +47,7 @@ const uint8_t * QUICPacketHeader::buf() { if (this->_buf) { - return this->_buf; + return this->_buf.get(); } else { // TODO Reuse serialzied data if nothing has changed size_t dummy; @@ -63,16 +63,16 @@ QUICPacketHeader::packet_size() const } QUICPacketHeaderUPtr -QUICPacketHeader::load(const uint8_t *buf, size_t len, QUICPacketNumber base) +QUICPacketHeader::load(ats_unique_buf buf, size_t len, QUICPacketNumber base) { QUICPacketHeaderUPtr header = QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header); - if (QUICTypeUtil::has_long_header(buf)) { + if (QUICTypeUtil::has_long_header(buf.get())) { QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); - new (long_header) QUICPacketLongHeader(buf, len, base); + new (long_header) QUICPacketLongHeader(std::move(buf), len, base); header = QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); } else { QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); - new (short_header) QUICPacketShortHeader(buf, len, base); + new (short_header) QUICPacketShortHeader(std::move(buf), len, base); header = QUICPacketHeaderUPtr(short_header, &QUICPacketHeaderDeleter::delete_short_header); } return header; @@ -133,7 +133,7 @@ QUICPacketType QUICPacketLongHeader::type() const { if (this->_buf) { - uint8_t type = this->_buf[0] & 0x7F; + uint8_t type = this->_buf.get()[0] & 0x7F; if (this->version() == 0x00) { return QUICPacketType::VERSION_NEGOTIATION; } else { @@ -149,7 +149,7 @@ QUICConnectionId QUICPacketLongHeader::connection_id() const { if (this->_buf) { - return QUICTypeUtil::read_QUICConnectionId(this->_buf + LONG_HDR_OFFSET_CONNECTION_ID, 8); + return QUICTypeUtil::read_QUICConnectionId(this->_buf.get() + LONG_HDR_OFFSET_CONNECTION_ID, 8); } else { return this->_connection_id; } @@ -160,7 +160,7 @@ QUICPacketLongHeader::packet_number() const { if (this->_buf) { const uint8_t packet_number_len = 4; - QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf + LONG_HDR_OFFSET_PACKET_NUMBER, packet_number_len); + QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + LONG_HDR_OFFSET_PACKET_NUMBER, packet_number_len); QUICPacketNumber dst = 0; QUICPacket::decode_packet_number(dst, src, packet_number_len, this->_base_packet_number); @@ -180,7 +180,7 @@ QUICVersion QUICPacketLongHeader::version() const { if (this->_buf) { - return QUICTypeUtil::read_QUICVersion(this->_buf + LONG_HDR_OFFSET_VERSION); + return QUICTypeUtil::read_QUICVersion(this->_buf.get() + LONG_HDR_OFFSET_VERSION); } else { return this->_version; } @@ -196,7 +196,7 @@ const uint8_t * QUICPacketLongHeader::payload() const { if (this->_buf) { - return this->_buf + LONG_HDR_OFFSET_PAYLOAD; + return this->_buf.get() + LONG_HDR_OFFSET_PAYLOAD; } else { return this->_payload.get(); } @@ -314,7 +314,7 @@ QUICPacketShortHeader::connection_id() const { if (this->_buf) { ink_release_assert(this->has_connection_id()); - return QUICTypeUtil::read_QUICConnectionId(this->_buf + SHORT_HDR_OFFSET_CONNECTION_ID, 8); + return QUICTypeUtil::read_QUICConnectionId(this->_buf.get() + SHORT_HDR_OFFSET_CONNECTION_ID, 8); } else { return _connection_id; } @@ -330,7 +330,7 @@ QUICPacketShortHeader::packet_number() const offset += 8; } - QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf + offset, n); + QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + offset, n); QUICPacketNumber dst = 0; QUICPacket::decode_packet_number(dst, src, n, this->_base_packet_number); @@ -357,7 +357,7 @@ QUICPacketShortHeader::_packet_number_len() const { QUICPacketShortHeaderType type; if (this->_buf) { - type = static_cast(this->_buf[0] & 0x1F); + type = static_cast(this->_buf.get()[0] & 0x1F); } else { type = this->_packet_number_type; } @@ -393,7 +393,7 @@ bool QUICPacketShortHeader::has_connection_id() const { if (this->_buf) { - return QUICTypeUtil::has_connection_id(this->_buf); + return QUICTypeUtil::has_connection_id(this->_buf.get()); } else { return this->_has_connection_id; } @@ -403,7 +403,7 @@ const uint8_t * QUICPacketShortHeader::payload() const { if (this->_buf) { - return this->_buf + this->size(); + return this->_buf.get() + this->size(); } else { return this->_payload.get(); } @@ -419,7 +419,7 @@ QUICKeyPhase QUICPacketShortHeader::key_phase() const { if (this->_buf) { - if (this->_buf[0] & 0x20) { + if (this->_buf.get()[0] & 0x20) { return QUICKeyPhase::PHASE_1; } else { return QUICKeyPhase::PHASE_0; @@ -664,7 +664,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ ats_unique_buf plain_txt = ats_unique_malloc(max_plain_txt_len); size_t plain_txt_len = 0; - QUICPacketHeaderUPtr header = QUICPacketHeader::load(buf.release(), len, base_packet_number); + QUICPacketHeaderUPtr header = QUICPacketHeader::load(std::move(buf), len, base_packet_number); if (header->has_version() && !QUICTypeUtil::is_supported_version(header->version())) { // We can't decrypt packets that have unknown versions diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 6992b792332..be45b6e0a7b 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -52,7 +52,11 @@ using QUICPacketHeaderUPtr = std::unique_ptr(header); ink_assert(long_header != nullptr); + long_header->~QUICPacketLongHeader(); quicPacketLongHeaderAllocator.free(long_header); } @@ -222,6 +229,7 @@ class QUICPacketHeaderDeleter { QUICPacketShortHeader *short_header = dynamic_cast(header); ink_assert(short_header != nullptr); + short_header->~QUICPacketShortHeader(); quicPacketShortHeaderAllocator.free(short_header); } }; @@ -320,6 +328,7 @@ class QUICPacketDeleter static void delete_packet(QUICPacket *packet) { + packet->~QUICPacket(); quicPacketAllocator.free(packet); } }; From 95474563255c9169ca71d1d3740ae3b38fc3e1d7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 12 Mar 2018 17:26:22 +0900 Subject: [PATCH 0423/1313] Fix build warnings --- iocore/net/quic/QUICPacket.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index be45b6e0a7b..6306955d9f9 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -161,7 +161,7 @@ class QUICPacketLongHeader : public QUICPacketHeader { public: QUICPacketLongHeader() : QUICPacketHeader(){}; - ~QUICPacketLongHeader(){}; + virtual ~QUICPacketLongHeader(){}; QUICPacketLongHeader(ats_unique_buf buf, size_t len, QUICPacketNumber base) : QUICPacketHeader(std::move(buf), len, base) {} QUICPacketLongHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len); @@ -182,7 +182,7 @@ class QUICPacketShortHeader : public QUICPacketHeader { public: QUICPacketShortHeader() : QUICPacketHeader(){}; - ~QUICPacketShortHeader(){}; + virtual ~QUICPacketShortHeader(){}; QUICPacketShortHeader(ats_unique_buf buf, size_t len, QUICPacketNumber base) : QUICPacketHeader(std::move(buf), len, base) {} QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len); From 6f515f1c1b33b930b1acd023c722c97eef501ada Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 13 Mar 2018 10:08:31 +0900 Subject: [PATCH 0424/1313] Fix signature of QUICHandshakeProtocol::is_key_derived() in Mock.h --- iocore/net/quic/Mock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index fbac3503782..f916ded1268 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -477,7 +477,7 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol } bool - is_key_derived() const override + is_key_derived(QUICKeyPhase /* key_phase */) const override { return true; } From ca73ea98ac4618c464c6c27d478dfc2a52388783 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 13 Mar 2018 10:26:03 +0900 Subject: [PATCH 0425/1313] Add logs around encrypting and decrypting --- iocore/net/quic/Mock.h | 6 +----- iocore/net/quic/QUICDebugNames.cc | 17 +++++++++++++++++ iocore/net/quic/QUICDebugNames.h | 1 + iocore/net/quic/QUICPacket.cc | 4 ++-- iocore/net/quic/QUICTLS.cc | 14 +++++++++++++- 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index f916ded1268..31a9fd49b0d 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -476,11 +476,7 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol return true; } - bool - is_key_derived(QUICKeyPhase /* key_phase */) const override - { - return true; - } + bool is_key_derived(QUICKeyPhase /* key_phase */) const override { return true; } int initialize_key_materials(QUICConnectionId cid) override diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 088cd0b2f64..f7ec117abbe 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -208,3 +208,20 @@ QUICDebugNames::stream_state(QUICStreamState state) return "UNKNOWN"; } } + +const char * +QUICDebugNames::key_phase(QUICKeyPhase phase) +{ + switch (phase) { + case QUICKeyPhase::PHASE_0: + return "PHASE_0"; + case QUICKeyPhase::PHASE_1: + return "PHASE_1"; + case QUICKeyPhase::CLEARTEXT: + return "CLEARTEXT"; + case QUICKeyPhase::ZERORTT: + return "ZERORTT"; + default: + return "UNKNOWN"; + } +} diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index 093e81db8f5..bb4e7d7f221 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -38,4 +38,5 @@ class QUICDebugNames static const char *transport_parameter_id(QUICTransportParameterId id); static const char *stream_state(QUICStreamState state); static const char *quic_event(int event); + static const char *key_phase(QUICKeyPhase phase); }; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 1fcc8a2cb9e..659e826fed0 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -672,7 +672,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ memcpy(plain_txt.get(), header->payload(), header->payload_size()); plain_txt_len = header->payload_size(); } else { - Debug("quic_packet", "Decrypting %s packet", QUICDebugNames::packet_type(header->type())); + Debug("quic_packet", "Decrypting %s packet #%" PRIu64, QUICDebugNames::packet_type(header->type()), header->packet_number()); switch (header->type()) { case QUICPacketType::VERSION_NEGOTIATION: case QUICPacketType::STATELESS_RESET: @@ -847,7 +847,7 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool re ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); size_t cipher_txt_len = 0; - Debug("quic_packet", "Encrypting %s packet", QUICDebugNames::packet_type(header->type())); + Debug("quic_packet", "Encrypting %s packet #%" PRIu64, QUICDebugNames::packet_type(header->type()), header->packet_number()); QUICPacket *packet = nullptr; if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 67a6942e34f..7baa1939679 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -22,6 +22,7 @@ */ #include "QUICTLS.h" +#include "QUICDebugNames.h" #include #include @@ -131,6 +132,7 @@ int QUICTLS::initialize_key_materials(QUICConnectionId cid) { // Generate keys + Debug(tag, "Generating %s keys", QUICDebugNames::key_phase(QUICKeyPhase::CLEARTEXT)); uint8_t print_buf[512]; std::unique_ptr km; km = this->_keygen_for_client.generate(cid); @@ -182,6 +184,7 @@ QUICTLS::update_key_materials() } // Generate keys + Debug(tag, "Generating %s keys", QUICDebugNames::key_phase(next_key_phase)); uint8_t print_buf[512]; std::unique_ptr km; km = this->_keygen_for_client.generate(this->_ssl); @@ -226,6 +229,7 @@ void QUICTLS::_generate_0rtt_key() { // Generate key material for 0-RTT + Debug(tag, "Generating %s keys", QUICDebugNames::key_phase(QUICKeyPhase::ZERORTT)); std::unique_ptr km; km = this->_keygen_for_client.generate_0rtt(this->_ssl); if (is_debug_tag_set("vv_quic_crypto")) { @@ -249,6 +253,7 @@ QUICTLS::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, con uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const { QUICPacketProtection *pp = nullptr; + Debug(tag, "Encrypting packet using %s key", QUICDebugNames::key_phase(phase)); switch (this->_netvc_context) { case NET_VCONNECTION_IN: { @@ -267,10 +272,15 @@ QUICTLS::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, con size_t tag_len = this->_get_aead_tag_len(); const KeyMaterial *km = pp->get_key(phase); if (!km) { + Debug(tag, "Failed to encrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } - return _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, *km, tag_len); + bool ret = _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, *km, tag_len); + if (!ret) { + Debug(tag, "Failed to encrypt a packet: pkt_num=%" PRIu64, pkt_num); + } + return ret; } bool @@ -278,6 +288,7 @@ QUICTLS::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const { QUICPacketProtection *pp = nullptr; + Debug(tag, "Decrypting packet using %s key", QUICDebugNames::key_phase(phase)); switch (this->_netvc_context) { case NET_VCONNECTION_IN: { @@ -296,6 +307,7 @@ QUICTLS::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const size_t tag_len = this->_get_aead_tag_len(); const KeyMaterial *km = pp->get_key(phase); if (!km) { + Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, *km, tag_len); From 943dfdb66eef9aec56e417bcbe49165429331365 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 13 Mar 2018 14:31:11 +0900 Subject: [PATCH 0426/1313] Make tests compilable again --- iocore/net/quic/test/Makefile.am | 16 ++++++++++++++++ iocore/net/quic/test/test_QUICLossDetector.cc | 4 ++-- iocore/net/quic/test/test_QUICPacket.cc | 10 +++++----- iocore/net/quic/test/test_QUICPacketFactory.cc | 4 ++-- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index d0b482ed769..6e05382892f 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -347,6 +347,8 @@ test_QUICKeyGenerator_LDFLAGS = \ test_QUICKeyGenerator_LDADD = \ @OPENSSL_LIBS@ \ $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a @@ -355,6 +357,13 @@ test_QUICKeyGenerator_SOURCES = \ test_QUICKeyGenerator.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ + ../QUICDebugNames.cc \ + ../QUICIncomingFrameBuffer.cc \ + ../QUICFlowController.cc \ + ../QUICPacket.cc \ + ../QUICStreamState.cc \ + ../QUICFrame.cc \ + ../QUICStream.cc \ ../QUICHKDF.cc \ ../QUICTypes.cc @@ -387,6 +396,13 @@ test_QUICHandshakeProtocol_SOURCES = \ $(QUICTLS_impl) \ ../QUICHandshakeProtocol.h \ ../QUICTypes.cc \ + ../QUICDebugNames.cc \ + ../QUICStreamState.cc \ + ../QUICFrame.cc \ + ../QUICStream.cc \ + ../QUICPacket.cc \ + ../QUICIncomingFrameBuffer.cc \ + ../QUICFlowController.cc \ ../QUICGlobals.cc \ ../../SSLNextProtocolSet.cc diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 1fb01cfc5e3..963be5fb2b2 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -54,10 +54,10 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, 0xffddbb9977553311ULL, 0x00000001, 0, 0x00112233, + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, 0xffddbb9977553311ULL, 0x00000001, 0, 0x00112233, std::move(payload), sizeof(raw)); QUICPacketUPtr packet = - QUICPacketUPtr(new QUICPacket(header, std::move(payload), sizeof(raw), true), [](QUICPacket *p) { delete p; }); + QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true), [](QUICPacket *p) { delete p; }); detector.on_packet_sent(std::move(packet)); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); CHECK(tx->retransmitted.size() > 0); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index fe83032e6ac..d8bf64d6235 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -37,7 +37,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0x00, 0x00, 0x00, 0x09, // Supported Version 1 }; - QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({const_cast(input), [](void *p) {}}, sizeof(input), 0); CHECK(header->size() == 13); CHECK(header->packet_size() == 21); CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); @@ -58,7 +58,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0xff, 0xff, // Payload (dummy) }; - QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({const_cast(input), [](void *p) {}}, sizeof(input), 0); CHECK(header->size() == 17); CHECK(header->packet_size() == 19); CHECK(header->type() == QUICPacketType::INITIAL); @@ -85,7 +85,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") ats_unique_buf payload = ats_unique_malloc(5); memcpy(payload.get(), expected + 17, 5); - QUICPacketHeader *header = + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::INITIAL, 0x0102030405060708, 0x12345678, 0, 0x11223344, std::move(payload), 32); CHECK(header->size() == 17); @@ -115,7 +115,7 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") 0xff, 0xff, // Payload (dummy) }; - QUICPacketHeader *header = QUICPacketHeader::load(input, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({const_cast(input), [](void *p) {}}, sizeof(input), 0); CHECK(header->size() == 13); CHECK(header->packet_size() == 15); CHECK(header->has_key_phase() == true); @@ -140,7 +140,7 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") ats_unique_buf payload = ats_unique_malloc(5); memcpy(payload.get(), expected + 13, 5); - QUICPacketHeader *header = QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, 0x0102030405060708, + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, 0x0102030405060708, 0x12345678, 0, std::move(payload), 32); CHECK(header->size() == 13); CHECK(header->packet_size() == 0); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index ba5c5233c6c..853f43600b7 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -42,8 +42,8 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x00 // Payload }; - QUICPacketHeader *header = QUICPacketHeader::load(client_initial_packet_header, sizeof(client_initial_packet_header), 0); - QUICPacket client_initial_packet(header, ats_unique_buf(client_initial_packet_payload, [](void *) {}), + QUICPacketHeaderUPtr header = QUICPacketHeader::load({client_initial_packet_header, [](void *) {}}, sizeof(client_initial_packet_header), 0); + QUICPacket client_initial_packet(std::move(header), ats_unique_buf(client_initial_packet_payload, [](void *) {}), sizeof(client_initial_packet_payload), 0); QUICPacketUPtr packet = factory.create_version_negotiation_packet(&client_initial_packet, 0); From f9651e356af77b531a03ab982345199db1d34a93 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 13 Mar 2018 16:08:42 +0900 Subject: [PATCH 0427/1313] Add SSL_stateless() support in QUICTLS Also add test cases for key_share mismatch, stateless retry and both. This is a piece of Client Address Validation support. This requires latest OpenSSL (1.1.1-rc3+) for SSL_CTX_set_stateless_cookie_{generate,verify}_cb - https://github.com/openssl/openssl/commit/3fa2812f32bdb922d47b84ab7b5a98a807d838c0 --- iocore/net/quic/QUICTLS.cc | 75 +++- iocore/net/quic/QUICTLS.h | 7 +- .../quic/test/test_QUICHandshakeProtocol.cc | 422 +++++++++++++++++- 3 files changed, 466 insertions(+), 38 deletions(-) diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 7baa1939679..44412607f35 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -42,20 +42,19 @@ to_hex(uint8_t *out, uint8_t *in, int in_len) out[in_len * 2] = 0; } -QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx) +QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless) + : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx), _stateless(stateless) { - if (this->_netvc_context == NET_VCONNECTION_IN) { - SSL_set_accept_state(this->_ssl); - } else if (this->_netvc_context == NET_VCONNECTION_OUT) { - SSL_set_connect_state(this->_ssl); - } else { - ink_assert(false); - } + ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); this->_client_pp = new QUICPacketProtection(); this->_server_pp = new QUICPacketProtection(); } +QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICTLS(ssl, nvc_ctx, false) +{ +} + QUICTLS::~QUICTLS() { delete this->_client_pp; @@ -77,18 +76,50 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint int err = SSL_ERROR_NONE; if (!SSL_is_init_finished(this->_ssl)) { - if (!this->_early_data_processed) { - if (this->_read_early_data()) { - Debug(tag, "Early data processed"); - this->_early_data_processed = true; + ERR_clear_error(); + int ret = 0; + if (this->_netvc_context == NET_VCONNECTION_IN) { + // // process early data + if (!this->_early_data_processed) { + if (this->_read_early_data()) { + this->_early_data_processed = true; + } + + if (SSL_get_early_data_status(this->_ssl) == SSL_EARLY_DATA_ACCEPTED) { + Debug(tag, "Early data processed"); + + if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT)) { + this->_generate_0rtt_key(); + } + } } - if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT) && SSL_get_early_data_status(this->_ssl) == SSL_EARLY_DATA_ACCEPTED) { - this->_generate_0rtt_key(); + + // process stateless retry + if (this->_stateless && SSL_get_early_data_status(this->_ssl) != SSL_EARLY_DATA_ACCEPTED) { + // start over + // TODO: make sure no memory leaks + rbio = BIO_new(BIO_s_mem()); + wbio = BIO_new(BIO_s_mem()); + if (in != nullptr || in_len != 0) { + BIO_write(rbio, in, in_len); + } + SSL_set_bio(this->_ssl, rbio, wbio); + + ret = SSL_stateless(this->_ssl); + if (ret >= 0) { + Debug(tag, "Sending HRR"); + this->_stateless = false; + } else { + Debug(tag, "SSL_stateless error"); + } + } else { + ret = SSL_accept(this->_ssl); } + } else { + ret = SSL_connect(this->_ssl); } - ERR_clear_error(); - int ret = SSL_do_handshake(this->_ssl); - if (ret <= 0) { + + if (ret < 0) { err = SSL_get_error(this->_ssl, ret); switch (err) { @@ -97,8 +128,8 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint break; default: char err_buf[256] = {0}; - ERR_error_string_n(err, err_buf, sizeof(err_buf)); - Debug(tag, "Handshake error: %s (%d)", err_buf, err); + ERR_error_string_n(ERR_get_error(), err_buf, sizeof(err_buf)); + Debug(tag, "Handshake: %s", err_buf); return err; } } @@ -128,6 +159,12 @@ QUICTLS::is_key_derived(QUICKeyPhase key_phase) const } } +bool +QUICTLS::is_stateless() +{ + return this->_stateless; +} + int QUICTLS::initialize_key_materials(QUICConnectionId cid) { diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 0ac7c10abbb..5de0dcc472d 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -40,6 +40,7 @@ class QUICTLS : public QUICHandshakeProtocol { public: QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx); + QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless); ~QUICTLS(); int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override; @@ -54,6 +55,7 @@ class QUICTLS : public QUICHandshakeProtocol // FIXME SSL handle should not be exported SSL *ssl_handle(); + bool is_stateless(); private: QUICKeyGenerator _keygen_for_client = QUICKeyGenerator(QUICKeyGenerator::Context::CLIENT); @@ -80,8 +82,9 @@ class QUICTLS : public QUICHandshakeProtocol QUICPacketProtection *_client_pp = nullptr; QUICPacketProtection *_server_pp = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; - - bool _early_data_processed = false; + bool _stateless = false; + bool _early_data_processed = false; + bool _early_data = true; int _read_early_data(); void _generate_0rtt_key(); }; diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 07360678e1d..ccc17efedfb 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -56,6 +56,54 @@ print_hex(const uint8_t *v, size_t len) return; } +static const uint8_t original[] = { + 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x20, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const uint64_t pkt_num = 0x123456789; +static const uint8_t ad[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + +/* Fixed value used in the ServerHello random field to identify an HRR */ +const unsigned char hrr_random[] = { + 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91, + 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c, +}; + +static const bool +is_hrr(uint8_t *msg, size_t msg_len) +{ + return memmem(msg, msg_len, hrr_random, sizeof(hrr_random)) != nullptr; +} + +// dummy token to simplify test +static uint8_t token[] = {0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, + 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, + 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, + 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef}; + +static int +generate_cookie_callback(SSL * /* ssl */, unsigned char *cookie, size_t *cookie_len) +{ + memcpy(cookie, token, sizeof(token)); + *cookie_len = sizeof(token); + + return 1; +} + +static int +verify_cookie_callback(SSL *ssl, const unsigned char *cookie, size_t cookie_len) +{ + if (memcmp(token, cookie, sizeof(token)) == 0) { + return 1; + } else { + return 0; + } +} + + + TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]") { // Client @@ -80,15 +128,6 @@ TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]") CHECK(server->initialize_key_materials(0x8394c8f03e515700)); // encrypt - decrypt - uint8_t original[] = { - 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x20, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - uint64_t pkt_num = 0x123456789; - uint8_t ad[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; - // client (encrypt) - server (decrypt) std::cout << "### Original Text" << std::endl; print_hex(original, sizeof(original)); @@ -175,15 +214,364 @@ TEST_CASE("QUICHandshakeProtocol 1-RTT", "[quic]") CHECK(server->update_key_materials()); // encrypt - decrypt - uint8_t original[] = { - 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x20, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - uint64_t pkt_num = 0x123456789; - uint8_t ad[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + // client (encrypt) - server (decrypt) + std::cout << "### Original Text" << std::endl; + print_hex(original, sizeof(original)); + + uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead + size_t cipher_len = 0; + CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), + QUICKeyPhase::PHASE_0)); + + std::cout << "### Encrypted Text" << std::endl; + print_hex(cipher, cipher_len); + + uint8_t plain[128] = {0}; + size_t plain_len = 0; + CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); + + std::cout << "### Decrypted Text" << std::endl; + print_hex(plain, plain_len); + + CHECK(sizeof(original) == (plain_len)); + CHECK(memcmp(original, plain, plain_len) == 0); + + // Teardown + delete client; + delete server; +} + +// HRR - Incorrect DHE Share +// NOTE: This is *NOT* client address validation. +// https://tools.ietf.org/html/draft-ietf-tls-tls13-26 - 2.1. Incorrect DHE Share +TEST_CASE("QUICHandshakeProtocol 1-RTT HRR key_share mismatch", "[quic]") +{ + // Client + SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + + QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + + // Server + SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); + SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); + BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); + SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); + + // client key_share will be X25519 (default of OpenSSL) + if (SSL_CTX_set1_groups_list(server_ssl_ctx, "P-521:P-384:P-256") != 1) { + REQUIRE(false); + } + + QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + + CHECK(client->initialize_key_materials(0x8394c8f03e515708)); + CHECK(server->initialize_key_materials(0x8394c8f03e515708)); + + // Client Hello + uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t client_hello_len = 0; + REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); + REQUIRE(client_hello_len > 0); + std::cout << "### Client Hello" << std::endl; + print_hex(client_hello, client_hello_len); + + // Hello Retry Request w/o cookie + uint8_t retry[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t retry_len = 0; + REQUIRE(server->handshake(retry, retry_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == SSL_ERROR_WANT_READ); + REQUIRE(retry_len > 0); + REQUIRE(is_hrr(retry, retry_len)); + std::cout << "### HRR" << std::endl; + print_hex(retry, retry_len); + + // Client Hello w/ cookie + memset(client_hello, 0, MAX_HANDSHAKE_MSG_LEN); + client_hello_len = 0; + REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, retry, retry_len) == SSL_ERROR_WANT_READ); + REQUIRE(client_hello_len > 0); + std::cout << "### Client Hello" << std::endl; + print_hex(client_hello, client_hello_len); + + // Server Hello + uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t server_hello_len = 0; + REQUIRE(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == + SSL_ERROR_WANT_READ); + REQUIRE(server_hello_len > 0); + std::cout << "### Server Hello" << std::endl; + print_hex(server_hello, server_hello_len); + + // Client Fnished + uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t client_finished_len = 0; + REQUIRE(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == + SSL_ERROR_NONE); + REQUIRE(client_finished_len > 0); + std::cout << "### Client Finished" << std::endl; + print_hex(client_finished, client_finished_len); + + CHECK(client->update_key_materials()); + + // Post Handshake Msg + uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t post_handshake_msg_len = 0; + REQUIRE(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, + client_finished_len) == SSL_ERROR_NONE); + std::cout << "### Post Handshake Message" << std::endl; + print_hex(post_handshake_msg, post_handshake_msg_len); + + CHECK(server->update_key_materials()); + + // encrypt - decrypt + // client (encrypt) - server (decrypt) + std::cout << "### Original Text" << std::endl; + print_hex(original, sizeof(original)); + uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead + size_t cipher_len = 0; + CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), + QUICKeyPhase::PHASE_0)); + + std::cout << "### Encrypted Text" << std::endl; + print_hex(cipher, cipher_len); + + uint8_t plain[128] = {0}; + size_t plain_len = 0; + CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); + + std::cout << "### Decrypted Text" << std::endl; + print_hex(plain, plain_len); + + CHECK(sizeof(original) == (plain_len)); + CHECK(memcmp(original, plain, plain_len) == 0); + + // Teardown + delete client; + delete server; +} + +// HRR for client address varidation +TEST_CASE("QUICHandshakeProtocol 1-RTT HRR statless", "[quic]") +{ + // Client + SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + + QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + + // Server + SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); + SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); + BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); + SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); + + // callbacks for cookie ext + // Requires OpenSSL-1.1.1-rc3+ : https://github.com/openssl/openssl/pull/5463 + SSL_CTX_set_stateless_cookie_generate_cb(server_ssl_ctx, generate_cookie_callback); + SSL_CTX_set_stateless_cookie_verify_cb(server_ssl_ctx, verify_cookie_callback); + + bool stateless = true; + QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN, stateless); + + CHECK(client->initialize_key_materials(0x8394c8f03e515708)); + CHECK(server->initialize_key_materials(0x8394c8f03e515708)); + + // Client Hello + uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t client_hello_len = 0; + REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); + REQUIRE(client_hello_len > 0); + std::cout << "### Client Hello" << std::endl; + print_hex(client_hello, client_hello_len); + + // Hello Retry Request + uint8_t retry[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t retry_len = 0; + CHECK(server->handshake(retry, retry_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == SSL_ERROR_NONE); + REQUIRE(retry_len > 0); + CHECK(is_hrr(retry, retry_len)); + std::cout << "### HRR" << std::endl; + print_hex(retry, retry_len); + + // Make sure "stateless" + delete server; + server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN, stateless); + + // Client Hello w/ cookie + memset(client_hello, 0, MAX_HANDSHAKE_MSG_LEN); + client_hello_len = 0; + CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, retry, retry_len) == SSL_ERROR_WANT_READ); + REQUIRE(client_hello_len > 0); + std::cout << "### Client Hello" << std::endl; + print_hex(client_hello, client_hello_len); + + // Server Hello + uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t server_hello_len = 0; + REQUIRE(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == + SSL_ERROR_NONE); + REQUIRE(server_hello_len > 0); + std::cout << "### Server Hello" << std::endl; + print_hex(server_hello, server_hello_len); + + // Client Fnished + uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t client_finished_len = 0; + REQUIRE(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == + SSL_ERROR_NONE); + REQUIRE(client_finished_len > 0); + std::cout << "### Client Finished" << std::endl; + print_hex(client_finished, client_finished_len); + + CHECK(client->update_key_materials()); + + // Post Handshake Msg + uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t post_handshake_msg_len = 0; + REQUIRE(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, + client_finished_len) == SSL_ERROR_NONE); + std::cout << "### Post Handshake Message" << std::endl; + print_hex(post_handshake_msg, post_handshake_msg_len); + + CHECK(server->update_key_materials()); + + // encrypt - decrypt + // client (encrypt) - server (decrypt) + std::cout << "### Original Text" << std::endl; + print_hex(original, sizeof(original)); + + uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead + size_t cipher_len = 0; + CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), + QUICKeyPhase::PHASE_0)); + + std::cout << "### Encrypted Text" << std::endl; + print_hex(cipher, cipher_len); + + uint8_t plain[128] = {0}; + size_t plain_len = 0; + CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); + + std::cout << "### Decrypted Text" << std::endl; + print_hex(plain, plain_len); + + CHECK(sizeof(original) == (plain_len)); + CHECK(memcmp(original, plain, plain_len) == 0); + + // Teardown + delete client; + delete server; +} + +// HRR for client address varidation & Incorrect DHE Share +TEST_CASE("QUICHandshakeProtocol 1-RTT HRR statless & key_share mismatch", "[quic]") +{ + // Client + SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + + QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + + // Server + SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); + SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); + BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); + SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); + + // client key_share will be X25519 (default of OpenSSL) + if (SSL_CTX_set1_groups_list(server_ssl_ctx, "P-521:P-384:P-256") != 1) { + REQUIRE(false); + } + + // callbacks for cookie ext + SSL_CTX_set_stateless_cookie_generate_cb(server_ssl_ctx, generate_cookie_callback); + SSL_CTX_set_stateless_cookie_verify_cb(server_ssl_ctx, verify_cookie_callback); + + bool stateless = true; + QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN, stateless); + + CHECK(client->initialize_key_materials(0x8394c8f03e515708)); + CHECK(server->initialize_key_materials(0x8394c8f03e515708)); + + // Client Hello + uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t client_hello_len = 0; + REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); + REQUIRE(client_hello_len > 0); + std::cout << "### Client Hello" << std::endl; + print_hex(client_hello, client_hello_len); + + // Hello Retry Request + uint8_t retry[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t retry_len = 0; + CHECK(server->handshake(retry, retry_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == SSL_ERROR_NONE); + REQUIRE(retry_len > 0); + REQUIRE(is_hrr(retry, retry_len)); + std::cout << "### HRR" << std::endl; + print_hex(retry, retry_len); + + // Make sure "stateless" + delete server; + server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN, stateless); + + // Client Hello w/ cookie + memset(client_hello, 0, MAX_HANDSHAKE_MSG_LEN); + client_hello_len = 0; + REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, retry, retry_len) == SSL_ERROR_WANT_READ); + REQUIRE(client_hello_len > 0); + std::cout << "### Client Hello" << std::endl; + print_hex(client_hello, client_hello_len); + + // Server Hello + uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t server_hello_len = 0; + REQUIRE(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == + SSL_ERROR_NONE); + REQUIRE(server_hello_len > 0); + std::cout << "### Server Hello" << std::endl; + print_hex(server_hello, server_hello_len); + + // Client Fnished + uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t client_finished_len = 0; + CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == + SSL_ERROR_NONE); + REQUIRE(client_finished_len > 0); + std::cout << "### Client Finished" << std::endl; + print_hex(client_finished, client_finished_len); + + CHECK(client->update_key_materials()); + + // Post Handshake Msg + uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t post_handshake_msg_len = 0; + REQUIRE(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, + client_finished_len) == SSL_ERROR_NONE); + std::cout << "### Post Handshake Message" << std::endl; + print_hex(post_handshake_msg, post_handshake_msg_len); + + CHECK(server->update_key_materials()); + + // encrypt - decrypt // client (encrypt) - server (decrypt) std::cout << "### Original Text" << std::endl; print_hex(original, sizeof(original)); From 94263e8967288676c1d3f16910a8cad9c9f2a16b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 13 Mar 2018 17:03:11 +0900 Subject: [PATCH 0428/1313] Delay key driviation until it's ready to do that --- iocore/net/quic/Mock.h | 6 ++++++ iocore/net/quic/QUICHandshake.cc | 2 +- iocore/net/quic/QUICHandshakeProtocol.h | 1 + iocore/net/quic/QUICTLS.cc | 6 ++++++ iocore/net/quic/QUICTLS.h | 1 + iocore/net/quic/test/test_QUICHandshakeProtocol.cc | 2 -- iocore/net/quic/test/test_QUICLossDetector.cc | 4 ++-- iocore/net/quic/test/test_QUICPacket.cc | 6 +++--- iocore/net/quic/test/test_QUICPacketFactory.cc | 3 ++- 9 files changed, 22 insertions(+), 9 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 31a9fd49b0d..23625619bda 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -476,6 +476,12 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol return true; } + bool + is_ready_to_derive() const override + { + return true; + }; + bool is_key_derived(QUICKeyPhase /* key_phase */) const override { return true; } int diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index d71e8c4021c..428106a116a 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -464,7 +464,7 @@ QUICHandshake::_do_handshake(bool initial) stream_io->write(out, out_len); } - if (!this->_hs_protocol->is_key_derived(QUICKeyPhase::PHASE_0)) { + if (!this->_hs_protocol->is_key_derived(QUICKeyPhase::PHASE_0) && this->_hs_protocol->is_ready_to_derive()) { int res = this->_hs_protocol->update_key_materials(); if (res) { QUICHSDebug("Keying Materials are exported"); diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 13c45a48f33..86412f4d099 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -51,6 +51,7 @@ class QUICHandshakeProtocol virtual int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) = 0; virtual bool is_handshake_finished() const = 0; + virtual bool is_ready_to_derive() const = 0; virtual bool is_key_derived(QUICKeyPhase key_phase) const = 0; virtual int initialize_key_materials(QUICConnectionId cid) = 0; virtual int update_key_materials() = 0; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 44412607f35..74e8c46ca7b 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -149,6 +149,12 @@ QUICTLS::is_handshake_finished() const return SSL_is_init_finished(this->_ssl); } +bool +QUICTLS::is_ready_to_derive() const +{ + return SSL_get_current_cipher(this->_ssl) != nullptr; +} + bool QUICTLS::is_key_derived(QUICKeyPhase key_phase) const { diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 5de0dcc472d..20d1c61f1e2 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -45,6 +45,7 @@ class QUICTLS : public QUICHandshakeProtocol int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override; bool is_handshake_finished() const override; + bool is_ready_to_derive() const override; bool is_key_derived(QUICKeyPhase key_phase) const override; int initialize_key_materials(QUICConnectionId cid) override; int update_key_materials() override; diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index ccc17efedfb..3b51d870a03 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -102,8 +102,6 @@ verify_cookie_callback(SSL *ssl, const unsigned char *cookie, size_t cookie_len) } } - - TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]") { // Client diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 963be5fb2b2..3fbfbb39d81 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -54,8 +54,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, 0xffddbb9977553311ULL, 0x00000001, 0, 0x00112233, - std::move(payload), sizeof(raw)); + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, 0xffddbb9977553311ULL, 0x00000001, 0, + 0x00112233, std::move(payload), sizeof(raw)); QUICPacketUPtr packet = QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true), [](QUICPacket *p) { delete p; }); detector.on_packet_sent(std::move(packet)); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index d8bf64d6235..1d79ac21e0c 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -37,7 +37,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0x00, 0x00, 0x00, 0x09, // Supported Version 1 }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({const_cast(input), [](void *p) {}}, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({const_cast(input), [](void *p) {}}, sizeof(input), 0); CHECK(header->size() == 13); CHECK(header->packet_size() == 21); CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); @@ -58,7 +58,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0xff, 0xff, // Payload (dummy) }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({const_cast(input), [](void *p) {}}, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({const_cast(input), [](void *p) {}}, sizeof(input), 0); CHECK(header->size() == 17); CHECK(header->packet_size() == 19); CHECK(header->type() == QUICPacketType::INITIAL); @@ -141,7 +141,7 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") ats_unique_buf payload = ats_unique_malloc(5); memcpy(payload.get(), expected + 13, 5); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, 0x0102030405060708, - 0x12345678, 0, std::move(payload), 32); + 0x12345678, 0, std::move(payload), 32); CHECK(header->size() == 13); CHECK(header->packet_size() == 0); CHECK(header->has_key_phase() == true); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 853f43600b7..4f84f2d6036 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -42,7 +42,8 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x00 // Payload }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({client_initial_packet_header, [](void *) {}}, sizeof(client_initial_packet_header), 0); + QUICPacketHeaderUPtr header = + QUICPacketHeader::load({client_initial_packet_header, [](void *) {}}, sizeof(client_initial_packet_header), 0); QUICPacket client_initial_packet(std::move(header), ats_unique_buf(client_initial_packet_payload, [](void *) {}), sizeof(client_initial_packet_payload), 0); From c9845e0ed9d68ad2dd6abecd40f0e609459aea37 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 14 Mar 2018 09:31:32 +0900 Subject: [PATCH 0429/1313] Create RETRY packet --- iocore/net/quic/QUICPacket.cc | 10 ++++++++++ iocore/net/quic/QUICPacket.h | 2 ++ .../net/quic/test/test_QUICPacketFactory.cc | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 659e826fed0..35e8749e644 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -782,6 +782,16 @@ QUICPacketFactory::create_initial_packet(QUICConnectionId connection_id, QUICPac return this->_create_encrypted_packet(std::move(header), true); } +// retransmittable? depends on stateless? +QUICPacketUPtr +QUICPacketFactory::create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, + size_t len) +{ + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, connection_id, this->_packet_number_generator.next(), + base_packet_number, this->_version, std::move(payload), len); + return this->_create_encrypted_packet(std::move(header), false); +} + QUICPacketUPtr QUICPacketFactory::create_handshake_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 6306955d9f9..c4b13cb7535 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -342,6 +342,8 @@ class QUICPacketFactory QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number); QUICPacketUPtr create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); + QUICPacketUPtr create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, + size_t len); QUICPacketUPtr create_handshake_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); QUICPacketUPtr create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 4f84f2d6036..d90ba775947 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -55,6 +55,25 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") CHECK(memcmp(packet->payload(), "\xff\x00\x00\x09", 4) == 0); } +TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") +{ + QUICPacketFactory factory; + MockQUICHandshakeProtocol hs_protocol; + factory.set_hs_protocol(&hs_protocol); + factory.set_version(0x11223344); + + uint8_t raw[] = {0xaa, 0xbb, 0xcc, 0xdd}; + ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); + memcpy(payload.get(), raw, sizeof(raw)); + + QUICPacketUPtr packet = factory.create_retry_packet(0x01020304, 0, std::move(payload), sizeof(raw)); + CHECK(packet->type() == QUICPacketType::RETRY); + CHECK(packet->connection_id() == 0x01020304); + CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); + CHECK((packet->packet_number() & 0xFFFFFFFF80000000) == 0); + CHECK(packet->version() == 0x11223344); +} + TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") { QUICPacketFactory factory; From 3d549767e6379eb6fb1e415b1ffdf6a508cf8549 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 14 Mar 2018 16:26:18 +0900 Subject: [PATCH 0430/1313] Separate out QUICVariableInt from QUICUtil so that HQ can use it --- iocore/net/quic/Makefile.am | 1 + iocore/net/quic/QUICFrame.cc | 43 +++--- iocore/net/quic/QUICIntUtil.cc | 129 ++++++++++++++++++ iocore/net/quic/QUICIntUtil.h | 45 +++++++ iocore/net/quic/QUICTransportParameters.cc | 33 ++--- iocore/net/quic/QUICTypes.cc | 149 +++------------------ iocore/net/quic/QUICTypes.h | 25 +--- iocore/net/quic/test/Makefile.am | 9 ++ iocore/net/quic/test/test_QUICTypeUtil.cc | 19 +-- lib/ts/ink_endian.h | 34 +++++ 10 files changed, 287 insertions(+), 200 deletions(-) create mode 100644 iocore/net/quic/QUICIntUtil.cc create mode 100644 iocore/net/quic/QUICIntUtil.h create mode 100644 lib/ts/ink_endian.h diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 63636734baf..7898ddf95a8 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -46,6 +46,7 @@ endif libquic_a_SOURCES = \ QUICGlobals.cc \ QUICTypes.cc \ + QUICIntUtil.cc \ QUICPacket.cc \ QUICFrame.cc \ QUICFrameDispatcher.cc \ diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 92fd9612368..bb12bedccb6 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -23,6 +23,7 @@ #include "QUICFrame.h" #include "QUICStream.h" +#include "QUICIntUtil.h" ClassAllocator quicStreamFrameAllocator("quicStreamFrameAllocator"); ClassAllocator quicAckFrameAllocator("quicAckFrameAllocator"); @@ -122,7 +123,7 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, bool include_length_field) con // [Length (i)] "L of "0b0010OLF" if (include_length_field) { - QUICTypeUtil::write_QUICVariableInt(this->data_length(), buf + *len, &n); + QUICIntUtil::write_QUICVariableInt(this->data_length(), buf + *len, &n); *len += n; buf[0] += 0x02; } @@ -166,7 +167,7 @@ QUICStreamFrame::data_length() const { if (this->_buf) { if (this->has_length_field()) { - return QUICTypeUtil::read_QUICVariableInt(this->_buf + this->_get_length_field_offset()); + return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_length_field_offset()); } else { return this->_len - this->_get_data_field_offset(); } @@ -358,11 +359,11 @@ QUICAckFrame::store(uint8_t *buf, size_t *len) const *p = static_cast(QUICFrameType::ACK); ++p; - QUICTypeUtil::write_QUICVariableInt(this->_largest_acknowledged, p, &n); + QUICIntUtil::write_QUICVariableInt(this->_largest_acknowledged, p, &n); p += n; - QUICTypeUtil::write_QUICVariableInt(this->_ack_delay, p, &n); + QUICIntUtil::write_QUICVariableInt(this->_ack_delay, p, &n); p += n; - QUICTypeUtil::write_QUICVariableInt(this->ack_block_count(), p, &n); + QUICIntUtil::write_QUICVariableInt(this->ack_block_count(), p, &n); p += n; this->_ack_block_section->store(p, &n); p += n; @@ -390,7 +391,7 @@ uint64_t QUICAckFrame::ack_delay() const { if (this->_buf) { - return QUICTypeUtil::read_QUICVariableInt(this->_buf + this->_get_ack_delay_offset()); + return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_ack_delay_offset()); } else { return this->_ack_delay; } @@ -400,7 +401,7 @@ uint64_t QUICAckFrame::ack_block_count() const { if (this->_buf) { - return QUICTypeUtil::read_QUICVariableInt(this->_buf + this->_get_ack_block_count_offset()); + return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_ack_block_count_offset()); } else { return this->_ack_block_section->count(); } @@ -479,7 +480,7 @@ uint64_t QUICAckFrame::AckBlock::gap() const { if (this->_buf) { - return QUICTypeUtil::read_QUICVariableInt(this->_buf); + return QUICIntUtil::read_QUICVariableInt(this->_buf); } else { return this->_gap; } @@ -489,7 +490,7 @@ uint64_t QUICAckFrame::AckBlock::length() const { if (this->_buf) { - return QUICTypeUtil::read_QUICVariableInt(this->_buf + this->_get_gap_size()); + return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_gap_size()); } else { return this->_length; } @@ -560,13 +561,13 @@ QUICAckFrame::AckBlockSection::store(uint8_t *buf, size_t *len) const size_t n; uint8_t *p = buf; - QUICTypeUtil::write_QUICVariableInt(this->_first_ack_block_length, p, &n); + QUICIntUtil::write_QUICVariableInt(this->_first_ack_block_length, p, &n); p += n; for (auto &&block : *this) { - QUICTypeUtil::write_QUICVariableInt(block.gap(), p, &n); + QUICIntUtil::write_QUICVariableInt(block.gap(), p, &n); p += n; - QUICTypeUtil::write_QUICVariableInt(block.length(), p, &n); + QUICIntUtil::write_QUICVariableInt(block.length(), p, &n); p += n; } @@ -577,7 +578,7 @@ uint64_t QUICAckFrame::AckBlockSection::first_ack_block_length() const { if (this->_buf) { - return QUICTypeUtil::read_QUICVariableInt(this->_buf); + return QUICIntUtil::read_QUICVariableInt(this->_buf); } else { return this->_first_ack_block_length; } @@ -831,7 +832,7 @@ uint8_t QUICPingFrame::data_length() const { if (this->_buf) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf + sizeof(QUICFrameType), 1); + return QUICIntUtil::read_nbytes_as_uint(this->_buf + sizeof(QUICFrameType), 1); } else { return this->_data_len; } @@ -902,7 +903,7 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len) const ++p; QUICTypeUtil::write_QUICTransErrorCode(this->_error_code, p, &n); p += n; - QUICTypeUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); + QUICIntUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); p += n; if (this->_reason_phrase_length > 0) { memcpy(p, this->_reason_phrase, this->_reason_phrase_length); @@ -927,7 +928,7 @@ uint64_t QUICConnectionCloseFrame::reason_phrase_length() const { if (this->_buf) { - return QUICTypeUtil::read_QUICVariableInt(this->_buf + this->_get_reason_phrase_length_field_offset()); + return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_reason_phrase_length_field_offset()); } else { return this->_reason_phrase_length; } @@ -1002,7 +1003,7 @@ QUICApplicationCloseFrame::store(uint8_t *buf, size_t *len) const ++p; QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); p += n; - QUICTypeUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); + QUICIntUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); p += n; if (this->_reason_phrase_length > 0) { memcpy(p, this->_reason_phrase, this->_reason_phrase_length); @@ -1027,7 +1028,7 @@ uint64_t QUICApplicationCloseFrame::reason_phrase_length() const { if (this->_buf) { - return QUICTypeUtil::read_QUICVariableInt(this->_buf + this->_get_reason_phrase_length_field_offset()); + return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_reason_phrase_length_field_offset()); } else { return this->_reason_phrase_length; } @@ -1490,7 +1491,7 @@ QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len) const uint8_t *p = buf; *p = static_cast(QUICFrameType::NEW_CONNECTION_ID); ++p; - QUICTypeUtil::write_QUICVariableInt(this->_sequence, p, &n); + QUICIntUtil::write_QUICVariableInt(this->_sequence, p, &n); p += n; QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, p, &n); p += n; @@ -1505,7 +1506,7 @@ uint64_t QUICNewConnectionIdFrame::sequence() const { if (this->_buf) { - return QUICTypeUtil::read_QUICVariableInt(this->_buf + sizeof(QUICFrameType)); + return QUICIntUtil::read_QUICVariableInt(this->_buf + sizeof(QUICFrameType)); } else { return this->_sequence; } @@ -1668,7 +1669,7 @@ uint8_t QUICPongFrame::data_length() const { if (this->_buf) { - return QUICTypeUtil::read_nbytes_as_uint(this->_buf + sizeof(QUICFrameType), 1); + return QUICIntUtil::read_nbytes_as_uint(this->_buf + sizeof(QUICFrameType), 1); } else { return this->_data_len; } diff --git a/iocore/net/quic/QUICIntUtil.cc b/iocore/net/quic/QUICIntUtil.cc new file mode 100644 index 00000000000..00d20dea59e --- /dev/null +++ b/iocore/net/quic/QUICIntUtil.cc @@ -0,0 +1,129 @@ +/** @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 "QUICIntUtil.h" +#include "ts/ink_endian.h" +#include + +size_t +QUICVariableInt::size(const uint8_t *src) +{ + return 1 << (src[0] >> 6); +} + +size_t +QUICVariableInt::size(uint64_t src) +{ + uint8_t flag = 0; + if (src > 4611686018427387903) { + // max usable bits is 62 + return 0; + } else if (src > 1073741823) { + flag = 0x03; + } else if (src > 16383) { + flag = 0x02; + } else if (src > 63) { + flag = 0x01; + } else { + flag = 0x00; + } + + return 1 << flag; +} + +int +QUICVariableInt::encode(uint8_t *dst, size_t dst_len, size_t &len, uint64_t src) +{ + uint8_t flag = 0; + if (src > 4611686018427387903) { + // max usable bits is 62 + return 1; + } else if (src > 1073741823) { + flag = 0x03; + } else if (src > 16383) { + flag = 0x02; + } else if (src > 63) { + flag = 0x01; + } else { + flag = 0x00; + } + + len = 1 << flag; + if (len > dst_len) { + return 1; + } + + size_t dummy = 0; + QUICIntUtil::write_uint_as_nbytes(src, len, dst, &dummy); + dst[0] |= (flag << 6); + + return 0; +} + +int +QUICVariableInt::decode(uint64_t &dst, size_t &len, const uint8_t *src, size_t src_len) +{ + len = 1 << (src[0] >> 6); + if (src_len < len) { + return 1; + } + + uint8_t buf[8] = {0}; + memcpy(buf, src, len); + buf[0] &= 0x3f; + + dst = QUICIntUtil::read_nbytes_as_uint(buf, len); + + return 0; +} + +uint64_t +QUICIntUtil::read_QUICVariableInt(const uint8_t *buf) +{ + uint64_t dst = 0; + size_t len = 0; + QUICVariableInt::decode(dst, len, buf, 8); + return dst; +} + +void +QUICIntUtil::write_QUICVariableInt(uint64_t data, uint8_t *buf, size_t *len) +{ + QUICVariableInt::encode(buf, 8, *len, data); +} + +uint64_t +QUICIntUtil::read_nbytes_as_uint(const uint8_t *buf, uint8_t n) +{ + uint64_t value = 0; + memcpy(&value, buf, n); + return be64toh(value << (64 - n * 8)); +} + +void +QUICIntUtil::write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size_t *len) +{ + value = htobe64(value) >> (64 - n * 8); + memcpy(buf, reinterpret_cast(&value), n); + *len = n; +} diff --git a/iocore/net/quic/QUICIntUtil.h b/iocore/net/quic/QUICIntUtil.h new file mode 100644 index 00000000000..c259bca682a --- /dev/null +++ b/iocore/net/quic/QUICIntUtil.h @@ -0,0 +1,45 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +class QUICVariableInt +{ +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); +}; + +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); +}; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index bf524ecfc6f..7b74a6f0986 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -24,6 +24,7 @@ #include #include "ts/Diags.h" #include "QUICGlobals.h" +#include "QUICIntUtil.h" #include "QUICTransportParameters.h" #include "QUICConnection.h" #include "QUICHandshake.h" @@ -160,7 +161,7 @@ QUICTransportParameters::_validate_parameters() const if (ite->second->len() != 2) { return -5; } - if (QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 600) { + if (QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 600) { return -6; } } else { @@ -178,7 +179,7 @@ QUICTransportParameters::_validate_parameters() const if (ite->second->len() != 2) { return -9; } - if (QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) < 1200) { + if (QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) < 1200) { return -10; } } @@ -187,7 +188,7 @@ QUICTransportParameters::_validate_parameters() const if (ite->second->len() != 1) { return -11; } - if (QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 20) { + if (QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 20) { return -12; } } @@ -214,7 +215,7 @@ QUICTransportParameters::getAsUInt8(QUICTransportParameterId tpid) const uint16_t len = 0; const uint8_t *value = this->getAsBytes(tpid, len); if (value) { - return QUICTypeUtil::read_nbytes_as_uint(value, 1); + return QUICIntUtil::read_nbytes_as_uint(value, 1); } else { return 0; } @@ -226,7 +227,7 @@ QUICTransportParameters::getAsUInt16(QUICTransportParameterId tpid) const uint16_t len = 0; const uint8_t *value = this->getAsBytes(tpid, len); if (value) { - return QUICTypeUtil::read_nbytes_as_uint(value, 2); + return QUICIntUtil::read_nbytes_as_uint(value, 2); } else { return 0; } @@ -238,7 +239,7 @@ QUICTransportParameters::getAsUInt32(QUICTransportParameterId tpid) const uint16_t len = 0; const uint8_t *value = this->getAsBytes(tpid, len); if (value) { - return QUICTypeUtil::read_nbytes_as_uint(value, 4); + return QUICIntUtil::read_nbytes_as_uint(value, 4); } else { return 0; } @@ -258,7 +259,7 @@ QUICTransportParameters::set(QUICTransportParameterId id, uint16_t value) { uint8_t v[2]; size_t n; - QUICTypeUtil::write_uint_as_nbytes(value, 2, v, &n); + QUICIntUtil::write_uint_as_nbytes(value, 2, v, &n); this->set(id, v, 2); } @@ -267,7 +268,7 @@ QUICTransportParameters::set(QUICTransportParameterId id, uint32_t value) { uint8_t v[4]; size_t n; - QUICTypeUtil::write_uint_as_nbytes(value, 4, v, &n); + QUICIntUtil::write_uint_as_nbytes(value, 4, v, &n); this->set(id, v, 4); } @@ -312,8 +313,8 @@ QUICTransportParameters::_print() const Debug(tag, "%s: (no value)", QUICDebugNames::transport_parameter_id(p.first)); } else if (p.second->len() <= 8) { Debug(tag, "%s: 0x%" PRIx64 " (%" PRIu64 ")", QUICDebugNames::transport_parameter_id(p.first), - QUICTypeUtil::read_nbytes_as_uint(p.second->data(), p.second->len()), - QUICTypeUtil::read_nbytes_as_uint(p.second->data(), p.second->len())); + QUICIntUtil::read_nbytes_as_uint(p.second->data(), p.second->len()), + QUICIntUtil::read_nbytes_as_uint(p.second->data(), p.second->len())); } else { Debug(tag, "%s: (long data)", QUICDebugNames::transport_parameter_id(p.first)); } @@ -366,7 +367,7 @@ QUICTransportParametersInClientHello::_validate_parameters() const if (ite->second->len() != 4) { return -2; } - if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != + if (QUICTypeUtil::detect_stream_type(QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != QUICStreamType::SERVER_BIDI) { return -3; } @@ -376,7 +377,7 @@ QUICTransportParametersInClientHello::_validate_parameters() const if (ite->second->len() != 4) { return -4; } - if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != + if (QUICTypeUtil::detect_stream_type(QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != QUICStreamType::SERVER_UNI) { return -5; } @@ -468,7 +469,7 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const if (ite->second->len() != 4) { return -3; } - if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != + if (QUICTypeUtil::detect_stream_type(QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != QUICStreamType::CLIENT_BIDI) { return -4; } @@ -478,7 +479,7 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const if (ite->second->len() != 4) { return -5; } - if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != + if (QUICTypeUtil::detect_stream_type(QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != QUICStreamType::CLIENT_UNI) { return -6; } @@ -534,7 +535,7 @@ QUICTransportParametersInNewSessionTicket::_validate_parameters() const if (ite->second->len() != 4) { return -3; } - if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != + if (QUICTypeUtil::detect_stream_type(QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != QUICStreamType::CLIENT_BIDI) { return -4; } @@ -544,7 +545,7 @@ QUICTransportParametersInNewSessionTicket::_validate_parameters() const if (ite->second->len() != 4) { return -5; } - if (QUICTypeUtil::detect_stream_type(QUICTypeUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != + if (QUICTypeUtil::detect_stream_type(QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != QUICStreamType::CLIENT_UNI) { return -6; } diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 1b4c87ff0e6..1fe1fdc04e4 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -22,6 +22,7 @@ */ #include "QUICTypes.h" +#include "QUICIntUtil.h" ats_unique_buf ats_unique_malloc(size_t size) @@ -67,137 +68,97 @@ QUICConnectionId QUICTypeUtil::read_QUICConnectionId(const uint8_t *buf, uint8_t len) { // Should be QUICConnectionId(read_nbytes_as_uint(buf, len)); - return static_cast(read_nbytes_as_uint(buf, len)); + return static_cast(QUICIntUtil::read_nbytes_as_uint(buf, len)); } QUICPacketNumber QUICTypeUtil::read_QUICPacketNumber(const uint8_t *buf, uint8_t len) { - return static_cast(read_nbytes_as_uint(buf, len)); + return static_cast(QUICIntUtil::read_nbytes_as_uint(buf, len)); } QUICVersion QUICTypeUtil::read_QUICVersion(const uint8_t *buf) { - return static_cast(read_nbytes_as_uint(buf, 4)); + return static_cast(QUICIntUtil::read_nbytes_as_uint(buf, 4)); } QUICStreamId QUICTypeUtil::read_QUICStreamId(const uint8_t *buf) { - uint64_t stream_id = 0; - size_t len = 0; - QUICVariableInt::decode(stream_id, len, buf, 8); - return static_cast(stream_id); + return static_cast(QUICIntUtil::read_QUICVariableInt(buf)); } QUICOffset QUICTypeUtil::read_QUICOffset(const uint8_t *buf) { - uint64_t offset = 0; - size_t len = 0; - QUICVariableInt::decode(offset, len, buf, 8); - return static_cast(offset); + return static_cast(QUICIntUtil::read_QUICVariableInt(buf)); } QUICTransErrorCode QUICTypeUtil::read_QUICTransErrorCode(const uint8_t *buf) { - return static_cast(read_nbytes_as_uint(buf, 2)); + return static_cast(QUICIntUtil::read_nbytes_as_uint(buf, 2)); } QUICAppErrorCode QUICTypeUtil::read_QUICAppErrorCode(const uint8_t *buf) { - return static_cast(read_nbytes_as_uint(buf, 2)); + return static_cast(QUICIntUtil::read_nbytes_as_uint(buf, 2)); } uint64_t QUICTypeUtil::read_QUICMaxData(const uint8_t *buf) { - uint64_t max_data = 0; - size_t len = 0; - QUICVariableInt::decode(max_data, len, buf, 8); - return max_data; -} - -uint64_t -QUICTypeUtil::read_QUICVariableInt(const uint8_t *buf) -{ - uint64_t dst = 0; - size_t len = 0; - QUICVariableInt::decode(dst, len, buf, 8); - return dst; -} - -uint64_t -QUICTypeUtil::read_nbytes_as_uint(const uint8_t *buf, uint8_t n) -{ - uint64_t value = 0; - memcpy(&value, buf, n); - return be64toh(value << (64 - n * 8)); + return QUICIntUtil::read_QUICVariableInt(buf); } void QUICTypeUtil::write_QUICConnectionId(QUICConnectionId connection_id, uint8_t n, uint8_t *buf, size_t *len) { - write_uint_as_nbytes(static_cast(connection_id), n, buf, len); + QUICIntUtil::write_uint_as_nbytes(static_cast(connection_id), n, buf, len); } void QUICTypeUtil::write_QUICPacketNumber(QUICPacketNumber packet_number, uint8_t n, uint8_t *buf, size_t *len) { - write_uint_as_nbytes(static_cast(packet_number), n, buf, len); + QUICIntUtil::write_uint_as_nbytes(static_cast(packet_number), n, buf, len); } void QUICTypeUtil::write_QUICVersion(QUICVersion version, uint8_t *buf, size_t *len) { - write_uint_as_nbytes(static_cast(version), 4, buf, len); + QUICIntUtil::write_uint_as_nbytes(static_cast(version), 4, buf, len); } void QUICTypeUtil::write_QUICStreamId(QUICStreamId stream_id, uint8_t *buf, size_t *len) { - QUICVariableInt::encode(buf, 8, *len, stream_id); + QUICIntUtil::write_QUICVariableInt(stream_id, buf, len); } void QUICTypeUtil::write_QUICOffset(QUICOffset offset, uint8_t *buf, size_t *len) { - QUICVariableInt::encode(buf, 8, *len, offset); + QUICIntUtil::write_QUICVariableInt(offset, buf, len); } void QUICTypeUtil::write_QUICTransErrorCode(QUICTransErrorCode error_code, uint8_t *buf, size_t *len) { - write_uint_as_nbytes(static_cast(error_code), 2, buf, len); + QUICIntUtil::write_uint_as_nbytes(static_cast(error_code), 2, buf, len); } void QUICTypeUtil::write_QUICAppErrorCode(QUICAppErrorCode error_code, uint8_t *buf, size_t *len) { - write_uint_as_nbytes(static_cast(error_code), 2, buf, len); + QUICIntUtil::write_uint_as_nbytes(static_cast(error_code), 2, buf, len); } void QUICTypeUtil::write_QUICMaxData(uint64_t max_data, uint8_t *buf, size_t *len) { - QUICVariableInt::encode(buf, 8, *len, max_data); -} - -void -QUICTypeUtil::write_QUICVariableInt(uint64_t data, uint8_t *buf, size_t *len) -{ - QUICVariableInt::encode(buf, 8, *len, data); -} - -void -QUICTypeUtil::write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size_t *len) -{ - value = htobe64(value) >> (64 - n * 8); - memcpy(buf, reinterpret_cast(&value), n); - *len = n; + QUICIntUtil::write_QUICVariableInt(max_data, buf, len); } void @@ -211,8 +172,8 @@ QUICStatelessResetToken::_gen_token(uint64_t data) ctx.finalize(_hash); size_t dummy; - QUICTypeUtil::write_uint_as_nbytes(_hash.u64[0], 8, _token, &dummy); - QUICTypeUtil::write_uint_as_nbytes(_hash.u64[1], 8, _token + 8, &dummy); + QUICIntUtil::write_uint_as_nbytes(_hash.u64[0], 8, _token, &dummy); + QUICIntUtil::write_uint_as_nbytes(_hash.u64[1], 8, _token + 8, &dummy); } uint16_t @@ -220,75 +181,3 @@ QUICError::code() { return static_cast(this->trans_error_code); } - -size_t -QUICVariableInt::size(const uint8_t *src) -{ - return 1 << (src[0] >> 6); -} - -size_t -QUICVariableInt::size(uint64_t src) -{ - uint8_t flag = 0; - if (src > 4611686018427387903) { - // max usable bits is 62 - return 0; - } else if (src > 1073741823) { - flag = 0x03; - } else if (src > 16383) { - flag = 0x02; - } else if (src > 63) { - flag = 0x01; - } else { - flag = 0x00; - } - - return 1 << flag; -} - -int -QUICVariableInt::encode(uint8_t *dst, size_t dst_len, size_t &len, uint64_t src) -{ - uint8_t flag = 0; - if (src > 4611686018427387903) { - // max usable bits is 62 - return 1; - } else if (src > 1073741823) { - flag = 0x03; - } else if (src > 16383) { - flag = 0x02; - } else if (src > 63) { - flag = 0x01; - } else { - flag = 0x00; - } - - len = 1 << flag; - if (len > dst_len) { - return 1; - } - - size_t dummy = 0; - QUICTypeUtil::write_uint_as_nbytes(src, len, dst, &dummy); - dst[0] |= (flag << 6); - - return 0; -} - -int -QUICVariableInt::decode(uint64_t &dst, size_t &len, const uint8_t *src, size_t src_len) -{ - len = 1 << (src[0] >> 6); - if (src_len < len) { - return 1; - } - - uint8_t buf[8] = {0}; - memcpy(buf, src, len); - buf[0] &= 0x3f; - - dst = QUICTypeUtil::read_nbytes_as_uint(buf, len); - - return 0; -} diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 255b57796ff..7a36484ea33 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -23,16 +23,8 @@ #pragma once -#if defined(darwin) -#include -#define be64toh(x) OSSwapBigToHostInt64(x) -#define htobe64(x) OSSwapHostToBigInt64(x) -#elif defined(freebsd) -#include -#else -#include -#endif #include +#include "ts/ink_endian.h" #include #include @@ -274,7 +266,6 @@ class QUICTypeUtil static QUICTransErrorCode read_QUICTransErrorCode(const uint8_t *buf); static QUICAppErrorCode read_QUICAppErrorCode(const uint8_t *buf); static uint64_t read_QUICMaxData(const uint8_t *buf); - static uint64_t read_QUICVariableInt(const uint8_t *buf); static void write_QUICConnectionId(QUICConnectionId connection_id, uint8_t n, uint8_t *buf, size_t *len); static void write_QUICPacketNumber(QUICPacketNumber packet_number, uint8_t n, uint8_t *buf, size_t *len); @@ -285,19 +276,5 @@ class QUICTypeUtil static void write_QUICAppErrorCode(QUICAppErrorCode error_code, uint8_t *buf, size_t *len); static void write_QUICMaxData(uint64_t max_data, uint8_t *buf, size_t *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); - private: }; - -class QUICVariableInt -{ -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); -}; diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 6e05382892f..54c669ccd35 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -140,6 +140,7 @@ test_QUICFrame_SOURCES = \ ../QUICTLS.cc \ $(QUICTLS_impl) \ ../QUICTypes.cc \ + ../QUICIntUtil.cc \ ../QUICStream.cc \ ../QUICStreamState.cc \ ../QUICIncomingFrameBuffer.cc \ @@ -183,6 +184,7 @@ test_QUICFrameDispatcher_SOURCES = \ ../QUICApplication.cc \ ../QUICHandshake.cc \ ../QUICTypes.cc \ + ../QUICIntUtil.cc \ ../QUICEchoApp.cc \ ../QUICDebugNames.cc \ ../QUICHandshakeProtocol.cc \ @@ -324,6 +326,7 @@ test_QUICTransportParameters_SOURCES = \ ../QUICDebugNames.cc \ ../QUICTransportParameters.cc \ ../QUICTypes.cc \ + ../QUICIntUtil.cc \ ../../SSLNextProtocolSet.cc test_QUICTransportParameters_LDADD = \ @@ -365,6 +368,7 @@ test_QUICKeyGenerator_SOURCES = \ ../QUICFrame.cc \ ../QUICStream.cc \ ../QUICHKDF.cc \ + ../QUICIntUtil.cc \ ../QUICTypes.cc # @@ -396,6 +400,7 @@ test_QUICHandshakeProtocol_SOURCES = \ $(QUICTLS_impl) \ ../QUICHandshakeProtocol.h \ ../QUICTypes.cc \ + ../QUICIntUtil.cc \ ../QUICDebugNames.cc \ ../QUICStreamState.cc \ ../QUICFrame.cc \ @@ -469,6 +474,7 @@ test_QUICTypeUtil_SOURCES = \ ../QUICHandshakeProtocol.cc \ ../QUICTLS.cc \ $(QUICTLS_impl) \ + ../QUICIntUtil.cc \ ../QUICTypes.cc # @@ -493,6 +499,7 @@ test_QUICAckFrameCreator_SOURCES = \ ../QUICAckFrameCreator.cc \ ../QUICGlobals.cc \ ../QUICTypes.cc \ + ../QUICIntUtil.cc \ ../QUICFrame.cc \ ../QUICPacket.cc \ ../QUICStream.cc \ @@ -532,6 +539,7 @@ test_QUICVersionNegotiator_SOURCES = \ test_QUICVersionNegotiator.cc \ ../QUICGlobals.cc \ ../QUICTypes.cc \ + ../QUICIntUtil.cc \ ../QUICPacket.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ @@ -582,6 +590,7 @@ test_QUICFlowController_SOURCES = \ ../QUICStreamState.cc \ ../QUICDebugNames.cc \ ../QUICTypes.cc \ + ../QUICIntUtil.cc \ ../QUICPacket.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ diff --git a/iocore/net/quic/test/test_QUICTypeUtil.cc b/iocore/net/quic/test/test_QUICTypeUtil.cc index 99ae818e81b..b71ce4ab6ba 100644 --- a/iocore/net/quic/test/test_QUICTypeUtil.cc +++ b/iocore/net/quic/test/test_QUICTypeUtil.cc @@ -24,6 +24,7 @@ #include "catch.hpp" #include "quic/QUICTypes.h" +#include "quic/QUICIntUtil.h" #include TEST_CASE("QUICTypeUtil", "[quic]") @@ -31,39 +32,39 @@ TEST_CASE("QUICTypeUtil", "[quic]") uint8_t buf[8]; size_t len; - QUICTypeUtil::write_uint_as_nbytes(0xff, 1, buf, &len); + QUICIntUtil::write_uint_as_nbytes(0xff, 1, buf, &len); INFO("1 byte to 1 byte"); CHECK(memcmp(buf, "\xff\x00\x00\x00\x00\x00\x00\x00", 1) == 0); - QUICTypeUtil::write_uint_as_nbytes(0xff, 2, buf, &len); + QUICIntUtil::write_uint_as_nbytes(0xff, 2, buf, &len); INFO("1 byte to 2 byte"); CHECK(memcmp(buf, "\x00\xff\x00\x00\x00\x00\x00\x00", 2) == 0); - QUICTypeUtil::write_uint_as_nbytes(0xff, 4, buf, &len); + QUICIntUtil::write_uint_as_nbytes(0xff, 4, buf, &len); INFO("1 byte to 4 byte"); CHECK(memcmp(buf, "\x00\x00\x00\xff\x00\x00\x00\x00", 4) == 0); - QUICTypeUtil::write_uint_as_nbytes(0xff, 6, buf, &len); + QUICIntUtil::write_uint_as_nbytes(0xff, 6, buf, &len); INFO("1 byte to 6 byte"); CHECK(memcmp(buf, "\x00\x00\x00\x00\x00\xff\x00\x00", 6) == 0); - QUICTypeUtil::write_uint_as_nbytes(0xff, 8, buf, &len); + QUICIntUtil::write_uint_as_nbytes(0xff, 8, buf, &len); INFO("1 byte to 8 byte"); CHECK(memcmp(buf, "\x00\x00\x00\x00\x00\x00\x00\xff", 8) == 0); - QUICTypeUtil::write_uint_as_nbytes(0x11ff, 2, buf, &len); + QUICIntUtil::write_uint_as_nbytes(0x11ff, 2, buf, &len); INFO("2 byte to 2 byte"); CHECK(memcmp(buf, "\x11\xff\x00\x00\x00\x00\x00\x00", 2) == 0); - QUICTypeUtil::write_uint_as_nbytes(0x11ff, 4, buf, &len); + QUICIntUtil::write_uint_as_nbytes(0x11ff, 4, buf, &len); INFO("2 byte to 4 byte"); CHECK(memcmp(buf, "\x00\x00\x11\xff\x00\x00\x00\x00", 4) == 0); - QUICTypeUtil::write_uint_as_nbytes(0x11ff, 6, buf, &len); + QUICIntUtil::write_uint_as_nbytes(0x11ff, 6, buf, &len); INFO("2 byte to 6 byte"); CHECK(memcmp(buf, "\x00\x00\x00\x00\x11\xff\x00\x00", 6) == 0); - QUICTypeUtil::write_uint_as_nbytes(0x11ff, 8, buf, &len); + QUICIntUtil::write_uint_as_nbytes(0x11ff, 8, buf, &len); INFO("2 byte to 8 byte"); CHECK(memcmp(buf, "\x00\x00\x00\x00\x00\x00\x11\xff", 8) == 0); } diff --git a/lib/ts/ink_endian.h b/lib/ts/ink_endian.h new file mode 100644 index 00000000000..e5cf8f9eccb --- /dev/null +++ b/lib/ts/ink_endian.h @@ -0,0 +1,34 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#if defined(darwin) +#include +#define be64toh(x) OSSwapBigToHostInt64(x) +#define htobe64(x) OSSwapHostToBigInt64(x) +#elif defined(freebsd) +#include +#else +#include +#endif From b12c4d49582afcb943c67557efc443a2aa4ed29d Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 13 Mar 2018 17:47:44 +0800 Subject: [PATCH 0431/1313] QUIC: Fix the QUICHandshakeProtocol test --- iocore/net/quic/test/Makefile.am | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 54c669ccd35..d8e6a099c2f 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -49,6 +49,7 @@ AM_CPPFLAGS += \ -I$(abs_top_srcdir)/proxy/logging \ -I$(abs_top_srcdir)/proxy/shared \ -I$(abs_top_srcdir)/tests/include \ + $(TS_INCLUDES) \ @OPENSSL_INCLUDES@ if OPENSSL_IS_BORINGSSL @@ -382,12 +383,13 @@ test_QUICHandshakeProtocol_LDFLAGS = \ @OPENSSL_LDFLAGS@ test_QUICHandshakeProtocol_LDADD = \ - @OPENSSL_LIBS@ \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + @LIBTCL@ \ + @OPENSSL_LIBS@ test_QUICHandshakeProtocol_SOURCES = \ main.cc \ From a9565325408e3aa15c22560c95cd7336b21a652d Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 15 Mar 2018 11:36:59 +0800 Subject: [PATCH 0432/1313] QUIC: Fix compiler error of memcpy --- iocore/net/quic/QUICIntUtil.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/QUICIntUtil.cc b/iocore/net/quic/QUICIntUtil.cc index 00d20dea59e..d9e745d0a93 100644 --- a/iocore/net/quic/QUICIntUtil.cc +++ b/iocore/net/quic/QUICIntUtil.cc @@ -24,6 +24,7 @@ #include "QUICIntUtil.h" #include "ts/ink_endian.h" #include +#include size_t QUICVariableInt::size(const uint8_t *src) From e86ea3860f2ca5ca74f7c8322e61abba2e0ad635 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 15 Mar 2018 15:24:05 +0900 Subject: [PATCH 0433/1313] Move ats_unique_buf to ink_memory --- iocore/net/quic/QUICTypes.cc | 6 ------ iocore/net/quic/QUICTypes.h | 4 ---- lib/ts/ink_memory.cc | 6 ++++++ lib/ts/ink_memory.h | 4 ++++ 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 1fe1fdc04e4..077e26d6332 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -24,12 +24,6 @@ #include "QUICTypes.h" #include "QUICIntUtil.h" -ats_unique_buf -ats_unique_malloc(size_t size) -{ - return ats_unique_buf(reinterpret_cast(ats_malloc(size)), [](void *p) { ats_free(p); }); -} - bool QUICTypeUtil::has_long_header(const uint8_t *buf) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 7a36484ea33..25c1aabf7fe 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -37,10 +37,6 @@ #define MAGIC_NUMBER_1 1 #define MAGIC_NUMBER_TRUE true -// TODO: move to lib/ts/ink_memory.h? -using ats_unique_buf = std::unique_ptr; -ats_unique_buf ats_unique_malloc(size_t size); - using QUICPacketNumber = uint64_t; using QUICVersion = uint32_t; using QUICStreamId = uint64_t; diff --git a/lib/ts/ink_memory.cc b/lib/ts/ink_memory.cc index a45f147e6ff..d3152bc80d6 100644 --- a/lib/ts/ink_memory.cc +++ b/lib/ts/ink_memory.cc @@ -161,6 +161,12 @@ ats_mallopt(int param ATS_UNUSED, int value ATS_UNUSED) return 0; } +ats_unique_buf +ats_unique_malloc(size_t size) +{ + return ats_unique_buf(reinterpret_cast(ats_malloc(size)), [](void *p) { ats_free(p); }); +} + int ats_msync(caddr_t addr, size_t len, caddr_t end, int flags) { diff --git a/lib/ts/ink_memory.h b/lib/ts/ink_memory.h index e56686717d2..52d45ceda7d 100644 --- a/lib/ts/ink_memory.h +++ b/lib/ts/ink_memory.h @@ -590,6 +590,10 @@ path_join(ats_scoped_str const &lhs, ats_scoped_str const &rhs) return x.release(); } + +using ats_unique_buf = std::unique_ptr; +ats_unique_buf ats_unique_malloc(size_t size); + #endif /* __cplusplus */ #endif From e10160e6b505b9a285ee85d641f15158409357f9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 14 Mar 2018 12:08:57 +0900 Subject: [PATCH 0434/1313] Add Stateless Retry Support To enable this feature set `proxy.config.quic.stateless_retry` 1. Currently Address Validation Token in cookie ext is dummy. --- iocore/net/P_QUICNetVConnection.h | 3 ++ iocore/net/QUICNetVConnection.cc | 48 +++++++++++++++++++++++- iocore/net/QUICPacketHandler.cc | 31 +++++++++++++++ iocore/net/quic/QUICConfig.cc | 9 ++++- iocore/net/quic/QUICConfig.h | 2 + iocore/net/quic/QUICHandshake.cc | 44 +++++++++++++++++----- iocore/net/quic/QUICHandshake.h | 16 +++++--- iocore/net/quic/QUICHandshakeProtocol.cc | 9 +++++ iocore/net/quic/QUICHandshakeProtocol.h | 4 ++ iocore/net/quic/QUICPacket.cc | 5 +-- iocore/net/quic/QUICPacket.h | 2 +- iocore/net/quic/QUICTLS.cc | 17 +++------ iocore/net/quic/QUICTLS.h | 1 - iocore/net/quic/QUICTypes.h | 8 ++++ mgmt/RecordsConfig.cc | 2 + 15 files changed, 166 insertions(+), 35 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 781ee3c862f..03a1c4214b0 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -112,6 +112,8 @@ class SSLNextProtocolSet; * | _state_handshake_process_zero_rtt_protected_packet() * | WRITE: * | _state_common_send_packet() + * | or + * | _state_handshake_send_retry_packet() * v * state_connection_established() * | READ: @@ -295,6 +297,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICErrorUPtr _state_common_receive_packet(); QUICErrorUPtr _state_connection_closing_and_draining_receive_packet(); QUICErrorUPtr _state_common_send_packet(); + QUICErrorUPtr _state_handshake_send_retry_packet(); QUICErrorUPtr _state_closing_send_packet(); Ptr _packet_transmitter_mutex; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a6859daa2db..42d21977331 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -176,7 +176,7 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx) if (this->direction() == NET_VCONNECTION_IN) { QUICConfig::scoped_config params; this->_reset_token.generate(this->_quic_connection_id, params->server_id()); - this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_reset_token); + this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_reset_token, params->stateless_retry()); } else { this->_handshake_handler = new QUICHandshake(this, ssl_ctx); this->_handshake_handler->start(&this->_packet_factory); @@ -549,7 +549,16 @@ QUICNetVConnection::state_handshake(int event, Event *data) } case QUIC_EVENT_PACKET_WRITE_READY: { this->_close_packet_write_ready(data); - error = this->_state_common_send_packet(); + + if (this->_handshake_handler && this->_handshake_handler->msg_type() == QUICHandshakeMsgType::HRR) { + error = this->_state_handshake_send_retry_packet(); + if (this->_handshake_handler->is_stateless_retry_enabled()) { + this->_switch_to_close_state(); + } + } else { + error = this->_state_common_send_packet(); + } + break; } case EVENT_IMMEDIATE: @@ -919,6 +928,37 @@ QUICNetVConnection::_state_common_send_packet() return QUICErrorUPtr(new QUICNoError()); } +// RETRY packet contains ONLY a single STREAM frame +QUICErrorUPtr +QUICNetVConnection::_state_handshake_send_retry_packet() +{ + size_t len = 0; + ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); + QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; + + QUICFrameUPtr frame(nullptr, nullptr); + bool retransmittable = this->_handshake_handler->is_stateless_retry_enabled() ? false : true; + + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); + SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); + + ink_assert(this->_frame_send_queue.size() == 1); + frame = std::move(this->_frame_send_queue.front()); + this->_frame_send_queue.pop(); + this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + if (len == 0) { + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); + } + + QUICPacketUPtr packet = this->_build_packet(std::move(buf), len, retransmittable, QUICPacketType::RETRY); + this->_packet_handler->send_packet(*packet, this); + this->_loss_detector->on_packet_sent(std::move(packet)); + + QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, 1); + + return QUICErrorUPtr(new QUICNoError()); +} + QUICErrorUPtr QUICNetVConnection::_state_closing_send_packet() { @@ -1089,6 +1129,10 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->largest_acked_packet_number(), QUIC_SUPPORTED_VERSIONS[0], std::move(buf), len); break; + case QUICPacketType::RETRY: + packet = this->_packet_factory.create_retry_packet(this->_quic_connection_id, this->largest_acked_packet_number(), + std::move(buf), len, retransmittable); + break; case QUICPacketType::HANDSHAKE: packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 256100514e3..da986930914 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -85,6 +85,32 @@ QUICPacketHandler::_read_connection_id(IOBufferBlock *block) return QUICPacket::connection_id(buf); } +// TODO: ramdomize token and verify it +// dummy token to simplify test +static uint8_t token[] = {0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, + 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, + 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, + 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef}; + +static int +generate_cookie_callback(SSL * /* ssl */, unsigned char *cookie, size_t *cookie_len) +{ + memcpy(cookie, token, sizeof(token)); + *cookie_len = sizeof(token); + + return 1; +} + +static int +verify_cookie_callback(SSL *ssl, const unsigned char *cookie, size_t cookie_len) +{ + if (memcmp(token, cookie, sizeof(token)) == 0) { + return 1; + } else { + return 0; + } +} + // // QUICPacketHandlerIn // @@ -94,6 +120,11 @@ QUICPacketHandlerIn::QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, // create Connection Table QUICConfig::scoped_config params; _ctable = new QUICConnectionTable(params->connection_table_size()); + + // callbacks for cookie ext + // Requires OpenSSL-1.1.1-pre3+ : https://github.com/openssl/openssl/pull/5463 + SSL_CTX_set_stateless_cookie_generate_cb(this->_ssl_ctx, generate_cookie_callback); + SSL_CTX_set_stateless_cookie_verify_cb(this->_ssl_ctx, verify_cookie_callback); } QUICPacketHandlerIn::~QUICPacketHandlerIn() diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 8bcf9c99c4e..0b8c00c7eb2 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -39,7 +39,8 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_initial_max_data, "proxy.config.quic.initial_max_data"); REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data, "proxy.config.quic.initial_max_stream_data"); REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); - REC_EstablishStaticConfigInt32(_connection_table_size, "proxy.config.quic.connection_table.size"); + REC_EstablishStaticConfigInt32(this->_connection_table_size, "proxy.config.quic.connection_table.size"); + REC_EstablishStaticConfigInt32U(this->_stateless_retry, "proxy.config.quic.stateless_retry"); } uint32_t @@ -66,6 +67,12 @@ QUICConfigParams::connection_table_size() return _connection_table_size; } +uint32_t +QUICConfigParams::stateless_retry() const +{ + return this->_stateless_retry; +} + uint32_t QUICConfigParams::initial_max_data() const { diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index a7a4f60ecc2..4ae77212db9 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -39,6 +39,7 @@ class QUICConfigParams : public ConfigInfo uint32_t initial_max_stream_id_uni_out() const; uint32_t server_id() const; static int connection_table_size(); + uint32_t stateless_retry() const; private: // FIXME Fill appropriate default values in RecordsConfig.cc @@ -48,6 +49,7 @@ class QUICConfigParams : public ConfigInfo uint32_t _initial_max_stream_data = 0; uint32_t _server_id = 0; static int _connection_table_size; + uint32_t _stateless_retry = 0; uint32_t _initial_max_stream_id_bidi_in = 100; uint32_t _initial_max_stream_id_bidi_out = 101; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 428106a116a..4276715bcdb 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -86,17 +86,18 @@ static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandshake(qc, ssl_ctx, {}) +QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandshake(qc, ssl_ctx, {}, false) { } -QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token) +QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token, bool stateless_retry) : QUICApplication(qc), _ssl(SSL_new(ssl_ctx)), - _hs_protocol(new QUICTLS(this->_ssl, qc->direction())), + _hs_protocol(new QUICTLS(this->_ssl, qc->direction(), stateless_retry)), _version_negotiator(new QUICVersionNegotiator()), _netvc_context(qc->direction()), - _reset_token(token) + _reset_token(token), + _stateless_retry(stateless_retry) { SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_hs_index, this); @@ -144,17 +145,24 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet } bool -QUICHandshake::is_version_negotiated() +QUICHandshake::is_version_negotiated() const { return (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED); } bool -QUICHandshake::is_completed() +QUICHandshake::is_completed() const { return this->handler == &QUICHandshake::state_complete; } +bool +QUICHandshake::is_stateless_retry_enabled() const +{ + return this->_stateless_retry; +} + + QUICHandshakeProtocol * QUICHandshake::protocol() { @@ -393,6 +401,16 @@ QUICHandshake::state_closed(int event, void *data) { return EVENT_DONE; } + +QUICHandshakeMsgType +QUICHandshake::msg_type() const { + if (this->_hs_protocol) { + return this->_hs_protocol->msg_type(); + } else { + return QUICHandshakeMsgType::NONE; + } +} + void QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_version) { @@ -505,12 +523,18 @@ QUICHandshake::_process_client_hello() QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (result) { + case SSL_ERROR_NONE: case SSL_ERROR_WANT_READ: { - QUICHSDebug("Enter state_auth"); - SET_HANDLER(&QUICHandshake::state_auth); + if (this->_hs_protocol->msg_type() == QUICHandshakeMsgType::HRR) { + // TODO: Send HRR on Retry Packet directly + stream_io->write_reenable(); + } else { + QUICHSDebug("Enter state_auth"); + SET_HANDLER(&QUICHandshake::state_auth); - stream_io->write_reenable(); - stream_io->read_reenable(); + stream_io->write_reenable(); + stream_io->read_reenable(); + } break; } diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 3fd0dfe1d59..d53171f5aaf 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -55,7 +55,7 @@ class QUICHandshake : public QUICApplication // Constructor for client side QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx); // Constructor for server side - QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token); + QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token, bool stateless_retry); ~QUICHandshake(); // for client side @@ -79,13 +79,17 @@ class QUICHandshake : public QUICApplication std::shared_ptr local_transport_parameters(); std::shared_ptr remote_transport_parameters(); - bool is_version_negotiated(); - bool is_completed(); + bool is_version_negotiated() const; + bool is_completed() const; + bool is_stateless_retry_enabled() const; void set_transport_parameters(std::shared_ptr tp); void set_transport_parameters(std::shared_ptr tp); void set_transport_parameters(std::shared_ptr tp); + // A workaround API to indicate handshake msg type to QUICNetVConnection + QUICHandshakeMsgType msg_type() const; + private: SSL *_ssl = nullptr; QUICHandshakeProtocol *_hs_protocol = nullptr; @@ -93,6 +97,9 @@ class QUICHandshake : public QUICApplication std::shared_ptr _remote_transport_parameters = nullptr; QUICVersionNegotiator *_version_negotiator = nullptr; + NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; + QUICStatelessResetToken _reset_token; + bool _stateless_retry = false; void _load_local_server_transport_parameters(QUICVersion negotiated_version); void _load_local_client_transport_parameters(QUICVersion initial_version); @@ -106,7 +113,4 @@ class QUICHandshake : public QUICApplication int _complete_handshake(); void _abort_handshake(QUICTransErrorCode code); - - NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; - QUICStatelessResetToken _reset_token; }; diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index 4cb7a1008c8..d73826a0039 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -79,3 +79,12 @@ QUICPacketProtection::key_phase() const { return this->_key_phase; } + +// +// QUICHandshakeProtocol +// +QUICHandshakeMsgType +QUICHandshakeProtocol::msg_type() const +{ + return this->_msg_type; +} diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 86412f4d099..3e4649d8fb6 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -59,4 +59,8 @@ class QUICHandshakeProtocol uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; virtual bool decrypt(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, QUICKeyPhase phase) const = 0; + virtual QUICHandshakeMsgType msg_type() const; + +protected: + QUICHandshakeMsgType _msg_type = QUICHandshakeMsgType::NONE; }; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 35e8749e644..610a67b6daf 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -782,14 +782,13 @@ QUICPacketFactory::create_initial_packet(QUICConnectionId connection_id, QUICPac return this->_create_encrypted_packet(std::move(header), true); } -// retransmittable? depends on stateless? QUICPacketUPtr QUICPacketFactory::create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, - size_t len) + size_t len, bool retransmittable) { QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, connection_id, this->_packet_number_generator.next(), base_packet_number, this->_version, std::move(payload), len); - return this->_create_encrypted_packet(std::move(header), false); + return this->_create_encrypted_packet(std::move(header), retransmittable); } QUICPacketUPtr diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index c4b13cb7535..669cbeab49a 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -343,7 +343,7 @@ class QUICPacketFactory QUICPacketUPtr create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); QUICPacketUPtr create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, - size_t len); + size_t len, bool retransmittable); QUICPacketUPtr create_handshake_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); QUICPacketUPtr create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 74e8c46ca7b..50b2e73a349 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -79,7 +79,7 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint ERR_clear_error(); int ret = 0; if (this->_netvc_context == NET_VCONNECTION_IN) { - // // process early data + // process early data if (!this->_early_data_processed) { if (this->_read_early_data()) { this->_early_data_processed = true; @@ -106,14 +106,15 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint SSL_set_bio(this->_ssl, rbio, wbio); ret = SSL_stateless(this->_ssl); - if (ret >= 0) { - Debug(tag, "Sending HRR"); + if (ret > 0) { this->_stateless = false; - } else { - Debug(tag, "SSL_stateless error"); + this->_msg_type = QUICHandshakeMsgType::SH; + } else if (ret == 0) { + this->_msg_type = QUICHandshakeMsgType::HRR; } } else { ret = SSL_accept(this->_ssl); + this->_msg_type = QUICHandshakeMsgType::SH; } } else { ret = SSL_connect(this->_ssl); @@ -165,12 +166,6 @@ QUICTLS::is_key_derived(QUICKeyPhase key_phase) const } } -bool -QUICTLS::is_stateless() -{ - return this->_stateless; -} - int QUICTLS::initialize_key_materials(QUICConnectionId cid) { diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 20d1c61f1e2..4c6ebef880a 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -56,7 +56,6 @@ class QUICTLS : public QUICHandshakeProtocol // FIXME SSL handle should not be exported SSL *ssl_handle(); - bool is_stateless(); private: QUICKeyGenerator _keygen_for_client = QUICKeyGenerator(QUICKeyGenerator::Context::CLIENT); diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 25c1aabf7fe..2b4814d7d23 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -136,6 +136,14 @@ enum class QUICTransErrorCode : uint16_t { TLS_FATAL_ALERT_RECEIVED, }; +enum class QUICHandshakeMsgType { + NONE = 0, + CH, + SH, + HRR, + FN, +}; + // Application Protocol Error Codes defined in application using QUICAppErrorCode = uint16_t; constexpr uint16_t QUIC_APP_ERROR_CODE_STOPPING = 0; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 86e6af2469e..87531c7ed91 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1328,6 +1328,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.connection_table.size", RECD_INT, "65521", RECU_RESTART_TS, RR_NULL, RECC_INT, "[1-536870909]", RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.stateless_retry", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} + , //# Add LOCAL Records Here {RECT_LOCAL, "proxy.local.incoming_ip_to_bind", RECD_STRING, nullptr, RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL} From 89f9562844399648d28184662b60fe1072ca000f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 16 Mar 2018 10:57:44 +0900 Subject: [PATCH 0435/1313] Generate client address validation token --- iocore/net/QUICPacketHandler.cc | 31 ++---------------- iocore/net/quic/QUICGlobals.cc | 57 +++++++++++++++++++++++++++++++-- iocore/net/quic/QUICGlobals.h | 15 ++++----- 3 files changed, 64 insertions(+), 39 deletions(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index da986930914..f5a3bbebdce 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -27,6 +27,7 @@ #include "QUICPacket.h" #include "QUICDebugNames.h" #include "QUICEvents.h" +#include "QUICGlobals.h" // // QUICPacketHandler @@ -85,32 +86,6 @@ QUICPacketHandler::_read_connection_id(IOBufferBlock *block) return QUICPacket::connection_id(buf); } -// TODO: ramdomize token and verify it -// dummy token to simplify test -static uint8_t token[] = {0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, - 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, - 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, - 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef}; - -static int -generate_cookie_callback(SSL * /* ssl */, unsigned char *cookie, size_t *cookie_len) -{ - memcpy(cookie, token, sizeof(token)); - *cookie_len = sizeof(token); - - return 1; -} - -static int -verify_cookie_callback(SSL *ssl, const unsigned char *cookie, size_t cookie_len) -{ - if (memcmp(token, cookie, sizeof(token)) == 0) { - return 1; - } else { - return 0; - } -} - // // QUICPacketHandlerIn // @@ -123,8 +98,8 @@ QUICPacketHandlerIn::QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, // callbacks for cookie ext // Requires OpenSSL-1.1.1-pre3+ : https://github.com/openssl/openssl/pull/5463 - SSL_CTX_set_stateless_cookie_generate_cb(this->_ssl_ctx, generate_cookie_callback); - SSL_CTX_set_stateless_cookie_verify_cb(this->_ssl_ctx, verify_cookie_callback); + SSL_CTX_set_stateless_cookie_generate_cb(this->_ssl_ctx, QUIC::ssl_generate_stateless_cookie); + SSL_CTX_set_stateless_cookie_verify_cb(this->_ssl_ctx, QUIC::ssl_verify_stateless_cookie); } QUICPacketHandlerIn::~QUICPacketHandlerIn() diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index 7627a2e91b8..c843e9b48f0 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -21,17 +21,37 @@ * limitations under the License. */ -#include #include "QUICGlobals.h" + +#include + +#include +#include + +#include "P_SSLNextProtocolSet.h" +#include "P_QUICNetVConnection.h" #include "QUICStats.h" #include "QUICConnection.h" -#include "P_SSLNextProtocolSet.h" RecRawStatBlock *quic_rsb; int QUIC::ssl_quic_qc_index = -1; int QUIC::ssl_quic_hs_index = -1; +static constexpr size_t STATELESS_COOKIE_SECRET_LENGTH = 16; +static uint8_t stateless_cookie_secret[STATELESS_COOKIE_SECRET_LENGTH] = {0}; + +void +QUIC::init() +{ + QUIC::_register_stats(); + ssl_quic_qc_index = SSL_get_ex_new_index(0, (void *)"QUICConnection index", nullptr, nullptr, nullptr); + ssl_quic_hs_index = SSL_get_ex_new_index(0, (void *)"QUICHandshake index", nullptr, nullptr, nullptr); + + // TODO: read cookie secret from file like SSLTicketKeyConfig + RAND_bytes(stateless_cookie_secret, STATELESS_COOKIE_SECRET_LENGTH); +} + int QUIC::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen, void *) @@ -50,6 +70,39 @@ QUIC::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned cha return SSL_TLSEXT_ERR_NOACK; } +int +QUIC::ssl_generate_stateless_cookie(SSL *ssl, unsigned char *cookie, size_t *cookie_len) +{ + // Call UnixNetVConnection::get_remote_addr() safely + // TODO: add APIs to getting client addr in QUICConnection + QUICConnection *qc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); + QUICNetVConnection *qvc = dynamic_cast(qc); + + uint8_t key[INET6_ADDRPORTSTRLEN] = {0}; + size_t key_len = INET6_ADDRPORTSTRLEN; + ats_ip_nptop(qvc->get_remote_addr(), reinterpret_cast(key), key_len); + + unsigned int dst_len = 0; + HMAC(EVP_sha1(), stateless_cookie_secret, STATELESS_COOKIE_SECRET_LENGTH, key, key_len, cookie, &dst_len); + *cookie_len = dst_len; + + return 1; +} + +int +QUIC::ssl_verify_stateless_cookie(SSL *ssl, const unsigned char *cookie, size_t cookie_len) +{ + uint8_t token[EVP_MAX_MD_SIZE]; + size_t token_len; + + if (QUIC::ssl_generate_stateless_cookie(ssl, token, &token_len) && cookie_len == token_len && + memcmp(token, cookie, cookie_len) == 0) { + return 1; + } else { + return 0; + } +} + void QUIC::_register_stats() { diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h index c4b52689ca4..26f2e1bce68 100644 --- a/iocore/net/quic/QUICGlobals.h +++ b/iocore/net/quic/QUICGlobals.h @@ -28,19 +28,16 @@ class QUIC { public: - static void - init() - { - QUIC::_register_stats(); - ssl_quic_qc_index = SSL_get_ex_new_index(0, (void *)"QUICConnection index", nullptr, nullptr, nullptr); - ssl_quic_hs_index = SSL_get_ex_new_index(0, (void *)"QUICHandshake index", nullptr, nullptr, nullptr); - } - static int ssl_quic_qc_index; - static int ssl_quic_hs_index; + static void init(); // SSL callbacks static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen, void *); + static int ssl_generate_stateless_cookie(SSL *ssl, unsigned char *cookie, size_t *cookie_len); + static int ssl_verify_stateless_cookie(SSL *ssl, const unsigned char *cookie, size_t cookie_len); + + static int ssl_quic_qc_index; + static int ssl_quic_hs_index; private: static void _register_stats(); From 147b19b16d760e692df7e5b267f6324f390478ef Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 16 Mar 2018 11:00:03 +0900 Subject: [PATCH 0436/1313] clang-format --- iocore/net/quic/QUICHandshake.cc | 4 ++-- iocore/net/quic/QUICHandshake.h | 2 +- iocore/net/quic/QUICTLS.cc | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 4276715bcdb..42b79f18f42 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -162,7 +162,6 @@ QUICHandshake::is_stateless_retry_enabled() const return this->_stateless_retry; } - QUICHandshakeProtocol * QUICHandshake::protocol() { @@ -403,7 +402,8 @@ QUICHandshake::state_closed(int event, void *data) } QUICHandshakeMsgType -QUICHandshake::msg_type() const { +QUICHandshake::msg_type() const +{ if (this->_hs_protocol) { return this->_hs_protocol->msg_type(); } else { diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index d53171f5aaf..6ddae160316 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -97,7 +97,7 @@ class QUICHandshake : public QUICApplication std::shared_ptr _remote_transport_parameters = nullptr; QUICVersionNegotiator *_version_negotiator = nullptr; - NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; + NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; QUICStatelessResetToken _reset_token; bool _stateless_retry = false; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 50b2e73a349..46ac529d8cc 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -108,12 +108,12 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint ret = SSL_stateless(this->_ssl); if (ret > 0) { this->_stateless = false; - this->_msg_type = QUICHandshakeMsgType::SH; + this->_msg_type = QUICHandshakeMsgType::SH; } else if (ret == 0) { this->_msg_type = QUICHandshakeMsgType::HRR; } } else { - ret = SSL_accept(this->_ssl); + ret = SSL_accept(this->_ssl); this->_msg_type = QUICHandshakeMsgType::SH; } } else { From 5f04fd1bc14d79e920c36ceb87d1615b855aacc8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sun, 18 Mar 2018 21:13:46 +0900 Subject: [PATCH 0437/1313] Use negotiated cipher suite It was broken when we add 0rtt support because the logic checked whether handshake is complete. --- iocore/net/quic/QUICTLS.cc | 16 +++--- iocore/net/quic/QUICTLS.h | 22 ++++---- iocore/net/quic/QUICTLS_openssl.cc | 82 +++++++++++++++++------------- 3 files changed, 67 insertions(+), 53 deletions(-) diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 46ac529d8cc..949a9169d7b 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -191,9 +191,6 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) } this->_server_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); - // Update algorithm - this->_aead = _get_evp_aead(); - return 1; } @@ -242,9 +239,6 @@ QUICTLS::update_key_materials() } this->_server_pp->set_key(std::move(km), next_key_phase); - // Update algorithm - this->_aead = _get_evp_aead(); - return 1; } @@ -307,14 +301,15 @@ QUICTLS::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, con return false; } - size_t tag_len = this->_get_aead_tag_len(); + size_t tag_len = this->_get_aead_tag_len(phase); const KeyMaterial *km = pp->get_key(phase); if (!km) { Debug(tag, "Failed to encrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } + const EVP_CIPHER *aead = this->_get_evp_aead(phase); - bool ret = _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, *km, tag_len); + bool ret = _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, *km, aead, tag_len); if (!ret) { Debug(tag, "Failed to encrypt a packet: pkt_num=%" PRIu64, pkt_num); } @@ -342,13 +337,14 @@ QUICTLS::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const return false; } - size_t tag_len = this->_get_aead_tag_len(); + size_t tag_len = this->_get_aead_tag_len(phase); const KeyMaterial *km = pp->get_key(phase); if (!km) { Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } - bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, *km, tag_len); + const EVP_CIPHER *aead = this->_get_evp_aead(phase); + bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, *km, aead, tag_len); if (!ret) { Debug(tag, "Failed to decrypt a packet: pkt_num=%" PRIu64, pkt_num); } diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 4c6ebef880a..0cbf52062ac 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -64,21 +64,25 @@ class QUICTLS : public QUICHandshakeProtocol #ifdef OPENSSL_IS_BORINGSSL const EVP_AEAD *_get_evp_aead() const; #else - const EVP_CIPHER *_get_evp_aead() const; + const EVP_CIPHER *_get_evp_aead(QUICKeyPhase phase) const; #endif // OPENSSL_IS_BORINGSSL - size_t _get_aead_tag_len() const; + size_t _get_aead_tag_len(QUICKeyPhase phase) const; +#ifdef OPENSSL_IS_BORINGSSL bool _encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const; + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const EVP_AEAD *aead, + size_t tag_len) const; bool _decrypt(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 KeyMaterial &km, size_t tag_len) const; - - SSL *_ssl = nullptr; -#ifdef OPENSSL_IS_BORINGSSL - const EVP_AEAD *_aead = nullptr; + const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const EVP_AEAD *aead, size_t tag_len) const; #else - const EVP_CIPHER *_aead = nullptr; + bool _encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const EVP_CIPHER *aead, + size_t tag_len) const; + bool _decrypt(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 KeyMaterial &km, const EVP_CIPHER *aead, size_t tag_len) const; #endif // OPENSSL_IS_BORINGSSL + + SSL *_ssl = nullptr; QUICPacketProtection *_client_pp = nullptr; QUICPacketProtection *_server_pp = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 7dafc652fb3..c92116aed47 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -31,54 +31,67 @@ static constexpr char tag[] = "quic_tls"; const EVP_CIPHER * -QUICTLS::_get_evp_aead() const +QUICTLS::_get_evp_aead(QUICKeyPhase phase) const { - if (this->is_handshake_finished()) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(this->_ssl))) { - case TLS1_3_CK_AES_128_GCM_SHA256: - return EVP_aes_128_gcm(); - case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_aes_256_gcm(); - case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_chacha20_poly1305(); - case TLS1_3_CK_AES_128_CCM_SHA256: - case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_aes_128_ccm(); - default: + if (phase == QUICKeyPhase::CLEARTEXT) { + return EVP_aes_128_gcm(); + } else { + const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); + if (cipher) { + switch (SSL_CIPHER_get_id(cipher)) { + case TLS1_3_CK_AES_128_GCM_SHA256: + return EVP_aes_128_gcm(); + case TLS1_3_CK_AES_256_GCM_SHA384: + return EVP_aes_256_gcm(); + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + return EVP_chacha20_poly1305(); + case TLS1_3_CK_AES_128_CCM_SHA256: + case TLS1_3_CK_AES_128_CCM_8_SHA256: + return EVP_aes_128_ccm(); + default: + ink_assert(false); + return nullptr; + } + } else { ink_assert(false); return nullptr; } - } else { - return EVP_aes_128_gcm(); } } size_t -QUICTLS::_get_aead_tag_len() const +QUICTLS::_get_aead_tag_len(QUICKeyPhase phase) const { - if (this->is_handshake_finished()) { - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(this->_ssl))) { - case TLS1_3_CK_AES_128_GCM_SHA256: - case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_GCM_TLS_TAG_LEN; - case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_CHACHAPOLY_TLS_TAG_LEN; - case TLS1_3_CK_AES_128_CCM_SHA256: - return EVP_CCM_TLS_TAG_LEN; - case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_CCM8_TLS_TAG_LEN; - default: + if (phase == QUICKeyPhase::CLEARTEXT) { + return EVP_GCM_TLS_TAG_LEN; + } else { + const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); + if (cipher) { + switch (SSL_CIPHER_get_id(cipher)) { + case TLS1_3_CK_AES_128_GCM_SHA256: + case TLS1_3_CK_AES_256_GCM_SHA384: + return EVP_GCM_TLS_TAG_LEN; + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + return EVP_CHACHAPOLY_TLS_TAG_LEN; + case TLS1_3_CK_AES_128_CCM_SHA256: + return EVP_CCM_TLS_TAG_LEN; + case TLS1_3_CK_AES_128_CCM_8_SHA256: + return EVP_CCM8_TLS_TAG_LEN; + default: + ink_assert(false); + return -1; + } + } else { ink_assert(false); return -1; } - } else { - return EVP_GCM_TLS_TAG_LEN; } } bool QUICTLS::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const EVP_CIPHER *aead, + size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; @@ -90,7 +103,7 @@ QUICTLS::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, co if (!(aead_ctx = EVP_CIPHER_CTX_new())) { return false; } - if (!EVP_EncryptInit_ex(aead_ctx, this->_aead, nullptr, nullptr, nullptr)) { + 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)) { @@ -127,7 +140,8 @@ QUICTLS::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, co bool QUICTLS::_decrypt(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 KeyMaterial &km, size_t tag_len) const + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const EVP_CIPHER *aead, + size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; @@ -139,7 +153,7 @@ QUICTLS::_decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const if (!(aead_ctx = EVP_CIPHER_CTX_new())) { return false; } - if (!EVP_DecryptInit_ex(aead_ctx, this->_aead, nullptr, nullptr, nullptr)) { + 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)) { From 8388bc206fb86a824e26d1d1a778132f0f261ebd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 19 Mar 2018 09:26:59 +0900 Subject: [PATCH 0438/1313] Fix compile errors of unit tests --- iocore/net/quic/test/test_QUICHandshake.cc | 2 +- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc index daada593a4a..8e8ad8d1728 100644 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -61,7 +61,7 @@ TEST_CASE("1-RTT handshake ", "[quic]") QUICStatelessResetToken server_token; server_token.generate(conn_id, 0); - QUICHandshake *server = new QUICHandshake(server_qc, server_ssl_ctx, server_token); + QUICHandshake *server = new QUICHandshake(server_qc, server_ssl_ctx, server_token, false); // setup stream 0 MockQUICFrameTransmitter tx; diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index d90ba775947..3db7a692a29 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -66,7 +66,7 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketUPtr packet = factory.create_retry_packet(0x01020304, 0, std::move(payload), sizeof(raw)); + QUICPacketUPtr packet = factory.create_retry_packet(0x01020304, 0, std::move(payload), sizeof(raw), false); CHECK(packet->type() == QUICPacketType::RETRY); CHECK(packet->connection_id() == 0x01020304); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); From 09f62d9ffc55e6d18bbad8df76aa93bf37945a00 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 19 Mar 2018 10:14:26 +0900 Subject: [PATCH 0439/1313] Separate stateless cookie callbacks from QUICGlobal QUICNetVconnection is used from these callbacks for getting client address. This made link issues in Unit Tests of QUIC. --- iocore/net/QUICNetProcessor.cc | 8 +++ iocore/net/QUICPacketHandler.cc | 6 --- iocore/net/quic/Makefile.am | 3 +- iocore/net/quic/QUICGlobals.cc | 43 --------------- iocore/net/quic/QUICGlobals.h | 2 - iocore/net/quic/QUICStatelessRetry.cc | 76 +++++++++++++++++++++++++++ iocore/net/quic/QUICStatelessRetry.h | 34 ++++++++++++ 7 files changed, 120 insertions(+), 52 deletions(-) create mode 100644 iocore/net/quic/QUICStatelessRetry.cc create mode 100644 iocore/net/quic/QUICStatelessRetry.h diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index ed329b4c9a2..55c7b10be85 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -28,6 +28,7 @@ #include "QUICGlobals.h" #include "QUICConfig.h" #include "QUICTransportParameters.h" +#include "QUICStatelessRetry.h" // // Global Data @@ -67,6 +68,7 @@ QUICNetProcessor::start(int, size_t stacksize) // This initialization order matters ... // QUICInitializeLibrary(); QUICConfig::startup(); + QUICStatelessRetry::init(); #ifdef TLS1_3_VERSION_DRAFT_TXT // FIXME: remove this when TLS1_3_VERSION_DRAFT_TXT is removed @@ -79,6 +81,7 @@ QUICNetProcessor::start(int, size_t stacksize) // Initialize QUIC statistics. This depends on an initial set of certificates being loaded above. // QUICInitializeStatistics(); + // TODO: separate SSL_CTX for client and server // TODO: load certs from SSLConfig this->_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(this->_ssl_ctx, TLS1_3_VERSION); @@ -94,6 +97,11 @@ QUICNetProcessor::start(int, size_t stacksize) &QUICTransportParametersHandler::add, &QUICTransportParametersHandler::free, nullptr, &QUICTransportParametersHandler::parse, nullptr); + // callbacks for cookie ext + // Requires OpenSSL-1.1.1-pre3+ : https://github.com/openssl/openssl/pull/5463 + SSL_CTX_set_stateless_cookie_generate_cb(this->_ssl_ctx, QUICStatelessRetry::generate_cookie); + SSL_CTX_set_stateless_cookie_verify_cb(this->_ssl_ctx, QUICStatelessRetry::verify_cookie); + SSLConfig::scoped_config params; SSLParseCertificateConfiguration(params, this->_ssl_ctx); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index f5a3bbebdce..256100514e3 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -27,7 +27,6 @@ #include "QUICPacket.h" #include "QUICDebugNames.h" #include "QUICEvents.h" -#include "QUICGlobals.h" // // QUICPacketHandler @@ -95,11 +94,6 @@ QUICPacketHandlerIn::QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, // create Connection Table QUICConfig::scoped_config params; _ctable = new QUICConnectionTable(params->connection_table_size()); - - // callbacks for cookie ext - // Requires OpenSSL-1.1.1-pre3+ : https://github.com/openssl/openssl/pull/5463 - SSL_CTX_set_stateless_cookie_generate_cb(this->_ssl_ctx, QUIC::ssl_generate_stateless_cookie); - SSL_CTX_set_stateless_cookie_verify_cb(this->_ssl_ctx, QUIC::ssl_verify_stateless_cookie); } QUICPacketHandlerIn::~QUICPacketHandlerIn() diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 7898ddf95a8..fcb8e6dafa4 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -72,7 +72,8 @@ libquic_a_SOURCES = \ QUICDebugNames.cc \ QUICApplication.cc \ QUICApplicationMap.cc \ - QUICIncomingFrameBuffer.cc + QUICIncomingFrameBuffer.cc \ + QUICStatelessRetry.cc include $(top_srcdir)/build/tidy.mk diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index c843e9b48f0..ceb4c9549ed 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -25,11 +25,7 @@ #include -#include -#include - #include "P_SSLNextProtocolSet.h" -#include "P_QUICNetVConnection.h" #include "QUICStats.h" #include "QUICConnection.h" @@ -38,18 +34,12 @@ RecRawStatBlock *quic_rsb; int QUIC::ssl_quic_qc_index = -1; int QUIC::ssl_quic_hs_index = -1; -static constexpr size_t STATELESS_COOKIE_SECRET_LENGTH = 16; -static uint8_t stateless_cookie_secret[STATELESS_COOKIE_SECRET_LENGTH] = {0}; - void QUIC::init() { QUIC::_register_stats(); ssl_quic_qc_index = SSL_get_ex_new_index(0, (void *)"QUICConnection index", nullptr, nullptr, nullptr); ssl_quic_hs_index = SSL_get_ex_new_index(0, (void *)"QUICHandshake index", nullptr, nullptr, nullptr); - - // TODO: read cookie secret from file like SSLTicketKeyConfig - RAND_bytes(stateless_cookie_secret, STATELESS_COOKIE_SECRET_LENGTH); } int @@ -70,39 +60,6 @@ QUIC::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned cha return SSL_TLSEXT_ERR_NOACK; } -int -QUIC::ssl_generate_stateless_cookie(SSL *ssl, unsigned char *cookie, size_t *cookie_len) -{ - // Call UnixNetVConnection::get_remote_addr() safely - // TODO: add APIs to getting client addr in QUICConnection - QUICConnection *qc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); - QUICNetVConnection *qvc = dynamic_cast(qc); - - uint8_t key[INET6_ADDRPORTSTRLEN] = {0}; - size_t key_len = INET6_ADDRPORTSTRLEN; - ats_ip_nptop(qvc->get_remote_addr(), reinterpret_cast(key), key_len); - - unsigned int dst_len = 0; - HMAC(EVP_sha1(), stateless_cookie_secret, STATELESS_COOKIE_SECRET_LENGTH, key, key_len, cookie, &dst_len); - *cookie_len = dst_len; - - return 1; -} - -int -QUIC::ssl_verify_stateless_cookie(SSL *ssl, const unsigned char *cookie, size_t cookie_len) -{ - uint8_t token[EVP_MAX_MD_SIZE]; - size_t token_len; - - if (QUIC::ssl_generate_stateless_cookie(ssl, token, &token_len) && cookie_len == token_len && - memcmp(token, cookie, cookie_len) == 0) { - return 1; - } else { - return 0; - } -} - void QUIC::_register_stats() { diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h index 26f2e1bce68..379fa18619c 100644 --- a/iocore/net/quic/QUICGlobals.h +++ b/iocore/net/quic/QUICGlobals.h @@ -33,8 +33,6 @@ class QUIC // SSL callbacks static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen, void *); - static int ssl_generate_stateless_cookie(SSL *ssl, unsigned char *cookie, size_t *cookie_len); - static int ssl_verify_stateless_cookie(SSL *ssl, const unsigned char *cookie, size_t cookie_len); static int ssl_quic_qc_index; static int ssl_quic_hs_index; diff --git a/iocore/net/quic/QUICStatelessRetry.cc b/iocore/net/quic/QUICStatelessRetry.cc new file mode 100644 index 00000000000..700b8c76e60 --- /dev/null +++ b/iocore/net/quic/QUICStatelessRetry.cc @@ -0,0 +1,76 @@ +/** @file + * + * Callbacks for Stateless Retry + * + * @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 "QUICStatelessRetry.h" + +#include +#include +#include + +#include "P_QUICNetVConnection.h" + +#include "QUICGlobals.h" +#include "QUICConnection.h" + +static constexpr size_t STATELESS_COOKIE_SECRET_LENGTH = 16; +static uint8_t stateless_cookie_secret[STATELESS_COOKIE_SECRET_LENGTH] = {0}; + +void +QUICStatelessRetry::init() +{ + // TODO: read cookie secret from file like SSLTicketKeyConfig + RAND_bytes(stateless_cookie_secret, STATELESS_COOKIE_SECRET_LENGTH); +} + +int +QUICStatelessRetry::generate_cookie(SSL *ssl, unsigned char *cookie, size_t *cookie_len) +{ + // Call UnixNetVConnection::get_remote_addr() safely + // TODO: add APIs to getting client addr in QUICConnection + QUICConnection *qc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); + QUICNetVConnection *qvc = dynamic_cast(qc); + + uint8_t key[INET6_ADDRPORTSTRLEN] = {0}; + size_t key_len = INET6_ADDRPORTSTRLEN; + ats_ip_nptop(qvc->get_remote_addr(), reinterpret_cast(key), key_len); + + unsigned int dst_len = 0; + HMAC(EVP_sha1(), stateless_cookie_secret, STATELESS_COOKIE_SECRET_LENGTH, key, key_len, cookie, &dst_len); + *cookie_len = dst_len; + + return 1; +} + +int +QUICStatelessRetry::verify_cookie(SSL *ssl, const unsigned char *cookie, size_t cookie_len) +{ + uint8_t token[EVP_MAX_MD_SIZE]; + size_t token_len; + + if (QUICStatelessRetry::generate_cookie(ssl, token, &token_len) && cookie_len == token_len && + memcmp(token, cookie, cookie_len) == 0) { + return 1; + } else { + return 0; + } +} diff --git a/iocore/net/quic/QUICStatelessRetry.h b/iocore/net/quic/QUICStatelessRetry.h new file mode 100644 index 00000000000..a63081ba951 --- /dev/null +++ b/iocore/net/quic/QUICStatelessRetry.h @@ -0,0 +1,34 @@ +/** @file + * + * Callbacks for Stateless Retry + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +class QUICStatelessRetry +{ +public: + static void init(); + static int generate_cookie(SSL *ssl, unsigned char *cookie, size_t *cookie_len); + static int verify_cookie(SSL *ssl, const unsigned char *cookie, size_t cookie_len); +}; From 3e379b176101a87bbfb257cab47f837010937ebb Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 19 Mar 2018 11:37:08 +0900 Subject: [PATCH 0440/1313] Format debug logs of sending/receiving packets/frames --- iocore/net/QUICNetVConnection.cc | 11 +++++++---- iocore/net/quic/QUICFrameDispatcher.cc | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 42d21977331..5d6e6ae4b4d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -48,6 +48,9 @@ #define QUICConDebug(fmt, ...) \ Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) +#define QUICConVDebug(fmt, ...) \ + Debug("v_quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) + #define QUICError(fmt, ...) \ Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__); \ Error("quic_net [%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) @@ -339,7 +342,7 @@ QUICNetVConnection::_transmit_packet(QUICPacketUPtr packet) SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); if (packet) { - QUICConDebug("Packet Number=%" PRIu64 " Type=%s Size=%hu", packet->packet_number(), QUICDebugNames::packet_type(packet->type()), + QUICConDebug("Enqueue %s pkt_num=%" PRIu64 " size=%hu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), packet->size()); // TODO Remove const_cast this->_packet_send_queue.enqueue(const_cast(packet.release())); @@ -402,7 +405,7 @@ QUICNetVConnection::_transmit_frame(QUICFrameUPtr frame) SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); if (frame) { - QUICConDebug("Frame Type=%s Size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); + QUICConVDebug("type=%s size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); if (frame->type() == QUICFrameType::STREAM) { QUICStreamFrame &stream_frame = static_cast(*frame); // XXX: Stream 0 is exempt from the connection-level flow control window. @@ -1005,7 +1008,7 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans } size_t l = 0; - QUICConDebug("type=%s", QUICDebugNames::frame_type(frame->type())); + QUICConDebug("type=%s size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); frame->store(buf.get() + len, &l); len += l; @@ -1265,7 +1268,7 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) QUICConDebug("Unsupported version"); break; case QUICPacketCreationResult::SUCCESS: - QUICConDebug("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), + QUICConDebug("Dequeue %s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), quic_packet->packet_number(), quic_packet->size()); break; default: diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index b4582b9a562..5b8b7a10607 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -24,7 +24,7 @@ #include "QUICFrameDispatcher.h" #include "QUICDebugNames.h" -static constexpr char tag[] = "quic_frame_handler"; +static constexpr char tag[] = "quic_net"; // // Frame Dispatcher @@ -58,7 +58,7 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size, bool // TODO: check debug build if (type != QUICFrameType::PADDING) { - Debug(tag, "Received %s frame, size %zu", QUICDebugNames::frame_type(frame->type()), frame->size()); + Debug(tag, "type=%s, size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); } should_send_ack |= (type != QUICFrameType::PADDING && type != QUICFrameType::ACK); From e7fda2c95512d6151860b68e0b3776360069bed1 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 19 Mar 2018 16:33:03 +0900 Subject: [PATCH 0441/1313] Derive key after handshake completed on client side --- iocore/net/quic/QUICTLS.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 949a9169d7b..07939b104fd 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -153,7 +153,11 @@ QUICTLS::is_handshake_finished() const bool QUICTLS::is_ready_to_derive() const { - return SSL_get_current_cipher(this->_ssl) != nullptr; + if (this->_netvc_context == NET_VCONNECTION_IN) { + return SSL_get_current_cipher(this->_ssl) != nullptr; + } else { + return this->is_handshake_finished(); + } } bool From 05f30d5785544ca2d3168a8cc65cfaf62d501311 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Mar 2018 23:17:36 +0900 Subject: [PATCH 0442/1313] Fix Version Negotiation Fixes #3305 --- iocore/net/QUICNet.cc | 51 ++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index 14becbe08e9..f73ba264982 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -56,12 +56,10 @@ QUICPollCont::~QUICPollCont() void QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) { - uint8_t *buf; - QUICPacketType ptype; UDPPacketInternal *p = e->packet; // FIXME: VC is nullptr ? QUICNetVConnection *vc = static_cast(e->con); - buf = (uint8_t *)p->getIOBlockChain()->buf(); + uint8_t *buf = (uint8_t *)p->getIOBlockChain()->buf(); e->free(); if (!QUICTypeUtil::has_connection_id(reinterpret_cast(buf))) { @@ -70,38 +68,27 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) return; } - ptype = static_cast(buf[0] & 0x7f); - switch (ptype) { - case QUICPacketType::INITIAL: - if (!vc->read.triggered) { - vc->read.triggered = 1; - vc->handle_received_packet(p); - vc->handleEvent(QUIC_EVENT_PACKET_READ_READY, nullptr); - } else { - p->free(); - } + QUICPacketType ptype = static_cast(buf[0] & 0x7f); + if (ptype == QUICPacketType::INITIAL && !vc->read.triggered) { + vc->read.triggered = 1; + vc->handle_received_packet(p); + vc->handleEvent(QUIC_EVENT_PACKET_READ_READY, nullptr); return; - case QUICPacketType::ZERO_RTT_PROTECTED: - // TODO:: do something ? - // break; - case QUICPacketType::HANDSHAKE: - default: - // Just Pass Through - if (vc) { - vc->read.triggered = 1; - vc->handle_received_packet(p); - } else { - this->_longInQueue.push(p); - } + } + + if (vc) { + vc->read.triggered = 1; + vc->handle_received_packet(p); + } else { + this->_longInQueue.push(p); + } - // Push QUICNetVC into nethandler's enabled list - if (vc != nullptr) { - int isin = ink_atomic_swap(&vc->read.in_enabled_list, 1); - if (!isin) { - nh->read_enable_list.push(vc); - } + // Push QUICNetVC into nethandler's enabled list + if (vc != nullptr) { + int isin = ink_atomic_swap(&vc->read.in_enabled_list, 1); + if (!isin) { + nh->read_enable_list.push(vc); } - break; } } From 4c6a3e851bbaf11c29660730fab0e3c051dd9db3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Mar 2018 16:56:27 +0900 Subject: [PATCH 0443/1313] Add HQ frame support --- configure.ac | 1 + iocore/net/quic/QUICApplication.cc | 6 + iocore/net/quic/QUICApplication.h | 1 + iocore/net/quic/QUICIntUtil.cc | 3 + proxy/hq/HQClientTransaction.cc | 167 ++++++++++----- proxy/hq/HQClientTransaction.h | 18 ++ proxy/hq/HQDataFramer.cc | 55 +++++ proxy/hq/HQDataFramer.h | 44 ++++ proxy/hq/HQDebugNames.h | 29 +++ proxy/hq/HQFrame.cc | 313 +++++++++++++++++++++++++++++ proxy/hq/HQFrame.h | 190 +++++++++++++++++ proxy/hq/HQFrameCollector.cc | 62 ++++++ proxy/hq/HQFrameCollector.h | 40 ++++ proxy/hq/HQFrameDispatcher.cc | 73 +++++++ proxy/hq/HQFrameDispatcher.h | 40 ++++ proxy/hq/HQFrameGenerator.h | 32 +++ proxy/hq/HQFrameHandler.h | 36 ++++ proxy/hq/HQHeaderFramer.cc | 98 +++++++++ proxy/hq/HQHeaderFramer.h | 54 +++++ proxy/hq/HQHeaderVIOAdaptor.cc | 50 +++++ proxy/hq/HQHeaderVIOAdaptor.h | 41 ++++ proxy/hq/HQStreamDataVIOAdaptor.cc | 49 +++++ proxy/hq/HQStreamDataVIOAdaptor.h | 41 ++++ proxy/hq/HQTypes.h | 95 +++++++++ proxy/hq/Makefile.am | 9 + 25 files changed, 1497 insertions(+), 50 deletions(-) create mode 100644 proxy/hq/HQDataFramer.cc create mode 100644 proxy/hq/HQDataFramer.h create mode 100644 proxy/hq/HQDebugNames.h create mode 100644 proxy/hq/HQFrame.cc create mode 100644 proxy/hq/HQFrame.h create mode 100644 proxy/hq/HQFrameCollector.cc create mode 100644 proxy/hq/HQFrameCollector.h create mode 100644 proxy/hq/HQFrameDispatcher.cc create mode 100644 proxy/hq/HQFrameDispatcher.h create mode 100644 proxy/hq/HQFrameGenerator.h create mode 100644 proxy/hq/HQFrameHandler.h create mode 100644 proxy/hq/HQHeaderFramer.cc create mode 100644 proxy/hq/HQHeaderFramer.h create mode 100644 proxy/hq/HQHeaderVIOAdaptor.cc create mode 100644 proxy/hq/HQHeaderVIOAdaptor.h create mode 100644 proxy/hq/HQStreamDataVIOAdaptor.cc create mode 100644 proxy/hq/HQStreamDataVIOAdaptor.h create mode 100644 proxy/hq/HQTypes.h diff --git a/configure.ac b/configure.ac index fddeed0453c..6d448dc5c7f 100644 --- a/configure.ac +++ b/configure.ac @@ -2087,6 +2087,7 @@ AC_CONFIG_FILES([ proxy/http/remap/Makefile proxy/http2/Makefile proxy/hq/Makefile + proxy/hq/test/Makefile proxy/logging/Makefile proxy/shared/Makefile rc/Makefile diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index e2d73bfe34f..c15dd93c3c9 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -69,6 +69,12 @@ QUICStreamIO::write(const uint8_t *buf, int64_t len) return this->_write_buffer->write(buf, len); } +int64_t +QUICStreamIO::write_avail() +{ + return this->_write_buffer->write_avail(); +} + int64_t QUICStreamIO::write(IOBufferReader *r, int64_t alen, int64_t offset) { diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index cbffb955555..d1f94decbb6 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -43,6 +43,7 @@ class QUICStreamIO int64_t read_avail(); bool is_read_avail_more_than(int64_t size); int64_t read(uint8_t *buf, int64_t len); + int64_t write_avail(); int64_t write(const uint8_t *buf, int64_t len); int64_t write(IOBufferReader *r, int64_t len = INT64_MAX, int64_t offset = 0); void set_write_vio_nbytes(int64_t); diff --git a/iocore/net/quic/QUICIntUtil.cc b/iocore/net/quic/QUICIntUtil.cc index d9e745d0a93..683c449a8c1 100644 --- a/iocore/net/quic/QUICIntUtil.cc +++ b/iocore/net/quic/QUICIntUtil.cc @@ -84,6 +84,9 @@ QUICVariableInt::encode(uint8_t *dst, size_t dst_len, size_t &len, uint64_t src) int QUICVariableInt::decode(uint64_t &dst, size_t &len, const uint8_t *src, size_t src_len) { + if (src_len < 1) { + return -1; + } len = 1 << (src[0] >> 6); if (src_len < len) { return 1; diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 779210d457b..c60cef6a114 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -26,6 +26,10 @@ #include "QUICDebugNames.h" #include "HQClientSession.h" +#include "HQStreamDataVIOAdaptor.h" +#include "HQHeaderVIOAdaptor.h" +#include "HQHeaderFramer.h" +#include "HQDataFramer.h" #include "HttpSM.h" #define HQTransDebug(fmt, ...) \ @@ -45,16 +49,34 @@ // } HQClientTransaction::HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) - { this->mutex = new_ProxyMutex(); this->set_parent(session); this->sm_reader = this->_read_vio_buf.alloc_reader(); static_cast(this->parent)->add_transaction(this); + this->_header_framer = new HQHeaderFramer(this, &this->_write_vio); + this->_data_framer = new HQDataFramer(this, &this->_write_vio); + this->_frame_collector.add_generator(this->_header_framer); + this->_frame_collector.add_generator(this->_data_framer); + // this->_frame_collector.add_generator(this->_push_controller); + + this->_header_handler = new HQHeaderVIOAdaptor(&this->_read_vio); + this->_data_handler = new HQStreamDataVIOAdaptor(&this->_read_vio); + this->_frame_dispatcher.add_handler(this->_header_handler); + this->_frame_dispatcher.add_handler(this->_data_handler); + SET_HANDLER(&HQClientTransaction::state_stream_open); } +HQClientTransaction::~HQClientTransaction() +{ + delete this->_header_framer; + delete this->_data_framer; + delete this->_header_handler; + delete this->_data_handler; +} + void HQClientTransaction::set_active_timeout(ink_hrtime timeout_in) { @@ -356,33 +378,59 @@ HQClientTransaction::_process_read_vio() IOBufferReader *client_vio_reader = this->_stream_io->get_read_buffer_reader(); int64_t bytes_avail = client_vio_reader->read_avail(); - MIOBuffer *writer = this->_read_vio.get_writer(); - if (!this->_client_req_header_complete) { - int n = 2; - // Check client request is complete or not - if (bytes_avail < 2 || client_vio_reader->start()[bytes_avail - 1] != '\n') { + // Nuke this block when we drop 0.9 support + if (!this->_protocol_detected) { + if (bytes_avail < 3) { return 0; } - this->_client_req_header_complete = true; - - // Check "CRLF" or "LF" - if (client_vio_reader->start()[bytes_avail - 2] != '\r') { - n = 1; + // If the first two bit are 0 and 1, the 3rd byte is type field. + // Because there is no type value larger than 0x20, we can assume that the + // request is HTTP/0.9 if the value is larger than 0x20. + const uint8_t *start = reinterpret_cast(client_vio_reader->start()); + if (0x40 <= *start && *start < 0x80 && *(start + 2) > 0x20) { + this->_legacy_request = true; } + this->_protocol_detected = true; + } - writer->write(client_vio_reader, bytes_avail - n); - client_vio_reader->consume(bytes_avail); + if (this->_legacy_request) { + MIOBuffer *writer = this->_read_vio.get_writer(); + + // Nuke this branch when we drop 0.9 support + if (!this->_client_req_header_complete) { + int n = 2; + // Check client request is complete or not + if (bytes_avail < 2 || client_vio_reader->start()[bytes_avail - 1] != '\n') { + return 0; + } + this->_client_req_header_complete = true; + + // Check "CRLF" or "LF" + if (client_vio_reader->start()[bytes_avail - 2] != '\r') { + n = 1; + } + + writer->write(client_vio_reader, bytes_avail - n); + client_vio_reader->consume(bytes_avail); + + // FIXME: Get hostname from SNI? + const char version[] = " HTTP/1.1\r\nHost: localhost\r\n\r\n"; + writer->write(version, sizeof(version)); + } else { + writer->write(client_vio_reader, bytes_avail); + client_vio_reader->consume(bytes_avail); + } - // FIXME: Get hostname from SNI? - const char version[] = " HTTP/1.1\r\nHost: localhost\r\n\r\n"; - writer->write(version, sizeof(version)); + return bytes_avail; + // End of code for HTTP/0.9 } else { - writer->write(client_vio_reader, bytes_avail); - client_vio_reader->consume(bytes_avail); + // This branch is for HQ + uint16_t nread = 0; + this->_frame_dispatcher.on_read_ready(reinterpret_cast(client_vio_reader->start()), bytes_avail, nread); + client_vio_reader->consume(nread); + return nread; } - - return bytes_avail; } // FIXME: already defined somewhere? @@ -400,45 +448,52 @@ HQClientTransaction::_process_write_vio() IOBufferReader *reader = this->_write_vio.get_reader(); - int64_t http_1_1_version_len = sizeof(http_1_1_version) - 1; + if (this->_legacy_request) { + // This branch is for HTTP/0.9 + int64_t http_1_1_version_len = sizeof(http_1_1_version) - 1; - if (reader->is_read_avail_more_than(http_1_1_version_len) && - memcmp(reader->start(), http_1_1_version, http_1_1_version_len) == 0) { - // Skip HTTP/1.1 response headers - IOBufferBlock *headers = reader->get_current_block(); - int64_t headers_size = headers->read_avail(); - reader->consume(headers_size); - this->_write_vio.ndone += headers_size; + if (reader->is_read_avail_more_than(http_1_1_version_len) && + memcmp(reader->start(), http_1_1_version, http_1_1_version_len) == 0) { + // Skip HTTP/1.1 response headers + IOBufferBlock *headers = reader->get_current_block(); + int64_t headers_size = headers->read_avail(); + reader->consume(headers_size); + this->_write_vio.ndone += headers_size; - // The size of respons to client - this->_stream_io->set_write_vio_nbytes(this->_write_vio.nbytes - headers_size); - } + // The size of respons to client + this->_stream_io->set_write_vio_nbytes(this->_write_vio.nbytes - headers_size); + } + + // Write HTTP/1.1 response body + int64_t bytes_avail = reader->read_avail(); + int64_t total_written = 0; - // Write HTTP/1.1 response body - int64_t bytes_avail = reader->read_avail(); - int64_t total_written = 0; + HQTransDebug("%" PRId64, bytes_avail); - HQTransDebug("%" PRId64, bytes_avail); + while (total_written < bytes_avail) { + int64_t data_len = reader->block_read_avail(); + int64_t bytes_written = this->_stream_io->write(reader, data_len); + if (bytes_written <= 0) { + break; + } - while (total_written < bytes_avail) { - int64_t data_len = reader->block_read_avail(); - int64_t bytes_written = this->_stream_io->write(reader, data_len); - if (bytes_written <= 0) { - break; + reader->consume(bytes_written); + this->_write_vio.ndone += bytes_written; + total_written += bytes_written; } - reader->consume(bytes_written); - this->_write_vio.ndone += bytes_written; - total_written += bytes_written; - } + // NOTE: When Chunked Transfer Coding is supported, check ChunkedState of ChunkedHandler + // is CHUNK_READ_DONE and set FIN flag + if (this->_write_vio.ntodo() == 0) { + this->_stream_io->shutdown(); + } - // NOTE: When Chunked Transfer Coding is supported, check ChunkedState of ChunkedHandler - // is CHUNK_READ_DONE and set FIN flag - if (this->_write_vio.ntodo() == 0) { - this->_stream_io->shutdown(); + return total_written; + } else { + size_t nwritten = 0; + this->_frame_collector.on_write_ready(this->_stream_io, nwritten); + return nwritten; } - - return total_written; } void @@ -453,3 +508,15 @@ HQClientTransaction::get_transaction_id() const { return this->_stream_io->get_transaction_id(); } + +bool +HQClientTransaction::is_response_header_sent() const +{ + return this->_header_framer->is_done(); +} + +bool +HQClientTransaction::is_response_body_sent() const +{ + return this->_data_framer->is_done(); +} diff --git a/proxy/hq/HQClientTransaction.h b/proxy/hq/HQClientTransaction.h index 7a10e9d10ef..155cbc50774 100644 --- a/proxy/hq/HQClientTransaction.h +++ b/proxy/hq/HQClientTransaction.h @@ -25,9 +25,13 @@ #include "I_VConnection.h" #include "ProxyClientTransaction.h" +#include "HQFrameDispatcher.h" +#include "HQFrameCollector.h" class QUICStreamIO; class HQClientSession; +class HQHeaderFramer; +class HQDataFramer; class HQClientTransaction : public ProxyClientTransaction { @@ -35,6 +39,7 @@ class HQClientTransaction : public ProxyClientTransaction using super = ProxyClientTransaction; HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io); + ~HQClientTransaction(); // Implement ProxyClienTransaction interface void set_active_timeout(ink_hrtime timeout_in) override; @@ -59,6 +64,8 @@ class HQClientTransaction : public ProxyClientTransaction // HQClientTransaction specific methods int state_stream_open(int, void *); int state_stream_closed(int event, void *data); + bool is_response_header_sent() const; + bool is_response_body_sent() const; private: Event *_send_tracked_event(Event *, int, VIO *); @@ -75,5 +82,16 @@ class HQClientTransaction : public ProxyClientTransaction Event *_read_event = nullptr; Event *_write_event = nullptr; + // These are for HQ + HQFrameDispatcher _frame_dispatcher; + HQFrameCollector _frame_collector; + HQFrameGenerator *_header_framer = nullptr; + HQFrameGenerator *_data_framer = nullptr; + HQFrameHandler *_header_handler = nullptr; + HQFrameHandler *_data_handler = nullptr; + + // These are for 0.9 support + bool _protocol_detected = false; + bool _legacy_request = false; bool _client_req_header_complete = false; }; diff --git a/proxy/hq/HQDataFramer.cc b/proxy/hq/HQDataFramer.cc new file mode 100644 index 00000000000..09f55ae043b --- /dev/null +++ b/proxy/hq/HQDataFramer.cc @@ -0,0 +1,55 @@ +/** @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 "HQFrame.h" +#include "HQDataFramer.h" +#include "HQClientTransaction.h" + +HQDataFramer::HQDataFramer(HQClientTransaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) +{ +} + +HQFrameUPtr +HQDataFramer::generate_frame(uint16_t max_size) +{ + if (!this->_transaction->is_response_header_sent()) { + return HQFrameFactory::create_null_frame(); + } + + HQFrameUPtr frame = HQFrameFactory::create_null_frame(); + IOBufferReader *reader = this->_source_vio->get_reader(); + size_t len = std::min(reader->read_avail(), static_cast(max_size)); + if (len) { + frame = HQFrameFactory::create_data_frame(reinterpret_cast(reader->start()), len); + reader->consume(len); + this->_source_vio->ndone += len; + } + + return frame; +} + +bool +HQDataFramer::is_done() const +{ + return this->_source_vio->ntodo() == 0; +} diff --git a/proxy/hq/HQDataFramer.h b/proxy/hq/HQDataFramer.h new file mode 100644 index 00000000000..af6fe8d09b4 --- /dev/null +++ b/proxy/hq/HQDataFramer.h @@ -0,0 +1,44 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "HQFrameGenerator.h" +#include "HQFrame.h" + +class HQClientTransaction; +class VIO; + +class HQDataFramer : public HQFrameGenerator +{ +public: + HQDataFramer(HQClientTransaction *transaction, VIO *source); + + // HQFrameGenerator + HQFrameUPtr generate_frame(uint16_t max_size) override; + bool is_done() const override; + +private: + HQClientTransaction *_transaction = nullptr; + VIO *_source_vio = nullptr; +}; diff --git a/proxy/hq/HQDebugNames.h b/proxy/hq/HQDebugNames.h new file mode 100644 index 00000000000..f1aa81da4be --- /dev/null +++ b/proxy/hq/HQDebugNames.h @@ -0,0 +1,29 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +class HQDebugNames +{ + static const char *frame_type(HQFrameType type); +}; diff --git a/proxy/hq/HQFrame.cc b/proxy/hq/HQFrame.cc new file mode 100644 index 00000000000..e92a7c12d44 --- /dev/null +++ b/proxy/hq/HQFrame.cc @@ -0,0 +1,313 @@ +/** @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 "ts/Diags.h" +#include "quic/QUICIntUtil.h" +#include "HQFrame.h" + +ClassAllocator hqFrameAllocator("hqFrameAllocator"); +ClassAllocator hqDataFrameAllocator("hqDataFrameAllocator"); +ClassAllocator hqHeadersFrameAllocator("hqHeadersFrameAllocator"); + +// +// Static functions +// + +int +HQFrame::length(const uint8_t *buf, size_t buf_len, uint64_t &length) +{ + size_t length_field_length = 0; + return QUICVariableInt::decode(length, length_field_length, buf, buf_len); +} + +HQFrameType +HQFrame::type(const uint8_t *buf, size_t buf_len) +{ + uint64_t length = 0; + size_t length_field_length = 0; + int ret = QUICVariableInt::decode(length, length_field_length, buf, buf_len); + ink_assert(ret != 1); + if (buf[length_field_length] <= static_cast(HQFrameType::X_MAX_DEFINED)) { + return static_cast(buf[length_field_length]); + } else { + return HQFrameType::UNKNOWN; + } +} + +// +// Generic Frame +// + +HQFrame::HQFrame(const uint8_t *buf, size_t buf_len) +{ + // Length + size_t length_field_length = 0; + int ret = QUICVariableInt::decode(this->_length, length_field_length, buf, buf_len); + ink_assert(ret != 1); + + // Type + this->_type = HQFrameType(buf[length_field_length]); + + // Flags + this->_flags = buf[length_field_length + 1]; + + // Payload offset + this->_payload_offset = length_field_length + 2; +} + +HQFrame::HQFrame(HQFrameType type) : _type(type) +{ +} + +uint64_t +HQFrame::total_length() const +{ + return this->_payload_offset + this->length(); +} + +uint64_t +HQFrame::length() const +{ + return this->_length; +} + +HQFrameType +HQFrame::type() const +{ + return this->_type; +} + +uint8_t +HQFrame::flags() const +{ + return this->_flags; +} + +void +HQFrame::store(uint8_t *buf, size_t *len) const +{ + // If you really need this, you should keep the data passed to its constructor + ink_assert(!"Not supported"); +} + +void +HQFrame::reset(const uint8_t *buf, size_t len) +{ + this->~HQFrame(); + new (this) HQFrame(buf, len); +} + +// +// UNKNOWN Frame +// +HQUnknownFrame::HQUnknownFrame(const uint8_t *buf, size_t buf_len) : HQFrame(buf, buf_len), _buf(buf), _buf_len(buf_len) +{ +} + +void +HQUnknownFrame::store(uint8_t *buf, size_t *len) const +{ + memcpy(buf, this->_buf, this->_buf_len); + *len = this->_buf_len; +} + +// +// DATA Frame +// +HQDataFrame::HQDataFrame(const uint8_t *buf, size_t buf_len) : HQFrame(buf, buf_len) +{ + this->_payload = buf + this->_payload_offset; + this->_payload_len = buf_len - this->_payload_offset; +} + +HQDataFrame::HQDataFrame(ats_unique_buf payload, size_t payload_len) + : HQFrame(HQFrameType::DATA), _payload_uptr(std::move(payload)), _payload_len(payload_len) +{ + this->_length = this->_payload_len; + this->_payload = this->_payload_uptr.get(); +} + +void +HQDataFrame::store(uint8_t *buf, size_t *len) const +{ + size_t written = 0; + QUICVariableInt::encode(buf, UINT64_MAX, written, this->_length); + buf[written++] = static_cast(this->_type); + buf[written++] = this->_flags; + memcpy(buf + written, this->_payload, this->_payload_len); + written += this->_payload_len; + *len = written; +} + +void +HQDataFrame::reset(const uint8_t *buf, size_t len) +{ + this->~HQDataFrame(); + new (this) HQDataFrame(buf, len); +} + +const uint8_t * +HQDataFrame::payload() const +{ + return this->_payload; +} + +uint64_t +HQDataFrame::payload_length() const +{ + return this->_payload_len; +} + +// +// HEADERS Frame +// +HQHeadersFrame::HQHeadersFrame(const uint8_t *buf, size_t buf_len) : HQFrame(buf, buf_len) +{ + this->_header_block = buf + this->_payload_offset; + this->_header_block_len = buf_len - this->_payload_offset; +} + +HQHeadersFrame::HQHeadersFrame(ats_unique_buf header_block, size_t header_block_len) + : HQFrame(HQFrameType::HEADERS), _header_block_uptr(std::move(header_block)), _header_block_len(header_block_len) +{ + this->_length = header_block_len; + this->_header_block = this->_header_block_uptr.get(); +} + +void +HQHeadersFrame::store(uint8_t *buf, size_t *len) const +{ + size_t written = 0; + QUICVariableInt::encode(buf, UINT64_MAX, written, this->_length); + buf[written++] = static_cast(this->_type); + buf[written++] = this->_flags; + memcpy(buf + written, this->_header_block, this->_header_block_len); + written += this->_header_block_len; + *len = written; +} + +void +HQHeadersFrame::reset(const uint8_t *buf, size_t len) +{ + this->~HQHeadersFrame(); + new (this) HQHeadersFrame(buf, len); +} + +const uint8_t * +HQHeadersFrame::header_block() const +{ + return this->_header_block; +} + +uint64_t +HQHeadersFrame::header_block_length() const +{ + return this->_header_block_len; +} + +// +// HQFrameFactory +// +HQFrameUPtr +HQFrameFactory::create_null_frame() +{ + return {nullptr, &HQFrameDeleter::delete_null_frame}; +} + +HQFrameUPtr +HQFrameFactory::create(const uint8_t *buf, size_t len) +{ + HQFrame *frame = nullptr; + HQFrameType type = HQFrame::type(buf, len); + + switch (type) { + case HQFrameType::HEADERS: + frame = hqHeadersFrameAllocator.alloc(); + new (frame) HQHeadersFrame(buf, len); + return HQFrameUPtr(frame, &HQFrameDeleter::delete_headers_frame); + case HQFrameType::DATA: + frame = hqDataFrameAllocator.alloc(); + new (frame) HQDataFrame(buf, len); + return HQFrameUPtr(frame, &HQFrameDeleter::delete_data_frame); + default: + // Unknown frame + Debug("hq_frame_factory", "Unknown frame type %hhx", type); + frame = hqFrameAllocator.alloc(); + new (frame) HQFrame(buf, len); + return HQFrameUPtr(frame, &HQFrameDeleter::delete_frame); + } +} + +std::shared_ptr +HQFrameFactory::fast_create(const uint8_t *buf, size_t len) +{ + uint64_t frame_length = 0; + if (HQFrame::length(buf, len, frame_length) == -1 || frame_length > len) { + return nullptr; + } + HQFrameType type = HQFrame::type(buf, len); + if (type == HQFrameType::UNKNOWN) { + if (!this->_unknown_frame) { + this->_unknown_frame = HQFrameFactory::create(buf, len); + } else { + this->_unknown_frame->reset(buf, len); + } + return _unknown_frame; + } + + std::shared_ptr frame = this->_reusable_frames[static_cast(type)]; + + if (frame == nullptr) { + frame = HQFrameFactory::create(buf, len); + if (frame != nullptr) { + this->_reusable_frames[static_cast(type)] = frame; + } + } else { + frame->reset(buf, len); + } + fprintf(stderr, "%p\n", frame.get()); + + return frame; +} + +HQHeadersFrameUPtr +HQFrameFactory::create_headers_frame(const uint8_t *header_block, size_t header_block_len) +{ + ats_unique_buf buf = ats_unique_malloc(header_block_len); + memcpy(buf.get(), header_block, header_block_len); + + HQHeadersFrame *frame = hqHeadersFrameAllocator.alloc(); + new (frame) HQHeadersFrame(std::move(buf), header_block_len); + return HQHeadersFrameUPtr(frame, &HQFrameDeleter::delete_headers_frame); +} + +HQDataFrameUPtr +HQFrameFactory::create_data_frame(const uint8_t *payload, size_t payload_len) +{ + ats_unique_buf buf = ats_unique_malloc(payload_len); + memcpy(buf.get(), payload, payload_len); + + HQDataFrame *frame = hqDataFrameAllocator.alloc(); + new (frame) HQDataFrame(std::move(buf), payload_len); + return HQDataFrameUPtr(frame, &HQFrameDeleter::delete_data_frame); +} diff --git a/proxy/hq/HQFrame.h b/proxy/hq/HQFrame.h new file mode 100644 index 00000000000..d061e5274f7 --- /dev/null +++ b/proxy/hq/HQFrame.h @@ -0,0 +1,190 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ts/Allocator.h" +#include "ts/ink_memory.h" +#include "ts/ink_assert.h" +#include "HQTypes.h" + +class HQFrame +{ +public: + HQFrame() {} + HQFrame(const uint8_t *buf, size_t len); + HQFrame(HQFrameType type); + virtual ~HQFrame() {} + + uint64_t total_length() const; + uint64_t length() const; + HQFrameType type() const; + uint8_t flags() const; + virtual void store(uint8_t *buf, size_t *len) const; + virtual void reset(const uint8_t *buf, size_t len); + static int length(const uint8_t *buf, size_t buf_len, uint64_t &length); + static HQFrameType type(const uint8_t *buf, size_t buf_len); + +protected: + uint64_t _length = 0; + HQFrameType _type = HQFrameType::UNKNOWN; + uint8_t _flags = 0; + size_t _payload_offset = 0; +}; + +class HQUnknownFrame : public HQFrame +{ +public: + HQUnknownFrame() : HQFrame() {} + HQUnknownFrame(const uint8_t *buf, size_t len); + + void store(uint8_t *buf, size_t *len) const override; + +protected: + const uint8_t *_buf = nullptr; + size_t _buf_len = 0; +}; + +// +// DATA Frame +// + +class HQDataFrame : public HQFrame +{ +public: + HQDataFrame() : HQFrame() {} + HQDataFrame(const uint8_t *buf, size_t len); + HQDataFrame(ats_unique_buf payload, size_t payload_len); + + void store(uint8_t *buf, size_t *len) const override; + void reset(const uint8_t *buf, size_t len) override; + + const uint8_t *payload() const; + uint64_t payload_length() const; + +private: + const uint8_t *_payload = nullptr; + ats_unique_buf _payload_uptr = {nullptr, [](void *p) { ats_free(p); }}; + size_t _payload_len = 0; +}; + +// +// HEADERS Frame +// + +class HQHeadersFrame : public HQFrame +{ +public: + HQHeadersFrame() : HQFrame() {} + HQHeadersFrame(const uint8_t *buf, size_t len); + HQHeadersFrame(ats_unique_buf header_block, size_t header_block_len); + + void store(uint8_t *buf, size_t *len) const override; + void reset(const uint8_t *buf, size_t len) override; + + const uint8_t *header_block() const; + uint64_t header_block_length() const; + +private: + const uint8_t *_header_block = nullptr; + ats_unique_buf _header_block_uptr = {nullptr, [](void *p) { ats_free(p); }}; + size_t _header_block_len = 0; +}; + +using HQFrameDeleterFunc = void (*)(HQFrame *p); +using HQFrameUPtr = std::unique_ptr; +using HQDataFrameUPtr = std::unique_ptr; +using HQHeadersFrameUPtr = std::unique_ptr; + +extern ClassAllocator hqFrameAllocator; +extern ClassAllocator hqDataFrameAllocator; +extern ClassAllocator hqHeadersFrameAllocator; + +class HQFrameDeleter +{ +public: + static void + delete_null_frame(HQFrame *frame) + { + ink_assert(frame == nullptr); + } + + static void + delete_frame(HQFrame *frame) + { + frame->~HQFrame(); + hqFrameAllocator.free(static_cast(frame)); + } + + static void + delete_data_frame(HQFrame *frame) + { + frame->~HQFrame(); + hqDataFrameAllocator.free(static_cast(frame)); + } + + static void + delete_headers_frame(HQFrame *frame) + { + frame->~HQFrame(); + hqHeadersFrameAllocator.free(static_cast(frame)); + } +}; + +// +// HQFrameFactory +// +class HQFrameFactory +{ +public: + /* + * This is for an empty HQFrameUPtr. + * Empty frames are used for variable initialization and return value of frame creation failure + */ + static HQFrameUPtr create_null_frame(); + + /* + * This is used for creating a HQFrame object based on received data. + */ + static HQFrameUPtr create(const uint8_t *buf, size_t len); + + /* + * 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. + */ + std::shared_ptr fast_create(const uint8_t *buf, size_t len); + + /* + * Creates a HEADERS frame. + */ + static HQHeadersFrameUPtr create_headers_frame(const uint8_t *header_block, size_t header_block_len); + + /* + * Creates a DATA frame. + */ + static HQDataFrameUPtr create_data_frame(const uint8_t *data, size_t data_len); + +private: + std::shared_ptr _unknown_frame = nullptr; + std::shared_ptr _reusable_frames[256] = {nullptr}; +}; diff --git a/proxy/hq/HQFrameCollector.cc b/proxy/hq/HQFrameCollector.cc new file mode 100644 index 00000000000..f3165245fce --- /dev/null +++ b/proxy/hq/HQFrameCollector.cc @@ -0,0 +1,62 @@ +/** @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 "HQFrameCollector.h" + +HQErrorUPtr +HQFrameCollector::on_write_ready(QUICStreamIO *stream_io, size_t &nwritten) +{ + bool all_done = true; + uint8_t tmp[32768]; + nwritten = 0; + + for (auto g : this->_generators) { + if (g->is_done()) { + continue; + } + size_t len = 0; + HQFrameUPtr frame = g->generate_frame(sizeof(tmp) - nwritten); + if (frame) { + frame->store(tmp + nwritten, &len); + nwritten += len; + } + all_done &= g->is_done(); + } + + if (nwritten) { + int64_t len = stream_io->write(tmp, nwritten); + ink_assert(len > 0 && (uint64_t)len == nwritten); + } + + if (all_done) { + stream_io->shutdown(); + } + + return HQErrorUPtr(new HQNoError()); +} + +void +HQFrameCollector::add_generator(HQFrameGenerator *generator) +{ + this->_generators.push_back(generator); +} diff --git a/proxy/hq/HQFrameCollector.h b/proxy/hq/HQFrameCollector.h new file mode 100644 index 00000000000..8542a0a20b7 --- /dev/null +++ b/proxy/hq/HQFrameCollector.h @@ -0,0 +1,40 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICApplication.h" +#include "HQFrame.h" +#include "HQFrameGenerator.h" +#include + +class HQFrameCollector +{ +public: + HQErrorUPtr on_write_ready(QUICStreamIO *stream_io, size_t &nread); + + void add_generator(HQFrameGenerator *generator); + +private: + std::vector _generators; +}; diff --git a/proxy/hq/HQFrameDispatcher.cc b/proxy/hq/HQFrameDispatcher.cc new file mode 100644 index 00000000000..e8ffc9e22f8 --- /dev/null +++ b/proxy/hq/HQFrameDispatcher.cc @@ -0,0 +1,73 @@ +/** @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 "HQFrameDispatcher.h" +#include "HQDebugNames.h" +#include "ts/Diags.h" + +static constexpr char tag[] = "hq_frame"; + +// +// Frame Dispatcher +// + +void +HQFrameDispatcher::add_handler(HQFrameHandler *handler) +{ + for (HQFrameType t : handler->interests()) { + this->_handlers[static_cast(t)].push_back(handler); + } +} + +HQErrorUPtr +HQFrameDispatcher::on_read_ready(const uint8_t *src, uint16_t read_avail, uint16_t &nread) +{ + std::shared_ptr frame(nullptr); + const uint8_t *cursor = src; + HQErrorUPtr error = HQErrorUPtr(new HQNoError()); + uint64_t frame_length = 0; + + while (HQFrame::length(cursor, read_avail, frame_length) != -1 && read_avail >= frame_length) { + frame = this->_frame_factory.fast_create(cursor, read_avail); + if (frame == nullptr) { + Debug(tag, "Failed to create a frame"); + // error = HQErrorUPtr(new HQStreamError()); + break; + } + cursor += frame->total_length(); + read_avail -= frame->total_length(); + + HQFrameType type = frame->type(); + std::vector handlers = this->_handlers[static_cast(type)]; + for (auto h : handlers) { + error = h->handle_frame(frame); + if (error->cls != HQErrorClass::NONE) { + return error; + } + } + } + + nread = cursor - src; + + return error; +} diff --git a/proxy/hq/HQFrameDispatcher.h b/proxy/hq/HQFrameDispatcher.h new file mode 100644 index 00000000000..6fa893ddc2c --- /dev/null +++ b/proxy/hq/HQFrameDispatcher.h @@ -0,0 +1,40 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "HQFrame.h" +#include "HQFrameHandler.h" +#include + +class HQFrameDispatcher +{ +public: + HQErrorUPtr on_read_ready(const uint8_t *source, uint16_t read_avail, uint16_t &nread); + + void add_handler(HQFrameHandler *handler); + +private: + HQFrameFactory _frame_factory; + std::vector _handlers[256]; +}; diff --git a/proxy/hq/HQFrameGenerator.h b/proxy/hq/HQFrameGenerator.h new file mode 100644 index 00000000000..680a9ed74d1 --- /dev/null +++ b/proxy/hq/HQFrameGenerator.h @@ -0,0 +1,32 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +class HQFrameGenerator +{ +public: + virtual ~HQFrameGenerator(){}; + virtual HQFrameUPtr generate_frame(uint16_t max_size) = 0; + virtual bool is_done() const = 0; +}; diff --git a/proxy/hq/HQFrameHandler.h b/proxy/hq/HQFrameHandler.h new file mode 100644 index 00000000000..486c3de0599 --- /dev/null +++ b/proxy/hq/HQFrameHandler.h @@ -0,0 +1,36 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +class HQFrameHandler +{ +public: + virtual ~HQFrameHandler(){}; + virtual std::vector interests() = 0; + virtual HQErrorUPtr handle_frame(std::shared_ptr frame) = 0; +}; diff --git a/proxy/hq/HQHeaderFramer.cc b/proxy/hq/HQHeaderFramer.cc new file mode 100644 index 00000000000..f8bf717fc99 --- /dev/null +++ b/proxy/hq/HQHeaderFramer.cc @@ -0,0 +1,98 @@ +/** @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 "HQFrame.h" +#include "HQHeaderFramer.h" +#include "HQClientTransaction.h" +#include "HTTP.h" +#include "I_VIO.h" + +HQHeaderFramer::HQHeaderFramer(HQClientTransaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) +{ + http_parser_init(&this->_http_parser); +} + +HQFrameUPtr +HQHeaderFramer::generate_frame(uint16_t max_size) +{ + ink_assert(!this->_transaction->is_response_header_sent()); + + if (!this->_header_block) { + // this->_header_block will be filled if it is ready + this->_generate_header_block(); + } + + if (this->_header_block) { + // Create frames on demand base on max_size since we don't know how much we can write now + const uint8_t *start = this->_header_block + this->_header_block_wrote; + size_t len = std::min(this->_header_block_len - this->_header_block_wrote, static_cast(max_size)); + HQFrameUPtr frame = HQFrameFactory::create_headers_frame(start, len); + this->_header_block_wrote += len; + if (this->_header_block_len == this->_header_block_wrote) { + this->_sent_all_data = true; + } + return frame; + } else { + return HQFrameFactory::create_null_frame(); + } +} + +bool +HQHeaderFramer::is_done() const +{ + return this->_sent_all_data; +} + +void +HQHeaderFramer::_generate_header_block() +{ + // Prase response header and generate header block + int bytes_used = 0; + // TODO Use HTTP_TYPE_REQUEST if this is for requests + this->_header.create(HTTP_TYPE_RESPONSE); + int parse_result = this->_header.parse_resp(&this->_http_parser, this->_source_vio->get_reader(), &bytes_used, false); + this->_source_vio->ndone += this->_header.length_get(); + + switch (parse_result) { + case PARSE_RESULT_DONE: + this->_compress_header(); + break; + case PARSE_RESULT_CONT: + break; + default: + break; + } +} + +void +HQHeaderFramer::_compress_header() +{ + // TODO Compress the header data + // Just copy the header data for now. + int written = 0; + int tmp = 0; + int len = this->_header.length_get(); + this->_header_block = static_cast(ats_malloc(len)); + this->_header.print(reinterpret_cast(this->_header_block), len, &written, &tmp); + this->_header_block_len = written; +} diff --git a/proxy/hq/HQHeaderFramer.h b/proxy/hq/HQHeaderFramer.h new file mode 100644 index 00000000000..b719efa3e06 --- /dev/null +++ b/proxy/hq/HQHeaderFramer.h @@ -0,0 +1,54 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "HQFrameGenerator.h" +#include "HQFrame.h" +#include "hdrs/HTTP.h" + +class HQClientTransaction; +class VIO; + +class HQHeaderFramer : public HQFrameGenerator +{ +public: + HQHeaderFramer(HQClientTransaction *transaction, VIO *source); + + // HQFrameGenerator + HQFrameUPtr generate_frame(uint16_t max_size) override; + bool is_done() const override; + +private: + HQClientTransaction *_transaction = nullptr; + VIO *_source_vio = nullptr; + HTTPParser _http_parser; + HTTPHdr _header; + uint8_t *_header_block = nullptr; + size_t _header_block_len = 0; + size_t _header_block_wrote = 0; + bool _sent_all_data = false; + + void _generate_header_block(); + void _compress_header(); +}; diff --git a/proxy/hq/HQHeaderVIOAdaptor.cc b/proxy/hq/HQHeaderVIOAdaptor.cc new file mode 100644 index 00000000000..366e8651118 --- /dev/null +++ b/proxy/hq/HQHeaderVIOAdaptor.cc @@ -0,0 +1,50 @@ +/** @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 "HQHeaderVIOAdaptor.h" +#include "I_VIO.h" + +HQHeaderVIOAdaptor::HQHeaderVIOAdaptor(VIO *sink) : _sink_vio(sink) +{ +} + +std::vector +HQHeaderVIOAdaptor::interests() +{ + return {HQFrameType::HEADERS}; +} + +HQErrorUPtr +HQHeaderVIOAdaptor::handle_frame(std::shared_ptr frame) +{ + ink_assert(frame->type() == HQFrameType::HEADERS); + const HQHeadersFrame *hframe = dynamic_cast(frame.get()); + + SCOPED_MUTEX_LOCK(lock, this->_sink_vio->mutex, this_ethread()); + + MIOBuffer *writer = this->_sink_vio->get_writer(); + // TODO Uncompress header block + writer->write(hframe->header_block(), hframe->header_block_length()); + + return HQErrorUPtr(new HQNoError()); +} diff --git a/proxy/hq/HQHeaderVIOAdaptor.h b/proxy/hq/HQHeaderVIOAdaptor.h new file mode 100644 index 00000000000..0ec8c79d346 --- /dev/null +++ b/proxy/hq/HQHeaderVIOAdaptor.h @@ -0,0 +1,41 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include "HQFrameHandler.h" + +class VIO; + +class HQHeaderVIOAdaptor : public HQFrameHandler +{ +public: + HQHeaderVIOAdaptor(VIO *sink); + + // HQFrameHandler + std::vector interests() override; + HQErrorUPtr handle_frame(std::shared_ptr frame) override; + +private: + VIO *_sink_vio = nullptr; +}; diff --git a/proxy/hq/HQStreamDataVIOAdaptor.cc b/proxy/hq/HQStreamDataVIOAdaptor.cc new file mode 100644 index 00000000000..5df11902b9b --- /dev/null +++ b/proxy/hq/HQStreamDataVIOAdaptor.cc @@ -0,0 +1,49 @@ +/** @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 "HQStreamDataVIOAdaptor.h" +#include "I_VIO.h" + +HQStreamDataVIOAdaptor::HQStreamDataVIOAdaptor(VIO *sink) : _sink_vio(sink) +{ +} + +std::vector +HQStreamDataVIOAdaptor::interests() +{ + return {HQFrameType::DATA}; +} + +HQErrorUPtr +HQStreamDataVIOAdaptor::handle_frame(std::shared_ptr frame) +{ + ink_assert(frame->type() == HQFrameType::DATA); + const HQDataFrame *dframe = dynamic_cast(frame.get()); + + SCOPED_MUTEX_LOCK(lock, this->_sink_vio->mutex, this_ethread()); + + MIOBuffer *writer = this->_sink_vio->get_writer(); + writer->write(dframe->payload(), dframe->payload_length()); + + return HQErrorUPtr(new HQNoError()); +} diff --git a/proxy/hq/HQStreamDataVIOAdaptor.h b/proxy/hq/HQStreamDataVIOAdaptor.h new file mode 100644 index 00000000000..d3f79684c6a --- /dev/null +++ b/proxy/hq/HQStreamDataVIOAdaptor.h @@ -0,0 +1,41 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include "HQFrameHandler.h" + +class VIO; + +class HQStreamDataVIOAdaptor : public HQFrameHandler +{ +public: + HQStreamDataVIOAdaptor(VIO *sink); + + // HQFrameHandler + std::vector interests() override; + HQErrorUPtr handle_frame(std::shared_ptr frame) override; + +private: + VIO *_sink_vio = nullptr; +}; diff --git a/proxy/hq/HQTypes.h b/proxy/hq/HQTypes.h new file mode 100644 index 00000000000..3676d229ba3 --- /dev/null +++ b/proxy/hq/HQTypes.h @@ -0,0 +1,95 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// Update HQFrame::type(const uint8_t *) too when you modify this list +enum class HQFrameType : uint8_t { + DATA = 0x00, + HEADERS = 0x01, + PRIORITY = 0x02, + CANCEL_PUSH = 0x03, + SETTINGS = 0x04, + PUSH_PROMISE = 0x05, + X_RESERVED_1 = 0x06, + GOAWAY = 0x07, + HEADER_ACK = 0x08, + X_RESERVED_2 = 0x09, + MAX_PUSH_ID = 0x0D, + X_MAX_DEFINED = 0x0D, + UNKNOWN = 0xFF, +}; + +enum class HQErrorClass { + NONE, + APPLICATION, +}; + +using HQAppErrorCode = uint16_t; + +class HQError +{ +public: + virtual ~HQError() {} + uint16_t code(); + + HQErrorClass cls = HQErrorClass::NONE; + union { + HQAppErrorCode app_error_code; + }; + const char *msg = nullptr; + +protected: + HQError(){}; + HQError(const HQAppErrorCode error_code, const char *error_msg = nullptr) + : cls(HQErrorClass::APPLICATION), app_error_code(error_code), msg(error_msg){}; +}; + +class HQNoError : public HQError +{ +public: + HQNoError() : HQError() {} +}; + +class HQConnectionError : public HQError +{ +public: + HQConnectionError() : HQError() {} + HQConnectionError(const HQAppErrorCode error_code, const char *error_msg = nullptr) : HQError(error_code, error_msg){}; +}; + +class HQStream; + +class HQStreamError : public HQError +{ +public: + HQStreamError() : HQError() {} + HQStreamError(HQStream *s, const HQAppErrorCode error_code, const char *error_msg = nullptr) + : HQError(error_code, error_msg), stream(s){}; + + HQStream *stream; +}; + +using HQErrorUPtr = std::unique_ptr; +using HQConnectionErrorUPtr = std::unique_ptr; +using HQStreamErrorUPtr = std::unique_ptr; diff --git a/proxy/hq/Makefile.am b/proxy/hq/Makefile.am index e0d900b446d..17b99b6a83f 100644 --- a/proxy/hq/Makefile.am +++ b/proxy/hq/Makefile.am @@ -19,6 +19,8 @@ include $(top_srcdir)/build/tidy.mk +SUBDIRS = test + AM_CPPFLAGS += \ $(iocore_include_dirs) \ -I$(abs_top_srcdir)/proxy/api/ts \ @@ -40,6 +42,13 @@ libhq_a_SOURCES = \ HQSessionAccept.cc \ HQClientSession.cc \ HQClientTransaction.cc \ + HQFrame.cc \ + HQFrameCollector.cc \ + HQFrameDispatcher.cc \ + HQHeaderFramer.cc \ + HQDataFramer.cc \ + HQHeaderVIOAdaptor.cc \ + HQStreamDataVIOAdaptor.cc \ QUICSimpleApp.cc tidy-local: $(libhq_a_SOURCES) \ From ef7df31604ac843e736dd758c7debdafe68fc595 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 20 Mar 2018 15:23:26 +0900 Subject: [PATCH 0444/1313] Add tests for HQ --- .gitignore | 2 + proxy/hq/test/Makefile.am | 81 +++++++++++++ proxy/hq/test/Mock.h | 47 +++++++ proxy/hq/test/main.cc | 44 +++++++ proxy/hq/test/test_HQFrame.cc | 155 ++++++++++++++++++++++++ proxy/hq/test/test_HQFrameDispatcher.cc | 50 ++++++++ 6 files changed, 379 insertions(+) create mode 100644 proxy/hq/test/Makefile.am create mode 100644 proxy/hq/test/Mock.h create mode 100644 proxy/hq/test/main.cc create mode 100644 proxy/hq/test/test_HQFrame.cc create mode 100644 proxy/hq/test/test_HQFrameDispatcher.cc diff --git a/.gitignore b/.gitignore index e79029f75ed..dd7c8ad3de2 100644 --- a/.gitignore +++ b/.gitignore @@ -122,6 +122,8 @@ proxy/http2/test_Huffmancode proxy/http2/test_Http2DependencyTree proxy/http2/test_HPACK proxy/http2/hpack-tests/results +proxy/hq/test/test_HQFrame +proxy/hq/test/test_HQFrameDispatcher proxy/logging/test_LogUtils plugins/header_rewrite/header_rewrite_test diff --git a/proxy/hq/test/Makefile.am b/proxy/hq/test/Makefile.am new file mode 100644 index 00000000000..10536c9a1ed --- /dev/null +++ b/proxy/hq/test/Makefile.am @@ -0,0 +1,81 @@ +# Makefile.am for the traffic/iocore/net hierarchy +# +# 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. + +TESTS = $(check_PROGRAMS) +check_PROGRAMS = \ + test_HQFrame \ + test_HQFrameDispatcher + + +AM_CPPFLAGS += \ + $(iocore_include_dirs) \ + -I$(abs_top_srcdir)/lib \ + -I$(abs_top_srcdir)/lib/records \ + -I$(abs_top_srcdir)/mgmt \ + -I$(abs_top_srcdir)/mgmt/utils \ + -I$(abs_top_srcdir)/proxy \ + -I$(abs_top_srcdir)/proxy/hdrs \ + -I$(abs_top_srcdir)/proxy/http \ + -I$(abs_top_srcdir)/proxy/hq \ + -I$(abs_top_srcdir)/proxy/logging \ + -I$(abs_top_srcdir)/proxy/shared \ + -I$(abs_top_srcdir)/tests/include \ + @OPENSSL_INCLUDES@ + +# +# test_HQFrame +# +test_HQFrame_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_HQFrame_LDFLAGS = \ + @AM_LDFLAGS@ + +test_HQFrame_SOURCES = \ + main.cc \ + test_HQFrame.cc \ + ../HQFrame.cc + +test_HQFrame_LDADD = \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/lib/ts/libtsutil.la + +# +# test_HQFrameDispatcher +# +test_HQFrameDispatcher_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_HQFrameDispatcher_LDFLAGS = \ + @AM_LDFLAGS@ + +test_HQFrameDispatcher_SOURCES = \ + main.cc \ + test_HQFrameDispatcher.cc \ + ../HQFrameDispatcher.cc \ + ../HQFrame.cc + +test_HQFrameDispatcher_LDADD = \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/lib/ts/libtsutil.la + + +include $(top_srcdir)/build/tidy.mk + +tidy-local: $(DIST_SOURCES) + $(CXX_Clang_Tidy) diff --git a/proxy/hq/test/Mock.h b/proxy/hq/test/Mock.h new file mode 100644 index 00000000000..3e7090e9797 --- /dev/null +++ b/proxy/hq/test/Mock.h @@ -0,0 +1,47 @@ +/** @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 "catch.hpp" + +#include "HQFrameHandler.h" + +class HQMockFrameHandler : public HQFrameHandler +{ +public: + int total_frame_received = 0; + + // HQFrameHandler + + std::vector + interests() override + { + return {HQFrameType::DATA}; + } + + HQErrorUPtr + handle_frame(std::shared_ptr frame) override + { + this->total_frame_received++; + return HQErrorUPtr(new HQNoError()); + } +}; diff --git a/proxy/hq/test/main.cc b/proxy/hq/test/main.cc new file mode 100644 index 00000000000..f611f5e04e1 --- /dev/null +++ b/proxy/hq/test/main.cc @@ -0,0 +1,44 @@ +/** @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. + */ + +// To make compile faster +// https://github.com/philsquared/Catch/blob/master/docs/slow-compiles.md +#define CATCH_CONFIG_MAIN +#include "catch.hpp" + +#include "ts/Diags.h" + +struct EventProcessorListener : Catch::TestEventListenerBase { + using TestEventListenerBase::TestEventListenerBase; // inherit constructor + + virtual void + testRunStarting(Catch::TestRunInfo const &testRunInfo) override + { + BaseLogFile *base_log_file = new BaseLogFile("stderr"); + diags = new Diags(testRunInfo.name.c_str(), "" /* tags */, "" /* actions */, base_log_file); + diags->activate_taglist("vv_quic|quic", DiagsTagType_Debug); + diags->config.enabled[DiagsTagType_Debug] = true; + diags->show_location = SHOW_LOCATION_DEBUG; + } +}; +CATCH_REGISTER_LISTENER(EventProcessorListener); diff --git a/proxy/hq/test/test_HQFrame.cc b/proxy/hq/test/test_HQFrame.cc new file mode 100644 index 00000000000..061061b8063 --- /dev/null +++ b/proxy/hq/test/test_HQFrame.cc @@ -0,0 +1,155 @@ +/** @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 "catch.hpp" +#include +#include "HQFrame.h" +#include "HQFrameDispatcher.h" + +TEST_CASE("HQFrame Type", "[hq]") +{ + CHECK(HQFrame::type(reinterpret_cast("\x00\x00"), 2) == HQFrameType::DATA); + // Undefined ragne + CHECK(HQFrame::type(reinterpret_cast("\x00\x0e"), 2) == HQFrameType::UNKNOWN); + CHECK(HQFrame::type(reinterpret_cast("\x00\xff"), 2) == HQFrameType::UNKNOWN); +} + +TEST_CASE("Load DATA Frame", "[hq]") +{ + SECTION("No flags") + { + uint8_t buf1[] = { + 0x04, // Length + 0x00, // Type + 0x00, // Flags + 0x11, 0x22, 0x33, 0x44, // Payload + }; + std::shared_ptr frame1 = HQFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == HQFrameType::DATA); + CHECK(frame1->length() == 4); + std::shared_ptr data_frame = std::dynamic_pointer_cast(frame1); + CHECK(data_frame); + CHECK(data_frame->payload_length() == 4); + CHECK(memcmp(data_frame->payload(), "\x11\x22\x33\x44", 4) == 0); + } + + SECTION("Have flags (invalid)") + { + uint8_t buf1[] = { + 0x04, // Length + 0x00, // Type + 0xff, // Flags + 0x11, 0x22, 0x33, 0x44, // Payload + }; + std::shared_ptr frame1 = HQFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == HQFrameType::DATA); + CHECK(frame1->length() == 4); + std::shared_ptr data_frame = std::dynamic_pointer_cast(frame1); + CHECK(data_frame); + CHECK(data_frame->payload_length() == 4); + CHECK(memcmp(data_frame->payload(), "\x11\x22\x33\x44", 4) == 0); + } +} + +TEST_CASE("Store DATA Frame", "[hq]") +{ + SECTION("Normal") + { + uint8_t buf[32] = {0}; + size_t len; + uint8_t expected1[] = { + 0x04, // Length + 0x00, // Type + 0x00, // Flags + 0x11, 0x22, 0x33, 0x44, // Payload + }; + + uint8_t raw1[] = "\x11\x22\x33\x44"; + ats_unique_buf payload1 = ats_unique_malloc(4); + memcpy(payload1.get(), raw1, 4); + + HQDataFrame data_frame(std::move(payload1), 4); + CHECK(data_frame.length() == 4); + + data_frame.store(buf, &len); + CHECK(len == 7); + CHECK(memcmp(buf, expected1, len) == 0); + } +} + +TEST_CASE("HQFrameFactory Create Unknown Frame", "[hq]") +{ + uint8_t buf1[] = { + 0x00, // Length + 0xff, // Type + 0x00, // Flags + }; + std::shared_ptr frame1 = HQFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1); + CHECK(frame1->type() == HQFrameType::UNKNOWN); + CHECK(frame1->length() == 0); +} + +TEST_CASE("HQFrameFactory Fast Create Frame", "[hq]") +{ + HQFrameFactory factory; + + uint8_t buf1[] = { + 0x04, // Length + 0x00, // Type + 0x00, // Flags + 0x11, 0x22, 0x33, 0x44, // Payload + }; + uint8_t buf2[] = { + 0x04, // Length + 0x00, // Type + 0x00, // Flags + 0xaa, 0xbb, 0xcc, 0xdd, // Payload + }; + std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); + CHECK(frame1 != nullptr); + + std::shared_ptr data_frame1 = std::dynamic_pointer_cast(frame1); + CHECK(data_frame1 != nullptr); + CHECK(memcmp(data_frame1->payload(), buf1 + 3, 4) == 0); + + std::shared_ptr frame2 = factory.fast_create(buf2, sizeof(buf2)); + CHECK(frame2 != nullptr); + + std::shared_ptr data_frame2 = std::dynamic_pointer_cast(frame2); + CHECK(data_frame2 != nullptr); + CHECK(memcmp(data_frame2->payload(), buf2 + 3, 4) == 0); + + CHECK(frame1 == frame2); +} + +TEST_CASE("HQFrameFactory Fast Create Unknown Frame", "[hq]") +{ + HQFrameFactory factory; + + uint8_t buf1[] = { + 0x0f, // Type + }; + std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); + CHECK(frame1 == nullptr); +} diff --git a/proxy/hq/test/test_HQFrameDispatcher.cc b/proxy/hq/test/test_HQFrameDispatcher.cc new file mode 100644 index 00000000000..caf40ee21c0 --- /dev/null +++ b/proxy/hq/test/test_HQFrameDispatcher.cc @@ -0,0 +1,50 @@ +/** @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 "catch.hpp" + +#include "HQFrameDispatcher.h" +#include "Mock.h" + +TEST_CASE("HQFrameHandler dispatch", "[hq]") +{ + uint8_t input[] = {// 1st frame (HEADERS) + 0x02, 0x01, 0x00, 0x01, 0x23, + // 2nd frame (DATA) + 0x04, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, + // 3rd frame (incomplete) + 0xff}; + + HQFrameDispatcher hqFrameDispatcher; + HQMockFrameHandler handler; + hqFrameDispatcher.add_handler(&handler); + uint16_t nread = 0; + + // Initial state + CHECK(handler.total_frame_received == 0); + CHECK(nread == 0); + + hqFrameDispatcher.on_read_ready(input, sizeof(input), nread); + CHECK(handler.total_frame_received == 1); + CHECK(nread == 12); +} From 0bf98811bcb980b88c2e430e0c2f9accfba910c0 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 20 Mar 2018 15:06:07 +0900 Subject: [PATCH 0445/1313] Echo packet number of INITIAL packet in RETRY packet Following below in section 5.4.2 "Retry Packet" (draft-09) > The packet number field echoes the packet number field from the triggering client packet. --- iocore/net/QUICNetVConnection.cc | 3 ++- iocore/net/quic/QUICPacket.cc | 9 ++++++--- iocore/net/quic/QUICPacket.h | 2 +- iocore/net/quic/test/test_QUICPacketFactory.cc | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5d6e6ae4b4d..c647e93dd3d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1133,7 +1133,8 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi QUIC_SUPPORTED_VERSIONS[0], std::move(buf), len); break; case QUICPacketType::RETRY: - packet = this->_packet_factory.create_retry_packet(this->_quic_connection_id, this->largest_acked_packet_number(), + // Echo "_largest_received_packet_number" as packet number. Probably this is the packet number from triggering client packet. + packet = this->_packet_factory.create_retry_packet(this->_quic_connection_id, this->_largest_received_packet_number, std::move(buf), len, retransmittable); break; case QUICPacketType::HANDSHAKE: diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 610a67b6daf..2d5932ad034 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -782,12 +782,15 @@ QUICPacketFactory::create_initial_packet(QUICConnectionId connection_id, QUICPac return this->_create_encrypted_packet(std::move(header), true); } +/* + * Unlike other create_*_packet, the 2nd argument is not base packet number. + */ QUICPacketUPtr -QUICPacketFactory::create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, +QUICPacketFactory::create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, connection_id, this->_packet_number_generator.next(), - base_packet_number, this->_version, std::move(payload), len); + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::RETRY, connection_id, packet_number, 0, this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), retransmittable); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 669cbeab49a..cca3571d960 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -342,7 +342,7 @@ class QUICPacketFactory QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number); QUICPacketUPtr create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); - QUICPacketUPtr create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, + QUICPacketUPtr create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len, bool retransmittable); QUICPacketUPtr create_handshake_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 3db7a692a29..e260563e2af 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -66,11 +66,11 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketUPtr packet = factory.create_retry_packet(0x01020304, 0, std::move(payload), sizeof(raw), false); + QUICPacketUPtr packet = factory.create_retry_packet(0x01020304, 1234, std::move(payload), sizeof(raw), false); CHECK(packet->type() == QUICPacketType::RETRY); CHECK(packet->connection_id() == 0x01020304); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); - CHECK((packet->packet_number() & 0xFFFFFFFF80000000) == 0); + CHECK(packet->packet_number() == 1234); CHECK(packet->version() == 0x11223344); } From 976e1ecf82f82659d5145435ffc1cb6ebe52544a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 20 Mar 2018 16:08:24 +0900 Subject: [PATCH 0446/1313] Add five_tuple() to QUICConnection interface --- iocore/net/P_QUICNetVConnection.h | 2 ++ iocore/net/QUICNetVConnection.cc | 7 +++++ iocore/net/quic/Mock.h | 6 +++++ iocore/net/quic/QUICConnection.h | 1 + iocore/net/quic/QUICConnectionTable.h | 13 ---------- iocore/net/quic/QUICStatelessRetry.cc | 7 ++--- iocore/net/quic/QUICTypes.cc | 37 +++++++++++++++++++++++++++ iocore/net/quic/QUICTypes.h | 18 +++++++++++++ 8 files changed, 73 insertions(+), 18 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 03a1c4214b0..0cca49db88a 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -181,6 +181,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection // QUICConnection QUICConnectionId original_connection_id() override; QUICConnectionId connection_id() override; + const QUICFiveTuple five_tuple() override; uint32_t maximum_quic_packet_size() override; uint32_t minimum_quic_packet_size() override; uint32_t maximum_stream_frame_data_size() override; @@ -226,6 +227,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICConnectionId _original_quic_connection_id; QUICConnectionId _quic_connection_id; + QUICFiveTuple _five_tuple; AltConnectionInfo _alt_quic_connection_ids[3]; int8_t _alt_quic_connection_id_seq_num = 0; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index c647e93dd3d..32b45a2219c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -175,6 +175,7 @@ QUICNetVConnection::startEvent(int event, Event *e) void QUICNetVConnection::start(SSL_CTX *ssl_ctx) { + this->_five_tuple.update(this->local_addr, this->remote_addr, SOCK_DGRAM); // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not if (this->direction() == NET_VCONNECTION_IN) { QUICConfig::scoped_config params; @@ -289,6 +290,12 @@ QUICNetVConnection::connection_id() return this->_quic_connection_id; } +const QUICFiveTuple +QUICNetVConnection::five_tuple() +{ + return this->_five_tuple; +} + uint32_t QUICNetVConnection::pmtu() { diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 23625619bda..6c61438877d 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -157,6 +157,12 @@ class MockQUICConnection : public QUICConnection return 0; } + const QUICFiveTuple + five_tuple() override + { + return QUICFiveTuple(); + } + uint32_t transmit_packet(QUICPacketUPtr packet) override { diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index afcade0633b..8ab7b67b35d 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -39,6 +39,7 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter public: virtual QUICConnectionId original_connection_id() = 0; virtual QUICConnectionId connection_id() = 0; + virtual const QUICFiveTuple five_tuple() = 0; /* * Retruns the maximum packet size at the time called diff --git a/iocore/net/quic/QUICConnectionTable.h b/iocore/net/quic/QUICConnectionTable.h index 0ead233d6cf..2a4fefd91fb 100644 --- a/iocore/net/quic/QUICConnectionTable.h +++ b/iocore/net/quic/QUICConnectionTable.h @@ -27,19 +27,6 @@ #include "QUICConnection.h" #include "ts/MT_hashtable.h" -class QUICFiveTuple -{ -public: - QUICFiveTuple(IpEndpoint src, IpEndpoint dst, int protocol) - { - // FIXME Generate a hash code - this->_hash_code = src.port() + dst.port() + protocol; - } - -private: - uint64_t _hash_code = 0; -}; - class QUICConnectionTable { public: diff --git a/iocore/net/quic/QUICStatelessRetry.cc b/iocore/net/quic/QUICStatelessRetry.cc index 700b8c76e60..2776537f57c 100644 --- a/iocore/net/quic/QUICStatelessRetry.cc +++ b/iocore/net/quic/QUICStatelessRetry.cc @@ -45,14 +45,11 @@ QUICStatelessRetry::init() int QUICStatelessRetry::generate_cookie(SSL *ssl, unsigned char *cookie, size_t *cookie_len) { - // Call UnixNetVConnection::get_remote_addr() safely - // TODO: add APIs to getting client addr in QUICConnection - QUICConnection *qc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); - QUICNetVConnection *qvc = dynamic_cast(qc); + QUICConnection *qc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); uint8_t key[INET6_ADDRPORTSTRLEN] = {0}; size_t key_len = INET6_ADDRPORTSTRLEN; - ats_ip_nptop(qvc->get_remote_addr(), reinterpret_cast(key), key_len); + ats_ip_nptop(qc->five_tuple().source(), reinterpret_cast(key), key_len); unsigned int dst_len = 0; HMAC(EVP_sha1(), stateless_cookie_secret, STATELESS_COOKIE_SECRET_LENGTH, key, key_len, cookie, &dst_len); diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 077e26d6332..c4064b56ea9 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -175,3 +175,40 @@ QUICError::code() { return static_cast(this->trans_error_code); } + +// +// QUICFiveTuple +// +QUICFiveTuple::QUICFiveTuple(IpEndpoint src, IpEndpoint dst, int protocol) : _source(src), _destination(dst), _protocol(protocol) +{ + // FIXME Generate a hash code + this->_hash_code = src.port() + dst.port() + protocol; +} +void +QUICFiveTuple::update(IpEndpoint src, IpEndpoint dst, int protocol) +{ + this->_source = src; + this->_destination = dst; + this->_protocol = protocol; + + // FIXME Generate a hash code + this->_hash_code = src.port() + dst.port() + protocol; +} + +IpEndpoint +QUICFiveTuple::source() const +{ + return this->_source; +} + +IpEndpoint +QUICFiveTuple::destination() const +{ + return this->_destination; +} + +int +QUICFiveTuple::protocol() const +{ + return this->_protocol; +} diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 2b4814d7d23..6f77ad1a82e 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -31,6 +31,7 @@ #include #include "ts/INK_MD5.h" #include "ts/ink_memory.h" +#include "ts/ink_inet.h" // These magical defines should be removed when we implement seriously #define MAGIC_NUMBER_0 0 @@ -254,6 +255,23 @@ enum class QUICStreamType : uint8_t { HANDSHAKE, }; +class QUICFiveTuple +{ +public: + QUICFiveTuple(){}; + QUICFiveTuple(IpEndpoint src, IpEndpoint dst, int protocol); + void update(IpEndpoint src, IpEndpoint dst, int protocol); + IpEndpoint source() const; + IpEndpoint destination() const; + int protocol() const; + +private: + IpEndpoint _source; + IpEndpoint _destination; + int _protocol; + uint64_t _hash_code = 0; +}; + class QUICTypeUtil { public: From 63bb874a887c99340951111302f2d1db6ef60d1f Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 21 Mar 2018 17:06:38 +0800 Subject: [PATCH 0447/1313] QUIC: Fix complier error --- proxy/hq/HQFrame.cc | 2 +- proxy/hq/HQTypes.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/proxy/hq/HQFrame.cc b/proxy/hq/HQFrame.cc index e92a7c12d44..f34ac78d84e 100644 --- a/proxy/hq/HQFrame.cc +++ b/proxy/hq/HQFrame.cc @@ -251,7 +251,7 @@ HQFrameFactory::create(const uint8_t *buf, size_t len) return HQFrameUPtr(frame, &HQFrameDeleter::delete_data_frame); default: // Unknown frame - Debug("hq_frame_factory", "Unknown frame type %hhx", type); + Debug("hq_frame_factory", "Unknown frame type %hhx", static_cast(type)); frame = hqFrameAllocator.alloc(); new (frame) HQFrame(buf, len); return HQFrameUPtr(frame, &HQFrameDeleter::delete_frame); diff --git a/proxy/hq/HQTypes.h b/proxy/hq/HQTypes.h index 3676d229ba3..5a94007124e 100644 --- a/proxy/hq/HQTypes.h +++ b/proxy/hq/HQTypes.h @@ -23,6 +23,10 @@ #pragma once +#include "ts/ink_platform.h" + +#include + // Update HQFrame::type(const uint8_t *) too when you modify this list enum class HQFrameType : uint8_t { DATA = 0x00, From 17a22bf0d8452b5be926b0888496571c45e6baf6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 22 Mar 2018 09:35:45 +0900 Subject: [PATCH 0448/1313] Do not allow early data when stateless retry is enabled The operator must dicide calling SSLStateless() or SSL_read_early_data(), because these are incompatible. For now, if `proxy.config.quic.stateless_retry` is enabled, 0-RTT is disabled. This could be changed if SSL_accept() support cookie ext. --- iocore/net/quic/QUICTLS.cc | 45 ++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 07939b104fd..1b77b7cc436 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -79,32 +79,10 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint ERR_clear_error(); int ret = 0; if (this->_netvc_context == NET_VCONNECTION_IN) { - // process early data - if (!this->_early_data_processed) { - if (this->_read_early_data()) { - this->_early_data_processed = true; - } - - if (SSL_get_early_data_status(this->_ssl) == SSL_EARLY_DATA_ACCEPTED) { - Debug(tag, "Early data processed"); - - if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT)) { - this->_generate_0rtt_key(); - } - } - } - - // process stateless retry - if (this->_stateless && SSL_get_early_data_status(this->_ssl) != SSL_EARLY_DATA_ACCEPTED) { - // start over - // TODO: make sure no memory leaks - rbio = BIO_new(BIO_s_mem()); - wbio = BIO_new(BIO_s_mem()); - if (in != nullptr || in_len != 0) { - BIO_write(rbio, in, in_len); - } - SSL_set_bio(this->_ssl, rbio, wbio); - + // If stateless is enabled, TS should not allow early data, these are incompatible. + // Details in https://github.com/openssl/openssl/issues/5235 + if (this->_stateless) { + // process stateless retry ret = SSL_stateless(this->_ssl); if (ret > 0) { this->_stateless = false; @@ -113,6 +91,21 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint this->_msg_type = QUICHandshakeMsgType::HRR; } } else { + // process early data + if (!this->_early_data_processed) { + if (this->_read_early_data()) { + this->_early_data_processed = true; + } + + if (SSL_get_early_data_status(this->_ssl) == SSL_EARLY_DATA_ACCEPTED) { + Debug(tag, "Early data processed"); + + if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT)) { + this->_generate_0rtt_key(); + } + } + } + ret = SSL_accept(this->_ssl); this->_msg_type = QUICHandshakeMsgType::SH; } From 72c9c4abad2b0b9a7ce6b4173390ca129da2f34c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 22 Mar 2018 10:20:51 +0900 Subject: [PATCH 0449/1313] Rename handshake msg types --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICHandshake.cc | 2 +- iocore/net/quic/QUICTLS.cc | 13 ++++++++++--- iocore/net/quic/QUICTypes.h | 15 +++++++-------- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 32b45a2219c..d5b60d31bd5 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -560,7 +560,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) case QUIC_EVENT_PACKET_WRITE_READY: { this->_close_packet_write_ready(data); - if (this->_handshake_handler && this->_handshake_handler->msg_type() == QUICHandshakeMsgType::HRR) { + if (this->_handshake_handler && this->_handshake_handler->msg_type() == QUICHandshakeMsgType::RETRY) { error = this->_state_handshake_send_retry_packet(); if (this->_handshake_handler->is_stateless_retry_enabled()) { this->_switch_to_close_state(); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 42b79f18f42..cc21f5a476f 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -525,7 +525,7 @@ QUICHandshake::_process_client_hello() switch (result) { case SSL_ERROR_NONE: case SSL_ERROR_WANT_READ: { - if (this->_hs_protocol->msg_type() == QUICHandshakeMsgType::HRR) { + if (this->_hs_protocol->msg_type() == QUICHandshakeMsgType::RETRY) { // TODO: Send HRR on Retry Packet directly stream_io->write_reenable(); } else { diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 1b77b7cc436..ec2434588a1 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -86,9 +86,9 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint ret = SSL_stateless(this->_ssl); if (ret > 0) { this->_stateless = false; - this->_msg_type = QUICHandshakeMsgType::SH; + this->_msg_type = QUICHandshakeMsgType::HANDSHAKE; } else if (ret == 0) { - this->_msg_type = QUICHandshakeMsgType::HRR; + this->_msg_type = QUICHandshakeMsgType::RETRY; } } else { // process early data @@ -107,10 +107,17 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint } ret = SSL_accept(this->_ssl); - this->_msg_type = QUICHandshakeMsgType::SH; + this->_msg_type = QUICHandshakeMsgType::HANDSHAKE; } } else { ret = SSL_connect(this->_ssl); + + // FIXME: if SSL_get_state work well on server side, use this for distinction of HANDSHAKE and RERTY + if (SSL_get_state(this->_ssl) == TLS_ST_CW_CLNT_HELLO) { + this->_msg_type = QUICHandshakeMsgType::INITIAL; + } else { + this->_msg_type = QUICHandshakeMsgType::HANDSHAKE; + } } if (ret < 0) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 6f77ad1a82e..78b9a01c742 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -51,6 +51,13 @@ constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { }; constexpr QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; +enum class QUICHandshakeMsgType { + NONE = 0, + INITIAL, + RETRY, + HANDSHAKE, +}; + // Devide to QUICPacketType and QUICPacketLongHeaderType ? enum class QUICPacketType : uint8_t { VERSION_NEGOTIATION = 0, @@ -137,14 +144,6 @@ enum class QUICTransErrorCode : uint16_t { TLS_FATAL_ALERT_RECEIVED, }; -enum class QUICHandshakeMsgType { - NONE = 0, - CH, - SH, - HRR, - FN, -}; - // Application Protocol Error Codes defined in application using QUICAppErrorCode = uint16_t; constexpr uint16_t QUIC_APP_ERROR_CODE_STOPPING = 0; From f3cceb579ca3049da4a47efb7e551d38f8444824 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 22 Mar 2018 16:27:49 +0900 Subject: [PATCH 0450/1313] Handle ACK block legnth and gap as ranges This fixes #3314 --- iocore/net/quic/QUICFrame.cc | 34 +++++++++++++++++++ iocore/net/quic/QUICFrame.h | 20 +++++++++++ iocore/net/quic/QUICLossDetector.cc | 32 ++++++++--------- iocore/net/quic/QUICLossDetector.h | 2 +- iocore/net/quic/test/test_QUICLossDetector.cc | 18 ++++++++++ 5 files changed, 89 insertions(+), 17 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index bb12bedccb6..5663d7c276b 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -473,6 +473,40 @@ QUICAckFrame::_get_ack_block_section_offset() const return this->_get_ack_block_count_offset() + this->_get_ack_block_count_length(); } +// +// QUICAckFrame::PacketNumberRange +// +QUICAckFrame::PacketNumberRange::PacketNumberRange(PacketNumberRange &&a) noexcept +{ + this->_first = a._first; + this->_last = a._last; +} + +uint64_t +QUICAckFrame::PacketNumberRange::first() const +{ + return this->_first; +} + +uint64_t +QUICAckFrame::PacketNumberRange::last() const +{ + return this->_last; +} + +uint64_t +QUICAckFrame::PacketNumberRange::size() const +{ + return this->_first - this->_last; +} + +bool +QUICAckFrame::PacketNumberRange::contains(QUICPacketNumber x) const +{ + return static_cast(this->_last) <= static_cast(x) && + static_cast(x) <= static_cast(this->_first); +} + // // QUICAckFrame::AckBlock // diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 6d2044e8d7a..fb4729dbaa2 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -98,6 +98,26 @@ class QUICStreamFrame : public QUICFrame class QUICAckFrame : public QUICFrame { public: + class PacketNumberRange + { + public: + PacketNumberRange(QUICPacketNumber first, QUICPacketNumber last) : _first(first), _last(last) {} + PacketNumberRange(PacketNumberRange &&a) noexcept; + QUICPacketNumber first() const; + QUICPacketNumber last() const; + uint64_t size() const; + bool contains(QUICPacketNumber x) const; + bool + operator<(const PacketNumberRange &b) const + { + return static_cast(this->first()) < static_cast(b.first()); + } + + private: + QUICPacketNumber _first; + QUICPacketNumber _last; + }; + class AckBlock { public: diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index a4f0bb2908b..68496000df0 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -178,10 +178,14 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); // Find all newly acked packets. - for (auto acked_packet_number : this->_determine_newly_acked_packets(*ack_frame)) { - auto pi = this->_sent_packets.find(acked_packet_number); - if (pi != this->_sent_packets.end()) { - this->_on_packet_acked(pi->first, pi->second->bytes); + for (auto &&range : this->_determine_newly_acked_packets(*ack_frame)) { + for (auto ite = this->_sent_packets.begin(); ite != this->_sent_packets.end(); /* no increment here*/) { + auto tmp_ite = ite; + tmp_ite++; + if (range.contains(ite->first)) { + this->_on_packet_acked(ite->first, ite->second->bytes); + } + ite = tmp_ite; } } @@ -439,24 +443,20 @@ QUICLossDetector::_retransmit_lost_packet(const QUICPacket &packet) this->_transmitter->retransmit_packet(packet); } -std::set +std::set QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame) { - std::set packets; + std::set numbers; QUICPacketNumber x = ack_frame.largest_acknowledged(); - for (uint64_t i = 0; i <= ack_frame.ack_block_section()->first_ack_block_length(); ++i) { - packets.insert(x--); - } + numbers.insert({x, static_cast(x) - ack_frame.ack_block_section()->first_ack_block_length()}); + x -= ack_frame.ack_block_section()->first_ack_block_length() + 1; for (auto &&block : *(ack_frame.ack_block_section())) { - for (uint64_t i = 0; i <= block.gap(); ++i) { - x--; - } - for (uint64_t i = 0; i <= block.length(); ++i) { - packets.insert(x--); - } + x -= block.gap() + 1; + numbers.insert({x, static_cast(x) - block.length()}); + x -= block.length() + 1; } - return packets; + return numbers; } void diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 924f2217392..861e426b9e3 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -129,7 +129,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _on_loss_detection_alarm(); void _retransmit_lost_packet(const QUICPacket &packet); - std::set _determine_newly_acked_packets(const QUICAckFrame &ack_frame); + std::set _determine_newly_acked_packets(const QUICAckFrame &ack_frame); void _retransmit_handshake_packets(); void _send_one_packet(); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 3fbfbb39d81..a5d8cdbd93d 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -26,6 +26,7 @@ #include "QUICLossDetector.h" #include "QUICEvents.h" #include "Mock.h" +#include "ts/ink_hrtime.h" TEST_CASE("QUICLossDetector_Loss", "[quic]") { @@ -153,3 +154,20 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") CHECK(cc->lost_packets.find(pn9) == cc->lost_packets.end()); } } + +TEST_CASE("QUICLossDetector_HugeGap", "[quic]") +{ + MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); + MockQUICCongestionController *cc = new MockQUICCongestionController(); + QUICLossDetector detector(tx, cc); + + // Check initial state + CHECK(tx->retransmitted.size() == 0); + + auto t1 = Thread::get_hrtime(); + std::shared_ptr ack = QUICFrameFactory::create_ack_frame(100000000, 100, 10000000); + ack->ack_block_section()->add_ack_block({20000000, 30000000}); + detector.handle_frame(ack); + auto t2 = Thread::get_hrtime(); + CHECK(t2 - t1 < HRTIME_MSECONDS(100)); +} From f17041180f4452031cb85cfd10958f9752ed1c7a Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 23 Mar 2018 10:07:45 +0800 Subject: [PATCH 0451/1313] QUIC: Memory pollution in building packet --- iocore/net/QUICNetVConnection.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index d5b60d31bd5..1c3af539866 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1006,6 +1006,7 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans this->_transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, previous_packet_type)); retransmittable = false; len = 0; + buf = nullptr; } retransmittable = retransmittable || (frame->type() != QUICFrameType::ACK && frame->type() != QUICFrameType::PADDING); From bef6fbad1085423d4b1a1b4228fea4f2e62a1a2e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 23 Mar 2018 09:29:43 +0900 Subject: [PATCH 0452/1313] Don't ack protected packets with a handshake packet --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 22 ++--- iocore/net/quic/QUICAckFrameCreator.cc | 21 +++-- iocore/net/quic/QUICAckFrameCreator.h | 5 +- iocore/net/quic/QUICFrame.cc | 65 ++++++++++----- iocore/net/quic/QUICFrame.h | 94 +++++++++++++--------- iocore/net/quic/QUICIncomingFrameBuffer.cc | 2 +- iocore/net/quic/QUICStream.cc | 3 +- 8 files changed, 140 insertions(+), 74 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 0cca49db88a..270992607e0 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -289,7 +289,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type = QUICPacketType::UNINITIALIZED); - QUICErrorUPtr _recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_numm); + QUICErrorUPtr _recv_and_ack(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_initial_client_packet(QUICPacketUPtr packet); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 1c3af539866..a361c3bb721 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -819,7 +819,7 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPt // Start handshake QUICErrorUPtr error = this->_handshake_handler->start(packet.get(), &this->_packet_factory); if (this->_handshake_handler->is_version_negotiated()) { - error = this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); + error = this->_recv_and_ack(std::move(packet)); } else { // Perhaps response packets for initial client packet were lost, but no need to start handshake again because loss detector will // retransmit the packets. @@ -830,20 +830,20 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPt QUICErrorUPtr QUICNetVConnection::_state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet) { - return this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); + return this->_recv_and_ack(std::move(packet)); } QUICErrorUPtr QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet) { this->_start_application(); - return this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); + return this->_recv_and_ack(std::move(packet)); } QUICErrorUPtr QUICNetVConnection::_state_connection_established_process_packet(QUICPacketUPtr packet) { - return this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); + return this->_recv_and_ack(std::move(packet)); } QUICErrorUPtr @@ -906,7 +906,7 @@ QUICNetVConnection::_state_connection_closing_and_draining_receive_packet() QUICPacketCreationResult result; QUICPacketUPtr packet = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::SUCCESS) { - this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number()); + this->_recv_and_ack(std::move(packet)); this->_schedule_packet_write_ready(); } @@ -995,8 +995,7 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans QUICRetransmissionFrame *rf = dynamic_cast(frame.get()); if (rf) { current_packet_type = rf->packet_type(); - } else if (frame->type() == QUICFrameType::STREAM && - static_cast(frame.get())->stream_id() != STREAM_ID_FOR_HANDSHAKE) { + } else if (frame->is_protected()) { current_packet_type = QUICPacketType::PROTECTED; } else { current_packet_type = QUICPacketType::UNINITIALIZED; @@ -1101,8 +1100,12 @@ QUICNetVConnection::_packetize_frames() } QUICErrorUPtr -QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_num) +QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) { + const uint8_t *payload = packet->payload(); + uint16_t size = packet->payload_size(); + QUICPacketNumber packet_num = packet->packet_number(); + if (packet_num > this->_largest_received_packet_number) { this->_largest_received_packet_number = packet_num; } @@ -1123,7 +1126,8 @@ QUICNetVConnection::_recv_and_ack(const uint8_t *payload, uint16_t size, QUICPac return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } - this->_ack_frame_creator.update(packet_num, should_send_ack); + bool protection = packet->type() == QUICPacketType::PROTECTED || packet->type() == QUICPacketType::ZERO_RTT_PROTECTED; + this->_ack_frame_creator.update(packet_num, protection, should_send_ack); static_cast(this)->transmit_frame(); return error; diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 9c81166c36a..ab9de24258e 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -26,7 +26,7 @@ #include int -QUICAckFrameCreator::update(QUICPacketNumber packet_number, bool should_send) +QUICAckFrameCreator::update(QUICPacketNumber packet_number, bool protection, bool should_send) { if (this->_packet_numbers.size() == MAXIMUM_PACKET_COUNT) { return -1; @@ -34,6 +34,10 @@ QUICAckFrameCreator::update(QUICPacketNumber packet_number, bool should_send) this->_packet_numbers.push_back(packet_number); + if (!protection) { + this->_unprotected_packets.insert(packet_number); + } + if (!this->_can_send) { this->_can_send = true; } @@ -54,6 +58,7 @@ QUICAckFrameCreator::create() this->_should_send = false; this->_packet_count = 0; this->_packet_numbers.clear(); + this->_unprotected_packets.clear(); } return ack_frame; } @@ -85,8 +90,14 @@ QUICAckFrameCreator::_create_ack_frame() size_t i = 0; uint8_t gap = 0; uint64_t length = 0; + bool protection = false; while (i < this->_packet_numbers.size()) { + if (!protection) { + if (this->_unprotected_packets.find(last_ack_number) == this->_unprotected_packets.end()) { + protection = true; + } + } if (this->_packet_numbers[i] == last_ack_number) { last_ack_number--; length++; @@ -95,10 +106,10 @@ QUICAckFrameCreator::_create_ack_frame() } if (ack_frame) { - ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); + ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}, protection); } else { uint64_t delay = this->_calculate_delay(); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, protection); } gap = last_ack_number - this->_packet_numbers[i]; @@ -107,10 +118,10 @@ QUICAckFrameCreator::_create_ack_frame() } if (ack_frame) { - ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); + ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}, protection); } else { uint64_t delay = this->_calculate_delay(); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, protection); } return ack_frame; } diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 5a8e7995b4f..088d574f3f3 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -26,6 +26,8 @@ #include "ts/ink_hrtime.h" #include "QUICTypes.h" #include "QUICFrame.h" +#include +#include class QUICAckPacketNumbers { @@ -59,7 +61,7 @@ class QUICAckFrameCreator * All packet numbers ATS received need to be passed to this method. * Returns 0 if updated successfully. */ - int update(QUICPacketNumber packet_number, bool should_send); + int update(QUICPacketNumber packet_number, bool protection, bool should_send); /* * Returns QUICAckFrame only if ACK frame is able to be sent. @@ -80,6 +82,7 @@ class QUICAckFrameCreator QUICAckPacketNumbers _packet_numbers; uint16_t _packet_count = 0; + std::set _unprotected_packets; void _sort_packet_numbers(); std::unique_ptr _create_ack_frame(); diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 5663d7c276b..2e4bc1dadeb 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -70,11 +70,19 @@ QUICFrame::reset(const uint8_t *buf, size_t len) this->_len = len; } +bool +QUICFrame::is_protected() const +{ + return this->_protection; +} + // // STREAM Frame // -QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last) +QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, + bool protection) + : QUICFrame(protection) { this->_data = std::move(data); this->_data_len = data_len; @@ -309,12 +317,14 @@ QUICStreamFrame::_get_length_field_len() const // ACK frame // -QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) +QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len, bool protection) : QUICFrame(buf, len, protection) { this->reset(buf, len); } -QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block_length) +QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block_length, + bool protection) + : QUICFrame(protection) { this->_largest_acknowledged = largest_acknowledged; this->_ack_delay = ack_delay; @@ -373,6 +383,12 @@ QUICAckFrame::store(uint8_t *buf, size_t *len) const return; } +bool +QUICAckFrame::is_protected() const +{ + return QUICFrame::is_protected() || this->_ack_block_section->has_protected(); +} + QUICPacketNumber QUICAckFrame::largest_acknowledged() const { @@ -619,9 +635,16 @@ QUICAckFrame::AckBlockSection::first_ack_block_length() const } void -QUICAckFrame::AckBlockSection::add_ack_block(AckBlock block) +QUICAckFrame::AckBlockSection::add_ack_block(AckBlock block, bool protection) { this->_ack_blocks.push_back(block); + this->_protection |= protection; +} + +bool +QUICAckFrame::AckBlockSection::has_protected() const +{ + return this->_protection; } QUICAckFrame::AckBlockSection::const_iterator @@ -715,8 +738,9 @@ QUICAckFrame::AckBlockSection::const_iterator::operator==(const const_iterator & // RST_STREAM frame // -QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset) - : _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset) +QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, + bool protection) + : QUICFrame(protection), _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset) { } @@ -904,7 +928,8 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len) const // CONNECTION_CLOSE frame // QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint64_t reason_phrase_length, - const char *reason_phrase) + const char *reason_phrase, bool protection) + : QUICFrame(protection) { this->_error_code = error_code; this->_reason_phrase_length = reason_phrase_length; @@ -1004,7 +1029,8 @@ QUICConnectionCloseFrame::_get_reason_phrase_field_offset() const // APPLICATION_CLOSE frame // QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, - const char *reason_phrase) + const char *reason_phrase, bool protection) + : QUICFrame(protection) { this->_error_code = error_code; this->_reason_phrase_length = reason_phrase_length; @@ -1103,7 +1129,7 @@ QUICApplicationCloseFrame::_get_reason_phrase_field_offset() const // // MAX_DATA frame // -QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data) +QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, bool protection) { this->_maximum_data = maximum_data; } @@ -1161,7 +1187,8 @@ QUICMaxDataFrame::_get_max_data_field_length() const // // MAX_STREAM_DATA // -QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data) +QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, bool protection) + : QUICFrame(protection) { this->_stream_id = stream_id; this->_maximum_stream_data = maximum_stream_data; @@ -1254,7 +1281,7 @@ QUICMaxStreamDataFrame::_get_max_stream_data_field_length() const // // MAX_STREAM_ID // -QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id) +QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, bool protection) : QUICFrame(protection) { this->_maximum_stream_id = maximum_stream_id; } @@ -1586,8 +1613,8 @@ QUICNewConnectionIdFrame::_get_connection_id_field_offset() const // STOP_SENDING frame // -QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code) - : _stream_id(stream_id), _error_code(error_code) +QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, bool protection) + : QUICFrame(protection), _stream_id(stream_id), _error_code(error_code) { } @@ -1719,7 +1746,7 @@ QUICPongFrame::_data_offset() const // QUICRetransmissionFrame // QUICRetransmissionFrame::QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet) - : QUICFrame(), _packet_type(original_packet.type()) + : QUICFrame(original_frame->is_protected()), _packet_type(original_packet.type()) { size_t dummy; this->_size = original_frame->size(); @@ -1862,21 +1889,23 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) } QUICStreamFrameUPtr -QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last) +QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, + bool protection) { ats_unique_buf buf = ats_unique_malloc(data_len); memcpy(buf.get(), data, data_len); QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last); + new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last, protection); return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); } std::unique_ptr -QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block_length) +QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block_length, + bool protection) { QUICAckFrame *frame = quicAckFrameAllocator.alloc(); - new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block_length); + new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block_length, protection); return std::unique_ptr(frame, &QUICFrameDeleter::delete_ack_frame); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index fb4729dbaa2..d2ef572a91d 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -34,19 +34,24 @@ class QUICFrame { public: - QUICFrame(const uint8_t *buf, size_t len) : _buf(buf), _len(len){}; + QUICFrame(const uint8_t *buf, size_t len, bool protection) : _buf(buf), _len(len), _protection(protection) {} + QUICFrame(bool protection) : _protection(protection) {} + virtual ~QUICFrame() {} + + static QUICFrameType type(const uint8_t *buf); + virtual QUICFrameType type() const; virtual size_t size() const = 0; virtual void store(uint8_t *buf, size_t *len) const = 0; virtual void reset(const uint8_t *buf, size_t len); - static QUICFrameType type(const uint8_t *buf); - virtual ~QUICFrame() {} + virtual bool is_protected() const; LINK(QUICFrame, link); protected: QUICFrame() {} const uint8_t *_buf = nullptr; size_t _len = 0; + bool _protection = true; }; // @@ -57,8 +62,9 @@ class QUICStreamFrame : public QUICFrame { public: QUICStreamFrame() : QUICFrame() {} - QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false); + QUICStreamFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false, + bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -168,9 +174,10 @@ class QUICAckFrame : public QUICFrame size_t size() const; void store(uint8_t *buf, size_t *len) const; uint64_t first_ack_block_length() const; - void add_ack_block(const AckBlock block); + void add_ack_block(const AckBlock block, bool protection = true); const_iterator begin() const; const_iterator end() const; + bool has_protected() const; private: size_t _get_first_ack_block_length_size() const; @@ -179,17 +186,19 @@ class QUICAckFrame : public QUICFrame uint64_t _first_ack_block_length = 0; uint8_t _ack_block_count = 0; std::vector _ack_blocks; + bool _protection = false; }; QUICAckFrame() : QUICFrame() {} - QUICAckFrame(const uint8_t *buf, size_t len); - QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block_length); + QUICAckFrame(const uint8_t *buf, size_t len, bool protection = true); + QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block_length, bool protection = true); virtual ~QUICAckFrame(); virtual void reset(const uint8_t *buf, size_t len) override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; + bool is_protected() const override; QUICPacketNumber largest_acknowledged() const; uint64_t ack_delay() const; @@ -219,8 +228,8 @@ class QUICRstStreamFrame : public QUICFrame { public: QUICRstStreamFrame() : QUICFrame() {} - QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset); + QUICRstStreamFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -250,8 +259,11 @@ class QUICPingFrame : public QUICFrame { public: QUICPingFrame() : QUICFrame() {} - QUICPingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICPingFrame(ats_unique_buf data, size_t data_len) : _data(std::move(data)), _data_len(data_len) {} + QUICPingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICPingFrame(ats_unique_buf data, size_t data_len, bool protection = true) + : QUICFrame(protection), _data(std::move(data)), _data_len(data_len) + { + } virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -273,7 +285,7 @@ class QUICPaddingFrame : public QUICFrame { public: QUICPaddingFrame() : QUICFrame() {} - QUICPaddingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICPaddingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -287,8 +299,9 @@ class QUICConnectionCloseFrame : public QUICFrame { public: QUICConnectionCloseFrame() : QUICFrame() {} - QUICConnectionCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase); + QUICConnectionCloseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase, + bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -314,8 +327,9 @@ class QUICApplicationCloseFrame : public QUICFrame { public: QUICApplicationCloseFrame() : QUICFrame() {} - QUICApplicationCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase); + QUICApplicationCloseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase, + bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -341,8 +355,8 @@ class QUICMaxDataFrame : public QUICFrame { public: QUICMaxDataFrame() : QUICFrame() {} - QUICMaxDataFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICMaxDataFrame(uint64_t maximum_data); + QUICMaxDataFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICMaxDataFrame(uint64_t maximum_data, bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -362,8 +376,8 @@ class QUICMaxStreamDataFrame : public QUICFrame { public: QUICMaxStreamDataFrame() : QUICFrame() {} - QUICMaxStreamDataFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data); + QUICMaxStreamDataFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -388,8 +402,8 @@ class QUICMaxStreamIdFrame : public QUICFrame { public: QUICMaxStreamIdFrame() : QUICFrame() {} - QUICMaxStreamIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id); + QUICMaxStreamIdFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -408,8 +422,8 @@ class QUICBlockedFrame : public QUICFrame { public: QUICBlockedFrame() : QUICFrame() {} - QUICBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICBlockedFrame(QUICOffset offset) : _offset(offset){}; + QUICBlockedFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICBlockedFrame(QUICOffset offset, bool protection = true) : QUICFrame(protection), _offset(offset){}; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -431,8 +445,8 @@ class QUICStreamBlockedFrame : public QUICFrame { public: QUICStreamBlockedFrame() : QUICFrame() {} - QUICStreamBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o) : _stream_id(s), _offset(o){}; + QUICStreamBlockedFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o, bool protection = true) : QUICFrame(protection), _stream_id(s), _offset(o){}; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -457,8 +471,8 @@ class QUICStreamIdBlockedFrame : public QUICFrame { public: QUICStreamIdBlockedFrame() : QUICFrame() {} - QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamIdBlockedFrame(QUICStreamId s) : _stream_id(s) {} + QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICStreamIdBlockedFrame(QUICStreamId s, bool protection = true) : QUICFrame(protection), _stream_id(s) {} virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -480,9 +494,9 @@ class QUICNewConnectionIdFrame : public QUICFrame { public: QUICNewConnectionIdFrame() : QUICFrame() {} - QUICNewConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId id, QUICStatelessResetToken token) - : _sequence(seq), _connection_id(id), _stateless_reset_token(token){}; + QUICNewConnectionIdFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId id, QUICStatelessResetToken token, bool protection = true) + : QUICFrame(protection), _sequence(seq), _connection_id(id), _stateless_reset_token(token){}; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -509,8 +523,8 @@ class QUICStopSendingFrame : public QUICFrame { public: QUICStopSendingFrame() : QUICFrame() {} - QUICStopSendingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code); + QUICStopSendingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -539,8 +553,11 @@ class QUICPongFrame : public QUICFrame { public: QUICPongFrame() : QUICFrame() {} - QUICPongFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICPongFrame(ats_unique_buf data, size_t data_len) : _data(std::move(data)), _data_len(data_len) {} + QUICPongFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICPongFrame(ats_unique_buf data, size_t data_len, bool protection = true) + : QUICFrame(protection), _data(std::move(data)), _data_len(data_len) + { + } virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -753,14 +770,15 @@ class QUICFrameFactory * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ static QUICStreamFrameUPtr create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, - bool last = false); + bool last = false, bool protection = true); /* * Creates a ACK frame. * You shouldn't call this directly but through QUICAckFrameCreator because QUICAckFrameCreator manages packet numbers that we * need to ack. */ static std::unique_ptr create_ack_frame(QUICPacketNumber largest_acknowledged, - uint64_t ack_delay, uint64_t first_ack_block_length); + uint64_t ack_delay, uint64_t first_ack_block_length, + bool protection = true); /* * Creates a CONNECTION_CLOSE frame. */ diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index a00d6d78581..f2cea29d5ae 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -101,7 +101,7 @@ std::shared_ptr QUICIncomingFrameBuffer::_clone(std::shared_ptr frame) { return QUICFrameFactory::create_stream_frame(frame->data(), frame->data_length(), frame->stream_id(), frame->offset(), - frame->has_fin_flag()); + frame->has_fin_flag(), frame->is_protected()); } QUICErrorUPtr diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 195ed4c34ad..f82c81ad5be 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -476,8 +476,9 @@ QUICStream::_process_write_vio() } } + bool protection = this->_id != STREAM_ID_FOR_HANDSHAKE; QUICStreamFrameUPtr frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, - this->_id, this->_send_offset, fin); + this->_id, this->_send_offset, fin, protection); if (!this->_state.is_allowed_to_send(*frame)) { QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); break; From dc7577a4151361ddfa4b3db595712ad2100b866b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 23 Mar 2018 12:22:57 +0900 Subject: [PATCH 0453/1313] clang-format --- iocore/net/QUICNetVConnection.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a361c3bb721..73b31f6e857 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1102,8 +1102,8 @@ QUICNetVConnection::_packetize_frames() QUICErrorUPtr QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) { - const uint8_t *payload = packet->payload(); - uint16_t size = packet->payload_size(); + const uint8_t *payload = packet->payload(); + uint16_t size = packet->payload_size(); QUICPacketNumber packet_num = packet->packet_number(); if (packet_num > this->_largest_received_packet_number) { From d268ad432abff4379c158afd5db1b761ae688ee3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 23 Mar 2018 14:01:12 +0900 Subject: [PATCH 0454/1313] Add reset api to QUICLossDetector, QUICStreamManager and QUICStream for handling RETRY packet --- iocore/net/quic/QUICLossDetector.cc | 14 ++++++++++++++ iocore/net/quic/QUICLossDetector.h | 1 + iocore/net/quic/QUICStream.cc | 19 +++++++++++++++++++ iocore/net/quic/QUICStream.h | 2 ++ iocore/net/quic/QUICStreamManager.cc | 16 ++++++++++++++++ iocore/net/quic/QUICStreamManager.h | 2 ++ 6 files changed, 54 insertions(+) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 68496000df0..e9bbd3dc686 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -139,6 +139,20 @@ QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) this->_on_packet_sent(packet_number, is_ack_only, is_handshake, sent_bytes, std::move(packet)); } +void +QUICLossDetector::reset() +{ + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); + if (this->_loss_detection_alarm) { + this->_loss_detection_alarm->cancel(); + } + + this->_sent_packets.clear(); + + this->_handshake_outstanding = 0; + this->_retransmittable_outstanding = 0; +} + void QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes, QUICPacketUPtr packet) diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 861e426b9e3..d6b1262f614 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -76,6 +76,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler virtual QUICErrorUPtr handle_frame(std::shared_ptr) override; void on_packet_sent(QUICPacketUPtr packet); QUICPacketNumber largest_acked_packet_number(); + void reset(); private: Ptr _loss_detection_mutex; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index f82c81ad5be..fb69e587e97 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -360,6 +360,25 @@ QUICStream::recv(const std::shared_ptr frame) return QUICErrorUPtr(new QUICNoError()); } +/** + * Reset send/recv offset of stream. This is only for stream 0. + */ +void +QUICStream::reset_send_offset() +{ + if (this->_id == STREAM_ID_FOR_HANDSHAKE) { + this->_send_offset = 0; + } +} + +void +QUICStream::reset_recv_offset() +{ + if (this->_id == STREAM_ID_FOR_HANDSHAKE) { + this->_received_stream_frame_buffer.clear(); + } +} + /** * Replace existing event only if the new event is different than the inprogress event */ diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index e7e9879819c..b139d4e826b 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -63,6 +63,8 @@ class QUICStream : public VConnection QUICStreamId id() const; QUICOffset final_offset(); + void reset_send_offset(); + void reset_recv_offset(); // Implement VConnection Interface. VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index ecc12c29358..8c96a9c593a 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -297,3 +297,19 @@ QUICStreamManager::set_default_application(QUICApplication *app) { this->_app_map->set_default(app); } + +void +QUICStreamManager::reset_send_offset() +{ + QUICStream *stream = this->_find_stream(STREAM_ID_FOR_HANDSHAKE); + + stream->reset_send_offset(); +} + +void +QUICStreamManager::reset_recv_offset() +{ + QUICStream *stream = this->_find_stream(STREAM_ID_FOR_HANDSHAKE); + + stream->reset_recv_offset(); +} diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 37375b4952d..44b823b1d60 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -51,6 +51,8 @@ class QUICStreamManager : public QUICFrameHandler QUICErrorUPtr create_stream(QUICStreamId stream_id); void set_default_application(QUICApplication *app); + void reset_send_offset(); + void reset_recv_offset(); DLL stream_list; From 7cb0796781a075c9585fed9355cda9b92f61c69e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 26 Mar 2018 11:04:46 +0900 Subject: [PATCH 0455/1313] Handle RETRY packet on client side --- iocore/net/P_QUICNetVConnection.h | 3 ++ iocore/net/QUICNetVConnection.cc | 69 ++++++++++++++++++++++++------- iocore/net/quic/QUICPacket.cc | 15 +++++++ 3 files changed, 72 insertions(+), 15 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 270992607e0..83bef51596f 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -108,6 +108,7 @@ class SSLNextProtocolSet; * | READ: * | _state_handshake_process_packet() * | _state_handshake_process_initial_client_packet() + * | _state_handshake_process_retry_packet() * | _state_handshake_process_client_cleartext_packet() * | _state_handshake_process_zero_rtt_protected_packet() * | WRITE: @@ -223,6 +224,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICStatelessResetToken token; }; + QUICPacketType _last_received_packet_type = QUICPacketType::UNINITIALIZED; std::random_device _rnd; QUICConnectionId _original_quic_connection_id; @@ -293,6 +295,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICErrorUPtr _state_handshake_process_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_initial_client_packet(QUICPacketUPtr packet); + QUICErrorUPtr _state_handshake_process_retry_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_connection_established_process_packet(QUICPacketUPtr packet); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 73b31f6e857..8e22c803447 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -79,6 +79,7 @@ QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, this->_ctable->insert(this->_quic_connection_id, this); this->_ctable->insert(this->_original_quic_connection_id, this); } + QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(this->_original_quic_connection_id), static_cast(this->_quic_connection_id)); } @@ -566,6 +567,16 @@ QUICNetVConnection::state_handshake(int event, Event *data) this->_switch_to_close_state(); } } else { + if (this->get_context() == NET_VCONNECTION_OUT && (this->_last_received_packet_type == QUICPacketType::UNINITIALIZED || + this->_last_received_packet_type == QUICPacketType::RETRY)) { + QUICConnectionId tmp = this->_original_quic_connection_id; + this->_original_quic_connection_id.randomize(); + QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(tmp), + static_cast(this->_original_quic_connection_id)); + + this->_hs_protocol->initialize_key_materials(this->_original_quic_connection_id); + } + error = this->_state_common_send_packet(); } @@ -794,6 +805,9 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) case QUICPacketType::INITIAL: error = this->_state_handshake_process_initial_client_packet(std::move(packet)); break; + case QUICPacketType::RETRY: + error = this->_state_handshake_process_retry_packet(std::move(packet)); + break; case QUICPacketType::HANDSHAKE: error = this->_state_handshake_process_client_cleartext_packet(std::move(packet)); break; @@ -821,12 +835,29 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPt if (this->_handshake_handler->is_version_negotiated()) { error = this->_recv_and_ack(std::move(packet)); } else { - // Perhaps response packets for initial client packet were lost, but no need to start handshake again because loss detector will + // Perhaps response packets for initial client packet were lost, but no need to start handshake again because loss detector + // will // retransmit the packets. } return error; } +QUICErrorUPtr +QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) +{ + // discard all transport state + this->_stream_manager->reset_send_offset(); + this->_loss_detector->reset(); + + QUICErrorUPtr error = this->_recv_and_ack(std::move(packet)); + + // Packet number of RETRY packet is echo of INITIAL packet + this->_largest_received_packet_number = 0; + this->_stream_manager->reset_recv_offset(); + + return error; +} + QUICErrorUPtr QUICNetVConnection::_state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet) { @@ -1119,6 +1150,10 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) return error; } + if (packet->type() == QUICPacketType::RETRY) { + should_send_ack = false; + } + int ret = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); @@ -1138,11 +1173,25 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi { QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); + // TODO: support NET_VCONNECTION_IN + if (this->get_context() == NET_VCONNECTION_OUT && type == QUICPacketType::UNINITIALIZED) { + if (this->_handshake_handler && this->_handshake_handler->is_completed()) { + type = QUICPacketType::PROTECTED; + } else if (this->_last_received_packet_type == QUICPacketType::UNINITIALIZED || + this->_last_received_packet_type == QUICPacketType::RETRY) { + type = QUICPacketType::INITIAL; + } else if (_last_received_packet_type == QUICPacketType::HANDSHAKE) { + type = QUICPacketType::HANDSHAKE; + } + } + switch (type) { case QUICPacketType::INITIAL: ink_assert(this->get_context() == NET_VCONNECTION_OUT); packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->largest_acked_packet_number(), QUIC_SUPPORTED_VERSIONS[0], std::move(buf), len); + this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); + break; case QUICPacketType::RETRY: // Echo "_largest_received_packet_number" as packet number. Probably this is the packet number from triggering client packet. @@ -1152,26 +1201,15 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi case QUICPacketType::HANDSHAKE: packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); + this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); + break; case QUICPacketType::PROTECTED: packet = this->_packet_factory.create_server_protected_packet(this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); break; default: - if (this->get_context() == NET_VCONNECTION_OUT) { - if (this->_handshake_handler->handler == reinterpret_cast(&QUICHandshake::state_initial)) { - packet = this->_packet_factory.create_initial_packet( - this->_original_quic_connection_id, this->largest_acked_packet_number(), QUIC_SUPPORTED_VERSIONS[0], std::move(buf), len); - this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); - } else if (this->_handshake_handler->handler == reinterpret_cast(&QUICHandshake::state_key_exchange)) { - packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), - std::move(buf), len, retransmittable); - this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); - } else { - packet = this->_packet_factory.create_server_protected_packet( - this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); - } - } else { + if (this->get_context() == NET_VCONNECTION_IN) { if (this->_handshake_handler && this->_handshake_handler->is_completed()) { packet = this->_packet_factory.create_server_protected_packet( this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); @@ -1283,6 +1321,7 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) case QUICPacketCreationResult::SUCCESS: QUICConDebug("Dequeue %s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), quic_packet->packet_number(), quic_packet->size()); + this->_last_received_packet_type = quic_packet->type(); break; default: QUICConDebug("Failed to decrypt the packet"); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 2d5932ad034..66ed12c42d2 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -711,6 +711,21 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ result = QUICPacketCreationResult::IGNORED; } break; + case QUICPacketType::RETRY: + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::CLEARTEXT)) { + if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + QUICKeyPhase::CLEARTEXT)) { + result = QUICPacketCreationResult::SUCCESS; + } else { + // ignore failure - probably clear text key is already updated + // FIXME: make sure packet number is smaller than largest sent packet number + result = QUICPacketCreationResult::IGNORED; + } + } else { + result = QUICPacketCreationResult::IGNORED; + } + break; case QUICPacketType::HANDSHAKE: if (this->_hs_protocol->is_key_derived(QUICKeyPhase::CLEARTEXT)) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), From 9946719bddddd3be87f78740fbb03a993817fad6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 26 Mar 2018 15:00:42 +0900 Subject: [PATCH 0456/1313] Fix QUICAckFrameCreator::update() calling in unit tests --- .../net/quic/test/test_QUICAckFrameCreator.cc | 30 +++++++++---------- iocore/net/quic/test/test_QUICLossDetector.cc | 12 ++++---- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 6153460c424..9002d6e73d2 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -36,7 +36,7 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame == nullptr); // One packet - creator.update(1, true); + creator.update(1, false, true); frame = creator.create(); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -47,10 +47,10 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame == nullptr); // Not sequential - creator.update(2, true); - creator.update(5, true); - creator.update(3, true); - creator.update(4, true); + creator.update(2, false, true); + creator.update(5, false, true); + creator.update(3, false, true); + creator.update(4, false, true); frame = creator.create(); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -58,9 +58,9 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame->ack_block_section()->first_ack_block_length() == 3); // Loss - creator.update(6, true); - creator.update(7, true); - creator.update(10, true); + creator.update(6, false, true); + creator.update(7, false, true); + creator.update(10, false, true); frame = creator.create(); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); @@ -78,11 +78,11 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") frame = creator.create(); CHECK(frame == nullptr); - creator.update(2, true); - creator.update(5, true); - creator.update(6, true); - creator.update(8, true); - creator.update(9, true); + creator.update(2, false, true); + creator.update(5, false, true); + creator.update(6, false, true); + creator.update(8, false, true); + creator.update(9, false, true); frame = creator.create(); CHECK(frame != nullptr); @@ -94,8 +94,8 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") frame = creator.create(); CHECK(frame == nullptr); - creator.update(7, true); - creator.update(4, true); + creator.update(7, false, true); + creator.update(4, false, true); frame = creator.create(); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index a5d8cdbd93d..d777ba96f8c 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -130,12 +130,12 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") ink_hrtime_sleep(HRTIME_MSECONDS(1000)); // Receive an ACK for (1) (4) (5) (7) (8) (9) - afc->update(pn1, true); - afc->update(pn4, true); - afc->update(pn5, true); - afc->update(pn7, true); - afc->update(pn8, true); - afc->update(pn9, true); + afc->update(pn1, false, true); + afc->update(pn4, false, true); + afc->update(pn5, false, true); + afc->update(pn7, false, true); + afc->update(pn8, false, true); + afc->update(pn9, false, true); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); frame = afc->create(); detector.handle_frame(frame); From bd09c194af798c32306923bb637e4a0def946002 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 26 Mar 2018 12:46:03 +0900 Subject: [PATCH 0457/1313] Separate SSL_CTX for client and server As for client, add SSL_CTX* to QUICConfig, just like SSLConfig has SSL_CTX *client_ctx. As for server, add SSL_CTX* to QUICConfig too for now. Probably this should be integrated with SSLCertLookup or SNIConfigParams. --- iocore/net/P_QUICNetProcessor.h | 2 - iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/P_QUICPacketHandler.h | 3 +- iocore/net/QUICNetProcessor.cc | 45 +---------------- iocore/net/QUICNetVConnection.cc | 9 ++-- iocore/net/QUICPacketHandler.cc | 8 +-- iocore/net/quic/QUICConfig.cc | 83 +++++++++++++++++++++++++++++++ iocore/net/quic/QUICConfig.h | 13 +++++ 8 files changed, 110 insertions(+), 55 deletions(-) diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h index c9d6c2adfb5..59fb931dafc 100644 --- a/iocore/net/P_QUICNetProcessor.h +++ b/iocore/net/P_QUICNetProcessor.h @@ -73,8 +73,6 @@ class QUICNetProcessor : public UnixNetProcessor private: QUICNetProcessor(const QUICNetProcessor &); QUICNetProcessor &operator=(const QUICNetProcessor &); - - SSL_CTX *_ssl_ctx = nullptr; }; extern QUICNetProcessor quic_NetProcessor; diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 83bef51596f..ba4a65779eb 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -165,7 +165,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection int state_connection_closing(int event, Event *data); int state_connection_draining(int event, Event *data); int state_connection_closed(int event, Event *data); - void start(SSL_CTX *); + void start(); void free(EThread *t) override; void destroy(EThread *t); diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 886ce707fdf..8ffd36a696e 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -59,7 +59,7 @@ class QUICPacketHandler class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler { public: - QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, SSL_CTX *); + QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt); ~QUICPacketHandlerIn(); // NetAccept @@ -75,7 +75,6 @@ class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler void _recv_packet(int event, UDPPacket *udp_packet) override; QUICConnectionTable *_ctable = nullptr; - SSL_CTX *_ssl_ctx; }; /* diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 55c7b10be85..94d6fb6e7ce 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -27,8 +27,6 @@ #include "QUICGlobals.h" #include "QUICConfig.h" -#include "QUICTransportParameters.h" -#include "QUICStatelessRetry.h" // // Global Data @@ -48,7 +46,6 @@ QUICNetProcessor::~QUICNetProcessor() void QUICNetProcessor::cleanup() { - SSL_CTX_free(this->_ssl_ctx); } void @@ -68,55 +65,17 @@ QUICNetProcessor::start(int, size_t stacksize) // This initialization order matters ... // QUICInitializeLibrary(); QUICConfig::startup(); - QUICStatelessRetry::init(); - -#ifdef TLS1_3_VERSION_DRAFT_TXT - // FIXME: remove this when TLS1_3_VERSION_DRAFT_TXT is removed - Debug("quic_ps", "%s", TLS1_3_VERSION_DRAFT_TXT); -#endif - - // Acquire a QUICConfigParams instance *after* we start QUIC up. - // QUICConfig::scoped_config params; // Initialize QUIC statistics. This depends on an initial set of certificates being loaded above. // QUICInitializeStatistics(); - // TODO: separate SSL_CTX for client and server - // TODO: load certs from SSLConfig - this->_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(this->_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(this->_ssl_ctx, TLS1_3_VERSION); - - // FIXME: OpenSSL (1.1.1-alpha) enable this option by default. But this shoule be removed when OpenSSL disable this by default. - SSL_CTX_clear_options(this->_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - - SSL_CTX_set_alpn_select_cb(this->_ssl_ctx, QUIC::ssl_select_next_protocol, nullptr); - SSL_CTX_set_max_early_data(this->_ssl_ctx, UINT32_C(0xFFFFFFFF)); - SSL_CTX_add_custom_ext(this->_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); - - // callbacks for cookie ext - // Requires OpenSSL-1.1.1-pre3+ : https://github.com/openssl/openssl/pull/5463 - SSL_CTX_set_stateless_cookie_generate_cb(this->_ssl_ctx, QUICStatelessRetry::generate_cookie); - SSL_CTX_set_stateless_cookie_verify_cb(this->_ssl_ctx, QUICStatelessRetry::verify_cookie); - - SSLConfig::scoped_config params; - SSLParseCertificateConfiguration(params, this->_ssl_ctx); - - if (SSL_CTX_check_private_key(this->_ssl_ctx) != 1) { - Error("check private key failed"); - // ink_assert(false); - } - return 0; } NetAccept * QUICNetProcessor::createNetAccept(const NetProcessor::AcceptOptions &opt) { - return (NetAccept *)new QUICPacketHandlerIn(opt, this->_ssl_ctx); + return (NetAccept *)new QUICPacketHandlerIn(opt); } NetVConnection * @@ -195,7 +154,7 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne SET_CONTINUATION_HANDLER(vc, &QUICNetVConnection::startEvent); - vc->start(this->_ssl_ctx); + vc->start(); if (t->is_event_type(opt->etype)) { MUTEX_TRY_LOCK(lock, cont->mutex, t); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8e22c803447..cc8e72b9271 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -174,16 +174,17 @@ QUICNetVConnection::startEvent(int event, Event *e) // XXX This might be called on ET_UDP thread void -QUICNetVConnection::start(SSL_CTX *ssl_ctx) +QUICNetVConnection::start() { + QUICConfig::scoped_config params; + this->_five_tuple.update(this->local_addr, this->remote_addr, SOCK_DGRAM); // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not if (this->direction() == NET_VCONNECTION_IN) { - QUICConfig::scoped_config params; this->_reset_token.generate(this->_quic_connection_id, params->server_id()); - this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_reset_token, params->stateless_retry()); + this->_handshake_handler = new QUICHandshake(this, params->server_ssl_ctx(), this->_reset_token, params->stateless_retry()); } else { - this->_handshake_handler = new QUICHandshake(this, ssl_ctx); + this->_handshake_handler = new QUICHandshake(this, params->client_ssl_ctx()); this->_handshake_handler->start(&this->_packet_factory); } this->_application_map = new QUICApplicationMap(); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 256100514e3..5bbb4a5dcf8 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -23,6 +23,8 @@ #include "P_Net.h" #include "P_QUICClosedConCollector.h" + +#include "QUICGlobals.h" #include "QUICConfig.h" #include "QUICPacket.h" #include "QUICDebugNames.h" @@ -88,7 +90,7 @@ QUICPacketHandler::_read_connection_id(IOBufferBlock *block) // // QUICPacketHandlerIn // -QUICPacketHandlerIn::QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, SSL_CTX *ctx) : NetAccept(opt), _ssl_ctx(ctx) +QUICPacketHandlerIn::QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt) : NetAccept(opt) { this->mutex = new_ProxyMutex(); // create Connection Table @@ -112,7 +114,7 @@ NetAccept * QUICPacketHandlerIn::clone() const { NetAccept *na; - na = new QUICPacketHandlerIn(opt, this->_ssl_ctx); + na = new QUICPacketHandlerIn(opt); *na = *this; return na; } @@ -218,7 +220,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) vc->action_ = *this->action_; vc->set_is_transparent(this->opt.f_inbound_transparent); vc->set_context(NET_VCONNECTION_IN); - vc->start(this->_ssl_ctx); + vc->start(); vc->options.ip_proto = NetVCOptions::USE_UDP; vc->options.ip_family = udp_packet->from.sa.sa_family; diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 0b8c00c7eb2..f440d59cff5 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -23,14 +23,80 @@ #include "QUICConfig.h" +#include #include +#include "P_SSLConfig.h" + +#include "QUICGlobals.h" +#include "QUICTransportParameters.h" +#include "QUICStatelessRetry.h" + int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; +static SSL_CTX * +quic_new_ssl_ctx() +{ +#ifdef TLS1_3_VERSION_DRAFT_TXT + // FIXME: remove this when TLS1_3_VERSION_DRAFT_TXT is removed + Debug("quic_ps", "%s", TLS1_3_VERSION_DRAFT_TXT); +#endif + + SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); + + SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION); + + // FIXME: OpenSSL (1.1.1-alpha) enable this option by default. But this shoule be removed when OpenSSL disable this by default. + SSL_CTX_clear_options(ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + + 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); + return ssl_ctx; +} + +static SSL_CTX * +quic_init_server_ssl_ctx(SSL_CTX *ssl_ctx) +{ + SSLConfig::scoped_config ssl_params; + SSLParseCertificateConfiguration(ssl_params, ssl_ctx); + + if (SSL_CTX_check_private_key(ssl_ctx) != 1) { + Error("check private key failed"); + } + + // callbacks for cookie ext + // Requires OpenSSL-1.1.1-pre3+ : https://github.com/openssl/openssl/pull/5463 + SSL_CTX_set_stateless_cookie_generate_cb(ssl_ctx, QUICStatelessRetry::generate_cookie); + SSL_CTX_set_stateless_cookie_verify_cb(ssl_ctx, QUICStatelessRetry::verify_cookie); + + SSL_CTX_set_alpn_select_cb(ssl_ctx, QUIC::ssl_select_next_protocol, nullptr); + + return ssl_ctx; +} + +static SSL_CTX * +quic_init_client_ssl_ctx(SSL_CTX *ssl_ctx) +{ + // SSL_CTX_set_alpn_protos() + + return ssl_ctx; +} + // // QUICConfigParams // +QUICConfigParams::~QUICConfigParams() +{ + SSL_CTX_free(this->_server_ssl_ctx); + SSL_CTX_free(this->_client_ssl_ctx); +}; + void QUICConfigParams::initialize() { @@ -41,6 +107,11 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); REC_EstablishStaticConfigInt32(this->_connection_table_size, "proxy.config.quic.connection_table.size"); REC_EstablishStaticConfigInt32U(this->_stateless_retry, "proxy.config.quic.stateless_retry"); + + QUICStatelessRetry::init(); + + this->_server_ssl_ctx = quic_init_server_ssl_ctx(quic_new_ssl_ctx()); + this->_client_ssl_ctx = quic_init_client_ssl_ctx(quic_new_ssl_ctx()); } uint32_t @@ -109,6 +180,18 @@ QUICConfigParams::initial_max_stream_id_uni_out() const return this->_initial_max_stream_id_uni_out; } +SSL_CTX * +QUICConfigParams::server_ssl_ctx() const +{ + return this->_server_ssl_ctx; +} + +SSL_CTX * +QUICConfigParams::client_ssl_ctx() const +{ + return this->_client_ssl_ctx; +} + // // QUICConfig // diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 4ae77212db9..43bac32578d 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -23,10 +23,16 @@ #pragma once +#include + #include "ProxyConfig.h" + class QUICConfigParams : public ConfigInfo { public: + QUICConfigParams(){}; + ~QUICConfigParams(); + void initialize(); uint32_t no_activity_timeout_in() const; @@ -41,6 +47,9 @@ class QUICConfigParams : public ConfigInfo static int connection_table_size(); uint32_t stateless_retry() const; + SSL_CTX *server_ssl_ctx() const; + SSL_CTX *client_ssl_ctx() const; + private: // FIXME Fill appropriate default values in RecordsConfig.cc uint32_t _no_activity_timeout_in = 0; @@ -55,6 +64,10 @@ class QUICConfigParams : public ConfigInfo uint32_t _initial_max_stream_id_bidi_out = 101; uint32_t _initial_max_stream_id_uni_in = 102; uint32_t _initial_max_stream_id_uni_out = 103; + + // TODO: integrate with SSLCertLookup or SNIConfigParams + SSL_CTX *_server_ssl_ctx = nullptr; + SSL_CTX *_client_ssl_ctx = nullptr; }; class QUICConfig From 2389503983f52fc0914d473489e768596eb51321 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 26 Mar 2018 14:45:11 +0900 Subject: [PATCH 0458/1313] Add suported_group configs --- iocore/net/QUICNetProcessor.cc | 6 +++-- iocore/net/quic/QUICConfig.cc | 46 +++++++++++++++++++++++++++------- iocore/net/quic/QUICConfig.h | 5 ++++ mgmt/RecordsConfig.cc | 4 +++ 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 94d6fb6e7ce..e580a623b94 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -66,8 +66,10 @@ QUICNetProcessor::start(int, size_t stacksize) // QUICInitializeLibrary(); QUICConfig::startup(); - // Initialize QUIC statistics. This depends on an initial set of certificates being loaded above. - // QUICInitializeStatistics(); +#ifdef TLS1_3_VERSION_DRAFT_TXT + // FIXME: remove this when TLS1_3_VERSION_DRAFT_TXT is removed + Debug("quic_ps", "%s", TLS1_3_VERSION_DRAFT_TXT); +#endif return 0; } diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index f440d59cff5..84d8e9ee2d5 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -38,11 +38,6 @@ int QUICConfigParams::_connection_table_size = 65521; static SSL_CTX * quic_new_ssl_ctx() { -#ifdef TLS1_3_VERSION_DRAFT_TXT - // FIXME: remove this when TLS1_3_VERSION_DRAFT_TXT is removed - Debug("quic_ps", "%s", TLS1_3_VERSION_DRAFT_TXT); -#endif - SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); @@ -61,8 +56,10 @@ quic_new_ssl_ctx() } static SSL_CTX * -quic_init_server_ssl_ctx(SSL_CTX *ssl_ctx) +quic_init_server_ssl_ctx(const QUICConfigParams *params) { + SSL_CTX *ssl_ctx = quic_new_ssl_ctx(); + SSLConfig::scoped_config ssl_params; SSLParseCertificateConfiguration(ssl_params, ssl_ctx); @@ -77,14 +74,28 @@ quic_init_server_ssl_ctx(SSL_CTX *ssl_ctx) SSL_CTX_set_alpn_select_cb(ssl_ctx, QUIC::ssl_select_next_protocol, nullptr); + if (params->server_supported_groups() != nullptr) { + if (SSL_CTX_set1_groups_list(ssl_ctx, params->server_supported_groups()) != 1) { + Error("SSL_CTX_set1_groups_list failed"); + } + } + return ssl_ctx; } static SSL_CTX * -quic_init_client_ssl_ctx(SSL_CTX *ssl_ctx) +quic_init_client_ssl_ctx(const QUICConfigParams *params) { + SSL_CTX *ssl_ctx = quic_new_ssl_ctx(); + // SSL_CTX_set_alpn_protos() + if (params->client_supported_groups() != nullptr) { + if (SSL_CTX_set1_groups_list(ssl_ctx, params->client_supported_groups()) != 1) { + Error("SSL_CTX_set1_groups_list failed"); + } + } + return ssl_ctx; } @@ -93,6 +104,9 @@ quic_init_client_ssl_ctx(SSL_CTX *ssl_ctx) // QUICConfigParams::~QUICConfigParams() { + this->_server_supported_groups = (char *)ats_free_null(this->_server_supported_groups); + this->_client_supported_groups = (char *)ats_free_null(this->_client_supported_groups); + SSL_CTX_free(this->_server_ssl_ctx); SSL_CTX_free(this->_client_ssl_ctx); }; @@ -107,11 +121,13 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); REC_EstablishStaticConfigInt32(this->_connection_table_size, "proxy.config.quic.connection_table.size"); REC_EstablishStaticConfigInt32U(this->_stateless_retry, "proxy.config.quic.stateless_retry"); + REC_ReadConfigStringAlloc(this->_server_supported_groups, "proxy.config.quic.server.supported_groups"); + REC_ReadConfigStringAlloc(this->_client_supported_groups, "proxy.config.quic.client.supported_groups"); QUICStatelessRetry::init(); - this->_server_ssl_ctx = quic_init_server_ssl_ctx(quic_new_ssl_ctx()); - this->_client_ssl_ctx = quic_init_client_ssl_ctx(quic_new_ssl_ctx()); + this->_server_ssl_ctx = quic_init_server_ssl_ctx(this); + this->_client_ssl_ctx = quic_init_client_ssl_ctx(this); } uint32_t @@ -180,6 +196,18 @@ QUICConfigParams::initial_max_stream_id_uni_out() const return this->_initial_max_stream_id_uni_out; } +const char * +QUICConfigParams::server_supported_groups() const +{ + return this->_server_supported_groups; +} + +const char * +QUICConfigParams::client_supported_groups() const +{ + return this->_client_supported_groups; +} + SSL_CTX * QUICConfigParams::server_ssl_ctx() const { diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 43bac32578d..1fc1797ceaf 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -46,6 +46,8 @@ class QUICConfigParams : public ConfigInfo uint32_t server_id() const; static int connection_table_size(); uint32_t stateless_retry() const; + const char *server_supported_groups() const; + const char *client_supported_groups() const; SSL_CTX *server_ssl_ctx() const; SSL_CTX *client_ssl_ctx() const; @@ -65,6 +67,9 @@ class QUICConfigParams : public ConfigInfo uint32_t _initial_max_stream_id_uni_in = 102; uint32_t _initial_max_stream_id_uni_out = 103; + char *_server_supported_groups; + char *_client_supported_groups; + // TODO: integrate with SSLCertLookup or SNIConfigParams SSL_CTX *_server_ssl_ctx = nullptr; SSL_CTX *_client_ssl_ctx = nullptr; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 89df43c95e2..50328584068 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1330,6 +1330,10 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.stateless_retry", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.server.supported_groups", RECD_STRING, "P-256:X25519:P-384:P-521" , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.client.supported_groups", RECD_STRING, "P-256:X25519:P-384:P-521" , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} + , //# Add LOCAL Records Here {RECT_LOCAL, "proxy.local.incoming_ip_to_bind", RECD_STRING, nullptr, RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL} From d774873ebc8ed4edc51b822f78c4d7e1b1c87b4a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 26 Mar 2018 16:15:41 +0900 Subject: [PATCH 0459/1313] Fix unit tests --- iocore/net/quic/QUICStream.cc | 1 - iocore/net/quic/test/Makefile.am | 40 +++++++++++++------ iocore/net/quic/test/stub_QUICConfig.cc | 45 ++++++++++++++++++++++ iocore/net/quic/test/test_QUICHandshake.cc | 3 -- 4 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 iocore/net/quic/test/stub_QUICConfig.cc diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index fb69e587e97..9e78714450c 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -27,7 +27,6 @@ #include "P_VConnection.h" #include "QUICStreamManager.h" #include "QUICDebugNames.h" -#include "QUICConfig.h" #define QUICStreamDebug(fmt, ...) \ Debug("quic_stream", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index d8e6a099c2f..1c4b445cf5d 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -169,6 +169,7 @@ test_QUICFrameDispatcher_SOURCES = \ test_QUICFrameDispatcher.cc \ ../QUICGlobals.cc \ ../QUICConfig.cc \ + stub_QUICConfig.cc \ ../QUICVersionNegotiator.cc \ ../QUICFrameDispatcher.cc \ ../QUICTransportParameters.cc \ @@ -198,6 +199,7 @@ test_QUICFrameDispatcher_SOURCES = \ test_QUICFrameDispatcher_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/mgmt/libmgmt_p.la \ @@ -206,7 +208,6 @@ test_QUICFrameDispatcher_LDADD = \ @LIBTCL@ \ @HWLOC_LIBS@ - # # test_QUICStreamState # @@ -249,7 +250,8 @@ test_QUICStream_SOURCES = \ ../QUICStreamManager.cc \ ../QUICApplicationMap.cc \ ../QUICCongestionController.cc \ - ../../SSLNextProtocolSet.cc + ../../SSLNextProtocolSet.cc \ + stub_QUICConfig.cc test_QUICStream_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -280,7 +282,9 @@ test_QUICStreamManager_SOURCES = \ ../QUICStreamManager.cc \ ../QUICApplicationMap.cc \ ../QUICCongestionController.cc \ - ../../SSLNextProtocolSet.cc + ../../SSLNextProtocolSet.cc \ + ../QUICConfig.cc \ + stub_QUICConfig.cc test_QUICStreamManager_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -307,6 +311,7 @@ test_QUICTransportParameters_SOURCES = \ test_QUICTransportParameters.cc \ ../QUICGlobals.cc \ ../QUICConfig.cc \ + stub_QUICConfig.cc \ ../QUICApplication.cc \ ../QUICApplicationMap.cc \ ../QUICHandshake.cc \ @@ -332,6 +337,7 @@ test_QUICTransportParameters_SOURCES = \ test_QUICTransportParameters_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/mgmt/libmgmt_p.la \ @@ -345,8 +351,7 @@ test_QUICKeyGenerator_CPPFLAGS = \ $(AM_CPPFLAGS) test_QUICKeyGenerator_LDFLAGS = \ - @AM_LDFLAGS@ \ - @OPENSSL_LDFLAGS@ + @AM_LDFLAGS@ test_QUICKeyGenerator_LDADD = \ @OPENSSL_LIBS@ \ @@ -442,7 +447,9 @@ test_QUICLossDetector_SOURCES = \ ../QUICHandshakeProtocol.cc \ ../QUICTLS.cc \ $(QUICTLS_impl) \ - ../QUICFrame.cc + ../QUICFrame.cc \ + ../../SSLNextProtocolSet.cc \ + stub_QUICConfig.cc # # test_QUICTypeUtil @@ -455,10 +462,12 @@ test_QUICTypeUtil_LDFLAGS = \ test_QUICTypeUtil_LDADD = \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - $(top_builddir)/lib/ts/libtsutil.la + $(top_builddir)/lib/ts/libtsutil.la \ + @OPENSSL_LIBS@ test_QUICTypeUtil_SOURCES = \ main.cc \ @@ -477,7 +486,9 @@ test_QUICTypeUtil_SOURCES = \ ../QUICTLS.cc \ $(QUICTLS_impl) \ ../QUICIntUtil.cc \ - ../QUICTypes.cc + ../QUICTypes.cc \ + ../../SSLNextProtocolSet.cc \ + stub_QUICConfig.cc # # test_QUICAckFrameCreator @@ -490,6 +501,7 @@ test_QUICAckFrameCreator_LDFLAGS = \ test_QUICAckFrameCreator_LDADD = \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ @@ -515,7 +527,8 @@ test_QUICAckFrameCreator_SOURCES = \ ../QUICHandshakeProtocol.cc \ ../QUICTLS.cc \ $(QUICTLS_impl) \ - ../../SSLNextProtocolSet.cc + ../../SSLNextProtocolSet.cc \ + stub_QUICConfig.cc # # test_QUICTypeUtil @@ -529,6 +542,7 @@ test_QUICVersionNegotiator_LDFLAGS = \ test_QUICVersionNegotiator_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -562,6 +576,7 @@ test_QUICVersionNegotiator_SOURCES = \ ../QUICVersionNegotiator.cc \ ../QUICTransportParameters.cc \ ../QUICConfig.cc \ + stub_QUICConfig.cc \ ../../SSLNextProtocolSet.cc # @@ -576,6 +591,7 @@ test_QUICFlowController_LDFLAGS = \ test_QUICFlowController_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -620,7 +636,8 @@ test_QUICIncomingFrameBuffer_SOURCES = \ ../QUICCongestionController.cc \ ../../SSLNextProtocolSet.cc \ ../QUICIncomingFrameBuffer.cc \ - test_QUICIncomingFrameBuffer.cc + test_QUICIncomingFrameBuffer.cc \ + stub_QUICConfig.cc test_QUICIncomingFrameBuffer_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -646,7 +663,8 @@ test_QUICHandshake_SOURCES = \ event_processor_main.cc \ test_QUICHandshake.cc \ ../QUICHandshake.cc \ - ../../SSLNextProtocolSet.cc + ../../SSLNextProtocolSet.cc \ + stub_QUICConfig.cc test_QUICHandshake_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ diff --git a/iocore/net/quic/test/stub_QUICConfig.cc b/iocore/net/quic/test/stub_QUICConfig.cc new file mode 100644 index 00000000000..22f7f81309c --- /dev/null +++ b/iocore/net/quic/test/stub_QUICConfig.cc @@ -0,0 +1,45 @@ +/** @file + * + * Stubs for QUICConfig + * + * @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 "ts/ink_assert.h" + +#include "P_SSLConfig.h" + +bool +SSLParseCertificateConfiguration(const SSLConfigParams *, SSL_CTX *) +{ + ink_assert(false); + return false; +} + +SSLConfigParams * +SSLConfig::acquire() +{ + ink_assert(false); + return nullptr; +} + +void +SSLConfig::release(SSLConfigParams *) +{ + ink_assert(false); +} diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc index 8e8ad8d1728..30268d40c33 100644 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -25,14 +25,11 @@ #include "Mock.h" #include "QUICHandshake.h" -#include "QUICConfig.h" #include "./server_cert.h" TEST_CASE("1-RTT handshake ", "[quic]") { - QUICConfig::startup(); - // setup client QUICConnection *client_qc = new MockQUICConnection(NET_VCONNECTION_OUT); From b8cae7d470eb5cc0fc23017ed73f34112021cc4a Mon Sep 17 00:00:00 2001 From: scw00 Date: Sun, 25 Mar 2018 18:03:04 +0800 Subject: [PATCH 0460/1313] QUIC: Set packet_info's bytes to zero if it is the ack-only packet --- iocore/net/quic/QUICLossDetector.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index e9bbd3dc686..33d109734b6 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -135,7 +135,7 @@ QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) QUICPacketNumber packet_number = packet->packet_number(); bool is_ack_only = !packet->is_retransmittable(); - size_t sent_bytes = packet->size(); + size_t sent_bytes = is_ack_only ? 0 : packet->size(); this->_on_packet_sent(packet_number, is_ack_only, is_handshake, sent_bytes, std::move(packet)); } From 6183b8ef8f8ca5f502acffc834ac437db0b0568e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 27 Mar 2018 14:04:41 +0900 Subject: [PATCH 0461/1313] Re-randomize Connection ID only if TS received RETRY packet --- iocore/net/QUICNetVConnection.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index cc8e72b9271..ae53aa4bfe5 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -568,8 +568,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) this->_switch_to_close_state(); } } else { - if (this->get_context() == NET_VCONNECTION_OUT && (this->_last_received_packet_type == QUICPacketType::UNINITIALIZED || - this->_last_received_packet_type == QUICPacketType::RETRY)) { + if (this->get_context() == NET_VCONNECTION_OUT && (this->_last_received_packet_type == QUICPacketType::RETRY)) { QUICConnectionId tmp = this->_original_quic_connection_id; this->_original_quic_connection_id.randomize(); QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(tmp), From ae3c68d463fa9f8e4985ab999580f00f8cc6bad2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 22 Mar 2018 11:20:09 +0900 Subject: [PATCH 0462/1313] Refactoring QUICHandshake --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 14 +++ iocore/net/quic/QUICHandshake.cc | 200 ++++-------------------------- iocore/net/quic/QUICHandshake.h | 30 ++--- 4 files changed, 50 insertions(+), 195 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index ba4a65779eb..47144883df1 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -297,6 +297,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICErrorUPtr _state_handshake_process_initial_client_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_retry_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet); + QUICErrorUPtr _state_handshake_process_protected_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_connection_established_process_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_common_receive_packet(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ae53aa4bfe5..34286fae538 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -811,10 +811,16 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) case QUICPacketType::HANDSHAKE: error = this->_state_handshake_process_client_cleartext_packet(std::move(packet)); break; + case QUICPacketType::PROTECTED: + error = this->_state_handshake_process_protected_packet(std::move(packet)); + break; case QUICPacketType::ZERO_RTT_PROTECTED: error = this->_state_handshake_process_zero_rtt_protected_packet(std::move(packet)); break; + default: + QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(packet->type()), packet->type()); + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); break; } @@ -864,6 +870,12 @@ QUICNetVConnection::_state_handshake_process_client_cleartext_packet(QUICPacketU return this->_recv_and_ack(std::move(packet)); } +QUICErrorUPtr +QUICNetVConnection::_state_handshake_process_protected_packet(QUICPacketUPtr packet) +{ + return this->_recv_and_ack(std::move(packet)); +} + QUICErrorUPtr QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet) { @@ -922,6 +934,8 @@ QUICNetVConnection::_state_common_receive_packet() // FIXME Just ignore for now but it has to be acked (GitHub#2609) break; default: + QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(p->type()), p->type()); + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); break; } diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index cc21f5a476f..aec09076169 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -103,7 +103,11 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_hs_index, this); this->_hs_protocol->initialize_key_materials(this->_client_qc->original_connection_id()); - SET_HANDLER(&QUICHandshake::state_initial); + if (this->_netvc_context == NET_VCONNECTION_OUT) { + this->_initial = true; + } + + SET_HANDLER(&QUICHandshake::state_handshake); } QUICHandshake::~QUICHandshake() @@ -266,50 +270,7 @@ QUICHandshake::remote_transport_parameters() } int -QUICHandshake::state_initial(int event, Event *data) -{ - QUICHSDebug("%s (%d)", get_vc_event_name(event), event); - - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - switch (event) { - case QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE: { - QUICHSDebug("Enter state_key_exchange"); - SET_HANDLER(&QUICHandshake::state_key_exchange); - break; - } - case VC_EVENT_READ_READY: - case VC_EVENT_READ_COMPLETE: { - if (this->_netvc_context == NET_VCONNECTION_IN) { - error = this->_process_client_hello(); - } - break; - } - case VC_EVENT_WRITE_READY: - case VC_EVENT_WRITE_COMPLETE: { - if (this->_netvc_context == NET_VCONNECTION_OUT) { - error = this->_process_initial(); - } - break; - } - default: - break; - } - - if (error->cls != QUICErrorClass::NONE) { - QUICTransErrorCode code; - if (dynamic_cast(error.get()) != nullptr) { - code = error->trans_error_code; - } else { - code = QUICTransErrorCode::PROTOCOL_VIOLATION; - } - this->_abort_handshake(code); - } - - return EVENT_DONE; -} - -int -QUICHandshake::state_key_exchange(int event, Event *data) +QUICHandshake::state_handshake(int event, Event *data) { QUICHSDebug("%s (%d)", get_vc_event_name(event), event); @@ -322,44 +283,13 @@ QUICHandshake::state_key_exchange(int event, Event *data) this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); } } - break; } case VC_EVENT_READ_READY: - case VC_EVENT_READ_COMPLETE: { - ink_assert(this->_netvc_context == NET_VCONNECTION_OUT); - error = this->_process_server_hello(); - break; - } - default: - break; - } - - if (error->cls != QUICErrorClass::NONE) { - QUICTransErrorCode code; - if (dynamic_cast(error.get()) != nullptr) { - code = error->trans_error_code; - } else { - code = QUICTransErrorCode::PROTOCOL_VIOLATION; - } - this->_abort_handshake(code); - } - - return EVENT_DONE; -} - -int -QUICHandshake::state_auth(int event, Event *data) -{ - QUICHSDebug("%s (%d)", get_vc_event_name(event), event); - - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - switch (event) { - case VC_EVENT_READ_READY: - case VC_EVENT_READ_COMPLETE: { - ink_assert(this->_netvc_context == NET_VCONNECTION_IN); - - error = this->_process_finished(); + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + error = this->_process_handshake_msg(); break; } default: @@ -376,13 +306,6 @@ QUICHandshake::state_auth(int event, Event *data) this->_abort_handshake(code); } - return EVENT_CONT; -} - -int -QUICHandshake::state_address_validation(int event, void *data) -{ - // TODO Address validation should be implemented for the 2nd implementation draft return EVENT_DONE; } @@ -453,7 +376,7 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi } int -QUICHandshake::_do_handshake(bool initial) +QUICHandshake::_do_handshake(size_t &out_len) { // TODO: pass stream_io QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); @@ -461,7 +384,9 @@ QUICHandshake::_do_handshake(bool initial) uint8_t in[UDP_MAXIMUM_PAYLOAD_SIZE] = {0}; int64_t in_len = 0; - if (!initial) { + if (this->_initial) { + this->_initial = false; + } else { // Complete message should fit in a packet and be able to read in_len = stream_io->read_avail(); stream_io->read(in, in_len); @@ -474,7 +399,6 @@ QUICHandshake::_do_handshake(bool initial) } uint8_t out[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t out_len = 0; int result = this->_hs_protocol->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, in, in_len); if (out_len > 0) { @@ -495,104 +419,32 @@ QUICHandshake::_do_handshake(bool initial) } QUICErrorUPtr -QUICHandshake::_process_initial() +QUICHandshake::_process_handshake_msg() { QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); - int result = _do_handshake(true); - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - - switch (result) { - case SSL_ERROR_WANT_READ: { - stream_io->write_reenable(); - stream_io->read_reenable(); - - break; - } - default: - error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); - } - - return error; -} - -QUICErrorUPtr -QUICHandshake::_process_client_hello() -{ - QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); - int result = _do_handshake(); + size_t out_len = 0; + int result = this->_do_handshake(out_len); QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (result) { case SSL_ERROR_NONE: - case SSL_ERROR_WANT_READ: { - if (this->_hs_protocol->msg_type() == QUICHandshakeMsgType::RETRY) { - // TODO: Send HRR on Retry Packet directly - stream_io->write_reenable(); - } else { - QUICHSDebug("Enter state_auth"); - SET_HANDLER(&QUICHandshake::state_auth); - - stream_io->write_reenable(); - stream_io->read_reenable(); + if (this->_hs_protocol->is_handshake_finished()) { + int res = this->_complete_handshake(); + if (!res) { + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); + } } - - break; - } - default: - error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); - } - - return error; -} - -QUICErrorUPtr -QUICHandshake::_process_server_hello() -{ - QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); - int result = _do_handshake(); - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - - switch (result) { - case SSL_ERROR_NONE: { - stream_io->write_reenable(); - break; - } + // Fall-through case SSL_ERROR_WANT_READ: { - // FIXME: check if write_reenable should be called or not - stream_io->write_reenable(); - stream_io->read_reenable(); - break; - } - default: - error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); - } - - return error; -} - -QUICErrorUPtr -QUICHandshake::_process_finished() -{ - QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); - int result = _do_handshake(); - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - - switch (result) { - case SSL_ERROR_NONE: { - int res = this->_complete_handshake(); - if (res) { + if (out_len > 0) { stream_io->write_reenable(); - } else { - this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); } - - break; - } - case SSL_ERROR_WANT_READ: { stream_io->read_reenable(); + break; } default: + QUICHSDebug("Handshake failed: %d", result); error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); } diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 6ddae160316..2005041bc7f 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -32,19 +32,12 @@ * @brief Do handshake as a QUIC application * @detail * - * # client - * state_initial() + * state_handshake() + * | * v - * state_key_exchange() - * v - * state_complete() - * - * # server - * state_initial() - * v - * state_auth() - * v - * state_complete() + * state_complete() on success + * or + * state_closed() on error */ class QUICVersionNegotiator; class SSLNextProtocolSet; @@ -64,10 +57,7 @@ class QUICHandshake : public QUICApplication QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); // States - int state_initial(int event, Event *data); - int state_key_exchange(int event, Event *data); - int state_address_validation(int event, void *data); - int state_auth(int event, Event *data); + int state_handshake(int event, Event *data); int state_complete(int event, void *data); int state_closed(int event, void *data); @@ -99,17 +89,15 @@ class QUICHandshake : public QUICApplication QUICVersionNegotiator *_version_negotiator = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; QUICStatelessResetToken _reset_token; + bool _initial = false; bool _stateless_retry = false; void _load_local_server_transport_parameters(QUICVersion negotiated_version); void _load_local_client_transport_parameters(QUICVersion initial_version); - int _do_handshake(bool initial = false); + int _do_handshake(size_t &out_len); - QUICErrorUPtr _process_initial(); - QUICErrorUPtr _process_client_hello(); - QUICErrorUPtr _process_server_hello(); - QUICErrorUPtr _process_finished(); + QUICErrorUPtr _process_handshake_msg(); int _complete_handshake(); void _abort_handshake(QUICTransErrorCode code); From 4cb3a5bf56446d8b2dec7a0890af1cba09e3fc5d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 28 Mar 2018 11:13:58 +0900 Subject: [PATCH 0463/1313] Ignore INITIAL packet on state_connection_established Client might retransmit INITLA packet even if connection is established. This made crash on a assert in connection migration logic. Just ignore it for now. --- iocore/net/QUICNetVConnection.cc | 39 +++++++++++++++++--------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 34286fae538..2709454bb86 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -907,31 +907,34 @@ QUICNetVConnection::_state_common_receive_packet() continue; } - // Check connection migration - if (this->_handshake_handler->is_completed() && p->connection_id() != this->_quic_connection_id) { - for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { - AltConnectionInfo &info = this->_alt_quic_connection_ids[i]; - if (info.id == p->connection_id()) { - // Migrate connection - // TODO Address Validation - // TODO Adjust expected packet number with a gap computed based on info.seq_num - // TODO Unregister the old connection id (Should we wait for a while?) - this->_quic_connection_id = info.id; - this->_reset_token = info.token; - this->_update_alt_connection_ids(i); - break; - } - } - ink_assert(p->connection_id() == this->_quic_connection_id); - } - // Process the packet switch (p->type()) { case QUICPacketType::PROTECTED: + // Check connection migration + if (this->_handshake_handler->is_completed() && p->connection_id() != this->_quic_connection_id) { + for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { + AltConnectionInfo &info = this->_alt_quic_connection_ids[i]; + if (info.id == p->connection_id()) { + // Migrate connection + // TODO Address Validation + // TODO Adjust expected packet number with a gap computed based on info.seq_num + // TODO Unregister the old connection id (Should we wait for a while?) + this->_quic_connection_id = info.id; + this->_reset_token = info.token; + this->_update_alt_connection_ids(i); + break; + } + } + ink_assert(p->connection_id() == this->_quic_connection_id); + } + error = this->_state_connection_established_process_packet(std::move(p)); break; + case QUICPacketType::INITIAL: case QUICPacketType::HANDSHAKE: // FIXME Just ignore for now but it has to be acked (GitHub#2609) + QUICConDebug("Ignore %s packet", QUICDebugNames::packet_type(p->type())); + break; default: QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(p->type()), p->type()); From 152108180a294c91e5d31ec7b7e2918e90701faa Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 28 Mar 2018 11:24:33 +0900 Subject: [PATCH 0464/1313] Print ACK frame info in debug log --- iocore/net/quic/QUICLossDetector.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 33d109734b6..0142b754332 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -176,6 +176,11 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); + + QUICLDDebug("Largest Acknowledged: %" PRIu64, ack_frame->largest_acknowledged()); + QUICLDDebug("ACK Delay: %" PRIu64, ack_frame->ack_delay()); + QUICLDDebug("ACK Block Count: %" PRIu64, ack_frame->ack_block_count()); + this->_largest_acked_packet = ack_frame->largest_acknowledged(); // If the largest acked is newly acked, update the RTT. auto pi = this->_sent_packets.find(ack_frame->largest_acknowledged()); From 133e1082a5bb6e2b15ffee6a53ad572ef481987e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 28 Mar 2018 14:21:17 +0900 Subject: [PATCH 0465/1313] Fix packet type selection logic on client side --- iocore/net/QUICNetVConnection.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2709454bb86..a76aca81580 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1192,13 +1192,13 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi // TODO: support NET_VCONNECTION_IN if (this->get_context() == NET_VCONNECTION_OUT && type == QUICPacketType::UNINITIALIZED) { - if (this->_handshake_handler && this->_handshake_handler->is_completed()) { - type = QUICPacketType::PROTECTED; - } else if (this->_last_received_packet_type == QUICPacketType::UNINITIALIZED || - this->_last_received_packet_type == QUICPacketType::RETRY) { + if (this->_last_received_packet_type == QUICPacketType::UNINITIALIZED || + this->_last_received_packet_type == QUICPacketType::RETRY) { type = QUICPacketType::INITIAL; } else if (_last_received_packet_type == QUICPacketType::HANDSHAKE) { type = QUICPacketType::HANDSHAKE; + } else if (this->_handshake_handler && this->_handshake_handler->is_completed()) { + type = QUICPacketType::PROTECTED; } } From d59e78bb0f093a9d54497fb9228721e72e19bdd7 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 28 Mar 2018 14:22:03 +0900 Subject: [PATCH 0466/1313] Ignore PROTECTED packet on state_handshake --- iocore/net/P_QUICNetVConnection.h | 1 - iocore/net/QUICNetVConnection.cc | 13 ++----------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 47144883df1..ba4a65779eb 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -297,7 +297,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICErrorUPtr _state_handshake_process_initial_client_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_retry_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet); - QUICErrorUPtr _state_handshake_process_protected_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_connection_established_process_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_common_receive_packet(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a76aca81580..97a669000b9 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -811,15 +811,12 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) case QUICPacketType::HANDSHAKE: error = this->_state_handshake_process_client_cleartext_packet(std::move(packet)); break; - case QUICPacketType::PROTECTED: - error = this->_state_handshake_process_protected_packet(std::move(packet)); - break; case QUICPacketType::ZERO_RTT_PROTECTED: error = this->_state_handshake_process_zero_rtt_protected_packet(std::move(packet)); break; - + case QUICPacketType::PROTECTED: default: - QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(packet->type()), packet->type()); + QUICConDebug("Ignore %s(%" PRIu8 ") packet", QUICDebugNames::packet_type(packet->type()), packet->type()); error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); break; @@ -870,12 +867,6 @@ QUICNetVConnection::_state_handshake_process_client_cleartext_packet(QUICPacketU return this->_recv_and_ack(std::move(packet)); } -QUICErrorUPtr -QUICNetVConnection::_state_handshake_process_protected_packet(QUICPacketUPtr packet) -{ - return this->_recv_and_ack(std::move(packet)); -} - QUICErrorUPtr QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet) { From d11c84838637d5d08c37d45c19229fcd3c2d4367 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 28 Mar 2018 15:50:26 +0900 Subject: [PATCH 0467/1313] Send ack for discarded packets Pass discarded packet to QUICNetVConnection::_recv_and_ack() to send ack to the packet. Probably this is fine, because if the packet has some stream data to ignore, it will be discarded by offset mismatch. --- iocore/net/QUICNetVConnection.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 97a669000b9..2b06b960e81 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -838,9 +838,9 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPt if (this->_handshake_handler->is_version_negotiated()) { error = this->_recv_and_ack(std::move(packet)); } else { - // Perhaps response packets for initial client packet were lost, but no need to start handshake again because loss detector - // will - // retransmit the packets. + // Perhaps response packets for initial packet were lost. Pass packet to _recv_and_ack to send ack to the initial packet. + // Stream data will be discarded by offset mismatch. + error = this->_recv_and_ack(std::move(packet)); } return error; } @@ -923,9 +923,8 @@ QUICNetVConnection::_state_common_receive_packet() break; case QUICPacketType::INITIAL: case QUICPacketType::HANDSHAKE: - // FIXME Just ignore for now but it has to be acked (GitHub#2609) - QUICConDebug("Ignore %s packet", QUICDebugNames::packet_type(p->type())); - + // 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(std::move(p)); break; default: QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(p->type()), p->type()); From c341432576f220dfe01dccf8d727f517567ccc9d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 29 Mar 2018 09:12:00 +0900 Subject: [PATCH 0468/1313] Remove unused header inclusion --- iocore/net/QUICNetVConnection.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2b06b960e81..aa7b0c3f9d3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -25,13 +25,11 @@ #include "ts/ink_config.h" #include "ts/ink_std_compat.h" -#include "ts/EventNotify.h" #include "records/I_RecHttp.h" #include "ts/Diags.h" #include "P_Net.h" #include "InkAPIInternal.h" // Added to include the quic_hook definitions -#include "BIO_fastopen.h" #include "Log.h" #include "P_SSLNextProtocolSet.h" From 2ca74d875c4bb2dce21e7973cf1205a7b4dab8f9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 29 Mar 2018 09:32:55 +0900 Subject: [PATCH 0469/1313] Cancel scheduled loss_detection_alarm on destructor Fix test_QUICLossDetector crash. --- iocore/net/quic/QUICLossDetector.cc | 7 +++++++ iocore/net/quic/QUICLossDetector.h | 1 + 2 files changed, 8 insertions(+) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 0142b754332..22823deff39 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -59,6 +59,13 @@ QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConge SET_HANDLER(&QUICLossDetector::event_handler); } +QUICLossDetector::~QUICLossDetector() +{ + if (this->_loss_detection_alarm) { + this->_loss_detection_alarm->cancel(); + } +} + int QUICLossDetector::event_handler(int event, Event *edata) { diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index d6b1262f614..7a34d89255d 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -69,6 +69,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler { public: QUICLossDetector(QUICPacketTransmitter *transmitter, QUICCongestionController *cc); + ~QUICLossDetector(); int event_handler(int event, Event *edata); From c7a31b9bdf92e692183116b1e96da3937b535e60 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 29 Mar 2018 09:40:20 +0900 Subject: [PATCH 0470/1313] Print First ACK Block when ack received Also rename first_ack_block_length to first_ack_block because it's renamed by draft-08 --- iocore/net/quic/QUICFrame.cc | 23 +++++++++---------- iocore/net/quic/QUICFrame.h | 16 ++++++------- iocore/net/quic/QUICLossDetector.cc | 7 ++++-- .../net/quic/test/test_QUICAckFrameCreator.cc | 10 ++++---- iocore/net/quic/test/test_QUICFrame.cc | 4 ++-- 5 files changed, 31 insertions(+), 29 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 2e4bc1dadeb..c0d6fe60b71 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -322,13 +322,12 @@ QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len, bool protection) : QU this->reset(buf, len); } -QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block_length, - bool protection) +QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, bool protection) : QUICFrame(protection) { this->_largest_acknowledged = largest_acknowledged; this->_ack_delay = ack_delay; - this->_ack_block_section = new AckBlockSection(first_ack_block_length); + this->_ack_block_section = new AckBlockSection(first_ack_block); } QUICAckFrame::~QUICAckFrame() @@ -596,7 +595,7 @@ QUICAckFrame::AckBlockSection::size() const { size_t n = 0; - n += this->_get_first_ack_block_length_size(); + n += this->_get_first_ack_block_size(); for (auto &&block : *this) { n += block.size(); @@ -611,7 +610,7 @@ QUICAckFrame::AckBlockSection::store(uint8_t *buf, size_t *len) const size_t n; uint8_t *p = buf; - QUICIntUtil::write_QUICVariableInt(this->_first_ack_block_length, p, &n); + QUICIntUtil::write_QUICVariableInt(this->_first_ack_block, p, &n); p += n; for (auto &&block : *this) { @@ -625,12 +624,12 @@ QUICAckFrame::AckBlockSection::store(uint8_t *buf, size_t *len) const } uint64_t -QUICAckFrame::AckBlockSection::first_ack_block_length() const +QUICAckFrame::AckBlockSection::first_ack_block() const { if (this->_buf) { return QUICIntUtil::read_QUICVariableInt(this->_buf); } else { - return this->_first_ack_block_length; + return this->_first_ack_block; } } @@ -651,7 +650,7 @@ QUICAckFrame::AckBlockSection::const_iterator QUICAckFrame::AckBlockSection::begin() const { if (this->_buf) { - return const_iterator(0, this->_buf + this->_get_first_ack_block_length_size(), this->_ack_block_count); + return const_iterator(0, this->_buf + this->_get_first_ack_block_size(), this->_ack_block_count); } else { return const_iterator(0, &this->_ack_blocks); } @@ -668,12 +667,12 @@ QUICAckFrame::AckBlockSection::end() const } size_t -QUICAckFrame::AckBlockSection::_get_first_ack_block_length_size() const +QUICAckFrame::AckBlockSection::_get_first_ack_block_size() const { if (this->_buf) { return QUICVariableInt::size(this->_buf); } else { - return QUICVariableInt::size(this->_first_ack_block_length); + return QUICVariableInt::size(this->_first_ack_block); } } @@ -1901,11 +1900,11 @@ QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUIC } std::unique_ptr -QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block_length, +QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, bool protection) { QUICAckFrame *frame = quicAckFrameAllocator.alloc(); - new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block_length, protection); + new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block, protection); return std::unique_ptr(frame, &QUICFrameDeleter::delete_ack_frame); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index d2ef572a91d..5e21ef45027 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -168,30 +168,30 @@ class QUICAckFrame : public QUICFrame const std::vector *_ack_blocks = nullptr; }; - AckBlockSection(uint64_t first_ack_block_length) : _first_ack_block_length(first_ack_block_length) {} + AckBlockSection(uint64_t first_ack_block) : _first_ack_block(first_ack_block) {} AckBlockSection(const uint8_t *buf, uint8_t ack_block_count) : _buf(buf), _ack_block_count(ack_block_count) {} uint8_t count() const; size_t size() const; void store(uint8_t *buf, size_t *len) const; - uint64_t first_ack_block_length() const; + uint64_t first_ack_block() const; void add_ack_block(const AckBlock block, bool protection = true); const_iterator begin() const; const_iterator end() const; bool has_protected() const; private: - size_t _get_first_ack_block_length_size() const; + size_t _get_first_ack_block_size() const; - const uint8_t *_buf = nullptr; - uint64_t _first_ack_block_length = 0; - uint8_t _ack_block_count = 0; + const uint8_t *_buf = nullptr; + uint64_t _first_ack_block = 0; + uint8_t _ack_block_count = 0; std::vector _ack_blocks; bool _protection = false; }; QUICAckFrame() : QUICFrame() {} QUICAckFrame(const uint8_t *buf, size_t len, bool protection = true); - QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block_length, bool protection = true); + QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, bool protection = true); virtual ~QUICAckFrame(); virtual void reset(const uint8_t *buf, size_t len) override; @@ -777,7 +777,7 @@ class QUICFrameFactory * need to ack. */ static std::unique_ptr create_ack_frame(QUICPacketNumber largest_acknowledged, - uint64_t ack_delay, uint64_t first_ack_block_length, + uint64_t ack_delay, uint64_t first_ack_block, bool protection = true); /* * Creates a CONNECTION_CLOSE frame. diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 22823deff39..db182286ed6 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -187,6 +187,9 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac QUICLDDebug("Largest Acknowledged: %" PRIu64, ack_frame->largest_acknowledged()); QUICLDDebug("ACK Delay: %" PRIu64, ack_frame->ack_delay()); QUICLDDebug("ACK Block Count: %" PRIu64, ack_frame->ack_block_count()); + if (ack_frame->ack_block_section()) { + QUICLDDebug("First ACK Block: %" PRIu64, ack_frame->ack_block_section()->first_ack_block()); + } this->_largest_acked_packet = ack_frame->largest_acknowledged(); // If the largest acked is newly acked, update the RTT. @@ -474,8 +477,8 @@ QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame) { std::set numbers; QUICPacketNumber x = ack_frame.largest_acknowledged(); - numbers.insert({x, static_cast(x) - ack_frame.ack_block_section()->first_ack_block_length()}); - x -= ack_frame.ack_block_section()->first_ack_block_length() + 1; + numbers.insert({x, static_cast(x) - ack_frame.ack_block_section()->first_ack_block()}); + x -= ack_frame.ack_block_section()->first_ack_block() + 1; for (auto &&block : *(ack_frame.ack_block_section())) { x -= block.gap() + 1; numbers.insert({x, static_cast(x) - block.length()}); diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 9002d6e73d2..a19851eaf93 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -41,7 +41,7 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 1); - CHECK(frame->ack_block_section()->first_ack_block_length() == 0); + CHECK(frame->ack_block_section()->first_ack_block() == 0); frame = creator.create(); CHECK(frame == nullptr); @@ -55,7 +55,7 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 5); - CHECK(frame->ack_block_section()->first_ack_block_length() == 3); + CHECK(frame->ack_block_section()->first_ack_block() == 3); // Loss creator.update(6, false, true); @@ -65,7 +65,7 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); CHECK(frame->largest_acknowledged() == 10); - CHECK(frame->ack_block_section()->first_ack_block_length() == 0); + CHECK(frame->ack_block_section()->first_ack_block() == 0); CHECK(frame->ack_block_section()->begin()->gap() == 1); } @@ -88,7 +88,7 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 2); CHECK(frame->largest_acknowledged() == 9); - CHECK(frame->ack_block_section()->first_ack_block_length() == 1); + CHECK(frame->ack_block_section()->first_ack_block() == 1); CHECK(frame->ack_block_section()->begin()->gap() == 0); frame = creator.create(); @@ -100,7 +100,7 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); CHECK(frame->largest_acknowledged() == 7); - CHECK(frame->ack_block_section()->first_ack_block_length() == 0); + CHECK(frame->ack_block_section()->first_ack_block() == 0); CHECK(frame->ack_block_section()->begin()->gap() == 1); } diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 4623a9c6000..ac37d8b7f5f 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -364,7 +364,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") CHECK(ack_frame1->ack_block_count() == 0); const QUICAckFrame::AckBlockSection *section = ack_frame1->ack_block_section(); - CHECK(section->first_ack_block_length() == 0x01); + CHECK(section->first_ack_block() == 0x01); } SECTION("2 Ack Block, 8 bit packet number length, 8 bit block length") @@ -391,7 +391,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") CHECK(ack_frame1->ack_block_count() == 2); const QUICAckFrame::AckBlockSection *section = ack_frame1->ack_block_section(); - CHECK(section->first_ack_block_length() == 0x01); + CHECK(section->first_ack_block() == 0x01); auto ite = section->begin(); CHECK(ite != section->end()); CHECK(ite->gap() == 0x02); From 919da9dd2fcb6411d71187fdb4de45400ec05d4c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 29 Mar 2018 09:48:05 +0900 Subject: [PATCH 0471/1313] Set nullptr when _loss_detection_alarm is canceled --- iocore/net/quic/QUICLossDetector.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index db182286ed6..015d0613d1f 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -63,7 +63,11 @@ QUICLossDetector::~QUICLossDetector() { if (this->_loss_detection_alarm) { this->_loss_detection_alarm->cancel(); + this->_loss_detection_alarm = nullptr; } + + this->_transmitter = nullptr; + this->_cc = nullptr; } int @@ -83,6 +87,7 @@ QUICLossDetector::event_handler(int event, Event *edata) if (this->_loss_detection_alarm) { this->_loss_detection_alarm->cancel(); + this->_loss_detection_alarm = nullptr; } break; } @@ -152,6 +157,7 @@ QUICLossDetector::reset() SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); if (this->_loss_detection_alarm) { this->_loss_detection_alarm->cancel(); + this->_loss_detection_alarm = nullptr; } this->_sent_packets.clear(); @@ -283,6 +289,7 @@ QUICLossDetector::_set_loss_detection_alarm() this->_loss_detection_alarm->cancel(); this->_loss_detection_alarm = nullptr; QUICLDDebug("Loss detection alarm has been unset"); + return; } if (this->_handshake_outstanding) { From 6e5b664a31c54d939867469520f5609130193d8a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 26 Mar 2018 17:24:21 +0900 Subject: [PATCH 0472/1313] Create frames on demand --- iocore/net/P_QUICNetVConnection.h | 38 +-- iocore/net/QUICNetVConnection.cc | 262 ++++++++---------- iocore/net/quic/Makefile.am | 2 + iocore/net/quic/Mock.h | 29 -- iocore/net/quic/QUICAltConnectionManager.cc | 104 +++++++ iocore/net/quic/QUICAltConnectionManager.h | 61 ++++ iocore/net/quic/QUICConnection.h | 3 +- iocore/net/quic/QUICFlowController.cc | 22 +- iocore/net/quic/QUICFlowController.h | 34 +-- ...rameTransmitter.h => QUICFrameGenerator.h} | 12 +- iocore/net/quic/QUICPacketRetransmitter.cc | 72 +++++ iocore/net/quic/QUICPacketRetransmitter.h | 42 +++ iocore/net/quic/QUICStream.cc | 137 +++++---- iocore/net/quic/QUICStream.h | 28 +- iocore/net/quic/QUICStreamManager.cc | 25 +- iocore/net/quic/QUICStreamManager.h | 10 +- .../net/quic/test/test_QUICFlowController.cc | 28 +- iocore/net/quic/test/test_QUICFrame.cc | 2 +- iocore/net/quic/test/test_QUICHandshake.cc | 1 - iocore/net/quic/test/test_QUICStream.cc | 67 +++-- .../net/quic/test/test_QUICStreamManager.cc | 12 +- 21 files changed, 634 insertions(+), 357 deletions(-) create mode 100644 iocore/net/quic/QUICAltConnectionManager.cc create mode 100644 iocore/net/quic/QUICAltConnectionManager.h rename iocore/net/quic/{QUICFrameTransmitter.h => QUICFrameGenerator.h} (75%) create mode 100644 iocore/net/quic/QUICPacketRetransmitter.cc create mode 100644 iocore/net/quic/QUICPacketRetransmitter.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index ba4a65779eb..e0baec556c2 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -53,8 +53,10 @@ #include "quic/QUICStream.h" #include "quic/QUICHandshakeProtocol.h" #include "quic/QUICAckFrameCreator.h" +#include "quic/QUICPacketRetransmitter.h" #include "quic/QUICLossDetector.h" #include "quic/QUICStreamManager.h" +#include "quic/QUICAltConnectionManager.h" #include "quic/QUICApplicationMap.h" // These are included here because older OpenQUIC libraries don't have them. @@ -185,7 +187,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection const QUICFiveTuple five_tuple() override; uint32_t maximum_quic_packet_size() override; uint32_t minimum_quic_packet_size() override; - uint32_t maximum_stream_frame_data_size() override; QUICStreamManager *stream_manager() override; uint32_t pmtu() override; NetVConnectionContext_t direction() override; @@ -201,13 +202,14 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection virtual void retransmit_packet(const QUICPacket &packet) override; virtual Ptr get_packet_transmitter_mutex() override; - // QUICConnection (QUICFrameTransmitter) - virtual void transmit_frame(QUICFrameUPtr frame) override; - // QUICConnection (QUICFrameHandler) std::vector interests() override; QUICErrorUPtr handle_frame(std::shared_ptr frame) override; + // QUICConnection (QUICFrameGenerator) + bool will_generate_frame(); + QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size); + int in_closed_queue = 0; bool shouldDestroy(); @@ -216,14 +218,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection SLINK(QUICNetVConnection, closed_alink); private: - class AltConnectionInfo - { - public: - int seq_num; - QUICConnectionId id; - QUICStatelessResetToken token; - }; - QUICPacketType _last_received_packet_type = QUICPacketType::UNINITIALIZED; std::random_device _rnd; @@ -231,15 +225,13 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICConnectionId _quic_connection_id; QUICFiveTuple _five_tuple; - AltConnectionInfo _alt_quic_connection_ids[3]; - int8_t _alt_quic_connection_id_seq_num = 0; - QUICPacketNumber _largest_received_packet_number = 0; UDPConnection *_udp_con = nullptr; QUICPacketHandler *_packet_handler = nullptr; QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; QUICAckFrameCreator _ack_frame_creator; + QUICPacketRetransmitter _packet_retransmitter; QUICApplicationMap *_application_map = nullptr; uint32_t _pmtu = 1280; @@ -257,17 +249,15 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection QUICRemoteFlowController *_remote_flow_controller = nullptr; QUICLocalFlowController *_local_flow_controller = nullptr; QUICConnectionTable *_ctable = nullptr; + QUICAltConnectionManager *_alt_con_manager = nullptr; CountQueue _packet_recv_queue; CountQueue _packet_send_queue; std::queue _quic_packet_recv_queue; - // `_frame_send_queue` is the queue for any type of frame except STREAM frame. - // The flow contorl doesn't blcok frames in this queue. - // `_stream_frame_send_queue` is the queue for STREAM frame. - std::queue _frame_send_queue; - std::queue _stream_frame_send_queue; - void _schedule_packet_write_ready(); + QUICConnectionErrorUPtr _connection_error = nullptr; + + void _schedule_packet_write_ready(bool delay = false); void _unschedule_packet_write_ready(); void _close_packet_write_ready(Event *data); Event *_packet_write_ready = nullptr; @@ -282,9 +272,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _close_closed_event(Event *data); Event *_closed_event = nullptr; - uint32_t _transmit_packet(QUICPacketUPtr); - void _transmit_frame(QUICFrameUPtr); - + uint32_t _maximum_stream_frame_data_size(); + uint32_t _transmit_packet(QUICPacketUPtr packet); void _store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, QUICFrameUPtr frame); void _packetize_frames(); @@ -324,7 +313,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection void _start_application(); void _handle_idle_timeout(); - void _update_alt_connection_ids(uint8_t chosen); QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet(); QUICStatelessResetToken _reset_token; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index aa7b0c3f9d3..460c547922c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -56,6 +56,8 @@ static constexpr uint32_t MAX_PACKET_OVERHEAD = 17; // Max long header len(17) static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; static constexpr uint32_t MINIMUM_INITIAL_CLIENT_PACKET_SIZE = 1200; +static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(20); +static constexpr int FRAME_PER_EVENT = 64; ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); @@ -148,6 +150,8 @@ QUICNetVConnection::acceptEvent(int event, Event *e) } action_.continuation->handleEvent(NET_EVENT_ACCEPT, this); + this->_schedule_packet_write_ready(); + return EVENT_DONE; } @@ -193,11 +197,11 @@ QUICNetVConnection::start() this->_packet_factory.set_hs_protocol(this->_hs_protocol); // Create frame handlers - this->_stream_manager = new QUICStreamManager(this->connection_id(), this, this->_application_map); + this->_stream_manager = new QUICStreamManager(this->connection_id(), this->_application_map); this->_congestion_controller = new QUICCongestionController(); this->_loss_detector = new QUICLossDetector(this, this->_congestion_controller); - this->_remote_flow_controller = new QUICRemoteConnectionFlowController(0, this); - this->_local_flow_controller = new QUICLocalConnectionFlowController(0, this); + this->_remote_flow_controller = new QUICRemoteConnectionFlowController(0); + this->_local_flow_controller = new QUICLocalConnectionFlowController(0); this->_frame_dispatcher->add_handler(this); this->_frame_dispatcher->add_handler(this->_stream_manager); @@ -211,9 +215,7 @@ QUICNetVConnection::free(EThread *t) this->_ctable->erase(this->_original_quic_connection_id, this); this->_ctable->erase(this->_quic_connection_id, this); - for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { - this->_ctable->erase(this->_alt_quic_connection_ids[i].id, this); - } + this->_alt_con_manager->invalidate_alt_connections(); /* TODO: Uncmment these blocks after refactoring read / write process this->_udp_con = nullptr; @@ -227,6 +229,9 @@ QUICNetVConnection::free(EThread *t) delete this->_frame_dispatcher; delete this->_stream_manager; delete this->_congestion_controller; + if (this->_alt_con_manager) { + delete this->_alt_con_manager; + } // TODO: clear member variables like `UnixNetVConnection::free(EThread *t)` this->mutex.clear(); @@ -332,7 +337,7 @@ QUICNetVConnection::maximum_quic_packet_size() } uint32_t -QUICNetVConnection::maximum_stream_frame_data_size() +QUICNetVConnection::_maximum_stream_frame_data_size() { return this->maximum_quic_packet_size() - MAX_STREAM_FRAME_OVERHEAD - MAX_PACKET_OVERHEAD; } @@ -368,30 +373,7 @@ QUICNetVConnection::transmit_packet(QUICPacketUPtr packet) void QUICNetVConnection::retransmit_packet(const QUICPacket &packet) { - QUICConDebug("Retransmit packet #%" PRIu64 " type %s", packet.packet_number(), QUICDebugNames::packet_type(packet.type())); - ink_assert(packet.type() != QUICPacketType::VERSION_NEGOTIATION && packet.type() != QUICPacketType::UNINITIALIZED); - - // Get payload from a header because packet.payload() is encrypted - uint16_t size = packet.header().payload_size(); - const uint8_t *payload = packet.header().payload(); - - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - uint16_t cursor = 0; - - while (cursor < size) { - frame = QUICFrameFactory::create(payload + cursor, size - cursor); - cursor += frame->size(); - - switch (frame->type()) { - case QUICFrameType::PADDING: - case QUICFrameType::ACK: - break; - default: - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), packet); - this->transmit_frame(std::move(frame)); - break; - } - } + this->_packet_retransmitter.retransmit_packet(packet); } Ptr @@ -406,34 +388,6 @@ QUICNetVConnection::handle_received_packet(UDPPacket *packet) this->_packet_recv_queue.enqueue(packet); } -void -QUICNetVConnection::_transmit_frame(QUICFrameUPtr frame) -{ - SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); - - if (frame) { - QUICConVDebug("type=%s size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); - if (frame->type() == QUICFrameType::STREAM) { - QUICStreamFrame &stream_frame = static_cast(*frame); - // XXX: Stream 0 is exempt from the connection-level flow control window. - if (stream_frame.stream_id() == STREAM_ID_FOR_HANDSHAKE) { - this->_frame_send_queue.push(std::move(frame)); - } else { - this->_stream_frame_send_queue.push(std::move(frame)); - } - } else { - this->_frame_send_queue.push(std::move(frame)); - } - } -} - -void -QUICNetVConnection::transmit_frame(QUICFrameUPtr frame) -{ - this->_transmit_frame(std::move(frame)); - this->_schedule_packet_write_ready(); -} - void QUICNetVConnection::close(QUICConnectionErrorUPtr error) { @@ -466,9 +420,7 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) break; case QUICFrameType::PING: - if (std::static_pointer_cast(frame)->data_length() > 0) { - this->transmit_frame(QUICFrameFactory::create_pong_frame(*std::static_pointer_cast(frame))); - } + // Nothing to do break; case QUICFrameType::BLOCKED: // BLOCKED frame is for debugging. Nothing to do here. @@ -577,6 +529,8 @@ QUICNetVConnection::state_handshake(int event, Event *data) error = this->_state_common_send_packet(); } + // Reschedule WRITE_READY + this->_schedule_packet_write_ready(true); break; } @@ -608,6 +562,8 @@ QUICNetVConnection::state_connection_established(int event, Event *data) case QUIC_EVENT_PACKET_WRITE_READY: { this->_close_packet_write_ready(data); error = this->_state_common_send_packet(); + // Reschedule WRITE_READY + this->_schedule_packet_write_ready(true); break; } case EVENT_IMMEDIATE: { @@ -640,6 +596,8 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) case QUIC_EVENT_PACKET_WRITE_READY: this->_close_packet_write_ready(data); this->_state_closing_send_packet(); + // Reschedule WRITE_READY + this->_schedule_packet_write_ready(true); break; case QUIC_EVENT_CLOSING_TIMEOUT: this->_close_closing_timeout(data); @@ -901,22 +859,15 @@ QUICNetVConnection::_state_common_receive_packet() case QUICPacketType::PROTECTED: // Check connection migration if (this->_handshake_handler->is_completed() && p->connection_id() != this->_quic_connection_id) { - for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { - AltConnectionInfo &info = this->_alt_quic_connection_ids[i]; - if (info.id == p->connection_id()) { - // Migrate connection - // TODO Address Validation - // TODO Adjust expected packet number with a gap computed based on info.seq_num - // TODO Unregister the old connection id (Should we wait for a while?) - this->_quic_connection_id = info.id; - this->_reset_token = info.token; - this->_update_alt_connection_ids(i); - break; - } + if (this->_alt_con_manager->migrate_to(p->connection_id(), this->_reset_token)) { + // Migrate connection + // TODO Address Validation + // TODO Adjust expected packet number with a gap computed based on info.seq_num + this->_quic_connection_id = p->connection_id(); + } else { + // TODO Send some error? } - ink_assert(p->connection_id() == this->_quic_connection_id); } - error = this->_state_connection_established_process_packet(std::move(p)); break; case QUICPacketType::INITIAL: @@ -943,7 +894,7 @@ QUICNetVConnection::_state_connection_closing_and_draining_receive_packet() QUICPacketUPtr packet = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::SUCCESS) { this->_recv_and_ack(std::move(packet)); - this->_schedule_packet_write_ready(); + this->_schedule_packet_write_ready(true); } if (this->_packet_recv_queue.size > 0) { @@ -969,7 +920,9 @@ QUICNetVConnection::_state_common_send_packet() } QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, packet_count); - net_activity(this, this_ethread()); + if (packet_count) { + net_activity(this, this_ethread()); + } return QUICErrorUPtr(new QUICNoError()); } @@ -988,9 +941,9 @@ QUICNetVConnection::_state_handshake_send_retry_packet() SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); - ink_assert(this->_frame_send_queue.size() == 1); - frame = std::move(this->_frame_send_queue.front()); - this->_frame_send_queue.pop(); + frame = this->_stream_manager->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); + ink_assert(frame); + ink_assert(frame->type() == QUICFrameType::STREAM); this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); if (len == 0) { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); @@ -1025,6 +978,8 @@ void QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, QUICFrameUPtr frame) { + QUICConVDebug("type=%s size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); + uint32_t max_size = this->maximum_quic_packet_size(); QUICPacketType previous_packet_type = current_packet_type; @@ -1074,7 +1029,8 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans void QUICNetVConnection::_packetize_frames() { - size_t len = 0; + int frame_count = 0; + size_t len = 0; ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; @@ -1084,45 +1040,93 @@ QUICNetVConnection::_packetize_frames() SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); - QUICFrameUPtr ack_frame = QUICFrameFactory::create_null_ack_frame(); - if (this->_frame_send_queue.size() || this->_stream_frame_send_queue.size()) { - ack_frame = this->_ack_frame_creator.create(); + bool will_be_ack_only = true; + if (this->_connection_error || this->_packet_retransmitter.will_generate_frame() || + this->_stream_manager->will_generate_frame()) { + will_be_ack_only = false; + } + + // ACK + if (will_be_ack_only) { + frame = this->_ack_frame_creator.create_if_needed(); } else { - ack_frame = this->_ack_frame_creator.create_if_needed(); + frame = this->_ack_frame_creator.create(); } - if (ack_frame != nullptr) { - this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(ack_frame)); + if (frame != nullptr) { + ++frame_count; + this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); } - while (this->_frame_send_queue.size() > 0) { - frame = std::move(this->_frame_send_queue.front()); - this->_frame_send_queue.pop(); - this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - if (this->_the_final_packet) { - return; + // CONNECTION_CLOSE, APPLICATION_CLOSE + if (this->_connection_error) { + QUICFrameUPtr frame = QUICFrameFactory::create_null_ack_frame(); + if (this->_connection_error->cls == QUICErrorClass::APPLICATION) { + frame = QUICFrameFactory::create_application_close_frame(std::move(this->_connection_error)); + } else { + frame = QUICFrameFactory::create_connection_close_frame(std::move(this->_connection_error)); } + ++frame_count; + this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); } - while (this->_stream_frame_send_queue.size() > 0) { - const QUICFrameUPtr &f = this->_stream_frame_send_queue.front(); - uint32_t frame_size = f->size(); - - int ret = this->_remote_flow_controller->update((this->_stream_manager->total_offset_sent() + frame_size)); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, - static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); + // NEW_CONNECTION_ID + if (this->_alt_con_manager) { + frame = + this->_alt_con_manager->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); + while (frame) { + ++frame_count; + this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + if (this->_the_final_packet) { + return; + } + if (frame_count >= FRAME_PER_EVENT) { + break; + } + frame = + this->_alt_con_manager->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); + } + } - if (ret != 0) { - QUICConDebug("Flow Controller blocked sending a STREAM frame"); + // Lost frames + frame = + this->_packet_retransmitter.generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); + while (frame) { + ++frame_count; + this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + if (this->_the_final_packet) { + return; + } + if (frame_count >= FRAME_PER_EVENT) { break; } + frame = + this->_packet_retransmitter.generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); + } - frame = std::move(this->_stream_frame_send_queue.front()); - this->_stream_frame_send_queue.pop(); + // STREAM, MAX_STREAM_DATA, STREAM_BLOCKED + frame = this->_stream_manager->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); + while (frame) { + ++frame_count; + if (frame->type() == QUICFrameType::STREAM) { + uint16_t frame_size = frame->size(); + int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent() + frame_size); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, + static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); + ink_assert(ret == 0); + this->_stream_manager->add_total_offset_sent(frame_size); + } this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - this->_stream_manager->add_total_offset_sent(frame_size); + if (this->_the_final_packet) { + return; + } + if (frame_count >= FRAME_PER_EVENT) { + break; + } + frame = this->_stream_manager->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); } + // Schedule a packet if (len != 0) { // Pad with PADDING frames uint32_t min_size = this->minimum_quic_packet_size(); @@ -1168,7 +1172,6 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) bool protection = packet->type() == QUICPacketType::PROTECTED || packet->type() == QUICPacketType::ZERO_RTT_PROTECTED; this->_ack_frame_creator.update(packet_num, protection, should_send_ack); - static_cast(this)->transmit_frame(); return error; } @@ -1337,12 +1340,16 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) } void -QUICNetVConnection::_schedule_packet_write_ready() +QUICNetVConnection::_schedule_packet_write_ready(bool delay) { SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); if (!this->_packet_write_ready) { - QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); - this->_packet_write_ready = this_ethread()->schedule_imm(this, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + QUICConVDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); + if (delay) { + this->_packet_write_ready = this_ethread()->schedule_in(this, WRITE_READY_INTERVAL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + } else { + this->_packet_write_ready = this_ethread()->schedule_imm(this, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + } } } @@ -1475,7 +1482,7 @@ QUICNetVConnection::_switch_to_established_state() SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); if (netvc_context == NET_VCONNECTION_IN) { - this->_update_alt_connection_ids(countof(this->_alt_quic_connection_ids) - 1); + this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable); } } else { // Illegal state change @@ -1494,11 +1501,7 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) } else { QUICConDebug("Reason was not provided"); } - if (error->cls == QUICErrorClass::APPLICATION) { - this->transmit_frame(QUICFrameFactory::create_application_close_frame(std::move(error))); - } else { - this->transmit_frame(QUICFrameFactory::create_connection_close_frame(std::move(error))); - } + this->_connection_error = std::move(error); this->remove_from_active_queue(); this->set_inactivity_timeout(0); @@ -1563,28 +1566,3 @@ QUICNetVConnection::_handle_idle_timeout() // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application } - -void -QUICNetVConnection::_update_alt_connection_ids(uint8_t chosen) -{ - QUICConfig::scoped_config params; - int n = sizeof(this->_alt_quic_connection_ids); - int current = this->_alt_quic_connection_id_seq_num % n; - int delta = chosen - current; - int count = (n + delta) % n + 1; - - for (int i = 0; i < count; ++i) { - int index = (current + i) % n; - QUICConnectionId conn_id; - QUICStatelessResetToken token; - - conn_id.randomize(); - token.generate(conn_id, params->server_id()); - this->_alt_quic_connection_ids[index] = {this->_alt_quic_connection_id_seq_num + i, conn_id, token}; - this->transmit_frame(QUICFrameFactory::create_new_connection_id_frame(this->_alt_quic_connection_ids[index].seq_num, - this->_alt_quic_connection_ids[index].id, - this->_alt_quic_connection_ids[index].token)); - this->_ctable->insert(conn_id, this); - } - this->_alt_quic_connection_id_seq_num += count; -} diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index fcb8e6dafa4..c682941be7a 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -67,12 +67,14 @@ libquic_a_SOURCES = \ QUICHKDF.cc \ QUICTransportParameters.cc \ QUICConnectionTable.cc \ + QUICAltConnectionManager.cc \ QUICAckFrameCreator.cc \ QUICConfig.cc \ QUICDebugNames.cc \ QUICApplication.cc \ QUICApplicationMap.cc \ QUICIncomingFrameBuffer.cc \ + QUICPacketRetransmitter.cc \ QUICStatelessRetry.cc include $(top_srcdir)/build/tidy.mk diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 6c61438877d..0156e04bf0d 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -182,11 +182,6 @@ class MockQUICConnection : public QUICConnection return this->_mutex; } - void - transmit_frame(QUICFrameUPtr frame) override - { - } - std::vector interests() override { @@ -214,12 +209,6 @@ class MockQUICConnection : public QUICConnection return 1200; } - uint32_t - maximum_stream_frame_data_size() override - { - return 1160; - } - uint32_t pmtu() override { @@ -322,24 +311,6 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter std::set retransmitted; }; -class MockQUICFrameTransmitter : public QUICFrameTransmitter -{ -public: - void - transmit_frame(QUICFrameUPtr frame) override - { - ++frameCount[static_cast(frame->type())]; - } - - uint32_t - maximum_stream_frame_data_size() override - { - return 1200; - } - - int frameCount[256] = {0}; -}; - class MockQUICCongestionController : public QUICCongestionController { public: diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc new file mode 100644 index 00000000000..13cf4511fa4 --- /dev/null +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -0,0 +1,104 @@ +/** @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 "QUICAltConnectionManager.h" +#include "QUICConnectionTable.h" +#include "QUICConfig.h" + +QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable) : _qc(qc), _ctable(ctable) +{ + this->_update_alt_connection_ids(-1); +} + +void +QUICAltConnectionManager::_update_alt_connection_ids(int8_t chosen) +{ + if (chosen == -1) { + chosen = countof(this->_alt_quic_connection_ids) - 1; + } + + QUICConfig::scoped_config params; + int n = sizeof(this->_alt_quic_connection_ids); + int current = this->_alt_quic_connection_id_seq_num % n; + int delta = chosen - current; + int count = (n + delta) % n + 1; + + for (int i = 0; i < count; ++i) { + int index = (current + i) % n; + QUICConnectionId conn_id; + QUICStatelessResetToken token; + + conn_id.randomize(); + token.generate(conn_id, params->server_id()); + this->_alt_quic_connection_ids[index] = {this->_alt_quic_connection_id_seq_num + i, conn_id, token, false}; + this->_ctable.insert(conn_id, this->_qc); + } + this->_alt_quic_connection_id_seq_num += count; + this->_need_advertise = true; +} + +bool +QUICAltConnectionManager::migrate_to(QUICConnectionId cid, QUICStatelessResetToken &new_reset_token) +{ + for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { + AltConnectionInfo &info = this->_alt_quic_connection_ids[i]; + if (info.id == cid) { + // Migrate connection + // TODO Unregister the old connection id (Should we wait for a while?) + new_reset_token = info.token; + this->_update_alt_connection_ids(i); + return true; + } + } + return false; +} + +void +QUICAltConnectionManager::invalidate_alt_connections() +{ + for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { + this->_ctable.erase(this->_alt_quic_connection_ids[i].id, this->_qc); + } +} + +bool +QUICAltConnectionManager::will_generate_frame() +{ + return this->_need_advertise; +} + +QUICFrameUPtr +QUICAltConnectionManager::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) +{ + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + int count = countof(this->_alt_quic_connection_ids); + for (int i = 0; i < count; ++i) { + if (!this->_alt_quic_connection_ids[i].advertised) { + this->_alt_quic_connection_ids[i].advertised = true; + return QUICFrameFactory::create_new_connection_id_frame( + this->_alt_quic_connection_ids[i].seq_num, this->_alt_quic_connection_ids[i].id, this->_alt_quic_connection_ids[i].token); + } + } + this->_need_advertise = false; + return frame; +} diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h new file mode 100644 index 00000000000..f6502aaf7c6 --- /dev/null +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -0,0 +1,61 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include "QUICFrameGenerator.h" +#include "QUICTypes.h" +#include "QUICConnection.h" + +class QUICConnectionTable; + +class QUICAltConnectionManager : public QUICFrameGenerator +{ +public: + QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable); + bool migrate_to(QUICConnectionId cid, QUICStatelessResetToken &new_reset_token); + void invalidate_alt_connections(); + + // QUICFrameGenerator + bool will_generate_frame(); + QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size); + +private: + class AltConnectionInfo + { + public: + int seq_num; + QUICConnectionId id; + QUICStatelessResetToken token; + bool advertised; + }; + + QUICConnection *_qc = nullptr; + QUICConnectionTable &_ctable; + AltConnectionInfo _alt_quic_connection_ids[3]; + int8_t _alt_quic_connection_id_seq_num = 0; + bool _need_advertise = false; + + void _update_alt_connection_ids(int8_t chosen = -1); +}; diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 8ab7b67b35d..c4d7b73b607 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -26,7 +26,6 @@ #include "I_EventSystem.h" #include "I_NetVConnection.h" #include "QUICPacketTransmitter.h" -#include "QUICFrameTransmitter.h" #include "QUICFrameHandler.h" class QUICApplication; @@ -34,7 +33,7 @@ class QUICStreamManager; class UDPPacket; class SSLNextProtocolSet; -class QUICConnection : public QUICPacketTransmitter, public QUICFrameTransmitter, public QUICFrameHandler +class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler { public: virtual QUICConnectionId original_connection_id() = 0; diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 7fac445a2ca..67a2898ecbf 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -23,11 +23,16 @@ #include "QUICFlowController.h" #include "QUICFrame.h" -#include "QUICFrameTransmitter.h" // // QUICFlowController // +uint32_t +QUICFlowController::credit() +{ + return this->current_limit() - this->current_offset(); +} + QUICOffset QUICFlowController::current_offset() { @@ -76,6 +81,17 @@ QUICFlowController::set_threshold(uint64_t threshold) this->_threshold = threshold; } +QUICFrameUPtr +QUICFlowController::generate_frame() +{ + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + if (this->_frame) { + frame = std::move(this->_frame); + this->_frame = nullptr; + } + return frame; +} + // // QUICRemoteFlowController // @@ -98,7 +114,7 @@ QUICRemoteFlowController::update(QUICOffset offset) // Send BLOCKED(_STREAM) frame if (!this->_blocked && offset > this->_limit) { - this->_tx->transmit_frame(this->_create_frame()); + this->_frame = this->_create_frame(); this->_blocked = true; } @@ -115,7 +131,7 @@ QUICLocalFlowController::forward_limit(QUICOffset offset) // Send MAX_(STREAM_)DATA frame if (this->_limit - this->_offset <= this->_threshold) { - this->_tx->transmit_frame(this->_create_frame()); + this->_frame = this->_create_frame(); } } diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index 6a56aa369a9..930d9f08a63 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -26,11 +26,10 @@ #include "QUICTypes.h" #include "QUICFrame.h" -class QUICFrameTransmitter; - class QUICFlowController { public: + uint32_t credit(); QUICOffset current_offset(); QUICOffset current_limit(); @@ -40,21 +39,22 @@ class QUICFlowController virtual int update(QUICOffset offset); virtual void forward_limit(QUICOffset limit); void set_threshold(uint64_t threshold); + QUICFrameUPtr generate_frame(); protected: - QUICFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : _limit(initial_limit), _tx(tx) {} + QUICFlowController(uint64_t initial_limit) : _limit(initial_limit) {} virtual QUICFrameUPtr _create_frame() = 0; - QUICOffset _offset = 0; - QUICOffset _limit = 0; - QUICOffset _threshold = 1024; - QUICFrameTransmitter *_tx = nullptr; + QUICOffset _offset = 0; + QUICOffset _limit = 0; + QUICOffset _threshold = 1024; + QUICFrameUPtr _frame = QUICFrameFactory::create_null_frame(); }; class QUICRemoteFlowController : public QUICFlowController { public: - QUICRemoteFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICFlowController(initial_limit, tx) {} + QUICRemoteFlowController(uint64_t initial_limit) : QUICFlowController(initial_limit) {} int update(QUICOffset offset) override; void forward_limit(QUICOffset limit) override; @@ -65,33 +65,29 @@ class QUICRemoteFlowController : public QUICFlowController class QUICLocalFlowController : public QUICFlowController { public: - QUICLocalFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICFlowController(initial_limit, tx) {} + QUICLocalFlowController(uint64_t initial_limit) : QUICFlowController(initial_limit) {} void forward_limit(QUICOffset limit) override; }; class QUICRemoteConnectionFlowController : public QUICRemoteFlowController { public: - QUICRemoteConnectionFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICRemoteFlowController(initial_limit, tx) - { - } + QUICRemoteConnectionFlowController(uint64_t initial_limit) : QUICRemoteFlowController(initial_limit) {} QUICFrameUPtr _create_frame() override; }; class QUICLocalConnectionFlowController : public QUICLocalFlowController { public: - QUICLocalConnectionFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx) : QUICLocalFlowController(initial_limit, tx) - { - } + QUICLocalConnectionFlowController(uint64_t initial_limit) : QUICLocalFlowController(initial_limit) {} QUICFrameUPtr _create_frame() override; }; class QUICRemoteStreamFlowController : public QUICRemoteFlowController { public: - QUICRemoteStreamFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx, QUICStreamId stream_id) - : QUICRemoteFlowController(initial_limit, tx), _stream_id(stream_id) + QUICRemoteStreamFlowController(uint64_t initial_limit, QUICStreamId stream_id) + : QUICRemoteFlowController(initial_limit), _stream_id(stream_id) { } QUICFrameUPtr _create_frame() override; @@ -103,8 +99,8 @@ class QUICRemoteStreamFlowController : public QUICRemoteFlowController class QUICLocalStreamFlowController : public QUICLocalFlowController { public: - QUICLocalStreamFlowController(uint64_t initial_limit, QUICFrameTransmitter *tx, QUICStreamId stream_id) - : QUICLocalFlowController(initial_limit, tx), _stream_id(stream_id) + QUICLocalStreamFlowController(uint64_t initial_limit, QUICStreamId stream_id) + : QUICLocalFlowController(initial_limit), _stream_id(stream_id) { } QUICFrameUPtr _create_frame() override; diff --git a/iocore/net/quic/QUICFrameTransmitter.h b/iocore/net/quic/QUICFrameGenerator.h similarity index 75% rename from iocore/net/quic/QUICFrameTransmitter.h rename to iocore/net/quic/QUICFrameGenerator.h index e3143d137ce..7c2d40ee2da 100644 --- a/iocore/net/quic/QUICFrameTransmitter.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -25,14 +25,10 @@ #include "QUICFrame.h" -class QUICFrameTransmitter +class QUICFrameGenerator { public: - /* - * Enqueue a frame for transmission - * - * This schedules QUIC_PACKET_WRITE_READY event. - */ - virtual void transmit_frame(QUICFrameUPtr frame = QUICFrameUPtr(nullptr, &QUICFrameDeleter::delete_null_frame)) = 0; - virtual uint32_t maximum_stream_frame_data_size() = 0; + virtual ~QUICFrameGenerator(){}; + virtual bool will_generate_frame() = 0; + virtual QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) = 0; }; diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc new file mode 100644 index 00000000000..32c005d3d6b --- /dev/null +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -0,0 +1,72 @@ +/** @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 "QUICPacketRetransmitter.h" +#include "QUICDebugNames.h" + +void +QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) +{ + Debug("quic_con", "Retransmit packet #%" PRIu64 " type %s", packet.packet_number(), QUICDebugNames::packet_type(packet.type())); + ink_assert(packet.type() != QUICPacketType::VERSION_NEGOTIATION && packet.type() != QUICPacketType::UNINITIALIZED); + + // Get payload from a header because packet.payload() is encrypted + uint16_t size = packet.header().payload_size(); + const uint8_t *payload = packet.header().payload(); + + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + uint16_t cursor = 0; + + while (cursor < size) { + frame = QUICFrameFactory::create(payload + cursor, size - cursor); + cursor += frame->size(); + + switch (frame->type()) { + case QUICFrameType::PADDING: + case QUICFrameType::ACK: + break; + default: + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), packet); + // FIXME We should probably reframe STREAM frames so that it can fit in new packets + this->_retransmission_frames.push(std::move(frame)); + break; + } + } +} + +bool +QUICPacketRetransmitter::will_generate_frame() +{ + return !this->_retransmission_frames.empty(); +} + +QUICFrameUPtr +QUICPacketRetransmitter::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) +{ + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + if (!this->_retransmission_frames.empty()) { + frame = std::move(this->_retransmission_frames.front()); + this->_retransmission_frames.pop(); + } + return frame; +} diff --git a/iocore/net/quic/QUICPacketRetransmitter.h b/iocore/net/quic/QUICPacketRetransmitter.h new file mode 100644 index 00000000000..c24d6b5a94b --- /dev/null +++ b/iocore/net/quic/QUICPacketRetransmitter.h @@ -0,0 +1,42 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICPacket.h" +#include "QUICFrame.h" +#include "QUICFrameGenerator.h" +#include + +class QUICPacketRetransmitter : public QUICFrameGenerator +{ +public: + void retransmit_packet(const QUICPacket &packet); + + // QUICFrameGenerator + bool will_generate_frame() override; + QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) override; + +private: + std::queue _retransmission_frames; +}; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 9e78714450c..b0f1c5f2559 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -35,15 +35,13 @@ Debug("quic_flow_ctrl", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) -QUICStream::QUICStream(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data, - uint64_t send_max_stream_data) +QUICStream::QUICStream(QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data) : VConnection(nullptr), _connection_id(cid), _id(sid), - _remote_flow_controller(send_max_stream_data, tx, _id), - _local_flow_controller(recv_max_stream_data, tx, _id), - _received_stream_frame_buffer(this), - _tx(tx) + _remote_flow_controller(send_max_stream_data, _id), + _local_flow_controller(recv_max_stream_data, _id), + _received_stream_frame_buffer(this) { SET_HANDLER(&QUICStream::state_stream_open); mutex = new_ProxyMutex(); @@ -359,6 +357,76 @@ QUICStream::recv(const std::shared_ptr frame) return QUICErrorUPtr(new QUICNoError()); } +bool +QUICStream::will_generate_frame() +{ + return this->_write_vio.get_reader()->read_avail() > 0; +} + +QUICFrameUPtr +QUICStream::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) +{ + SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); + + QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); + + if (this->_reset_reason) { + return QUICFrameFactory::create_rst_stream_frame(std::move(this->_reset_reason)); + } + + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + frame = this->_local_flow_controller.generate_frame(); + if (frame) { + return frame; + } + + IOBufferReader *reader = this->_write_vio.get_reader(); + int64_t bytes_avail = reader->read_avail(); + if (bytes_avail == 0) { + return frame; + } + + int64_t data_len = reader->block_read_avail(); + int64_t len = 0; + bool fin = false; + + len = std::min(data_len, static_cast( + std::min(static_cast(maximum_frame_size), + std::min(this->_remote_flow_controller.credit(), static_cast(connection_credit))))); + if (len >= bytes_avail) { + fin = this->_fin; + } + + if (len > 0) { + bool protection = this->_id != STREAM_ID_FOR_HANDSHAKE; + frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, this->_id, + this->_send_offset, fin, protection); + if (!this->_state.is_allowed_to_send(*frame)) { + QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); + return frame; + } + } else { + len = bytes_avail; + } + + int ret = this->_remote_flow_controller.update(this->_send_offset + len); + // We cannot cancel sending the frame after updating the flow controller + + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); + if (frame && ret == 0) { + this->_send_offset += len; + reader->consume(len); + this->_write_vio.ndone += len; + this->_signal_write_event(); + this->_state.update_with_sent_frame(*frame); + } else { + QUICStreamDebug("Flow Controller blocked sending a STREAM frame"); + frame = this->_remote_flow_controller.generate_frame(); + } + return frame; +} + /** * Reset send/recv offset of stream. This is only for stream 0. */ @@ -467,66 +535,13 @@ QUICStream::_process_write_vio() return 0; } - SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); - - QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); - - IOBufferReader *reader = this->_write_vio.get_reader(); - int64_t bytes_avail = reader->read_avail(); - int64_t total_len = 0; - uint32_t max_size = this->_tx->maximum_stream_frame_data_size(); - - while (total_len < bytes_avail) { - int64_t data_len = reader->block_read_avail(); - int64_t len = 0; - bool fin = false; - - uint64_t credit = this->_remote_flow_controller.current_limit() - this->_remote_flow_controller.current_offset(); - if (credit != 0 && max_size > credit) { - max_size = credit; - } - if (data_len > max_size) { - len = max_size; - } else { - len = data_len; - if (total_len + len >= bytes_avail) { - fin = this->_fin; - } - } - - bool protection = this->_id != STREAM_ID_FOR_HANDSHAKE; - QUICStreamFrameUPtr frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, - this->_id, this->_send_offset, fin, protection); - if (!this->_state.is_allowed_to_send(*frame)) { - QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); - break; - } - - int ret = this->_remote_flow_controller.update(this->_send_offset + len); - QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), - this->_remote_flow_controller.current_limit()); - if (ret != 0) { - QUICStreamDebug("Flow Controller blocked sending a STREAM frame"); - break; - } - // We cannot cancel sending the frame after updating the flow controller - - this->_send_offset += len; - reader->consume(len); - this->_write_vio.ndone += len; - total_len += len; - - this->_state.update_with_sent_frame(*frame); - this->_tx->transmit_frame(std::move(frame)); - } - - return total_len; + return 0; } void QUICStream::reset(QUICStreamErrorUPtr error) { - this->_tx->transmit_frame(QUICFrameFactory::create_rst_stream_frame(std::move(error))); + this->_reset_reason = std::move(error); } void diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index b139d4e826b..f2299f8628c 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -32,9 +32,9 @@ #include "QUICStreamState.h" #include "QUICFlowController.h" #include "QUICIncomingFrameBuffer.h" +#include "QUICFrameGenerator.h" class QUICNetVConnection; -class QUICFrameTransmitter; class QUICStreamState; class QUICStreamManager; @@ -42,18 +42,14 @@ class QUICStreamManager; * @brief QUIC Stream * TODO: This is similar to Http2Stream. Need to think some integration. */ -class QUICStream : public VConnection +class QUICStream : public VConnection, public QUICFrameGenerator { public: QUICStream() - : VConnection(nullptr), - _remote_flow_controller(0, nullptr, 0), - _local_flow_controller(0, nullptr, 0), - _received_stream_frame_buffer(this) + : VConnection(nullptr), _remote_flow_controller(0, 0), _local_flow_controller(0, 0), _received_stream_frame_buffer(this) { } - QUICStream(QUICFrameTransmitter *tx, QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data = 0, - uint64_t send_max_stream_data = 0); + QUICStream(QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data = 0, uint64_t send_max_stream_data = 0); ~QUICStream(); // void start(); int state_stream_open(int event, void *data); @@ -65,6 +61,7 @@ class QUICStream : public VConnection QUICOffset final_offset(); void reset_send_offset(); void reset_recv_offset(); + QUICStreamFrameUPtr generete_frame(uint16_t flow_control_credit, uint16_t maximum_frame_size); // Implement VConnection Interface. VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; @@ -89,6 +86,10 @@ class QUICStream : public VConnection LINK(QUICStream, link); + // QUICFrameGenerator + QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) override; + bool will_generate_frame() override; + private: virtual int64_t _process_read_vio(); virtual int64_t _process_write_vio(); @@ -99,10 +100,11 @@ class QUICStream : public VConnection void _write_to_read_vio(const std::shared_ptr &); QUICStreamState _state; - bool _fin = false; - QUICConnectionId _connection_id = 0; - QUICStreamId _id = 0; - QUICOffset _send_offset = 0; + bool _fin = false; + QUICStreamErrorUPtr _reset_reason = nullptr; + QUICConnectionId _connection_id = 0; + QUICStreamId _id = 0; + QUICOffset _send_offset = 0; QUICRemoteStreamFlowController _remote_flow_controller; QUICLocalStreamFlowController _local_flow_controller; @@ -117,6 +119,4 @@ class QUICStream : public VConnection // Fragments of received STREAM frame (offset is unmatched) // TODO: Consider to replace with ts/RbTree.h or other data structure QUICIncomingFrameBuffer _received_stream_frame_buffer; - - QUICFrameTransmitter *_tx = nullptr; }; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 8c96a9c593a..c636f5bcade 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -32,8 +32,7 @@ static constexpr char tag[] = "quic_stream_manager"; ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); ClassAllocator quicStreamAllocator("quicStreamAllocator"); -QUICStreamManager::QUICStreamManager(QUICConnectionId cid, QUICFrameTransmitter *tx, QUICApplicationMap *app_map) - : _connection_id(cid), _tx(tx), _app_map(app_map) +QUICStreamManager::QUICStreamManager(QUICConnectionId cid, QUICApplicationMap *app_map) : _connection_id(cid), _app_map(app_map) { } @@ -247,7 +246,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) // TODO Free the stream somewhere stream = THREAD_ALLOC(quicStreamAllocator, this_ethread()); - new (stream) QUICStream(this->_tx, this->_connection_id, stream_id, local_max_stream_data, remote_max_stream_data); + new (stream) QUICStream(this->_connection_id, stream_id, local_max_stream_data, remote_max_stream_data); this->stream_list.push(stream); } @@ -313,3 +312,23 @@ QUICStreamManager::reset_recv_offset() stream->reset_recv_offset(); } + +bool +QUICStreamManager::will_generate_frame() +{ + return this->stream_list.head; +} + +QUICFrameUPtr +QUICStreamManager::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) +{ + // FIXME We should pick a stream based on priority + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + frame = s->generate_frame(connection_credit, maximum_frame_size); + if (frame) { + break; + } + } + return frame; +} diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 44b823b1d60..f453ab6c198 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -28,17 +28,16 @@ #include "QUICApplicationMap.h" #include "QUICFrameHandler.h" #include "QUICFrame.h" -#include "QUICFrameTransmitter.h" extern ClassAllocator quicStreamAllocator; class QUICTransportParameters; -class QUICStreamManager : public QUICFrameHandler +class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator { public: QUICStreamManager(){}; - QUICStreamManager(QUICConnectionId cid, QUICFrameTransmitter *tx, QUICApplicationMap *app_map); + QUICStreamManager(QUICConnectionId cid, QUICApplicationMap *app_map); void init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); @@ -60,6 +59,10 @@ class QUICStreamManager : public QUICFrameHandler virtual std::vector interests() override; virtual QUICErrorUPtr handle_frame(std::shared_ptr) override; + // QUICFrameGenerator + bool will_generate_frame() override; + QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) override; + private: QUICStream *_find_stream(QUICStreamId id); QUICStream *_find_or_create_stream(QUICStreamId stream_id); @@ -70,7 +73,6 @@ class QUICStreamManager : public QUICFrameHandler QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICConnectionId _connection_id = 0; - QUICFrameTransmitter *_tx = nullptr; QUICApplicationMap *_app_map = nullptr; std::shared_ptr _local_tp = nullptr; std::shared_ptr _remote_tp = nullptr; diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index b2a04c87a07..8e438f990b0 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -30,8 +30,7 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") { int ret = 0; - MockQUICFrameTransmitter tx; - QUICLocalConnectionFlowController fc(1024, &tx); + QUICLocalConnectionFlowController fc(1024); // Check initial state CHECK(fc.current_offset() == 0); @@ -71,11 +70,12 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") CHECK(ret != 0); // MAX_STREAM_DATA - CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_DATA)] == 0); fc.forward_limit(2048); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 2048); - CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_DATA)] == 1); + QUICFrameUPtr frame = fc.generate_frame(); + CHECK(frame); + CHECK(frame->type() == QUICFrameType::MAX_DATA); ret = fc.update(1280); CHECK(fc.current_offset() == 1280); @@ -86,8 +86,7 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") { int ret = 0; - MockQUICFrameTransmitter tx; - QUICRemoteConnectionFlowController fc(1024, &tx); + QUICRemoteConnectionFlowController fc(1024); // Check initial state CHECK(fc.current_offset() == 0); @@ -121,12 +120,13 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") CHECK(ret == 0); // Exceed limit - CHECK(tx.frameCount[static_cast(QUICFrameType::BLOCKED)] == 0); ret = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); CHECK(ret != 0); - CHECK(tx.frameCount[static_cast(QUICFrameType::BLOCKED)] == 1); + QUICFrameUPtr frame = fc.generate_frame(); + CHECK(frame); + CHECK(frame->type() == QUICFrameType::BLOCKED); // MAX_STREAM_DATA fc.forward_limit(2048); @@ -142,8 +142,7 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") TEST_CASE("QUICFlowController_Local_Stream", "[quic]") { int ret = 0; - MockQUICFrameTransmitter tx; - QUICLocalStreamFlowController fc(1024, &tx, 0); + QUICLocalStreamFlowController fc(1024, 0); // Check initial state CHECK(fc.current_offset() == 0); @@ -183,11 +182,12 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]") CHECK(ret != 0); // MAX_STREAM_DATA - CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_STREAM_DATA)] == 0); fc.forward_limit(2048); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 2048); - CHECK(tx.frameCount[static_cast(QUICFrameType::MAX_STREAM_DATA)] == 1); + QUICFrameUPtr frame = fc.generate_frame(); + CHECK(frame); + CHECK(frame->type() == QUICFrameType::MAX_STREAM_DATA); ret = fc.update(1280); CHECK(fc.current_offset() == 1280); @@ -198,8 +198,7 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]") TEST_CASE("QUICFlowController_Remote_Stream", "[quic]") { int ret = 0; - MockQUICFrameTransmitter tx; - QUICRemoteStreamFlowController fc(1024, &tx, 0); + QUICRemoteStreamFlowController fc(1024, 0); // Check initial state CHECK(fc.current_offset() == 0); @@ -233,7 +232,6 @@ TEST_CASE("QUICFlowController_Remote_Stream", "[quic]") CHECK(ret == 0); // Exceed limit - CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM_BLOCKED)] == 0); ret = fc.update(1280); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index ac37d8b7f5f..dcd12b4d699 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1099,7 +1099,7 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") { - QUICStream stream(new MockQUICFrameTransmitter(), 0, 0x1234, 0, 0); + QUICStream stream(0, 0x1234, 0, 0); std::unique_ptr error = std::unique_ptr(new QUICStreamError(&stream, static_cast(0x01))); std::unique_ptr rst_stream_frame1 = diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc index 30268d40c33..2f5d47fd156 100644 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -61,7 +61,6 @@ TEST_CASE("1-RTT handshake ", "[quic]") QUICHandshake *server = new QUICHandshake(server_qc, server_ssl_ctx, server_token, false); // setup stream 0 - MockQUICFrameTransmitter tx; QUICStream *stream = new MockQUICStream(); MockQUICStreamIO *stream_io = new MockQUICStreamIO(nullptr, stream); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 8d1dec549cc..0e6331a478f 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -68,9 +68,8 @@ TEST_CASE("QUICStream", "[quic]") { MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICFrameTransmitter tx; - std::unique_ptr stream(new QUICStream(&tx, 0, stream_id, 1024, 1024)); + std::unique_ptr stream(new QUICStream(0, stream_id, 1024, 1024)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_1); @@ -94,9 +93,8 @@ TEST_CASE("QUICStream", "[quic]") { MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICFrameTransmitter tx; - std::unique_ptr stream(new QUICStream(&tx, 0, stream_id)); + std::unique_ptr stream(new QUICStream(0, stream_id)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -120,9 +118,8 @@ TEST_CASE("QUICStream", "[quic]") { MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICFrameTransmitter tx; - std::unique_ptr stream(new QUICStream(&tx, 0, stream_id)); + std::unique_ptr stream(new QUICStream(0, stream_id)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -150,9 +147,8 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICFrameTransmitter tx; - std::unique_ptr stream(new QUICStream(&tx, 0, stream_id)); + std::unique_ptr stream(new QUICStream(0, stream_id)); stream->init_flow_control_params(4096, 4096); stream->do_io_read(nullptr, 0, read_buffer); @@ -187,45 +183,64 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *read_buffer_reader = read_buffer->alloc_reader(); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - MockQUICFrameTransmitter tx; - std::unique_ptr stream(new QUICStream(&tx, 0, stream_id)); + std::unique_ptr stream(new QUICStream(0, stream_id)); stream->init_flow_control_params(4096, 4096); MockContinuation mock_cont(stream->mutex); stream->do_io_read(nullptr, 0, read_buffer); stream->do_io_write(&mock_cont, 0, write_buffer_reader); - // Check the initial state - CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 0); - const char data[1024] = {0}; + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 1); + CHECK(stream->will_generate_frame() == true); + frame = stream->generate_frame(4096, 4096); + CHECK(frame->type() == QUICFrameType::MAX_STREAM_DATA); + CHECK(stream->will_generate_frame() == true); + frame = stream->generate_frame(4096, 4096); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame() == false); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 2); + CHECK(stream->will_generate_frame() == true); + frame = stream->generate_frame(4096, 4096); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame() == false); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 3); + CHECK(stream->will_generate_frame() == true); + frame = stream->generate_frame(4096, 4096); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame() == false); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 4); + CHECK(stream->will_generate_frame() == true); + frame = stream->generate_frame(4096, 4096); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame() == false); // This should not send a frame because of flow control write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 4); + CHECK(stream->will_generate_frame() == true); + frame = stream->generate_frame(4096, 4096); + CHECK(frame); + CHECK(frame->type() == QUICFrameType::STREAM_BLOCKED); + CHECK(stream->will_generate_frame() == true); // Update window stream->recv(std::make_shared(stream_id, 5120)); // This should send a frame stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 5); + CHECK(stream->will_generate_frame() == true); + frame = stream->generate_frame(4096, 4096); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame() == false); // Update window stream->recv(std::make_shared(stream_id, 5632)); @@ -233,15 +248,23 @@ TEST_CASE("QUICStream", "[quic]") // This should send a frame write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 6); + CHECK(stream->will_generate_frame() == true); + frame = stream->generate_frame(4096, 4096); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame() == true); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 6); + CHECK(stream->will_generate_frame() == true); + frame = stream->generate_frame(4096, 4096); + CHECK(frame->type() == QUICFrameType::STREAM_BLOCKED); // Update window stream->recv(std::make_shared(stream_id, 6144)); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(tx.frameCount[static_cast(QUICFrameType::STREAM)] == 7); + CHECK(stream->will_generate_frame() == true); + frame = stream->generate_frame(4096, 4096); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame() == false); } } diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 54af018796b..c05794e89ed 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -31,11 +31,10 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") { - MockQUICFrameTransmitter tx; QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(0, &tx, &app_map); + QUICStreamManager sm(0, &app_map); std::shared_ptr local_tp = std::make_shared(static_cast(0)); std::shared_ptr remote_tp = @@ -78,11 +77,10 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") { - MockQUICFrameTransmitter tx; QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(0, &tx, &app_map); + QUICStreamManager sm(0, &app_map); std::shared_ptr local_tp = std::make_shared(static_cast(0)); std::shared_ptr remote_tp = @@ -99,11 +97,10 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") { - MockQUICFrameTransmitter tx; QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(0, &tx, &app_map); + QUICStreamManager sm(0, &app_map); std::shared_ptr local_tp = std::make_shared(static_cast(0)); local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); @@ -133,11 +130,10 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") { - MockQUICFrameTransmitter tx; QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(0, &tx, &app_map); + QUICStreamManager sm(0, &app_map); std::shared_ptr local_tp = std::make_shared(static_cast(0)); local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); From b7c07e5b45c7ec0cc2eb6f2a8e0f47ccdb1401bb Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 30 Mar 2018 10:52:37 +0900 Subject: [PATCH 0473/1313] Update packet recovery logic to draft-10 --- iocore/net/quic/QUICCongestionController.cc | 10 ++++++++-- iocore/net/quic/QUICLossDetector.cc | 4 ++-- iocore/net/quic/QUICLossDetector.h | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index d06c0903bed..44f4de9da9e 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -41,12 +41,18 @@ QUICCongestionController::on_packet_sent(size_t bytes_sent) this->_bytes_in_flight += bytes_sent; } +bool +QUICCongestionController::_in_recovery(QUICPacketNumber packet_number) +{ + return packet_number <= this->_end_of_recovery; +} + void QUICCongestionController::on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size) { // Remove from bytes_in_flight. this->_bytes_in_flight -= acked_packet_size; - if (acked_packet_number < this->_end_of_recovery) { + if (this->_in_recovery(acked_packet_number)) { // Do not increase congestion window in recovery period. return; } @@ -69,7 +75,7 @@ QUICCongestionController::on_packets_lost(std::mapfirst; // Start a new recovery epoch if the lost packet is larger // than the end of the previous recovery epoch. - if (this->_end_of_recovery < largest_lost_packet) { + if (!this->_in_recovery(largest_lost_packet)) { this->_end_of_recovery = largest_lost_packet; this->_congestion_window *= LOSS_REDUCTION_FACTOR; this->_congestion_window = std::max(this->_congestion_window, MINIMUM_WINDOW); diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 015d0613d1f..68a0ba1bfc1 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -299,7 +299,7 @@ QUICLossDetector::_set_loss_detection_alarm() } else { alarm_duration = 2 * this->_smoothed_rtt; } - alarm_duration = std::max(alarm_duration, MIN_TLP_TIMEOUT); + alarm_duration = std::max(alarm_duration + this->_max_ack_delay, MIN_TLP_TIMEOUT); alarm_duration = alarm_duration * (1 << this->_handshake_count); QUICLDDebug("Handshake retransmission alarm will be set"); } else if (this->_loss_time != 0) { @@ -312,7 +312,7 @@ QUICLossDetector::_set_loss_detection_alarm() QUICLDDebug("TLP alarm will be set"); } else { // RTO alarm - alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar; + alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; alarm_duration = std::max(alarm_duration, MIN_RTO_TIMEOUT); alarm_duration = alarm_duration * (1 << this->_rto_count); QUICLDDebug("RTO alarm will be set"); diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 7a34d89255d..d6e21e71ed9 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -63,6 +63,8 @@ class QUICCongestionController uint32_t _congestion_window = 0; QUICPacketNumber _end_of_recovery = 0; uint32_t _ssthresh = UINT32_MAX; + + bool _in_recovery(QUICPacketNumber packet_number); }; class QUICLossDetector : public Continuation, public QUICFrameHandler From 830ed665bb245b0c83aa9eb985559b55c87dc548 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 30 Mar 2018 11:49:46 +0900 Subject: [PATCH 0474/1313] Check if alt_con_manager is available alt_con_manager is not available until handshake completion --- iocore/net/QUICNetVConnection.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 460c547922c..0502b384c32 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -215,7 +215,9 @@ QUICNetVConnection::free(EThread *t) this->_ctable->erase(this->_original_quic_connection_id, this); this->_ctable->erase(this->_quic_connection_id, this); - this->_alt_con_manager->invalidate_alt_connections(); + if (this->_alt_con_manager) { + this->_alt_con_manager->invalidate_alt_connections(); + } /* TODO: Uncmment these blocks after refactoring read / write process this->_udp_con = nullptr; From 5c2a52c0b4323e4e4d4c5731cd5ce40caff95c58 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 30 Mar 2018 14:26:32 +0900 Subject: [PATCH 0475/1313] Make constants of Loss Detector configurable Add below configs ``` proxy.config.quic.loss_detection.max_tlps proxy.config.quic.loss_detection.reordering_threshold proxy.config.quic.loss_detection.time_reordering_fraction proxy.config.quic.loss_detection.using_time_loss_detection proxy.config.quic.loss_detection.min_tlp_timeout proxy.config.quic.loss_detection.min_rto_timeout proxy.config.quic.loss_detection.delayed_ack_timeout proxy.config.quic.loss_detection.default_initial_rtt ``` --- iocore/net/quic/QUICConfig.cc | 66 +++++++++++++++++++++++++++++ iocore/net/quic/QUICConfig.h | 28 ++++++++++-- iocore/net/quic/QUICLossDetector.cc | 46 ++++++++++---------- iocore/net/quic/QUICLossDetector.h | 21 ++++++--- mgmt/RecordsConfig.cc | 17 ++++++++ 5 files changed, 146 insertions(+), 32 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 84d8e9ee2d5..1f3661b7e82 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -124,6 +124,24 @@ QUICConfigParams::initialize() 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_EstablishStaticConfigInt32U(this->_ld_max_tlps, "proxy.config.quic.loss_detection.max_tlps"); + REC_EstablishStaticConfigInt32U(this->_ld_reordering_threshold, "proxy.config.quic.loss_detection.reordering_threshold"); + REC_EstablishStaticConfigFloat(this->_ld_time_reordering_fraction, "proxy.config.quic.loss_detection.time_reordering_fraction"); + REC_EstablishStaticConfigInt32U(this->_ld_time_loss_detection, "proxy.config.quic.loss_detection.using_time_loss_detection"); + + uint32_t timeout = 0; + REC_EstablishStaticConfigInt32U(timeout, "proxy.config.quic.loss_detection.min_tlp_timeout"); + this->_ld_min_tlp_timeout = HRTIME_MSECONDS(timeout); + + REC_EstablishStaticConfigInt32U(timeout, "proxy.config.quic.loss_detection.min_rto_timeout"); + this->_ld_min_rto_timeout = HRTIME_MSECONDS(timeout); + + REC_EstablishStaticConfigInt32U(timeout, "proxy.config.quic.loss_detection.delayed_ack_timeout"); + this->_ld_delayed_ack_timeout = HRTIME_MSECONDS(timeout); + + REC_EstablishStaticConfigInt32U(timeout, "proxy.config.quic.loss_detection.default_initial_rtt"); + this->_ld_default_initial_rtt = HRTIME_MSECONDS(timeout); + QUICStatelessRetry::init(); this->_server_ssl_ctx = quic_init_server_ssl_ctx(this); @@ -220,6 +238,54 @@ QUICConfigParams::client_ssl_ctx() const return this->_client_ssl_ctx; } +uint32_t +QUICConfigParams::ld_max_tlps() const +{ + return _ld_max_tlps; +} + +uint32_t +QUICConfigParams::ld_reordering_threshold() const +{ + return _ld_reordering_threshold; +} + +float +QUICConfigParams::ld_time_reordering_fraction() const +{ + return _ld_time_reordering_fraction; +} + +uint32_t +QUICConfigParams::ld_time_loss_detection() const +{ + return _ld_time_loss_detection; +} + +ink_hrtime +QUICConfigParams::ld_min_tlp_timeout() const +{ + return _ld_min_tlp_timeout; +} + +ink_hrtime +QUICConfigParams::ld_min_rto_timeout() const +{ + return _ld_min_rto_timeout; +} + +ink_hrtime +QUICConfigParams::ld_delayed_ack_timeout() const +{ + return _ld_delayed_ack_timeout; +} + +ink_hrtime +QUICConfigParams::ld_default_initial_rtt() const +{ + return _ld_default_initial_rtt; +} + // // QUICConfig // diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 1fc1797ceaf..a2fb0ed1a9a 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -52,27 +52,47 @@ class QUICConfigParams : public ConfigInfo SSL_CTX *server_ssl_ctx() const; SSL_CTX *client_ssl_ctx() const; + uint32_t ld_max_tlps() const; + uint32_t ld_reordering_threshold() const; + float ld_time_reordering_fraction() const; + uint32_t ld_time_loss_detection() const; + ink_hrtime ld_min_tlp_timeout() const; + ink_hrtime ld_min_rto_timeout() const; + ink_hrtime ld_delayed_ack_timeout() const; + ink_hrtime ld_default_initial_rtt() const; + private: + static int _connection_table_size; + // FIXME Fill appropriate default values in RecordsConfig.cc uint32_t _no_activity_timeout_in = 0; uint32_t _no_activity_timeout_out = 0; uint32_t _initial_max_data = 0; uint32_t _initial_max_stream_data = 0; uint32_t _server_id = 0; - static int _connection_table_size; - uint32_t _stateless_retry = 0; + uint32_t _stateless_retry = 0; uint32_t _initial_max_stream_id_bidi_in = 100; uint32_t _initial_max_stream_id_bidi_out = 101; uint32_t _initial_max_stream_id_uni_in = 102; uint32_t _initial_max_stream_id_uni_out = 103; - char *_server_supported_groups; - char *_client_supported_groups; + char *_server_supported_groups = nullptr; + char *_client_supported_groups = nullptr; // TODO: integrate with SSLCertLookup or SNIConfigParams SSL_CTX *_server_ssl_ctx = nullptr; SSL_CTX *_client_ssl_ctx = nullptr; + + // [draft-10 recovery] - 3.4.1. Constants of interest + uint32_t _ld_max_tlps = 2; + uint32_t _ld_reordering_threshold = 3; + float _ld_time_reordering_fraction = 0.125; + uint32_t _ld_time_loss_detection = 0; + ink_hrtime _ld_min_tlp_timeout = HRTIME_MSECONDS(10); + ink_hrtime _ld_min_rto_timeout = HRTIME_MSECONDS(200); + ink_hrtime _ld_delayed_ack_timeout = HRTIME_MSECONDS(25); + ink_hrtime _ld_default_initial_rtt = HRTIME_MSECONDS(100); }; class QUICConfig diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 68a0ba1bfc1..ddeaf217933 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -22,34 +22,36 @@ */ #include "QUICLossDetector.h" -#include "QUICEvents.h" + #include "ts/ink_assert.h" +#include "QUICConfig.h" +#include "QUICEvents.h" + #define QUICLDDebug(fmt, ...) \ Debug("quic_loss_detector", "[%" PRIx64 "] " fmt, static_cast(this->_connection_id), ##__VA_ARGS__) -// 3.4.1. Constants of interest (draft-08) -// Keep the order as the same as the spec so that we can see the difference easily. -constexpr static uint32_t MAX_TLPS = 2; -constexpr static uint32_t REORDERING_THRESHOLD = 3; -constexpr static double TIME_REORDERING_FRACTION = 1.0 / 8.0; -constexpr static ink_hrtime MIN_TLP_TIMEOUT = HRTIME_MSECONDS(10); -constexpr static ink_hrtime MIN_RTO_TIMEOUT = HRTIME_MSECONDS(200); -// This is defined on the spec but not used -// constexpr static ink_hrtime DELAYED_ACK_TIMEOUT = HRTIME_MSECONDS(25); -constexpr static ink_hrtime DEFAULT_INITIAL_RTT = HRTIME_MSECONDS(100); - QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICCongestionController *cc) : _transmitter(transmitter), _cc(cc) { this->mutex = new_ProxyMutex(); this->_loss_detection_mutex = new_ProxyMutex(); - if (this->_time_loss_detection) { + QUICConfig::scoped_config params; + this->_k_max_tlps = params->ld_max_tlps(); + this->_k_reordering_threshold = params->ld_reordering_threshold(); + this->_k_time_reordering_fraction = params->ld_time_reordering_fraction(); + this->_k_using_time_loss_detection = params->ld_time_loss_detection(); + this->_k_min_tlp_timeout = params->ld_min_tlp_timeout(); + this->_k_min_rto_timeout = params->ld_min_rto_timeout(); + this->_k_delayed_ack_timeout = params->ld_delayed_ack_timeout(); + this->_k_default_initial_rtt = params->ld_default_initial_rtt(); + + if (this->_k_using_time_loss_detection) { this->_reordering_threshold = UINT32_MAX; - this->_time_reordering_fraction = TIME_REORDERING_FRACTION; + this->_time_reordering_fraction = this->_k_time_reordering_fraction; } else { - this->_reordering_threshold = REORDERING_THRESHOLD; + this->_reordering_threshold = this->_k_reordering_threshold; this->_time_reordering_fraction = INFINITY; } @@ -295,25 +297,25 @@ QUICLossDetector::_set_loss_detection_alarm() if (this->_handshake_outstanding) { // Handshake retransmission alarm. if (this->_smoothed_rtt == 0) { - alarm_duration = 2 * DEFAULT_INITIAL_RTT; + alarm_duration = 2 * this->_k_default_initial_rtt; } else { alarm_duration = 2 * this->_smoothed_rtt; } - alarm_duration = std::max(alarm_duration + this->_max_ack_delay, MIN_TLP_TIMEOUT); + alarm_duration = std::max(alarm_duration + this->_max_ack_delay, this->_k_min_tlp_timeout); alarm_duration = alarm_duration * (1 << this->_handshake_count); QUICLDDebug("Handshake retransmission alarm will be set"); } else if (this->_loss_time != 0) { // Early retransmit timer or time loss detection. alarm_duration = this->_loss_time - this->_time_of_last_sent_packet; QUICLDDebug("Early retransmit timer or time loss detection will be set"); - } else if (this->_tlp_count < MAX_TLPS) { + } else if (this->_tlp_count < this->_k_max_tlps) { // Tail Loss Probe - alarm_duration = std::max(static_cast(1.5 * this->_smoothed_rtt + this->_max_ack_delay), MIN_TLP_TIMEOUT); + alarm_duration = std::max(static_cast(1.5 * this->_smoothed_rtt + this->_max_ack_delay), this->_k_min_tlp_timeout); QUICLDDebug("TLP alarm will be set"); } else { // RTO alarm alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; - alarm_duration = std::max(alarm_duration, MIN_RTO_TIMEOUT); + alarm_duration = std::max(alarm_duration, this->_k_min_rto_timeout); alarm_duration = alarm_duration * (1 << this->_rto_count); QUICLDDebug("RTO alarm will be set"); } @@ -348,7 +350,7 @@ QUICLossDetector::_on_loss_detection_alarm() } else if (this->_loss_time != 0) { // Early retransmit or Time Loss Detection this->_detect_lost_packets(this->_largest_acked_packet); - } else if (this->_tlp_count < MAX_TLPS) { + } else if (this->_tlp_count < this->_k_max_tlps) { // Tail Loss Probe. QUICLDDebug("TLP"); // FIXME TLP causes inifinite loop somehow @@ -377,7 +379,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num std::map lost_packets; double delay_until_lost = INFINITY; - if (this->_time_loss_detection) { + if (this->_k_using_time_loss_detection) { delay_until_lost = (1 + this->_time_reordering_fraction) * std::max(this->_latest_rtt, this->_smoothed_rtt); } else if (largest_acked_packet_number == this->_largest_sent_packet) { // Early retransmit alarm. diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index d6e21e71ed9..b129b4a9d82 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -86,11 +86,20 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler QUICConnectionId _connection_id = 0; - bool _time_loss_detection = true; - // TODO QUICCongestionController *cc = nullptr; - // 3.4.2. Variables of interest (draft-08) + // 3.4.1. Constants of interest (draft-10) + // Values will be loaded from records.config via QUICConfig at constructor + uint32_t _k_max_tlps = 0; + uint32_t _k_reordering_threshold = 0; + float _k_time_reordering_fraction = 0.0; + bool _k_using_time_loss_detection = false; + ink_hrtime _k_min_tlp_timeout = 0; + ink_hrtime _k_min_rto_timeout = 0; + ink_hrtime _k_delayed_ack_timeout = 0; + ink_hrtime _k_default_initial_rtt = 0; + + // 3.4.2. Variables of interest (draft-10) // Keep the order as the same as the spec so that we can see the difference easily. Action *_loss_detection_alarm = nullptr; uint32_t _handshake_count = 0; @@ -105,9 +114,9 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler ink_hrtime _rttvar = 0; ink_hrtime _min_rtt = 0; ink_hrtime _max_ack_delay = 0; - uint32_t _reordering_threshold; - double _time_reordering_fraction; - ink_hrtime _loss_time = 0; + uint32_t _reordering_threshold = 0; + double _time_reordering_fraction = 0.0; + ink_hrtime _loss_time = 0; std::map> _sent_packets; // These are not defined on the spec but expected to be count diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 50328584068..85bd71a9728 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1334,6 +1334,23 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.client.supported_groups", RECD_STRING, "P-256:X25519:P-384:P-521" , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , + // Constants of Loss Detection + {RECT_CONFIG, "proxy.config.quic.loss_detection.max_tlps", RECD_INT, "2", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.loss_detection.reordering_threshold", RECD_INT, "3", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.loss_detection.time_reordering_fraction", RECD_FLOAT, "0.125", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[\\.0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.loss_detection.using_time_loss_detection", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "[0-1]", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.loss_detection.min_tlp_timeout", RECD_INT, "10", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.loss_detection.min_rto_timeout", RECD_INT, "200", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.loss_detection.delayed_ack_timeout", RECD_INT, "25", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.loss_detection.default_initial_rtt", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , //# Add LOCAL Records Here {RECT_LOCAL, "proxy.local.incoming_ip_to_bind", RECD_STRING, nullptr, RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL} From e7babfd06a1db965415110b2df0052cc1f039b88 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 30 Mar 2018 14:44:03 +0900 Subject: [PATCH 0476/1313] Initialize RecordsConfig and QUICConfig on unit test - Load configs written in mgmt/RecordsConfig.cc - Start QUICConfig up --- iocore/net/quic/test/Makefile.am | 98 +++++++++----------- iocore/net/quic/test/event_processor_main.cc | 9 +- iocore/net/quic/test/main.cc | 10 ++ iocore/net/quic/test/stub_QUICConfig.cc | 4 +- 4 files changed, 64 insertions(+), 57 deletions(-) diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 1c4b445cf5d..e492ea31e8f 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -60,6 +60,16 @@ QUICKeyGenerator_impl = ../QUICKeyGenerator_openssl.cc QUICTLS_impl = ../QUICTLS_openssl.cc endif +catch_main = \ + main.cc \ + stub_QUICConfig.cc \ + ../../SSLNextProtocolSet.cc + +catch_event_processor_main = \ + event_processor_main.cc \ + stub_QUICConfig.cc \ + ../../SSLNextProtocolSet.cc + # # test_QUICPacket # @@ -70,7 +80,7 @@ test_QUICPacket_LDFLAGS = \ @AM_LDFLAGS@ test_QUICPacket_SOURCES = \ - event_processor_main.cc \ + $(catch_main) \ test_QUICPacket.cc \ ../QUICPacket.cc \ ../QUICHandshakeProtocol.cc \ @@ -99,7 +109,7 @@ test_QUICPacketFactory_LDFLAGS = \ @AM_LDFLAGS@ test_QUICPacketFactory_SOURCES = \ - event_processor_main.cc \ + $(catch_main) \ test_QUICPacketFactory.cc \ ../QUICPacket.cc \ ../QUICHandshakeProtocol.cc \ @@ -129,7 +139,7 @@ test_QUICFrame_LDFLAGS = \ @AM_LDFLAGS@ test_QUICFrame_SOURCES = \ - main.cc \ + $(catch_main) \ test_QUICFrame.cc \ ../QUICGlobals.cc \ ../QUICFrame.cc \ @@ -146,14 +156,15 @@ test_QUICFrame_SOURCES = \ ../QUICStreamState.cc \ ../QUICIncomingFrameBuffer.cc \ ../QUICDebugNames.cc \ - ../QUICFlowController.cc \ - ../../SSLNextProtocolSet.cc + ../QUICFlowController.cc test_QUICFrame_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a + # # test_QUICFrameDispatcher @@ -165,11 +176,10 @@ test_QUICFrameDispatcher_LDFLAGS = \ @AM_LDFLAGS@ test_QUICFrameDispatcher_SOURCES = \ - main.cc \ + $(catch_main) \ test_QUICFrameDispatcher.cc \ ../QUICGlobals.cc \ ../QUICConfig.cc \ - stub_QUICConfig.cc \ ../QUICVersionNegotiator.cc \ ../QUICFrameDispatcher.cc \ ../QUICTransportParameters.cc \ @@ -194,8 +204,7 @@ test_QUICFrameDispatcher_SOURCES = \ $(QUICTLS_impl) \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ - ../QUICHKDF.cc \ - ../../SSLNextProtocolSet.cc + ../QUICHKDF.cc test_QUICFrameDispatcher_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -218,7 +227,7 @@ test_QUICStreamState_LDFLAGS = \ @AM_LDFLAGS@ test_QUICStreamState_SOURCES = \ - main.cc \ + $(catch_main) \ test_QUICStreamState.cc \ ../QUICStreamState.cc @@ -242,16 +251,14 @@ test_QUICStream_LDFLAGS = \ @AM_LDFLAGS@ test_QUICStream_SOURCES = \ - event_processor_main.cc \ + $(catch_event_processor_main) \ test_QUICStream.cc \ ../QUICStream.cc \ ../QUICIncomingFrameBuffer.cc \ ../QUICFrameDispatcher.cc \ ../QUICStreamManager.cc \ ../QUICApplicationMap.cc \ - ../QUICCongestionController.cc \ - ../../SSLNextProtocolSet.cc \ - stub_QUICConfig.cc + ../QUICCongestionController.cc test_QUICStream_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -274,7 +281,7 @@ test_QUICStreamManager_LDFLAGS = \ @AM_LDFLAGS@ test_QUICStreamManager_SOURCES = \ - event_processor_main.cc \ + $(catch_event_processor_main) \ test_QUICStreamManager.cc \ ../QUICStream.cc \ ../QUICIncomingFrameBuffer.cc \ @@ -282,9 +289,7 @@ test_QUICStreamManager_SOURCES = \ ../QUICStreamManager.cc \ ../QUICApplicationMap.cc \ ../QUICCongestionController.cc \ - ../../SSLNextProtocolSet.cc \ - ../QUICConfig.cc \ - stub_QUICConfig.cc + ../QUICConfig.cc test_QUICStreamManager_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -307,11 +312,10 @@ test_QUICTransportParameters_LDFLAGS = \ @AM_LDFLAGS@ test_QUICTransportParameters_SOURCES = \ - main.cc \ + $(catch_main) \ test_QUICTransportParameters.cc \ ../QUICGlobals.cc \ ../QUICConfig.cc \ - stub_QUICConfig.cc \ ../QUICApplication.cc \ ../QUICApplicationMap.cc \ ../QUICHandshake.cc \ @@ -332,8 +336,7 @@ test_QUICTransportParameters_SOURCES = \ ../QUICDebugNames.cc \ ../QUICTransportParameters.cc \ ../QUICTypes.cc \ - ../QUICIntUtil.cc \ - ../../SSLNextProtocolSet.cc + ../QUICIntUtil.cc test_QUICTransportParameters_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -359,10 +362,11 @@ test_QUICKeyGenerator_LDADD = \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - $(top_builddir)/iocore/eventsystem/libinkevent.a + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a test_QUICKeyGenerator_SOURCES = \ - main.cc \ + $(catch_main) \ test_QUICKeyGenerator.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ @@ -393,11 +397,12 @@ test_QUICHandshakeProtocol_LDADD = \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ @LIBTCL@ \ @OPENSSL_LIBS@ test_QUICHandshakeProtocol_SOURCES = \ - main.cc \ + $(catch_main) \ test_QUICHandshakeProtocol.cc \ ../QUICKeyGenerator.cc \ $(QUICKeyGenerator_impl) \ @@ -415,8 +420,7 @@ test_QUICHandshakeProtocol_SOURCES = \ ../QUICPacket.cc \ ../QUICIncomingFrameBuffer.cc \ ../QUICFlowController.cc \ - ../QUICGlobals.cc \ - ../../SSLNextProtocolSet.cc + ../QUICGlobals.cc # # test_QUICLossDetector @@ -439,7 +443,7 @@ test_QUICLossDetector_LDADD = \ @HWLOC_LIBS@ test_QUICLossDetector_SOURCES = \ - event_processor_main.cc \ + $(catch_event_processor_main) \ test_QUICLossDetector.cc \ ../QUICLossDetector.cc \ ../QUICTypes.cc \ @@ -447,9 +451,7 @@ test_QUICLossDetector_SOURCES = \ ../QUICHandshakeProtocol.cc \ ../QUICTLS.cc \ $(QUICTLS_impl) \ - ../QUICFrame.cc \ - ../../SSLNextProtocolSet.cc \ - stub_QUICConfig.cc + ../QUICFrame.cc # # test_QUICTypeUtil @@ -470,7 +472,7 @@ test_QUICTypeUtil_LDADD = \ @OPENSSL_LIBS@ test_QUICTypeUtil_SOURCES = \ - main.cc \ + $(catch_main) \ test_QUICTypeUtil.cc \ ../QUICStream.cc \ ../QUICIncomingFrameBuffer.cc \ @@ -486,9 +488,7 @@ test_QUICTypeUtil_SOURCES = \ ../QUICTLS.cc \ $(QUICTLS_impl) \ ../QUICIntUtil.cc \ - ../QUICTypes.cc \ - ../../SSLNextProtocolSet.cc \ - stub_QUICConfig.cc + ../QUICTypes.cc # # test_QUICAckFrameCreator @@ -508,7 +508,7 @@ test_QUICAckFrameCreator_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la test_QUICAckFrameCreator_SOURCES = \ - main.cc \ + $(catch_main) \ test_QUICAckFrameCreator.cc \ ../QUICAckFrameCreator.cc \ ../QUICGlobals.cc \ @@ -526,9 +526,7 @@ test_QUICAckFrameCreator_SOURCES = \ ../QUICHKDF.cc \ ../QUICHandshakeProtocol.cc \ ../QUICTLS.cc \ - $(QUICTLS_impl) \ - ../../SSLNextProtocolSet.cc \ - stub_QUICConfig.cc + $(QUICTLS_impl) # # test_QUICTypeUtil @@ -551,7 +549,7 @@ test_QUICVersionNegotiator_LDADD = \ @HWLOC_LIBS@ test_QUICVersionNegotiator_SOURCES = \ - main.cc \ + $(catch_main) \ test_QUICVersionNegotiator.cc \ ../QUICGlobals.cc \ ../QUICTypes.cc \ @@ -575,9 +573,7 @@ test_QUICVersionNegotiator_SOURCES = \ ../QUICDebugNames.cc \ ../QUICVersionNegotiator.cc \ ../QUICTransportParameters.cc \ - ../QUICConfig.cc \ - stub_QUICConfig.cc \ - ../../SSLNextProtocolSet.cc + ../QUICConfig.cc # # test_QUICFlowController @@ -600,7 +596,7 @@ test_QUICFlowController_LDADD = \ @HWLOC_LIBS@ test_QUICFlowController_SOURCES = \ - main.cc \ + $(catch_main) \ test_QUICFlowController.cc \ ../QUICFlowController.cc \ ../QUICStream.cc \ @@ -628,16 +624,14 @@ test_QUICIncomingFrameBuffer_LDFLAGS = \ @AM_LDFLAGS@ test_QUICIncomingFrameBuffer_SOURCES = \ - event_processor_main.cc \ + $(catch_event_processor_main) \ ../QUICStream.cc \ ../QUICFrameDispatcher.cc \ ../QUICStreamManager.cc \ ../QUICApplicationMap.cc \ ../QUICCongestionController.cc \ - ../../SSLNextProtocolSet.cc \ ../QUICIncomingFrameBuffer.cc \ - test_QUICIncomingFrameBuffer.cc \ - stub_QUICConfig.cc + test_QUICIncomingFrameBuffer.cc test_QUICIncomingFrameBuffer_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -660,11 +654,9 @@ test_QUICHandshake_LDFLAGS = \ @AM_LDFLAGS@ test_QUICHandshake_SOURCES = \ - event_processor_main.cc \ + $(catch_event_processor_main) \ test_QUICHandshake.cc \ - ../QUICHandshake.cc \ - ../../SSLNextProtocolSet.cc \ - stub_QUICConfig.cc + ../QUICHandshake.cc test_QUICHandshake_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ diff --git a/iocore/net/quic/test/event_processor_main.cc b/iocore/net/quic/test/event_processor_main.cc index 9132a389de2..44cb8ec012c 100644 --- a/iocore/net/quic/test/event_processor_main.cc +++ b/iocore/net/quic/test/event_processor_main.cc @@ -26,10 +26,14 @@ #define CATCH_CONFIG_MAIN #include "catch.hpp" -#include "I_EventSystem.h" #include "ts/I_Layout.h" #include "ts/Diags.h" +#include "I_EventSystem.h" +#include "RecordsConfig.h" + +#include "QUICConfig.h" + #define TEST_THREADS 1 struct EventProcessorListener : Catch::TestEventListenerBase { @@ -46,6 +50,9 @@ struct EventProcessorListener : Catch::TestEventListenerBase { Layout::create(); RecProcessInit(RECM_STAND_ALONE); + LibRecordsConfigInit(); + + QUICConfig::startup(); ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); eventProcessor.start(TEST_THREADS); diff --git a/iocore/net/quic/test/main.cc b/iocore/net/quic/test/main.cc index f611f5e04e1..c3813f33204 100644 --- a/iocore/net/quic/test/main.cc +++ b/iocore/net/quic/test/main.cc @@ -26,8 +26,12 @@ #define CATCH_CONFIG_MAIN #include "catch.hpp" +#include "ts/I_Layout.h" #include "ts/Diags.h" +#include "RecordsConfig.h" +#include "QUICConfig.h" + struct EventProcessorListener : Catch::TestEventListenerBase { using TestEventListenerBase::TestEventListenerBase; // inherit constructor @@ -39,6 +43,12 @@ struct EventProcessorListener : Catch::TestEventListenerBase { diags->activate_taglist("vv_quic|quic", DiagsTagType_Debug); diags->config.enabled[DiagsTagType_Debug] = true; diags->show_location = SHOW_LOCATION_DEBUG; + + Layout::create(); + RecProcessInit(RECM_STAND_ALONE); + LibRecordsConfigInit(); + + QUICConfig::startup(); } }; CATCH_REGISTER_LISTENER(EventProcessorListener); diff --git a/iocore/net/quic/test/stub_QUICConfig.cc b/iocore/net/quic/test/stub_QUICConfig.cc index 22f7f81309c..aa817abcea3 100644 --- a/iocore/net/quic/test/stub_QUICConfig.cc +++ b/iocore/net/quic/test/stub_QUICConfig.cc @@ -27,19 +27,17 @@ bool SSLParseCertificateConfiguration(const SSLConfigParams *, SSL_CTX *) { - ink_assert(false); return false; } SSLConfigParams * SSLConfig::acquire() { - ink_assert(false); return nullptr; } void SSLConfig::release(SSLConfigParams *) { - ink_assert(false); + return; } From 567f567ee4a33aadeb6156d6e8d890203b7f13f9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 30 Mar 2018 15:56:04 +0900 Subject: [PATCH 0477/1313] Cleanup Makefile.am of unit test for QUIC --- iocore/net/quic/test/Makefile.am | 168 +++++-------------------------- 1 file changed, 27 insertions(+), 141 deletions(-) diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index e492ea31e8f..ee0863d821d 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -36,7 +36,6 @@ check_PROGRAMS = \ test_QUICIncomingFrameBuffer \ test_QUICHandshake - AM_CPPFLAGS += \ $(iocore_include_dirs) \ -I$(abs_top_srcdir)/lib \ @@ -70,6 +69,16 @@ catch_event_processor_main = \ stub_QUICConfig.cc \ ../../SSLNextProtocolSet.cc +test_LDADD = \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ \ + @HWLOC_LIBS@ + # # test_QUICPacket # @@ -89,15 +98,7 @@ test_QUICPacket_SOURCES = \ ../QUICTypes.cc test_QUICPacket_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ \ - @HWLOC_LIBS@ + $(test_LDADD) # # test_QUICPacketFactory @@ -118,15 +119,7 @@ test_QUICPacketFactory_SOURCES = \ ../QUICTypes.cc test_QUICPacketFactory_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ \ - @HWLOC_LIBS@ + $(test_LDADD) # # test_QUICFrame @@ -135,7 +128,6 @@ test_QUICFrame_CPPFLAGS = \ $(AM_CPPFLAGS) test_QUICFrame_LDFLAGS = \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ @AM_LDFLAGS@ test_QUICFrame_SOURCES = \ @@ -159,12 +151,7 @@ test_QUICFrame_SOURCES = \ ../QUICFlowController.cc test_QUICFrame_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a - + $(test_LDADD) # # test_QUICFrameDispatcher @@ -207,15 +194,7 @@ test_QUICFrameDispatcher_SOURCES = \ ../QUICHKDF.cc test_QUICFrameDispatcher_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ \ - @HWLOC_LIBS@ + $(test_LDADD) # # test_QUICStreamState @@ -232,14 +211,7 @@ test_QUICStreamState_SOURCES = \ ../QUICStreamState.cc test_QUICStreamState_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ \ - @HWLOC_LIBS@ + $(test_LDADD) # # test_QUICStream @@ -261,15 +233,7 @@ test_QUICStream_SOURCES = \ ../QUICCongestionController.cc test_QUICStream_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ \ - @HWLOC_LIBS@ + $(test_LDADD) # # test_QUICStreamManager @@ -292,15 +256,7 @@ test_QUICStreamManager_SOURCES = \ ../QUICConfig.cc test_QUICStreamManager_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ \ - @HWLOC_LIBS@ + $(test_LDADD) # # test_QUICTransportParameters @@ -339,13 +295,7 @@ test_QUICTransportParameters_SOURCES = \ ../QUICIntUtil.cc test_QUICTransportParameters_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a + $(test_LDADD) # # test_QUICKeyGenerator @@ -357,13 +307,7 @@ test_QUICKeyGenerator_LDFLAGS = \ @AM_LDFLAGS@ test_QUICKeyGenerator_LDADD = \ - @OPENSSL_LIBS@ \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a + $(test_LDADD) test_QUICKeyGenerator_SOURCES = \ $(catch_main) \ @@ -392,14 +336,7 @@ test_QUICHandshakeProtocol_LDFLAGS = \ @OPENSSL_LDFLAGS@ test_QUICHandshakeProtocol_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - @LIBTCL@ \ - @OPENSSL_LIBS@ + $(test_LDADD) test_QUICHandshakeProtocol_SOURCES = \ $(catch_main) \ @@ -432,15 +369,7 @@ test_QUICLossDetector_LDFLAGS = \ @AM_LDFLAGS@ test_QUICLossDetector_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ \ - @HWLOC_LIBS@ + $(test_LDADD) test_QUICLossDetector_SOURCES = \ $(catch_event_processor_main) \ @@ -463,13 +392,7 @@ test_QUICTypeUtil_LDFLAGS = \ @AM_LDFLAGS@ test_QUICTypeUtil_LDADD = \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - $(top_builddir)/lib/ts/libtsutil.la \ - @OPENSSL_LIBS@ + $(test_LDADD) test_QUICTypeUtil_SOURCES = \ $(catch_main) \ @@ -500,12 +423,7 @@ test_QUICAckFrameCreator_LDFLAGS = \ @AM_LDFLAGS@ test_QUICAckFrameCreator_LDADD = \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - $(top_builddir)/lib/ts/libtsutil.la + $(test_LDADD) test_QUICAckFrameCreator_SOURCES = \ $(catch_main) \ @@ -538,15 +456,7 @@ test_QUICVersionNegotiator_LDFLAGS = \ @AM_LDFLAGS@ test_QUICVersionNegotiator_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ \ - @HWLOC_LIBS@ + $(test_LDADD) test_QUICVersionNegotiator_SOURCES = \ $(catch_main) \ @@ -585,15 +495,7 @@ test_QUICFlowController_LDFLAGS = \ @AM_LDFLAGS@ test_QUICFlowController_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ \ - @HWLOC_LIBS@ + $(test_LDADD) test_QUICFlowController_SOURCES = \ $(catch_main) \ @@ -634,15 +536,7 @@ test_QUICIncomingFrameBuffer_SOURCES = \ test_QUICIncomingFrameBuffer.cc test_QUICIncomingFrameBuffer_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ \ - @HWLOC_LIBS@ + $(test_LDADD) # # test_QUICHandshake @@ -659,15 +553,7 @@ test_QUICHandshake_SOURCES = \ ../QUICHandshake.cc test_QUICHandshake_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ \ - @HWLOC_LIBS@ + $(test_LDADD) include $(top_srcdir)/build/tidy.mk From bb333b9379f8579f918bf940542b8e290615b34b Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 31 Mar 2018 08:32:52 +0800 Subject: [PATCH 0478/1313] QUIC: Fix compiler warning --- iocore/net/QUICNetVConnection.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 0502b384c32..96c1e062ca3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -774,7 +774,7 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) break; case QUICPacketType::PROTECTED: default: - QUICConDebug("Ignore %s(%" PRIu8 ") packet", QUICDebugNames::packet_type(packet->type()), packet->type()); + QUICConDebug("Ignore %s(%" PRIu8 ") packet", QUICDebugNames::packet_type(packet->type()), static_cast(packet->type())); error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); break; @@ -878,7 +878,7 @@ QUICNetVConnection::_state_common_receive_packet() error = this->_recv_and_ack(std::move(p)); break; default: - QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(p->type()), p->type()); + QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(p->type()), static_cast(p->type())); error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); break; From cef711994b9b676f1713bf4e79419d8f1c3a40fc Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 20 Feb 2018 11:26:38 +0800 Subject: [PATCH 0479/1313] add refcount to protect qvc --- iocore/net/P_QUICNetVConnection.h | 3 +- iocore/net/QUICClosedConCollector.cc | 5 ++-- iocore/net/QUICNet.cc | 26 ++++++++++++++++-- iocore/net/QUICNetVConnection.cc | 41 ++++++++++++++++++---------- 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e0baec556c2..6b34210ebac 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -142,7 +142,7 @@ class SSLNextProtocolSet; * WRITE: * Do nothing **/ -class QUICNetVConnection : public UnixNetVConnection, public QUICConnection +class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, public RefCountObj { using super = UnixNetVConnection; ///< Parent type. @@ -168,6 +168,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection int state_connection_draining(int event, Event *data); int state_connection_closed(int event, Event *data); void start(); + void remove_connection_ids(); void free(EThread *t) override; void destroy(EThread *t); diff --git a/iocore/net/QUICClosedConCollector.cc b/iocore/net/QUICClosedConCollector.cc index 19095fe4909..647468e1cf3 100644 --- a/iocore/net/QUICClosedConCollector.cc +++ b/iocore/net/QUICClosedConCollector.cc @@ -43,7 +43,7 @@ QUICClosedConCollector::_process_closed_connection(EThread *t) while ((qvc = this->_localClosedQueue.pop())) { if (qvc->shouldDestroy()) { - qvc->free(t); + qvc->destroy(t); } else { local_queue.push(qvc); } @@ -51,8 +51,9 @@ QUICClosedConCollector::_process_closed_connection(EThread *t) SList(QUICNetVConnection, closed_alink) aq(this->closedQueue.popall()); while ((qvc = aq.pop())) { + qvc->remove_connection_ids(); if (qvc->shouldDestroy()) { - qvc->free(t); + qvc->destroy(t); } else { local_queue.push(qvc); } diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index f73ba264982..f51c5ac70fb 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -31,11 +31,19 @@ QUICPollEvent::init(QUICConnection *con, UDPPacketInternal *packet) { this->con = con; this->packet = packet; + if (con != nullptr) { + static_cast(con)->refcount_inc(); + } } void QUICPollEvent::free() { + if (this->con != nullptr) { + ink_assert(static_cast(this->con)->refcount_dec() >= 0); + this->con = nullptr; + } + quicPollEventAllocator.free(this); } @@ -61,9 +69,9 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) QUICNetVConnection *vc = static_cast(e->con); uint8_t *buf = (uint8_t *)p->getIOBlockChain()->buf(); - e->free(); if (!QUICTypeUtil::has_connection_id(reinterpret_cast(buf))) { // TODO: Some packets may not have connection id + e->free(); p->free(); return; } @@ -73,6 +81,7 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) vc->read.triggered = 1; vc->handle_received_packet(p); vc->handleEvent(QUIC_EVENT_PACKET_READ_READY, nullptr); + e->free(); return; } @@ -90,6 +99,9 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) nh->read_enable_list.push(vc); } } + + // Note: We should free QUICPollEvent here since vc could be freed from other thread. + e->free(); } void @@ -100,10 +112,10 @@ QUICPollCont::_process_short_header_packet(QUICPollEvent *e, NetHandler *nh) QUICNetVConnection *vc = static_cast(e->con); buf = (uint8_t *)p->getIOBlockChain()->buf(); - e->free(); if (!QUICTypeUtil::has_connection_id(reinterpret_cast(buf))) { // TODO: Some packets may not have connection id p->free(); + e->free(); return; } @@ -115,6 +127,9 @@ QUICPollCont::_process_short_header_packet(QUICPollEvent *e, NetHandler *nh) if (!isin) { nh->read_enable_list.push(vc); } + + // Note: We should free QUICPollEvent here since vc could be freed from other thread. + e->free(); } // @@ -134,6 +149,13 @@ QUICPollCont::pollEvent(int, Event *) SList(QUICPollEvent, alink) aq(inQueue.popall()); Queue result; while ((e = aq.pop())) { + QUICNetVConnection *qvc = static_cast(e->con); + UDPPacketInternal *p = e->packet; + if (qvc != nullptr && qvc->in_closed_queue) { + p->free(); + e->free(); + continue; + } result.push(e); } diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 96c1e062ca3..759b454865c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -87,8 +87,7 @@ QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, bool QUICNetVConnection::shouldDestroy() { - // TODO: return this->refcount == 0; - return true; + return this->refcount() == 0; } VIO * @@ -212,16 +211,12 @@ void QUICNetVConnection::free(EThread *t) { QUICConDebug("Free connection"); - - this->_ctable->erase(this->_original_quic_connection_id, this); - this->_ctable->erase(this->_quic_connection_id, this); - if (this->_alt_con_manager) { - this->_alt_con_manager->invalidate_alt_connections(); - } + this->remove_connection_ids(); /* TODO: Uncmment these blocks after refactoring read / write process this->_udp_con = nullptr; this->_packet_handler = nullptr; + _unschedule_packet_write_ready(); delete this->_handshake_handler; @@ -235,9 +230,28 @@ QUICNetVConnection::free(EThread *t) delete this->_alt_con_manager; } - // TODO: clear member variables like `UnixNetVConnection::free(EThread *t)` - this->mutex.clear(); + super::clear(); + */ + this->_packet_handler->close_conenction(this); +} + +// called by ET_UDP +void +QUICNetVConnection::remove_connection_ids() +{ + this->_ctable->erase(this->_original_quic_connection_id, this); + this->_ctable->erase(this->_quic_connection_id, this); + if (this->_alt_con_manager) { + this->_alt_con_manager->invalidate_alt_connections(); + } +} +// called by ET_UDP +void +QUICNetVConnection::destroy(EThread *t) +{ + QUICConDebug("Destroy connection"); + /* TODO: Uncmment these blocks after refactoring read / write process if (from_accept_thread) { quicNetVCAllocator.free(this); } else { @@ -660,11 +674,10 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) this->_loss_detector->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); if (this->nh) { - this->nh->stopCop(this); - this->nh->stopIO(this); + this->nh->free_netvc(this); + } else { + this->free(this->mutex->thread_holding); } - - this->_packet_handler->close_conenction(this); break; } case QUIC_EVENT_PACKET_WRITE_READY: { From 5b6864516badc0b60b8d89737ccc809c72439e51 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 2 Apr 2018 11:08:30 +0900 Subject: [PATCH 0480/1313] Schedule QUIC_EVENT_PACKET_WRITE_READY in connectUp --- iocore/net/QUICNetVConnection.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 759b454865c..3f6d80d360f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -295,6 +295,7 @@ QUICNetVConnection::connectUp(EThread *t, int fd) // start QUIC handshake this->_handshake_handler->handleEvent(VC_EVENT_WRITE_READY, nullptr); + this->_schedule_packet_write_ready(); return CONNECT_SUCCESS; } From 6726567e60c83efb1605bbf6a3ddb200a3ca09de Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 2 Apr 2018 11:29:24 +0900 Subject: [PATCH 0481/1313] Check every stream in QUICStreamManager::will_generate_frame() QUICStream might be in the stream_list, if it doesn't have any data to send. --- iocore/net/quic/QUICStreamManager.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index c636f5bcade..3ff654dae15 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -316,7 +316,13 @@ QUICStreamManager::reset_recv_offset() bool QUICStreamManager::will_generate_frame() { - return this->stream_list.head; + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + if (s->will_generate_frame()) { + return true; + } + } + + return false; } QUICFrameUPtr From 108c33a2919cc0a010df11ccbd8cbd60b3750eaf Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 2 Apr 2018 11:57:09 +0900 Subject: [PATCH 0482/1313] Minor cleanup: rename "Client Initial" to "Initial" --- iocore/net/P_QUICNetVConnection.h | 8 +++---- iocore/net/QUICNetVConnection.cc | 24 +++++++++---------- .../net/quic/test/test_QUICPacketFactory.cc | 17 +++++++------ 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 6b34210ebac..4c08f86d25e 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -109,9 +109,9 @@ class SSLNextProtocolSet; * state_handshake() * | READ: * | _state_handshake_process_packet() - * | _state_handshake_process_initial_client_packet() + * | _state_handshake_process_initial_packet() * | _state_handshake_process_retry_packet() - * | _state_handshake_process_client_cleartext_packet() + * | _state_handshake_process_handshake_packet() * | _state_handshake_process_zero_rtt_protected_packet() * | WRITE: * | _state_common_send_packet() @@ -284,9 +284,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICErrorUPtr _recv_and_ack(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_packet(QUICPacketUPtr packet); - QUICErrorUPtr _state_handshake_process_initial_client_packet(QUICPacketUPtr packet); + QUICErrorUPtr _state_handshake_process_initial_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_retry_packet(QUICPacketUPtr packet); - QUICErrorUPtr _state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet); + QUICErrorUPtr _state_handshake_process_handshake_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_connection_established_process_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_common_receive_packet(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3f6d80d360f..21bbcc19c8f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -53,11 +53,11 @@ Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__); \ Error("quic_net [%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) -static constexpr uint32_t MAX_PACKET_OVERHEAD = 17; // Max long header len(17) -static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; -static constexpr uint32_t MINIMUM_INITIAL_CLIENT_PACKET_SIZE = 1200; -static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(20); -static constexpr int FRAME_PER_EVENT = 64; +static constexpr uint32_t MAX_PACKET_OVERHEAD = 17; // Max long header len(17) +static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; +static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; +static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(20); +static constexpr int FRAME_PER_EVENT = 64; ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); @@ -335,7 +335,7 @@ QUICNetVConnection::minimum_quic_packet_size() { if (netvc_context == NET_VCONNECTION_OUT) { // FIXME Only the first packet need to be 1200 bytes at least - return MINIMUM_INITIAL_CLIENT_PACKET_SIZE; + return MINIMUM_INITIAL_PACKET_SIZE; } else { // FIXME This size should be configurable and should have some randomness // This is just for providing protection against packet analysis for protected packets @@ -775,13 +775,13 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (packet->type()) { case QUICPacketType::INITIAL: - error = this->_state_handshake_process_initial_client_packet(std::move(packet)); + error = this->_state_handshake_process_initial_packet(std::move(packet)); break; case QUICPacketType::RETRY: error = this->_state_handshake_process_retry_packet(std::move(packet)); break; case QUICPacketType::HANDSHAKE: - error = this->_state_handshake_process_client_cleartext_packet(std::move(packet)); + error = this->_state_handshake_process_handshake_packet(std::move(packet)); break; case QUICPacketType::ZERO_RTT_PROTECTED: error = this->_state_handshake_process_zero_rtt_protected_packet(std::move(packet)); @@ -797,10 +797,10 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) } QUICErrorUPtr -QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPtr packet) +QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packet) { - if (packet->size() < MINIMUM_INITIAL_CLIENT_PACKET_SIZE) { - QUICConDebug("Packet size is smaller than the minimum initial client packet size"); + if (packet->size() < MINIMUM_INITIAL_PACKET_SIZE) { + QUICConDebug("Packet size is smaller than the minimum initial packet size"); // Ignore the packet return QUICErrorUPtr(new QUICNoError()); } @@ -834,7 +834,7 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) } QUICErrorUPtr -QUICNetVConnection::_state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet) +QUICNetVConnection::_state_handshake_process_handshake_packet(QUICPacketUPtr packet) { return this->_recv_and_ack(std::move(packet)); } diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index e260563e2af..78e382033a3 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -32,25 +32,24 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); - uint8_t client_initial_packet_header[] = { + uint8_t initial_packet_header[] = { 0x82, // Type 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection id 0xaa, 0xbb, 0xcc, 0xdd, // Version 0x00, 0x00, 0x00, 0x00, // Packet number }; - uint8_t client_initial_packet_payload[] = { + uint8_t initial_packet_payload[] = { 0x00 // Payload }; - QUICPacketHeaderUPtr header = - QUICPacketHeader::load({client_initial_packet_header, [](void *) {}}, sizeof(client_initial_packet_header), 0); - QUICPacket client_initial_packet(std::move(header), ats_unique_buf(client_initial_packet_payload, [](void *) {}), - sizeof(client_initial_packet_payload), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({initial_packet_header, [](void *) {}}, sizeof(initial_packet_header), 0); + QUICPacket initial_packet(std::move(header), ats_unique_buf(initial_packet_payload, [](void *) {}), + sizeof(initial_packet_payload), 0); - QUICPacketUPtr packet = factory.create_version_negotiation_packet(&client_initial_packet, 0); + QUICPacketUPtr packet = factory.create_version_negotiation_packet(&initial_packet, 0); CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); - CHECK(packet->connection_id() == client_initial_packet.connection_id()); - CHECK(packet->packet_number() == client_initial_packet.packet_number()); + CHECK(packet->connection_id() == initial_packet.connection_id()); + CHECK(packet->packet_number() == initial_packet.packet_number()); CHECK(packet->version() == 0x00); CHECK(memcmp(packet->payload(), "\xff\x00\x00\x09", 4) == 0); } From b49f6c8784458d5b60762ffe6a2d113495126c32 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 31 Mar 2018 10:55:42 +0800 Subject: [PATCH 0483/1313] QUIC: Change QUIC closing period dynamically --- iocore/net/QUICNetVConnection.cc | 16 ++++++++-------- iocore/net/quic/QUICLossDetector.cc | 10 ++++++++++ iocore/net/quic/QUICLossDetector.h | 1 + 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 21bbcc19c8f..1f74784217d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1522,16 +1522,16 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) this->remove_from_active_queue(); this->set_inactivity_timeout(0); - QUICConDebug("Enter state_connection_closing"); + ink_hrtime rto = this->_loss_detector->current_rto_period(); + + QUICConDebug("Enter state_connection_closing %" PRIu64 "ms", 3 * rto / HRTIME_MSECOND); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); // This states SHOULD persist for three times the // current Retransmission Timeout (RTO) interval as defined in // [QUIC-RECOVERY]. - // TODO The closing period should be obtained from QUICLossDetector since it is the only component that knows the RTO interval. - // Use 3 times kkMinRTOTimeout(200ms) for now. - this->_schedule_closing_timeout(HRTIME_MSECONDS(3 * 200)); + this->_schedule_closing_timeout(3 * rto); } void @@ -1549,16 +1549,16 @@ QUICNetVConnection::_switch_to_draining_state(QUICConnectionErrorUPtr error) this->remove_from_active_queue(); this->set_inactivity_timeout(0); - QUICConDebug("Enter state_connection_draining"); + ink_hrtime rto = this->_loss_detector->current_rto_period(); + + QUICConDebug("Enter state_connection_draining %" PRIu64 "ms", 3 * rto / HRTIME_MSECOND); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_draining); // This states SHOULD persist for three times the // current Retransmission Timeout (RTO) interval as defined in // [QUIC-RECOVERY]. - // TODO The draining period should be obtained from QUICLossDetector since it is the only component that knows the RTO interval. - // Use 3 times kkMinRTOTimeout(200ms) for now. - this->_schedule_closing_timeout(HRTIME_MSECONDS(3 * 200)); + this->_schedule_closing_timeout(3 * rto); } void diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index ddeaf217933..c94935cc4a7 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -540,3 +540,13 @@ QUICLossDetector::_remove_from_sent_packet_list(QUICPacketNumber packet_number) // Remove from the list this->_sent_packets.erase(packet_number); } + +ink_hrtime +QUICLossDetector::current_rto_period() +{ + ink_hrtime alarm_duration; + alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; + alarm_duration = std::max(alarm_duration, this->_k_min_rto_timeout); + alarm_duration = alarm_duration * (1 << this->_rto_count); + return alarm_duration; +} diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index b129b4a9d82..3fd79fa7771 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -80,6 +80,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void on_packet_sent(QUICPacketUPtr packet); QUICPacketNumber largest_acked_packet_number(); void reset(); + ink_hrtime current_rto_period(); private: Ptr _loss_detection_mutex; From de061414396063f85aa09a31b7a10fd60104546b Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 2 Apr 2018 11:34:41 +0800 Subject: [PATCH 0484/1313] QUIC: Fix clang warning --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 4c08f86d25e..eb7defd121c 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -170,6 +170,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void start(); void remove_connection_ids(); void free(EThread *t) override; + void free() override; void destroy(EThread *t); UDPConnection *get_udp_con(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 1f74784217d..63b8a56f6ba 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -235,6 +235,12 @@ QUICNetVConnection::free(EThread *t) this->_packet_handler->close_conenction(this); } +void +QUICNetVConnection::free() +{ + this->free(this_ethread()); +} + // called by ET_UDP void QUICNetVConnection::remove_connection_ids() From 90d86680169a72c94235e3591a9d72d8eb1ff467 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 31 Mar 2018 10:10:02 +0800 Subject: [PATCH 0485/1313] QUIC: Check congestion window when sending packet --- iocore/net/QUICNetVConnection.cc | 10 ++++- iocore/net/quic/QUICCongestionController.cc | 48 +++++++++++++++++++++ iocore/net/quic/QUICLossDetector.h | 9 ++++ 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 63b8a56f6ba..540b39cf99e 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -197,7 +197,7 @@ QUICNetVConnection::start() // Create frame handlers this->_stream_manager = new QUICStreamManager(this->connection_id(), this->_application_map); - this->_congestion_controller = new QUICCongestionController(); + this->_congestion_controller = new QUICCongestionController(this->connection_id()); this->_loss_detector = new QUICLossDetector(this, this->_congestion_controller); this->_remote_flow_controller = new QUICRemoteConnectionFlowController(0); this->_local_flow_controller = new QUICLocalConnectionFlowController(0); @@ -935,10 +935,16 @@ QUICNetVConnection::_state_common_send_packet() QUICPacket *packet; SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); - uint32_t packet_count = this->_packet_send_queue.size; + uint32_t packet_count = 0; while ((packet = this->_packet_send_queue.dequeue()) != nullptr) { + if (!this->_congestion_controller->check_credit()) { + this->_packet_send_queue.push(packet); + break; + } + this->_packet_handler->send_packet(*packet, this); this->_loss_detector->on_packet_sent(QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet)); + packet_count++; } QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, packet_count); diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 44f4de9da9e..de607a4405a 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -24,6 +24,18 @@ #include #include +#define QUICCCDebug(fmt, ...) \ + Debug("quic_cc", "[%" PRIx64 "] " \ + "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ + static_cast(this->_connection_id), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, \ + ##__VA_ARGS__) + +#define QUICCCError(fmt, ...) \ + Error("quic_cc", "[%" PRIx64 "] " \ + "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ + static_cast(this->_connection_id), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, \ + ##__VA_ARGS__) + // 4.7.1. Constants of interest constexpr static uint16_t DEFAULT_MSS = 1460; constexpr static uint32_t INITIAL_WINDOW = 10 * DEFAULT_MSS; @@ -35,6 +47,11 @@ QUICCongestionController::QUICCongestionController() this->_congestion_window = INITIAL_WINDOW; } +QUICCongestionController::QUICCongestionController(QUICConnectionId connection_id) : _connection_id(connection_id) +{ + this->_congestion_window = INITIAL_WINDOW; +} + void QUICCongestionController::on_packet_sent(size_t bytes_sent) { @@ -59,9 +76,11 @@ QUICCongestionController::on_packet_acked(QUICPacketNumber acked_packet_number, if (this->_congestion_window < this->_ssthresh) { // Slow start. this->_congestion_window += acked_packet_size; + QUICCCDebug("slow start window chaged"); } else { // Congestion avoidance. this->_congestion_window += DEFAULT_MSS * acked_packet_size / this->_congestion_window; + QUICCCDebug("Congestion avoidance window changed"); } } @@ -80,6 +99,7 @@ QUICCongestionController::on_packets_lost(std::map_congestion_window *= LOSS_REDUCTION_FACTOR; this->_congestion_window = std::max(this->_congestion_window, MINIMUM_WINDOW); this->_ssthresh = this->_congestion_window; + QUICCCDebug("packet lost, window changed"); } } @@ -88,3 +108,31 @@ QUICCongestionController::on_retransmission_timeout_verified() { this->_congestion_window = MINIMUM_WINDOW; } + +bool +QUICCongestionController::check_credit() const +{ + if (this->_bytes_in_flight >= this->_congestion_window) { + QUICCCDebug("Congestion control pending"); + } + + return this->_bytes_in_flight < this->_congestion_window; +} + +uint32_t +QUICCongestionController::bytes_in_flight() const +{ + return this->_bytes_in_flight; +} + +uint32_t +QUICCongestionController::congestion_window() const +{ + return this->_congestion_window; +} + +uint32_t +QUICCongestionController::current_ssthresh() const +{ + return this->_ssthresh; +} diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 3fd79fa7771..202e6a7b08d 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -50,12 +50,19 @@ class QUICCongestionController { public: QUICCongestionController(); + QUICCongestionController(QUICConnectionId connection_id); virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); void on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size); virtual void on_packets_lost(std::map packets); void on_retransmission_timeout_verified(); + bool check_credit() const; + + // Debug + uint32_t bytes_in_flight() const; + uint32_t congestion_window() const; + uint32_t current_ssthresh() const; private: // 4.7.2. Variables of interest @@ -64,6 +71,8 @@ class QUICCongestionController QUICPacketNumber _end_of_recovery = 0; uint32_t _ssthresh = UINT32_MAX; + QUICConnectionId _connection_id = 0; + bool _in_recovery(QUICPacketNumber packet_number); }; From eb6b247130413a91ac816a4fa0b6174953c064b9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 2 Apr 2018 14:52:04 +0900 Subject: [PATCH 0486/1313] Make constans of Congestion Control configurable Add below configs ``` proxy.config.quic.congestion_control.default_mss proxy.config.quic.congestion_control.initial_window_scale proxy.config.quic.congestion_control.minimum_window_scale proxy.config.quic.congestion_control.loss_reduction_factor ``` --- iocore/net/quic/QUICConfig.cc | 29 +++++++++++++++++++++ iocore/net/quic/QUICConfig.h | 11 ++++++++ iocore/net/quic/QUICCongestionController.cc | 28 +++++++++++--------- iocore/net/quic/QUICLossDetector.h | 9 ++++++- mgmt/RecordsConfig.cc | 9 +++++++ 5 files changed, 72 insertions(+), 14 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 1f3661b7e82..5d5654bad9c 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -142,6 +142,11 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(timeout, "proxy.config.quic.loss_detection.default_initial_rtt"); this->_ld_default_initial_rtt = HRTIME_MSECONDS(timeout); + REC_EstablishStaticConfigInt32U(this->_cc_default_mss, "proxy.config.quic.congestion_control.default_mss"); + REC_EstablishStaticConfigInt32U(this->_cc_initial_window_scale, "proxy.config.quic.congestion_control.initial_window_scale"); + REC_EstablishStaticConfigInt32U(this->_cc_minimum_window_scale, "proxy.config.quic.congestion_control.minimum_window_scale"); + REC_EstablishStaticConfigFloat(this->_cc_loss_reduction_factor, "proxy.config.quic.congestion_control.loss_reduction_factor"); + QUICStatelessRetry::init(); this->_server_ssl_ctx = quic_init_server_ssl_ctx(this); @@ -286,6 +291,30 @@ QUICConfigParams::ld_default_initial_rtt() const return _ld_default_initial_rtt; } +uint32_t +QUICConfigParams::cc_default_mss() const +{ + return _cc_default_mss; +} + +uint32_t +QUICConfigParams::cc_initial_window() const +{ + return _cc_initial_window_scale * _cc_default_mss; +} + +uint32_t +QUICConfigParams::cc_minimum_window() const +{ + return _cc_minimum_window_scale * _cc_default_mss; +} + +float +QUICConfigParams::cc_loss_reduction_factor() const +{ + return _cc_loss_reduction_factor; +} + // // QUICConfig // diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index a2fb0ed1a9a..af7649935c3 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -61,6 +61,11 @@ class QUICConfigParams : public ConfigInfo ink_hrtime ld_delayed_ack_timeout() const; ink_hrtime ld_default_initial_rtt() const; + uint32_t cc_default_mss() const; + uint32_t cc_initial_window() const; + uint32_t cc_minimum_window() const; + float cc_loss_reduction_factor() const; + private: static int _connection_table_size; @@ -93,6 +98,12 @@ class QUICConfigParams : public ConfigInfo ink_hrtime _ld_min_rto_timeout = HRTIME_MSECONDS(200); ink_hrtime _ld_delayed_ack_timeout = HRTIME_MSECONDS(25); ink_hrtime _ld_default_initial_rtt = HRTIME_MSECONDS(100); + + // [draft-10 recovery] - 4.7.1. Constants of interest + uint32_t _cc_default_mss = 1460; + uint32_t _cc_initial_window_scale = 10; // Actual initial window size is this value multiplied by the _cc_default_mss + uint32_t _cc_minimum_window_scale = 2; // Actual minimum window size is this value multiplied by the _cc_default_mss + float _cc_loss_reduction_factor = 0.5; }; class QUICConfig diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index de607a4405a..b748050c60a 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -24,6 +24,8 @@ #include #include +#include "QUICConfig.h" + #define QUICCCDebug(fmt, ...) \ Debug("quic_cc", "[%" PRIx64 "] " \ "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ @@ -36,20 +38,20 @@ static_cast(this->_connection_id), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, \ ##__VA_ARGS__) -// 4.7.1. Constants of interest -constexpr static uint16_t DEFAULT_MSS = 1460; -constexpr static uint32_t INITIAL_WINDOW = 10 * DEFAULT_MSS; -constexpr static uint32_t MINIMUM_WINDOW = 2 * DEFAULT_MSS; -constexpr static double LOSS_REDUCTION_FACTOR = 0.5; - -QUICCongestionController::QUICCongestionController() +QUICCongestionController::QUICCongestionController() : QUICCongestionController(0) { - this->_congestion_window = INITIAL_WINDOW; } QUICCongestionController::QUICCongestionController(QUICConnectionId connection_id) : _connection_id(connection_id) { - this->_congestion_window = INITIAL_WINDOW; + QUICConfig::scoped_config params; + this->_k_default_mss = params->cc_default_mss(); + this->_k_initial_window = params->cc_initial_window(); + this->_k_minimum_window = params->cc_minimum_window(); + this->_k_loss_reduction_factor = params->cc_loss_reduction_factor(); + + // 4.7.3. Initialization + this->_congestion_window = this->_k_initial_window; } void @@ -79,7 +81,7 @@ QUICCongestionController::on_packet_acked(QUICPacketNumber acked_packet_number, QUICCCDebug("slow start window chaged"); } else { // Congestion avoidance. - this->_congestion_window += DEFAULT_MSS * acked_packet_size / this->_congestion_window; + this->_congestion_window += this->_k_default_mss * acked_packet_size / this->_congestion_window; QUICCCDebug("Congestion avoidance window changed"); } } @@ -96,8 +98,8 @@ QUICCongestionController::on_packets_lost(std::map_in_recovery(largest_lost_packet)) { this->_end_of_recovery = largest_lost_packet; - this->_congestion_window *= LOSS_REDUCTION_FACTOR; - this->_congestion_window = std::max(this->_congestion_window, MINIMUM_WINDOW); + 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; QUICCCDebug("packet lost, window changed"); } @@ -106,7 +108,7 @@ QUICCongestionController::on_packets_lost(std::map_congestion_window = MINIMUM_WINDOW; + this->_congestion_window = this->_k_minimum_window; } bool diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 202e6a7b08d..0fd65c5a6e8 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -65,7 +65,14 @@ class QUICCongestionController uint32_t current_ssthresh() const; private: - // 4.7.2. Variables of interest + // 4.7.1. Constants of interest (draft-10) + // Values will be loaded from records.config via QUICConfig at constructor + uint32_t _k_default_mss = 0; + uint32_t _k_initial_window = 0; + uint32_t _k_minimum_window = 0; + float _k_loss_reduction_factor = 0.0; + + // 4.7.2. Variables of interest uint32_t _bytes_in_flight = 0; uint32_t _congestion_window = 0; QUICPacketNumber _end_of_recovery = 0; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 85bd71a9728..4705eed3a00 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1351,6 +1351,15 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.loss_detection.default_initial_rtt", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , + // Constatns of Congestion Control + {RECT_CONFIG, "proxy.config.quic.congestion_control.default_mss", RECD_INT, "1460", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.congestion_control.initial_window_scale", RECD_INT, "10", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.congestion_control.minimum_window_scale", RECD_INT, "2", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.congestion_control.loss_reduction_factor", RECD_FLOAT, "0.5", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[\\.0-9]+$", RECA_NULL} + , //# Add LOCAL Records Here {RECT_LOCAL, "proxy.local.incoming_ip_to_bind", RECD_STRING, nullptr, RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL} From 8185c20aad939cfe0187e1b7b711bd973e4b60e1 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 2 Apr 2018 15:18:56 +0900 Subject: [PATCH 0487/1313] Add nullptr check before calling QUICConnectionTable::erase() QUICNetVConnection::_ctable is nullptr when QVC is out going connection --- iocore/net/QUICNetVConnection.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 540b39cf99e..cac33f3199c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -245,8 +245,11 @@ QUICNetVConnection::free() void QUICNetVConnection::remove_connection_ids() { - this->_ctable->erase(this->_original_quic_connection_id, this); - this->_ctable->erase(this->_quic_connection_id, this); + if (this->_ctable) { + this->_ctable->erase(this->_original_quic_connection_id, this); + this->_ctable->erase(this->_quic_connection_id, this); + } + if (this->_alt_con_manager) { this->_alt_con_manager->invalidate_alt_connections(); } From fc1bc3600758cd0c712788896271db946dec669a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 4 Apr 2018 14:28:43 +0900 Subject: [PATCH 0488/1313] Fix QUICPacketFactory for Version Negotiation Packet --- iocore/net/quic/QUICHandshake.cc | 3 +- iocore/net/quic/QUICPacket.cc | 38 ++++++++++++------- iocore/net/quic/QUICPacket.h | 2 +- .../net/quic/test/test_QUICPacketFactory.cc | 6 ++- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index aec09076169..f6a6cecb258 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -137,8 +137,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet this->_load_local_server_transport_parameters(initial_packet->version()); packet_factory->set_version(this->_version_negotiator->negotiated_version()); } else { - this->_client_qc->transmit_packet( - packet_factory->create_version_negotiation_packet(initial_packet, _client_qc->largest_acked_packet_number())); + this->_client_qc->transmit_packet(packet_factory->create_version_negotiation_packet(initial_packet)); QUICHSDebug("Version negotiation failed: %x", initial_packet->version()); } } else { diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 66ed12c42d2..a195f20be07 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -196,7 +196,11 @@ const uint8_t * QUICPacketLongHeader::payload() const { if (this->_buf) { - return this->_buf.get() + LONG_HDR_OFFSET_PAYLOAD; + if (this->type() == QUICPacketType::VERSION_NEGOTIATION) { + return this->_buf.get() + VERSION_NEGOTIATION_PKT_HEADER_LENGTH; + } else { + return this->_buf.get() + LONG_HDR_OFFSET_PAYLOAD; + } } else { return this->_payload.get(); } @@ -253,11 +257,13 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const QUICTypeUtil::write_QUICVersion(this->_version, buf + *len, &n); *len += n; - QUICPacketNumber dst = 0; - size_t dst_len = 4; - QUICPacket::encode_packet_number(dst, this->_packet_number, dst_len); - QUICTypeUtil::write_QUICPacketNumber(dst, dst_len, buf + *len, &n); - *len += n; + if (this->_type != QUICPacketType::VERSION_NEGOTIATION) { + QUICPacketNumber dst = 0; + size_t dst_len = 4; + QUICPacket::encode_packet_number(dst, this->_packet_number, dst_len); + QUICTypeUtil::write_QUICPacketNumber(dst, dst_len, buf + *len, &n); + *len += n; + } } // @@ -667,14 +673,20 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ QUICPacketHeaderUPtr header = QUICPacketHeader::load(std::move(buf), len, base_packet_number); if (header->has_version() && !QUICTypeUtil::is_supported_version(header->version())) { - // We can't decrypt packets that have unknown versions - result = QUICPacketCreationResult::UNSUPPORTED; + if (header->type() == QUICPacketType::VERSION_NEGOTIATION) { + // version of VN packet is 0x00000000 + // This packet is unprotected. Just copy the payload + result = QUICPacketCreationResult::SUCCESS; + } else { + // We can't decrypt packets that have unknown versions + result = QUICPacketCreationResult::UNSUPPORTED; + } + memcpy(plain_txt.get(), header->payload(), header->payload_size()); plain_txt_len = header->payload_size(); } else { Debug("quic_packet", "Decrypting %s packet #%" PRIu64, QUICDebugNames::packet_type(header->type()), header->packet_number()); switch (header->type()) { - case QUICPacketType::VERSION_NEGOTIATION: case QUICPacketType::STATELESS_RESET: // These packets are unprotected. Just copy the payload memcpy(plain_txt.get(), header->payload(), header->payload_size()); @@ -768,7 +780,7 @@ QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_ } QUICPacketUPtr -QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number) +QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_sent_by_client) { size_t len = sizeof(QUICVersion) * countof(QUIC_SUPPORTED_VERSIONS); ats_unique_buf versions(reinterpret_cast(ats_malloc(len)), [](void *p) { ats_free(p); }); @@ -780,9 +792,9 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se p += n; } - QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), - packet_sent_by_client->packet_number(), base_packet_number, 0x00, std::move(versions), len); + // VN packet dosen't have packet number field and version field is always 0x00000000 + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), + 0x00, 0x00, 0x00, std::move(versions), len); return QUICPacketFactory::_create_unprotected_packet(std::move(header)); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index cca3571d960..1bc32299ce9 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -339,7 +339,7 @@ class QUICPacketFactory static QUICPacketUPtr create_null_packet(); QUICPacketUPtr create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result); - QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number); + QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client); QUICPacketUPtr create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); QUICPacketUPtr create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 78e382033a3..e0be9f18df8 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -46,12 +46,14 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") QUICPacket initial_packet(std::move(header), ats_unique_buf(initial_packet_payload, [](void *) {}), sizeof(initial_packet_payload), 0); - QUICPacketUPtr packet = factory.create_version_negotiation_packet(&initial_packet, 0); + QUICPacketUPtr packet = factory.create_version_negotiation_packet(&initial_packet); CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); CHECK(packet->connection_id() == initial_packet.connection_id()); CHECK(packet->packet_number() == initial_packet.packet_number()); CHECK(packet->version() == 0x00); - CHECK(memcmp(packet->payload(), "\xff\x00\x00\x09", 4) == 0); + + QUICVersion supported_version = QUICTypeUtil::read_QUICVersion(packet->payload()); + CHECK(supported_version == QUIC_SUPPORTED_VERSIONS[0]); } TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") From b778c96d2cf62791168f9ac885761e79e380c090 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 4 Apr 2018 14:58:13 +0900 Subject: [PATCH 0489/1313] Remove version args from create_initial_packet To use PacketFactory's _version like other create_X_packet functions --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICPacket.cc | 4 ++-- iocore/net/quic/QUICPacket.h | 4 ++-- iocore/net/quic/test/test_QUICVersionNegotiator.cc | 11 ++++++----- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index cac33f3199c..a22a7b18f3a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1228,7 +1228,7 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi case QUICPacketType::INITIAL: ink_assert(this->get_context() == NET_VCONNECTION_OUT); packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->largest_acked_packet_number(), - QUIC_SUPPORTED_VERSIONS[0], std::move(buf), len); + std::move(buf), len); this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); break; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index a195f20be07..61e19ba9aa4 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -800,12 +800,12 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se } QUICPacketUPtr -QUICPacketFactory::create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, +QUICPacketFactory::create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len) { QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::INITIAL, connection_id, this->_packet_number_generator.next(), base_packet_number, - version, std::move(payload), len); + this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), true); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 1bc32299ce9..6a87d1e1c12 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -340,8 +340,8 @@ class QUICPacketFactory QUICPacketUPtr create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result); QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client); - QUICPacketUPtr create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version, - ats_unique_buf payload, size_t len); + QUICPacketUPtr create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, + size_t len); QUICPacketUPtr create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, size_t len, bool retransmittable); QUICPacketUPtr create_handshake_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index ea6d87b8ac2..be32502c415 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -39,8 +39,8 @@ TEST_CASE("QUICVersionNegotiator", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); // Negotiate version - QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, 0, QUIC_SUPPORTED_VERSIONS[0], ats_unique_malloc(0), 0); + packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, ats_unique_malloc(0), 0); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -57,8 +57,8 @@ TEST_CASE("QUICVersionNegotiator", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); // Negotiate version - QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, 0, QUIC_SUPPORTED_VERSIONS[0], ats_unique_malloc(0), 0); + packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, ats_unique_malloc(0), 0); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -75,7 +75,8 @@ TEST_CASE("QUICVersionNegotiator", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); // Negotiate version - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, 0xbabababa, ats_unique_malloc(0), 0); + packet_factory.set_version(0xbabababa); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, ats_unique_malloc(0), 0); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); From 528f1ee56b7857c716fd74352b4ba04f19772027 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 4 Apr 2018 15:06:13 +0900 Subject: [PATCH 0490/1313] Add VERSION_NEGOTIATION packet support to QUICVersionNegotiator --- iocore/net/quic/QUICTransportParameters.cc | 12 ++++ iocore/net/quic/QUICTransportParameters.h | 1 + iocore/net/quic/QUICTypes.h | 2 + iocore/net/quic/QUICVersionNegotiator.cc | 63 +++++++++++++++++-- iocore/net/quic/QUICVersionNegotiator.h | 1 + .../quic/test/test_QUICTransportParameters.cc | 1 + .../quic/test/test_QUICVersionNegotiator.cc | 55 +++++++++++++++- 7 files changed, 128 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 7b74a6f0986..9a8182f7b2c 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -439,6 +439,18 @@ QUICTransportParametersInEncryptedExtensions::add_version(QUICVersion version) this->_versions[this->_n_versions++] = version; } +bool +QUICTransportParametersInEncryptedExtensions::is_valid_negotiated_version() const +{ + for (int i = 0; QUICVersion v = this->_versions[i]; i++) { + if (this->_negotiated_version == v) { + return true; + } + } + + return false; +} + std::ptrdiff_t QUICTransportParametersInEncryptedExtensions::_parameters_offset(const uint8_t *buf) const { diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 11bc8b08faa..96ff64b7c3d 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -136,6 +136,7 @@ class QUICTransportParametersInEncryptedExtensions : public QUICTransportParamet QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len); QUICVersion negotiated_version() const; void add_version(QUICVersion version); + bool is_valid_negotiated_version() const; protected: std::ptrdiff_t _parameters_offset(const uint8_t *buf) const override; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 78b9a01c742..57de3919ee5 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -49,6 +49,8 @@ using QUICOffset = uint64_t; constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { 0xff000009, }; +constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; + constexpr QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; enum class QUICHandshakeMsgType { diff --git a/iocore/net/quic/QUICVersionNegotiator.cc b/iocore/net/quic/QUICVersionNegotiator.cc index 2329c31efbc..8aff8a9d163 100644 --- a/iocore/net/quic/QUICVersionNegotiator.cc +++ b/iocore/net/quic/QUICVersionNegotiator.cc @@ -31,12 +31,40 @@ QUICVersionNegotiator::status() } QUICVersionNegotiationStatus -QUICVersionNegotiator::negotiate(const QUICPacket *initial_packet) +QUICVersionNegotiator::negotiate(const QUICPacket *packet) { - if (QUICTypeUtil::is_supported_version(initial_packet->version())) { - this->_status = QUICVersionNegotiationStatus::NEGOTIATED; - this->_negotiated_version = initial_packet->version(); + switch (packet->type()) { + case QUICPacketType::INITIAL: { + if (QUICTypeUtil::is_supported_version(packet->version())) { + this->_status = QUICVersionNegotiationStatus::NEGOTIATED; + this->_negotiated_version = packet->version(); + } + + break; + } + case QUICPacketType::VERSION_NEGOTIATION: { + const uint8_t *supported_versions = packet->payload(); + uint16_t supported_versions_len = packet->payload_size(); + uint16_t len = 0; + + while (len < supported_versions_len) { + QUICVersion version = QUICTypeUtil::read_QUICVersion(supported_versions + len); + len += sizeof(QUICVersion); + + if (QUICTypeUtil::is_supported_version(version)) { + this->_status = QUICVersionNegotiationStatus::NEGOTIATED; + this->_negotiated_version = version; + break; + } + } + + break; } + default: + ink_assert(false); + break; + } + return this->_status; } @@ -46,6 +74,7 @@ QUICVersionNegotiator::validate(const QUICTransportParametersInClientHello *tp) if (this->_negotiated_version == tp->initial_version()) { this->_status = QUICVersionNegotiationStatus::VALIDATED; } else { + // Version negotiation was performed if (QUICTypeUtil::is_supported_version(tp->initial_version())) { this->_status = QUICVersionNegotiationStatus::FAILED; this->_negotiated_version = 0; @@ -56,6 +85,32 @@ QUICVersionNegotiator::validate(const QUICTransportParametersInClientHello *tp) return this->_status; } +QUICVersionNegotiationStatus +QUICVersionNegotiator::validate(const QUICTransportParametersInEncryptedExtensions *tp) +{ + if (!tp->is_valid_negotiated_version()) { + this->_status = QUICVersionNegotiationStatus::FAILED; + this->_negotiated_version = 0; + + return this->_status; + } + + if (this->_status == QUICVersionNegotiationStatus::NEGOTIATED) { + // Version negotiation was performed + if (this->_negotiated_version == tp->negotiated_version()) { + this->_status = QUICVersionNegotiationStatus::VALIDATED; + } else { + this->_status = QUICVersionNegotiationStatus::FAILED; + this->_negotiated_version = 0; + } + } else { + this->_status = QUICVersionNegotiationStatus::VALIDATED; + this->_negotiated_version = tp->negotiated_version(); + } + + return this->_status; +} + QUICVersion QUICVersionNegotiator::negotiated_version() { diff --git a/iocore/net/quic/QUICVersionNegotiator.h b/iocore/net/quic/QUICVersionNegotiator.h index 651a7db51c4..c59d59e90b4 100644 --- a/iocore/net/quic/QUICVersionNegotiator.h +++ b/iocore/net/quic/QUICVersionNegotiator.h @@ -37,6 +37,7 @@ class QUICVersionNegotiator QUICVersionNegotiationStatus status(); QUICVersionNegotiationStatus negotiate(const QUICPacket *initial_packet); QUICVersionNegotiationStatus validate(const QUICTransportParametersInClientHello *tp); + QUICVersionNegotiationStatus validate(const QUICTransportParametersInEncryptedExtensions *tp); QUICVersion negotiated_version(); private: diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index cc737145bdc..3e26f9387ef 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -153,6 +153,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf)); CHECK(params_in_ee.is_valid()); + CHECK(params_in_ee.is_valid_negotiated_version()); CHECK(params_in_ee.negotiated_version() == 0x01020304); uint16_t len = 0; diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index be32502c415..a318c987a75 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -26,7 +26,7 @@ #include "quic/QUICVersionNegotiator.h" #include "quic/Mock.h" -TEST_CASE("QUICVersionNegotiator", "[quic]") +TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") { QUICPacketFactory packet_factory; MockQUICHandshakeProtocol hs_protocol; @@ -63,7 +63,7 @@ TEST_CASE("QUICVersionNegotiator", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); // Validate version - QUICTransportParametersInClientHello tp(0xbabababa); + QUICTransportParametersInClientHello tp(QUIC_EXERCISE_VERSIONS); vn.validate(&tp); CHECK(vn.status() == QUICVersionNegotiationStatus::VALIDATED); CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); @@ -75,7 +75,7 @@ TEST_CASE("QUICVersionNegotiator", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); // Negotiate version - packet_factory.set_version(0xbabababa); + packet_factory.set_version(QUIC_EXERCISE_VERSIONS); QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, ats_unique_malloc(0), 0); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); @@ -87,3 +87,52 @@ TEST_CASE("QUICVersionNegotiator", "[quic]") CHECK(vn.negotiated_version() != QUIC_SUPPORTED_VERSIONS[0]); } } + +TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") +{ + QUICPacketFactory packet_factory; + MockQUICHandshakeProtocol hs_protocol; + packet_factory.set_hs_protocol(&hs_protocol); + QUICVersionNegotiator vn; + + SECTION("Normal case") + { + // Check initial state + CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); + + // No Version Negotiation packet from server + + // Validate version + QUICTransportParametersInEncryptedExtensions tp(QUIC_SUPPORTED_VERSIONS[0]); + tp.add_version(QUIC_SUPPORTED_VERSIONS[0]); + + vn.validate(&tp); + CHECK(vn.status() == QUICVersionNegotiationStatus::VALIDATED); + CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); + } + + SECTION("Negotiation case") + { + // Check initial state + CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); + + // Negotiate version + packet_factory.set_version(QUIC_EXERCISE_VERSIONS); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, ats_unique_malloc(0), 0); + + // Server send VN packet based on Initial packet + QUICPacketUPtr vn_packet = packet_factory.create_version_negotiation_packet(initial_packet.get()); + + // Negotiate version + vn.negotiate(vn_packet.get()); + CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); + CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); + + // Validate version + QUICTransportParametersInEncryptedExtensions tp(QUIC_SUPPORTED_VERSIONS[0]); + tp.add_version(QUIC_SUPPORTED_VERSIONS[0]); + + vn.validate(&tp); + CHECK(vn.status() == QUICVersionNegotiationStatus::VALIDATED); + } +} From 6ff1a3f373f7af9339285c6f4b96d5636ca8912c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 4 Apr 2018 15:15:47 +0900 Subject: [PATCH 0491/1313] Add Version Negotiation support on QUIC client To enforce version negotiation exercise, set below config 1. ``` proxy.config.quic.client.vn_exercise_enabled ``` --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 21 ++++++++++++- iocore/net/quic/QUICConfig.cc | 8 +++++ iocore/net/quic/QUICConfig.h | 3 ++ iocore/net/quic/QUICHandshake.cc | 49 ++++++++++++++++++++++++++++--- iocore/net/quic/QUICHandshake.h | 4 ++- mgmt/RecordsConfig.cc | 2 ++ 7 files changed, 82 insertions(+), 6 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index eb7defd121c..e68b2e2c26c 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -285,6 +285,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICErrorUPtr _recv_and_ack(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_packet(QUICPacketUPtr packet); + QUICErrorUPtr _state_handshake_process_version_negotiation_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_initial_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_retry_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_handshake_packet(QUICPacketUPtr packet); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a22a7b18f3a..6ea5de40713 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -186,7 +186,7 @@ QUICNetVConnection::start() this->_handshake_handler = new QUICHandshake(this, params->server_ssl_ctx(), this->_reset_token, params->stateless_retry()); } else { this->_handshake_handler = new QUICHandshake(this, params->client_ssl_ctx()); - this->_handshake_handler->start(&this->_packet_factory); + this->_handshake_handler->start(&this->_packet_factory, params->vn_exercise_enabled()); } this->_application_map = new QUICApplicationMap(); this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); @@ -783,6 +783,9 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (packet->type()) { + case QUICPacketType::VERSION_NEGOTIATION: + error = this->_state_handshake_process_version_negotiation_packet(std::move(packet)); + break; case QUICPacketType::INITIAL: error = this->_state_handshake_process_initial_packet(std::move(packet)); break; @@ -805,6 +808,22 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) return error; } +QUICErrorUPtr +QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPacketUPtr packet) +{ + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + + if (packet->connection_id() != this->connection_id()) { + QUICConDebug("Ignore Version Negotiation packet"); + return error; + } + + error = this->_handshake_handler->negotiate_version(packet.get(), &this->_packet_factory); + // Initial packet will be retransmited with negotiated version + + return error; +} + QUICErrorUPtr QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packet) { diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 5d5654bad9c..897002be52e 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -121,6 +121,8 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); REC_EstablishStaticConfigInt32(this->_connection_table_size, "proxy.config.quic.connection_table.size"); REC_EstablishStaticConfigInt32U(this->_stateless_retry, "proxy.config.quic.stateless_retry"); + REC_EstablishStaticConfigInt32U(this->_vn_exercise_enabled, "proxy.config.quic.client.vn_exercise_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"); @@ -183,6 +185,12 @@ QUICConfigParams::stateless_retry() const return this->_stateless_retry; } +uint32_t +QUICConfigParams::vn_exercise_enabled() const +{ + return this->_vn_exercise_enabled; +} + uint32_t QUICConfigParams::initial_max_data() const { diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index af7649935c3..3de36c74eb9 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -46,6 +46,8 @@ class QUICConfigParams : public ConfigInfo uint32_t server_id() const; static int connection_table_size(); uint32_t stateless_retry() const; + uint32_t vn_exercise_enabled() const; + const char *server_supported_groups() const; const char *client_supported_groups() const; @@ -76,6 +78,7 @@ class QUICConfigParams : public ConfigInfo uint32_t _initial_max_stream_data = 0; uint32_t _server_id = 0; uint32_t _stateless_retry = 0; + uint32_t _vn_exercise_enabled = 0; uint32_t _initial_max_stream_id_bidi_in = 100; uint32_t _initial_max_stream_id_bidi_out = 101; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index f6a6cecb258..5d2484e1c67 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -116,10 +116,16 @@ QUICHandshake::~QUICHandshake() } QUICErrorUPtr -QUICHandshake::start(QUICPacketFactory *packet_factory) +QUICHandshake::start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled) { - this->_load_local_client_transport_parameters(QUIC_SUPPORTED_VERSIONS[0]); - packet_factory->set_version(QUIC_SUPPORTED_VERSIONS[0]); + QUICVersion initital_version = QUIC_SUPPORTED_VERSIONS[0]; + if (vn_exercise_enabled) { + initital_version = QUIC_EXERCISE_VERSIONS; + } + + this->_load_local_client_transport_parameters(initital_version); + packet_factory->set_version(initital_version); + return QUICErrorUPtr(new QUICNoError()); } @@ -147,6 +153,36 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet return QUICErrorUPtr(new QUICNoError()); } +QUICErrorUPtr +QUICHandshake::negotiate_version(const QUICPacket *vn, QUICPacketFactory *packet_factory) +{ + // Client side only + ink_assert(this->_netvc_context == NET_VCONNECTION_OUT); + + // If already negotiated, just ignore it + if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED || + this->_version_negotiator->status() == QUICVersionNegotiationStatus::VALIDATED) { + QUICHSDebug("Ignore Version Negotiation packet"); + return QUICErrorUPtr(new QUICNoError()); + } + + if (vn->version() != 0x00) { + QUICHSDebug("Version field must be 0x00000000"); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); + } + + if (this->_version_negotiator->negotiate(vn) == QUICVersionNegotiationStatus::NEGOTIATED) { + QUICVersion version = this->_version_negotiator->negotiated_version(); + QUICHSDebug("Version negotiation succeeded: 0x%x", version); + packet_factory->set_version(version); + } else { + QUICHSDebug("Version negotiation failed"); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR)); + } + + return QUICErrorUPtr(new QUICNoError()); +} + bool QUICHandshake::is_version_negotiated() const { @@ -235,7 +271,12 @@ QUICHandshake::set_transport_parameters(std::shared_ptr_remote_transport_parameters = tp; - // TODO Add client side implementation + // Version revalidation + if (this->_version_negotiator->validate(tp.get()) != QUICVersionNegotiationStatus::VALIDATED) { + QUICHSDebug("Version revalidation failed"); + this->_abort_handshake(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR); + return; + } return; } diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 2005041bc7f..37e316e42a1 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -52,7 +52,9 @@ class QUICHandshake : public QUICApplication ~QUICHandshake(); // for client side - QUICErrorUPtr start(QUICPacketFactory *packet_factory); + QUICErrorUPtr start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled); + QUICErrorUPtr negotiate_version(const QUICPacket *packet, QUICPacketFactory *packet_factory); + // for server side QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 4705eed3a00..b69e2b50374 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1330,6 +1330,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.stateless_retry", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.client.vn_exercise_enabled", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} + , {RECT_CONFIG, "proxy.config.quic.server.supported_groups", RECD_STRING, "P-256:X25519:P-384:P-521" , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.client.supported_groups", RECD_STRING, "P-256:X25519:P-384:P-521" , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} From 5c7db9f3f6a9b68954798d07acb7a90eaff2dca5 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 5 Apr 2018 11:08:26 +0900 Subject: [PATCH 0492/1313] Start handshake over when qvc received VERSION NEGOTIATION packet --- iocore/net/QUICNetVConnection.cc | 22 +++++++++++++++++++--- iocore/net/quic/QUICHandshake.cc | 10 ++++++++++ iocore/net/quic/QUICHandshake.h | 1 + 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6ea5de40713..e55e524c7e0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -819,7 +819,16 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack } error = this->_handshake_handler->negotiate_version(packet.get(), &this->_packet_factory); - // Initial packet will be retransmited with negotiated version + + // discard all transport state except packet number + this->_stream_manager->reset_send_offset(); + this->_stream_manager->reset_recv_offset(); + this->_loss_detector->reset(); + + // start handshake over + this->_handshake_handler->reset(); + this->_handshake_handler->handleEvent(VC_EVENT_WRITE_READY, nullptr); + this->_schedule_packet_write_ready(); return error; } @@ -1234,6 +1243,7 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi // TODO: support NET_VCONNECTION_IN if (this->get_context() == NET_VCONNECTION_OUT && type == QUICPacketType::UNINITIALIZED) { if (this->_last_received_packet_type == QUICPacketType::UNINITIALIZED || + this->_last_received_packet_type == QUICPacketType::VERSION_NEGOTIATION || this->_last_received_packet_type == QUICPacketType::RETRY) { type = QUICPacketType::INITIAL; } else if (_last_received_packet_type == QUICPacketType::HANDSHAKE) { @@ -1377,9 +1387,15 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) QUICConDebug("Unsupported version"); break; case QUICPacketCreationResult::SUCCESS: - QUICConDebug("Dequeue %s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), - quic_packet->packet_number(), quic_packet->size()); this->_last_received_packet_type = quic_packet->type(); + + if (quic_packet->type() == QUICPacketType::VERSION_NEGOTIATION) { + QUICConDebug("Dequeue %s size=%u", QUICDebugNames::packet_type(quic_packet->type()), quic_packet->size()); + } else { + QUICConDebug("Dequeue %s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), + quic_packet->packet_number(), quic_packet->size()); + } + break; default: QUICConDebug("Failed to decrypt the packet"); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 5d2484e1c67..94b431eaecc 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -374,6 +374,16 @@ QUICHandshake::msg_type() const } } +/** + * reset states for starting over + */ +void +QUICHandshake::reset() +{ + this->_initial = true; + SSL_clear(this->_ssl); +} + void QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_version) { diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 37e316e42a1..5274a668ab3 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -54,6 +54,7 @@ class QUICHandshake : public QUICApplication // for client side QUICErrorUPtr start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled); QUICErrorUPtr negotiate_version(const QUICPacket *packet, QUICPacketFactory *packet_factory); + void reset(); // for server side QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); From 864da3bde6765bc17943d8654010dd02635bc70c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 5 Apr 2018 12:19:06 +0900 Subject: [PATCH 0493/1313] Fix QUICHandshake::is_version_negotiated() To do not send ACK frame if VRESION NEGOTIATION packet was sent. --- iocore/net/QUICNetVConnection.cc | 7 +++---- iocore/net/quic/QUICHandshake.cc | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e55e524c7e0..4fcecd3b5ff 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -844,13 +844,12 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe // Start handshake QUICErrorUPtr error = this->_handshake_handler->start(packet.get(), &this->_packet_factory); + + // 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(std::move(packet)); - } else { - // Perhaps response packets for initial packet were lost. Pass packet to _recv_and_ack to send ack to the initial packet. - // Stream data will be discarded by offset mismatch. - error = this->_recv_and_ack(std::move(packet)); } + return error; } diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 94b431eaecc..37ec33442c0 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -186,7 +186,8 @@ QUICHandshake::negotiate_version(const QUICPacket *vn, QUICPacketFactory *packet bool QUICHandshake::is_version_negotiated() const { - return (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED); + return (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED || + this->_version_negotiator->status() == QUICVersionNegotiationStatus::VALIDATED); } bool From 375fe44b33f207e1ae6c24df8fe4656ee3c53cb6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 5 Apr 2018 14:45:32 +0900 Subject: [PATCH 0494/1313] Randomize Connection ID only if needed Connection id was rondomized every time when state_handshake reveiced QUIC_EVENT_PACKET_WRITE_READY event. --- iocore/net/QUICNetVConnection.cc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 4fcecd3b5ff..c57ec910e7c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -544,15 +544,6 @@ QUICNetVConnection::state_handshake(int event, Event *data) this->_switch_to_close_state(); } } else { - if (this->get_context() == NET_VCONNECTION_OUT && (this->_last_received_packet_type == QUICPacketType::RETRY)) { - QUICConnectionId tmp = this->_original_quic_connection_id; - this->_original_quic_connection_id.randomize(); - QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(tmp), - static_cast(this->_original_quic_connection_id)); - - this->_hs_protocol->initialize_key_materials(this->_original_quic_connection_id); - } - error = this->_state_common_send_packet(); } // Reschedule WRITE_READY @@ -1255,6 +1246,16 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi switch (type) { case QUICPacketType::INITIAL: ink_assert(this->get_context() == NET_VCONNECTION_OUT); + + if (this->_last_received_packet_type == QUICPacketType::RETRY) { + QUICConnectionId tmp = this->_original_quic_connection_id; + this->_original_quic_connection_id.randomize(); + QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(tmp), + static_cast(this->_original_quic_connection_id)); + + this->_hs_protocol->initialize_key_materials(this->_original_quic_connection_id); + } + packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len); this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); From 308d5794a8f6f225c02eac52e9fb11e1b047045b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 5 Apr 2018 15:31:43 +0900 Subject: [PATCH 0495/1313] Randomize Connection ID only if needed - take 2 Connection ID should not be changed if INITIAL packet is retransmitted --- iocore/net/QUICNetVConnection.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index c57ec910e7c..98be94b670c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -857,6 +857,14 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) this->_largest_received_packet_number = 0; this->_stream_manager->reset_recv_offset(); + // Generate new Connection ID + QUICConnectionId tmp = this->_original_quic_connection_id; + this->_original_quic_connection_id.randomize(); + QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(tmp), + static_cast(this->_original_quic_connection_id)); + + this->_hs_protocol->initialize_key_materials(this->_original_quic_connection_id); + return error; } @@ -1240,22 +1248,14 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi type = QUICPacketType::HANDSHAKE; } else if (this->_handshake_handler && this->_handshake_handler->is_completed()) { type = QUICPacketType::PROTECTED; + } else { + Error("Unsupported case"); } } switch (type) { case QUICPacketType::INITIAL: ink_assert(this->get_context() == NET_VCONNECTION_OUT); - - if (this->_last_received_packet_type == QUICPacketType::RETRY) { - QUICConnectionId tmp = this->_original_quic_connection_id; - this->_original_quic_connection_id.randomize(); - QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(tmp), - static_cast(this->_original_quic_connection_id)); - - this->_hs_protocol->initialize_key_materials(this->_original_quic_connection_id); - } - packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len); this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); From a34cac14b4bd89e83efd9fbcee1401a85a865e11 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 5 Apr 2018 16:06:49 +0900 Subject: [PATCH 0496/1313] Set inactivity timeout in/out appropriately --- iocore/net/QUICNetVConnection.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 98be94b670c..e8dbcb9eb5b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -491,7 +491,12 @@ QUICNetVConnection::state_pre_handshake(int event, Event *data) // FIXME: Should be accept_no_activity_timeout? QUICConfig::scoped_config params; - this->set_inactivity_timeout(HRTIME_SECONDS(params->no_activity_timeout_in())); + if (this->get_context() == NET_VCONNECTION_IN) { + this->set_inactivity_timeout(HRTIME_SECONDS(params->no_activity_timeout_in())); + } else { + this->set_inactivity_timeout(HRTIME_SECONDS(params->no_activity_timeout_out())); + } + this->add_to_active_queue(); this->_switch_to_handshake_state(); From 4a3ea0e945557f3934f23d683bb586074dc511d3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 4 Apr 2018 14:14:03 +0900 Subject: [PATCH 0497/1313] Catch up draft-10 --- iocore/net/quic/QUICDebugNames.cc | 10 +- iocore/net/quic/QUICFrame.cc | 146 ++++++++++-------- iocore/net/quic/QUICFrame.h | 84 ++++++---- iocore/net/quic/QUICHKDF.cc | 2 - iocore/net/quic/QUICKeyGenerator.cc | 2 +- iocore/net/quic/QUICPacket.cc | 3 +- iocore/net/quic/QUICTypes.h | 13 +- iocore/net/quic/test/test_QUICFrame.cc | 141 +++++++++++------ iocore/net/quic/test/test_QUICKeyGenerator.cc | 12 +- iocore/net/quic/test/test_QUICPacket.cc | 4 +- lib/ts/ink_inet.cc | 2 +- 11 files changed, 251 insertions(+), 168 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index f7ec117abbe..664f034f014 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -58,6 +58,8 @@ QUICDebugNames::frame_type(QUICFrameType type) return "RST_STREAM"; case QUICFrameType::CONNECTION_CLOSE: return "CONNECTION_CLOSE"; + case QUICFrameType::APPLICATION_CLOSE: + return "APPLICATION_CLOSE"; case QUICFrameType::MAX_DATA: return "MAX_DATA"; case QUICFrameType::MAX_STREAM_DATA: @@ -74,12 +76,16 @@ QUICDebugNames::frame_type(QUICFrameType type) return "STREAM_ID_BLOCKED"; case QUICFrameType::NEW_CONNECTION_ID: return "NEW_CONNECTION_ID"; + case QUICFrameType::STOP_SENDING: + return "STOP_SENDING"; case QUICFrameType::ACK: return "ACK"; + case QUICFrameType::PATH_CHALLENGE: + return "PATH_CHALLENGE"; + case QUICFrameType::PATH_RESPONSE: + return "PATH_RESPONSE"; case QUICFrameType::STREAM: return "STREAM"; - case QUICFrameType::PONG: - return "PONG"; case QUICFrameType::UNKNOWN: default: return "UNKNOWN"; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index c0d6fe60b71..0bb7cef02b2 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -40,7 +40,8 @@ ClassAllocator quicStreamBlockedFrameAllocator("quicStre ClassAllocator quicStreamIdBlockedFrameAllocator("quicStreamIdBlockedFrameAllocator"); ClassAllocator quicNewConnectionIdFrameAllocator("quicNewConnectionIdFrameAllocator"); ClassAllocator quicStopSendingFrameAllocator("quicStopSendingFrameAllocator"); -ClassAllocator quicPongFrameAllocator("quicPongFrameAllocator"); +ClassAllocator quicPathChallengeFrameAllocator("quicPathChallengeFrameAllocator"); +ClassAllocator quicPathResponseFrameAllocator("quicPathResponseFrameAllocator"); ClassAllocator quicRetransmissionFrameAllocator("quicRetransmissionFrameAllocator"); QUICFrameType @@ -56,8 +57,6 @@ QUICFrame::type(const uint8_t *buf) return QUICFrameType::UNKNOWN; } else if (buf[0] >= static_cast(QUICFrameType::STREAM)) { return QUICFrameType::STREAM; - } else if (buf[0] > static_cast(QUICFrameType::ACK)) { - return QUICFrameType::UNKNOWN; } else { return static_cast(buf[0]); } @@ -857,7 +856,7 @@ QUICPingFrame::type() const size_t QUICPingFrame::size() const { - return this->_data_offset() + this->data_length(); + return 1; } void @@ -869,38 +868,9 @@ QUICPingFrame::store(uint8_t *buf, size_t *len) const memcpy(buf, this->_buf, *len); } else { buf[0] = static_cast(QUICFrameType::PING); - buf[1] = this->data_length(); - - memcpy(buf + this->_data_offset(), this->data(), this->data_length()); - } -} - -const uint8_t * -QUICPingFrame::data() const -{ - if (this->_buf) { - return this->_buf + this->_data_offset(); - } else { - return this->_data.get(); - } -} - -uint8_t -QUICPingFrame::data_length() const -{ - if (this->_buf) { - return QUICIntUtil::read_nbytes_as_uint(this->_buf + sizeof(QUICFrameType), 1); - } else { - return this->_data_len; } } -const size_t -QUICPingFrame::_data_offset() const -{ - return sizeof(QUICFrameType) + sizeof(this->_data_len); -} - // // PADDING frame // @@ -1686,37 +1656,35 @@ QUICStopSendingFrame::_get_error_code_field_offset() const } // -// PONG frame +// PATH_CHALLENGE frame // QUICFrameType -QUICPongFrame::type() const +QUICPathChallengeFrame::type() const { - return QUICFrameType::PONG; + return QUICFrameType::PATH_CHALLENGE; } size_t -QUICPongFrame::size() const +QUICPathChallengeFrame::size() const { - return this->_data_offset() + this->data_length(); + return this->_data_offset() + QUICPathChallengeFrame::DATA_LEN; } void -QUICPongFrame::store(uint8_t *buf, size_t *len) const +QUICPathChallengeFrame::store(uint8_t *buf, size_t *len) const { *len = this->size(); if (this->_buf) { memcpy(buf, this->_buf, *len); } else { - buf[0] = static_cast(QUICFrameType::PONG); - buf[1] = this->data_length(); - - memcpy(buf + this->_data_offset(), this->data(), this->data_length()); + buf[0] = static_cast(QUICFrameType::PATH_CHALLENGE); + memcpy(buf + this->_data_offset(), this->data(), QUICPathChallengeFrame::DATA_LEN); } } const uint8_t * -QUICPongFrame::data() const +QUICPathChallengeFrame::data() const { if (this->_buf) { return this->_buf + this->_data_offset(); @@ -1725,20 +1693,54 @@ QUICPongFrame::data() const } } -uint8_t -QUICPongFrame::data_length() const +const size_t +QUICPathChallengeFrame::_data_offset() const { + return sizeof(QUICFrameType); +} + +// +// PATH_RESPONSE frame +// +QUICFrameType +QUICPathResponseFrame::type() const +{ + return QUICFrameType::PATH_RESPONSE; +} + +size_t +QUICPathResponseFrame::size() const +{ + return this->_data_offset() + 8; +} + +void +QUICPathResponseFrame::store(uint8_t *buf, size_t *len) const +{ + *len = this->size(); + if (this->_buf) { - return QUICIntUtil::read_nbytes_as_uint(this->_buf + sizeof(QUICFrameType), 1); + memcpy(buf, this->_buf, *len); } else { - return this->_data_len; + buf[0] = static_cast(QUICFrameType::PATH_RESPONSE); + memcpy(buf + this->_data_offset(), this->data(), QUICPathResponseFrame::DATA_LEN); + } +} + +const uint8_t * +QUICPathResponseFrame::data() const +{ + if (this->_buf) { + return this->_buf + this->_data_offset(); + } else { + return this->_data.get(); } } const size_t -QUICPongFrame::_data_offset() const +QUICPathResponseFrame::_data_offset() const { - return sizeof(QUICFrameType) + sizeof(this->_data_len); + return sizeof(QUICFrameType); } // @@ -1855,10 +1857,14 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicStopSendingFrameAllocator.alloc(); new (frame) QUICStopSendingFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stop_sending_frame); - case QUICFrameType::PONG: - frame = quicPongFrameAllocator.alloc(); - new (frame) QUICPongFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_pong_frame); + case QUICFrameType::PATH_CHALLENGE: + frame = quicPathChallengeFrameAllocator.alloc(); + new (frame) QUICPathChallengeFrame(buf, len); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_path_challenge_frame); + case QUICFrameType::PATH_RESPONSE: + frame = quicPathResponseFrameAllocator.alloc(); + new (frame) QUICPathResponseFrame(buf, len); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_path_response_frame); default: // Unknown frame Debug("quic_frame_factory", "Unknown frame type %x", buf[0]); @@ -1965,25 +1971,33 @@ QUICFrameFactory::create_max_stream_data_frame(QUICStreamId stream_id, uint64_t } std::unique_ptr -QUICFrameFactory::create_ping_frame(const uint8_t *data, size_t data_len) +QUICFrameFactory::create_ping_frame() { - ats_unique_buf buf = ats_unique_malloc(data_len); - memcpy(buf.get(), data, data_len); - QUICPingFrame *frame = quicPingFrameAllocator.alloc(); - new (frame) QUICPingFrame(std::move(buf), data_len); + new (frame) QUICPingFrame(true); return std::unique_ptr(frame, &QUICFrameDeleter::delete_ping_frame); } -std::unique_ptr -QUICFrameFactory::create_pong_frame(const QUICPingFrame &ping_frame) +std::unique_ptr +QUICFrameFactory::create_path_challenge_frame(const uint8_t *data) +{ + ats_unique_buf buf = ats_unique_malloc(QUICPathChallengeFrame::DATA_LEN); + memcpy(buf.get(), data, QUICPathChallengeFrame::DATA_LEN); + + QUICPathChallengeFrame *frame = quicPathChallengeFrameAllocator.alloc(); + new (frame) QUICPathChallengeFrame(std::move(buf)); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_challenge_frame); +} + +std::unique_ptr +QUICFrameFactory::create_path_response_frame(const QUICPathChallengeFrame &path_challenge_frame) { - ats_unique_buf buf = ats_unique_malloc(ping_frame.data_length()); - memcpy(buf.get(), ping_frame.data(), ping_frame.data_length()); + ats_unique_buf buf = ats_unique_malloc(QUICPathResponseFrame::DATA_LEN); + memcpy(buf.get(), path_challenge_frame.data(), QUICPathResponseFrame::DATA_LEN); - QUICPongFrame *frame = quicPongFrameAllocator.alloc(); - new (frame) QUICPongFrame(std::move(buf), ping_frame.data_length()); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_pong_frame); + QUICPathResponseFrame *frame = quicPathResponseFrameAllocator.alloc(); + new (frame) QUICPathResponseFrame(std::move(buf)); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_challenge_frame); } std::unique_ptr diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 5e21ef45027..2cc50fda0ac 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -260,23 +260,13 @@ class QUICPingFrame : public QUICFrame public: QUICPingFrame() : QUICFrame() {} QUICPingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICPingFrame(ats_unique_buf data, size_t data_len, bool protection = true) - : QUICFrame(protection), _data(std::move(data)), _data_len(data_len) - { - } + QUICPingFrame(bool protection) : QUICFrame(protection) {} virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; - const uint8_t *data() const; - uint8_t data_length() const; - private: - const size_t _data_offset() const; - - ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; - uint8_t _data_len = 0; }; // PADDING @@ -541,38 +531,58 @@ class QUICStopSendingFrame : public QUICFrame QUICAppErrorCode _error_code = 0; }; -using QUICFrameDeleterFunc = void (*)(QUICFrame *p); -using QUICFrameUPtr = std::unique_ptr; -using QUICStreamFrameUPtr = std::unique_ptr; +// +// PATH_CHALLENGE +// + +class QUICPathChallengeFrame : public QUICFrame +{ +public: + static constexpr uint8_t DATA_LEN = 8; + QUICPathChallengeFrame() : QUICFrame() {} + QUICPathChallengeFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICPathChallengeFrame(ats_unique_buf data, bool protection = true) : QUICFrame(protection), _data(std::move(data)) {} + + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual void store(uint8_t *buf, size_t *len) const override; + + const uint8_t *data() const; + +private: + const size_t _data_offset() const; + + ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; +}; // -// PONG +// PATH_RESPONSE // -class QUICPongFrame : public QUICFrame +class QUICPathResponseFrame : public QUICFrame { public: - QUICPongFrame() : QUICFrame() {} - QUICPongFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICPongFrame(ats_unique_buf data, size_t data_len, bool protection = true) - : QUICFrame(protection), _data(std::move(data)), _data_len(data_len) - { - } + static constexpr uint8_t DATA_LEN = 8; + QUICPathResponseFrame() : QUICFrame() {} + QUICPathResponseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICPathResponseFrame(ats_unique_buf data, bool protection = true) : QUICFrame(protection), _data(std::move(data)) {} virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; const uint8_t *data() const; - uint8_t data_length() const; private: const size_t _data_offset() const; ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; - uint8_t _data_len = 0; }; +using QUICFrameDeleterFunc = void (*)(QUICFrame *p); +using QUICFrameUPtr = std::unique_ptr; +using QUICStreamFrameUPtr = std::unique_ptr; + // // Retransmission Frame // @@ -608,7 +618,8 @@ extern ClassAllocator quicStreamBlockedFrameAllocator; extern ClassAllocator quicStreamIdBlockedFrameAllocator; extern ClassAllocator quicNewConnectionIdFrameAllocator; extern ClassAllocator quicStopSendingFrameAllocator; -extern ClassAllocator quicPongFrameAllocator; +extern ClassAllocator quicPathChallengeFrameAllocator; +extern ClassAllocator quicPathResponseFrameAllocator; extern ClassAllocator quicRetransmissionFrameAllocator; class QUICFrameDeleter @@ -727,10 +738,17 @@ class QUICFrameDeleter } static void - delete_pong_frame(QUICFrame *frame) + delete_path_challenge_frame(QUICFrame *frame) + { + frame->~QUICFrame(); + quicPathChallengeFrameAllocator.free(static_cast(frame)); + } + + static void + delete_path_response_frame(QUICFrame *frame) { frame->~QUICFrame(); - quicPongFrameAllocator.free(static_cast(frame)); + quicPathResponseFrameAllocator.free(static_cast(frame)); } static void @@ -809,12 +827,18 @@ class QUICFrameFactory /* * Creates a PING frame */ - static std::unique_ptr create_ping_frame(const uint8_t *data, size_t data_len); + static std::unique_ptr create_ping_frame(); + + /* + * Creates a PATH_CHALLENGE frame + */ + static std::unique_ptr create_path_challenge_frame(const uint8_t *data); /* - * Creates a PONG frame + * Creates a PATH_RESPONSE frame */ - static std::unique_ptr create_pong_frame(const QUICPingFrame &ping_frame); + static std::unique_ptr create_path_response_frame( + const QUICPathChallengeFrame &path_challenge_frame); /* * Creates a BLOCKED frame. diff --git a/iocore/net/quic/QUICHKDF.cc b/iocore/net/quic/QUICHKDF.cc index adb2cff2344..fd0bd9dc0fa 100644 --- a/iocore/net/quic/QUICHKDF.cc +++ b/iocore/net/quic/QUICHKDF.cc @@ -38,8 +38,6 @@ QUICHKDF::expand(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t se // "QUIC " + Label hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%cQUIC %.*s", static_cast(5 + label_len), static_cast(label_len), label); - // Hash Value - hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%c%.*s", 0, 0, ""); HKDF::expand(dst, dst_len, secret, secret_len, hkdf_label, hkdf_label_len, length); return 1; diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 9cd1f3792d4..bd5fb28a725 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -27,7 +27,7 @@ #include "QUICHKDF.h" constexpr static uint8_t QUIC_VERSION_1_SALT[] = { - 0xaf, 0xc8, 0x24, 0xec, 0x5f, 0xc7, 0x7e, 0xca, 0x1e, 0x9d, 0x36, 0xf3, 0x7f, 0xb2, 0xd4, 0x65, 0x18, 0xc3, 0x66, 0x39, + 0x9c, 0x10, 0x8f, 0x98, 0x52, 0x0a, 0x5c, 0x5c, 0x32, 0x96, 0x8e, 0x95, 0x0e, 0x8a, 0x2c, 0x5f, 0xe0, 0x6d, 0x6c, 0x38, }; constexpr static ts::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("client hs"_sv); constexpr static ts::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("server hs"_sv); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 61e19ba9aa4..380cbe849ce 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -363,7 +363,7 @@ QUICPacketShortHeader::_packet_number_len() const { QUICPacketShortHeaderType type; if (this->_buf) { - type = static_cast(this->_buf.get()[0] & 0x1F); + type = static_cast(this->_buf.get()[0] & 0x07); } else { type = this->_packet_number_type; } @@ -463,6 +463,7 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const if (this->_key_phase == QUICKeyPhase::PHASE_1) { buf[0] += 0x20; } + buf[0] += 0x10; buf[0] += static_cast(this->_packet_number_type); *len += 1; if (this->_has_connection_id) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 57de3919ee5..80101da49e4 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -47,7 +47,7 @@ using QUICOffset = uint64_t; // Note: You also need to update tests for VersionNegotiationPacket creation, if you change the number of versions // Prefix for drafts (0xff000000) + draft number constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff000009, + 0xff00000a, }; constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; @@ -74,10 +74,10 @@ enum class QUICPacketType : uint8_t { // To detect length of Packet Number enum class QUICPacketShortHeaderType : int { - ONE = 0x1F, - TWO = 0x1E, - THREE = 0x1D, - UNINITIALIZED = 0x1C, + ONE = 0x0, + TWO = 0x1, + THREE = 0x2, + UNINITIALIZED = 0x3, }; // XXX If you add or remove QUICFrameType, you might also need to change QUICFrame::type(const uint8_t *) @@ -95,8 +95,9 @@ enum class QUICFrameType : uint8_t { STREAM_ID_BLOCKED, NEW_CONNECTION_ID, STOP_SENDING, - PONG, ACK, + PATH_CHALLENGE, + PATH_RESPONSE, STREAM = 0x10, // 0x10 - 0x17 UNKNOWN = 0x18, }; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index dcd12b4d699..fd4f4e5d0cd 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -42,10 +42,9 @@ TEST_CASE("QUICFrame Type", "[quic]") CHECK(QUICFrame::type(reinterpret_cast("\x0a")) == QUICFrameType::STREAM_ID_BLOCKED); CHECK(QUICFrame::type(reinterpret_cast("\x0b")) == QUICFrameType::NEW_CONNECTION_ID); CHECK(QUICFrame::type(reinterpret_cast("\x0c")) == QUICFrameType::STOP_SENDING); - CHECK(QUICFrame::type(reinterpret_cast("\x0d")) == QUICFrameType::PONG); - CHECK(QUICFrame::type(reinterpret_cast("\x0e")) == QUICFrameType::ACK); - // Undefined ragne - CHECK(QUICFrame::type(reinterpret_cast("\x0f")) == QUICFrameType::UNKNOWN); + CHECK(QUICFrame::type(reinterpret_cast("\x0d")) == QUICFrameType::ACK); + CHECK(QUICFrame::type(reinterpret_cast("\x0e")) == QUICFrameType::PATH_CHALLENGE); + CHECK(QUICFrame::type(reinterpret_cast("\x0f")) == QUICFrameType::PATH_RESPONSE); // Range of STREAM CHECK(QUICFrame::type(reinterpret_cast("\x10")) == QUICFrameType::STREAM); CHECK(QUICFrame::type(reinterpret_cast("\x17")) == QUICFrameType::STREAM); @@ -328,7 +327,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") { uint8_t buf1[] = { - 0x0e, // Type + 0x0d, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x00, // Ack Block Count @@ -347,7 +346,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") { uint8_t buf1[] = { - 0x0e, // Type + 0x0d, // Type 0x80, 0x00, 0x00, 0x01, // Largest Acknowledged 0x41, 0x71, // Ack Delay 0x00, // Ack Block Count @@ -370,7 +369,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("2 Ack Block, 8 bit packet number length, 8 bit block length") { uint8_t buf1[] = { - 0x0e, // Type + 0x0d, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x02, // Ack Block Count @@ -413,7 +412,7 @@ TEST_CASE("Store Ack Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x0e, // Type + 0x0d, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x00, // Ack Block Count @@ -434,7 +433,7 @@ TEST_CASE("Store Ack Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x0e, // Type + 0x0d, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x02, // Ack Block Count @@ -496,18 +495,14 @@ TEST_CASE("Store RST_STREAM Frame", "[quic]") TEST_CASE("Load Ping Frame", "[quic]") { uint8_t buf[] = { - 0x07, // Type - 0x08, // Length - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + 0x07, // Type }; std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::PING); - CHECK(frame->size() == 10); + CHECK(frame->size() == 1); std::shared_ptr ping_frame = std::dynamic_pointer_cast(frame); CHECK(ping_frame != nullptr); - CHECK(ping_frame->data_length() == 8); - CHECK(memcmp(ping_frame->data(), "\x01\x23\x45\x67\x89\xab\xcd\xef", 8) == 0); } TEST_CASE("Store Ping Frame", "[quic]") @@ -516,21 +511,14 @@ TEST_CASE("Store Ping Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x07, // Type - 0x08, // Length - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + 0x07, // Type }; - uint8_t raw[] = "\x01\x23\x45\x67\x89\xab\xcd\xef"; - size_t raw_len = sizeof(raw) - 1; - ats_unique_buf data = ats_unique_malloc(raw_len); - memcpy(data.get(), raw, raw_len); - - QUICPingFrame frame(std::move(data), 8); - CHECK(frame.size() == 10); + QUICPingFrame frame(true); + CHECK(frame.size() == 1); frame.store(buf, &len); - CHECK(len == 10); + CHECK(len == 1); CHECK(memcmp(buf, expected, len) == 0); } @@ -989,31 +977,29 @@ TEST_CASE("Store STOP_SENDING Frame", "[quic]") CHECK(memcmp(buf, expected, len) == 0); } -TEST_CASE("Load Pong Frame", "[quic]") +TEST_CASE("Load PATH_CHALLENGE Frame", "[quic]") { uint8_t buf[] = { - 0x0d, // Type - 0x08, // Length + 0x0e, // Type 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); - CHECK(frame->type() == QUICFrameType::PONG); - CHECK(frame->size() == 10); + CHECK(frame->type() == QUICFrameType::PATH_CHALLENGE); + CHECK(frame->size() == 9); - std::shared_ptr pong_frame = std::dynamic_pointer_cast(frame); - CHECK(pong_frame != nullptr); - CHECK(pong_frame->data_length() == 8); - CHECK(memcmp(pong_frame->data(), "\x01\x23\x45\x67\x89\xab\xcd\xef", 8) == 0); + std::shared_ptr path_challenge_frame = + std::dynamic_pointer_cast(frame); + CHECK(path_challenge_frame != nullptr); + CHECK(memcmp(path_challenge_frame->data(), "\x01\x23\x45\x67\x89\xab\xcd\xef", QUICPathChallengeFrame::DATA_LEN) == 0); } -TEST_CASE("Store Pong Frame", "[quic]") +TEST_CASE("Store PATH_CHALLENGE Frame", "[quic]") { uint8_t buf[16]; size_t len; uint8_t expected[] = { - 0x0d, // Type - 0x08, // Length + 0x0e, // Type 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; @@ -1022,18 +1008,56 @@ TEST_CASE("Store Pong Frame", "[quic]") ats_unique_buf data = ats_unique_malloc(raw_len); memcpy(data.get(), raw, raw_len); - QUICPongFrame frame(std::move(data), 8); - CHECK(frame.size() == 10); + QUICPathChallengeFrame frame(std::move(data), QUICPathChallengeFrame::DATA_LEN); + CHECK(frame.size() == 9); frame.store(buf, &len); - CHECK(len == 10); + CHECK(len == 9); + CHECK(memcmp(buf, expected, len) == 0); +} + +TEST_CASE("Load PATH_RESPONSE Frame", "[quic]") +{ + uint8_t buf[] = { + 0x0f, // Type + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + }; + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::PATH_RESPONSE); + CHECK(frame->size() == 9); + + std::shared_ptr path_response_frame = std::dynamic_pointer_cast(frame); + CHECK(path_response_frame != nullptr); + CHECK(memcmp(path_response_frame->data(), "\x01\x23\x45\x67\x89\xab\xcd\xef", QUICPathResponseFrame::DATA_LEN) == 0); +} + +TEST_CASE("Store PATH_RESPONSE Frame", "[quic]") +{ + uint8_t buf[16]; + size_t len; + + uint8_t expected[] = { + 0x0f, // Type + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + }; + + uint8_t raw[] = "\x01\x23\x45\x67\x89\xab\xcd\xef"; + size_t raw_len = sizeof(raw) - 1; + ats_unique_buf data = ats_unique_malloc(raw_len); + memcpy(data.get(), raw, raw_len); + + QUICPathResponseFrame frame(std::move(data), QUICPathResponseFrame::DATA_LEN); + CHECK(frame.size() == 9); + + frame.store(buf, &len); + CHECK(len == 9); CHECK(memcmp(buf, expected, len) == 0); } TEST_CASE("QUICFrameFactory Create Unknown Frame", "[quic]") { uint8_t buf1[] = { - 0x0f, // Type + 0x20, // Type }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1 == nullptr); @@ -1073,7 +1097,7 @@ TEST_CASE("QUICFrameFactory Fast Create Unknown Frame", "[quic]") QUICFrameFactory factory; uint8_t buf1[] = { - 0x0f, // Type + 0x20, // Type }; std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); CHECK(frame1 == nullptr); @@ -1255,9 +1279,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") SECTION("PING frame") { uint8_t frame_buf[] = { - 0x07, // Type - 0x08, // Length - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + 0x07, // Type }; QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); @@ -1267,7 +1289,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") size_t len; frame->store(buf, &len); - CHECK(len == 10); + CHECK(len == 1); CHECK(memcmp(buf, frame_buf, len) == 0); } @@ -1366,11 +1388,28 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") CHECK(memcmp(buf, frame_buf, len) == 0); } - SECTION("PONG frame") + SECTION("PATH_CHALLENGE frame") { uint8_t frame_buf[] = { - 0x0d, // Type - 0x08, // Length + 0x0e, // Type + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len); + + CHECK(len == 9); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + + SECTION("PATH_RESPONSE frame") + { + uint8_t frame_buf[] = { + 0x0f, // Type 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; @@ -1381,7 +1420,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") size_t len; frame->store(buf, &len); - CHECK(len == 10); + CHECK(len == 9); CHECK(memcmp(buf, frame_buf, len) == 0); } } diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index f364f0c54a3..1f94296c45f 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -57,9 +57,9 @@ TEST_CASE("QUICKeyGenerator", "[quic]") QUICKeyGenerator keygen(QUICKeyGenerator::Context::CLIENT); QUICConnectionId cid = 0x8394c8f03e515708; - uint8_t expected_client_key[] = {0x6b, 0x6a, 0xbc, 0x50, 0xf7, 0xac, 0x46, 0xd1, - 0x10, 0x8c, 0x19, 0xcc, 0x63, 0x64, 0xbd, 0xe3}; - uint8_t expected_client_iv[] = {0xb1, 0xf9, 0xa7, 0xe2, 0x7c, 0xc2, 0x33, 0xbb, 0x99, 0xe2, 0x03, 0x71}; + uint8_t expected_client_key[] = {0x3a, 0xd0, 0x54, 0x2c, 0x4a, 0x85, 0x84, 0x74, + 0x00, 0x63, 0x04, 0x9e, 0x3b, 0x3c, 0xaa, 0xb2}; + uint8_t expected_client_iv[] = {0xd1, 0xfd, 0x26, 0x05, 0x42, 0x75, 0x3a, 0xba, 0x38, 0x58, 0x9b, 0xad}; std::unique_ptr actual_km = keygen.generate(cid); @@ -74,9 +74,9 @@ TEST_CASE("QUICKeyGenerator", "[quic]") QUICKeyGenerator keygen(QUICKeyGenerator::Context::SERVER); QUICConnectionId cid = 0x8394c8f03e515708; - uint8_t expected_server_key[] = {0x9e, 0xe7, 0xe8, 0x57, 0x72, 0x00, 0x59, 0xaf, - 0x30, 0x11, 0xfb, 0x26, 0xe1, 0x21, 0x42, 0xc9}; - uint8_t expected_server_iv[] = {0xd5, 0xee, 0xe8, 0xb5, 0x7c, 0x9e, 0xc7, 0xc4, 0xbe, 0x98, 0x4a, 0xa5}; + uint8_t expected_server_key[] = {0xbe, 0xe4, 0xc2, 0x4d, 0x2a, 0xf1, 0x33, 0x80, + 0xa9, 0xfa, 0x24, 0xa5, 0xe2, 0xba, 0x2c, 0xff}; + uint8_t expected_server_iv[] = {0x25, 0xb5, 0x8e, 0x24, 0x6d, 0x9e, 0x7d, 0x5f, 0xfe, 0x43, 0x23, 0xfe}; std::unique_ptr actual_km = keygen.generate(cid); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 1d79ac21e0c..3b9518128bd 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -109,7 +109,7 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") SECTION("Short Header (load)") { const uint8_t input[] = { - 0x1D, // Short header with (C=0, K=0, Type=0x1D) + 0x12, // Short header with (C=0, K=0, Type=0x2) 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID 0x12, 0x34, 0x56, 0x78, // Packet number 0xff, 0xff, // Payload (dummy) @@ -132,7 +132,7 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") size_t len = 0; const uint8_t expected[] = { - 0x1D, // Short header with (C=0, K=0, Type=0x1D) + 0x12, // Short header with (C=0, K=0, Type=0x2) 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID 0x12, 0x34, 0x56, 0x78, // Packet number 0x11, 0x22, 0x33, 0x44, 0x55, // Protected Payload diff --git a/lib/ts/ink_inet.cc b/lib/ts/ink_inet.cc index 93469233e93..947bf451c0c 100644 --- a/lib/ts/ink_inet.cc +++ b/lib/ts/ink_inet.cc @@ -45,7 +45,7 @@ const ts::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"_sv); const ts::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"_sv); const ts::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"_sv); const ts::string_view IP_PROTO_TAG_HTTP_2_0("h2"_sv); // HTTP/2 over TLS -const ts::string_view IP_PROTO_TAG_HTTP_QUIC("hq-09"_sv); // HTTP over QUIC +const ts::string_view IP_PROTO_TAG_HTTP_QUIC("hq-10"_sv); // HTTP over QUIC uint32_t ink_inet_addr(const char *s) From 80763750fcfedf5ad2e8257549a67c2373e14ea4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 5 Apr 2018 14:18:35 +0900 Subject: [PATCH 0498/1313] Add Path Validator --- iocore/net/P_QUICNetVConnection.h | 2 + iocore/net/QUICNetVConnection.cc | 16 ++++ iocore/net/quic/Makefile.am | 1 + iocore/net/quic/QUICFrame.cc | 4 +- iocore/net/quic/QUICFrame.h | 3 +- iocore/net/quic/QUICPathValidator.cc | 121 +++++++++++++++++++++++++++ iocore/net/quic/QUICPathValidator.h | 61 ++++++++++++++ iocore/net/quic/QUICTypes.h | 10 ++- 8 files changed, 210 insertions(+), 8 deletions(-) create mode 100644 iocore/net/quic/QUICPathValidator.cc create mode 100644 iocore/net/quic/QUICPathValidator.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e68b2e2c26c..a0077b1b0f2 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -57,6 +57,7 @@ #include "quic/QUICLossDetector.h" #include "quic/QUICStreamManager.h" #include "quic/QUICAltConnectionManager.h" +#include "quic/QUICPathValidator.h" #include "quic/QUICApplicationMap.h" // These are included here because older OpenQUIC libraries don't have them. @@ -252,6 +253,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICLocalFlowController *_local_flow_controller = nullptr; QUICConnectionTable *_ctable = nullptr; QUICAltConnectionManager *_alt_con_manager = nullptr; + QUICPathValidator *_path_validator = nullptr; CountQueue _packet_recv_queue; CountQueue _packet_send_queue; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e8dbcb9eb5b..58f368d798f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -201,10 +201,12 @@ QUICNetVConnection::start() this->_loss_detector = new QUICLossDetector(this, this->_congestion_controller); this->_remote_flow_controller = new QUICRemoteConnectionFlowController(0); this->_local_flow_controller = new QUICLocalConnectionFlowController(0); + this->_path_validator = new QUICPathValidator(); this->_frame_dispatcher->add_handler(this); this->_frame_dispatcher->add_handler(this->_stream_manager); this->_frame_dispatcher->add_handler(this->_loss_detector); + this->_frame_dispatcher->add_handler(this->_path_validator); } void @@ -1119,6 +1121,20 @@ QUICNetVConnection::_packetize_frames() this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); } + // PATH_CHALLENGE, PATH_RESPOSNE + frame = this->_path_validator->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); + while (frame) { + ++frame_count; + this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + if (this->_the_final_packet) { + return; + } + if (frame_count >= FRAME_PER_EVENT) { + break; + } + frame = this->_path_validator->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); + } + // CONNECTION_CLOSE, APPLICATION_CLOSE if (this->_connection_error) { QUICFrameUPtr frame = QUICFrameFactory::create_null_ack_frame(); diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index c682941be7a..6b8da87ee56 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -75,6 +75,7 @@ libquic_a_SOURCES = \ QUICApplicationMap.cc \ QUICIncomingFrameBuffer.cc \ QUICPacketRetransmitter.cc \ + QUICPathValidator.cc \ QUICStatelessRetry.cc include $(top_srcdir)/build/tidy.mk diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 0bb7cef02b2..a2fadd9578f 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1990,10 +1990,10 @@ QUICFrameFactory::create_path_challenge_frame(const uint8_t *data) } std::unique_ptr -QUICFrameFactory::create_path_response_frame(const QUICPathChallengeFrame &path_challenge_frame) +QUICFrameFactory::create_path_response_frame(const uint8_t *data) { ats_unique_buf buf = ats_unique_malloc(QUICPathResponseFrame::DATA_LEN); - memcpy(buf.get(), path_challenge_frame.data(), QUICPathResponseFrame::DATA_LEN); + memcpy(buf.get(), data, QUICPathResponseFrame::DATA_LEN); QUICPathResponseFrame *frame = quicPathResponseFrameAllocator.alloc(); new (frame) QUICPathResponseFrame(std::move(buf)); diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 2cc50fda0ac..f8715413146 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -837,8 +837,7 @@ class QUICFrameFactory /* * Creates a PATH_RESPONSE frame */ - static std::unique_ptr create_path_response_frame( - const QUICPathChallengeFrame &path_challenge_frame); + static std::unique_ptr create_path_response_frame(const uint8_t *data); /* * Creates a BLOCKED frame. diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc new file mode 100644 index 00000000000..b779970dce8 --- /dev/null +++ b/iocore/net/quic/QUICPathValidator.cc @@ -0,0 +1,121 @@ +/** @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 "QUICPathValidator.h" + +bool +QUICPathValidator::is_validated() +{ + return this->_state == ValidationState::VALIDATED; +} + +void +QUICPathValidator::validate() +{ + if (this->_state == ValidationState::VALIDATING) { + // Do nothing + } else { + this->_generate_challenge(); + } +} + +void +QUICPathValidator::_generate_challenge() +{ + for (int i = countof(this->_outgoing_challenge) - 1; i >= 0; --i) { + // TODO Randomize challenge data + this->_outgoing_challenge[i] = i; + } + this->_has_outgoing_challenge = true; +} + +void +QUICPathValidator::_generate_response(std::shared_ptr frame) +{ + memcpy(this->_incoming_challenge, frame->data(), QUICPathChallengeFrame::DATA_LEN); + this->_has_outgoing_response = true; +} + +QUICErrorUPtr +QUICPathValidator::_validate_response(std::shared_ptr frame) +{ + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + + if (memcmp(this->_outgoing_challenge, frame->data(), QUICPathChallengeFrame::DATA_LEN) != 0) { + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE)); + } + + return error; +} + +// +// QUICFrameHandler +// +std::vector +QUICPathValidator::interests() +{ + return {QUICFrameType::PATH_CHALLENGE, QUICFrameType::PATH_RESPONSE}; +} + +QUICErrorUPtr +QUICPathValidator::handle_frame(std::shared_ptr frame) +{ + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + + switch (frame->type()) { + case QUICFrameType::PATH_CHALLENGE: + this->_generate_response(std::static_pointer_cast(frame)); + break; + case QUICFrameType::PATH_RESPONSE: + error = this->_validate_response(std::static_pointer_cast(frame)); + break; + default: + ink_assert(!"Can't happen"); + } + + return error; +} + +// +// QUICFrameGenerator +// +bool +QUICPathValidator::will_generate_frame() +{ + return (this->_has_outgoing_challenge || this->_has_outgoing_response); +} + +QUICFrameUPtr +QUICPathValidator::generate_frame(uint16_t connection_credit, uint16_t maximum_quic_packet_size) +{ + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + + if (this->_has_outgoing_response) { + frame = QUICFrameFactory::create_path_response_frame(this->_incoming_challenge); + this->_has_outgoing_response = false; + } else if (this->_has_outgoing_challenge) { + frame = QUICFrameFactory::create_path_challenge_frame(this->_outgoing_challenge); + this->_has_outgoing_challenge = false; + } + return frame; +} diff --git a/iocore/net/quic/QUICPathValidator.h b/iocore/net/quic/QUICPathValidator.h new file mode 100644 index 00000000000..f6e6818e667 --- /dev/null +++ b/iocore/net/quic/QUICPathValidator.h @@ -0,0 +1,61 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include "QUICTypes.h" +#include "QUICFrameHandler.h" +#include "QUICFrameGenerator.h" + +class QUICPathValidator : public QUICFrameHandler, public QUICFrameGenerator +{ +public: + QUICPathValidator() {} + bool is_validated(); + void validate(); + + // QUICFrameHandler + std::vector interests() override; + QUICErrorUPtr handle_frame(std::shared_ptr frame) override; + + // QUICFrameGeneratro + bool will_generate_frame() override; + QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) override; + +private: + enum class ValidationState : int { + NOT_VALIDATED, + VALIDATING, + VALIDATED, + }; + ValidationState _state = ValidationState::NOT_VALIDATED; + bool _has_outgoing_challenge = false; + bool _has_outgoing_response = false; + uint8_t _incoming_challenge[QUICPathChallengeFrame::DATA_LEN]; + uint8_t _outgoing_challenge[QUICPathChallengeFrame::DATA_LEN]; + + void _generate_challenge(); + void _generate_response(std::shared_ptr frame); + QUICErrorUPtr _validate_response(std::shared_ptr frame); +}; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 80101da49e4..25481bf725b 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -133,16 +133,18 @@ enum class QUICErrorClass { enum class QUICTransErrorCode : uint16_t { NO_ERROR = 0x00, INTERNAL_ERROR, - FLOW_CONTROL_ERROR = 0x03, + SERVER_BUSY, + FLOW_CONTROL_ERROR, STREAM_ID_ERROR, STREAM_STATE_ERROR, FINAL_OFFSET_ERROR, FRAME_FORMAT_ERROR, TRANSPORT_PARAMETER_ERROR, VERSION_NEGOTIATION_ERROR, - PROTOCOL_VIOLATION = 0x0A, - FRAME_ERROR = 0x0100, // 0x100 - 0x1FF - TLS_HANDSHAKE_FAILED = 0x0201, + PROTOCOL_VIOLATION, + UNSOLICITED_PATH_RESPONSE = 0x0B, + FRAME_ERROR = 0x0100, // 0x100 - 0x1FF + TLS_HANDSHAKE_FAILED = 0x0201, TLS_FATAL_ALERT_GENERATED, TLS_FATAL_ALERT_RECEIVED, }; From 20e97be78d145efbf8eca927add0684332767a81 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 9 Apr 2018 12:11:58 +0900 Subject: [PATCH 0499/1313] Set new endpoint to QNetVC when connection migration happens --- iocore/net/QUICNetVConnection.cc | 6 ++++- iocore/net/quic/QUICPacket.cc | 23 +++++++++++++---- iocore/net/quic/QUICPacket.h | 25 ++++++++++++++----- iocore/net/quic/test/test_QUICPacket.cc | 6 ++--- .../net/quic/test/test_QUICPacketFactory.cc | 2 +- 5 files changed, 46 insertions(+), 16 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 58f368d798f..4ad106cd8d0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -922,6 +922,9 @@ QUICNetVConnection::_state_common_receive_packet() // TODO Address Validation // TODO Adjust expected packet number with a gap computed based on info.seq_num this->_quic_connection_id = p->connection_id(); + Connection con; + con.setRemote(&p->from().sa); + this->con.move(con); } else { // TODO Send some error? } @@ -1392,7 +1395,8 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) } udp_packet->free(); - quic_packet = this->_packet_factory.create(std::move(pkt), written, this->largest_received_packet_number(), result); + quic_packet = + this->_packet_factory.create(udp_packet->from, std::move(pkt), written, this->largest_received_packet_number(), result); switch (result) { case QUICPacketCreationResult::NOT_READY: QUICConDebug("Not ready to decrypt the packet"); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 380cbe849ce..9f3f5881802 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -56,6 +56,12 @@ QUICPacketHeader::buf() } } +const IpEndpoint & +QUICPacketHeader::from() const +{ + return this->_from; +} + uint16_t QUICPacketHeader::packet_size() const { @@ -63,16 +69,16 @@ QUICPacketHeader::packet_size() const } QUICPacketHeaderUPtr -QUICPacketHeader::load(ats_unique_buf buf, size_t len, QUICPacketNumber base) +QUICPacketHeader::load(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base) { QUICPacketHeaderUPtr header = QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header); if (QUICTypeUtil::has_long_header(buf.get())) { QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); - new (long_header) QUICPacketLongHeader(std::move(buf), len, base); + new (long_header) QUICPacketLongHeader(from, std::move(buf), len, base); header = QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); } else { QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); - new (short_header) QUICPacketShortHeader(std::move(buf), len, base); + new (short_header) QUICPacketShortHeader(from, std::move(buf), len, base); header = QUICPacketHeaderUPtr(short_header, &QUICPacketHeaderDeleter::delete_short_header); } return header; @@ -507,6 +513,12 @@ QUICPacket::~QUICPacket() this->_header = nullptr; } +const IpEndpoint & +QUICPacket::from() const +{ + return this->_header->from(); +} + /** * When packet is "Short Header Packet", QUICPacket::type() will return 1-RTT Protected (key phase 0) * or 1-RTT Protected (key phase 1) @@ -665,13 +677,14 @@ QUICPacketFactory::create_null_packet() } QUICPacketUPtr -QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result) +QUICPacketFactory::create(IpEndpoint from, 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(std::move(buf), len, base_packet_number); + QUICPacketHeaderUPtr header = QUICPacketHeader::load(from, std::move(buf), len, base_packet_number); if (header->has_version() && !QUICTypeUtil::is_supported_version(header->version())) { if (header->type() == QUICPacketType::VERSION_NEGOTIATION) { diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 6a87d1e1c12..8ec0845eaa4 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -52,12 +52,15 @@ using QUICPacketHeaderUPtr = std::unique_ptr(input), [](void *p) {}}, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); CHECK(header->size() == 13); CHECK(header->packet_size() == 21); CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); @@ -58,7 +58,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0xff, 0xff, // Payload (dummy) }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({const_cast(input), [](void *p) {}}, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); CHECK(header->size() == 17); CHECK(header->packet_size() == 19); CHECK(header->type() == QUICPacketType::INITIAL); @@ -115,7 +115,7 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") 0xff, 0xff, // Payload (dummy) }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({const_cast(input), [](void *p) {}}, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); CHECK(header->size() == 13); CHECK(header->packet_size() == 15); CHECK(header->has_key_phase() == true); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index e0be9f18df8..8fcb9d88d26 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -42,7 +42,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x00 // Payload }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({initial_packet_header, [](void *) {}}, sizeof(initial_packet_header), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {initial_packet_header, [](void *) {}}, sizeof(initial_packet_header), 0); QUICPacket initial_packet(std::move(header), ats_unique_buf(initial_packet_payload, [](void *) {}), sizeof(initial_packet_payload), 0); From 5fa569877e56cdddb0bae36effd61140b3218809 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 9 Apr 2018 17:02:57 +0900 Subject: [PATCH 0500/1313] Send PATH_CHALLENGE when receives a packet with an alternative CID --- iocore/net/P_QUICNetVConnection.h | 5 +++ iocore/net/QUICNetVConnection.cc | 42 +++++++++++++++++++ iocore/net/quic/QUICEvents.h | 1 + iocore/net/quic/QUICPathValidator.cc | 1 + .../net/quic/test/test_QUICPacketFactory.cc | 3 +- 5 files changed, 51 insertions(+), 1 deletion(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index a0077b1b0f2..9d8523ad622 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -276,6 +276,11 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _close_closed_event(Event *data); Event *_closed_event = nullptr; + void _schedule_path_validation_timeout(ink_hrtime interval); + void _unschedule_path_validation_timeout(); + void _close_path_validation_timeout(Event *data); + Event *_path_validation_timeout = nullptr; + uint32_t _maximum_stream_frame_data_size(); uint32_t _transmit_packet(QUICPacketUPtr packet); void _store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 4ad106cd8d0..8c19e6c459b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -590,6 +590,10 @@ QUICNetVConnection::state_connection_established(int event, Event *data) this->_schedule_packet_write_ready(true); break; } + case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: + this->_close_path_validation_timeout(data); + this->_switch_to_close_state(); + break; case EVENT_IMMEDIATE: { // Start Immediate Close because of Idle Timeout this->_handle_idle_timeout(); @@ -623,6 +627,10 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) // Reschedule WRITE_READY this->_schedule_packet_write_ready(true); break; + case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: + this->_close_path_validation_timeout(data); + this->_switch_to_close_state(); + break; case QUIC_EVENT_CLOSING_TIMEOUT: this->_close_closing_timeout(data); this->_switch_to_close_state(); @@ -650,6 +658,10 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) // This should be the only difference between this and closing_state. this->_close_packet_write_ready(data); break; + case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: + this->_close_path_validation_timeout(data); + this->_switch_to_close_state(); + break; case QUIC_EVENT_CLOSING_TIMEOUT: this->_close_closing_timeout(data); this->_switch_to_close_state(); @@ -925,6 +937,11 @@ QUICNetVConnection::_state_common_receive_packet() Connection con; con.setRemote(&p->from().sa); this->con.move(con); + this->_path_validator->validate(); + // Not sure how long we should wait. The spec says just "enough time". + // Use the same time amount as the closing timeout. + ink_hrtime rto = this->_loss_detector->current_rto_period(); + this->_schedule_path_validation_timeout(3 * rto); } else { // TODO Send some error? } @@ -1531,6 +1548,31 @@ QUICNetVConnection::_complete_handshake_if_possible() return 0; } +void +QUICNetVConnection::_schedule_path_validation_timeout(ink_hrtime interval) +{ + if (!this->_path_validation_timeout) { + QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PATH_VALIDATION_TIMEOUT)); + this->_path_validation_timeout = this_ethread()->schedule_in_local(this, interval, QUIC_EVENT_PATH_VALIDATION_TIMEOUT); + } +} + +void +QUICNetVConnection::_unschedule_path_validation_timeout() +{ + if (this->_path_validation_timeout) { + this->_path_validation_timeout->cancel(); + this->_path_validation_timeout = nullptr; + } +} + +void +QUICNetVConnection::_close_path_validation_timeout(Event *data) +{ + ink_assert(this->_path_validation_timeout == data); + this->_path_validation_timeout = nullptr; +} + void QUICNetVConnection::_start_application() { diff --git a/iocore/net/quic/QUICEvents.h b/iocore/net/quic/QUICEvents.h index ffbb3b47abb..59e3feb5e97 100644 --- a/iocore/net/quic/QUICEvents.h +++ b/iocore/net/quic/QUICEvents.h @@ -31,6 +31,7 @@ enum { QUIC_EVENT_PACKET_WRITE_READY, QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, QUIC_EVENT_CLOSING_TIMEOUT, + QUIC_EVENT_PATH_VALIDATION_TIMEOUT, QUIC_EVENT_SHUTDOWN, QUIC_EVENT_LD_SHUTDOWN, }; diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index b779970dce8..510131c65cd 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -35,6 +35,7 @@ QUICPathValidator::validate() if (this->_state == ValidationState::VALIDATING) { // Do nothing } else { + this->_state = ValidationState::VALIDATING; this->_generate_challenge(); } } diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 8fcb9d88d26..29ff72a11ca 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -42,7 +42,8 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x00 // Payload }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {initial_packet_header, [](void *) {}}, sizeof(initial_packet_header), 0); + QUICPacketHeaderUPtr header = + QUICPacketHeader::load({}, {initial_packet_header, [](void *) {}}, sizeof(initial_packet_header), 0); QUICPacket initial_packet(std::move(header), ats_unique_buf(initial_packet_payload, [](void *) {}), sizeof(initial_packet_payload), 0); From 9e0712024c3b5611007f084f8b5e2ef58be6be02 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 10 Apr 2018 11:11:04 +0900 Subject: [PATCH 0501/1313] Respond to a STOP_SENDING with a RST_STREAM --- iocore/net/quic/QUICStream.cc | 9 +++++++++ iocore/net/quic/QUICStream.h | 1 + iocore/net/quic/QUICStreamManager.cc | 17 ++++++++++++++++- iocore/net/quic/QUICStreamManager.h | 1 + 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index b0f1c5f2559..dff57378e3f 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -357,6 +357,15 @@ QUICStream::recv(const std::shared_ptr frame) return QUICErrorUPtr(new QUICNoError()); } +QUICErrorUPtr +QUICStream::recv(const std::shared_ptr frame) +{ + this->_state.update_with_received_frame(*frame); + this->_reset_reason = QUICStreamErrorUPtr(new QUICStreamError(this, QUIC_APP_ERROR_CODE_STOPPING)); + // We received and processed STOP_SENDING frame, so return NO_ERROR here + return QUICErrorUPtr(new QUICNoError()); +} + bool QUICStream::will_generate_frame() { diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index f2299f8628c..a5d7639471e 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -75,6 +75,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator QUICErrorUPtr recv(const std::shared_ptr frame); QUICErrorUPtr recv(const std::shared_ptr frame); QUICErrorUPtr recv(const std::shared_ptr frame); + QUICErrorUPtr recv(const std::shared_ptr frame); void reset(QUICStreamErrorUPtr error); void shutdown(); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 3ff654dae15..9cefeb7da20 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -40,7 +40,8 @@ std::vector QUICStreamManager::interests() { return { - QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::MAX_STREAM_DATA, QUICFrameType::MAX_STREAM_ID, + QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::STOP_SENDING, + QUICFrameType::MAX_STREAM_DATA, QUICFrameType::MAX_STREAM_ID, }; } @@ -124,6 +125,9 @@ QUICStreamManager::handle_frame(std::shared_ptr frame) case QUICFrameType::STREAM: error = this->_handle_frame(std::static_pointer_cast(frame)); break; + case QUICFrameType::STOP_SENDING: + error = this->_handle_frame(std::static_pointer_cast(frame)); + break; case QUICFrameType::RST_STREAM: error = this->_handle_frame(std::static_pointer_cast(frame)); break; @@ -191,6 +195,17 @@ QUICStreamManager::_handle_frame(const std::shared_ptr } } +QUICErrorUPtr +QUICStreamManager::_handle_frame(const std::shared_ptr &frame) +{ + QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); + if (stream) { + return stream->recv(frame); + } else { + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); + } +} + QUICErrorUPtr QUICStreamManager::_handle_frame(const std::shared_ptr &frame) { diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index f453ab6c198..a58af82101e 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -68,6 +68,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICStream *_find_or_create_stream(QUICStreamId stream_id); QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICErrorUPtr _handle_frame(const std::shared_ptr &); + QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICErrorUPtr _handle_frame(const std::shared_ptr &); From 6e1e41bd83461d00f379a49bc860c6c787485f5a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 10 Apr 2018 11:58:32 +0900 Subject: [PATCH 0502/1313] Range of initial packet number is between 0 and 2^32 - 1025 (inclusive) --- iocore/net/quic/QUICPacket.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 9f3f5881802..aea9318f377 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -937,7 +937,7 @@ QUICPacketNumber QUICPacketNumberGenerator::randomize() { std::random_device rnd; - this->_current = rnd() & 0x7FFFFFFF; + this->_current = (rnd() & 0xFFFFFFFF) - 1024; return this->_current; } From 71a69310413b5137f4d54d97cb0f5061447ba056 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Apr 2018 12:09:24 +0900 Subject: [PATCH 0503/1313] Send CONNECTION/APPLICATION_CLOSE frame --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 72 ++++++++++++++----------------- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 9d8523ad622..05f49d18ce6 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -286,6 +286,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, QUICFrameUPtr frame); void _packetize_frames(); + void _packetize_closing_frame(); QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type = QUICPacketType::UNINITIALIZED); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8c19e6c459b..86e1a307cac 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -624,8 +624,6 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) case QUIC_EVENT_PACKET_WRITE_READY: this->_close_packet_write_ready(data); this->_state_closing_send_packet(); - // Reschedule WRITE_READY - this->_schedule_packet_write_ready(true); break; case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: this->_close_path_validation_timeout(data); @@ -1045,6 +1043,10 @@ QUICNetVConnection::_state_handshake_send_retry_packet() QUICErrorUPtr QUICNetVConnection::_state_closing_send_packet() { + this->_packetize_closing_frame(); + + // TODO: should credit of congestion controller be checked? + // During the closing period, an endpoint that sends a // closing frame SHOULD respond to any packet that it receives with // another packet containing a closing frame. To minimize the state @@ -1094,22 +1096,9 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans frame->store(buf.get() + len, &l); len += l; - if (frame->type() == QUICFrameType::CONNECTION_CLOSE || frame->type() == QUICFrameType::APPLICATION_CLOSE) { - this->_transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, previous_packet_type)); - retransmittable = false; - len = 0; - buf = ats_unique_malloc(max_size); - frame->store(buf.get(), &l); - this->_the_final_packet = this->_build_packet(std::move(buf), l, false); - } - return; } -// 1. Dequeue frame from _stream_frame_send_queue and _frame_send_queue -// 2. Put frames into buffer as many as possible -// 3. Build packet with the buffer -// 4. Enqueue the packet via transmit_packet void QUICNetVConnection::_packetize_frames() { @@ -1146,27 +1135,12 @@ QUICNetVConnection::_packetize_frames() while (frame) { ++frame_count; this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - if (this->_the_final_packet) { - return; - } if (frame_count >= FRAME_PER_EVENT) { break; } frame = this->_path_validator->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); } - // CONNECTION_CLOSE, APPLICATION_CLOSE - if (this->_connection_error) { - QUICFrameUPtr frame = QUICFrameFactory::create_null_ack_frame(); - if (this->_connection_error->cls == QUICErrorClass::APPLICATION) { - frame = QUICFrameFactory::create_application_close_frame(std::move(this->_connection_error)); - } else { - frame = QUICFrameFactory::create_connection_close_frame(std::move(this->_connection_error)); - } - ++frame_count; - this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - } - // NEW_CONNECTION_ID if (this->_alt_con_manager) { frame = @@ -1174,9 +1148,6 @@ QUICNetVConnection::_packetize_frames() while (frame) { ++frame_count; this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - if (this->_the_final_packet) { - return; - } if (frame_count >= FRAME_PER_EVENT) { break; } @@ -1191,9 +1162,6 @@ QUICNetVConnection::_packetize_frames() while (frame) { ++frame_count; this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - if (this->_the_final_packet) { - return; - } if (frame_count >= FRAME_PER_EVENT) { break; } @@ -1215,9 +1183,7 @@ QUICNetVConnection::_packetize_frames() this->_stream_manager->add_total_offset_sent(frame_size); } this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - if (this->_the_final_packet) { - return; - } + if (frame_count >= FRAME_PER_EVENT) { break; } @@ -1237,6 +1203,32 @@ QUICNetVConnection::_packetize_frames() } } +void +QUICNetVConnection::_packetize_closing_frame() +{ + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); + SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); + + if (this->_connection_error == nullptr) { + return; + } + + QUICFrameUPtr frame = QUICFrameFactory::create_null_ack_frame(); + if (this->_connection_error->cls == QUICErrorClass::APPLICATION) { + frame = QUICFrameFactory::create_application_close_frame(std::move(this->_connection_error)); + } else { + frame = QUICFrameFactory::create_connection_close_frame(std::move(this->_connection_error)); + } + + ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); + size_t len = 0; + bool retransmittable = false; + QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; + this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + + this->_the_final_packet = this->_build_packet(std::move(buf), len, false); +} + QUICErrorUPtr QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) { @@ -1635,6 +1627,7 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) QUICConDebug("Reason was not provided"); } this->_connection_error = std::move(error); + this->_schedule_packet_write_ready(); this->remove_from_active_queue(); this->set_inactivity_timeout(0); @@ -1647,7 +1640,6 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) // This states SHOULD persist for three times the // current Retransmission Timeout (RTO) interval as defined in // [QUIC-RECOVERY]. - this->_schedule_closing_timeout(3 * rto); } From ef8f9768d26f40534354c1d9d22b3b11d3bb44e4 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Apr 2018 14:56:19 +0900 Subject: [PATCH 0504/1313] Limit the number of sending packets on closing state --- iocore/net/P_QUICNetVConnection.h | 7 +++-- iocore/net/QUICNetVConnection.cc | 47 +++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 05f49d18ce6..964f59c8517 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -259,7 +259,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub CountQueue _packet_send_queue; std::queue _quic_packet_recv_queue; - QUICConnectionErrorUPtr _connection_error = nullptr; + QUICConnectionErrorUPtr _connection_error = nullptr; + uint32_t _state_closing_recv_packet_count = 0; + uint32_t _state_closing_recv_packet_window = 1; void _schedule_packet_write_ready(bool delay = false); void _unschedule_packet_write_ready(); @@ -300,7 +302,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_connection_established_process_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_common_receive_packet(); - QUICErrorUPtr _state_connection_closing_and_draining_receive_packet(); + QUICErrorUPtr _state_closing_receive_packet(); + QUICErrorUPtr _state_draining_receive_packet(); QUICErrorUPtr _state_common_send_packet(); QUICErrorUPtr _state_handshake_send_retry_packet(); QUICErrorUPtr _state_closing_send_packet(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 86e1a307cac..cf30f769d29 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -59,6 +59,9 @@ static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(20); static constexpr int FRAME_PER_EVENT = 64; +static constexpr uint32_t STATE_CLOSING_MAX_SEND_PKT_NUM = 8; // Max number of sending packets which contain a closing frame. +static constexpr uint32_t STATE_CLOSING_MAX_RECV_PKT_WIND = 1 << STATE_CLOSING_MAX_SEND_PKT_NUM; + ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); // XXX This might be called on ET_UDP thread @@ -619,7 +622,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: - error = this->_state_connection_closing_and_draining_receive_packet(); + error = this->_state_closing_receive_packet(); break; case QUIC_EVENT_PACKET_WRITE_READY: this->_close_packet_write_ready(data); @@ -649,7 +652,7 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: - error = this->_state_connection_closing_and_draining_receive_packet(); + error = this->_state_draining_receive_packet(); break; case QUIC_EVENT_PACKET_WRITE_READY: // Do not send any packets in this state. @@ -964,18 +967,40 @@ QUICNetVConnection::_state_common_receive_packet() } QUICErrorUPtr -QUICNetVConnection::_state_connection_closing_and_draining_receive_packet() +QUICNetVConnection::_state_closing_receive_packet() { - QUICPacketCreationResult result; - QUICPacketUPtr packet = this->_dequeue_recv_packet(result); - if (result == QUICPacketCreationResult::SUCCESS) { - this->_recv_and_ack(std::move(packet)); - this->_schedule_packet_write_ready(true); + while (this->_packet_recv_queue.size > 0) { + QUICPacketCreationResult result; + QUICPacketUPtr packet = this->_dequeue_recv_packet(result); + if (result == QUICPacketCreationResult::SUCCESS) { + this->_recv_and_ack(std::move(packet)); + } + ++this->_state_closing_recv_packet_count; + + if (this->_state_closing_recv_packet_window < STATE_CLOSING_MAX_RECV_PKT_WIND && + this->_state_closing_recv_packet_count >= this->_state_closing_recv_packet_window) { + this->_state_closing_recv_packet_count = 0; + this->_state_closing_recv_packet_window <<= 1; + + this->_schedule_packet_write_ready(true); + break; + } } - if (this->_packet_recv_queue.size > 0) { - // FIXME: scheduling new event to ensure the closed frame could be sent. - this_ethread()->schedule_in_local(this, HRTIME_MSECONDS(10), QUIC_EVENT_PACKET_READ_READY); + return QUICErrorUPtr(new QUICNoError()); +} + +QUICErrorUPtr +QUICNetVConnection::_state_draining_receive_packet() +{ + while (this->_packet_recv_queue.size > 0) { + QUICPacketCreationResult result; + QUICPacketUPtr packet = this->_dequeue_recv_packet(result); + if (result == QUICPacketCreationResult::SUCCESS) { + this->_recv_and_ack(std::move(packet)); + // Do NOT schedule WRITE_READY event from this point. + // An endpoint in the draining state MUST NOT send any packets. + } } return QUICErrorUPtr(new QUICNoError()); From 084ad245364f9137e667ad7baf6a2d3116204397 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Apr 2018 15:31:25 +0900 Subject: [PATCH 0505/1313] Send cross thread event to the right thread on HQTransaction --- proxy/hq/HQClientTransaction.cc | 37 ++++++++++++++++++++++++++++++++- proxy/hq/HQClientTransaction.h | 3 +++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index c60cef6a114..3574b65012d 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -50,7 +50,9 @@ HQClientTransaction::HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) { - this->mutex = new_ProxyMutex(); + this->mutex = new_ProxyMutex(); + this->_thread = this_ethread(); + this->set_parent(session); this->sm_reader = this->_read_vio_buf.alloc_reader(); static_cast(this->parent)->add_transaction(this); @@ -120,6 +122,21 @@ HQClientTransaction::state_stream_open(int event, void *edata) // TODO: should check recursive call? HQTransDebug("%s (%d)", get_vc_event_name(event), event); + if (this->_thread != this_ethread()) { + // Send on to the owning thread + if (this->_cross_thread_event == nullptr) { + this->_cross_thread_event = this->_thread->schedule_imm(this, event, edata); + } + return 0; + } + + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + + Event *e = static_cast(edata); + if (e == this->_cross_thread_event) { + this->_cross_thread_event = nullptr; + } + switch (event) { case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { @@ -374,6 +391,15 @@ HQClientTransaction::_process_read_vio() return 0; } + if (this->_thread != this_ethread()) { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + if (this->_cross_thread_event == nullptr) { + // Send to the right thread + this->_cross_thread_event = this->_thread->schedule_imm(this, VC_EVENT_READ_READY, nullptr); + } + return 0; + } + SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); IOBufferReader *client_vio_reader = this->_stream_io->get_read_buffer_reader(); @@ -444,6 +470,15 @@ HQClientTransaction::_process_write_vio() return 0; } + if (this->_thread != this_ethread()) { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + if (this->_cross_thread_event == nullptr) { + // Send to the right thread + this->_cross_thread_event = this->_thread->schedule_imm(this, VC_EVENT_WRITE_READY, nullptr); + } + return 0; + } + SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); IOBufferReader *reader = this->_write_vio.get_reader(); diff --git a/proxy/hq/HQClientTransaction.h b/proxy/hq/HQClientTransaction.h index 155cbc50774..d24c3bf744c 100644 --- a/proxy/hq/HQClientTransaction.h +++ b/proxy/hq/HQClientTransaction.h @@ -74,6 +74,9 @@ class HQClientTransaction : public ProxyClientTransaction int64_t _process_read_vio(); int64_t _process_write_vio(); + EThread *_thread = nullptr; + Event *_cross_thread_event = nullptr; + MIOBuffer _read_vio_buf = CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX; QUICStreamIO *_stream_io = nullptr; From cf3c8e54af3a7a88c6f4abc11ff67235bbf96687 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 10 Apr 2018 15:41:59 +0900 Subject: [PATCH 0506/1313] Send data from stream 0 first --- iocore/net/quic/QUICStreamManager.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 9cefeb7da20..6fbf258e8cc 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -345,7 +345,20 @@ QUICStreamManager::generate_frame(uint16_t connection_credit, uint16_t maximum_f { // FIXME We should pick a stream based on priority QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + + // Stream 0 must be prioritized over other streams + QUICStream *stream = this->_find_stream(STREAM_ID_FOR_HANDSHAKE); + if (stream) { + frame = stream->generate_frame(connection_credit, maximum_frame_size); + if (frame) { + return frame; + } + } + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + if (s->id() == STREAM_ID_FOR_HANDSHAKE) { + continue; + } frame = s->generate_frame(connection_credit, maximum_frame_size); if (frame) { break; From 0961c2af562a5fdc501890cda07cdb21dad7a61a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 10 Apr 2018 16:05:41 +0900 Subject: [PATCH 0507/1313] Include memory in ink_memory.h --- lib/ts/ink_memory.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ts/ink_memory.h b/lib/ts/ink_memory.h index bb8786dff7f..55caf2d93d5 100644 --- a/lib/ts/ink_memory.h +++ b/lib/ts/ink_memory.h @@ -146,6 +146,8 @@ char *_xstrdup(const char *str, int length, const char *path); #ifdef __cplusplus +#include + // this is to help with migration to a std::string issue with older code that // expects char* being copied. As more code moves to std::string, this can be // removed to avoid these extra copies. From 49c465c225c5d8a74e1a81b49f980d4bb021b171 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 11 Apr 2018 12:18:02 +0900 Subject: [PATCH 0508/1313] Fix flow control on 0-RTT scenario --- iocore/net/QUICNetVConnection.cc | 10 ++++++---- iocore/net/quic/QUICFlowController.cc | 24 ++++++++++-------------- iocore/net/quic/QUICFlowController.h | 10 +++++++++- iocore/net/quic/QUICStream.cc | 8 ++++---- iocore/net/quic/QUICStream.h | 2 +- iocore/net/quic/QUICStreamManager.cc | 19 +++++++------------ 6 files changed, 37 insertions(+), 36 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index cf30f769d29..fcf9ca19dc0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -202,8 +202,8 @@ QUICNetVConnection::start() this->_stream_manager = new QUICStreamManager(this->connection_id(), this->_application_map); this->_congestion_controller = new QUICCongestionController(this->connection_id()); this->_loss_detector = new QUICLossDetector(this, this->_congestion_controller); - this->_remote_flow_controller = new QUICRemoteConnectionFlowController(0); - this->_local_flow_controller = new QUICLocalConnectionFlowController(0); + this->_remote_flow_controller = new QUICRemoteConnectionFlowController(UINT64_MAX); + this->_local_flow_controller = new QUICLocalConnectionFlowController(UINT64_MAX); this->_path_validator = new QUICPathValidator(); this->_frame_dispatcher->add_handler(this); @@ -897,6 +897,8 @@ QUICNetVConnection::_state_handshake_process_handshake_packet(QUICPacketUPtr pac QUICErrorUPtr QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet) { + this->_stream_manager->init_flow_control_params(this->_handshake_handler->local_transport_parameters(), + this->_handshake_handler->remote_transport_parameters()); this->_start_application(); return this->_recv_and_ack(std::move(packet)); } @@ -1365,8 +1367,8 @@ QUICNetVConnection::_init_flow_control_params(const std::shared_ptrgetAsUInt32(QUICTransportParameterId::INITIAL_MAX_DATA); } - this->_local_flow_controller->forward_limit(local_initial_max_data * 1024); - this->_remote_flow_controller->forward_limit(remote_initial_max_data * 1024); + this->_local_flow_controller->set_limit(local_initial_max_data); + this->_remote_flow_controller->set_limit(remote_initial_max_data); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 67a2898ecbf..13cccc3e8ae 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -27,7 +27,7 @@ // // QUICFlowController // -uint32_t +uint64_t QUICFlowController::credit() { return this->current_limit() - this->current_offset(); @@ -42,20 +42,14 @@ QUICFlowController::current_offset() QUICOffset QUICFlowController::current_limit() { - // if _limit is 0, the limit is not set yet. - if (this->_limit) { - return this->_limit; - } else { - return UINT64_MAX; - } + return this->_limit; } int QUICFlowController::update(QUICOffset offset) { if (this->_offset <= offset) { - // Assume flow control is not initialized if the limit was 0 - if (this->_limit != 0 && offset > this->_limit) { + if (offset > this->_limit) { return -1; } this->_offset = offset; @@ -81,6 +75,13 @@ QUICFlowController::set_threshold(uint64_t threshold) this->_threshold = threshold; } +void +QUICFlowController::set_limit(QUICOffset limit) +{ + ink_assert(this->_limit == UINT64_MAX || this->_limit == limit); + this->_limit = limit; +} + QUICFrameUPtr QUICFlowController::generate_frame() { @@ -107,11 +108,6 @@ QUICRemoteFlowController::update(QUICOffset offset) { int ret = QUICFlowController::update(offset); - // Assume flow control is not initialized if the limit was 0 - if (this->_limit == 0) { - return ret; - } - // Send BLOCKED(_STREAM) frame if (!this->_blocked && offset > this->_limit) { this->_frame = this->_create_frame(); diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index 930d9f08a63..0510113ef3f 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -29,7 +29,7 @@ class QUICFlowController { public: - uint32_t credit(); + uint64_t credit(); QUICOffset current_offset(); QUICOffset current_limit(); @@ -38,7 +38,15 @@ class QUICFlowController */ virtual int update(QUICOffset offset); virtual void forward_limit(QUICOffset limit); + void set_threshold(uint64_t threshold); + + /** + * This is only for flow controllers initialized without a limit (== UINT64_MAX). + * Once a limit is set, it should be updated with forward_limit(). + */ + void set_limit(QUICOffset limit); + QUICFrameUPtr generate_frame(); protected: diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index dff57378e3f..81525c8c6e5 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -63,7 +63,7 @@ QUICStream::~QUICStream() } void -QUICStream::init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data) +QUICStream::init_flow_control_params(uint64_t recv_max_stream_data, uint64_t send_max_stream_data) { this->_flow_control_buffer_size = recv_max_stream_data; this->_local_flow_controller.forward_limit(recv_max_stream_data); @@ -400,8 +400,8 @@ QUICStream::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_si bool fin = false; len = std::min(data_len, static_cast( - std::min(static_cast(maximum_frame_size), - std::min(this->_remote_flow_controller.credit(), static_cast(connection_credit))))); + std::min(static_cast(maximum_frame_size), + std::min(this->_remote_flow_controller.credit(), static_cast(connection_credit))))); if (len >= bytes_avail) { fin = this->_fin; } @@ -429,7 +429,7 @@ QUICStream::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_si this->_write_vio.ndone += len; this->_signal_write_event(); this->_state.update_with_sent_frame(*frame); - } else { + } else if (ret != 0) { QUICStreamDebug("Flow Controller blocked sending a STREAM frame"); frame = this->_remote_flow_controller.generate_frame(); } diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index a5d7639471e..5899e242888 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -55,7 +55,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator int state_stream_open(int event, void *data); int state_stream_closed(int event, void *data); - void init_flow_control_params(uint32_t recv_max_stream_data, uint32_t send_max_stream_data); + void init_flow_control_params(uint64_t recv_max_stream_data, uint64_t send_max_stream_data); QUICStreamId id() const; QUICOffset final_offset(); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 6fbf258e8cc..3725d1c9e02 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -55,15 +55,7 @@ QUICStreamManager::init_flow_control_params(const std::shared_ptr_find_stream(STREAM_ID_FOR_HANDSHAKE); if (stream) { - uint32_t local_initial_max_stream_data = 0; - uint32_t remote_initial_max_stream_data = 0; - if (this->_local_tp) { - local_initial_max_stream_data = local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); - } - if (this->_remote_tp) { - remote_initial_max_stream_data = remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); - } - stream->init_flow_control_params(local_initial_max_stream_data, remote_initial_max_stream_data); + stream->init_flow_control_params(UINT64_MAX, UINT64_MAX); } if (this->_local_tp) { @@ -249,9 +241,12 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) return nullptr; } - uint32_t local_max_stream_data = 0; - uint32_t remote_max_stream_data = 0; - if (this->_local_tp) { + uint64_t local_max_stream_data = 0; + uint64_t remote_max_stream_data = 0; + if (stream_id == STREAM_ID_FOR_HANDSHAKE) { + local_max_stream_data = UINT64_MAX; + remote_max_stream_data = UINT64_MAX; + } else if (this->_local_tp) { local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA), remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); } else { From d75edbd523c096472ce8867c79d34121e0899976 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 11 Apr 2018 14:51:38 +0900 Subject: [PATCH 0509/1313] Explicitly specify max_stream_data in tests The default value was changed to 0 from INT64_MAX --- iocore/net/quic/test/test_QUICStream.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 0e6331a478f..508d015c4cf 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -94,7 +94,7 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(0, stream_id)); + std::unique_ptr stream(new QUICStream(0, stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -119,7 +119,7 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(0, stream_id)); + std::unique_ptr stream(new QUICStream(0, stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); From b118034bd4da5bbe0338578ee14b02bcfb1add8a Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 11 Apr 2018 11:08:41 +0800 Subject: [PATCH 0510/1313] QUIC: Send MAX_XXX_FRAME 2 rtt before sender to get blocked --- iocore/net/QUICNetVConnection.cc | 4 +- iocore/net/quic/QUICFlowController.cc | 38 ++++++++++++++++++- iocore/net/quic/QUICFlowController.h | 34 +++++++++++++++-- iocore/net/quic/QUICLossDetector.cc | 6 +++ iocore/net/quic/QUICLossDetector.h | 11 +++++- iocore/net/quic/QUICStream.cc | 5 ++- iocore/net/quic/QUICStream.h | 9 ++++- iocore/net/quic/QUICStreamManager.cc | 5 ++- iocore/net/quic/QUICStreamManager.h | 4 +- iocore/net/quic/test/Makefile.am | 5 ++- .../net/quic/test/test_QUICFlowController.cc | 31 ++++++++++++++- 11 files changed, 133 insertions(+), 19 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index fcf9ca19dc0..91f579c8ba3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -199,12 +199,12 @@ QUICNetVConnection::start() this->_packet_factory.set_hs_protocol(this->_hs_protocol); // Create frame handlers - this->_stream_manager = new QUICStreamManager(this->connection_id(), this->_application_map); this->_congestion_controller = new QUICCongestionController(this->connection_id()); this->_loss_detector = new QUICLossDetector(this, this->_congestion_controller); this->_remote_flow_controller = new QUICRemoteConnectionFlowController(UINT64_MAX); - this->_local_flow_controller = new QUICLocalConnectionFlowController(UINT64_MAX); + this->_local_flow_controller = new QUICLocalConnectionFlowController(this->_loss_detector, UINT64_MAX); this->_path_validator = new QUICPathValidator(); + this->_stream_manager = new QUICStreamManager(this->_loss_detector, this->connection_id(), this->_application_map); this->_frame_dispatcher->add_handler(this); this->_frame_dispatcher->add_handler(this->_stream_manager); diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 13cccc3e8ae..c833aa663cd 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -24,6 +24,24 @@ #include "QUICFlowController.h" #include "QUICFrame.h" +// +// QUICRateAnalyzer +// +void +QUICRateAnalyzer::update(QUICOffset offset) +{ + ink_hrtime now = Thread::get_hrtime(); + if (offset > 0 && now > this->_start_time) { + this->_rate = static_cast(offset) / (now - this->_start_time); + } +} + +uint64_t +QUICRateAnalyzer::expect_recv_bytes(ink_hrtime time) +{ + return static_cast(time * this->_rate); +} + // // QUICFlowController // @@ -126,11 +144,29 @@ QUICLocalFlowController::forward_limit(QUICOffset offset) QUICFlowController::forward_limit(offset); // Send MAX_(STREAM_)DATA frame - if (this->_limit - this->_offset <= this->_threshold) { + if (this->_need_to_gen_frame()) { this->_frame = this->_create_frame(); } } +int +QUICLocalFlowController::update(QUICOffset offset) +{ + this->_analyzer.update(offset); + return QUICFlowController::update(offset); +} + +bool +QUICLocalFlowController::_need_to_gen_frame() +{ + this->_threshold = this->_analyzer.expect_recv_bytes(2 * this->_rtt_provider->smoothed_rtt()); + if (this->_offset + this->_threshold > this->_limit) { + return true; + } + + return false; +} + // // QUIC[Remote|Local][Connection|Stream]FlowController // diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index 0510113ef3f..bc4a91ab9e4 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -23,8 +23,21 @@ #pragma once +#include "../../eventsystem/I_EventSystem.h" #include "QUICTypes.h" #include "QUICFrame.h" +#include "QUICLossDetector.h" + +class QUICRateAnalyzer +{ +public: + void update(QUICOffset offset); + uint64_t expect_recv_bytes(ink_hrtime time); + +private: + double _rate = 0.0; + ink_hrtime _start_time = Thread::get_hrtime(); +}; class QUICFlowController { @@ -73,8 +86,18 @@ class QUICRemoteFlowController : public QUICFlowController class QUICLocalFlowController : public QUICFlowController { public: - QUICLocalFlowController(uint64_t initial_limit) : QUICFlowController(initial_limit) {} + QUICLocalFlowController(QUICRTTProvider *rtt_provider, uint64_t initial_limit) + : QUICFlowController(initial_limit), _rtt_provider(rtt_provider) + { + } void forward_limit(QUICOffset limit) override; + int update(QUICOffset offset) override; + +private: + bool _need_to_gen_frame(); + QUICRateAnalyzer _analyzer; + + QUICRTTProvider *_rtt_provider = nullptr; }; class QUICRemoteConnectionFlowController : public QUICRemoteFlowController @@ -87,7 +110,10 @@ class QUICRemoteConnectionFlowController : public QUICRemoteFlowController class QUICLocalConnectionFlowController : public QUICLocalFlowController { public: - QUICLocalConnectionFlowController(uint64_t initial_limit) : QUICLocalFlowController(initial_limit) {} + QUICLocalConnectionFlowController(QUICRTTProvider *rtt_provider, uint64_t initial_limit) + : QUICLocalFlowController(rtt_provider, initial_limit) + { + } QUICFrameUPtr _create_frame() override; }; @@ -107,8 +133,8 @@ class QUICRemoteStreamFlowController : public QUICRemoteFlowController class QUICLocalStreamFlowController : public QUICLocalFlowController { public: - QUICLocalStreamFlowController(uint64_t initial_limit, QUICStreamId stream_id) - : QUICLocalFlowController(initial_limit), _stream_id(stream_id) + QUICLocalStreamFlowController(QUICRTTProvider *rtt_provider, uint64_t initial_limit, QUICStreamId stream_id) + : QUICLocalFlowController(rtt_provider, initial_limit), _stream_id(stream_id) { } QUICFrameUPtr _create_frame() override; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index c94935cc4a7..0c873c05de5 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -550,3 +550,9 @@ QUICLossDetector::current_rto_period() alarm_duration = alarm_duration * (1 << this->_rto_count); return alarm_duration; } + +ink_hrtime +QUICLossDetector::smoothed_rtt() const +{ + return this->_smoothed_rtt; +} diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 0fd65c5a6e8..e48fe3275a1 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -37,6 +37,8 @@ #include "QUICFrameHandler.h" #include "QUICPacketTransmitter.h" +class QUICLossDetector; + struct PacketInfo { QUICPacketNumber packet_number; ink_hrtime time; @@ -46,6 +48,12 @@ struct PacketInfo { QUICPacketUPtr packet; }; +class QUICRTTProvider +{ +public: + virtual ink_hrtime smoothed_rtt() const = 0; +}; + class QUICCongestionController { public: @@ -83,7 +91,7 @@ class QUICCongestionController bool _in_recovery(QUICPacketNumber packet_number); }; -class QUICLossDetector : public Continuation, public QUICFrameHandler +class QUICLossDetector : public Continuation, public QUICFrameHandler, public QUICRTTProvider { public: QUICLossDetector(QUICPacketTransmitter *transmitter, QUICCongestionController *cc); @@ -97,6 +105,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler QUICPacketNumber largest_acked_packet_number(); void reset(); ink_hrtime current_rto_period(); + ink_hrtime smoothed_rtt() const override; private: Ptr _loss_detection_mutex; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 81525c8c6e5..cd5f4382918 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -35,12 +35,13 @@ Debug("quic_flow_ctrl", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) -QUICStream::QUICStream(QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data) +QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data, + uint64_t send_max_stream_data) : VConnection(nullptr), _connection_id(cid), _id(sid), _remote_flow_controller(send_max_stream_data, _id), - _local_flow_controller(recv_max_stream_data, _id), + _local_flow_controller(rtt_provider, recv_max_stream_data, _id), _received_stream_frame_buffer(this) { SET_HANDLER(&QUICStream::state_stream_open); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 5899e242888..b4f522de8d5 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -33,6 +33,7 @@ #include "QUICFlowController.h" #include "QUICIncomingFrameBuffer.h" #include "QUICFrameGenerator.h" +#include "QUICLossDetector.h" class QUICNetVConnection; class QUICStreamState; @@ -46,10 +47,14 @@ class QUICStream : public VConnection, public QUICFrameGenerator { public: QUICStream() - : VConnection(nullptr), _remote_flow_controller(0, 0), _local_flow_controller(0, 0), _received_stream_frame_buffer(this) + : VConnection(nullptr), + _remote_flow_controller(0, 0), + _local_flow_controller(nullptr, 0, 0), + _received_stream_frame_buffer(this) { } - QUICStream(QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data = 0, uint64_t send_max_stream_data = 0); + QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data = 0, + uint64_t send_max_stream_data = 0); ~QUICStream(); // void start(); int state_stream_open(int event, void *data); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 3725d1c9e02..1a04efa634d 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -32,7 +32,8 @@ static constexpr char tag[] = "quic_stream_manager"; ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); ClassAllocator quicStreamAllocator("quicStreamAllocator"); -QUICStreamManager::QUICStreamManager(QUICConnectionId cid, QUICApplicationMap *app_map) : _connection_id(cid), _app_map(app_map) +QUICStreamManager::QUICStreamManager(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICApplicationMap *app_map) + : _connection_id(cid), _app_map(app_map), _rtt_provider(rtt_provider) { } @@ -256,7 +257,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) // TODO Free the stream somewhere stream = THREAD_ALLOC(quicStreamAllocator, this_ethread()); - new (stream) QUICStream(this->_connection_id, stream_id, local_max_stream_data, remote_max_stream_data); + new (stream) QUICStream(this->_rtt_provider, this->_connection_id, stream_id, local_max_stream_data, remote_max_stream_data); this->stream_list.push(stream); } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index a58af82101e..9f8851acda4 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -28,6 +28,7 @@ #include "QUICApplicationMap.h" #include "QUICFrameHandler.h" #include "QUICFrame.h" +#include "QUICLossDetector.h" extern ClassAllocator quicStreamAllocator; @@ -37,7 +38,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator { public: QUICStreamManager(){}; - QUICStreamManager(QUICConnectionId cid, QUICApplicationMap *app_map); + QUICStreamManager(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICApplicationMap *app_map); void init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); @@ -82,4 +83,5 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICStreamId _remote_maximum_stream_id_bidi = 0; QUICStreamId _remote_maximum_stream_id_uni = 0; uint64_t _total_offset_sent = 0; + QUICRTTProvider *_rtt_provider = nullptr; }; diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index ee0863d821d..3634ae5b091 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -76,7 +76,7 @@ test_LDADD = \ $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ \ + @LIBTCL@ @OPENSSL_LIBS@ \ @HWLOC_LIBS@ # @@ -514,7 +514,8 @@ test_QUICFlowController_SOURCES = \ ../QUICHandshakeProtocol.cc \ ../QUICTLS.cc \ $(QUICTLS_impl) \ - ../QUICFrame.cc + ../QUICFrame.cc \ + ../QUICLossDetector.cc # # test_QUICIncomingFrameBuffer diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index 8e438f990b0..6d7c5936bec 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -27,10 +27,34 @@ #include "quic/Mock.h" #include +static constexpr int DEFAULT_RTT = 1 * HRTIME_SECOND; + +class MockRTTProvider : public QUICRTTProvider +{ +public: + ink_hrtime + smoothed_rtt() const override + { + return this->_smoothed_rtt; + } + + MockRTTProvider(ink_hrtime rtt) : _smoothed_rtt(rtt) {} + + void + set_smoothed_rtt(ink_hrtime rtt) + { + this->_smoothed_rtt = rtt; + } + +private: + ink_hrtime _smoothed_rtt = 0; +}; + TEST_CASE("QUICFlowController_Local_Connection", "[quic]") { int ret = 0; - QUICLocalConnectionFlowController fc(1024); + MockRTTProvider rp(DEFAULT_RTT); + QUICLocalConnectionFlowController fc(&rp, 1024); // Check initial state CHECK(fc.current_offset() == 0); @@ -62,6 +86,7 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); CHECK(ret == 0); + Thread::get_hrtime_updated(); // Exceed limit ret = fc.update(1280); @@ -142,7 +167,8 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") TEST_CASE("QUICFlowController_Local_Stream", "[quic]") { int ret = 0; - QUICLocalStreamFlowController fc(1024, 0); + MockRTTProvider rp(DEFAULT_RTT); + QUICLocalStreamFlowController fc(&rp, 1024, 0); // Check initial state CHECK(fc.current_offset() == 0); @@ -174,6 +200,7 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]") CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); CHECK(ret == 0); + Thread::get_hrtime_updated(); // Exceed limit ret = fc.update(1280); From 3dddd89f1be2c032774c67e9e1efb3cfd1cc5918 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 12 Apr 2018 16:10:39 +0900 Subject: [PATCH 0511/1313] Make QUICClient::start an event handler --- cmd/traffic_quic/quic_client.cc | 7 ++++--- cmd/traffic_quic/quic_client.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc index d6a7176c508..3a2e661b4e5 100644 --- a/cmd/traffic_quic/quic_client.cc +++ b/cmd/traffic_quic/quic_client.cc @@ -28,8 +28,8 @@ QUICClient::~QUICClient() freeaddrinfo(this->_remote_addr_info); } -void -QUICClient::start() +int +QUICClient::start(int, void *) { SET_HANDLER(&QUICClient::state_http_server_open); @@ -44,7 +44,7 @@ QUICClient::start() int res = getaddrinfo(this->_remote_addr, this->_remote_port, &hints, &this->_remote_addr_info); if (res < 0) { Debug("quic_client", "Error: %s (%d)", strerror(errno), errno); - return; + return EVENT_DONE; } for (struct addrinfo *info = this->_remote_addr_info; info != nullptr; info = info->ai_next) { @@ -62,6 +62,7 @@ QUICClient::start() break; } } + return EVENT_CONT; } // Similar to HttpSM::state_http_server_open(int event, void *data) diff --git a/cmd/traffic_quic/quic_client.h b/cmd/traffic_quic/quic_client.h index 575d7a18c41..ea717396b69 100644 --- a/cmd/traffic_quic/quic_client.h +++ b/cmd/traffic_quic/quic_client.h @@ -37,7 +37,7 @@ class QUICClient : public Continuation }; ~QUICClient(); - void start(); + int start(int, void *); int state_http_server_open(int event, void *data); private: From 13fd1491205d3d3f00f59c59feab7e593dfccee6 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 12 Apr 2018 19:17:07 +0800 Subject: [PATCH 0512/1313] QUIC: make ack creator derive from QUICFrameGenerator --- iocore/net/QUICNetVConnection.cc | 8 +++-- iocore/net/quic/QUICAckFrameCreator.cc | 31 ++++++++++--------- iocore/net/quic/QUICAckFrameCreator.h | 22 +++++++------ .../net/quic/test/test_QUICAckFrameCreator.cc | 29 ++++++++++------- 4 files changed, 53 insertions(+), 37 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 91f579c8ba3..0f33a84b075 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1148,9 +1148,11 @@ QUICNetVConnection::_packetize_frames() // ACK if (will_be_ack_only) { - frame = this->_ack_frame_creator.create_if_needed(); + if (this->_ack_frame_creator.will_generate_frame()) { + frame = this->_ack_frame_creator.generate_frame(UINT16_MAX, this->_maximum_stream_frame_data_size()); + } } else { - frame = this->_ack_frame_creator.create(); + frame = this->_ack_frame_creator.generate_frame(UINT16_MAX, this->_maximum_stream_frame_data_size()); } if (frame != nullptr) { ++frame_count; @@ -1240,7 +1242,7 @@ QUICNetVConnection::_packetize_closing_frame() return; } - QUICFrameUPtr frame = QUICFrameFactory::create_null_ack_frame(); + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); if (this->_connection_error->cls == QUICErrorClass::APPLICATION) { frame = QUICFrameFactory::create_application_close_frame(std::move(this->_connection_error)); } else { diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index ab9de24258e..45792ebfbf4 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -48,10 +48,10 @@ QUICAckFrameCreator::update(QUICPacketNumber packet_number, bool protection, boo return 0; } -std::unique_ptr -QUICAckFrameCreator::create() +QUICFrameUPtr +QUICAckFrameCreator::_create_frame() { - std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); + QUICFrameUPtr ack_frame = QUICFrameFactory::create_null_frame(); if (this->_can_send) { ack_frame = this->_create_ack_frame(); this->_can_send = false; @@ -63,23 +63,13 @@ QUICAckFrameCreator::create() return ack_frame; } -std::unique_ptr -QUICAckFrameCreator::create_if_needed() -{ - std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); - if (this->_should_send) { - ack_frame = this->create(); - } - return ack_frame; -} - void QUICAckFrameCreator::_sort_packet_numbers() { // TODO Find more smart way } -std::unique_ptr +QUICFrameUPtr QUICAckFrameCreator::_create_ack_frame() { std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); @@ -126,6 +116,19 @@ QUICAckFrameCreator::_create_ack_frame() return ack_frame; } +bool +QUICAckFrameCreator::will_generate_frame() +{ + return this->_should_send; +} + +QUICFrameUPtr +QUICAckFrameCreator::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) +{ + // FIXME fix size + return this->_create_frame(); +} + uint64_t QUICAckFrameCreator::_calculate_delay() { diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 088d574f3f3..d474aadd079 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -24,6 +24,7 @@ #pragma once #include "ts/ink_hrtime.h" +#include "QUICFrameGenerator.h" #include "QUICTypes.h" #include "QUICFrame.h" #include @@ -51,7 +52,7 @@ class QUICAckPacketNumbers std::vector _packet_numbers; }; -class QUICAckFrameCreator +class QUICAckFrameCreator : public QUICFrameGenerator { public: static constexpr int MAXIMUM_PACKET_COUNT = 256; @@ -64,19 +65,22 @@ class QUICAckFrameCreator int update(QUICPacketNumber packet_number, bool protection, bool should_send); /* - * Returns QUICAckFrame only if ACK frame is able to be sent. - * Caller must send the ACK frame to the peer if it was returned. + * Returns true only if should send ack. */ - std::unique_ptr create(); + bool will_generate_frame() override; /* - * Returns QUICAckFrame only if ACK frame need to be sent, - * because sending an ACK only packet against an ACK only packet is prohibited. - * Caller must send the ACK frame to the peer if it was returned. + * Calls create directly. */ - std::unique_ptr create_if_needed(); + QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) override; private: + /* + * Returns QUICAckFrame only if ACK frame is able to be sent. + * Caller must send the ACK frame to the peer if it was returned. + */ + QUICFrameUPtr _create_frame(); + bool _can_send = false; bool _should_send = false; @@ -85,6 +89,6 @@ class QUICAckFrameCreator std::set _unprotected_packets; void _sort_packet_numbers(); - std::unique_ptr _create_ack_frame(); + QUICFrameUPtr _create_ack_frame(); uint64_t _calculate_delay(); }; diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index a19851eaf93..b044c5ac8bc 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -29,21 +29,23 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") { QUICAckFrameCreator creator; - std::unique_ptr frame = {nullptr, nullptr}; // Initial state - frame = creator.create(); + std::shared_ptr ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + std::shared_ptr frame = std::static_pointer_cast(ack_frame); CHECK(frame == nullptr); // One packet creator.update(1, false, true); - frame = creator.create(); + ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 1); CHECK(frame->ack_block_section()->first_ack_block() == 0); - frame = creator.create(); + ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); CHECK(frame == nullptr); // Not sequential @@ -51,7 +53,8 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") creator.update(5, false, true); creator.update(3, false, true); creator.update(4, false, true); - frame = creator.create(); + ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 5); @@ -61,7 +64,8 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") creator.update(6, false, true); creator.update(7, false, true); creator.update(10, false, true); - frame = creator.create(); + ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); CHECK(frame->largest_acknowledged() == 10); @@ -72,10 +76,10 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") { QUICAckFrameCreator creator; - std::unique_ptr frame = {nullptr, nullptr}; // Initial state - frame = creator.create(); + std::shared_ptr ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + std::shared_ptr frame = std::static_pointer_cast(ack_frame); CHECK(frame == nullptr); creator.update(2, false, true); @@ -84,19 +88,22 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") creator.update(8, false, true); creator.update(9, false, true); - frame = creator.create(); + ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 2); CHECK(frame->largest_acknowledged() == 9); CHECK(frame->ack_block_section()->first_ack_block() == 1); CHECK(frame->ack_block_section()->begin()->gap() == 0); - frame = creator.create(); + ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); CHECK(frame == nullptr); creator.update(7, false, true); creator.update(4, false, true); - frame = creator.create(); + ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); CHECK(frame->largest_acknowledged() == 7); From fadeb545dff56497db8cfb7e3a1448ada881698b Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 13 Apr 2018 08:31:27 +0800 Subject: [PATCH 0513/1313] QUIC: Adding total offset in Stream Manager --- iocore/net/QUICNetVConnection.cc | 4 +--- iocore/net/quic/QUICStreamManager.cc | 24 ++++++++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 0f33a84b075..146305620d8 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1203,13 +1203,11 @@ QUICNetVConnection::_packetize_frames() while (frame) { ++frame_count; if (frame->type() == QUICFrameType::STREAM) { - uint16_t frame_size = frame->size(); - int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent() + frame_size); + int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); ink_assert(ret == 0); - this->_stream_manager->add_total_offset_sent(frame_size); } this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 1a04efa634d..a01ffcefbf9 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -346,19 +346,23 @@ QUICStreamManager::generate_frame(uint16_t connection_credit, uint16_t maximum_f QUICStream *stream = this->_find_stream(STREAM_ID_FOR_HANDSHAKE); if (stream) { frame = stream->generate_frame(connection_credit, maximum_frame_size); - if (frame) { - return frame; - } } - for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { - if (s->id() == STREAM_ID_FOR_HANDSHAKE) { - continue; - } - frame = s->generate_frame(connection_credit, maximum_frame_size); - if (frame) { - break; + if (frame == nullptr) { + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + if (s->id() == STREAM_ID_FOR_HANDSHAKE) { + continue; + } + frame = s->generate_frame(connection_credit, maximum_frame_size); + if (frame) { + break; + } } } + + if (frame != nullptr && frame->type() == QUICFrameType::STREAM) { + this->add_total_offset_sent(frame->size()); + } + return frame; } From e1e5e86f896bae893a6507dc5f1df61d8e37e8b3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 13 Apr 2018 15:39:40 +0900 Subject: [PATCH 0514/1313] Rename QUICConnection in QUICApplication --- iocore/net/quic/QUICApplication.cc | 5 ++--- iocore/net/quic/QUICApplication.h | 2 +- iocore/net/quic/QUICHandshake.cc | 8 ++++---- proxy/hq/QUICSimpleApp.cc | 6 +++--- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index c15dd93c3c9..428381908e0 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -133,7 +133,7 @@ QUICStreamIO::get_transaction_id() const // QUICApplication::QUICApplication(QUICConnection *qc) : Continuation(new_ProxyMutex()) { - this->_client_qc = qc; + this->_qc = qc; } // @brief Bind stream and application @@ -162,8 +162,7 @@ QUICApplication::reenable(QUICStream *stream) stream_io->read_reenable(); stream_io->write_reenable(); } else { - Debug(tag, "[%" PRIx64 "] Unknown Stream, id: %" PRIx64, static_cast(this->_client_qc->connection_id()), - stream->id()); + Debug(tag, "[%" PRIx64 "] Unknown Stream, id: %" PRIx64, static_cast(this->_qc->connection_id()), stream->id()); } return; diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index d1f94decbb6..eef90a0923e 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -86,7 +86,7 @@ class QUICApplication : public Continuation QUICStreamIO *_find_stream_io(QUICStreamId id); QUICStreamIO *_find_stream_io(VIO *vio); - QUICConnection *_client_qc = nullptr; + QUICConnection *_qc = nullptr; private: std::map _stream_map; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 37ec33442c0..831da5655ee 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -37,7 +37,7 @@ static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; #define QUICHSDebug(fmt, ...) \ - Debug("quic_handshake", "[%" PRIx64 "] " fmt, static_cast(this->_client_qc->connection_id()), ##__VA_ARGS__) + Debug("quic_handshake", "[%" PRIx64 "] " fmt, static_cast(this->_qc->connection_id()), ##__VA_ARGS__) #define I_WANNA_DUMP_THIS_BUF(buf, len) \ { \ @@ -101,7 +101,7 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless { SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc); SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_hs_index, this); - this->_hs_protocol->initialize_key_materials(this->_client_qc->original_connection_id()); + this->_hs_protocol->initialize_key_materials(this->_qc->original_connection_id()); if (this->_netvc_context == NET_VCONNECTION_OUT) { this->_initial = true; @@ -143,7 +143,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet this->_load_local_server_transport_parameters(initial_packet->version()); packet_factory->set_version(this->_version_negotiator->negotiated_version()); } else { - this->_client_qc->transmit_packet(packet_factory->create_version_negotiation_packet(initial_packet)); + this->_qc->transmit_packet(packet_factory->create_version_negotiation_packet(initial_packet)); QUICHSDebug("Version negotiation failed: %x", initial_packet->version()); } } else { @@ -525,7 +525,7 @@ QUICHandshake::_complete_handshake() void QUICHandshake::_abort_handshake(QUICTransErrorCode code) { - this->_client_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(code))); + this->_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(code))); QUICHSDebug("Enter state_closed"); SET_HANDLER(&QUICHandshake::state_closed); diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index 36fd7d7b5a9..b06821daba3 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -42,7 +42,7 @@ QUICSimpleApp::QUICSimpleApp(QUICNetVConnection *client_vc) : QUICApplication(cl this->_client_session->acl_record = session_acl_record; this->_client_session->new_connection(client_vc, nullptr, nullptr, false); - this->_client_qc->stream_manager()->set_default_application(this); + this->_qc->stream_manager()->set_default_application(this); SET_HANDLER(&QUICSimpleApp::main_event_handler); } @@ -55,13 +55,13 @@ QUICSimpleApp::~QUICSimpleApp() int QUICSimpleApp::main_event_handler(int event, Event *data) { - Debug(tag, "[%" PRIx64 "] %s (%d)", static_cast(this->_client_qc->connection_id()), get_vc_event_name(event), event); + Debug(tag, "[%" PRIx64 "] %s (%d)", static_cast(this->_qc->connection_id()), get_vc_event_name(event), event); VIO *vio = reinterpret_cast(data); QUICStreamIO *stream_io = this->_find_stream_io(vio); if (stream_io == nullptr) { - Debug(tag, "[%" PRIx64 "] Unknown Stream", static_cast(this->_client_qc->connection_id())); + Debug(tag, "[%" PRIx64 "] Unknown Stream", static_cast(this->_qc->connection_id())); return -1; } From 643f7420aeedea9602c5f941df0ca443c30721d6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 13 Apr 2018 15:40:55 +0900 Subject: [PATCH 0515/1313] Add create_uni/bidi_stream to QUICStreamManager --- iocore/net/QUICNetVConnection.cc | 3 ++- iocore/net/quic/QUICStreamManager.cc | 37 ++++++++++++++++++++++++++-- iocore/net/quic/QUICStreamManager.h | 8 +++++- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 146305620d8..506223d8542 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -204,7 +204,8 @@ QUICNetVConnection::start() this->_remote_flow_controller = new QUICRemoteConnectionFlowController(UINT64_MAX); this->_local_flow_controller = new QUICLocalConnectionFlowController(this->_loss_detector, UINT64_MAX); this->_path_validator = new QUICPathValidator(); - this->_stream_manager = new QUICStreamManager(this->_loss_detector, this->connection_id(), this->_application_map); + this->_stream_manager = + new QUICStreamManager(this->_loss_detector, this->connection_id(), this->_application_map, this->netvc_context); this->_frame_dispatcher->add_handler(this); this->_frame_dispatcher->add_handler(this->_stream_manager); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index a01ffcefbf9..f52cf5280c0 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -32,9 +32,18 @@ static constexpr char tag[] = "quic_stream_manager"; ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); ClassAllocator quicStreamAllocator("quicStreamAllocator"); -QUICStreamManager::QUICStreamManager(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICApplicationMap *app_map) - : _connection_id(cid), _app_map(app_map), _rtt_provider(rtt_provider) +QUICStreamManager::QUICStreamManager(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICApplicationMap *app_map, + NetVConnectionContext_t context) + : _connection_id(cid), _app_map(app_map), _netvc_context(context), _rtt_provider(rtt_provider) { + if (this->_netvc_context == NET_VCONNECTION_OUT) { + // stream 0 is for handshake, smallest client bidi stream id is 4 + this->_next_stream_id_bidi = static_cast(QUICStreamType::CLIENT_BIDI) + 4; + this->_next_stream_id_uni = static_cast(QUICStreamType::CLIENT_UNI); + } else { + this->_next_stream_id_bidi = static_cast(QUICStreamType::SERVER_BIDI); + this->_next_stream_id_uni = static_cast(QUICStreamType::SERVER_UNI); + } } std::vector @@ -102,6 +111,30 @@ QUICStreamManager::create_stream(QUICStreamId stream_id) return QUICErrorUPtr(new QUICNoError()); } +QUICErrorUPtr +QUICStreamManager::create_uni_stream(QUICStreamId &new_stream_id) +{ + QUICErrorUPtr error = this->create_stream(this->_next_stream_id_uni); + if (error->cls == QUICErrorClass::NONE) { + new_stream_id = this->_next_stream_id_uni; + this->_next_stream_id_uni += 2; + } + + return error; +} + +QUICErrorUPtr +QUICStreamManager::create_bidi_stream(QUICStreamId &new_stream_id) +{ + QUICErrorUPtr error = this->create_stream(this->_next_stream_id_bidi); + if (error->cls == QUICErrorClass::NONE) { + new_stream_id = this->_next_stream_id_bidi; + this->_next_stream_id_bidi += 2; + } + + return error; +} + QUICErrorUPtr QUICStreamManager::handle_frame(std::shared_ptr frame) { diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 9f8851acda4..3b14b41167f 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -38,7 +38,8 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator { public: QUICStreamManager(){}; - QUICStreamManager(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICApplicationMap *app_map); + QUICStreamManager(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICApplicationMap *app_map, + NetVConnectionContext_t context); void init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); @@ -49,6 +50,8 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator uint32_t stream_count() const; QUICErrorUPtr create_stream(QUICStreamId stream_id); + QUICErrorUPtr create_uni_stream(QUICStreamId &new_stream_id); + QUICErrorUPtr create_bidi_stream(QUICStreamId &new_stream_id); void set_default_application(QUICApplication *app); void reset_send_offset(); @@ -76,12 +79,15 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICConnectionId _connection_id = 0; QUICApplicationMap *_app_map = nullptr; + NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; std::shared_ptr _local_tp = nullptr; std::shared_ptr _remote_tp = nullptr; QUICStreamId _local_maximum_stream_id_bidi = 0; QUICStreamId _local_maximum_stream_id_uni = 0; QUICStreamId _remote_maximum_stream_id_bidi = 0; QUICStreamId _remote_maximum_stream_id_uni = 0; + QUICStreamId _next_stream_id_uni = 0; + QUICStreamId _next_stream_id_bidi = 0; uint64_t _total_offset_sent = 0; QUICRTTProvider *_rtt_provider = nullptr; }; From 6212927aa508e8c365a405e7e0e2db47547f54a5 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 13 Apr 2018 15:55:58 +0900 Subject: [PATCH 0516/1313] Add HTTP/0.9 exchange support on quic client Out of scope: starting session or transaction of HTTP/QUIC --- cmd/traffic_quic/quic_client.cc | 80 +++++++++++++++++++++++++++++++- cmd/traffic_quic/quic_client.h | 19 ++++++-- cmd/traffic_quic/traffic_quic.cc | 6 ++- 3 files changed, 99 insertions(+), 6 deletions(-) diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc index 3a2e661b4e5..239641466af 100644 --- a/cmd/traffic_quic/quic_client.cc +++ b/cmd/traffic_quic/quic_client.cc @@ -72,8 +72,12 @@ QUICClient::state_http_server_open(int event, void *data) switch (event) { case NET_EVENT_OPEN: { // TODO: create ProxyServerSession / ProxyServerTransaction - // TODO: send HTTP/0.9 message Debug("quic_client", "start proxy server ssn/txn"); + + QUICNetVConnection *conn = static_cast(data); + QUICClientApp *app = new QUICClientApp(conn); + app->start(this->_path); + break; } case NET_EVENT_OPEN_FAILED: { @@ -90,3 +94,77 @@ QUICClient::state_http_server_open(int event, void *data) return 0; } + +// +// QUICClientApp +// +#define QUICClientAppDebug(fmt, ...) \ + Debug("quic_client_app", "[%" PRIx64 "] " fmt, static_cast(this->_qc->connection_id()), ##__VA_ARGS__) + +QUICClientApp::QUICClientApp(QUICNetVConnection *qvc) : QUICApplication(qvc) +{ + this->_qc->stream_manager()->set_default_application(this); + + SET_HANDLER(&QUICClientApp::main_event_handler); +} + +void +QUICClientApp::start(const char *path) +{ + QUICStreamId stream_id; + QUICErrorUPtr error = this->_qc->stream_manager()->create_bidi_stream(stream_id); + + if (error->cls != QUICErrorClass::NONE) { + Error("%s", error->msg); + ink_assert(abort); + } + + // TODO: move to transaction + char request[1024] = {0}; + int request_len = snprintf(request, sizeof(request), "GET %s\r\n", path); + + QUICClientAppDebug("\n%s", request); + + QUICStreamIO *stream_io = this->_find_stream_io(stream_id); + + stream_io->write(reinterpret_cast(request), request_len); + stream_io->write_reenable(); +} + +int +QUICClientApp::main_event_handler(int event, Event *data) +{ + QUICClientAppDebug("%s (%d)", get_vc_event_name(event), event); + + VIO *vio = reinterpret_cast(data); + QUICStreamIO *stream_io = this->_find_stream_io(vio); + + if (stream_io == nullptr) { + QUICClientAppDebug("Unknown Stream"); + return -1; + } + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: + if (stream_io->is_read_avail_more_than(0)) { + uint8_t response[1024] = {0}; + stream_io->read(response, sizeof(response)); + QUICClientAppDebug("\n%s", response); + } + break; + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: + break; + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: + ink_assert(false); + break; + default: + break; + } + + return EVENT_CONT; +} diff --git a/cmd/traffic_quic/quic_client.h b/cmd/traffic_quic/quic_client.h index ea717396b69..15071c35558 100644 --- a/cmd/traffic_quic/quic_client.h +++ b/cmd/traffic_quic/quic_client.h @@ -28,10 +28,13 @@ #include "I_NetVConnection.h" #include "P_QUICNetProcessor.h" +#include "QUICApplication.h" + class QUICClient : public Continuation { public: - QUICClient(const char *addr, const char *port) : Continuation(new_ProxyMutex()), _remote_addr(addr), _remote_port(port) + QUICClient(const char *addr, const char *port, const char *path) + : Continuation(new_ProxyMutex()), _remote_addr(addr), _remote_port(port), _path(path) { SET_HANDLER(&QUICClient::start); }; @@ -41,7 +44,17 @@ class QUICClient : public Continuation int state_http_server_open(int event, void *data); private: - const char *_remote_addr; - const char *_remote_port; + const char *_remote_addr = nullptr; + const char *_remote_port = nullptr; struct addrinfo *_remote_addr_info = nullptr; + const char *_path = nullptr; +}; + +class QUICClientApp : public QUICApplication +{ +public: + QUICClientApp(QUICNetVConnection *qvc); + + void start(const char *path); + int main_event_handler(int event, Event *data); }; diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index c46e80f4d49..2098d49131d 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -51,11 +51,13 @@ main(int argc, const char **argv) char addr[1024] = "127.0.0.1"; char port[16] = "4433"; - char debug_tags[1024] = "quic|udp"; + char path[1018] = "/"; + char debug_tags[1024] = "quic"; const ArgumentDescription argument_descriptions[] = { {"addr", 'a', "Address", "S1023", addr, nullptr, nullptr}, {"port", 'p', "Port", "S15", port, nullptr, nullptr}, + {"path", 'P', "Path", "S1017", path, nullptr, nullptr}, {"debug", 'T', "Vertical-bar-separated Debug Tags", "S1023", debug_tags, nullptr, nullptr}, HELP_ARGUMENT_DESCRIPTION(), VERSION_ARGUMENT_DESCRIPTION(), @@ -87,7 +89,7 @@ main(int argc, const char **argv) udpNet.start(1, stacksize); quic_NetProcessor.start(-1, stacksize); - QUICClient client(addr, port); + QUICClient client(addr, port, path); eventProcessor.schedule_in(&client, 1, ET_NET); this_thread()->execute(); From 59543aacaf5a9235dfce88256a68f5992d2e5e60 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 20 Apr 2018 12:24:43 +0900 Subject: [PATCH 0517/1313] Fix unit tests --- iocore/net/quic/Mock.h | 8 ++++++++ iocore/net/quic/test/test_QUICFrame.cc | 2 +- iocore/net/quic/test/test_QUICLossDetector.cc | 3 ++- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- iocore/net/quic/test/test_QUICStream.cc | 13 +++++-------- iocore/net/quic/test/test_QUICStreamManager.cc | 8 ++++---- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 0156e04bf0d..bed653e9763 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -507,3 +507,11 @@ class MockContinuation : public Continuation return EVENT_CONT; } }; + +class MockQUICRTTProvider : public QUICRTTProvider +{ + ink_hrtime smoothed_rtt() const + { + return HRTIME_MSECONDS(1); + } +}; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index fd4f4e5d0cd..992b03dd674 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1123,7 +1123,7 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") { - QUICStream stream(0, 0x1234, 0, 0); + QUICStream stream(new MockQUICRTTProvider(), 0, 0x1234, 0, 0); std::unique_ptr error = std::unique_ptr(new QUICStreamError(&stream, static_cast(0x01))); std::unique_ptr rst_stream_frame1 = diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index d777ba96f8c..b3ee4f007cc 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -137,7 +137,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") afc->update(pn8, false, true); afc->update(pn9, false, true); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); - frame = afc->create(); + std::shared_ptr x = afc->generate_frame(2048, 2048); + frame = std::dynamic_pointer_cast(x); detector.handle_frame(frame); ink_hrtime_sleep(HRTIME_MSECONDS(5000)); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 29ff72a11ca..fc9c8954e64 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -91,7 +91,7 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") CHECK(packet->type() == QUICPacketType::HANDSHAKE); CHECK(packet->connection_id() == 0x01020304); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); - CHECK((packet->packet_number() & 0xFFFFFFFF80000000) == 0); + CHECK(packet->packet_number() <= 0xFFFFFBFF); CHECK(packet->version() == 0x11223344); } diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 508d015c4cf..3dfb2ae7bd6 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -69,7 +69,7 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(0, stream_id, 1024, 1024)); + std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), 0, stream_id, 1024, 1024)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_1); @@ -94,7 +94,7 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(0, stream_id, UINT64_MAX, UINT64_MAX)); + std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), 0, stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -119,7 +119,7 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(0, stream_id, UINT64_MAX, UINT64_MAX)); + std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), 0, stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -148,7 +148,7 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(0, stream_id)); + std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), 0, stream_id)); stream->init_flow_control_params(4096, 4096); stream->do_io_read(nullptr, 0, read_buffer); @@ -184,7 +184,7 @@ TEST_CASE("QUICStream", "[quic]") IOBufferReader *read_buffer_reader = read_buffer->alloc_reader(); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(0, stream_id)); + std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), 0, stream_id)); stream->init_flow_control_params(4096, 4096); MockContinuation mock_cont(stream->mutex); stream->do_io_read(nullptr, 0, read_buffer); @@ -196,9 +196,6 @@ TEST_CASE("QUICStream", "[quic]") stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame() == true); frame = stream->generate_frame(4096, 4096); - CHECK(frame->type() == QUICFrameType::MAX_STREAM_DATA); - CHECK(stream->will_generate_frame() == true); - frame = stream->generate_frame(4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); CHECK(stream->will_generate_frame() == false); diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index c05794e89ed..796ca26a260 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -34,7 +34,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(0, &app_map); + QUICStreamManager sm(new MockQUICRTTProvider(), 0, &app_map, NET_VCONNECTION_IN); std::shared_ptr local_tp = std::make_shared(static_cast(0)); std::shared_ptr remote_tp = @@ -80,7 +80,7 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(0, &app_map); + QUICStreamManager sm(new MockQUICRTTProvider(), 0, &app_map, NET_VCONNECTION_IN); std::shared_ptr local_tp = std::make_shared(static_cast(0)); std::shared_ptr remote_tp = @@ -100,7 +100,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(0, &app_map); + QUICStreamManager sm(new MockQUICRTTProvider(), 0, &app_map, NET_VCONNECTION_IN); std::shared_ptr local_tp = std::make_shared(static_cast(0)); local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); @@ -133,7 +133,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(0, &app_map); + QUICStreamManager sm(new MockQUICRTTProvider(), 0, &app_map, NET_VCONNECTION_IN); std::shared_ptr local_tp = std::make_shared(static_cast(0)); local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); From 10540fb9a42b6426835ebdb26ee468ac4df9ad95 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 20 Apr 2018 14:16:17 +0900 Subject: [PATCH 0518/1313] Set FIN bit to request from quic client --- cmd/traffic_quic/quic_client.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc index 239641466af..2729f6dcd31 100644 --- a/cmd/traffic_quic/quic_client.cc +++ b/cmd/traffic_quic/quic_client.cc @@ -128,6 +128,7 @@ QUICClientApp::start(const char *path) QUICStreamIO *stream_io = this->_find_stream_io(stream_id); stream_io->write(reinterpret_cast(request), request_len); + stream_io->shutdown(); stream_io->write_reenable(); } From 5beddd6d1e29ceaff9c488f00949dab17f28ab48 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 20 Apr 2018 15:29:17 +0900 Subject: [PATCH 0519/1313] Print appropriate frame info in debug log --- iocore/net/QUICNetVConnection.cc | 9 ++++++--- iocore/net/quic/QUICFrame.cc | 28 ++++++++++++++++++++++++++ iocore/net/quic/QUICFrame.h | 4 ++++ iocore/net/quic/QUICFrameDispatcher.cc | 4 +++- iocore/net/quic/QUICLossDetector.cc | 7 ------- 5 files changed, 41 insertions(+), 11 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 506223d8542..b7a38323300 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1092,8 +1092,6 @@ void QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, QUICFrameUPtr frame) { - QUICConVDebug("type=%s size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); - uint32_t max_size = this->maximum_quic_packet_size(); QUICPacketType previous_packet_type = current_packet_type; @@ -1120,7 +1118,12 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans } size_t l = 0; - QUICConDebug("type=%s size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); + + // TODO: check debug build + char msg[1024]; + frame->debug_msg(msg, sizeof(msg)); + QUICConDebug("[TX] %s", msg); + frame->store(buf.get() + len, &l); len += l; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index a2fadd9578f..428f1e2ceaf 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -24,6 +24,7 @@ #include "QUICFrame.h" #include "QUICStream.h" #include "QUICIntUtil.h" +#include "QUICDebugNames.h" ClassAllocator quicStreamFrameAllocator("quicStreamFrameAllocator"); ClassAllocator quicAckFrameAllocator("quicAckFrameAllocator"); @@ -75,6 +76,12 @@ QUICFrame::is_protected() const return this->_protection; } +int +QUICFrame::debug_msg(char *msg, size_t msg_len) const +{ + return snprintf(msg, msg_len, "type=%s size=%zu", QUICDebugNames::frame_type(this->type()), this->size()); +} + // // STREAM Frame // @@ -108,6 +115,13 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len) const this->store(buf, len, true); } +int +QUICStreamFrame::debug_msg(char *msg, size_t msg_len) const +{ + return snprintf(msg, msg_len, "type=STREAM size=%zu id=%" PRIu64 " offset=%" PRIu64 " data_len=%" PRIu64 " fin=%d", this->size(), + this->stream_id(), this->offset(), this->data_length(), this->has_fin_flag()); +} + void QUICStreamFrame::store(uint8_t *buf, size_t *len, bool include_length_field) const { @@ -381,6 +395,20 @@ QUICAckFrame::store(uint8_t *buf, size_t *len) const return; } +int +QUICAckFrame::debug_msg(char *msg, size_t msg_len) const +{ + int len = snprintf(msg, msg_len, "type=ACK size=%zu largest_acked=%" PRIu64 " delay=%" PRIu64 " block_count=%" PRIu64, + this->size(), this->largest_acknowledged(), this->ack_delay(), this->ack_block_count()); + msg_len -= len; + + if (this->ack_block_section()) { + len += snprintf(msg + len, msg_len, " first_ack_block=%" PRIu64, this->ack_block_section()->first_ack_block()); + } + + return len; +} + bool QUICAckFrame::is_protected() const { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index f8715413146..89a289beb8f 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -45,6 +45,7 @@ class QUICFrame virtual void store(uint8_t *buf, size_t *len) const = 0; virtual void reset(const uint8_t *buf, size_t len); virtual bool is_protected() const; + virtual int debug_msg(char *msg, size_t msg_len) const; LINK(QUICFrame, link); protected: @@ -69,6 +70,7 @@ class QUICStreamFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; + virtual int debug_msg(char *msg, size_t msg_len) const override; void store(uint8_t *buf, size_t *len, bool include_length_field) const; QUICStreamId stream_id() const; @@ -198,6 +200,8 @@ class QUICAckFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; + virtual int debug_msg(char *msg, size_t msg_len) const override; + bool is_protected() const override; QUICPacketNumber largest_acknowledged() const; diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 5b8b7a10607..a6e58761102 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -58,7 +58,9 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size, bool // TODO: check debug build if (type != QUICFrameType::PADDING) { - Debug(tag, "type=%s, size=%zu", QUICDebugNames::frame_type(frame->type()), frame->size()); + char msg[1024]; + frame->debug_msg(msg, sizeof(msg)); + Debug(tag, "[RX] %s", msg); } should_send_ack |= (type != QUICFrameType::PADDING && type != QUICFrameType::ACK); diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 0c873c05de5..d0ace9ca735 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -192,13 +192,6 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - QUICLDDebug("Largest Acknowledged: %" PRIu64, ack_frame->largest_acknowledged()); - QUICLDDebug("ACK Delay: %" PRIu64, ack_frame->ack_delay()); - QUICLDDebug("ACK Block Count: %" PRIu64, ack_frame->ack_block_count()); - if (ack_frame->ack_block_section()) { - QUICLDDebug("First ACK Block: %" PRIu64, ack_frame->ack_block_section()->first_ack_block()); - } - this->_largest_acked_packet = ack_frame->largest_acknowledged(); // If the largest acked is newly acked, update the RTT. auto pi = this->_sent_packets.find(ack_frame->largest_acknowledged()); From 36b9f22cb5d0d97f6f73a9a86f857bb80c8a8b76 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 23 Apr 2018 16:19:27 +0900 Subject: [PATCH 0520/1313] Add QUICClientConfig --- cmd/traffic_quic/quic_client.cc | 9 +++++++-- cmd/traffic_quic/quic_client.h | 17 +++++++++-------- cmd/traffic_quic/traffic_quic.cc | 17 +++++++---------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc index 2729f6dcd31..7f10fd4b366 100644 --- a/cmd/traffic_quic/quic_client.cc +++ b/cmd/traffic_quic/quic_client.cc @@ -23,6 +23,11 @@ #include "quic_client.h" +QUICClient::~QUICClient(const QUICClientConfig *config) : Continuation(new_ProxyMutex()), _config(config) +{ + SET_HANDLER(&QUICClient::start); +} + QUICClient::~QUICClient() { freeaddrinfo(this->_remote_addr_info); @@ -41,7 +46,7 @@ QUICClient::start(int, void *) hints.ai_flags = 0; hints.ai_protocol = 0; - int res = getaddrinfo(this->_remote_addr, this->_remote_port, &hints, &this->_remote_addr_info); + int res = getaddrinfo(this->_config->addr, this->_config->port, &hints, &this->_remote_addr_info); if (res < 0) { Debug("quic_client", "Error: %s (%d)", strerror(errno), errno); return EVENT_DONE; @@ -76,7 +81,7 @@ QUICClient::state_http_server_open(int event, void *data) QUICNetVConnection *conn = static_cast(data); QUICClientApp *app = new QUICClientApp(conn); - app->start(this->_path); + app->start(this->_config->path); break; } diff --git a/cmd/traffic_quic/quic_client.h b/cmd/traffic_quic/quic_client.h index 15071c35558..8a13a49d704 100644 --- a/cmd/traffic_quic/quic_client.h +++ b/cmd/traffic_quic/quic_client.h @@ -30,24 +30,25 @@ #include "QUICApplication.h" +struct QUICClientConfig { + char addr[1024] = "127.0.0.1"; + char port[16] = "4433"; + char path[1018] = "/"; + char debug_tags[1024] = "quic"; +}; + class QUICClient : public Continuation { public: - QUICClient(const char *addr, const char *port, const char *path) - : Continuation(new_ProxyMutex()), _remote_addr(addr), _remote_port(port), _path(path) - { - SET_HANDLER(&QUICClient::start); - }; + QUICClient(const QUICClientConfig *config); ~QUICClient(); int start(int, void *); int state_http_server_open(int event, void *data); private: - const char *_remote_addr = nullptr; - const char *_remote_port = nullptr; + const QUICClientConfig *_config = nullptr; struct addrinfo *_remote_addr_info = nullptr; - const char *_path = nullptr; }; class QUICClientApp : public QUICApplication diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index 2098d49131d..7e85b38b754 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -49,16 +49,13 @@ main(int argc, const char **argv) AppVersionInfo appVersionInfo; appVersionInfo.setup(PACKAGE_NAME, "traffic_quic", PACKAGE_VERSION, __DATE__, __TIME__, BUILD_MACHINE, BUILD_PERSON, ""); - char addr[1024] = "127.0.0.1"; - char port[16] = "4433"; - char path[1018] = "/"; - char debug_tags[1024] = "quic"; + QUICClientConfig config; const ArgumentDescription argument_descriptions[] = { - {"addr", 'a', "Address", "S1023", addr, nullptr, nullptr}, - {"port", 'p', "Port", "S15", port, nullptr, nullptr}, - {"path", 'P', "Path", "S1017", path, nullptr, nullptr}, - {"debug", 'T', "Vertical-bar-separated Debug Tags", "S1023", debug_tags, nullptr, nullptr}, + {"addr", 'a', "Address", "S1023", config.addr, nullptr, nullptr}, + {"port", 'p', "Port", "S15", config.port, nullptr, nullptr}, + {"path", 'P', "Path", "S1017", config.path, nullptr, nullptr}, + {"debug", 'T', "Vertical-bar-separated Debug Tags", "S1023", config.debug_tags, nullptr, nullptr}, HELP_ARGUMENT_DESCRIPTION(), VERSION_ARGUMENT_DESCRIPTION(), RUNROOT_ARGUMENT_DESCRIPTION(), @@ -67,7 +64,7 @@ main(int argc, const char **argv) // Process command line arguments and dump into variables process_args(&appVersionInfo, argument_descriptions, countof(argument_descriptions), argv); - init_diags(debug_tags, nullptr); + init_diags(config.debug_tags, nullptr); RecProcessInit(RECM_STAND_ALONE); LibRecordsConfigInit(); @@ -89,7 +86,7 @@ main(int argc, const char **argv) udpNet.start(1, stacksize); quic_NetProcessor.start(-1, stacksize); - QUICClient client(addr, port, path); + QUICClient client(&config); eventProcessor.schedule_in(&client, 1, ET_NET); this_thread()->execute(); From 98ebf16b32524dea30b042d9b823c3cb98bd5044 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 23 Apr 2018 16:20:27 +0900 Subject: [PATCH 0521/1313] Add "output" option to quic client STDOUT is default destination. --- cmd/traffic_quic/quic_client.cc | 50 +++++++++++++++++++++++++++----- cmd/traffic_quic/quic_client.h | 6 +++- cmd/traffic_quic/traffic_quic.cc | 1 + 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc index 7f10fd4b366..5710b789dcf 100644 --- a/cmd/traffic_quic/quic_client.cc +++ b/cmd/traffic_quic/quic_client.cc @@ -23,7 +23,10 @@ #include "quic_client.h" -QUICClient::~QUICClient(const QUICClientConfig *config) : Continuation(new_ProxyMutex()), _config(config) +#include +#include + +QUICClient::QUICClient(const QUICClientConfig *config) : Continuation(new_ProxyMutex()), _config(config) { SET_HANDLER(&QUICClient::start); } @@ -80,7 +83,13 @@ QUICClient::state_http_server_open(int event, void *data) Debug("quic_client", "start proxy server ssn/txn"); QUICNetVConnection *conn = static_cast(data); - QUICClientApp *app = new QUICClientApp(conn); + + const char *filename = nullptr; + if (this->_config->output[0] != 0x0) { + filename = this->_config->output; + } + + QUICClientApp *app = new QUICClientApp(conn, filename); app->start(this->_config->path); break; @@ -106,7 +115,7 @@ QUICClient::state_http_server_open(int event, void *data) #define QUICClientAppDebug(fmt, ...) \ Debug("quic_client_app", "[%" PRIx64 "] " fmt, static_cast(this->_qc->connection_id()), ##__VA_ARGS__) -QUICClientApp::QUICClientApp(QUICNetVConnection *qvc) : QUICApplication(qvc) +QUICClientApp::QUICClientApp(QUICNetVConnection *qvc, const char *filename) : QUICApplication(qvc), _filename(filename) { this->_qc->stream_manager()->set_default_application(this); @@ -116,6 +125,11 @@ QUICClientApp::QUICClientApp(QUICNetVConnection *qvc) : QUICApplication(qvc) void QUICClientApp::start(const char *path) { + if (this->_filename) { + // Destroy contents if file already exists + std::ofstream f_stream(this->_filename, std::ios::binary | std::ios::trunc); + } + QUICStreamId stream_id; QUICErrorUPtr error = this->_qc->stream_manager()->create_bidi_stream(stream_id); @@ -152,13 +166,33 @@ QUICClientApp::main_event_handler(int event, Event *data) switch (event) { case VC_EVENT_READ_READY: - case VC_EVENT_READ_COMPLETE: - if (stream_io->is_read_avail_more_than(0)) { - uint8_t response[1024] = {0}; - stream_io->read(response, sizeof(response)); - QUICClientAppDebug("\n%s", response); + case VC_EVENT_READ_COMPLETE: { + std::streambuf *default_stream = nullptr; + std::ofstream f_stream; + + if (this->_filename) { + default_stream = std::cout.rdbuf(); + f_stream = std::ofstream(this->_filename, std::ios::binary | std::ios::app); + std::cout.rdbuf(f_stream.rdbuf()); } + + while (stream_io->is_read_avail_more_than(0)) { + uint8_t buf[8192] = {0}; + int64_t len = stream_io->get_read_buffer_reader()->block_read_avail(); + len = std::min(len, (int64_t)sizeof(buf)); + stream_io->read(buf, len); + + std::cout.write(reinterpret_cast(buf), len); + } + std::cout.flush(); + + if (this->_filename) { + f_stream.close(); + std::cout.rdbuf(default_stream); + } + break; + } case VC_EVENT_WRITE_READY: case VC_EVENT_WRITE_COMPLETE: break; diff --git a/cmd/traffic_quic/quic_client.h b/cmd/traffic_quic/quic_client.h index 8a13a49d704..0e3e534c857 100644 --- a/cmd/traffic_quic/quic_client.h +++ b/cmd/traffic_quic/quic_client.h @@ -32,6 +32,7 @@ struct QUICClientConfig { char addr[1024] = "127.0.0.1"; + char output[1024] = {0}; char port[16] = "4433"; char path[1018] = "/"; char debug_tags[1024] = "quic"; @@ -54,8 +55,11 @@ class QUICClient : public Continuation class QUICClientApp : public QUICApplication { public: - QUICClientApp(QUICNetVConnection *qvc); + QUICClientApp(QUICNetVConnection *qvc, const char *filename); void start(const char *path); int main_event_handler(int event, Event *data); + +private: + const char *_filename = nullptr; }; diff --git a/cmd/traffic_quic/traffic_quic.cc b/cmd/traffic_quic/traffic_quic.cc index 7e85b38b754..ec81a4582e7 100644 --- a/cmd/traffic_quic/traffic_quic.cc +++ b/cmd/traffic_quic/traffic_quic.cc @@ -53,6 +53,7 @@ main(int argc, const char **argv) const ArgumentDescription argument_descriptions[] = { {"addr", 'a', "Address", "S1023", config.addr, nullptr, nullptr}, + {"output", 'o', "Write to FILE instead of stdout", "S1023", config.output, nullptr, nullptr}, {"port", 'p', "Port", "S15", config.port, nullptr, nullptr}, {"path", 'P', "Path", "S1017", config.path, nullptr, nullptr}, {"debug", 'T', "Vertical-bar-separated Debug Tags", "S1023", config.debug_tags, nullptr, nullptr}, From d8feb83a9d39d269a06717e708b419ebd190c2b9 Mon Sep 17 00:00:00 2001 From: Leif Hedstrom Date: Sun, 29 Apr 2018 13:18:29 -0600 Subject: [PATCH 0522/1313] Updated to new clang-format --- iocore/net/QUICNet.cc | 4 +--- iocore/net/QUICNetProcessor.cc | 4 +--- iocore/net/QUICNextProtocolAccept.cc | 4 +--- iocore/net/quic/Mock.h | 3 ++- iocore/net/quic/QUICCongestionController.cc | 14 +++++++------- iocore/net/quic/QUICFrame.cc | 3 ++- iocore/net/quic/QUICFrame.h | 2 +- iocore/net/quic/QUICFrameGenerator.h | 2 +- iocore/net/quic/QUICHandshake.cc | 4 +--- iocore/net/quic/QUICHandshakeProtocol.cc | 4 +--- iocore/net/quic/QUICHandshakeProtocol.h | 14 +++++++------- iocore/net/quic/QUICPacket.cc | 4 +--- iocore/net/quic/QUICTLS.cc | 4 +--- iocore/net/quic/test/test_QUICKeyGenerator.cc | 4 ++-- iocore/net/quic/test/test_QUICLossDetector.cc | 2 +- lib/records/I_RecHttp.h | 2 +- proxy/hq/HQClientSession.cc | 4 +--- proxy/hq/HQDataFramer.cc | 4 +--- proxy/hq/HQFrame.cc | 8 ++------ proxy/hq/HQHeaderVIOAdaptor.cc | 4 +--- proxy/hq/HQSessionAccept.cc | 4 +--- proxy/hq/HQStreamDataVIOAdaptor.cc | 4 +--- 22 files changed, 38 insertions(+), 64 deletions(-) diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index f51c5ac70fb..83411ef0c36 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -57,9 +57,7 @@ QUICPollCont::QUICPollCont(Ptr &m, NetHandler *nh) : Continuation(m. SET_HANDLER(&QUICPollCont::pollEvent); } -QUICPollCont::~QUICPollCont() -{ -} +QUICPollCont::~QUICPollCont() {} void QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index e580a623b94..66c16d83414 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -34,9 +34,7 @@ QUICNetProcessor quic_NetProcessor; -QUICNetProcessor::QUICNetProcessor() -{ -} +QUICNetProcessor::QUICNetProcessor() {} QUICNetProcessor::~QUICNetProcessor() { diff --git a/iocore/net/QUICNextProtocolAccept.cc b/iocore/net/QUICNextProtocolAccept.cc index bdd89ed5922..d96d275dc91 100644 --- a/iocore/net/QUICNextProtocolAccept.cc +++ b/iocore/net/QUICNextProtocolAccept.cc @@ -98,6 +98,4 @@ QUICNextProtocolAccept::cloneProtoSet() return this->protoset.clone(); } -QUICNextProtocolAccept::~QUICNextProtocolAccept() -{ -} +QUICNextProtocolAccept::~QUICNextProtocolAccept() {} diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index bed653e9763..9ea5b61ced9 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -510,7 +510,8 @@ class MockContinuation : public Continuation class MockQUICRTTProvider : public QUICRTTProvider { - ink_hrtime smoothed_rtt() const + ink_hrtime + smoothed_rtt() const { return HRTIME_MSECONDS(1); } diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index b748050c60a..2c45aad14a2 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -27,20 +27,20 @@ #include "QUICConfig.h" #define QUICCCDebug(fmt, ...) \ - Debug("quic_cc", "[%" PRIx64 "] " \ - "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ + Debug("quic_cc", \ + "[%" PRIx64 "] " \ + "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ static_cast(this->_connection_id), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, \ ##__VA_ARGS__) #define QUICCCError(fmt, ...) \ - Error("quic_cc", "[%" PRIx64 "] " \ - "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ + Error("quic_cc", \ + "[%" PRIx64 "] " \ + "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ static_cast(this->_connection_id), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, \ ##__VA_ARGS__) -QUICCongestionController::QUICCongestionController() : QUICCongestionController(0) -{ -} +QUICCongestionController::QUICCongestionController() : QUICCongestionController(0) {} QUICCongestionController::QUICCongestionController(QUICConnectionId connection_id) : _connection_id(connection_id) { diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 428f1e2ceaf..36e4974a099 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -731,7 +731,8 @@ QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, con } // FIXME: something wrong with clang-format? -const QUICAckFrame::AckBlock &QUICAckFrame::AckBlockSection::const_iterator::operator++() +const QUICAckFrame::AckBlock & +QUICAckFrame::AckBlockSection::const_iterator::operator++() { ++(this->_index); diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 89a289beb8f..8d8173c5fd3 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -41,7 +41,7 @@ class QUICFrame static QUICFrameType type(const uint8_t *buf); virtual QUICFrameType type() const; - virtual size_t size() const = 0; + virtual size_t size() const = 0; virtual void store(uint8_t *buf, size_t *len) const = 0; virtual void reset(const uint8_t *buf, size_t len); virtual bool is_protected() const; diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index 7c2d40ee2da..f815437a941 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -29,6 +29,6 @@ class QUICFrameGenerator { public: virtual ~QUICFrameGenerator(){}; - virtual bool will_generate_frame() = 0; + virtual bool will_generate_frame() = 0; virtual QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) = 0; }; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 831da5655ee..540f5ab6871 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -86,9 +86,7 @@ static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandshake(qc, ssl_ctx, {}, false) -{ -} +QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandshake(qc, ssl_ctx, {}, false) {} QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token, bool stateless_retry) : QUICApplication(qc), diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index d73826a0039..cea5d48245e 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -32,9 +32,7 @@ // QUICPacketProtection // -QUICPacketProtection::~QUICPacketProtection() -{ -} +QUICPacketProtection::~QUICPacketProtection() {} void QUICPacketProtection::set_key(std::unique_ptr km, QUICKeyPhase phase) diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 3e4649d8fb6..e8760d333ec 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -50,15 +50,15 @@ class QUICHandshakeProtocol virtual ~QUICHandshakeProtocol(){}; virtual int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) = 0; - virtual bool is_handshake_finished() const = 0; - virtual bool is_ready_to_derive() const = 0; - virtual bool is_key_derived(QUICKeyPhase key_phase) const = 0; - virtual int initialize_key_materials(QUICConnectionId cid) = 0; - virtual int update_key_materials() = 0; + virtual bool is_handshake_finished() const = 0; + virtual bool is_ready_to_derive() const = 0; + virtual bool is_key_derived(QUICKeyPhase key_phase) const = 0; + virtual int initialize_key_materials(QUICConnectionId cid) = 0; + virtual int update_key_materials() = 0; virtual bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; virtual bool decrypt(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, QUICKeyPhase phase) const = 0; + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; virtual QUICHandshakeMsgType msg_type() const; protected: diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index aea9318f377..1dfc4ab1b06 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -489,9 +489,7 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const // QUICPacket // -QUICPacket::QUICPacket() -{ -} +QUICPacket::QUICPacket() {} QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len) { diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index ec2434588a1..76e9d3be1b7 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -51,9 +51,7 @@ QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless) this->_server_pp = new QUICPacketProtection(); } -QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICTLS(ssl, nvc_ctx, false) -{ -} +QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICTLS(ssl, nvc_ctx, false) {} QUICTLS::~QUICTLS() { diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index 1f94296c45f..fd91b209d2c 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -59,7 +59,7 @@ TEST_CASE("QUICKeyGenerator", "[quic]") QUICConnectionId cid = 0x8394c8f03e515708; uint8_t expected_client_key[] = {0x3a, 0xd0, 0x54, 0x2c, 0x4a, 0x85, 0x84, 0x74, 0x00, 0x63, 0x04, 0x9e, 0x3b, 0x3c, 0xaa, 0xb2}; - uint8_t expected_client_iv[] = {0xd1, 0xfd, 0x26, 0x05, 0x42, 0x75, 0x3a, 0xba, 0x38, 0x58, 0x9b, 0xad}; + uint8_t expected_client_iv[] = {0xd1, 0xfd, 0x26, 0x05, 0x42, 0x75, 0x3a, 0xba, 0x38, 0x58, 0x9b, 0xad}; std::unique_ptr actual_km = keygen.generate(cid); @@ -76,7 +76,7 @@ TEST_CASE("QUICKeyGenerator", "[quic]") QUICConnectionId cid = 0x8394c8f03e515708; uint8_t expected_server_key[] = {0xbe, 0xe4, 0xc2, 0x4d, 0x2a, 0xf1, 0x33, 0x80, 0xa9, 0xfa, 0x24, 0xa5, 0xe2, 0xba, 0x2c, 0xff}; - uint8_t expected_server_iv[] = {0x25, 0xb5, 0x8e, 0x24, 0x6d, 0x9e, 0x7d, 0x5f, 0xfe, 0x43, 0x23, 0xfe}; + uint8_t expected_server_iv[] = {0x25, 0xb5, 0x8e, 0x24, 0x6d, 0x9e, 0x7d, 0x5f, 0xfe, 0x43, 0x23, 0xfe}; std::unique_ptr actual_km = keygen.generate(cid); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index b3ee4f007cc..d898306dc51 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -138,7 +138,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") afc->update(pn9, false, true); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); std::shared_ptr x = afc->generate_frame(2048, 2048); - frame = std::dynamic_pointer_cast(x); + frame = std::dynamic_pointer_cast(x); detector.handle_frame(frame); ink_hrtime_sleep(HRTIME_MSECONDS(5000)); diff --git a/lib/records/I_RecHttp.h b/lib/records/I_RecHttp.h index 7584f131860..f9f069d38c3 100644 --- a/lib/records/I_RecHttp.h +++ b/lib/records/I_RecHttp.h @@ -307,7 +307,7 @@ struct HttpProxyPort { /// Check for QUIC ports. /// @return @c true if any port in @a ports is an QUIC port. static bool hasQUIC(Group const &ports ///< Ports to check. - ); + ); /// Check for QUIC ports. /// @return @c true if any global port is an QUIC port. diff --git a/proxy/hq/HQClientSession.cc b/proxy/hq/HQClientSession.cc index b8ede45db7c..332bcb052fa 100644 --- a/proxy/hq/HQClientSession.cc +++ b/proxy/hq/HQClientSession.cc @@ -23,9 +23,7 @@ #include "HQClientSession.h" -HQClientSession::HQClientSession(NetVConnection *vc) : _client_vc(vc) -{ -} +HQClientSession::HQClientSession(NetVConnection *vc) : _client_vc(vc) {} HQClientSession::~HQClientSession() { diff --git a/proxy/hq/HQDataFramer.cc b/proxy/hq/HQDataFramer.cc index 09f55ae043b..d074a27d8ee 100644 --- a/proxy/hq/HQDataFramer.cc +++ b/proxy/hq/HQDataFramer.cc @@ -25,9 +25,7 @@ #include "HQDataFramer.h" #include "HQClientTransaction.h" -HQDataFramer::HQDataFramer(HQClientTransaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) -{ -} +HQDataFramer::HQDataFramer(HQClientTransaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) {} HQFrameUPtr HQDataFramer::generate_frame(uint16_t max_size) diff --git a/proxy/hq/HQFrame.cc b/proxy/hq/HQFrame.cc index f34ac78d84e..3df902c7380 100644 --- a/proxy/hq/HQFrame.cc +++ b/proxy/hq/HQFrame.cc @@ -75,9 +75,7 @@ HQFrame::HQFrame(const uint8_t *buf, size_t buf_len) this->_payload_offset = length_field_length + 2; } -HQFrame::HQFrame(HQFrameType type) : _type(type) -{ -} +HQFrame::HQFrame(HQFrameType type) : _type(type) {} uint64_t HQFrame::total_length() const @@ -120,9 +118,7 @@ HQFrame::reset(const uint8_t *buf, size_t len) // // UNKNOWN Frame // -HQUnknownFrame::HQUnknownFrame(const uint8_t *buf, size_t buf_len) : HQFrame(buf, buf_len), _buf(buf), _buf_len(buf_len) -{ -} +HQUnknownFrame::HQUnknownFrame(const uint8_t *buf, size_t buf_len) : HQFrame(buf, buf_len), _buf(buf), _buf_len(buf_len) {} void HQUnknownFrame::store(uint8_t *buf, size_t *len) const diff --git a/proxy/hq/HQHeaderVIOAdaptor.cc b/proxy/hq/HQHeaderVIOAdaptor.cc index 366e8651118..0c44d81f8fa 100644 --- a/proxy/hq/HQHeaderVIOAdaptor.cc +++ b/proxy/hq/HQHeaderVIOAdaptor.cc @@ -24,9 +24,7 @@ #include "HQHeaderVIOAdaptor.h" #include "I_VIO.h" -HQHeaderVIOAdaptor::HQHeaderVIOAdaptor(VIO *sink) : _sink_vio(sink) -{ -} +HQHeaderVIOAdaptor::HQHeaderVIOAdaptor(VIO *sink) : _sink_vio(sink) {} std::vector HQHeaderVIOAdaptor::interests() diff --git a/proxy/hq/HQSessionAccept.cc b/proxy/hq/HQSessionAccept.cc index 75d8982fb4e..9906a457c2e 100644 --- a/proxy/hq/HQSessionAccept.cc +++ b/proxy/hq/HQSessionAccept.cc @@ -33,9 +33,7 @@ HQSessionAccept::HQSessionAccept(const HttpSessionAccept::Options &_o) : Session SET_HANDLER(&HQSessionAccept::mainEvent); } -HQSessionAccept::~HQSessionAccept() -{ -} +HQSessionAccept::~HQSessionAccept() {} bool HQSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader *reader) diff --git a/proxy/hq/HQStreamDataVIOAdaptor.cc b/proxy/hq/HQStreamDataVIOAdaptor.cc index 5df11902b9b..675b3c3ceed 100644 --- a/proxy/hq/HQStreamDataVIOAdaptor.cc +++ b/proxy/hq/HQStreamDataVIOAdaptor.cc @@ -24,9 +24,7 @@ #include "HQStreamDataVIOAdaptor.h" #include "I_VIO.h" -HQStreamDataVIOAdaptor::HQStreamDataVIOAdaptor(VIO *sink) : _sink_vio(sink) -{ -} +HQStreamDataVIOAdaptor::HQStreamDataVIOAdaptor(VIO *sink) : _sink_vio(sink) {} std::vector HQStreamDataVIOAdaptor::interests() From 4589908eee4863c0b33339283d3856024ab12e1f Mon Sep 17 00:00:00 2001 From: Leif Hedstrom Date: Sun, 29 Apr 2018 13:28:10 -0600 Subject: [PATCH 0523/1313] Fioxes build issues due to extraneous tab in Makefile --- proxy/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/Makefile.am b/proxy/Makefile.am index ac4b53e3535..c49f45731c5 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -216,7 +216,7 @@ endif traffic_server_LDADD += \ $(top_builddir)/iocore/net/libinknet.a - if ENABLE_QUIC +if ENABLE_QUIC traffic_server_LDADD += \ $(top_builddir)/iocore/net/quic/libquic.a endif From cbc48bcae3f6be1febde6b38b9723233bfe596aa Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 6 Apr 2018 10:45:59 +0900 Subject: [PATCH 0524/1313] Make ConnectionId width flexible --- iocore/net/quic/QUICCongestionController.cc | 2 +- iocore/net/quic/QUICConnectionTable.h | 2 +- iocore/net/quic/QUICFrame.h | 2 +- iocore/net/quic/QUICLossDetector.cc | 2 +- iocore/net/quic/QUICLossDetector.h | 4 +- iocore/net/quic/QUICPacket.h | 2 +- iocore/net/quic/QUICStream.h | 2 +- iocore/net/quic/QUICStreamManager.h | 2 +- iocore/net/quic/QUICTypes.cc | 58 +++++++++++++++++++-- iocore/net/quic/QUICTypes.h | 33 ++++++++---- 10 files changed, 88 insertions(+), 21 deletions(-) diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 2c45aad14a2..10ea251f77b 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -40,7 +40,7 @@ static_cast(this->_connection_id), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, \ ##__VA_ARGS__) -QUICCongestionController::QUICCongestionController() : QUICCongestionController(0) {} +QUICCongestionController::QUICCongestionController() : QUICCongestionController(QUICConnectionId::ZERO()) {} QUICCongestionController::QUICCongestionController(QUICConnectionId connection_id) : _connection_id(connection_id) { diff --git a/iocore/net/quic/QUICConnectionTable.h b/iocore/net/quic/QUICConnectionTable.h index 2a4fefd91fb..d210e84135c 100644 --- a/iocore/net/quic/QUICConnectionTable.h +++ b/iocore/net/quic/QUICConnectionTable.h @@ -56,5 +56,5 @@ class QUICConnectionTable QUICConnection *lookup(const uint8_t *packet, QUICFiveTuple endpoint); private: - MTHashTable _connections; + MTHashTable _connections; }; diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 8d8173c5fd3..1c0c223b97e 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -505,7 +505,7 @@ class QUICNewConnectionIdFrame : public QUICFrame size_t _get_connection_id_field_offset() const; uint64_t _sequence = 0; - QUICConnectionId _connection_id = 0; + QUICConnectionId _connection_id = QUICConnectionId::ZERO(); QUICStatelessResetToken _stateless_reset_token; }; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index d0ace9ca735..07926c3daff 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -132,7 +132,7 @@ QUICLossDetector::largest_acked_packet_number() void QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) { - if (this->_connection_id == 0 && packet->type() != QUICPacketType::VERSION_NEGOTIATION) { + if (this->_connection_id.is_zero() && packet->type() != QUICPacketType::VERSION_NEGOTIATION) { this->_connection_id = packet->connection_id(); } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index e48fe3275a1..1fef478f1b2 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -86,7 +86,7 @@ class QUICCongestionController QUICPacketNumber _end_of_recovery = 0; uint32_t _ssthresh = UINT32_MAX; - QUICConnectionId _connection_id = 0; + QUICConnectionId _connection_id = QUICConnectionId::ZERO(); bool _in_recovery(QUICPacketNumber packet_number); }; @@ -110,7 +110,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU private: Ptr _loss_detection_mutex; - QUICConnectionId _connection_id = 0; + QUICConnectionId _connection_id = QUICConnectionId::ZERO(); // TODO QUICCongestionController *cc = nullptr; diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 8ec0845eaa4..52d01783f39 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -152,7 +152,7 @@ class QUICPacketHeader ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); QUICPacketType _type = QUICPacketType::UNINITIALIZED; QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; - QUICConnectionId _connection_id = 0; + QUICConnectionId _connection_id = QUICConnectionId::ZERO(); QUICPacketNumber _packet_number = 0; QUICPacketNumber _base_packet_number = 0; QUICVersion _version = 0; diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index b4f522de8d5..c7cc01260e0 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -108,7 +108,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator QUICStreamState _state; bool _fin = false; QUICStreamErrorUPtr _reset_reason = nullptr; - QUICConnectionId _connection_id = 0; + QUICConnectionId _connection_id = QUICConnectionId::ZERO(); QUICStreamId _id = 0; QUICOffset _send_offset = 0; diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 3b14b41167f..0edc1142a90 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -77,7 +77,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICErrorUPtr _handle_frame(const std::shared_ptr &); - QUICConnectionId _connection_id = 0; + QUICConnectionId _connection_id = QUICConnectionId::ZERO(); QUICApplicationMap *_app_map = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; std::shared_ptr _local_tp = nullptr; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index c4064b56ea9..eea24f595ea 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -61,8 +61,7 @@ QUICTypeUtil::detect_stream_type(QUICStreamId id) QUICConnectionId QUICTypeUtil::read_QUICConnectionId(const uint8_t *buf, uint8_t len) { - // Should be QUICConnectionId(read_nbytes_as_uint(buf, len)); - return static_cast(QUICIntUtil::read_nbytes_as_uint(buf, len)); + return {buf, len}; } QUICPacketNumber @@ -110,7 +109,8 @@ QUICTypeUtil::read_QUICMaxData(const uint8_t *buf) void QUICTypeUtil::write_QUICConnectionId(QUICConnectionId connection_id, uint8_t n, uint8_t *buf, size_t *len) { - QUICIntUtil::write_uint_as_nbytes(static_cast(connection_id), n, buf, len); + memcpy(buf, connection_id, n); + *len = n; } void @@ -212,3 +212,55 @@ QUICFiveTuple::protocol() const { return this->_protocol; } + +// +// QUICConnectionId +// +QUICConnectionId +QUICConnectionId::ZERO() +{ + uint8_t zero[] = {0, 0, 0, 0, 0, 0, 0, 0}; + return QUICConnectionId(zero, sizeof(zero)); +} + +QUICConnectionId::QUICConnectionId() +{ + this->randomize(); +} + +QUICConnectionId::QUICConnectionId(const uint8_t *buf, uint8_t len) +{ + memcpy(this->_id, buf, len); +} + +bool +QUICConnectionId::is_zero() const +{ + for (int i = sizeof(this->_id) - 1; i >= 0; --i) { + if (this->_id[i]) { + return false; + } + } + return true; +} + +void +QUICConnectionId::randomize() +{ + std::random_device rnd; + uint32_t x; + for (int i = sizeof(this->_id) - 1; i >= 0; --i) { + if (i % 4 == 0) { + x = rnd(); + } + this->_id[i] = (x >> (8 * (i % 4))) & 0xFF; + } +} + +uint64_t +QUICConnectionId::_hashcode() const +{ + return (static_cast(this->_id[0]) << 56) + (static_cast(this->_id[1]) << 48) + + (static_cast(this->_id[2]) << 40) + (static_cast(this->_id[3]) << 32) + (this->_id[4] << 24) + + (this->_id[5] << 16) + (this->_id[6] << 8) + this->_id[7]; +} diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 25481bf725b..aa6e0543fd2 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -209,20 +209,35 @@ using QUICStreamErrorUPtr = std::unique_ptr; class QUICConnectionId { public: + static QUICConnectionId ZERO(); + QUICConnectionId(); + QUICConnectionId(const uint8_t *buf, uint8_t len); + explicit operator bool() const { return true; } - operator uint64_t() const { return _id; }; - QUICConnectionId() { this->randomize(); }; - QUICConnectionId(uint64_t id) : _id(id){}; + /** + * Note that this returns a kind of hash code so we can use a ConnectionId as a key for a hashtable. + */ + operator uint64_t() const { return this->_hashcode(); } + operator const uint8_t *() const { return this->_id; } + + bool + operator==(const QUICConnectionId &x) const + { + return memcmp(this->_id, x._id, sizeof(this->_id)) == 0; + } - void - randomize() + bool + operator!=(const QUICConnectionId &x) const { - std::random_device rnd; - this->_id = (static_cast(rnd()) << 32) + rnd(); - }; + return memcmp(this->_id, x._id, sizeof(this->_id)) != 0; + } + + bool is_zero() const; + void randomize(); private: - uint64_t _id; + uint64_t _hashcode() const; + uint8_t _id[8]; }; class QUICStatelessResetToken From 11e0bae268895e7739fcdeff2c9f8d9b495a3355 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 18 Apr 2018 13:25:01 +0900 Subject: [PATCH 0525/1313] Update QUIC version literals to 11 --- iocore/net/quic/QUICTypes.h | 2 +- lib/ts/ink_inet.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index aa6e0543fd2..5593630774d 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -47,7 +47,7 @@ using QUICOffset = uint64_t; // Note: You also need to update tests for VersionNegotiationPacket creation, if you change the number of versions // Prefix for drafts (0xff000000) + draft number constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff00000a, + 0xff00000b, }; constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; diff --git a/lib/ts/ink_inet.cc b/lib/ts/ink_inet.cc index c02190070ce..c61d0aaeeff 100644 --- a/lib/ts/ink_inet.cc +++ b/lib/ts/ink_inet.cc @@ -49,7 +49,7 @@ const ts::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"_sv); const ts::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"_sv); const ts::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"_sv); const ts::string_view IP_PROTO_TAG_HTTP_2_0("h2"_sv); // HTTP/2 over TLS -const ts::string_view IP_PROTO_TAG_HTTP_QUIC("hq-10"_sv); // HTTP over QUIC +const ts::string_view IP_PROTO_TAG_HTTP_QUIC("hq-11"_sv); // HTTP over QUIC uint32_t ink_inet_addr(const char *s) From adf54ea540029f6e87c6be3c2af3f428c7491b54 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 20 Apr 2018 10:36:54 +0900 Subject: [PATCH 0526/1313] Make tests compilable --- iocore/net/QUICNetVConnection.cc | 10 +- iocore/net/QUICPacketHandler.cc | 2 +- iocore/net/quic/Mock.h | 4 +- iocore/net/quic/QUICLossDetector.cc | 2 +- iocore/net/quic/QUICPacket.cc | 189 ++++++++---------- iocore/net/quic/QUICPacket.h | 45 +++-- iocore/net/quic/QUICVersionNegotiator.cc | 2 +- iocore/net/quic/test/test_QUICFrame.cc | 8 +- iocore/net/quic/test/test_QUICHandshake.cc | 4 +- .../quic/test/test_QUICHandshakeProtocol.cc | 20 +- iocore/net/quic/test/test_QUICKeyGenerator.cc | 4 +- iocore/net/quic/test/test_QUICLossDetector.cc | 4 +- iocore/net/quic/test/test_QUICPacket.cc | 25 +-- .../net/quic/test/test_QUICPacketFactory.cc | 18 +- iocore/net/quic/test/test_QUICStream.cc | 10 +- .../net/quic/test/test_QUICStreamManager.cc | 8 +- 16 files changed, 171 insertions(+), 184 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b7a38323300..badea1136db 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -825,7 +825,7 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - if (packet->connection_id() != this->connection_id()) { + if (packet->destination_cid() != this->connection_id()) { QUICConDebug("Ignore Version Negotiation packet"); return error; } @@ -932,12 +932,12 @@ QUICNetVConnection::_state_common_receive_packet() switch (p->type()) { case QUICPacketType::PROTECTED: // Check connection migration - if (this->_handshake_handler->is_completed() && p->connection_id() != this->_quic_connection_id) { - if (this->_alt_con_manager->migrate_to(p->connection_id(), this->_reset_token)) { + if (this->_handshake_handler->is_completed() && p->destination_cid() != this->_quic_connection_id) { + if (this->_alt_con_manager->migrate_to(p->destination_cid(), this->_reset_token)) { // Migrate connection // TODO Address Validation // TODO Adjust expected packet number with a gap computed based on info.seq_num - this->_quic_connection_id = p->connection_id(); + this->_quic_connection_id = p->destination_cid(); Connection con; con.setRemote(&p->from().sa); this->con.move(con); @@ -1264,7 +1264,7 @@ QUICErrorUPtr QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) { const uint8_t *payload = packet->payload(); - uint16_t size = packet->payload_size(); + uint16_t size = packet->payload_length(); QUICPacketNumber packet_num = packet->packet_number(); if (packet_num > this->_largest_received_packet_number) { diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 5bbb4a5dcf8..f6859112398 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -74,7 +74,7 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo // NOTE: p will be enqueued to udpOutQueue of UDPNetHandler ip_port_text_buffer ipb; - Debug("quic_sec", "[%" PRIx64 "] send %s packet to %s, size=%" PRId64, static_cast(packet.connection_id()), + Debug("quic_sec", "[%" PRIx64 "] send %s packet to %s, size=%" PRId64, static_cast(packet.destination_cid()), QUICDebugNames::packet_type(packet.type()), ats_ip_nptop(&udp_packet->to.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); udp_con->send(c, udp_packet); diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 9ea5b61ced9..dd12b709caa 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -148,13 +148,13 @@ class MockQUICConnection : public QUICConnection QUICConnectionId connection_id() override { - return 0; + return {reinterpret_cast("\x00"), 1}; } QUICConnectionId original_connection_id() override { - return 0; + return {reinterpret_cast("\x00"), 1}; } const QUICFiveTuple diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 07926c3daff..d385d5e35ed 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -133,7 +133,7 @@ void QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) { if (this->_connection_id.is_zero() && packet->type() != QUICPacketType::VERSION_NEGOTIATION) { - this->_connection_id = packet->connection_id(); + this->_connection_id = packet->destination_cid(); } bool is_handshake = false; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 1dfc4ab1b06..bc97c21668d 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -23,6 +23,7 @@ #include #include +#include "QUICIntUtil.h" #include "QUICPacket.h" #include "QUICDebugNames.h" @@ -30,16 +31,11 @@ ClassAllocator quicPacketAllocator("quicPacketAllocator"); ClassAllocator quicPacketLongHeaderAllocator("quicPacketLongHeaderAllocator"); ClassAllocator quicPacketShortHeaderAllocator("quicPacketShortHeaderAllocator"); -static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 1; -static constexpr int LONG_HDR_OFFSET_VERSION = 9; -static constexpr int LONG_HDR_OFFSET_PACKET_NUMBER = 13; -static constexpr int LONG_HDR_OFFSET_PAYLOAD = 17; -static constexpr int LONG_HDR_LENGTH = 17; +static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6; +static constexpr int LONG_HDR_OFFSET_VERSION = 1; static constexpr int SHORT_HDR_OFFSET_CONNECTION_ID = 1; -static constexpr int VERSION_NEGOTIATION_PKT_HEADER_LENGTH = 13; - // // QUICPacketHeader // @@ -69,7 +65,7 @@ QUICPacketHeader::packet_size() const } QUICPacketHeaderUPtr -QUICPacketHeader::load(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base) +QUICPacketHeader::load(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base, uint8_t dcil) { QUICPacketHeaderUPtr header = QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header); if (QUICTypeUtil::has_long_header(buf.get())) { @@ -78,7 +74,7 @@ QUICPacketHeader::load(const IpEndpoint from, ats_unique_buf buf, size_t len, QU header = QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); } else { QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); - new (short_header) QUICPacketShortHeader(from, std::move(buf), len, base); + new (short_header) QUICPacketShortHeader(from, std::move(buf), len, base, dcil); header = QUICPacketHeaderUPtr(short_header, &QUICPacketHeaderDeleter::delete_short_header); } return header; @@ -121,18 +117,46 @@ QUICPacketHeader::clone() const // // QUICPacketLongHeader // + +QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base) : QUICPacketHeader(from, std::move(buf), len, base) +{ + uint8_t *raw_buf = this->_buf.get(); + + uint8_t dcil = (raw_buf[1] >> 4); + if (dcil) { + dcil += 3; + } + uint8_t scil = (raw_buf[1] & 0x0F); + if (scil) { + scil += 3; + } + uint8_t *offset = raw_buf + LONG_HDR_OFFSET_CONNECTION_ID; + this->_destination_cid = {offset, dcil}; + offset += dcil; + this->_source_cid = {offset, scil}; + offset += scil; + + if (this->type() == QUICPacketType::VERSION_NEGOTIATION) { + this->_payload_start = offset; + } else { + this->_payload_length = QUICIntUtil::read_QUICVariableInt(offset); + offset += QUICVariableInt::size(offset); + QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(offset, 4), 4, this->_base_packet_number); + this->_payload_start = offset + 4; + } +} + QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len) { this->_type = type; - this->_has_connection_id = true; this->_connection_id = connection_id; this->_packet_number = packet_number; this->_base_packet_number = base_packet_number; this->_has_version = true; this->_version = version; this->_payload = std::move(buf); - this->_payload_len = len; + this->_payload_length = len; } QUICPacketType @@ -152,28 +176,21 @@ QUICPacketLongHeader::type() const } QUICConnectionId -QUICPacketLongHeader::connection_id() const +QUICPacketLongHeader::destination_cid() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICConnectionId(this->_buf.get() + LONG_HDR_OFFSET_CONNECTION_ID, 8); - } else { - return this->_connection_id; - } + return this->_destination_cid; +} + +QUICConnectionId +QUICPacketLongHeader::source_cid() const +{ + return this->_source_cid; } QUICPacketNumber QUICPacketLongHeader::packet_number() const { - if (this->_buf) { - const uint8_t packet_number_len = 4; - QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + LONG_HDR_OFFSET_PACKET_NUMBER, packet_number_len); - QUICPacketNumber dst = 0; - QUICPacket::decode_packet_number(dst, src, packet_number_len, this->_base_packet_number); - - return dst; - } else { - return this->_packet_number; - } + return this->_packet_number; } bool @@ -192,21 +209,11 @@ QUICPacketLongHeader::version() const } } -bool -QUICPacketLongHeader::has_connection_id() const -{ - return true; -} - const uint8_t * QUICPacketLongHeader::payload() const { if (this->_buf) { - if (this->type() == QUICPacketType::VERSION_NEGOTIATION) { - return this->_buf.get() + VERSION_NEGOTIATION_PKT_HEADER_LENGTH; - } else { - return this->_buf.get() + LONG_HDR_OFFSET_PAYLOAD; - } + return this->_payload_start; } else { return this->_payload.get(); } @@ -215,11 +222,7 @@ QUICPacketLongHeader::payload() const uint16_t QUICPacketHeader::payload_size() const { - if (this->_buf) { - return this->_buf_len - this->size(); - } else { - return this->_payload_len; - } + return this->_payload_length; } bool @@ -238,11 +241,13 @@ QUICPacketLongHeader::key_phase() const uint16_t QUICPacketLongHeader::size() const { - if (this->type() == QUICPacketType::VERSION_NEGOTIATION) { - return VERSION_NEGOTIATION_PKT_HEADER_LENGTH; - } else { - return LONG_HDR_LENGTH; - } + ink_assert("Is this really needed?"); + return 0; + // if (this->type() == QUICPacketType::VERSION_NEGOTIATION) { + // return VERSION_NEGOTIATION_PKT_HEADER_LENGTH; + // } else { + // return LONG_HDR_LENGTH; + // } } void @@ -275,6 +280,17 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const // // QUICPacketShortHeader // + +QUICPacketShortHeader::QUICPacketShortHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base, uint8_t dcil) + : QUICPacketHeader(from, std::move(buf), len, base), _dcil(dcil) +{ + int n = this->_packet_number_len(); + int offset = SHORT_HDR_OFFSET_CONNECTION_ID; + + QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + offset, n); + QUICPacket::decode_packet_number(this->_packet_number, src, n, this->_base_packet_number); +} + QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len) { @@ -285,7 +301,7 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase k this->_base_packet_number = base_packet_number; this->_packet_number_type = this->_discover_packet_number_type(packet_number, base_packet_number); this->_payload = std::move(buf); - this->_payload_len = len; + this->_payload_length = len; } QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId connection_id, @@ -295,13 +311,12 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase k this->_type = type; this->_has_key_phase = true; this->_key_phase = key_phase; - this->_has_connection_id = true; this->_connection_id = connection_id; this->_packet_number = packet_number; this->_base_packet_number = base_packet_number; this->_packet_number_type = this->_discover_packet_number_type(packet_number, base_packet_number); this->_payload = std::move(buf); - this->_payload_len = len; + this->_payload_length = len; } QUICPacketType @@ -322,10 +337,9 @@ QUICPacketShortHeader::type() const } QUICConnectionId -QUICPacketShortHeader::connection_id() const +QUICPacketShortHeader::destination_cid() const { if (this->_buf) { - ink_release_assert(this->has_connection_id()); return QUICTypeUtil::read_QUICConnectionId(this->_buf.get() + SHORT_HDR_OFFSET_CONNECTION_ID, 8); } else { return _connection_id; @@ -335,21 +349,7 @@ QUICPacketShortHeader::connection_id() const QUICPacketNumber QUICPacketShortHeader::packet_number() const { - if (this->_buf) { - int n = this->_packet_number_len(); - int offset = SHORT_HDR_OFFSET_CONNECTION_ID; - if (this->has_connection_id()) { - offset += 8; - } - - QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + offset, n); - QUICPacketNumber dst = 0; - QUICPacket::decode_packet_number(dst, src, n, this->_base_packet_number); - - return dst; - } else { - return this->_packet_number; - } + return this->_packet_number; } bool @@ -401,16 +401,6 @@ QUICPacketShortHeader::_discover_packet_number_type(QUICPacketNumber packet_numb } } -bool -QUICPacketShortHeader::has_connection_id() const -{ - if (this->_buf) { - return QUICTypeUtil::has_connection_id(this->_buf.get()); - } else { - return this->_has_connection_id; - } -} - const uint8_t * QUICPacketShortHeader::payload() const { @@ -447,14 +437,16 @@ QUICPacketShortHeader::key_phase() const uint16_t QUICPacketShortHeader::size() const { - uint16_t len = 1; - - if (this->has_connection_id()) { - len += 8; - } - len += this->_packet_number_len(); - - return len; + ink_assert("Is this really needed?"); + // uint16_t len = 1; + // + // if (this->has_connection_id()) { + // len += 8; + // } + // len += this->_packet_number_len(); + // + // return len; + return 0; } void @@ -463,19 +455,14 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const size_t n; *len = 0; buf[0] = 0x00; - if (!this->_has_connection_id) { - buf[0] += 0x40; - } if (this->_key_phase == QUICKeyPhase::PHASE_1) { buf[0] += 0x20; } buf[0] += 0x10; buf[0] += static_cast(this->_packet_number_type); *len += 1; - if (this->_has_connection_id) { - QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, buf + *len, &n); - *len += n; - } + QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, buf + *len, &n); + *len += n; QUICPacketNumber dst = 0; size_t dst_len = this->_packet_number_len(); @@ -528,9 +515,9 @@ QUICPacket::type() const } QUICConnectionId -QUICPacket::connection_id() const +QUICPacket::destination_cid() const { - return this->_header->connection_id(); + return this->_header->destination_cid(); } QUICPacketNumber @@ -569,7 +556,7 @@ QUICPacket::size() 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_size(); + size = this->header_size() + this->payload_length(); } return size; } @@ -581,7 +568,7 @@ QUICPacket::header_size() const } uint16_t -QUICPacket::payload_size() const +QUICPacket::payload_length() const { return this->_payload_size; } @@ -596,8 +583,8 @@ void QUICPacket::store(uint8_t *buf, size_t *len) const { memcpy(buf, this->_header->buf(), this->_header->size()); - memcpy(buf + this->_header->size(), this->payload(), this->payload_size()); - *len = this->_header->size() + this->payload_size(); + memcpy(buf + this->_header->size(), this->payload(), this->payload_length()); + *len = this->_header->size() + this->payload_length(); } uint8_t @@ -682,7 +669,7 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP ats_unique_buf plain_txt = ats_unique_malloc(max_plain_txt_len); size_t plain_txt_len = 0; - QUICPacketHeaderUPtr header = QUICPacketHeader::load(from, std::move(buf), len, base_packet_number); + QUICPacketHeaderUPtr header = QUICPacketHeader::load(from, std::move(buf), len, base_packet_number, this->_dcil); if (header->has_version() && !QUICTypeUtil::is_supported_version(header->version())) { if (header->type() == QUICPacketType::VERSION_NEGOTIATION) { @@ -805,7 +792,7 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se } // VN packet dosen't have packet number field and version field is always 0x00000000 - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->connection_id(), + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->destination_cid(), 0x00, 0x00, 0x00, std::move(versions), len); return QUICPacketFactory::_create_unprotected_packet(std::move(header)); diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 52d01783f39..ef72ad48b12 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -62,7 +62,12 @@ class QUICPacketHeader const IpEndpoint &from() const; virtual QUICPacketType type() const = 0; - virtual QUICConnectionId connection_id() const = 0; + + /* + * Returns a connection id + */ + virtual QUICConnectionId destination_cid() const = 0; + virtual QUICPacketNumber packet_number() const = 0; virtual QUICVersion version() const = 0; @@ -101,7 +106,6 @@ class QUICPacketHeader QUICPacketHeaderUPtr clone() const; virtual bool has_key_phase() const = 0; - virtual bool has_connection_id() const = 0; virtual bool has_version() const = 0; /***** STATIC members *****/ @@ -111,7 +115,7 @@ class QUICPacketHeader * * This creates either a QUICPacketShortHeader or a QUICPacketLongHeader. */ - static QUICPacketHeaderUPtr load(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base); + static QUICPacketHeaderUPtr load(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base, uint8_t dcil); /* * Build a QUICPacketHeader @@ -156,9 +160,8 @@ class QUICPacketHeader QUICPacketNumber _packet_number = 0; QUICPacketNumber _base_packet_number = 0; QUICVersion _version = 0; - size_t _payload_len = 0; + size_t _payload_length = 0; bool _has_key_phase = false; - bool _has_connection_id = false; bool _has_version = false; }; @@ -167,23 +170,25 @@ class QUICPacketLongHeader : public QUICPacketHeader public: QUICPacketLongHeader() : QUICPacketHeader(){}; virtual ~QUICPacketLongHeader(){}; - QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base) - : QUICPacketHeader(from, std::move(buf), len, base) - { - } + QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base); QUICPacketLongHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len); QUICPacketType type() const; - QUICConnectionId connection_id() const; + QUICConnectionId destination_cid() const; + QUICConnectionId source_cid() const; QUICPacketNumber packet_number() const; bool has_version() const; QUICVersion version() const; const uint8_t *payload() const; - bool has_connection_id() const; QUICKeyPhase key_phase() const; bool has_key_phase() const; uint16_t size() const; void store(uint8_t *buf, size_t *len) const; +private: + QUICPacketNumber _packet_number; + QUICConnectionId _destination_cid; + QUICConnectionId _source_cid; + uint8_t *_payload_start; }; class QUICPacketShortHeader : public QUICPacketHeader @@ -191,21 +196,18 @@ class QUICPacketShortHeader : public QUICPacketHeader public: QUICPacketShortHeader() : QUICPacketHeader(){}; virtual ~QUICPacketShortHeader(){}; - QUICPacketShortHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base) - : QUICPacketHeader(from, std::move(buf), len, base) - { - } + QUICPacketShortHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base, uint8_t dcil); 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, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len); QUICPacketType type() const; - QUICConnectionId connection_id() const; + QUICConnectionId destination_cid() const; + QUICConnectionId source_cid() const; QUICPacketNumber packet_number() const; bool has_version() const; QUICVersion version() const; const uint8_t *payload() const; - bool has_connection_id() const; QUICKeyPhase key_phase() const; bool has_key_phase() const; uint16_t size() const; @@ -215,6 +217,7 @@ class QUICPacketShortHeader : public QUICPacketHeader QUICPacketShortHeaderType _discover_packet_number_type(QUICPacketNumber packet_number, QUICPacketNumber base_packet_number) const; int _packet_number_len() const; QUICPacketShortHeaderType _packet_number_type = QUICPacketShortHeaderType::UNINITIALIZED; + uint8_t _dcil; }; class QUICPacketHeaderDeleter @@ -271,7 +274,7 @@ class QUICPacket const IpEndpoint &from() const; QUICPacketType type() const; - QUICConnectionId connection_id() const; + QUICConnectionId destination_cid() const; QUICPacketNumber packet_number() const; QUICVersion version() const; const QUICPacketHeader &header() const; @@ -291,9 +294,9 @@ class QUICPacket uint16_t header_size() const; /* - * Size of payload + * Length of payload */ - uint16_t payload_size() const; + uint16_t payload_length() const; void store(uint8_t *buf, size_t *len) const; QUICKeyPhase key_phase() const; @@ -365,11 +368,13 @@ class QUICPacketFactory QUICStatelessResetToken stateless_reset_token); void set_version(QUICVersion negotiated_version); void set_hs_protocol(QUICHandshakeProtocol *hs_protocol); + void set_dcil(uint8_t len); private: QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; QUICHandshakeProtocol *_hs_protocol = nullptr; QUICPacketNumberGenerator _packet_number_generator; + uint8_t _dcil = 0; static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeaderUPtr header); QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable); diff --git a/iocore/net/quic/QUICVersionNegotiator.cc b/iocore/net/quic/QUICVersionNegotiator.cc index 8aff8a9d163..f325fd05fb7 100644 --- a/iocore/net/quic/QUICVersionNegotiator.cc +++ b/iocore/net/quic/QUICVersionNegotiator.cc @@ -44,7 +44,7 @@ QUICVersionNegotiator::negotiate(const QUICPacket *packet) } case QUICPacketType::VERSION_NEGOTIATION: { const uint8_t *supported_versions = packet->payload(); - uint16_t supported_versions_len = packet->payload_size(); + uint16_t supported_versions_len = packet->payload_length(); uint16_t len = 0; while (len < supported_versions_len) { diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 992b03dd674..719e2f97d65 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -918,7 +918,7 @@ TEST_CASE("Load NewConnectionId Frame", "[quic]") std::dynamic_pointer_cast(frame1); CHECK(new_con_id_frame != nullptr); CHECK(new_con_id_frame->sequence() == 0x0102); - CHECK(new_con_id_frame->connection_id() == 0x1122334455667788ULL); + CHECK((new_con_id_frame->connection_id() == QUICConnectionId(reinterpret_cast("\x11\x22\x33\x44\x55\x66\x77\x88"), 8))); CHECK(memcmp(new_con_id_frame->stateless_reset_token().buf(), buf1 + 11, 16) == 0); } @@ -934,7 +934,7 @@ TEST_CASE("Store NewConnectionId Frame", "[quic]") 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Stateless Reset Token 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, }; - QUICNewConnectionIdFrame new_con_id_frame(0x0102, 0x1122334455667788ULL, {expected + 11}); + QUICNewConnectionIdFrame new_con_id_frame(0x0102, { reinterpret_cast("\x11\x22\x33\x44\x55\x66\x77\x88"), 8}, {expected + 11}); CHECK(new_con_id_frame.size() == 27); new_con_id_frame.store(buf, &len); @@ -1123,7 +1123,7 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") { - QUICStream stream(new MockQUICRTTProvider(), 0, 0x1234, 0, 0); + QUICStream stream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), 0x1234, 0, 0); std::unique_ptr error = std::unique_ptr(new QUICStreamError(&stream, static_cast(0x01))); std::unique_ptr rst_stream_frame1 = @@ -1139,7 +1139,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") QUICPacketFactory factory; MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); - QUICPacketUPtr packet = factory.create_server_protected_packet(0x01020304, 0, {nullptr, [](void *p) { ats_free(p); }}, 0, true); + QUICPacketUPtr packet = factory.create_server_protected_packet({reinterpret_cast("\x01\x02\x03\x04"), 4}, 0, {nullptr, [](void *p) { ats_free(p); }}, 0, true); SECTION("STREAM frame") { diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc index 2f5d47fd156..410bb505898 100644 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -38,7 +38,7 @@ TEST_CASE("1-RTT handshake ", "[quic]") SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - QUICConnectionId client_conn_id = 0x12345; + QUICConnectionId client_conn_id = {reinterpret_cast("\x01\x23\x45"), 3}; QUICHandshake *client = new QUICHandshake(client_qc, client_ssl_ctx); @@ -54,7 +54,7 @@ TEST_CASE("1-RTT handshake ", "[quic]") BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - QUICConnectionId conn_id = 0; + QUICConnectionId conn_id = QUICConnectionId::ZERO(); QUICStatelessResetToken server_token; server_token.generate(conn_id, 0); diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 3b51d870a03..a41dd612fd5 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -122,8 +122,8 @@ TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]") SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); - CHECK(client->initialize_key_materials(0x8394c8f03e515700)); - CHECK(server->initialize_key_materials(0x8394c8f03e515700)); + CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); // encrypt - decrypt // client (encrypt) - server (decrypt) @@ -173,8 +173,8 @@ TEST_CASE("QUICHandshakeProtocol 1-RTT", "[quic]") SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); - CHECK(client->initialize_key_materials(0x8394c8f03e515708)); - CHECK(server->initialize_key_materials(0x8394c8f03e515708)); + CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); // Client Hello uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; @@ -269,8 +269,8 @@ TEST_CASE("QUICHandshakeProtocol 1-RTT HRR key_share mismatch", "[quic]") QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); - CHECK(client->initialize_key_materials(0x8394c8f03e515708)); - CHECK(server->initialize_key_materials(0x8394c8f03e515708)); + CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); // Client Hello uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; @@ -384,8 +384,8 @@ TEST_CASE("QUICHandshakeProtocol 1-RTT HRR statless", "[quic]") bool stateless = true; QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN, stateless); - CHECK(client->initialize_key_materials(0x8394c8f03e515708)); - CHECK(server->initialize_key_materials(0x8394c8f03e515708)); + CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); // Client Hello uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; @@ -507,8 +507,8 @@ TEST_CASE("QUICHandshakeProtocol 1-RTT HRR statless & key_share mismatch", "[qui bool stateless = true; QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN, stateless); - CHECK(client->initialize_key_materials(0x8394c8f03e515708)); - CHECK(server->initialize_key_materials(0x8394c8f03e515708)); + CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); // Client Hello uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index fd91b209d2c..bf40970adae 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -56,7 +56,7 @@ TEST_CASE("QUICKeyGenerator", "[quic]") { QUICKeyGenerator keygen(QUICKeyGenerator::Context::CLIENT); - QUICConnectionId cid = 0x8394c8f03e515708; + QUICConnectionId cid = {reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x08"), 8}; uint8_t expected_client_key[] = {0x3a, 0xd0, 0x54, 0x2c, 0x4a, 0x85, 0x84, 0x74, 0x00, 0x63, 0x04, 0x9e, 0x3b, 0x3c, 0xaa, 0xb2}; uint8_t expected_client_iv[] = {0xd1, 0xfd, 0x26, 0x05, 0x42, 0x75, 0x3a, 0xba, 0x38, 0x58, 0x9b, 0xad}; @@ -73,7 +73,7 @@ TEST_CASE("QUICKeyGenerator", "[quic]") { QUICKeyGenerator keygen(QUICKeyGenerator::Context::SERVER); - QUICConnectionId cid = 0x8394c8f03e515708; + QUICConnectionId cid = {reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x08"), 8}; uint8_t expected_server_key[] = {0xbe, 0xe4, 0xc2, 0x4d, 0x2a, 0xf1, 0x33, 0x80, 0xa9, 0xfa, 0x24, 0xa5, 0xe2, 0xba, 0x2c, 0xff}; uint8_t expected_server_iv[] = {0x25, 0xb5, 0x8e, 0x24, 0x6d, 0x9e, 0x7d, 0x5f, 0xfe, 0x43, 0x23, 0xfe}; diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index d898306dc51..41fdfbdc537 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -35,7 +35,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") pf.set_hs_protocol(&hs_protocol); QUICAckFrameCreator *afc = new QUICAckFrameCreator(); - QUICConnectionId connection_id = 1; + QUICConnectionId connection_id = {reinterpret_cast("\x01"), 1}; MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); MockQUICCongestionController *cc = new MockQUICCongestionController(); QUICLossDetector detector(tx, cc); @@ -55,7 +55,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, 0xffddbb9977553311ULL, 0x00000001, 0, + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, {reinterpret_cast("\xff\xdd\xbb\x99\x77\x55\x33\x11"), 8}, 0x00000001, 0, 0x00112233, std::move(payload), sizeof(raw)); QUICPacketUPtr packet = QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true), [](QUICPacket *p) { delete p; }); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 019bb210ed4..f696986c7aa 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -37,12 +37,11 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0x00, 0x00, 0x00, 0x09, // Supported Version 1 }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0, 18); CHECK(header->size() == 13); CHECK(header->packet_size() == 21); CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); - CHECK(header->has_connection_id() == true); - CHECK(header->connection_id() == 0x0102030405060708); + CHECK((header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); CHECK(header->has_version() == true); CHECK(header->version() == 0x00000000); CHECK(header->has_key_phase() == false); @@ -58,12 +57,11 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0xff, 0xff, // Payload (dummy) }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0, 18); CHECK(header->size() == 17); CHECK(header->packet_size() == 19); CHECK(header->type() == QUICPacketType::INITIAL); - CHECK(header->has_connection_id() == true); - CHECK(header->connection_id() == 0x0102030405060708); + CHECK((header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); CHECK(header->packet_number() == 0x12345678); CHECK(header->has_version() == true); CHECK(header->version() == 0x11223344); @@ -86,14 +84,13 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") memcpy(payload.get(), expected + 17, 5); QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::INITIAL, 0x0102030405060708, 0x12345678, 0, 0x11223344, std::move(payload), 32); + QUICPacketHeader::build(QUICPacketType::INITIAL,{reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, 0x12345678, 0, 0x11223344, std::move(payload), 32); CHECK(header->size() == 17); CHECK(header->has_key_phase() == false); CHECK(header->packet_size() == 0); CHECK(header->type() == QUICPacketType::INITIAL); - CHECK(header->has_connection_id() == true); - CHECK(header->connection_id() == 0x0102030405060708); + CHECK((header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); CHECK(header->packet_number() == 0x12345678); CHECK(header->has_version() == true); CHECK(header->version() == 0x11223344); @@ -115,13 +112,12 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") 0xff, 0xff, // Payload (dummy) }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0, 18); CHECK(header->size() == 13); CHECK(header->packet_size() == 15); CHECK(header->has_key_phase() == true); CHECK(header->key_phase() == QUICKeyPhase::PHASE_0); - CHECK(header->has_connection_id() == true); - CHECK(header->connection_id() == 0x0102030405060708); + CHECK((header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); CHECK(header->packet_number() == 0x12345678); CHECK(header->has_version() == false); } @@ -140,15 +136,14 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") ats_unique_buf payload = ats_unique_malloc(5); memcpy(payload.get(), expected + 13, 5); - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, 0x0102030405060708, + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, {reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, 0x12345678, 0, std::move(payload), 32); CHECK(header->size() == 13); CHECK(header->packet_size() == 0); CHECK(header->has_key_phase() == true); CHECK(header->key_phase() == QUICKeyPhase::PHASE_0); CHECK(header->type() == QUICPacketType::PROTECTED); - CHECK(header->has_connection_id() == true); - CHECK(header->connection_id() == 0x0102030405060708); + CHECK((header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); CHECK(header->packet_number() == 0x12345678); CHECK(header->has_version() == false); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index fc9c8954e64..13e0ab93ff7 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -43,13 +43,13 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") }; QUICPacketHeaderUPtr header = - QUICPacketHeader::load({}, {initial_packet_header, [](void *) {}}, sizeof(initial_packet_header), 0); + QUICPacketHeader::load({}, {initial_packet_header, [](void *) {}}, sizeof(initial_packet_header), 0, 8); QUICPacket initial_packet(std::move(header), ats_unique_buf(initial_packet_payload, [](void *) {}), sizeof(initial_packet_payload), 0); QUICPacketUPtr packet = factory.create_version_negotiation_packet(&initial_packet); CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); - CHECK(packet->connection_id() == initial_packet.connection_id()); + CHECK((packet->destination_cid() == initial_packet.destination_cid())); CHECK(packet->packet_number() == initial_packet.packet_number()); CHECK(packet->version() == 0x00); @@ -68,9 +68,9 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketUPtr packet = factory.create_retry_packet(0x01020304, 1234, std::move(payload), sizeof(raw), false); + QUICPacketUPtr packet = factory.create_retry_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), 1234, std::move(payload), sizeof(raw), false); CHECK(packet->type() == QUICPacketType::RETRY); - CHECK(packet->connection_id() == 0x01020304); + CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"),4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); CHECK(packet->packet_number() == 1234); CHECK(packet->version() == 0x11223344); @@ -87,9 +87,9 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketUPtr packet = factory.create_handshake_packet(0x01020304, 0, std::move(payload), sizeof(raw), true); + QUICPacketUPtr packet = factory.create_handshake_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), 0, std::move(payload), sizeof(raw), true); CHECK(packet->type() == QUICPacketType::HANDSHAKE); - CHECK(packet->connection_id() == 0x01020304); + CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); CHECK(packet->packet_number() <= 0xFFFFFBFF); CHECK(packet->version() == 0x11223344); @@ -101,7 +101,7 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); QUICStatelessResetToken token; - token.generate(12345, 67890); + token.generate({reinterpret_cast("\x30\x39"), 2}, 67890); uint8_t expected_output[] = { 0x41, // 0CK0001 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, // Connection ID @@ -112,7 +112,7 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") uint8_t output[1024]; size_t out_len = 0; - QUICPacketUPtr packet = factory.create_stateless_reset_packet(0x01020304, token); + QUICPacketUPtr packet = factory.create_stateless_reset_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), token); CHECK(packet->type() == QUICPacketType::STATELESS_RESET); - CHECK(packet->connection_id() == 0x01020304); + CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); } diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 3dfb2ae7bd6..4e537ecfbb9 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -69,7 +69,7 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), 0, stream_id, 1024, 1024)); + std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id, 1024, 1024)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_1); @@ -94,7 +94,7 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), 0, stream_id, UINT64_MAX, UINT64_MAX)); + std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -119,7 +119,7 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), 0, stream_id, UINT64_MAX, UINT64_MAX)); + std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -148,7 +148,7 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), 0, stream_id)); + std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id)); stream->init_flow_control_params(4096, 4096); stream->do_io_read(nullptr, 0, read_buffer); @@ -184,7 +184,7 @@ TEST_CASE("QUICStream", "[quic]") IOBufferReader *read_buffer_reader = read_buffer->alloc_reader(); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), 0, stream_id)); + std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id)); stream->init_flow_control_params(4096, 4096); MockContinuation mock_cont(stream->mutex); stream->do_io_read(nullptr, 0, read_buffer); diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 796ca26a260..e500db00469 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -34,7 +34,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICRTTProvider(), 0, &app_map, NET_VCONNECTION_IN); + QUICStreamManager sm(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), &app_map, NET_VCONNECTION_IN); std::shared_ptr local_tp = std::make_shared(static_cast(0)); std::shared_ptr remote_tp = @@ -80,7 +80,7 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICRTTProvider(), 0, &app_map, NET_VCONNECTION_IN); + QUICStreamManager sm(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), &app_map, NET_VCONNECTION_IN); std::shared_ptr local_tp = std::make_shared(static_cast(0)); std::shared_ptr remote_tp = @@ -100,7 +100,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICRTTProvider(), 0, &app_map, NET_VCONNECTION_IN); + QUICStreamManager sm(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), &app_map, NET_VCONNECTION_IN); std::shared_ptr local_tp = std::make_shared(static_cast(0)); local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); @@ -133,7 +133,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICRTTProvider(), 0, &app_map, NET_VCONNECTION_IN); + QUICStreamManager sm(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), &app_map, NET_VCONNECTION_IN); std::shared_ptr local_tp = std::make_shared(static_cast(0)); local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); From 0efaaa386e893cf302debe845154ba6cbd7fae56 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 23 Apr 2018 14:44:09 +0900 Subject: [PATCH 0527/1313] Update wire formats and tests --- iocore/net/LuaSNIConfig.h | 1 - iocore/net/P_SNIActionPerformer.h | 1 - iocore/net/quic/Mock.h | 4 - iocore/net/quic/QUICAckFrameCreator.h | 1 - iocore/net/quic/QUICFrame.cc | 23 ++- iocore/net/quic/QUICFrame.h | 7 +- iocore/net/quic/QUICKeyGenerator.cc | 2 +- iocore/net/quic/QUICKeyGenerator.h | 1 - iocore/net/quic/QUICLossDetector.h | 1 - iocore/net/quic/QUICPacket.cc | 131 ++++++++++-------- iocore/net/quic/QUICPacket.h | 42 +++--- iocore/net/quic/QUICTypes.cc | 17 ++- iocore/net/quic/QUICTypes.h | 13 +- .../net/quic/test/test_QUICFlowController.cc | 1 - iocore/net/quic/test/test_QUICFrame.cc | 22 +-- iocore/net/quic/test/test_QUICLossDetector.cc | 6 +- iocore/net/quic/test/test_QUICPacket.cc | 74 ++++++---- .../net/quic/test/test_QUICPacketFactory.cc | 23 +-- iocore/net/quic/test/test_QUICStream.cc | 6 +- .../quic/test/test_QUICVersionNegotiator.cc | 8 +- 20 files changed, 227 insertions(+), 157 deletions(-) diff --git a/iocore/net/LuaSNIConfig.h b/iocore/net/LuaSNIConfig.h index f301a6dcd10..7b38a59b337 100644 --- a/iocore/net/LuaSNIConfig.h +++ b/iocore/net/LuaSNIConfig.h @@ -61,7 +61,6 @@ struct LuaSNIConfig : public TsConfigBase { static TsConfigArrayDescriptor DESCRIPTOR; LuaSNIConfig() : TsConfigBase(this->DESCRIPTOR) { self::Item::Initialize(); } - struct Item : public TsConfigBase { Item() : TsConfigBase(DESCRIPTOR), diff --git a/iocore/net/P_SNIActionPerformer.h b/iocore/net/P_SNIActionPerformer.h index f876a7007fb..41b5aa05468 100644 --- a/iocore/net/P_SNIActionPerformer.h +++ b/iocore/net/P_SNIActionPerformer.h @@ -59,7 +59,6 @@ class DisableH2 : public ActionItem public: DisableH2() {} ~DisableH2() override {} - void SNIAction(Continuation *cont) override { diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index dd12b709caa..3caffedb72d 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -282,7 +282,6 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter { public: MockQUICPacketTransmitter() : QUICPacketTransmitter() { this->_mutex = new_ProxyMutex(); }; - uint32_t transmit_packet(QUICPacketUPtr packet) override { @@ -415,7 +414,6 @@ class MockQUICStreamIO : public QUICStreamIO public: MockQUICStreamIO(QUICApplication *app, QUICStream *stream) : QUICStreamIO(app, stream) {} ~MockQUICStreamIO() {} - int64_t transfer() { @@ -440,7 +438,6 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol { public: MockQUICHandshakeProtocol() : QUICHandshakeProtocol() {} - int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override { @@ -460,7 +457,6 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol }; bool is_key_derived(QUICKeyPhase /* key_phase */) const override { return true; } - int initialize_key_materials(QUICConnectionId cid) override { diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index d474aadd079..5913e8d6378 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -44,7 +44,6 @@ class QUICAckPacketNumbers ink_hrtime largest_ack_received_time(); const QUICPacketNumber &operator[](int i) const { return this->_packet_numbers[i]; } - private: QUICPacketNumber _largest_ack_number = 0; ink_hrtime _largest_ack_received_time = 0; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 36e4974a099..03e0e665541 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1536,7 +1536,7 @@ QUICNewConnectionIdFrame::type() const size_t QUICNewConnectionIdFrame::size() const { - return sizeof(QUICFrameType) + this->_get_sequence_field_length() + sizeof(QUICConnectionId) + 16; + return sizeof(QUICFrameType) + this->_get_sequence_field_length() + 1 + this->_get_connection_id_length() + 16; } void @@ -1552,7 +1552,9 @@ QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len) const ++p; QUICIntUtil::write_QUICVariableInt(this->_sequence, p, &n); p += n; - QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, p, &n); + *p = this->_connection_id.length(); + p += 1; + QUICTypeUtil::write_QUICConnectionId(this->_connection_id, p, &n); p += n; memcpy(p, this->_stateless_reset_token.buf(), QUICStatelessResetToken::LEN); p += QUICStatelessResetToken::LEN; @@ -1575,7 +1577,8 @@ QUICConnectionId QUICNewConnectionIdFrame::connection_id() const { if (this->_buf) { - return QUICTypeUtil::read_QUICConnectionId(this->_buf + this->_get_connection_id_field_offset(), 8); + return QUICTypeUtil::read_QUICConnectionId(this->_buf + this->_get_connection_id_field_offset(), + this->_get_connection_id_length()); } else { return this->_connection_id; } @@ -1585,7 +1588,7 @@ QUICStatelessResetToken QUICNewConnectionIdFrame::stateless_reset_token() const { if (this->_buf) { - return QUICStatelessResetToken(this->_buf + this->_get_connection_id_field_offset() + sizeof(QUICConnectionId)); + return QUICStatelessResetToken(this->_buf + this->_get_connection_id_field_offset() + this->_get_connection_id_length()); } else { return this->_stateless_reset_token; } @@ -1601,10 +1604,20 @@ QUICNewConnectionIdFrame::_get_sequence_field_length() const } } +size_t +QUICNewConnectionIdFrame::_get_connection_id_length() const +{ + if (this->_buf) { + return this->_buf[sizeof(QUICFrameType) + this->_get_sequence_field_length()]; + } else { + return this->_connection_id.length(); + } +} + size_t QUICNewConnectionIdFrame::_get_connection_id_field_offset() const { - return sizeof(QUICFrameType) + this->_get_sequence_field_length(); + return sizeof(QUICFrameType) + this->_get_sequence_field_length() + 1; } // diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 1c0c223b97e..b9462516ba4 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -37,7 +37,6 @@ class QUICFrame QUICFrame(const uint8_t *buf, size_t len, bool protection) : _buf(buf), _len(len), _protection(protection) {} QUICFrame(bool protection) : _protection(protection) {} virtual ~QUICFrame() {} - static QUICFrameType type(const uint8_t *buf); virtual QUICFrameType type() const; @@ -131,7 +130,6 @@ class QUICAckFrame : public QUICFrame public: AckBlock(const uint8_t *b) : _buf(b) {} AckBlock(uint64_t g, uint64_t l) : _gap(g), _length(l) {} - uint64_t gap() const; uint64_t length() const; size_t size() const; @@ -265,7 +263,6 @@ class QUICPingFrame : public QUICFrame QUICPingFrame() : QUICFrame() {} QUICPingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICPingFrame(bool protection) : QUICFrame(protection) {} - virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -467,7 +464,6 @@ class QUICStreamIdBlockedFrame : public QUICFrame QUICStreamIdBlockedFrame() : QUICFrame() {} QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICStreamIdBlockedFrame(QUICStreamId s, bool protection = true) : QUICFrame(protection), _stream_id(s) {} - virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -503,6 +499,7 @@ class QUICNewConnectionIdFrame : public QUICFrame private: size_t _get_sequence_field_length() const; size_t _get_connection_id_field_offset() const; + size_t _get_connection_id_length() const; uint64_t _sequence = 0; QUICConnectionId _connection_id = QUICConnectionId::ZERO(); @@ -546,7 +543,6 @@ class QUICPathChallengeFrame : public QUICFrame QUICPathChallengeFrame() : QUICFrame() {} QUICPathChallengeFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICPathChallengeFrame(ats_unique_buf data, bool protection = true) : QUICFrame(protection), _data(std::move(data)) {} - virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; @@ -570,7 +566,6 @@ class QUICPathResponseFrame : public QUICFrame QUICPathResponseFrame() : QUICFrame() {} QUICPathResponseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICPathResponseFrame(ats_unique_buf data, bool protection = true) : QUICFrame(protection), _data(std::move(data)) {} - virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void store(uint8_t *buf, size_t *len) const override; diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index bd5fb28a725..8dd6b159c0f 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -130,7 +130,7 @@ QUICKeyGenerator::_generate_cleartext_secret(uint8_t *out, size_t *out_len, QUIC uint8_t cleartext_secret[512]; size_t cleartext_secret_len = sizeof(cleartext_secret); - QUICTypeUtil::write_QUICConnectionId(cid, 8, client_connection_id, &cid_len); + QUICTypeUtil::write_QUICConnectionId(cid, client_connection_id, &cid_len); if (hkdf.extract(cleartext_secret, &cleartext_secret_len, QUIC_VERSION_1_SALT, sizeof(QUIC_VERSION_1_SALT), client_connection_id, 8) != 1) { return -1; diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index 7eafded7260..0779a915c74 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -48,7 +48,6 @@ class QUICKeyGenerator enum class Context { SERVER, CLIENT }; QUICKeyGenerator(Context ctx) : _ctx(ctx) {} - /* * Gnerate a key and an IV for Cleartext */ diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 1fef478f1b2..92960888eb8 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -60,7 +60,6 @@ class QUICCongestionController QUICCongestionController(); QUICCongestionController(QUICConnectionId connection_id); virtual ~QUICCongestionController() {} - void on_packet_sent(size_t bytes_sent); void on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size); virtual void on_packets_lost(std::map packets); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index bc97c21668d..0feb7c93146 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -81,11 +81,13 @@ QUICPacketHeader::load(const IpEndpoint from, ats_unique_buf buf, size_t len, QU } QUICPacketHeaderUPtr -QUICPacketHeader::build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len) +QUICPacketHeader::build(QUICPacketType type, QUICConnectionId destination_cid, QUICConnectionId source_cid, + QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, + ats_unique_buf payload, size_t len) { QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); - new (long_header) QUICPacketLongHeader(type, connection_id, packet_number, base_packet_number, version, std::move(payload), len); + new (long_header) + QUICPacketLongHeader(type, destination_cid, source_cid, packet_number, base_packet_number, version, std::move(payload), len); return QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); } @@ -118,45 +120,52 @@ QUICPacketHeader::clone() const // QUICPacketLongHeader // -QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base) : QUICPacketHeader(from, std::move(buf), len, base) +QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base) + : QUICPacketHeader(from, std::move(buf), len, base) { uint8_t *raw_buf = this->_buf.get(); - uint8_t dcil = (raw_buf[1] >> 4); + uint8_t dcil = (raw_buf[5] >> 4); if (dcil) { dcil += 3; } - uint8_t scil = (raw_buf[1] & 0x0F); + uint8_t scil = (raw_buf[5] & 0x0F); if (scil) { scil += 3; } - uint8_t *offset = raw_buf + LONG_HDR_OFFSET_CONNECTION_ID; + uint8_t *offset = raw_buf + LONG_HDR_OFFSET_CONNECTION_ID; this->_destination_cid = {offset, dcil}; offset += dcil; - this->_source_cid = {offset, scil}; + this->_source_cid = {offset, scil}; offset += scil; if (this->type() == QUICPacketType::VERSION_NEGOTIATION) { - this->_payload_start = offset; + this->_payload_start = offset; + this->_payload_length = len - (offset - raw_buf); } else { - this->_payload_length = QUICIntUtil::read_QUICVariableInt(offset); + this->_payload_length = QUICIntUtil::read_QUICVariableInt(offset); offset += QUICVariableInt::size(offset); - QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(offset, 4), 4, this->_base_packet_number); + QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(offset, 4), 4, + this->_base_packet_number); this->_payload_start = offset + 4; } } -QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len) +QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICConnectionId destination_cid, QUICConnectionId source_cid, + QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, + ats_unique_buf buf, size_t len) { this->_type = type; - this->_connection_id = connection_id; + this->_destination_cid = destination_cid; + this->_source_cid = source_cid; this->_packet_number = packet_number; this->_base_packet_number = base_packet_number; this->_has_version = true; this->_version = version; this->_payload = std::move(buf); - this->_payload_length = len; + this->_payload_length = len; + this->_buf_len = LONG_HDR_OFFSET_CONNECTION_ID + this->_destination_cid.length() + this->_source_cid.length() + + QUICVariableInt::size(this->_payload_length) + 4 + len; } QUICPacketType @@ -241,13 +250,7 @@ QUICPacketLongHeader::key_phase() const uint16_t QUICPacketLongHeader::size() const { - ink_assert("Is this really needed?"); - return 0; - // if (this->type() == QUICPacketType::VERSION_NEGOTIATION) { - // return VERSION_NEGOTIATION_PKT_HEADER_LENGTH; - // } else { - // return LONG_HDR_LENGTH; - // } + return this->_buf_len - this->_payload_length; } void @@ -262,10 +265,19 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const } *len += 1; - QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, buf + *len, &n); + QUICTypeUtil::write_QUICVersion(this->_version, buf + *len, &n); *len += n; - QUICTypeUtil::write_QUICVersion(this->_version, buf + *len, &n); + buf[*len] = (this->_destination_cid.length() == 0 ? 0 : this->_destination_cid.length() - 3) << 4; + buf[*len] += this->_source_cid.length() == 0 ? 0 : this->_source_cid.length() - 3; + *len += 1; + + QUICTypeUtil::write_QUICConnectionId(this->_destination_cid, buf + *len, &n); + *len += n; + QUICTypeUtil::write_QUICConnectionId(this->_source_cid, buf + *len, &n); + *len += n; + + QUICIntUtil::write_QUICVariableInt(this->_payload_length, buf + *len, &n); *len += n; if (this->_type != QUICPacketType::VERSION_NEGOTIATION) { @@ -281,12 +293,14 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const // QUICPacketShortHeader // -QUICPacketShortHeader::QUICPacketShortHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base, uint8_t dcil) - : QUICPacketHeader(from, std::move(buf), len, base), _dcil(dcil) +QUICPacketShortHeader::QUICPacketShortHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base, + uint8_t dcil) + : QUICPacketHeader(from, std::move(buf), len, base), _dcil(dcil) { - int n = this->_packet_number_len(); - int offset = SHORT_HDR_OFFSET_CONNECTION_ID; + this->_connection_id = QUICTypeUtil::read_QUICConnectionId(this->_buf.get() + 1, dcil); + int n = this->_packet_number_len(); + int offset = 1 + this->_connection_id.length(); QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + offset, n); QUICPacket::decode_packet_number(this->_packet_number, src, n, this->_base_packet_number); } @@ -340,7 +354,7 @@ QUICConnectionId QUICPacketShortHeader::destination_cid() const { if (this->_buf) { - return QUICTypeUtil::read_QUICConnectionId(this->_buf.get() + SHORT_HDR_OFFSET_CONNECTION_ID, 8); + return QUICTypeUtil::read_QUICConnectionId(this->_buf.get() + SHORT_HDR_OFFSET_CONNECTION_ID, this->_dcil); } else { return _connection_id; } @@ -421,7 +435,7 @@ QUICKeyPhase QUICPacketShortHeader::key_phase() const { if (this->_buf) { - if (this->_buf.get()[0] & 0x20) { + if (this->_buf.get()[0] & 0x40) { return QUICKeyPhase::PHASE_1; } else { return QUICKeyPhase::PHASE_0; @@ -437,16 +451,11 @@ QUICPacketShortHeader::key_phase() const uint16_t QUICPacketShortHeader::size() const { - ink_assert("Is this really needed?"); - // uint16_t len = 1; - // - // if (this->has_connection_id()) { - // len += 8; - // } - // len += this->_packet_number_len(); - // - // return len; - return 0; + uint16_t len = 1; + len += this->_connection_id.length(); + len += this->_packet_number_len(); + + return len; } void @@ -456,12 +465,12 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const *len = 0; buf[0] = 0x00; if (this->_key_phase == QUICKeyPhase::PHASE_1) { - buf[0] += 0x20; + buf[0] += 0x40; } - buf[0] += 0x10; + buf[0] += 0x30; buf[0] += static_cast(this->_packet_number_type); *len += 1; - QUICTypeUtil::write_QUICConnectionId(this->_connection_id, 8, buf + *len, &n); + QUICTypeUtil::write_QUICConnectionId(this->_connection_id, buf + *len, &n); *len += n; QUICPacketNumber dst = 0; @@ -520,6 +529,12 @@ QUICPacket::destination_cid() const return this->_header->destination_cid(); } +QUICConnectionId +QUICPacket::source_cid() const +{ + return this->_header->source_cid(); +} + QUICPacketNumber QUICPacket::packet_number() const { @@ -792,19 +807,20 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se } // VN packet dosen't have packet number field and version field is always 0x00000000 - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->destination_cid(), - 0x00, 0x00, 0x00, std::move(versions), len); + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->source_cid(), + packet_sent_by_client->destination_cid(), 0x00, 0x00, 0x00, std::move(versions), len); return QUICPacketFactory::_create_unprotected_packet(std::move(header)); } QUICPacketUPtr -QUICPacketFactory::create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len) +QUICPacketFactory::create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len) { QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::INITIAL, connection_id, this->_packet_number_generator.next(), base_packet_number, - this->_version, std::move(payload), len); + QUICPacketHeader::build(QUICPacketType::INITIAL, destination_cid, source_cid, this->_packet_number_generator.next(), + base_packet_number, this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), true); } @@ -812,21 +828,22 @@ QUICPacketFactory::create_initial_packet(QUICConnectionId connection_id, QUICPac * Unlike other create_*_packet, the 2nd argument is not base packet number. */ QUICPacketUPtr -QUICPacketFactory::create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, - size_t len, bool retransmittable) +QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, + QUICPacketNumber packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::RETRY, connection_id, packet_number, 0, this->_version, std::move(payload), len); + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, destination_cid, source_cid, packet_number, 0, + this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), retransmittable); } QUICPacketUPtr -QUICPacketFactory::create_handshake_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable) +QUICPacketFactory::create_handshake_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, + bool retransmittable) { QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::HANDSHAKE, connection_id, this->_packet_number_generator.next(), base_packet_number, - this->_version, std::move(payload), len); + QUICPacketHeader::build(QUICPacketType::HANDSHAKE, destination_cid, source_cid, this->_packet_number_generator.next(), + base_packet_number, this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), retransmittable); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index ef72ad48b12..e0627f9e987 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -61,12 +61,13 @@ class QUICPacketHeader const IpEndpoint &from() const; - virtual QUICPacketType type() const = 0; + virtual QUICPacketType type() const = 0; /* * Returns a connection id */ virtual QUICConnectionId destination_cid() const = 0; + virtual QUICConnectionId source_cid() const = 0; virtual QUICPacketNumber packet_number() const = 0; virtual QUICVersion version() const = 0; @@ -105,8 +106,8 @@ class QUICPacketHeader QUICPacketHeaderUPtr clone() const; - virtual bool has_key_phase() const = 0; - virtual bool has_version() const = 0; + virtual bool has_key_phase() const = 0; + virtual bool has_version() const = 0; /***** STATIC members *****/ @@ -115,15 +116,16 @@ class QUICPacketHeader * * This creates either a QUICPacketShortHeader or a QUICPacketLongHeader. */ - static QUICPacketHeaderUPtr load(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base, uint8_t dcil); + static QUICPacketHeaderUPtr load(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base, uint8_t dcil = 0); /* * Build a QUICPacketHeader * * This creates a QUICPacketLongHeader. */ - static QUICPacketHeaderUPtr build(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); + static QUICPacketHeaderUPtr build(QUICPacketType type, QUICConnectionId destination_cid, QUICConnectionId source_cid, + QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, + ats_unique_buf payload, size_t len); /* * Build a QUICPacketHeader @@ -152,7 +154,7 @@ class QUICPacketHeader size_t _buf_len = 0; // These are used only if the instance was created without a buffer - uint8_t _serialized[17]; + uint8_t _serialized[64]; ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); QUICPacketType _type = QUICPacketType::UNINITIALIZED; QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; @@ -171,8 +173,9 @@ class QUICPacketLongHeader : public QUICPacketHeader QUICPacketLongHeader() : QUICPacketHeader(){}; virtual ~QUICPacketLongHeader(){}; QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base); - QUICPacketLongHeader(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len); + QUICPacketLongHeader(QUICPacketType type, QUICConnectionId destination_cid, QUICConnectionId source_cid, + QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, + size_t len); QUICPacketType type() const; QUICConnectionId destination_cid() const; QUICConnectionId source_cid() const; @@ -184,6 +187,7 @@ class QUICPacketLongHeader : public QUICPacketHeader bool has_key_phase() const; uint16_t size() const; void store(uint8_t *buf, size_t *len) const; + private: QUICPacketNumber _packet_number; QUICConnectionId _destination_cid; @@ -203,7 +207,11 @@ class QUICPacketShortHeader : public QUICPacketHeader QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len); QUICPacketType type() const; QUICConnectionId destination_cid() const; - QUICConnectionId source_cid() const; + QUICConnectionId + source_cid() const + { + return QUICConnectionId::ZERO(); + } QUICPacketNumber packet_number() const; bool has_version() const; QUICVersion version() const; @@ -275,6 +283,7 @@ class QUICPacket const IpEndpoint &from() const; QUICPacketType type() const; QUICConnectionId destination_cid() const; + QUICConnectionId source_cid() const; QUICPacketNumber packet_number() const; QUICVersion version() const; const QUICPacketHeader &header() const; @@ -356,12 +365,13 @@ class QUICPacketFactory QUICPacketUPtr create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result); QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client); - QUICPacketUPtr create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, - size_t len); - QUICPacketUPtr create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber packet_number, ats_unique_buf payload, - size_t len, bool retransmittable); - QUICPacketUPtr create_handshake_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable); + QUICPacketUPtr create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len); + QUICPacketUPtr create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber packet_number, + ats_unique_buf payload, size_t len, bool retransmittable); + QUICPacketUPtr create_handshake_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, + bool retransmittable); QUICPacketUPtr create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); static QUICPacketUPtr create_stateless_reset_packet(QUICConnectionId connection_id, diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index eea24f595ea..5fe899f0084 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -107,10 +107,10 @@ QUICTypeUtil::read_QUICMaxData(const uint8_t *buf) } void -QUICTypeUtil::write_QUICConnectionId(QUICConnectionId connection_id, uint8_t n, uint8_t *buf, size_t *len) +QUICTypeUtil::write_QUICConnectionId(QUICConnectionId connection_id, uint8_t *buf, size_t *len) { - memcpy(buf, connection_id, n); - *len = n; + memcpy(buf, connection_id, connection_id.length()); + *len = connection_id.length(); } void @@ -219,7 +219,7 @@ QUICFiveTuple::protocol() const QUICConnectionId QUICConnectionId::ZERO() { - uint8_t zero[] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t zero[18] = {0}; return QUICConnectionId(zero, sizeof(zero)); } @@ -228,11 +228,17 @@ QUICConnectionId::QUICConnectionId() this->randomize(); } -QUICConnectionId::QUICConnectionId(const uint8_t *buf, uint8_t len) +QUICConnectionId::QUICConnectionId(const uint8_t *buf, uint8_t len) : _len(len) { memcpy(this->_id, buf, len); } +uint8_t +QUICConnectionId::length() const +{ + return this->_len; +} + bool QUICConnectionId::is_zero() const { @@ -255,6 +261,7 @@ QUICConnectionId::randomize() } this->_id[i] = (x >> (8 * (i % 4))) & 0xFF; } + this->_len = 18; } uint64_t diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 5593630774d..53493e3a3dc 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -219,11 +219,13 @@ class QUICConnectionId */ operator uint64_t() const { return this->_hashcode(); } operator const uint8_t *() const { return this->_id; } - bool operator==(const QUICConnectionId &x) const { - return memcmp(this->_id, x._id, sizeof(this->_id)) == 0; + if (this->_len != x._len) { + return false; + } + return memcmp(this->_id, x._id, sizeof(this->_len)) == 0; } bool @@ -232,12 +234,14 @@ class QUICConnectionId return memcmp(this->_id, x._id, sizeof(this->_id)) != 0; } + uint8_t length() const; bool is_zero() const; void randomize(); private: uint64_t _hashcode() const; - uint8_t _id[8]; + uint8_t _id[18]; + uint8_t _len = 0; }; class QUICStatelessResetToken @@ -247,7 +251,6 @@ class QUICStatelessResetToken QUICStatelessResetToken() {} QUICStatelessResetToken(const uint8_t *buf) { memcpy(this->_token, buf, QUICStatelessResetToken::LEN); } - void generate(QUICConnectionId conn_id, uint32_t server_id) { @@ -308,7 +311,7 @@ class QUICTypeUtil static QUICAppErrorCode read_QUICAppErrorCode(const uint8_t *buf); static uint64_t read_QUICMaxData(const uint8_t *buf); - static void write_QUICConnectionId(QUICConnectionId connection_id, uint8_t n, uint8_t *buf, size_t *len); + static void write_QUICConnectionId(QUICConnectionId connection_id, uint8_t *buf, size_t *len); static void write_QUICPacketNumber(QUICPacketNumber packet_number, uint8_t n, uint8_t *buf, size_t *len); static void write_QUICVersion(QUICVersion version, uint8_t *buf, size_t *len); static void write_QUICStreamId(QUICStreamId stream_id, uint8_t *buf, size_t *len); diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index 6d7c5936bec..c52b8b202a2 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -39,7 +39,6 @@ class MockRTTProvider : public QUICRTTProvider } MockRTTProvider(ink_hrtime rtt) : _smoothed_rtt(rtt) {} - void set_smoothed_rtt(ink_hrtime rtt) { diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 719e2f97d65..b6d0086a873 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -907,19 +907,21 @@ TEST_CASE("Load NewConnectionId Frame", "[quic]") uint8_t buf1[] = { 0x0b, // Type 0x41, 0x02, // Sequence + 0x08, // Length 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::NEW_CONNECTION_ID); - CHECK(frame1->size() == 27); + CHECK(frame1->size() == 28); std::shared_ptr new_con_id_frame = std::dynamic_pointer_cast(frame1); CHECK(new_con_id_frame != nullptr); CHECK(new_con_id_frame->sequence() == 0x0102); - CHECK((new_con_id_frame->connection_id() == QUICConnectionId(reinterpret_cast("\x11\x22\x33\x44\x55\x66\x77\x88"), 8))); - CHECK(memcmp(new_con_id_frame->stateless_reset_token().buf(), buf1 + 11, 16) == 0); + CHECK((new_con_id_frame->connection_id() == + QUICConnectionId(reinterpret_cast("\x11\x22\x33\x44\x55\x66\x77\x88"), 8))); + CHECK(memcmp(new_con_id_frame->stateless_reset_token().buf(), buf1 + 12, 16) == 0); } TEST_CASE("Store NewConnectionId Frame", "[quic]") @@ -930,15 +932,17 @@ TEST_CASE("Store NewConnectionId Frame", "[quic]") uint8_t expected[] = { 0x0b, // Type 0x41, 0x02, // Sequence + 0x08, // Length 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Stateless Reset Token 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, }; - QUICNewConnectionIdFrame new_con_id_frame(0x0102, { reinterpret_cast("\x11\x22\x33\x44\x55\x66\x77\x88"), 8}, {expected + 11}); - CHECK(new_con_id_frame.size() == 27); + QUICNewConnectionIdFrame new_con_id_frame(0x0102, {reinterpret_cast("\x11\x22\x33\x44\x55\x66\x77\x88"), 8}, + {expected + 12}); + CHECK(new_con_id_frame.size() == 28); new_con_id_frame.store(buf, &len); - CHECK(len == 27); + CHECK(len == 28); CHECK(memcmp(buf, expected, len) == 0); } @@ -1139,7 +1143,8 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") QUICPacketFactory factory; MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); - QUICPacketUPtr packet = factory.create_server_protected_packet({reinterpret_cast("\x01\x02\x03\x04"), 4}, 0, {nullptr, [](void *p) { ats_free(p); }}, 0, true); + QUICPacketUPtr packet = factory.create_server_protected_packet({reinterpret_cast("\x01\x02\x03\x04"), 4}, 0, + {nullptr, [](void *p) { ats_free(p); }}, 0, true); SECTION("STREAM frame") { @@ -1353,6 +1358,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t frame_buf[] = { 0x0b, // Type 0x41, 0x02, // Sequence + 0x08, // Length 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, @@ -1365,7 +1371,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") size_t len; frame->store(buf, &len); - CHECK(len == 27); + CHECK(len == 28); CHECK(memcmp(buf, frame_buf, len) == 0); } diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 41fdfbdc537..ae3dce77734 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -55,8 +55,10 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, {reinterpret_cast("\xff\xdd\xbb\x99\x77\x55\x33\x11"), 8}, 0x00000001, 0, - 0x00112233, std::move(payload), sizeof(raw)); + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::HANDSHAKE, {reinterpret_cast("\xff\xdd\xbb\x99\x77\x55\x33\x11"), 8}, + {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x00000001, 0, 0x00112233, + std::move(payload), sizeof(raw)); QUICPacketUPtr packet = QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true), [](QUICPacket *p) { delete p; }); detector.on_packet_sent(std::move(packet)); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index f696986c7aa..33bb40b0a03 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -31,19 +31,23 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") { const uint8_t input[] = { 0x80, // Long header, Type: NONE - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID - 0x00, 0x00, 0x00, 0x00, // Version + 0x00, 0x00, 0x00, 0x0b, // Version + 0x55, // DCIL/SCIL + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID 0x00, 0x00, 0x00, 0x08, // Supported Version 1 0x00, 0x00, 0x00, 0x09, // Supported Version 1 }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0, 18); - CHECK(header->size() == 13); - CHECK(header->packet_size() == 21); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); + CHECK(header->size() == 22); + CHECK(header->packet_size() == 30); CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); - CHECK((header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); + CHECK( + (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); + CHECK((header->source_cid() == QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8))); CHECK(header->has_version() == true); - CHECK(header->version() == 0x00000000); + CHECK(header->version() == 0x0000000b); CHECK(header->has_key_phase() == false); } @@ -51,17 +55,22 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") { const uint8_t input[] = { 0xFF, // Long header, Type: INITIAL - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID 0x11, 0x22, 0x33, 0x44, // Version + 0x55, // DCIL/SCIL + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID + 0x02, // Payload length 0x12, 0x34, 0x56, 0x78, // Packet number 0xff, 0xff, // Payload (dummy) }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0, 18); - CHECK(header->size() == 17); - CHECK(header->packet_size() == 19); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); + CHECK(header->size() == 27); + CHECK(header->packet_size() == 29); CHECK(header->type() == QUICPacketType::INITIAL); - CHECK((header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); + CHECK( + (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); + CHECK((header->source_cid() == QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8))); CHECK(header->packet_number() == 0x12345678); CHECK(header->has_version() == true); CHECK(header->version() == 0x11223344); @@ -75,28 +84,34 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") const uint8_t expected[] = { 0xFF, // Long header, Type: INITIAL - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID 0x11, 0x22, 0x33, 0x44, // Version + 0x55, // DCIL/SCIL + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID + 0x05, // Payload length 0x12, 0x34, 0x56, 0x78, // Packet number 0x11, 0x22, 0x33, 0x44, 0x55, // Payload (dummy) }; ats_unique_buf payload = ats_unique_malloc(5); memcpy(payload.get(), expected + 17, 5); - QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::INITIAL,{reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, 0x12345678, 0, 0x11223344, std::move(payload), 32); + QUICPacketHeaderUPtr header = QUICPacketHeader::build( + QUICPacketType::INITIAL, {reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, + {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x12345678, 0, 0x11223344, std::move(payload), 5); - CHECK(header->size() == 17); + CHECK(header->size() == 27); CHECK(header->has_key_phase() == false); - CHECK(header->packet_size() == 0); + CHECK(header->packet_size() == 32); CHECK(header->type() == QUICPacketType::INITIAL); - CHECK((header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); + CHECK( + (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); + CHECK((header->source_cid() == QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8))); CHECK(header->packet_number() == 0x12345678); CHECK(header->has_version() == true); CHECK(header->version() == 0x11223344); header->store(buf, &len); - CHECK(len == 17); + CHECK(len == 27); CHECK(memcmp(buf, expected, len) == 0); } } @@ -106,18 +121,19 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") SECTION("Short Header (load)") { const uint8_t input[] = { - 0x12, // Short header with (C=0, K=0, Type=0x2) - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID + 0x32, // Short header with (K=0, Type=0x2) + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x12, 0x34, 0x56, 0x78, // Packet number 0xff, 0xff, // Payload (dummy) }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0, 18); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0, 8); CHECK(header->size() == 13); CHECK(header->packet_size() == 15); CHECK(header->has_key_phase() == true); CHECK(header->key_phase() == QUICKeyPhase::PHASE_0); - CHECK((header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); + CHECK( + (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); CHECK(header->packet_number() == 0x12345678); CHECK(header->has_version() == false); } @@ -128,22 +144,24 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") size_t len = 0; const uint8_t expected[] = { - 0x12, // Short header with (C=0, K=0, Type=0x2) - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection ID + 0x32, // Short header with (C=0, K=0, Type=0x2) + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x12, 0x34, 0x56, 0x78, // Packet number 0x11, 0x22, 0x33, 0x44, 0x55, // Protected Payload }; ats_unique_buf payload = ats_unique_malloc(5); memcpy(payload.get(), expected + 13, 5); - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, {reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, - 0x12345678, 0, std::move(payload), 32); + QUICPacketHeaderUPtr header = QUICPacketHeader::build( + QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, {reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, + 0x12345678, 0, std::move(payload), 32); CHECK(header->size() == 13); CHECK(header->packet_size() == 0); CHECK(header->has_key_phase() == true); CHECK(header->key_phase() == QUICKeyPhase::PHASE_0); CHECK(header->type() == QUICPacketType::PROTECTED); - CHECK((header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); + CHECK( + (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); CHECK(header->packet_number() == 0x12345678); CHECK(header->has_version() == false); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 13e0ab93ff7..1015fa0ba12 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -33,9 +33,11 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") factory.set_hs_protocol(&hs_protocol); uint8_t initial_packet_header[] = { - 0x82, // Type - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Connection id + 0xFF, // Type 0xaa, 0xbb, 0xcc, 0xdd, // Version + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection id + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection id + 0x01, // Payload Length 0x00, 0x00, 0x00, 0x00, // Packet number }; uint8_t initial_packet_payload[] = { @@ -49,8 +51,8 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") QUICPacketUPtr packet = factory.create_version_negotiation_packet(&initial_packet); CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); - CHECK((packet->destination_cid() == initial_packet.destination_cid())); - CHECK(packet->packet_number() == initial_packet.packet_number()); + CHECK((packet->source_cid() == initial_packet.destination_cid())); + CHECK((packet->destination_cid() == initial_packet.source_cid())); CHECK(packet->version() == 0x00); QUICVersion supported_version = QUICTypeUtil::read_QUICVersion(packet->payload()); @@ -68,9 +70,11 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketUPtr packet = factory.create_retry_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), 1234, std::move(payload), sizeof(raw), false); + QUICPacketUPtr packet = factory.create_retry_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), + QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), + 1234, std::move(payload), sizeof(raw), false); CHECK(packet->type() == QUICPacketType::RETRY); - CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"),4))); + CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); CHECK(packet->packet_number() == 1234); CHECK(packet->version() == 0x11223344); @@ -87,7 +91,9 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketUPtr packet = factory.create_handshake_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), 0, std::move(payload), sizeof(raw), true); + QUICPacketUPtr packet = factory.create_handshake_packet( + QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), + QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), 0, std::move(payload), sizeof(raw), true); CHECK(packet->type() == QUICPacketType::HANDSHAKE); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); @@ -112,7 +118,8 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") uint8_t output[1024]; size_t out_len = 0; - QUICPacketUPtr packet = factory.create_stateless_reset_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), token); + QUICPacketUPtr packet = + factory.create_stateless_reset_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), token); CHECK(packet->type() == QUICPacketType::STATELESS_RESET); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); } diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 4e537ecfbb9..b942b0337ef 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -94,7 +94,8 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id, UINT64_MAX, UINT64_MAX)); + std::unique_ptr stream( + new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -119,7 +120,8 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id, UINT64_MAX, UINT64_MAX)); + std::unique_ptr stream( + new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index a318c987a75..07dcdd7ee27 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -40,7 +40,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, ats_unique_malloc(0), 0); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -58,7 +58,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, ats_unique_malloc(0), 0); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -76,7 +76,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, ats_unique_malloc(0), 0); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); @@ -118,7 +118,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, 0, ats_unique_malloc(0), 0); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0); // Server send VN packet based on Initial packet QUICPacketUPtr vn_packet = packet_factory.create_version_negotiation_packet(initial_packet.get()); From 0509f141fe02183ed2e97603902aa35ea834ae85 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 23 Apr 2018 16:31:11 +0900 Subject: [PATCH 0528/1313] Fix bugs around Connection ID --- iocore/net/P_QUICNetVConnection.h | 5 +++- iocore/net/P_QUICPacketHandler.h | 3 +- iocore/net/QUICNetProcessor.cc | 8 ++++-- iocore/net/QUICNetVConnection.cc | 31 +++++++++++++-------- iocore/net/QUICPacketHandler.cc | 22 ++++++++++----- iocore/net/quic/QUICConnection.h | 1 + iocore/net/quic/QUICConnectionTable.cc | 2 +- iocore/net/quic/QUICKeyGenerator.cc | 4 +-- iocore/net/quic/QUICPacket.cc | 38 ++++++++++++++++++++++---- iocore/net/quic/QUICPacket.h | 7 +++-- iocore/net/quic/QUICTypes.h | 1 + 11 files changed, 87 insertions(+), 35 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 964f59c8517..745d7c52709 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -149,7 +149,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub public: QUICNetVConnection() {} - void init(QUICConnectionId original_cid, UDPConnection *, QUICPacketHandler *, QUICConnectionTable *ctable = nullptr); + void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *, QUICPacketHandler *, + QUICConnectionTable *ctable = nullptr); // accept new conn_id int acceptEvent(int event, Event *e); @@ -185,6 +186,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void registerNextProtocolSet(SSLNextProtocolSet *s); // QUICConnection + QUICConnectionId peer_connection_id() override; QUICConnectionId original_connection_id() override; QUICConnectionId connection_id() override; const QUICFiveTuple five_tuple() override; @@ -224,6 +226,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketType _last_received_packet_type = QUICPacketType::UNINITIALIZED; std::random_device _rnd; + QUICConnectionId _peer_quic_connection_id; QUICConnectionId _original_quic_connection_id; QUICConnectionId _quic_connection_id; QUICFiveTuple _five_tuple; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 8ffd36a696e..dd7067d2e53 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -44,7 +44,8 @@ class QUICPacketHandler protected: static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu); - static QUICConnectionId _read_connection_id(IOBufferBlock *block); + static QUICConnectionId _read_destination_connection_id(IOBufferBlock *block); + static QUICConnectionId _read_source_connection_id(IOBufferBlock *block); Event *_collector_event = nullptr; QUICClosedConCollector *_closed_con_collector = nullptr; diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 66c16d83414..1d55a734580 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -139,9 +139,11 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne } // Setup QUICNetVConnection - QUICConnectionId cid; - cid.randomize(); - vc->init(cid, con, packet_handler); + QUICConnectionId scid; + QUICConnectionId dcid; + scid.randomize(); + dcid.randomize(); + vc->init(scid, dcid, con, packet_handler); packet_handler->init(vc); // Connection ID will be changed diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index badea1136db..7fa2f682142 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -66,14 +66,15 @@ ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); // XXX This might be called on ET_UDP thread void -QUICNetVConnection::init(QUICConnectionId original_cid, UDPConnection *udp_con, QUICPacketHandler *packet_handler, - QUICConnectionTable *ctable) +QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *udp_con, + QUICPacketHandler *packet_handler, QUICConnectionTable *ctable) { SET_HANDLER((NetVConnHandler)&QUICNetVConnection::acceptEvent); this->_packet_transmitter_mutex = new_ProxyMutex(); this->_frame_transmitter_mutex = new_ProxyMutex(); 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->_quic_connection_id.randomize(); // PacketHandler for out going connection doesn't have connection table @@ -315,6 +316,12 @@ QUICNetVConnection::connectUp(EThread *t, int fd) return CONNECT_SUCCESS; } +QUICConnectionId +QUICNetVConnection::peer_connection_id() +{ + return this->_peer_quic_connection_id; +} + QUICConnectionId QUICNetVConnection::original_connection_id() { @@ -1320,19 +1327,20 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi switch (type) { case QUICPacketType::INITIAL: ink_assert(this->get_context() == NET_VCONNECTION_OUT); - packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->largest_acked_packet_number(), - std::move(buf), len); + packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->_original_quic_connection_id, + this->largest_acked_packet_number(), std::move(buf), len); this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); break; case QUICPacketType::RETRY: // Echo "_largest_received_packet_number" as packet number. Probably this is the packet number from triggering client packet. - packet = this->_packet_factory.create_retry_packet(this->_quic_connection_id, this->_largest_received_packet_number, - std::move(buf), len, retransmittable); + packet = this->_packet_factory.create_retry_packet(this->_peer_quic_connection_id, this->_quic_connection_id, + this->_largest_received_packet_number, std::move(buf), len, retransmittable); break; case QUICPacketType::HANDSHAKE: - packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), - std::move(buf), len, retransmittable); + packet = + this->_packet_factory.create_handshake_packet(this->_peer_quic_connection_id, this->_quic_connection_id, + this->largest_acked_packet_number(), std::move(buf), len, retransmittable); this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); break; @@ -1346,8 +1354,9 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi packet = this->_packet_factory.create_server_protected_packet( this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); } else { - packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(), - std::move(buf), len, retransmittable); + packet = + this->_packet_factory.create_handshake_packet(this->_peer_quic_connection_id, this->_quic_connection_id, + this->largest_acked_packet_number(), std::move(buf), len, retransmittable); } } break; @@ -1417,7 +1426,7 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) // FIXME This should happen only once IOBufferBlock *block = udp_packet->getIOBlockChain(); if (QUICTypeUtil::has_connection_id(reinterpret_cast(block->buf()))) { - QUICConnectionId cid = QUICPacket::connection_id(reinterpret_cast(block->buf())); + QUICConnectionId cid = QUICPacket::destination_connection_id(reinterpret_cast(block->buf())); if (this->_quic_connection_id != cid) { this->_quic_connection_id = cid; } diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index f6859112398..8954342215f 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -81,10 +81,17 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo } QUICConnectionId -QUICPacketHandler::_read_connection_id(IOBufferBlock *block) +QUICPacketHandler::_read_destination_connection_id(IOBufferBlock *block) { const uint8_t *buf = reinterpret_cast(block->buf()); - return QUICPacket::connection_id(buf); + return QUICPacket::destination_connection_id(buf); +} + +QUICConnectionId +QUICPacketHandler::_read_source_connection_id(IOBufferBlock *block) +{ + const uint8_t *buf = reinterpret_cast(block->buf()); + return QUICPacket::source_connection_id(buf); } // @@ -172,7 +179,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) if (is_debug_tag_set("quic_sec")) { ip_port_text_buffer ipb; if (QUICTypeUtil::has_connection_id(reinterpret_cast(block->buf()))) { - QUICConnectionId cid = this->_read_connection_id(block); + QUICConnectionId cid = this->_read_destination_connection_id(block); Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); } else { @@ -191,7 +198,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) if ((!vc && !QUICTypeUtil::has_long_header(reinterpret_cast(block->buf()))) || (vc && vc->in_closed_queue)) { Connection con; con.setRemote(&udp_packet->from.sa); - QUICConnectionId cid = this->_read_connection_id(block); + QUICConnectionId cid = this->_read_destination_connection_id(block); QUICStatelessResetToken token; { QUICConfig::scoped_config params; @@ -209,9 +216,10 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) eth = eventProcessor.assign_thread(ET_NET); // Create a new NetVConnection - QUICConnectionId original_cid = this->_read_connection_id(block); + QUICConnectionId original_cid = this->_read_destination_connection_id(block); + QUICConnectionId peer_cid = this->_read_source_connection_id(block); vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); - vc->init(original_cid, udp_packet->getConnection(), this, this->_ctable); + vc->init(peer_cid, original_cid, udp_packet->getConnection(), this, this->_ctable); vc->id = net_next_connection_number(); vc->con.move(con); vc->submit_time = Thread::get_hrtime(); @@ -293,7 +301,7 @@ QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet) { IOBufferBlock *block = udp_packet->getIOBlockChain(); - QUICConnectionId cid = this->_read_connection_id(block); + QUICConnectionId cid = this->_read_destination_connection_id(block); ip_port_text_buffer ipb; Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index c4d7b73b607..747fc2d4228 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -36,6 +36,7 @@ class SSLNextProtocolSet; class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler { public: + virtual QUICConnectionId peer_connection_id() = 0; virtual QUICConnectionId original_connection_id() = 0; virtual QUICConnectionId connection_id() = 0; virtual const QUICFiveTuple five_tuple() = 0; diff --git a/iocore/net/quic/QUICConnectionTable.cc b/iocore/net/quic/QUICConnectionTable.cc index 5f860b046fc..8337549adc1 100644 --- a/iocore/net/quic/QUICConnectionTable.cc +++ b/iocore/net/quic/QUICConnectionTable.cc @@ -59,7 +59,7 @@ QUICConnectionTable::lookup(const uint8_t *packet, QUICFiveTuple endpoint) { QUICConnectionId cid; if (QUICTypeUtil::has_connection_id(packet)) { - cid = QUICPacket::connection_id(packet); + cid = QUICPacket::destination_connection_id(packet); } else { // TODO: find cid with five tuples // cid = this->_cids.get(endpoint); diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 8dd6b159c0f..3f30a411bbe 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -125,14 +125,14 @@ int QUICKeyGenerator::_generate_cleartext_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid, const char *label, size_t label_len, size_t length) { - uint8_t client_connection_id[8]; + uint8_t client_connection_id[QUICConnectionId::MAX_LENGTH]; size_t cid_len = 0; uint8_t cleartext_secret[512]; size_t cleartext_secret_len = sizeof(cleartext_secret); QUICTypeUtil::write_QUICConnectionId(cid, client_connection_id, &cid_len); if (hkdf.extract(cleartext_secret, &cleartext_secret_len, QUIC_VERSION_1_SALT, sizeof(QUIC_VERSION_1_SALT), client_connection_id, - 8) != 1) { + cid.length()) != 1) { return -1; } diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 0feb7c93146..77d27180b8c 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -652,21 +652,47 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si } QUICConnectionId -QUICPacket::connection_id(const uint8_t *buf) +QUICPacket::destination_connection_id(const uint8_t *buf) { - constexpr uint8_t cid_offset = 1; - constexpr uint8_t cid_len = 8; + uint8_t cid_offset; + uint8_t cid_len; QUICConnectionId cid; if (QUICTypeUtil::has_long_header(buf)) { - cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); + cid_offset = 6; + cid_len = buf[5] >> 4; + if (cid_len) { + cid_len += 3; + } } else { - ink_assert(QUICTypeUtil::has_connection_id(buf)); - cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); + cid_offset = 1; + // TODO Read CID length from records.config + cid_len = 18; } + cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); return cid; } +QUICConnectionId +QUICPacket::source_connection_id(const uint8_t *buf) +{ + ink_assert(QUICTypeUtil::has_long_header(buf)); + + uint8_t cid_offset = 6; + uint8_t cid_len = 0; + + cid_len = buf[5] >> 4; + if (cid_len) { + cid_len += 3; + } + cid_offset += cid_len; + cid_len = buf[5] & 0x0F; + if (cid_len) { + cid_len += 3; + } + return QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); +} + // // QUICPacketFactory // diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index e0627f9e987..8d72f36511f 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -190,8 +190,8 @@ class QUICPacketLongHeader : public QUICPacketHeader private: QUICPacketNumber _packet_number; - QUICConnectionId _destination_cid; - QUICConnectionId _source_cid; + QUICConnectionId _destination_cid = QUICConnectionId::ZERO(); + QUICConnectionId _source_cid = QUICConnectionId::ZERO(); uint8_t *_payload_start; }; @@ -290,7 +290,8 @@ class QUICPacket const uint8_t *payload() const; bool is_retransmittable() const; - static QUICConnectionId connection_id(const uint8_t *packet); + static QUICConnectionId destination_connection_id(const uint8_t *packet); + static QUICConnectionId source_connection_id(const uint8_t *packet); /* * Size of whole QUIC packet (header + payload + integrity check) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 53493e3a3dc..98e49b32746 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -209,6 +209,7 @@ using QUICStreamErrorUPtr = std::unique_ptr; class QUICConnectionId { public: + static const int MAX_LENGTH = 18; static QUICConnectionId ZERO(); QUICConnectionId(); QUICConnectionId(const uint8_t *buf, uint8_t len); From 912ecb21979ddb585c21cd77ddac9c6b0e90e59d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 24 Apr 2018 15:55:51 +0900 Subject: [PATCH 0529/1313] Update Transport Parameters for draft-11 --- iocore/net/quic/QUICConfig.h | 6 +- iocore/net/quic/QUICDebugNames.cc | 2 - iocore/net/quic/QUICHandshake.cc | 1 - iocore/net/quic/QUICTransportParameters.cc | 61 ++++--------------- iocore/net/quic/QUICTransportParameters.h | 2 +- .../quic/test/test_QUICTransportParameters.cc | 10 +-- 6 files changed, 22 insertions(+), 60 deletions(-) diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 3de36c74eb9..69070c7c5e7 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -81,9 +81,9 @@ class QUICConfigParams : public ConfigInfo uint32_t _vn_exercise_enabled = 0; uint32_t _initial_max_stream_id_bidi_in = 100; - uint32_t _initial_max_stream_id_bidi_out = 101; - uint32_t _initial_max_stream_id_uni_in = 102; - uint32_t _initial_max_stream_id_uni_out = 103; + uint32_t _initial_max_stream_id_bidi_out = 100; + uint32_t _initial_max_stream_id_uni_in = 100; + uint32_t _initial_max_stream_id_uni_out = 100; char *_server_supported_groups = nullptr; char *_client_supported_groups = nullptr; diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 664f034f014..a13e5f24187 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -179,8 +179,6 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) return "INITIAL_MAX_STREAM_ID_BIDI"; case QUICTransportParameterId::IDLE_TIMEOUT: return "IDLE_TIMEOUT"; - case QUICTransportParameterId::OMIT_CONNECTION_ID: - return "OMIT_CONNECTION_ID"; case QUICTransportParameterId::MAX_PACKET_SIZE: return "MAX_PACKET_SIZE"; case QUICTransportParameterId::STATELESS_RESET_TOKEN: diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 540f5ab6871..ef7d8c0f4d1 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -399,7 +399,6 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve // MAYs tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi_in()); tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni_in()); - // this->_local_transport_parameters.add(QUICTransportParameterId::OMIT_CONNECTION_ID, {}); // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); this->_local_transport_parameters = std::unique_ptr(tp); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 9a8182f7b2c..ea168013f7e 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -169,12 +169,6 @@ QUICTransportParameters::_validate_parameters() const } // MAYs - if ((ite = this->_parameters.find(QUICTransportParameterId::OMIT_CONNECTION_ID)) != this->_parameters.end()) { - if (ite->second->len() != 0) { - return -8; - } - } - if ((ite = this->_parameters.find(QUICTransportParameterId::MAX_PACKET_SIZE)) != this->_parameters.end()) { if (ite->second->len() != 2) { return -9; @@ -193,6 +187,19 @@ QUICTransportParameters::_validate_parameters() const } } + // MAYs + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI)) != this->_parameters.end()) { + if (ite->second->len() != 2) { + return -3; + } + } + + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI)) != this->_parameters.end()) { + if (ite->second->len() != 2) { + return -5; + } + } + return 0; } @@ -362,27 +369,6 @@ QUICTransportParametersInClientHello::_validate_parameters() const return -1; } - // MAYs - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI)) != this->_parameters.end()) { - if (ite->second->len() != 4) { - return -2; - } - if (QUICTypeUtil::detect_stream_type(QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != - QUICStreamType::SERVER_BIDI) { - return -3; - } - } - - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI)) != this->_parameters.end()) { - if (ite->second->len() != 4) { - return -4; - } - if (QUICTypeUtil::detect_stream_type(QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != - QUICStreamType::SERVER_UNI) { - return -5; - } - } - return 0; } @@ -476,27 +462,6 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const return -2; } - // MAYs - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI)) != this->_parameters.end()) { - if (ite->second->len() != 4) { - return -3; - } - if (QUICTypeUtil::detect_stream_type(QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != - QUICStreamType::CLIENT_BIDI) { - return -4; - } - } - - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI)) != this->_parameters.end()) { - if (ite->second->len() != 4) { - return -5; - } - if (QUICTypeUtil::detect_stream_type(QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != - QUICStreamType::CLIENT_UNI) { - return -6; - } - } - return 0; } diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 96ff64b7c3d..cf5695789d7 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -38,7 +38,7 @@ class QUICTransportParameterId INITIAL_MAX_DATA, INITIAL_MAX_STREAM_ID_BIDI, IDLE_TIMEOUT, - OMIT_CONNECTION_ID, + X_RESERVED, MAX_PACKET_SIZE, STATELESS_RESET_TOKEN, ACK_DELAY_EXPONENT, diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index 3e26f9387ef..dc793693629 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -31,7 +31,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") { uint8_t buf[] = { 0x05, 0x06, 0x07, 0x08, // initial version - 0x00, 0x1e, // size of parameters + 0x00, 0x1c, // size of parameters 0x00, 0x00, // parameter id 0x00, 0x04, // length of value 0x11, 0x22, 0x33, 0x44, // value @@ -39,8 +39,8 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") 0x00, 0x04, // length of value 0x12, 0x34, 0x56, 0x78, // value 0x00, 0x02, // parameter id - 0x00, 0x04, // length of value - 0x0a, 0x0b, 0x0c, 0x0d, // value + 0x00, 0x02, // length of value + 0x0a, 0x0b, // value 0x00, 0x03, // parameter id 0x00, 0x02, // length of value 0x01, 0x23, // value @@ -62,8 +62,8 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, len); - CHECK(len == 4); - CHECK(memcmp(data, "\x0a\x0b\x0c\x0d", 4) == 0); + CHECK(len == 2); + CHECK(memcmp(data, "\x0a\x0b", 2) == 0); data = params_in_ch.getAsBytes(QUICTransportParameterId::IDLE_TIMEOUT, len); CHECK(len == 2); From 910e021064be3d0559ae0f9f39244b353e4fdd0f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 25 Apr 2018 11:06:59 +0900 Subject: [PATCH 0530/1313] Move vc event logs to verbose debug logs --- iocore/net/quic/QUICHandshake.cc | 11 +++++++---- iocore/net/quic/QUICStream.cc | 17 +++++++++++------ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index ef7d8c0f4d1..69b5b6f816e 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -39,6 +39,9 @@ static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; #define QUICHSDebug(fmt, ...) \ Debug("quic_handshake", "[%" PRIx64 "] " fmt, static_cast(this->_qc->connection_id()), ##__VA_ARGS__) +#define QUICVHSDebug(fmt, ...) \ + Debug("v_quic_handshake", "[%" PRIx64 "] " fmt, static_cast(this->_qc->connection_id()), ##__VA_ARGS__) + #define I_WANNA_DUMP_THIS_BUF(buf, len) \ { \ int i; \ @@ -311,7 +314,7 @@ QUICHandshake::remote_transport_parameters() int QUICHandshake::state_handshake(int event, Event *data) { - QUICHSDebug("%s (%d)", get_vc_event_name(event), event); + QUICVHSDebug("%s (%d)", get_vc_event_name(event), event); QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { @@ -351,8 +354,8 @@ QUICHandshake::state_handshake(int event, Event *data) int QUICHandshake::state_complete(int event, void *data) { - QUICHSDebug("%s (%d)", get_vc_event_name(event), event); - QUICHSDebug("Got an event on complete state. Ignoring it for now."); + QUICVHSDebug("%s (%d)", get_vc_event_name(event), event); + QUICVHSDebug("Got an event on complete state. Ignoring it for now."); return EVENT_DONE; } @@ -440,7 +443,7 @@ QUICHandshake::_do_handshake(size_t &out_len) stream_io->read(in, in_len); if (in_len <= 0) { - QUICHSDebug("No message"); + QUICVHSDebug("No message"); return SSL_ERROR_NONE; } I_WANNA_DUMP_THIS_BUF(in, in_len); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index cd5f4382918..7c9fafb06e1 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -31,6 +31,11 @@ #define QUICStreamDebug(fmt, ...) \ Debug("quic_stream", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) + +#define QUICVStreamDebug(fmt, ...) \ + Debug("v_quic_stream", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ + QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) + #define QUICStreamFCDebug(fmt, ...) \ Debug("quic_flow_ctrl", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) @@ -91,7 +96,7 @@ QUICStream::final_offset() int QUICStream::state_stream_open(int event, void *data) { - QUICStreamDebug("%s (%d)", get_vc_event_name(event), event); + QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); switch (event) { @@ -151,7 +156,7 @@ QUICStream::state_stream_open(int event, void *data) int QUICStream::state_stream_closed(int event, void *data) { - QUICStreamDebug("%s (%d)", get_vc_event_name(event), event); + QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); switch (event) { case VC_EVENT_READ_READY: @@ -250,14 +255,14 @@ void QUICStream::reenable(VIO *vio) { if (vio->op == VIO::READ) { - QUICStreamDebug("read_vio reenabled"); + QUICVStreamDebug("read_vio reenabled"); int64_t len = this->_process_read_vio(); if (len > 0) { this->_signal_read_event(); } } else if (vio->op == VIO::WRITE) { - QUICStreamDebug("write_vio reenabled"); + QUICVStreamDebug("write_vio reenabled"); int64_t len = this->_process_write_vio(); if (len > 0) { @@ -495,7 +500,7 @@ QUICStream::_signal_read_event() this_ethread()->schedule_imm(this->_read_vio._cont, event, &this->_read_vio); } - QUICStreamDebug("%s (%d)", get_vc_event_name(event), event); + QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); } /** @@ -517,7 +522,7 @@ QUICStream::_signal_write_event() this_ethread()->schedule_imm(this->_write_vio._cont, event, &this->_write_vio); } - QUICStreamDebug("%s (%d)", get_vc_event_name(event), event); + QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); } int64_t From 8a04c3b583acf7a3b2c9925f411ffe0bd26c8e8d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 25 Apr 2018 14:45:35 +0900 Subject: [PATCH 0531/1313] Fix unit test build --- iocore/net/quic/Mock.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 3caffedb72d..d1c6f8aba1f 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -151,6 +151,12 @@ class MockQUICConnection : public QUICConnection return {reinterpret_cast("\x00"), 1}; } + QUICConnectionId + peer_connection_id() override + { + return {reinterpret_cast("\x00"), 1}; + } + QUICConnectionId original_connection_id() override { From 2feed67598e11a9b73b182f2abb30721a0a220cb Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 25 Apr 2018 14:46:39 +0900 Subject: [PATCH 0532/1313] Fix storing Version Negotiation Packet and unit tests --- iocore/net/quic/QUICPacket.cc | 16 +++++++--- iocore/net/quic/test/test_QUICPacket.cc | 4 +-- .../net/quic/test/test_QUICPacketFactory.cc | 32 +++++++++++++++---- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 77d27180b8c..74f78e80801 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -164,8 +164,14 @@ QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICConnectionId this->_version = version; this->_payload = std::move(buf); this->_payload_length = len; - this->_buf_len = LONG_HDR_OFFSET_CONNECTION_ID + this->_destination_cid.length() + this->_source_cid.length() + - QUICVariableInt::size(this->_payload_length) + 4 + len; + + if (this->_type == QUICPacketType::VERSION_NEGOTIATION) { + this->_buf_len = + LONG_HDR_OFFSET_CONNECTION_ID + this->_destination_cid.length() + this->_source_cid.length() + this->_payload_length; + } else { + this->_buf_len = LONG_HDR_OFFSET_CONNECTION_ID + this->_destination_cid.length() + this->_source_cid.length() + + QUICVariableInt::size(this->_payload_length) + 4 + this->_payload_length; + } } QUICPacketType @@ -277,10 +283,10 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const QUICTypeUtil::write_QUICConnectionId(this->_source_cid, buf + *len, &n); *len += n; - QUICIntUtil::write_QUICVariableInt(this->_payload_length, buf + *len, &n); - *len += n; - if (this->_type != QUICPacketType::VERSION_NEGOTIATION) { + QUICIntUtil::write_QUICVariableInt(this->_payload_length, buf + *len, &n); + *len += n; + QUICPacketNumber dst = 0; size_t dst_len = 4; QUICPacket::encode_packet_number(dst, this->_packet_number, dst_len); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 33bb40b0a03..713fe52861a 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -31,7 +31,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") { const uint8_t input[] = { 0x80, // Long header, Type: NONE - 0x00, 0x00, 0x00, 0x0b, // Version + 0x00, 0x00, 0x00, 0x00, // Version 0x55, // DCIL/SCIL 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID @@ -47,7 +47,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); CHECK((header->source_cid() == QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8))); CHECK(header->has_version() == true); - CHECK(header->version() == 0x0000000b); + CHECK(header->version() == 0x00000000); CHECK(header->has_key_phase() == false); } diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 1015fa0ba12..533fbd5588c 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -35,8 +35,9 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") uint8_t initial_packet_header[] = { 0xFF, // Type 0xaa, 0xbb, 0xcc, 0xdd, // Version + 0x55, // DCIL/SCIL 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection id - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection id + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection id 0x01, // Payload Length 0x00, 0x00, 0x00, 0x00, // Packet number }; @@ -46,17 +47,34 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {initial_packet_header, [](void *) {}}, sizeof(initial_packet_header), 0, 8); + QUICPacket initial_packet(std::move(header), ats_unique_buf(initial_packet_payload, [](void *) {}), sizeof(initial_packet_payload), 0); - QUICPacketUPtr packet = factory.create_version_negotiation_packet(&initial_packet); - CHECK(packet->type() == QUICPacketType::VERSION_NEGOTIATION); - CHECK((packet->source_cid() == initial_packet.destination_cid())); - CHECK((packet->destination_cid() == initial_packet.source_cid())); - CHECK(packet->version() == 0x00); + QUICPacketUPtr vn_packet = factory.create_version_negotiation_packet(&initial_packet); + CHECK(vn_packet->type() == QUICPacketType::VERSION_NEGOTIATION); + + uint8_t dst_cid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + uint8_t src_cid[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; + CHECK((vn_packet->source_cid() == QUICConnectionId(dst_cid, sizeof(dst_cid)))); + CHECK((vn_packet->destination_cid() == QUICConnectionId(src_cid, sizeof(src_cid)))); + CHECK(vn_packet->version() == 0x00); - QUICVersion supported_version = QUICTypeUtil::read_QUICVersion(packet->payload()); + QUICVersion supported_version = QUICTypeUtil::read_QUICVersion(vn_packet->payload()); CHECK(supported_version == QUIC_SUPPORTED_VERSIONS[0]); + + uint8_t expected[] = { + 0xa7, // Long header, Type: NONE + 0x00, 0x00, 0x00, 0x00, // Version + 0x55, // DCIL/SCIL + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Destination Connection ID + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection ID + 0xff, 0x00, 0x00, 0x0b, // Supported Version + }; + uint8_t buf[1024] = {0}; + size_t buf_len; + vn_packet->store(buf, &buf_len); + CHECK(memcmp(buf, expected, buf_len) == 0); } TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") From 2cbe172c948986408a5b7cf68b21f80839c74834 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 25 Apr 2018 15:53:45 +0900 Subject: [PATCH 0533/1313] Keep payload size under PMTU - overheads --- iocore/net/QUICNetVConnection.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 7fa2f682142..e6b2f5b3d2d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -53,8 +53,11 @@ Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__); \ Error("quic_net [%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) -static constexpr uint32_t MAX_PACKET_OVERHEAD = 17; // Max long header len(17) -static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 15; +static constexpr uint32_t IPV4_HEADER_SIZE = 20; +static constexpr uint32_t IPV6_HEADER_SIZE = 40; +static constexpr uint32_t UDP_HEADER_SIZE = 8; +static constexpr uint32_t MAX_PACKET_OVERHEAD = 54; // Max long header len +static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(20); static constexpr int FRAME_PER_EVENT = 64; @@ -369,9 +372,9 @@ uint32_t QUICNetVConnection::maximum_quic_packet_size() { if (this->options.ip_family == PF_INET6) { - return this->_pmtu - 48; + return this->_pmtu - UDP_HEADER_SIZE - IPV6_HEADER_SIZE; } else { - return this->_pmtu - 28; + return this->_pmtu - UDP_HEADER_SIZE - IPV4_HEADER_SIZE; } } From f4401f04d2c04cd89af01593248eff16e08346cc Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 25 Apr 2018 16:44:44 +0900 Subject: [PATCH 0534/1313] INITIAL_MAX_STREAM_ID_* are 16 bits --- iocore/net/quic/QUICConfig.cc | 8 ++++---- iocore/net/quic/QUICConfig.h | 8 ++++---- iocore/net/quic/QUICStreamManager.cc | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 897002be52e..b6438d5d06c 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -203,25 +203,25 @@ QUICConfigParams::initial_max_stream_data() const return this->_initial_max_stream_data; } -uint32_t +uint16_t QUICConfigParams::initial_max_stream_id_bidi_in() const { return this->_initial_max_stream_id_bidi_in; } -uint32_t +uint16_t QUICConfigParams::initial_max_stream_id_bidi_out() const { return this->_initial_max_stream_id_bidi_out; } -uint32_t +uint16_t QUICConfigParams::initial_max_stream_id_uni_in() const { return this->_initial_max_stream_id_uni_in; } -uint32_t +uint16_t QUICConfigParams::initial_max_stream_id_uni_out() const { return this->_initial_max_stream_id_uni_out; diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 69070c7c5e7..31d69af4f34 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -39,10 +39,10 @@ class QUICConfigParams : public ConfigInfo uint32_t no_activity_timeout_out() const; uint32_t initial_max_data() const; uint32_t initial_max_stream_data() const; - uint32_t initial_max_stream_id_bidi_in() const; - uint32_t initial_max_stream_id_bidi_out() const; - uint32_t initial_max_stream_id_uni_in() const; - uint32_t initial_max_stream_id_uni_out() const; + uint16_t initial_max_stream_id_bidi_in() const; + uint16_t initial_max_stream_id_bidi_out() const; + uint16_t initial_max_stream_id_uni_in() const; + uint16_t initial_max_stream_id_uni_out() const; uint32_t server_id() const; static int connection_table_size(); uint32_t stateless_retry() const; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index f52cf5280c0..95b15025384 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -69,12 +69,12 @@ QUICStreamManager::init_flow_control_params(const std::shared_ptr_local_tp) { - this->_local_maximum_stream_id_bidi = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI); - this->_local_maximum_stream_id_uni = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI); + this->_local_maximum_stream_id_bidi = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI); + this->_local_maximum_stream_id_uni = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI); } if (this->_remote_tp) { - this->_remote_maximum_stream_id_bidi = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI); - this->_remote_maximum_stream_id_uni = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI); + this->_remote_maximum_stream_id_bidi = this->_remote_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI); + this->_remote_maximum_stream_id_uni = this->_remote_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI); } } From 89a5830c6979906819d5a0fdee93201d9ece9cc6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 26 Apr 2018 15:40:56 +0900 Subject: [PATCH 0535/1313] Fix bugs around packet headers --- iocore/net/QUICNetVConnection.cc | 7 ++++--- iocore/net/quic/QUICPacket.cc | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e6b2f5b3d2d..563ca9fa2b4 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1348,14 +1348,14 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi break; case QUICPacketType::PROTECTED: - packet = this->_packet_factory.create_server_protected_packet(this->_quic_connection_id, this->largest_acked_packet_number(), - std::move(buf), len, retransmittable); + packet = this->_packet_factory.create_server_protected_packet( + this->_peer_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); break; default: if (this->get_context() == NET_VCONNECTION_IN) { if (this->_handshake_handler && this->_handshake_handler->is_completed()) { packet = this->_packet_factory.create_server_protected_packet( - this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); + this->_peer_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); } else { packet = this->_packet_factory.create_handshake_packet(this->_peer_quic_connection_id, this->_quic_connection_id, @@ -1465,6 +1465,7 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) break; case QUICPacketCreationResult::SUCCESS: this->_last_received_packet_type = quic_packet->type(); + this->_packet_factory.set_dcil(quic_packet->destination_cid().length()); if (quic_packet->type() == QUICPacketType::VERSION_NEGOTIATION) { QUICConDebug("Dequeue %s size=%u", QUICDebugNames::packet_type(quic_packet->type()), quic_packet->size()); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 74f78e80801..1cd79481f36 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -309,6 +309,7 @@ QUICPacketShortHeader::QUICPacketShortHeader(const IpEndpoint from, ats_unique_b int offset = 1 + this->_connection_id.length(); QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + offset, n); QUICPacket::decode_packet_number(this->_packet_number, src, n, this->_base_packet_number); + this->_payload_length = len - (1 + this->_dcil + this->_packet_number_len()); } QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, @@ -959,6 +960,12 @@ QUICPacketFactory::set_hs_protocol(QUICHandshakeProtocol *hs_protocol) this->_hs_protocol = hs_protocol; } +void +QUICPacketFactory::set_dcil(uint8_t len) +{ + this->_dcil = len; +} + // // QUICPacketNumberGenerator // From adeaf3c131a39ddc29e383cd3d721589a7901fa7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 26 Apr 2018 16:46:52 +0900 Subject: [PATCH 0536/1313] Long header now has payload length and it will be 16 bytes larger when the packet is encrypted --- iocore/net/quic/QUICPacket.cc | 2 +- iocore/net/quic/test/test_QUICPacket.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 1cd79481f36..f8171fc4745 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -284,7 +284,7 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const *len += n; if (this->_type != QUICPacketType::VERSION_NEGOTIATION) { - QUICIntUtil::write_QUICVariableInt(this->_payload_length, buf + *len, &n); + QUICIntUtil::write_QUICVariableInt(this->_payload_length + 16, buf + *len, &n); *len += n; QUICPacketNumber dst = 0; diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 713fe52861a..0d5c8303f29 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -88,7 +88,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0x55, // DCIL/SCIL 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID - 0x05, // Payload length + 0x15, // Payload length (Not 0x05 because it will have 16 bytes of AEAD tag) 0x12, 0x34, 0x56, 0x78, // Packet number 0x11, 0x22, 0x33, 0x44, 0x55, // Payload (dummy) }; From 85fb9f6b44feca16395c77d88d84051c86454835 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 27 Apr 2018 10:33:33 +0900 Subject: [PATCH 0537/1313] Add a configuration for QUIC connection migration quic.max_connection_ids --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICAltConnectionManager.cc | 24 ++++++++++++++++----- iocore/net/quic/QUICAltConnectionManager.h | 4 +++- iocore/net/quic/QUICConfig.cc | 7 ++++++ iocore/net/quic/QUICConfig.h | 2 ++ mgmt/RecordsConfig.cc | 2 ++ 6 files changed, 34 insertions(+), 7 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 563ca9fa2b4..af64ddb9033 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1185,7 +1185,7 @@ QUICNetVConnection::_packetize_frames() } // NEW_CONNECTION_ID - if (this->_alt_con_manager) { + if (this->_alt_con_manager && this->_alt_con_manager->will_generate_frame()) { frame = this->_alt_con_manager->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); while (frame) { diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 13cf4511fa4..a4040e3948a 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -27,18 +27,32 @@ QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable) : _qc(qc), _ctable(ctable) { + QUICConfig::scoped_config params; + + this->_nids = params->max_alt_connection_ids(); + this->_alt_quic_connection_ids = static_cast(ats_malloc(sizeof(AltConnectionInfo) * this->_nids)); this->_update_alt_connection_ids(-1); } +QUICAltConnectionManager::~QUICAltConnectionManager() +{ + ats_free(this->_alt_quic_connection_ids); +} + void QUICAltConnectionManager::_update_alt_connection_ids(int8_t chosen) { + if (this->_nids == 0) { + // Connection migration is disabled + return; + } + if (chosen == -1) { - chosen = countof(this->_alt_quic_connection_ids) - 1; + chosen = (this->_nids - 1) & 0xff; } QUICConfig::scoped_config params; - int n = sizeof(this->_alt_quic_connection_ids); + int n = this->_nids; int current = this->_alt_quic_connection_id_seq_num % n; int delta = chosen - current; int count = (n + delta) % n + 1; @@ -60,7 +74,7 @@ QUICAltConnectionManager::_update_alt_connection_ids(int8_t chosen) bool QUICAltConnectionManager::migrate_to(QUICConnectionId cid, QUICStatelessResetToken &new_reset_token) { - for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { + for (unsigned int i = 0; i < this->_nids; ++i) { AltConnectionInfo &info = this->_alt_quic_connection_ids[i]; if (info.id == cid) { // Migrate connection @@ -76,7 +90,7 @@ QUICAltConnectionManager::migrate_to(QUICConnectionId cid, QUICStatelessResetTok void QUICAltConnectionManager::invalidate_alt_connections() { - for (unsigned int i = 0; i < countof(this->_alt_quic_connection_ids); ++i) { + for (unsigned int i = 0; i < this->_nids; ++i) { this->_ctable.erase(this->_alt_quic_connection_ids[i].id, this->_qc); } } @@ -91,7 +105,7 @@ QUICFrameUPtr QUICAltConnectionManager::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) { QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - int count = countof(this->_alt_quic_connection_ids); + int count = this->_nids; for (int i = 0; i < count; ++i) { if (!this->_alt_quic_connection_ids[i].advertised) { this->_alt_quic_connection_ids[i].advertised = true; diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index f6502aaf7c6..d05db44354e 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -34,6 +34,7 @@ class QUICAltConnectionManager : public QUICFrameGenerator { public: QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable); + ~QUICAltConnectionManager(); bool migrate_to(QUICConnectionId cid, QUICStatelessResetToken &new_reset_token); void invalidate_alt_connections(); @@ -53,7 +54,8 @@ class QUICAltConnectionManager : public QUICFrameGenerator QUICConnection *_qc = nullptr; QUICConnectionTable &_ctable; - AltConnectionInfo _alt_quic_connection_ids[3]; + AltConnectionInfo *_alt_quic_connection_ids; + uint8_t _nids = 0; int8_t _alt_quic_connection_id_seq_num = 0; bool _need_advertise = false; diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index b6438d5d06c..8b759937f6c 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -120,6 +120,7 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data, "proxy.config.quic.initial_max_stream_data"); REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); REC_EstablishStaticConfigInt32(this->_connection_table_size, "proxy.config.quic.connection_table.size"); + REC_EstablishStaticConfigInt32U(this->_max_alt_connection_ids, "proxy.config.quic.max_alt_connection_ids"); REC_EstablishStaticConfigInt32U(this->_stateless_retry, "proxy.config.quic.stateless_retry"); REC_EstablishStaticConfigInt32U(this->_vn_exercise_enabled, "proxy.config.quic.client.vn_exercise_enabled"); @@ -179,6 +180,12 @@ QUICConfigParams::connection_table_size() return _connection_table_size; } +uint32_t +QUICConfigParams::max_alt_connection_ids() const +{ + return this->_max_alt_connection_ids; +} + uint32_t QUICConfigParams::stateless_retry() const { diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 31d69af4f34..d6e17905435 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -45,6 +45,7 @@ class QUICConfigParams : public ConfigInfo uint16_t initial_max_stream_id_uni_out() const; uint32_t server_id() const; static int connection_table_size(); + uint32_t max_alt_connection_ids() const; uint32_t stateless_retry() const; uint32_t vn_exercise_enabled() const; @@ -77,6 +78,7 @@ class QUICConfigParams : public ConfigInfo uint32_t _initial_max_data = 0; uint32_t _initial_max_stream_data = 0; uint32_t _server_id = 0; + uint32_t _max_alt_connection_ids = 0; uint32_t _stateless_retry = 0; uint32_t _vn_exercise_enabled = 0; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index dd8b20c10fb..5d508dd505e 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1332,6 +1332,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.connection_table.size", RECD_INT, "65521", RECU_RESTART_TS, RR_NULL, RECC_INT, "[1-536870909]", RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.max_alt_connection_ids", RECD_INT, "3", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-5]", RECA_NULL} + , {RECT_CONFIG, "proxy.config.quic.stateless_retry", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.client.vn_exercise_enabled", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} From 7770308bad1314cb6b49a5f137ee729d5dc89162 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 14 May 2018 10:30:25 +0900 Subject: [PATCH 0538/1313] clang-format --- iocore/net/quic/QUICAckFrameCreator.h | 1 + iocore/net/quic/QUICAltConnectionManager.cc | 2 +- iocore/net/quic/QUICAltConnectionManager.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 5913e8d6378..d474aadd079 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -44,6 +44,7 @@ class QUICAckPacketNumbers ink_hrtime largest_ack_received_time(); const QUICPacketNumber &operator[](int i) const { return this->_packet_numbers[i]; } + private: QUICPacketNumber _largest_ack_number = 0; ink_hrtime _largest_ack_received_time = 0; diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index a4040e3948a..3b1ce232021 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -29,7 +29,7 @@ QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConne { QUICConfig::scoped_config params; - this->_nids = params->max_alt_connection_ids(); + this->_nids = params->max_alt_connection_ids(); this->_alt_quic_connection_ids = static_cast(ats_malloc(sizeof(AltConnectionInfo) * this->_nids)); this->_update_alt_connection_ids(-1); } diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index d05db44354e..28637947822 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -55,7 +55,7 @@ class QUICAltConnectionManager : public QUICFrameGenerator QUICConnection *_qc = nullptr; QUICConnectionTable &_ctable; AltConnectionInfo *_alt_quic_connection_ids; - uint8_t _nids = 0; + uint8_t _nids = 0; int8_t _alt_quic_connection_id_seq_num = 0; bool _need_advertise = false; From 2cb99d218a84453a488a02c9f7406a4d87d1523c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 14 May 2018 14:07:48 +0900 Subject: [PATCH 0539/1313] Fix a heap-use-after-free --- iocore/net/QUICNetVConnection.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index af64ddb9033..2557e257e31 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1445,10 +1445,11 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) written += b->read_avail(); b = b->next.get(); } - udp_packet->free(); quic_packet = this->_packet_factory.create(udp_packet->from, std::move(pkt), written, this->largest_received_packet_number(), result); + udp_packet->free(); + switch (result) { case QUICPacketCreationResult::NOT_READY: QUICConDebug("Not ready to decrypt the packet"); From b64517ca7a70dbb53413975851b8e957f7a14bf1 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 15 May 2018 08:35:39 +0800 Subject: [PATCH 0540/1313] Fix assertion in quic_client --- cmd/traffic_quic/quic_client.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc index 5710b789dcf..a39d160adb1 100644 --- a/cmd/traffic_quic/quic_client.cc +++ b/cmd/traffic_quic/quic_client.cc @@ -135,7 +135,7 @@ QUICClientApp::start(const char *path) if (error->cls != QUICErrorClass::NONE) { Error("%s", error->msg); - ink_assert(abort); + ink_assert(!error->msg); } // TODO: move to transaction From 7e738b00efd8e3ac73cd87a6461c2560c237d681 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 May 2018 16:38:04 +0900 Subject: [PATCH 0541/1313] Fix a compile issue --- iocore/net/quic/test/test_QUICKeyGenerator.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index bf40970adae..71123908f1e 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -24,6 +24,7 @@ #include "catch.hpp" #include +#include #ifdef OPENSSL_IS_BORINGSSL #include From 7cb18b38d88fd6af13eed65867701117cbc890ae Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 May 2018 16:40:57 +0900 Subject: [PATCH 0542/1313] Capsulate how to read QUIC packets from UDP packets To prepare for coalescing packets --- iocore/net/P_QUICNetVConnection.h | 6 +-- iocore/net/QUICNetVConnection.cc | 64 ++++++----------------- iocore/net/quic/Makefile.am | 1 + iocore/net/quic/Mock.h | 6 --- iocore/net/quic/QUICConnection.h | 1 - iocore/net/quic/QUICPacketReceiveQueue.cc | 61 +++++++++++++++++++++ iocore/net/quic/QUICPacketReceiveQueue.h | 46 ++++++++++++++++ 7 files changed, 126 insertions(+), 59 deletions(-) create mode 100644 iocore/net/quic/QUICPacketReceiveQueue.cc create mode 100644 iocore/net/quic/QUICPacketReceiveQueue.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 745d7c52709..a327772e18e 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -59,6 +59,7 @@ #include "quic/QUICAltConnectionManager.h" #include "quic/QUICPathValidator.h" #include "quic/QUICApplicationMap.h" +#include "quic/QUICPacketReceiveQueue.h" // These are included here because older OpenQUIC libraries don't have them. // Don't copy these defines, or use their values directly, they are merely @@ -197,7 +198,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub NetVConnectionContext_t direction() override; SSLNextProtocolSet *next_protocol_set() override; void close(QUICConnectionErrorUPtr error) override; - QUICPacketNumber largest_received_packet_number() override; QUICPacketNumber largest_acked_packet_number() override; void handle_received_packet(UDPPacket *packet) override; bool is_closed() override; @@ -231,7 +231,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICConnectionId _quic_connection_id; QUICFiveTuple _five_tuple; - QUICPacketNumber _largest_received_packet_number = 0; UDPConnection *_udp_con = nullptr; QUICPacketHandler *_packet_handler = nullptr; QUICPacketFactory _packet_factory; @@ -258,9 +257,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICAltConnectionManager *_alt_con_manager = nullptr; QUICPathValidator *_path_validator = nullptr; - CountQueue _packet_recv_queue; + QUICPacketReceiveQueue _packet_recv_queue = {this->_packet_factory}; CountQueue _packet_send_queue; - std::queue _quic_packet_recv_queue; QUICConnectionErrorUPtr _connection_error = nullptr; uint32_t _state_closing_recv_packet_count = 0; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2557e257e31..a924e746971 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -788,12 +788,6 @@ QUICNetVConnection::next_protocol_set() return this->_next_protocol_set; } -QUICPacketNumber -QUICNetVConnection::largest_received_packet_number() -{ - return this->_largest_received_packet_number; -} - QUICPacketNumber QUICNetVConnection::largest_acked_packet_number() { @@ -885,7 +879,7 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) QUICErrorUPtr error = this->_recv_and_ack(std::move(packet)); // Packet number of RETRY packet is echo of INITIAL packet - this->_largest_received_packet_number = 0; + this->_packet_recv_queue.reset(); this->_stream_manager->reset_recv_offset(); // Generate new Connection ID @@ -982,7 +976,7 @@ QUICNetVConnection::_state_common_receive_packet() QUICErrorUPtr QUICNetVConnection::_state_closing_receive_packet() { - while (this->_packet_recv_queue.size > 0) { + while (this->_packet_recv_queue.size() > 0) { QUICPacketCreationResult result; QUICPacketUPtr packet = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::SUCCESS) { @@ -1006,7 +1000,7 @@ QUICNetVConnection::_state_closing_receive_packet() QUICErrorUPtr QUICNetVConnection::_state_draining_receive_packet() { - while (this->_packet_recv_queue.size > 0) { + while (this->_packet_recv_queue.size() > 0) { QUICPacketCreationResult result; QUICPacketUPtr packet = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::SUCCESS) { @@ -1277,10 +1271,6 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) uint16_t size = packet->payload_length(); QUICPacketNumber packet_num = packet->packet_number(); - if (packet_num > this->_largest_received_packet_number) { - this->_largest_received_packet_number = packet_num; - } - bool should_send_ack; QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); @@ -1338,7 +1328,7 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi case QUICPacketType::RETRY: // Echo "_largest_received_packet_number" as packet number. Probably this is the packet number from triggering client packet. packet = this->_packet_factory.create_retry_packet(this->_peer_quic_connection_id, this->_quic_connection_id, - this->_largest_received_packet_number, std::move(buf), len, retransmittable); + this->_packet_recv_queue.largest_received_packet_number(), std::move(buf), len, retransmittable); break; case QUICPacketType::HANDSHAKE: packet = @@ -1417,46 +1407,28 @@ QUICNetVConnection::_handle_error(QUICErrorUPtr error) QUICPacketUPtr QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) { - QUICPacketUPtr quic_packet = QUICPacketFactory::create_null_packet(); - UDPPacket *udp_packet = this->_packet_recv_queue.dequeue(); - if (!udp_packet) { - result = QUICPacketCreationResult::NOT_READY; - return quic_packet; - } + QUICPacketUPtr packet = this->_packet_recv_queue.dequeue(result); if (this->direction() == NET_VCONNECTION_OUT) { // Reset CID if a server sent back a new CID // FIXME This should happen only once - IOBufferBlock *block = udp_packet->getIOBlockChain(); - if (QUICTypeUtil::has_connection_id(reinterpret_cast(block->buf()))) { - QUICConnectionId cid = QUICPacket::destination_connection_id(reinterpret_cast(block->buf())); + QUICConnectionId cid = packet->destination_cid(); + if (cid.length()) { if (this->_quic_connection_id != cid) { this->_quic_connection_id = cid; } } } - // Create a QUIC packet - ats_unique_buf pkt = ats_unique_malloc(udp_packet->getPktLength()); - IOBufferBlock *b = udp_packet->getIOBlockChain(); - size_t written = 0; - while (b) { - memcpy(pkt.get() + written, b->buf(), b->read_avail()); - written += b->read_avail(); - b = b->next.get(); + if (result == QUICPacketCreationResult::SUCCESS) { + this->_last_received_packet_type = packet->type(); + this->_packet_factory.set_dcil(packet->destination_cid().length()); } - quic_packet = - this->_packet_factory.create(udp_packet->from, std::move(pkt), written, this->largest_received_packet_number(), result); - udp_packet->free(); - + // Debug prints switch (result) { case QUICPacketCreationResult::NOT_READY: QUICConDebug("Not ready to decrypt the packet"); - // FIXME: unordered packet should be buffered and retried - if (this->_packet_recv_queue.size > 0) { - result = QUICPacketCreationResult::IGNORED; - } break; case QUICPacketCreationResult::IGNORED: QUICConDebug("Ignored"); @@ -1465,23 +1437,19 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) QUICConDebug("Unsupported version"); break; case QUICPacketCreationResult::SUCCESS: - this->_last_received_packet_type = quic_packet->type(); - this->_packet_factory.set_dcil(quic_packet->destination_cid().length()); - - if (quic_packet->type() == QUICPacketType::VERSION_NEGOTIATION) { - QUICConDebug("Dequeue %s size=%u", QUICDebugNames::packet_type(quic_packet->type()), quic_packet->size()); + if (packet->type() == QUICPacketType::VERSION_NEGOTIATION) { + QUICConDebug("Dequeue %s size=%u", QUICDebugNames::packet_type(packet->type()), packet->size()); } else { - QUICConDebug("Dequeue %s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), - quic_packet->packet_number(), quic_packet->size()); + QUICConDebug("Dequeue %s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(packet->type()), + packet->packet_number(), packet->size()); } - break; default: QUICConDebug("Failed to decrypt the packet"); break; } - return quic_packet; + return packet; } void diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 6b8da87ee56..d9787f5aec0 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -74,6 +74,7 @@ libquic_a_SOURCES = \ QUICApplication.cc \ QUICApplicationMap.cc \ QUICIncomingFrameBuffer.cc \ + QUICPacketReceiveQueue.cc \ QUICPacketRetransmitter.cc \ QUICPathValidator.cc \ QUICStatelessRetry.cc diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index d1c6f8aba1f..839bcfe5ccd 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -221,12 +221,6 @@ class MockQUICConnection : public QUICConnection return 1280; } - QUICPacketNumber - largest_received_packet_number() override - { - return 0; - } - QUICPacketNumber largest_acked_packet_number() override { diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 747fc2d4228..83c83a8ce9c 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -62,7 +62,6 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler virtual NetVConnectionContext_t direction() = 0; virtual SSLNextProtocolSet *next_protocol_set() = 0; virtual void close(QUICConnectionErrorUPtr error) = 0; - virtual QUICPacketNumber largest_received_packet_number() = 0; virtual QUICPacketNumber largest_acked_packet_number() = 0; virtual void handle_received_packet(UDPPacket *packeet) = 0; virtual bool is_closed() = 0; diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc new file mode 100644 index 00000000000..640dcaa03cf --- /dev/null +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -0,0 +1,61 @@ +#include "QUICPacketReceiveQueue.h" + +QUICPacketReceiveQueue::QUICPacketReceiveQueue(QUICPacketFactory &packet_factory) : _packet_factory(packet_factory) {} + +void +QUICPacketReceiveQueue::enqueue(UDPPacket *packet) +{ + this->_queue.enqueue(packet); +} + +QUICPacketUPtr +QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) +{ + QUICPacketUPtr quic_packet = QUICPacketFactory::create_null_packet(); + UDPPacket *udp_packet = this->_queue.dequeue(); + if (!udp_packet) { + result = QUICPacketCreationResult::NOT_READY; + return quic_packet; + } + + // Create a QUIC packet + ats_unique_buf pkt = ats_unique_malloc(udp_packet->getPktLength()); + IOBufferBlock *b = udp_packet->getIOBlockChain(); + size_t written = 0; + while (b) { + memcpy(pkt.get() + written, b->buf(), b->read_avail()); + written += b->read_avail(); + b = b->next.get(); + } + + quic_packet = + this->_packet_factory.create(udp_packet->from, std::move(pkt), written, this->largest_received_packet_number(), result); + udp_packet->free(); + + if (result == QUICPacketCreationResult::NOT_READY) { + // FIXME: unordered packet should be buffered and retried + if (this->_queue.size > 0) { + result = QUICPacketCreationResult::IGNORED; + } + } + + return quic_packet; +} + +uint32_t +QUICPacketReceiveQueue::size() +{ + return this->_queue.size; +} + +QUICPacketNumber +QUICPacketReceiveQueue::largest_received_packet_number() +{ + return this->_largest_received_packet_number; +} + +void +QUICPacketReceiveQueue::reset() +{ + this->_largest_received_packet_number = 0; +} diff --git a/iocore/net/quic/QUICPacketReceiveQueue.h b/iocore/net/quic/QUICPacketReceiveQueue.h new file mode 100644 index 00000000000..a711bbdae46 --- /dev/null +++ b/iocore/net/quic/QUICPacketReceiveQueue.h @@ -0,0 +1,46 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "I_UDPPacket.h" +#include "ts/List.h" + +#include "QUICPacket.h" + +class QUICPacketReceiveQueue +{ +public: + QUICPacketReceiveQueue(QUICPacketFactory &packet_factory); + + void enqueue(UDPPacket *packet); + QUICPacketUPtr dequeue(QUICPacketCreationResult &result); + uint32_t size(); + QUICPacketNumber largest_received_packet_number(); + void reset(); + +private: + CountQueue _queue; + QUICPacketFactory &_packet_factory; + QUICPacketNumber _largest_received_packet_number = 0; +}; From 041f420e53290181e841fbbb61e09610d8f40c44 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 16 May 2018 17:35:13 +0900 Subject: [PATCH 0543/1313] Print lower 64 bits of source CID at maximum --- iocore/net/P_QUICNetVConnection.h | 4 +- iocore/net/QUICNetVConnection.cc | 49 +++++++++------------ iocore/net/QUICPacketHandler.cc | 14 +++--- iocore/net/quic/QUICApplication.cc | 2 +- iocore/net/quic/QUICCongestionController.cc | 24 +++++----- iocore/net/quic/QUICConnection.h | 14 +++--- iocore/net/quic/QUICHandshake.cc | 6 +-- iocore/net/quic/QUICLossDetector.cc | 3 +- iocore/net/quic/QUICStream.cc | 12 ++--- iocore/net/quic/QUICTypes.cc | 14 ++++++ iocore/net/quic/QUICTypes.h | 5 +++ 11 files changed, 78 insertions(+), 69 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index a327772e18e..c64e072e0e6 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -231,8 +231,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICConnectionId _quic_connection_id; QUICFiveTuple _five_tuple; - UDPConnection *_udp_con = nullptr; - QUICPacketHandler *_packet_handler = nullptr; + UDPConnection *_udp_con = nullptr; + QUICPacketHandler *_packet_handler = nullptr; QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; QUICAckFrameCreator _ack_frame_creator; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a924e746971..d0f6bef5258 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -43,15 +43,13 @@ #define STATE_FROM_VIO(_x) ((NetState *)(((char *)(_x)) - STATE_VIO_OFFSET)) #define STATE_VIO_OFFSET ((uintptr_t) & ((NetState *)0)->vio) -#define QUICConDebug(fmt, ...) \ - Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) +#define QUICConDebug(fmt, ...) Debug("quic_net", "[%" PRIx64 "] " fmt, this->_peer_quic_connection_id.l64(), ##__VA_ARGS__) -#define QUICConVDebug(fmt, ...) \ - Debug("v_quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) +#define QUICConVDebug(fmt, ...) Debug("v_quic_net", "[%" PRIx64 "] " fmt, this->_peer_quic_connection_id.l64(), ##__VA_ARGS__) -#define QUICError(fmt, ...) \ - Debug("quic_net", "[%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__); \ - Error("quic_net [%" PRIx64 "] " fmt, static_cast(this->_quic_connection_id), ##__VA_ARGS__) +#define QUICError(fmt, ...) \ + Debug("quic_net", "[%" PRIx64 "] " fmt, this->_peer_quic_connection_id.l64(), ##__VA_ARGS__); \ + Error("quic_net [%" PRIx64 "] " fmt, this->_peer_quic_connection_id.l64(), ##__VA_ARGS__) static constexpr uint32_t IPV4_HEADER_SIZE = 20; static constexpr uint32_t IPV6_HEADER_SIZE = 40; @@ -87,8 +85,8 @@ QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_ci this->_ctable->insert(this->_original_quic_connection_id, this); } - QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(this->_original_quic_connection_id), - static_cast(this->_quic_connection_id)); + QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, this->_original_quic_connection_id.l64(), + this->_quic_connection_id.l64()); } bool @@ -203,13 +201,13 @@ QUICNetVConnection::start() this->_packet_factory.set_hs_protocol(this->_hs_protocol); // Create frame handlers - this->_congestion_controller = new QUICCongestionController(this->connection_id()); + this->_congestion_controller = new QUICCongestionController(this->peer_connection_id()); this->_loss_detector = new QUICLossDetector(this, this->_congestion_controller); this->_remote_flow_controller = new QUICRemoteConnectionFlowController(UINT64_MAX); this->_local_flow_controller = new QUICLocalConnectionFlowController(this->_loss_detector, UINT64_MAX); this->_path_validator = new QUICPathValidator(); this->_stream_manager = - new QUICStreamManager(this->_loss_detector, this->connection_id(), this->_application_map, this->netvc_context); + new QUICStreamManager(this->_loss_detector, this->peer_connection_id(), this->_application_map, this->netvc_context); this->_frame_dispatcher->add_handler(this); this->_frame_dispatcher->add_handler(this->_stream_manager); @@ -455,9 +453,8 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) switch (frame->type()) { case QUICFrameType::MAX_DATA: this->_remote_flow_controller->forward_limit(std::static_pointer_cast(frame)->maximum_data()); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, - static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, this->_peer_quic_connection_id.l64(), + this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); this->_schedule_packet_write_ready(); break; @@ -885,8 +882,7 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) // Generate new Connection ID QUICConnectionId tmp = this->_original_quic_connection_id; this->_original_quic_connection_id.randomize(); - QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, static_cast(tmp), - static_cast(this->_original_quic_connection_id)); + QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, tmp.l64(), this->_original_quic_connection_id.l64()); this->_hs_protocol->initialize_key_materials(this->_original_quic_connection_id); @@ -1212,9 +1208,8 @@ QUICNetVConnection::_packetize_frames() ++frame_count; if (frame->type() == QUICFrameType::STREAM) { int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, - static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, this->_peer_quic_connection_id.l64(), + this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); ink_assert(ret == 0); } this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); @@ -1285,7 +1280,7 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) } int ret = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, this->_peer_quic_connection_id.l64(), this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); if (ret != 0) { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); @@ -1328,7 +1323,8 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi case QUICPacketType::RETRY: // Echo "_largest_received_packet_number" as packet number. Probably this is the packet number from triggering client packet. packet = this->_packet_factory.create_retry_packet(this->_peer_quic_connection_id, this->_quic_connection_id, - this->_packet_recv_queue.largest_received_packet_number(), std::move(buf), len, retransmittable); + this->_packet_recv_queue.largest_received_packet_number(), std::move(buf), + len, retransmittable); break; case QUICPacketType::HANDSHAKE: packet = @@ -1375,11 +1371,10 @@ QUICNetVConnection::_init_flow_control_params(const std::shared_ptr_local_flow_controller->set_limit(local_initial_max_data); this->_remote_flow_controller->set_limit(remote_initial_max_data); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, static_cast(this->_quic_connection_id), + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, this->_peer_quic_connection_id.l64(), this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, - static_cast(this->_quic_connection_id), this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); + Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, this->_peer_quic_connection_id.l64(), + this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); } void @@ -1440,8 +1435,8 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) if (packet->type() == QUICPacketType::VERSION_NEGOTIATION) { QUICConDebug("Dequeue %s size=%u", QUICDebugNames::packet_type(packet->type()), packet->size()); } else { - QUICConDebug("Dequeue %s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(packet->type()), - packet->packet_number(), packet->size()); + QUICConDebug("Dequeue %s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), + packet->size()); } break; default: diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 8954342215f..17241a8c4c5 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -74,7 +74,7 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo // NOTE: p will be enqueued to udpOutQueue of UDPNetHandler ip_port_text_buffer ipb; - Debug("quic_sec", "[%" PRIx64 "] send %s packet to %s, size=%" PRId64, static_cast(packet.destination_cid()), + Debug("quic_sec", "[%" PRIx64 "] send %s packet to %s, size=%" PRId64, packet.destination_cid().l64(), QUICDebugNames::packet_type(packet.type()), ats_ip_nptop(&udp_packet->to.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); udp_con->send(c, udp_packet); @@ -178,13 +178,13 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) if (is_debug_tag_set("quic_sec")) { ip_port_text_buffer ipb; - if (QUICTypeUtil::has_connection_id(reinterpret_cast(block->buf()))) { - QUICConnectionId cid = this->_read_destination_connection_id(block); - Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), + if (QUICTypeUtil::has_long_header(reinterpret_cast(block->buf()))) { + QUICConnectionId cid = this->_read_source_connection_id(block); + Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, cid.l64(), ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); } else { - Debug("quic_sec", "received packet from %s, size=%" PRId64 "without CID", - ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); + Debug("quic_sec", "received packet from %s, size=%" PRId64, ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), + udp_packet->getPktLength()); } } @@ -304,7 +304,7 @@ QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet) QUICConnectionId cid = this->_read_destination_connection_id(block); ip_port_text_buffer ipb; - Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, static_cast(cid), + Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, cid.l64(), ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); this->_vc->handle_received_packet(udp_packet); diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 428381908e0..b6b4b98aa41 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -162,7 +162,7 @@ QUICApplication::reenable(QUICStream *stream) stream_io->read_reenable(); stream_io->write_reenable(); } else { - Debug(tag, "[%" PRIx64 "] Unknown Stream, id: %" PRIx64, static_cast(this->_qc->connection_id()), stream->id()); + Debug(tag, "[%" PRIx64 "] Unknown Stream, id: %" PRIx64, this->_qc->connection_id().l64(), stream->id()); } return; diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 10ea251f77b..89910175980 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -26,19 +26,17 @@ #include "QUICConfig.h" -#define QUICCCDebug(fmt, ...) \ - Debug("quic_cc", \ - "[%" PRIx64 "] " \ - "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ - static_cast(this->_connection_id), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, \ - ##__VA_ARGS__) - -#define QUICCCError(fmt, ...) \ - Error("quic_cc", \ - "[%" PRIx64 "] " \ - "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ - static_cast(this->_connection_id), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, \ - ##__VA_ARGS__) +#define QUICCCDebug(fmt, ...) \ + Debug("quic_cc", \ + "[%" PRIx64 "] " \ + "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ + this->_connection_id.l64(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, ##__VA_ARGS__) + +#define QUICCCError(fmt, ...) \ + Error("quic_cc", \ + "[%" PRIx64 "] " \ + "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ + this->_connection_id.l64(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, ##__VA_ARGS__) QUICCongestionController::QUICCongestionController() : QUICCongestionController(QUICConnectionId::ZERO()) {} diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 83c83a8ce9c..e7d567bf851 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -58,11 +58,11 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler virtual QUICStreamManager *stream_manager() = 0; - virtual uint32_t pmtu() = 0; - virtual NetVConnectionContext_t direction() = 0; - virtual SSLNextProtocolSet *next_protocol_set() = 0; - virtual void close(QUICConnectionErrorUPtr error) = 0; - virtual QUICPacketNumber largest_acked_packet_number() = 0; - virtual void handle_received_packet(UDPPacket *packeet) = 0; - virtual bool is_closed() = 0; + virtual uint32_t pmtu() = 0; + virtual NetVConnectionContext_t direction() = 0; + virtual SSLNextProtocolSet *next_protocol_set() = 0; + virtual void close(QUICConnectionErrorUPtr error) = 0; + virtual QUICPacketNumber largest_acked_packet_number() = 0; + virtual void handle_received_packet(UDPPacket *packeet) = 0; + virtual bool is_closed() = 0; }; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 69b5b6f816e..715c01cf7a3 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -36,11 +36,9 @@ static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; -#define QUICHSDebug(fmt, ...) \ - Debug("quic_handshake", "[%" PRIx64 "] " fmt, static_cast(this->_qc->connection_id()), ##__VA_ARGS__) +#define QUICHSDebug(fmt, ...) Debug("quic_handshake", "[%" PRIx64 "] " fmt, this->_qc->peer_connection_id().l64(), ##__VA_ARGS__) -#define QUICVHSDebug(fmt, ...) \ - Debug("v_quic_handshake", "[%" PRIx64 "] " fmt, static_cast(this->_qc->connection_id()), ##__VA_ARGS__) +#define QUICVHSDebug(fmt, ...) Debug("v_quic_handshake", "[%" PRIx64 "] " fmt, this->_qc->peer_connection_id().l64(), ##__VA_ARGS__) #define I_WANNA_DUMP_THIS_BUF(buf, len) \ { \ diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index d385d5e35ed..6ec69aa8558 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -28,8 +28,7 @@ #include "QUICConfig.h" #include "QUICEvents.h" -#define QUICLDDebug(fmt, ...) \ - Debug("quic_loss_detector", "[%" PRIx64 "] " fmt, static_cast(this->_connection_id), ##__VA_ARGS__) +#define QUICLDDebug(fmt, ...) Debug("quic_loss_detector", "[%" PRIx64 "] " fmt, this->_connection_id.l64(), ##__VA_ARGS__) QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICCongestionController *cc) : _transmitter(transmitter), _cc(cc) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 7c9fafb06e1..c4ac423c29c 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -28,16 +28,16 @@ #include "QUICStreamManager.h" #include "QUICDebugNames.h" -#define QUICStreamDebug(fmt, ...) \ - Debug("quic_stream", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ +#define QUICStreamDebug(fmt, ...) \ + Debug("quic_stream", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, this->_connection_id.l64(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) -#define QUICVStreamDebug(fmt, ...) \ - Debug("v_quic_stream", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ +#define QUICVStreamDebug(fmt, ...) \ + Debug("v_quic_stream", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, this->_connection_id.l64(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) -#define QUICStreamFCDebug(fmt, ...) \ - Debug("quic_flow_ctrl", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, static_cast(this->_connection_id), this->_id, \ +#define QUICStreamFCDebug(fmt, ...) \ + Debug("quic_flow_ctrl", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, this->_connection_id.l64(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data, diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 5fe899f0084..33a43e2b68a 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -21,10 +21,12 @@ * limitations under the License. */ +#include #include "QUICTypes.h" #include "QUICIntUtil.h" bool +#include QUICTypeUtil::has_long_header(const uint8_t *buf) { return (buf[0] & 0x80) != 0; @@ -271,3 +273,15 @@ QUICConnectionId::_hashcode() const (static_cast(this->_id[2]) << 40) + (static_cast(this->_id[3]) << 32) + (this->_id[4] << 24) + (this->_id[5] << 16) + (this->_id[6] << 8) + this->_id[7]; } + +uint64_t +QUICConnectionId::l64() const +{ + uint64_t v = 0; + int ndigit = std::min(8U, static_cast(this->_len)); + int offset = static_cast(this->_len) - ndigit; + for (int i = 0; i < ndigit; i++) { + v += static_cast(this->_id[offset + i]) << (8 * (ndigit - i - 1)); + } + return v; +} diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 98e49b32746..552b6857cfb 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -235,6 +235,11 @@ class QUICConnectionId return memcmp(this->_id, x._id, sizeof(this->_id)) != 0; } + /* + * This is just for debugging. + */ + uint64_t l64() const; + uint8_t length() const; bool is_zero() const; void randomize(); From df23d49602dbef944a22a4a67147648b8ba3dff9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 17 May 2018 10:25:20 +0900 Subject: [PATCH 0544/1313] Update largest received packet number The update logic was accidentally lost with 7cb18b38d88fd6af13eed65867701117cbc890ae --- iocore/net/quic/QUICPacketReceiveQueue.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 640dcaa03cf..9dec772a0d0 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -39,6 +39,10 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) } } + if (quic_packet->packet_number() > this->_largest_received_packet_number) { + this->_largest_received_packet_number = quic_packet->packet_number(); + } + return quic_packet; } From ba77c64514e9d585ed68c7c3251fe131af8c56c8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 17 May 2018 10:28:14 +0900 Subject: [PATCH 0545/1313] Add AL header --- iocore/net/quic/QUICPacketReceiveQueue.cc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 9dec772a0d0..ded0453bf34 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -1,3 +1,26 @@ +/** @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 "QUICPacketReceiveQueue.h" QUICPacketReceiveQueue::QUICPacketReceiveQueue(QUICPacketFactory &packet_factory) : _packet_factory(packet_factory) {} From 4b3d12790c5866abe2eba0772bb9441a0aec8e6f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 17 May 2018 11:29:16 +0900 Subject: [PATCH 0546/1313] Fix nullptr dereference --- iocore/net/QUICNetVConnection.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index d0f6bef5258..5b03dcb8804 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1404,18 +1404,18 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) { QUICPacketUPtr packet = this->_packet_recv_queue.dequeue(result); - if (this->direction() == NET_VCONNECTION_OUT) { - // Reset CID if a server sent back a new CID - // FIXME This should happen only once - QUICConnectionId cid = packet->destination_cid(); - if (cid.length()) { - if (this->_quic_connection_id != cid) { - this->_quic_connection_id = cid; + 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 cid = packet->destination_cid(); + if (cid.length()) { + if (this->_quic_connection_id != cid) { + this->_quic_connection_id = cid; + } } } - } - if (result == QUICPacketCreationResult::SUCCESS) { this->_last_received_packet_type = packet->type(); this->_packet_factory.set_dcil(packet->destination_cid().length()); } From 5624d2365f2d2b301086826d6f84c0db815a7e16 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 17 May 2018 14:10:50 +0900 Subject: [PATCH 0547/1313] QUIC Client: Set peer connection id --- iocore/net/QUICNetVConnection.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5b03dcb8804..8c0867be28f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1315,7 +1315,7 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi switch (type) { case QUICPacketType::INITIAL: ink_assert(this->get_context() == NET_VCONNECTION_OUT); - packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->_original_quic_connection_id, + packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len); this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); @@ -1408,10 +1408,10 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) if (this->direction() == NET_VCONNECTION_OUT) { // Reset CID if a server sent back a new CID // FIXME This should happen only once - QUICConnectionId cid = packet->destination_cid(); - if (cid.length()) { - if (this->_quic_connection_id != cid) { - this->_quic_connection_id = cid; + QUICConnectionId src_cid = packet->source_cid(); + if (src_cid.length()) { + if (this->_peer_quic_connection_id != src_cid) { + this->_peer_quic_connection_id = src_cid; } } } From 7268ee4916a7508f9ced4a81185ae1326ca79739 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 17 May 2018 14:12:24 +0900 Subject: [PATCH 0548/1313] Add nullptr check in QUICPacketReceiveQueue::dequeue() --- iocore/net/quic/QUICPacketReceiveQueue.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index ded0453bf34..c6292c4a88d 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -62,7 +62,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) } } - if (quic_packet->packet_number() > this->_largest_received_packet_number) { + if (quic_packet && quic_packet->packet_number() > this->_largest_received_packet_number) { this->_largest_received_packet_number = quic_packet->packet_number(); } From 77a09fbda3d836a0df8770371a00462174b965fc Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 17 May 2018 15:03:56 +0900 Subject: [PATCH 0549/1313] Do not update peer connection id when src cid is zero --- iocore/net/QUICNetVConnection.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8c0867be28f..68228430b96 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1409,7 +1409,8 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) // Reset CID if a server sent back a new CID // FIXME This should happen only once QUICConnectionId src_cid = packet->source_cid(); - if (src_cid.length()) { + // 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->_peer_quic_connection_id = src_cid; } From 0904ef1abe0950700a68bcfc08ed742d1109ecf8 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 17 May 2018 21:28:42 +0900 Subject: [PATCH 0550/1313] Add Coaslescing Packets Support --- iocore/net/QUICNetVConnection.cc | 11 +-- iocore/net/quic/QUICPacketReceiveQueue.cc | 93 +++++++++++++++++++---- iocore/net/quic/QUICPacketReceiveQueue.h | 5 ++ 3 files changed, 90 insertions(+), 19 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 68228430b96..590cf84cb57 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -849,11 +849,12 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack QUICErrorUPtr QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packet) { - if (packet->size() < MINIMUM_INITIAL_PACKET_SIZE) { - QUICConDebug("Packet size is smaller than the minimum initial packet size"); - // Ignore the packet - return QUICErrorUPtr(new QUICNoError()); - } + // QUIC packet could be smaller than MINIMUM_INITIAL_PACKET_SIZE when coalescing packets + // if (packet->size() < MINIMUM_INITIAL_PACKET_SIZE) { + // QUICConDebug("Packet size is smaller than the minimum initial packet size"); + // // Ignore the packet + // return QUICErrorUPtr(new QUICNoError()); + // } // Start handshake QUICErrorUPtr error = this->_handshake_handler->start(packet.get(), &this->_packet_factory); diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index c6292c4a88d..f4cfbe2cc59 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -23,6 +23,33 @@ #include "QUICPacketReceiveQueue.h" +#include "QUICIntUtil.h" + +// FIXME: workaround for coalescing packets +static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6; +static constexpr int LONG_HDR_PKT_NUM_LEN = 4; + +static size_t long_hdr_pkt_len(uint8_t *buf) { + uint8_t dcil = (buf[5] >> 4); + if (dcil) { + dcil += 3; + } + uint8_t scil = (buf[5] & 0x0F); + if (scil) { + scil += 3; + } + size_t offset = LONG_HDR_OFFSET_CONNECTION_ID; + offset += dcil; + offset += scil; + + size_t payload_len = QUICIntUtil::read_QUICVariableInt(buf + offset); + offset += QUICVariableInt::size(buf + offset); + offset += LONG_HDR_PKT_NUM_LEN; + offset += payload_len; + + return offset; +} + QUICPacketReceiveQueue::QUICPacketReceiveQueue(QUICPacketFactory &packet_factory) : _packet_factory(packet_factory) {} void @@ -35,25 +62,63 @@ QUICPacketUPtr QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) { QUICPacketUPtr quic_packet = QUICPacketFactory::create_null_packet(); - UDPPacket *udp_packet = this->_queue.dequeue(); - if (!udp_packet) { - result = QUICPacketCreationResult::NOT_READY; - return quic_packet; + UDPPacket *udp_packet = nullptr; + + // FIXME: avoid this copy + // Copy payload of UDP packet to this->_payload once + if (!this->_payload) { + udp_packet = this->_queue.dequeue(); + if (!udp_packet) { + result = QUICPacketCreationResult::NOT_READY; + return quic_packet; + } + + // Create a QUIC packet + this->_from = udp_packet->from; + this->_payload_len = udp_packet->getPktLength(); + this->_payload = ats_unique_malloc(this->_payload_len); + IOBufferBlock *b = udp_packet->getIOBlockChain(); + size_t written = 0; + while (b) { + memcpy(this->_payload.get() + written, b->buf(), b->read_avail()); + written += b->read_avail(); + b = b->next.get(); + } } - // Create a QUIC packet - ats_unique_buf pkt = ats_unique_malloc(udp_packet->getPktLength()); - IOBufferBlock *b = udp_packet->getIOBlockChain(); - size_t written = 0; - while (b) { - memcpy(pkt.get() + written, b->buf(), b->read_avail()); - written += b->read_avail(); - b = b->next.get(); + ats_unique_buf pkt = {nullptr, [](void *p) { ats_free(p); }}; + size_t pkt_len = 0; + + if (QUICTypeUtil::has_long_header(this->_payload.get())) { + if (QUICTypeUtil::has_long_header(this->_payload.get() + this->_offset)) { + pkt_len = long_hdr_pkt_len(this->_payload.get() + this->_offset); + } else { + pkt_len = this->_payload_len - this->_offset; + } + + if (pkt_len < this->_payload_len) { + pkt = ats_unique_malloc(pkt_len); + memcpy(pkt.get(), this->_payload.get() + this->_offset, pkt_len); + this->_offset += pkt_len; + + if (this->_offset >= this->_payload_len) { + this->_payload.release(); + } + } else { + pkt = std::move(this->_payload); + pkt_len = this->_payload_len; + } + } else { + pkt = std::move(this->_payload); + pkt_len = this->_payload_len; } quic_packet = - this->_packet_factory.create(udp_packet->from, std::move(pkt), written, this->largest_received_packet_number(), result); - udp_packet->free(); + this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->largest_received_packet_number(), result); + + if (udp_packet) { + udp_packet->free(); + } if (result == QUICPacketCreationResult::NOT_READY) { // FIXME: unordered packet should be buffered and retried diff --git a/iocore/net/quic/QUICPacketReceiveQueue.h b/iocore/net/quic/QUICPacketReceiveQueue.h index a711bbdae46..1930bb77838 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.h +++ b/iocore/net/quic/QUICPacketReceiveQueue.h @@ -43,4 +43,9 @@ class QUICPacketReceiveQueue CountQueue _queue; QUICPacketFactory &_packet_factory; QUICPacketNumber _largest_received_packet_number = 0; + // FIXME: workaround code for coalescing packets + ats_unique_buf _payload = {nullptr, [](void *p) { ats_free(p); }}; + size_t _payload_len = 0; + size_t _offset = 0; + IpEndpoint _from; }; From bec0f225b593fe6c499307b626460e3758091229 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 17 May 2018 22:22:59 +0900 Subject: [PATCH 0551/1313] Fix a buffer overflow --- iocore/net/quic/QUICPacketReceiveQueue.cc | 34 +++++++++++++++-------- iocore/net/quic/QUICPacketReceiveQueue.h | 4 +-- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index f4cfbe2cc59..04f8602348c 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -27,9 +27,11 @@ // FIXME: workaround for coalescing packets static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6; -static constexpr int LONG_HDR_PKT_NUM_LEN = 4; +static constexpr int LONG_HDR_PKT_NUM_LEN = 4; -static size_t long_hdr_pkt_len(uint8_t *buf) { +static size_t +long_hdr_pkt_len(uint8_t *buf) +{ uint8_t dcil = (buf[5] >> 4); if (dcil) { dcil += 3; @@ -62,7 +64,7 @@ QUICPacketUPtr QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) { QUICPacketUPtr quic_packet = QUICPacketFactory::create_null_packet(); - UDPPacket *udp_packet = nullptr; + UDPPacket *udp_packet = nullptr; // FIXME: avoid this copy // Copy payload of UDP packet to this->_payload once @@ -74,9 +76,9 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) } // Create a QUIC packet - this->_from = udp_packet->from; + this->_from = udp_packet->from; this->_payload_len = udp_packet->getPktLength(); - this->_payload = ats_unique_malloc(this->_payload_len); + this->_payload = ats_unique_malloc(this->_payload_len); IOBufferBlock *b = udp_packet->getIOBlockChain(); size_t written = 0; while (b) { @@ -87,7 +89,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) } ats_unique_buf pkt = {nullptr, [](void *p) { ats_free(p); }}; - size_t pkt_len = 0; + size_t pkt_len = 0; if (QUICTypeUtil::has_long_header(this->_payload.get())) { if (QUICTypeUtil::has_long_header(this->_payload.get() + this->_offset)) { @@ -103,18 +105,26 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) if (this->_offset >= this->_payload_len) { this->_payload.release(); + this->_payload = nullptr; + this->_payload_len = 0; + this->_offset = 0; } } else { - pkt = std::move(this->_payload); - pkt_len = this->_payload_len; + pkt = std::move(this->_payload); + pkt_len = this->_payload_len; + this->_payload = nullptr; + this->_payload_len = 0; + this->_offset = 0; } } else { - pkt = std::move(this->_payload); - pkt_len = this->_payload_len; + pkt = std::move(this->_payload); + pkt_len = this->_payload_len; + this->_payload = nullptr; + this->_payload_len = 0; + this->_offset = 0; } - quic_packet = - this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->largest_received_packet_number(), result); + quic_packet = this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->largest_received_packet_number(), result); if (udp_packet) { udp_packet->free(); diff --git a/iocore/net/quic/QUICPacketReceiveQueue.h b/iocore/net/quic/QUICPacketReceiveQueue.h index 1930bb77838..911c0cf72e9 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.h +++ b/iocore/net/quic/QUICPacketReceiveQueue.h @@ -45,7 +45,7 @@ class QUICPacketReceiveQueue QUICPacketNumber _largest_received_packet_number = 0; // FIXME: workaround code for coalescing packets ats_unique_buf _payload = {nullptr, [](void *p) { ats_free(p); }}; - size_t _payload_len = 0; - size_t _offset = 0; + size_t _payload_len = 0; + size_t _offset = 0; IpEndpoint _from; }; From 6d8574a764f2f668483956bffedf033321389c9c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 18 May 2018 09:00:53 +0900 Subject: [PATCH 0552/1313] Doesn't count frame header size Offset was calculated with header size when update conection level flow control credit. --- iocore/net/quic/QUICStreamManager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 95b15025384..eff8f53ae06 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -394,7 +394,7 @@ QUICStreamManager::generate_frame(uint16_t connection_credit, uint16_t maximum_f } if (frame != nullptr && frame->type() == QUICFrameType::STREAM) { - this->add_total_offset_sent(frame->size()); + this->add_total_offset_sent(static_cast(frame.get())->data_length()); } return frame; From ac6a84d294f6177ca9ebb882475017183ee056da Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 18 May 2018 11:33:21 +0900 Subject: [PATCH 0553/1313] draft-11 uses 2 bits but not 3 for short header type field --- iocore/net/quic/QUICPacket.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index f8171fc4745..6d27cc398b0 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -390,7 +390,7 @@ QUICPacketShortHeader::_packet_number_len() const { QUICPacketShortHeaderType type; if (this->_buf) { - type = static_cast(this->_buf.get()[0] & 0x07); + type = static_cast(this->_buf.get()[0] & 0x03); } else { type = this->_packet_number_type; } From 57cf4157f3504ee9264786e52bd05d262cdc833b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 18 May 2018 14:37:55 +0900 Subject: [PATCH 0554/1313] Make PATH_CHALLENGE/RESPONSE frame unprotected PATH_CHALLENGE/RESPONSE frame could be in HANDSHAKE packet. --- iocore/net/QUICNetVConnection.cc | 3 ++- iocore/net/quic/QUICFrame.cc | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 590cf84cb57..153b7012211 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1147,7 +1147,7 @@ QUICNetVConnection::_packetize_frames() bool will_be_ack_only = true; if (this->_connection_error || this->_packet_retransmitter.will_generate_frame() || - this->_stream_manager->will_generate_frame()) { + this->_stream_manager->will_generate_frame() || this->_path_validator->will_generate_frame()) { will_be_ack_only = false; } @@ -1159,6 +1159,7 @@ QUICNetVConnection::_packetize_frames() } else { frame = this->_ack_frame_creator.generate_frame(UINT16_MAX, this->_maximum_stream_frame_data_size()); } + if (frame != nullptr) { ++frame_count; this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 03e0e665541..559d07a5b2a 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2027,7 +2027,7 @@ QUICFrameFactory::create_path_challenge_frame(const uint8_t *data) memcpy(buf.get(), data, QUICPathChallengeFrame::DATA_LEN); QUICPathChallengeFrame *frame = quicPathChallengeFrameAllocator.alloc(); - new (frame) QUICPathChallengeFrame(std::move(buf)); + new (frame) QUICPathChallengeFrame(std::move(buf), false); return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_challenge_frame); } @@ -2038,7 +2038,7 @@ QUICFrameFactory::create_path_response_frame(const uint8_t *data) memcpy(buf.get(), data, QUICPathResponseFrame::DATA_LEN); QUICPathResponseFrame *frame = quicPathResponseFrameAllocator.alloc(); - new (frame) QUICPathResponseFrame(std::move(buf)); + new (frame) QUICPathResponseFrame(std::move(buf), false); return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_challenge_frame); } From b42f7d27467c6e56be9ae8f9664a55e733e7f38d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 21 May 2018 09:53:09 +0900 Subject: [PATCH 0555/1313] Replace ts::string_view with std::string_view in QUIC --- iocore/net/P_QUICNetVConnection.h | 4 ++-- iocore/net/QUICNetVConnection.cc | 7 +++---- iocore/net/quic/QUICHandshakeProtocol.cc | 1 - iocore/net/quic/QUICKeyGenerator.cc | 16 +++++++++------- proxy/hq/HQClientSession.cc | 2 +- proxy/hq/HQClientSession.h | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index c64e072e0e6..8ee8358e723 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -180,8 +180,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub virtual void net_read_io(NetHandler *nh, EThread *lthread) override; virtual int64_t load_buffer_and_write(int64_t towrite, MIOBufferAccessor &buf, int64_t &total_written, int &needs) override; - int populate_protocol(ts::string_view *results, int n) const override; - const char *protocol_contains(ts::string_view tag) const override; + int populate_protocol(std::string_view *results, int n) const override; + const char *protocol_contains(std::string_view tag) const override; // QUICNetVConnection void registerNextProtocolSet(SSLNextProtocolSet *s); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 153b7012211..30d95a69303 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -24,7 +24,6 @@ #include #include "ts/ink_config.h" -#include "ts/ink_std_compat.h" #include "records/I_RecHttp.h" #include "ts/Diags.h" @@ -742,7 +741,7 @@ QUICNetVConnection::load_buffer_and_write(int64_t towrite, MIOBufferAccessor &bu } int -QUICNetVConnection::populate_protocol(ts::string_view *results, int n) const +QUICNetVConnection::populate_protocol(std::string_view *results, int n) const { int retval = 0; if (n > retval) { @@ -755,10 +754,10 @@ QUICNetVConnection::populate_protocol(ts::string_view *results, int n) const } const char * -QUICNetVConnection::protocol_contains(ts::string_view prefix) const +QUICNetVConnection::protocol_contains(std::string_view prefix) const { const char *retval = nullptr; - ts::string_view tag = IP_PROTO_TAG_QUIC; + std::string_view tag = IP_PROTO_TAG_QUIC; if (prefix.size() <= tag.size() && strncmp(tag.data(), prefix.data(), prefix.size()) == 0) { retval = tag.data(); } else { diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index cea5d48245e..8d463700f4e 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -24,7 +24,6 @@ #include "QUICHandshakeProtocol.h" #include "ts/Diags.h" -#include "ts/string_view.h" #include "QUICTypes.h" #include "QUICHKDF.h" diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 3f30a411bbe..5f97b58716b 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -26,16 +26,18 @@ #include "ts/ink_assert.h" #include "QUICHKDF.h" +using namespace std::literals; + constexpr static uint8_t QUIC_VERSION_1_SALT[] = { 0x9c, 0x10, 0x8f, 0x98, 0x52, 0x0a, 0x5c, 0x5c, 0x32, 0x96, 0x8e, 0x95, 0x0e, 0x8a, 0x2c, 0x5f, 0xe0, 0x6d, 0x6c, 0x38, }; -constexpr static ts::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("client hs"_sv); -constexpr static ts::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("server hs"_sv); -constexpr static ts::string_view LABEL_FOR_CLIENT_0RTT_SECRET("EXPORTER-QUIC 0rtt"_sv); -constexpr static ts::string_view LABEL_FOR_CLIENT_PP_SECRET("EXPORTER-QUIC client 1rtt"_sv); -constexpr static ts::string_view LABEL_FOR_SERVER_PP_SECRET("EXPORTER-QUIC server 1rtt"_sv); -constexpr static ts::string_view LABEL_FOR_KEY("key"_sv); -constexpr static ts::string_view LABEL_FOR_IV("iv"_sv); +constexpr static std::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("client hs"sv); +constexpr static std::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("server hs"sv); +constexpr static std::string_view LABEL_FOR_CLIENT_0RTT_SECRET("EXPORTER-QUIC 0rtt"sv); +constexpr static std::string_view LABEL_FOR_CLIENT_PP_SECRET("EXPORTER-QUIC client 1rtt"sv); +constexpr static std::string_view LABEL_FOR_SERVER_PP_SECRET("EXPORTER-QUIC server 1rtt"sv); +constexpr static std::string_view LABEL_FOR_KEY("key"sv); +constexpr static std::string_view LABEL_FOR_IV("iv"sv); std::unique_ptr QUICKeyGenerator::generate(QUICConnectionId cid) diff --git a/proxy/hq/HQClientSession.cc b/proxy/hq/HQClientSession.cc index 332bcb052fa..f9468474d7b 100644 --- a/proxy/hq/HQClientSession.cc +++ b/proxy/hq/HQClientSession.cc @@ -123,7 +123,7 @@ HQClientSession::release(ProxyClientTransaction *trans) } int -HQClientSession::populate_protocol(ts::string_view *result, int size) const +HQClientSession::populate_protocol(std::string_view *result, int size) const { int retval = 0; if (size > retval) { diff --git a/proxy/hq/HQClientSession.h b/proxy/hq/HQClientSession.h index ccbae3d5daf..928503fe86c 100644 --- a/proxy/hq/HQClientSession.h +++ b/proxy/hq/HQClientSession.h @@ -50,7 +50,7 @@ class HQClientSession : public ProxyClientSession int get_transact_count() const override; const char *get_protocol_string() const override; void release(ProxyClientTransaction *trans) override; - int populate_protocol(ts::string_view *result, int size) const override; + int populate_protocol(std::string_view *result, int size) const override; // HQClientSession specific methods void add_transaction(HQClientTransaction *); From 87370f98ecdaec37a53dcb15ee669c83e7922a72 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 21 May 2018 10:13:16 +0900 Subject: [PATCH 0556/1313] clang-format --- iocore/net/QUICNetVConnection.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 30d95a69303..6d52b5400ae 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -756,7 +756,7 @@ QUICNetVConnection::populate_protocol(std::string_view *results, int n) const const char * QUICNetVConnection::protocol_contains(std::string_view prefix) const { - const char *retval = nullptr; + const char *retval = nullptr; std::string_view tag = IP_PROTO_TAG_QUIC; if (prefix.size() <= tag.size() && strncmp(tag.data(), prefix.data(), prefix.size()) == 0) { retval = tag.data(); From 2391a97e2ffa7f815d71e0e614cb4fd9ee1c8201 Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 16 May 2018 08:12:32 +0800 Subject: [PATCH 0557/1313] [QUIC] Limits the size when store frame into buffer --- iocore/net/QUICNetVConnection.cc | 20 +- iocore/net/quic/QUICFrame.cc | 248 ++++++++++++++++++++----- iocore/net/quic/QUICFrame.h | 51 ++--- iocore/net/quic/test/test_QUICFrame.cc | 115 +++++++----- 4 files changed, 323 insertions(+), 111 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6d52b5400ae..525f129c5ba 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1121,12 +1121,26 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans // TODO: check debug build char msg[1024]; - frame->debug_msg(msg, sizeof(msg)); QUICConDebug("[TX] %s", msg); - frame->store(buf.get() + len, &l); - len += l; + ink_assert(max_size > len); + size_t n = frame->store(buf.get() + len, &l, max_size - len); + if (n > 0) { + frame->debug_msg(msg, sizeof(msg)); + len += l; + return; + } + + // split frame + auto new_frame = QUICFrameFactory::split_frame(frame.get(), max_size - len); + frame->debug_msg(msg, sizeof(msg)); + ink_assert(frame->store(buf.get() + len, &l, max_size - len) > 0); + ink_assert(new_frame != nullptr); + this->_transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, current_packet_type)); + len = 0; + buf = ats_unique_malloc(max_size); + this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(new_frame)); return; } diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 559d07a5b2a..1cc10009dd5 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -97,6 +97,44 @@ QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStrea this->_fin = last; } +QUICStreamFrame * +QUICStreamFrame::split(size_t size) +{ + if (size <= this->_get_data_field_offset()) { + return nullptr; + } + bool fin = this->has_fin_flag(); + + ink_assert(size < this->size()); + + size_t data_len = size - this->_get_data_field_offset(); + size_t buf2_len = this->data_length() - data_len; + + ats_unique_buf buf = ats_unique_malloc(data_len); + ats_unique_buf buf2 = ats_unique_malloc(buf2_len); + memcpy(buf.get(), this->data(), data_len); + memcpy(buf2.get(), this->data() + data_len, buf2_len); + + if (this->has_offset_field()) { + this->_offset = this->offset(); + } + + if (this->has_length_field()) { + this->_data_len = data_len; + } + + this->_fin = false; + this->_data = std::move(buf); + this->_stream_id = this->stream_id(); + + this->reset(nullptr, 0); + + QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); + new (frame) + QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin, this->is_protected()); + return frame; +} + QUICFrameType QUICStreamFrame::type() const { @@ -109,10 +147,10 @@ QUICStreamFrame::size() const return this->_get_data_field_offset() + this->data_length(); } -void -QUICStreamFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICStreamFrame::store(uint8_t *buf, size_t *len, size_t limit) const { - this->store(buf, len, true); + return this->store(buf, len, limit, true); } int @@ -122,9 +160,13 @@ QUICStreamFrame::debug_msg(char *msg, size_t msg_len) const this->stream_id(), this->offset(), this->data_length(), this->has_fin_flag()); } -void -QUICStreamFrame::store(uint8_t *buf, size_t *len, bool include_length_field) const +size_t +QUICStreamFrame::store(uint8_t *buf, size_t *len, size_t limit, bool include_length_field) const { + if (limit < this->size()) { + return 0; + } + // Build Frame Type: "0b0010OLF" buf[0] = static_cast(QUICFrameType::STREAM); *len = 1; @@ -157,6 +199,8 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, bool include_length_field) con // Stream Data (*) memcpy(buf + *len, this->data(), this->data_length()); *len += this->data_length(); + + return *len; } QUICStreamId @@ -373,9 +417,13 @@ QUICAckFrame::size() const return this->_get_ack_block_section_offset() + this->_ack_block_section->size(); } -void -QUICAckFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICAckFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + uint8_t *p = buf; size_t n; *p = static_cast(QUICFrameType::ACK); @@ -387,12 +435,15 @@ QUICAckFrame::store(uint8_t *buf, size_t *len) const p += n; QUICIntUtil::write_QUICVariableInt(this->ack_block_count(), p, &n); p += n; - this->_ack_block_section->store(p, &n); + + ink_assert(limit >= static_cast(p - buf)); + limit -= (p - buf); + this->_ack_block_section->store(p, &n, limit); p += n; *len = p - buf; - return; + return *len; } int @@ -631,9 +682,13 @@ QUICAckFrame::AckBlockSection::size() const return n; } -void -QUICAckFrame::AckBlockSection::store(uint8_t *buf, size_t *len) const +size_t +QUICAckFrame::AckBlockSection::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + size_t n; uint8_t *p = buf; @@ -648,6 +703,8 @@ QUICAckFrame::AckBlockSection::store(uint8_t *buf, size_t *len) const } *len = p - buf; + + return *len; } uint64_t @@ -783,9 +840,13 @@ QUICRstStreamFrame::size() const return 1 + this->_get_stream_id_field_length() + sizeof(QUICAppErrorCode) + this->_get_final_offset_field_length(); } -void -QUICRstStreamFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICRstStreamFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + if (this->_buf) { *len = this->size(); memcpy(buf, this->_buf, *len); @@ -803,6 +864,8 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } + + return *len; } QUICStreamId @@ -888,9 +951,13 @@ QUICPingFrame::size() const return 1; } -void -QUICPingFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICPingFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + *len = this->size(); if (this->_buf) { @@ -898,6 +965,8 @@ QUICPingFrame::store(uint8_t *buf, size_t *len) const } else { buf[0] = static_cast(QUICFrameType::PING); } + + return *len; } // @@ -915,11 +984,16 @@ QUICPaddingFrame::size() const return 1; } -void -QUICPaddingFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICPaddingFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + buf[0] = static_cast(QUICFrameType::PADDING); *len = 1; + return *len; } // @@ -947,9 +1021,13 @@ QUICConnectionCloseFrame::size() const this->reason_phrase_length(); } -void -QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + if (this->_buf) { *len = this->size(); memcpy(buf, this->_buf, *len); @@ -969,6 +1047,8 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } + + return *len; } QUICTransErrorCode @@ -1048,9 +1128,13 @@ QUICApplicationCloseFrame::size() const this->reason_phrase_length(); } -void -QUICApplicationCloseFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICApplicationCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + if (this->_buf) { *len = this->size(); memcpy(buf, this->_buf, *len); @@ -1070,6 +1154,8 @@ QUICApplicationCloseFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } + + return *len; } QUICAppErrorCode @@ -1144,9 +1230,13 @@ QUICMaxDataFrame::size() const return sizeof(QUICFrameType) + this->_get_max_data_field_length(); } -void -QUICMaxDataFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICMaxDataFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + if (this->_buf) { *len = this->size(); memcpy(buf, this->_buf, *len); @@ -1160,6 +1250,8 @@ QUICMaxDataFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } + + return *len; } uint64_t @@ -1204,9 +1296,12 @@ QUICMaxStreamDataFrame::size() const return sizeof(QUICFrameType) + this->_get_stream_id_field_length() + this->_get_max_stream_data_field_length(); } -void -QUICMaxStreamDataFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICMaxStreamDataFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } if (this->_buf) { *len = this->size(); memcpy(buf, this->_buf, *len); @@ -1222,6 +1317,7 @@ QUICMaxStreamDataFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } + return *len; } QUICStreamId @@ -1296,9 +1392,13 @@ QUICMaxStreamIdFrame::size() const return sizeof(QUICFrameType) + this->_get_max_stream_id_field_length(); } -void -QUICMaxStreamIdFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICMaxStreamIdFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + if (this->_buf) { *len = this->size(); memcpy(buf, this->_buf, *len); @@ -1312,6 +1412,7 @@ QUICMaxStreamIdFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } + return *len; } QUICStreamId @@ -1349,9 +1450,13 @@ QUICBlockedFrame::size() const return sizeof(QUICFrameType) + this->_get_offset_field_length(); } -void -QUICBlockedFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + if (this->_buf) { *len = this->size(); memcpy(buf, this->_buf, *len); @@ -1366,6 +1471,8 @@ QUICBlockedFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } + + return *len; } QUICOffset @@ -1403,9 +1510,13 @@ QUICStreamBlockedFrame::size() const return sizeof(QUICFrameType) + this->_get_stream_id_field_length() + this->_get_offset_field_length(); } -void -QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + if (this->_buf) { *len = this->size(); memcpy(buf, this->_buf, *len); @@ -1421,6 +1532,8 @@ QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } + + return *len; } QUICStreamId @@ -1484,9 +1597,13 @@ QUICStreamIdBlockedFrame::size() const return sizeof(QUICFrameType) + this->_get_stream_id_field_length(); } -void -QUICStreamIdBlockedFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICStreamIdBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + if (this->_buf) { *len = this->size(); memcpy(buf, this->_buf, *len); @@ -1501,6 +1618,8 @@ QUICStreamIdBlockedFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } + + return *len; } QUICStreamId @@ -1539,9 +1658,13 @@ QUICNewConnectionIdFrame::size() const return sizeof(QUICFrameType) + this->_get_sequence_field_length() + 1 + this->_get_connection_id_length() + 16; } -void -QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + if (this->_buf) { *len = this->size(); memcpy(buf, this->_buf, *len); @@ -1561,6 +1684,8 @@ QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } + + return *len; } uint64_t @@ -1641,9 +1766,13 @@ QUICStopSendingFrame::size() const return sizeof(QUICFrameType) + this->_get_stream_id_field_length() + sizeof(QUICAppErrorCode); } -void -QUICStopSendingFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICStopSendingFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + if (this->_buf) { *len = this->size(); memcpy(buf, this->_buf, *len); @@ -1659,6 +1788,8 @@ QUICStopSendingFrame::store(uint8_t *buf, size_t *len) const *len = p - buf; } + + return *len; } QUICAppErrorCode @@ -1712,9 +1843,13 @@ QUICPathChallengeFrame::size() const return this->_data_offset() + QUICPathChallengeFrame::DATA_LEN; } -void -QUICPathChallengeFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICPathChallengeFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + *len = this->size(); if (this->_buf) { @@ -1723,6 +1858,8 @@ QUICPathChallengeFrame::store(uint8_t *buf, size_t *len) const buf[0] = static_cast(QUICFrameType::PATH_CHALLENGE); memcpy(buf + this->_data_offset(), this->data(), QUICPathChallengeFrame::DATA_LEN); } + + return *len; } const uint8_t * @@ -1756,9 +1893,13 @@ QUICPathResponseFrame::size() const return this->_data_offset() + 8; } -void -QUICPathResponseFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICPathResponseFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + *len = this->size(); if (this->_buf) { @@ -1767,6 +1908,8 @@ QUICPathResponseFrame::store(uint8_t *buf, size_t *len) const buf[0] = static_cast(QUICFrameType::PATH_RESPONSE); memcpy(buf + this->_data_offset(), this->data(), QUICPathResponseFrame::DATA_LEN); } + + return *len; } const uint8_t * @@ -1795,7 +1938,7 @@ QUICRetransmissionFrame::QUICRetransmissionFrame(QUICFrameUPtr original_frame, c this->_size = original_frame->size(); this->_data = ats_unique_malloc(this->_size); this->_buf = this->_data.get(); - original_frame->store(this->_data.get(), &dummy); + original_frame->store(this->_data.get(), &dummy, this->_size); } size_t @@ -1804,11 +1947,16 @@ QUICRetransmissionFrame::size() const return this->_size; } -void -QUICRetransmissionFrame::store(uint8_t *buf, size_t *len) const +size_t +QUICRetransmissionFrame::store(uint8_t *buf, size_t *len, size_t limit) const { + if (limit < this->size()) { + return 0; + } + memcpy(buf, this->_data.get(), this->_size); *len = this->_size; + return *len; } QUICPacketType @@ -1947,6 +2095,18 @@ QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUIC return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); } +QUICFrameUPtr +QUICFrameFactory::split_frame(QUICFrame *frame, size_t size) +{ + if (frame->type() != QUICFrameType::STREAM) { + return QUICFrameFactory::create_null_frame(); + } + + QUICStreamFrame *old_frame = static_cast(frame); + QUICStreamFrame *new_frame = old_frame->split(size); + return QUICFrameUPtr(new_frame, &QUICFrameDeleter::delete_stream_frame); +} + std::unique_ptr QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, bool protection) diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index b9462516ba4..94bbadb3961 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -40,8 +40,8 @@ class QUICFrame static QUICFrameType type(const uint8_t *buf); virtual QUICFrameType type() const; - virtual size_t size() const = 0; - virtual void store(uint8_t *buf, size_t *len) const = 0; + virtual size_t size() const = 0; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const = 0; virtual void reset(const uint8_t *buf, size_t len); virtual bool is_protected() const; virtual int debug_msg(char *msg, size_t msg_len) const; @@ -66,12 +66,13 @@ class QUICStreamFrame : public QUICFrame QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false, bool protection = true); + QUICStreamFrame *split(size_t size); virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual int debug_msg(char *msg, size_t msg_len) const override; - void store(uint8_t *buf, size_t *len, bool include_length_field) const; + size_t store(uint8_t *buf, size_t *len, size_t limit, bool include_length_field) const; QUICStreamId stream_id() const; QUICOffset offset() const; const uint8_t *data() const; @@ -172,7 +173,7 @@ class QUICAckFrame : public QUICFrame AckBlockSection(const uint8_t *buf, uint8_t ack_block_count) : _buf(buf), _ack_block_count(ack_block_count) {} uint8_t count() const; size_t size() const; - void store(uint8_t *buf, size_t *len) const; + size_t store(uint8_t *buf, size_t *len, size_t limit) const; uint64_t first_ack_block() const; void add_ack_block(const AckBlock block, bool protection = true); const_iterator begin() const; @@ -197,7 +198,7 @@ class QUICAckFrame : public QUICFrame virtual void reset(const uint8_t *buf, size_t len) override; virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual int debug_msg(char *msg, size_t msg_len) const override; bool is_protected() const override; @@ -235,7 +236,7 @@ class QUICRstStreamFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICStreamId stream_id() const; QUICAppErrorCode error_code() const; @@ -265,7 +266,7 @@ class QUICPingFrame : public QUICFrame QUICPingFrame(bool protection) : QUICFrame(protection) {} virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; private: }; @@ -279,7 +280,7 @@ class QUICPaddingFrame : public QUICFrame QUICPaddingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; }; // @@ -295,7 +296,7 @@ class QUICConnectionCloseFrame : public QUICFrame bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICTransErrorCode error_code() const; uint64_t reason_phrase_length() const; const char *reason_phrase() const; @@ -323,7 +324,7 @@ class QUICApplicationCloseFrame : public QUICFrame bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICAppErrorCode error_code() const; uint64_t reason_phrase_length() const; const char *reason_phrase() const; @@ -350,7 +351,7 @@ class QUICMaxDataFrame : public QUICFrame QUICMaxDataFrame(uint64_t maximum_data, bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; uint64_t maximum_data() const; private: @@ -371,7 +372,7 @@ class QUICMaxStreamDataFrame : public QUICFrame QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICStreamId stream_id() const; uint64_t maximum_stream_data() const; @@ -397,7 +398,7 @@ class QUICMaxStreamIdFrame : public QUICFrame QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICStreamId maximum_stream_id() const; private: @@ -418,7 +419,7 @@ class QUICBlockedFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICOffset offset() const; @@ -441,7 +442,7 @@ class QUICStreamBlockedFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICStreamId stream_id() const; QUICOffset offset() const; @@ -466,7 +467,7 @@ class QUICStreamIdBlockedFrame : public QUICFrame QUICStreamIdBlockedFrame(QUICStreamId s, bool protection = true) : QUICFrame(protection), _stream_id(s) {} virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICStreamId stream_id() const; @@ -490,7 +491,7 @@ class QUICNewConnectionIdFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; uint64_t sequence() const; QUICConnectionId connection_id() const; @@ -519,7 +520,7 @@ class QUICStopSendingFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICStreamId stream_id() const; QUICAppErrorCode error_code() const; @@ -545,7 +546,7 @@ class QUICPathChallengeFrame : public QUICFrame QUICPathChallengeFrame(ats_unique_buf data, bool protection = true) : QUICFrame(protection), _data(std::move(data)) {} virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; const uint8_t *data() const; @@ -568,7 +569,7 @@ class QUICPathResponseFrame : public QUICFrame QUICPathResponseFrame(ats_unique_buf data, bool protection = true) : QUICFrame(protection), _data(std::move(data)) {} virtual QUICFrameType type() const override; virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; const uint8_t *data() const; @@ -592,7 +593,7 @@ class QUICRetransmissionFrame : public QUICFrame QUICRetransmissionFrame() : QUICFrame() {} QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet); virtual size_t size() const override; - virtual void store(uint8_t *buf, size_t *len) const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICPacketType packet_type() const; private: @@ -764,6 +765,12 @@ class QUICFrameDeleter class QUICFrameFactory { public: + /* + * Split Stream frame into two frame + * Return the new frame + */ + static QUICFrameUPtr split_frame(QUICFrame *frame, size_t size); + /* * This is for an empty QUICFrameUptr. * Empty frames are used for variable initialization and return value of frame creation failure diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index b6d0086a873..03b8869bd8e 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -155,7 +155,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(std::move(payload1), 5, 0x01, 0x00); CHECK(stream_frame.size() == 8); - stream_frame.store(buf, &len); + stream_frame.store(buf, &len, 32); CHECK(len == 8); CHECK(memcmp(buf, expected1, len) == 0); } @@ -178,7 +178,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(std::move(payload2), 5, 0x01, 0x01); CHECK(stream_frame.size() == 9); - stream_frame.store(buf, &len); + stream_frame.store(buf, &len, 32); CHECK(len == 9); CHECK(memcmp(buf, expected2, len) == 0); } @@ -201,7 +201,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(std::move(payload3), 5, 0x01, 0x010000); CHECK(stream_frame.size() == 12); - stream_frame.store(buf, &len); + stream_frame.store(buf, &len, 32); CHECK(len == 12); CHECK(memcmp(buf, expected3, len) == 0); } @@ -224,7 +224,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(std::move(payload4), 5, 0x01, 0x0100000000); CHECK(stream_frame.size() == 16); - stream_frame.store(buf, &len); + stream_frame.store(buf, &len, 32); CHECK(len == 16); CHECK(memcmp(buf, expected4, len) == 0); } @@ -247,7 +247,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(std::move(payload5), 5, 0x0100, 0x0100000000); CHECK(stream_frame.size() == 17); - stream_frame.store(buf, &len); + stream_frame.store(buf, &len, 32); CHECK(len == 17); CHECK(memcmp(buf, expected5, len) == 0); } @@ -270,7 +270,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(std::move(payload6), 5, 0x010000, 0x0100000000); CHECK(stream_frame.size() == 19); - stream_frame.store(buf, &len); + stream_frame.store(buf, &len, 32); CHECK(len == 19); CHECK(memcmp(buf, expected6, len) == 0); } @@ -293,7 +293,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(std::move(payload7), 5, 0x01000000, 0x0100000000); CHECK(stream_frame.size() == 19); - stream_frame.store(buf, &len); + stream_frame.store(buf, &len, 32); CHECK(len == 19); CHECK(memcmp(buf, expected7, len) == 0); } @@ -316,10 +316,41 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(std::move(payload), 5, 0x01000000, 0x0100000000, true); CHECK(stream_frame.size() == 19); - stream_frame.store(buf, &len); + stream_frame.store(buf, &len, 32); CHECK(len == 19); CHECK(memcmp(buf, expected, len) == 0); } + + SECTION("split stream frame") + { + size_t len; + uint8_t buf1[] = { + 0x16, // 0b00010OLF (OLF=110) + 0x01, // Stream ID + 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset + 0x0a, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + 0x11, 0x22, 0x33, 0x44, 0x55, + }; + + QUICFrameUPtr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM); + CHECK(frame1->size() == 21); + QUICStreamFrame *stream_frame = dynamic_cast(frame1.get()); + CHECK(stream_frame->offset() == 0x100000000); + CHECK(stream_frame->stream_id() == 0x01); + CHECK(stream_frame->data_length() == 10); + QUICStreamFrame *stream_frame2 = stream_frame->split(16); + CHECK(stream_frame->stream_id() == 0x01); + CHECK(stream_frame->data_length() == 5); + CHECK(memcmp(stream_frame->data(), "\x01\x02\x03\x04\x05", stream_frame->data_length()) == 0); + CHECK(stream_frame->offset() == 0x100000000); + + CHECK(stream_frame2->data_length() == 5); + CHECK(memcmp(stream_frame2->data(), "\x11\x22\x33\x44\x55", stream_frame2->data_length()) == 0); + CHECK(stream_frame2->offset() == 0x100000000 + 5); + CHECK(stream_frame2->stream_id() == 0x01); + } } TEST_CASE("Load Ack Frame 1", "[quic]") @@ -422,7 +453,7 @@ TEST_CASE("Store Ack Frame", "[quic]") QUICAckFrame ack_frame(0x12, 0x3456, 0); CHECK(ack_frame.size() == 6); - ack_frame.store(buf, &len); + ack_frame.store(buf, &len, 32); CHECK(len == 6); CHECK(memcmp(buf, expected, len) == 0); } @@ -449,7 +480,7 @@ TEST_CASE("Store Ack Frame", "[quic]") section->add_ack_block({0x05060708, 0x090a0b0c0d0e0f10}); CHECK(ack_frame.size() == 21); - ack_frame.store(buf, &len); + ack_frame.store(buf, &len, 32); CHECK(len == 21); CHECK(memcmp(buf, expected, len) == 0); } @@ -487,7 +518,7 @@ TEST_CASE("Store RST_STREAM Frame", "[quic]") QUICRstStreamFrame rst_stream_frame(0x12345678, 0x0001, 0x1122334455667788); CHECK(rst_stream_frame.size() == 15); - rst_stream_frame.store(buf, &len); + rst_stream_frame.store(buf, &len, 65535); CHECK(len == 15); CHECK(memcmp(buf, expected, len) == 0); } @@ -517,7 +548,7 @@ TEST_CASE("Store Ping Frame", "[quic]") QUICPingFrame frame(true); CHECK(frame.size() == 1); - frame.store(buf, &len); + frame.store(buf, &len, 16); CHECK(len == 1); CHECK(memcmp(buf, expected, len) == 0); } @@ -543,7 +574,7 @@ TEST_CASE("Store Padding Frame", "[quic]") 0x00, // Type }; QUICPaddingFrame padding_frame; - padding_frame.store(buf, &len); + padding_frame.store(buf, &len, 65535); CHECK(len == 1); CHECK(memcmp(buf, expected, len) == 0); } @@ -605,7 +636,7 @@ TEST_CASE("Store ConnectionClose Frame", "[quic]") QUICConnectionCloseFrame connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, 5, "ABCDE"); CHECK(connection_close_frame.size() == 9); - connection_close_frame.store(buf, &len); + connection_close_frame.store(buf, &len, 32); CHECK(len == 9); CHECK(memcmp(buf, expected1, len) == 0); } @@ -621,7 +652,7 @@ TEST_CASE("Store ConnectionClose Frame", "[quic]") 0x00, // Reason Phrase Length }; QUICConnectionCloseFrame connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, 0, nullptr); - connection_close_frame.store(buf, &len); + connection_close_frame.store(buf, &len, 32); CHECK(len == 4); CHECK(memcmp(buf, expected2, len) == 0); } @@ -684,7 +715,7 @@ TEST_CASE("Store ApplicationClose Frame", "[quic]") QUICApplicationCloseFrame app_close_frame(static_cast(0x01), 5, "ABCDE"); CHECK(app_close_frame.size() == 9); - app_close_frame.store(buf, &len); + app_close_frame.store(buf, &len, 32); CHECK(len == 9); CHECK(memcmp(buf, expected1, len) == 0); } @@ -701,7 +732,7 @@ TEST_CASE("Store ApplicationClose Frame", "[quic]") QUICApplicationCloseFrame app_close_frame(static_cast(0x01), 0, nullptr); CHECK(app_close_frame.size() == 4); - app_close_frame.store(buf, &len); + app_close_frame.store(buf, &len, 32); CHECK(len == 4); CHECK(memcmp(buf, expected2, len) == 0); } @@ -733,7 +764,7 @@ TEST_CASE("Store MaxData Frame", "[quic]") QUICMaxDataFrame max_data_frame(0x1122334455667788); CHECK(max_data_frame.size() == 9); - max_data_frame.store(buf, &len); + max_data_frame.store(buf, &len, 65535); CHECK(len == 9); CHECK(memcmp(buf, expected, len) == 0); } @@ -768,7 +799,7 @@ TEST_CASE("Store MaxStreamData Frame", "[quic]") QUICMaxStreamDataFrame max_stream_data_frame(0x01020304, 0x1122334455667788ULL); CHECK(max_stream_data_frame.size() == 13); - max_stream_data_frame.store(buf, &len); + max_stream_data_frame.store(buf, &len, 65535); CHECK(len == 13); CHECK(memcmp(buf, expected, len) == 0); } @@ -799,7 +830,7 @@ TEST_CASE("Store MaxStreamId Frame", "[quic]") QUICMaxStreamIdFrame max_stream_id_frame(0x01020304); CHECK(max_stream_id_frame.size() == 5); - max_stream_id_frame.store(buf, &len); + max_stream_id_frame.store(buf, &len, 65535); CHECK(len == 5); CHECK(memcmp(buf, expected, len) == 0); } @@ -830,7 +861,7 @@ TEST_CASE("Store Blocked Frame", "[quic]") QUICBlockedFrame blocked_stream_frame(0x07); CHECK(blocked_stream_frame.size() == 2); - blocked_stream_frame.store(buf, &len); + blocked_stream_frame.store(buf, &len, 65535); CHECK(len == 2); CHECK(memcmp(buf, expected, len) == 0); } @@ -865,7 +896,7 @@ TEST_CASE("Store StreamBlocked Frame", "[quic]") QUICStreamBlockedFrame stream_blocked_frame(0x01020304, 0x07); CHECK(stream_blocked_frame.size() == 6); - stream_blocked_frame.store(buf, &len); + stream_blocked_frame.store(buf, &len, 65535); CHECK(len == 6); CHECK(memcmp(buf, expected, len) == 0); } @@ -897,7 +928,7 @@ TEST_CASE("Store StreamIdBlocked Frame", "[quic]") QUICStreamIdBlockedFrame stream_id_blocked_frame(0x0102); CHECK(stream_id_blocked_frame.size() == 3); - stream_id_blocked_frame.store(buf, &len); + stream_id_blocked_frame.store(buf, &len, 65535); CHECK(len == 3); CHECK(memcmp(buf, expected, len) == 0); } @@ -941,7 +972,7 @@ TEST_CASE("Store NewConnectionId Frame", "[quic]") {expected + 12}); CHECK(new_con_id_frame.size() == 28); - new_con_id_frame.store(buf, &len); + new_con_id_frame.store(buf, &len, 32); CHECK(len == 28); CHECK(memcmp(buf, expected, len) == 0); } @@ -976,7 +1007,7 @@ TEST_CASE("Store STOP_SENDING Frame", "[quic]") QUICStopSendingFrame stop_sending_frame(0x12345678, static_cast(0x01)); CHECK(stop_sending_frame.size() == 7); - stop_sending_frame.store(buf, &len); + stop_sending_frame.store(buf, &len, 65535); CHECK(len == 7); CHECK(memcmp(buf, expected, len) == 0); } @@ -1015,7 +1046,7 @@ TEST_CASE("Store PATH_CHALLENGE Frame", "[quic]") QUICPathChallengeFrame frame(std::move(data), QUICPathChallengeFrame::DATA_LEN); CHECK(frame.size() == 9); - frame.store(buf, &len); + frame.store(buf, &len, 16); CHECK(len == 9); CHECK(memcmp(buf, expected, len) == 0); } @@ -1053,7 +1084,7 @@ TEST_CASE("Store PATH_RESPONSE Frame", "[quic]") QUICPathResponseFrame frame(std::move(data), QUICPathResponseFrame::DATA_LEN); CHECK(frame.size() == 9); - frame.store(buf, &len); + frame.store(buf, &len, 16); CHECK(len == 9); CHECK(memcmp(buf, expected, len) == 0); } @@ -1160,7 +1191,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 8); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1180,7 +1211,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 15); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1200,7 +1231,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 9); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1220,7 +1251,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 9); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1238,7 +1269,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 9); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1257,7 +1288,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 13); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1275,7 +1306,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 5); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1292,7 +1323,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 1); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1310,7 +1341,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 2); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1329,7 +1360,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 6); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1347,7 +1378,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 3); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1369,7 +1400,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 28); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1388,7 +1419,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 7); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1406,7 +1437,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 9); CHECK(memcmp(buf, frame_buf, len) == 0); @@ -1424,7 +1455,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t buf[32] = {0}; size_t len; - frame->store(buf, &len); + frame->store(buf, &len, 32); CHECK(len == 9); CHECK(memcmp(buf, frame_buf, len) == 0); From e1cc18fbc445d36d27df39acc1adf7e76b904713 Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 16 May 2018 15:09:41 +0800 Subject: [PATCH 0558/1313] [QUIC] Fixs the compiler error with c++17 --- iocore/net/quic/QUICAckFrameCreator.cc | 1 + iocore/net/quic/QUICCongestionController.cc | 4 ++-- iocore/net/quic/QUICLossDetector.cc | 8 ++++---- iocore/net/quic/QUICLossDetector.h | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 45792ebfbf4..931d3f4b5a9 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -113,6 +113,7 @@ QUICAckFrameCreator::_create_ack_frame() uint64_t delay = this->_calculate_delay(); ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, protection); } + return ack_frame; } diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 89910175980..9a756d8a4dc 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -85,11 +85,11 @@ QUICCongestionController::on_packet_acked(QUICPacketNumber acked_packet_number, } void -QUICCongestionController::on_packets_lost(std::map lost_packets) +QUICCongestionController::on_packets_lost(std::map &lost_packets) { // Remove lost packets from bytes_in_flight. for (auto &lost_packet : lost_packets) { - this->_bytes_in_flight -= lost_packet.second.bytes; + this->_bytes_in_flight -= lost_packet.second->bytes; } QUICPacketNumber largest_lost_packet = lost_packets.rbegin()->first; // Start a new recovery epoch if the lost packet is larger diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 6ec69aa8558..e58fce22139 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -368,7 +368,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); this->_loss_time = 0; - std::map lost_packets; + std::map lost_packets; double delay_until_lost = INFINITY; if (this->_k_using_time_loss_detection) { @@ -388,11 +388,11 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num QUICLDDebug("Lost: time since sent is too long (sent=%" PRId64 ", delay=%lf, fraction=%lf, lrtt=%" PRId64 ", srtt=%" PRId64 ")", time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, this->_smoothed_rtt); - lost_packets.insert({unacked.first, *unacked.second}); + lost_packets.insert({unacked.first, unacked.second.get()}); } else if (packet_delta > this->_reordering_threshold) { QUICLDDebug("Lost: packet delta is too large (largest=%" PRId64 " unacked=%" PRId64 " threshold=%" PRId32 ")", largest_acked_packet_number, unacked.second->packet_number, this->_reordering_threshold); - lost_packets.insert({unacked.first, *unacked.second}); + lost_packets.insert({unacked.first, unacked.second.get()}); } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) { this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent; } @@ -407,7 +407,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num // Not sure how we can get feedback from congestion control and when we should retransmit the lost packets but we need to send // them somewhere. // I couldn't find the place so just send them here for now. - this->_retransmit_lost_packet(*lost_packet.second.packet); + this->_retransmit_lost_packet(*lost_packet.second->packet); // END OF ADDITIONAL CODE this->_remove_from_sent_packet_list(lost_packet.first); } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 92960888eb8..c44872753d2 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -62,7 +62,7 @@ class QUICCongestionController virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); void on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size); - virtual void on_packets_lost(std::map packets); + virtual void on_packets_lost(std::map &packets); void on_retransmission_timeout_verified(); bool check_credit() const; From cc560cf271f0f6f0cadd56f6b992ee24d48c0807 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 21 May 2018 14:03:47 +0900 Subject: [PATCH 0559/1313] Set ALPN ext for quic client --- iocore/net/quic/QUICConfig.cc | 6 +++++- iocore/net/quic/QUICTypes.h | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 8b759937f6c..bd6294b2d04 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -24,6 +24,7 @@ #include "QUICConfig.h" #include + #include #include "P_SSLConfig.h" @@ -88,7 +89,10 @@ quic_init_client_ssl_ctx(const QUICConfigParams *params) { SSL_CTX *ssl_ctx = quic_new_ssl_ctx(); - // SSL_CTX_set_alpn_protos() + if (SSL_CTX_set_alpn_protos(ssl_ctx, reinterpret_cast(QUIC_ALPN_PROTO_LIST.data()), + QUIC_ALPN_PROTO_LIST.size()) != 0) { + Error("SSL_CTX_set_alpn_protos failed"); + } if (params->client_supported_groups() != nullptr) { if (SSL_CTX_set1_groups_list(ssl_ctx, params->client_supported_groups()) != 1) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 552b6857cfb..715b37c6d40 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -53,6 +53,11 @@ constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; constexpr QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; +// OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings) +// https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html +// Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? +constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-11"sv); + enum class QUICHandshakeMsgType { NONE = 0, INITIAL, From a0f579e882224e8945b29f898b83fe900250512a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 21 May 2018 14:29:18 +0900 Subject: [PATCH 0560/1313] Fix debug message when storing frame --- iocore/net/QUICNetVConnection.cc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 525f129c5ba..5d659b6d253 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1117,23 +1117,27 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans buf = ats_unique_malloc(max_size); } - size_t l = 0; + ink_assert(max_size > len); - // TODO: check debug build char msg[1024]; - QUICConDebug("[TX] %s", msg); - - ink_assert(max_size > len); + size_t l = 0; size_t n = frame->store(buf.get() + len, &l, max_size - len); if (n > 0) { + // TODO: check debug build frame->debug_msg(msg, sizeof(msg)); + QUICConDebug("[TX] %s", msg); + len += l; return; } // split frame auto new_frame = QUICFrameFactory::split_frame(frame.get(), max_size - len); + + // TODO: check debug build frame->debug_msg(msg, sizeof(msg)); + QUICConDebug("[TX] %s", msg); + ink_assert(frame->store(buf.get() + len, &l, max_size - len) > 0); ink_assert(new_frame != nullptr); From 433fa5b6a9e2ebab48dd71de5560fe988013ebae Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 22 May 2018 16:48:58 +0900 Subject: [PATCH 0561/1313] Fix tests --- iocore/net/quic/Mock.h | 2 +- iocore/net/quic/test/test_QUICFrameDispatcher.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 839bcfe5ccd..b11eac63c45 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -315,7 +315,7 @@ class MockQUICCongestionController : public QUICCongestionController public: // Override virtual void - on_packets_lost(std::map packets) override + on_packets_lost(std::map &packets) override { for (auto &p : packets) { lost_packets.insert(p.first); diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 5d90c777562..d307d29e13d 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -50,7 +50,7 @@ TEST_CASE("QUICFrameHandler", "[quic]") // STREAM frame uint8_t buf[4096] = {0}; size_t len = 0; - streamFrame.store(buf, &len); + streamFrame.store(buf, &len, 4096); bool should_send_ack; quicFrameDispatcher.receive_frames(buf, len, should_send_ack); CHECK(connection->getTotalFrameCount() == 0); @@ -58,7 +58,7 @@ TEST_CASE("QUICFrameHandler", "[quic]") // CONNECTION_CLOSE frame QUICConnectionCloseFrame connectionCloseFrame({}); - connectionCloseFrame.store(buf, &len); + connectionCloseFrame.store(buf, &len, 4096); quicFrameDispatcher.receive_frames(buf, len, should_send_ack); CHECK(connection->getTotalFrameCount() == 1); CHECK(streamManager->getTotalFrameCount() == 1); From 7b3a66fda73336af6fa47b3c46080bd8756e8510 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 May 2018 16:14:59 +0900 Subject: [PATCH 0562/1313] Set nbytes when total stream data length become clear To indicate FIN flag beween QUICStream and QUICApplication. This is similar to processing chunked transfer encoding. Mark VIO wrapper apis in QUICStreamIO as deprecated. QUICApplications should use read/write/reenable apis. --- cmd/traffic_quic/quic_client.cc | 7 +- iocore/net/quic/QUICApplication.cc | 107 +++++++++++++++++++---------- iocore/net/quic/QUICApplication.h | 31 ++++++--- iocore/net/quic/QUICStream.cc | 40 +++-------- iocore/net/quic/QUICStream.h | 6 -- proxy/hq/HQClientTransaction.cc | 8 +-- proxy/hq/HQFrameCollector.cc | 2 +- proxy/hq/QUICSimpleApp.cc | 2 +- 8 files changed, 114 insertions(+), 89 deletions(-) diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc index a39d160adb1..da435832f2a 100644 --- a/cmd/traffic_quic/quic_client.cc +++ b/cmd/traffic_quic/quic_client.cc @@ -147,7 +147,7 @@ QUICClientApp::start(const char *path) QUICStreamIO *stream_io = this->_find_stream_io(stream_id); stream_io->write(reinterpret_cast(request), request_len); - stream_io->shutdown(); + stream_io->write_done(); stream_io->write_reenable(); } @@ -191,6 +191,11 @@ QUICClientApp::main_event_handler(int event, Event *data) std::cout.rdbuf(default_stream); } + if (stream_io->is_read_done()) { + // Connection Close Exercise + this->_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::NO_ERROR, "Close Exercise"))); + } + break; } case VC_EVENT_WRITE_READY: diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index b6b4b98aa41..cd178f0105e 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -34,31 +34,41 @@ QUICStreamIO::QUICStreamIO(QUICApplication *app, QUICStream *stream) : _stream(s this->_read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); this->_write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); - this->_read_buffer_reader = _read_buffer->alloc_reader(); - this->_write_buffer_reader = _write_buffer->alloc_reader(); + this->_read_buffer_reader = this->_read_buffer->alloc_reader(); + this->_write_buffer_reader = this->_write_buffer->alloc_reader(); this->_read_vio = stream->do_io_read(app, INT64_MAX, this->_read_buffer); this->_write_vio = stream->do_io_write(app, INT64_MAX, this->_write_buffer_reader); } -int64_t -QUICStreamIO::read_avail() +QUICStreamIO::~QUICStreamIO() { - return this->_read_buffer_reader->read_avail(); -} + // All readers will be deallocated + free_MIOBuffer(this->_read_buffer); + free_MIOBuffer(this->_write_buffer); +}; -bool -QUICStreamIO::is_read_avail_more_than(int64_t size) +uint32_t +QUICStreamIO::stream_id() const { - return this->_read_buffer_reader->is_read_avail_more_than(size); + return this->_stream->id(); } int64_t QUICStreamIO::read(uint8_t *buf, int64_t len) { - int64_t read_len = this->_read_buffer_reader->read(const_cast(buf), len); - this->_read_vio->ndone += read_len; - return read_len; + int64_t nread = this->_read_buffer_reader->read(const_cast(buf), len); + if (nread > 0) { + this->_read_vio->ndone += nread; + } + + return nread; +} + +bool +QUICStreamIO::is_read_done() +{ + return this->_read_vio->ntodo() == 0; } int64_t @@ -66,32 +76,71 @@ QUICStreamIO::write(const uint8_t *buf, int64_t len) { SCOPED_MUTEX_LOCK(lock, this->_write_vio->mutex, this_ethread()); - return this->_write_buffer->write(buf, len); -} + int64_t nwritten = this->_write_buffer->write(buf, len); + if (nwritten > 0) { + this->_nwritten += nwritten; + } -int64_t -QUICStreamIO::write_avail() -{ - return this->_write_buffer->write_avail(); + return len; } int64_t -QUICStreamIO::write(IOBufferReader *r, int64_t alen, int64_t offset) +QUICStreamIO::write(IOBufferReader *r, int64_t len) { SCOPED_MUTEX_LOCK(lock, this->_write_vio->mutex, this_ethread()); int64_t bytes_avail = this->_write_buffer->write_avail(); - Debug(tag, "nbytes=%" PRId64 " ndone=%" PRId64 " write_avail=%" PRId64 " write_len=%" PRId64, this->_write_vio->nbytes, - this->_write_vio->ndone, bytes_avail, alen); if (bytes_avail > 0) { - int64_t len = std::min(bytes_avail, alen); - return this->_write_buffer->write(r, len, offset); + Debug(tag, "nbytes=%" PRId64 " ndone=%" PRId64 " write_avail=%" PRId64 " write_len=%" PRId64, this->_write_vio->nbytes, + this->_write_vio->ndone, bytes_avail, len); + + int64_t bytes_len = std::min(bytes_avail, len); + int64_t nwritten = this->_write_buffer->write(r, bytes_len); + + if (nwritten > 0) { + this->_nwritten += nwritten; + } + + return nwritten; } else { return 0; } } +// TODO: Similar to other "write" apis, but do not copy. +int64_t +QUICStreamIO::write(IOBufferBlock *b) +{ + ink_assert(!"not implemented yet"); + return 0; +} + +void +QUICStreamIO::write_done() +{ + this->_write_vio->nbytes = this->_nwritten; +} + +// !!! DEPRECATED !!! +int64_t +QUICStreamIO::read_avail() +{ + return this->_read_buffer_reader->read_avail(); +} + +bool +QUICStreamIO::is_read_avail_more_than(int64_t size) +{ + return this->_read_buffer_reader->is_read_avail_more_than(size); +} + +int64_t +QUICStreamIO::write_avail() +{ + return this->_write_buffer->write_avail(); +} + void QUICStreamIO::set_write_vio_nbytes(int64_t nbytes) { @@ -116,18 +165,6 @@ QUICStreamIO::get_read_buffer_reader() return this->_read_buffer_reader; } -void -QUICStreamIO::shutdown() -{ - return this->_stream->shutdown(); -} - -uint32_t -QUICStreamIO::get_transaction_id() const -{ - return this->_stream->id(); -} - // // QUICApplication // diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index eef90a0923e..e9b8e4c8f92 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -32,26 +32,31 @@ class QUICApplication; /** - * @brief QUICStream I/O interface from QUIC Application + @brief QUICStream I/O Interface for QUICApplication */ class QUICStreamIO { public: QUICStreamIO(QUICApplication *app, QUICStream *stream); - virtual ~QUICStreamIO(){}; + virtual ~QUICStreamIO(); + + uint32_t stream_id() const; - int64_t read_avail(); - bool is_read_avail_more_than(int64_t size); int64_t read(uint8_t *buf, int64_t len); - int64_t write_avail(); - int64_t write(const uint8_t *buf, int64_t len); - int64_t write(IOBufferReader *r, int64_t len = INT64_MAX, int64_t offset = 0); - void set_write_vio_nbytes(int64_t); + bool is_read_done(); virtual void read_reenable(); + + int64_t write(const uint8_t *buf, int64_t len); + int64_t write(IOBufferReader *r, int64_t len); + int64_t write(IOBufferBlock *b); + void write_done(); virtual void write_reenable(); - IOBufferReader *get_read_buffer_reader(); - void shutdown(); - uint32_t get_transaction_id() const; + + [[deprecated]] int64_t read_avail(); + [[deprecated]] bool is_read_avail_more_than(int64_t size); + [[deprecated]] int64_t write_avail(); + [[deprecated]] void set_write_vio_nbytes(int64_t); + [[deprecated]] IOBufferReader *get_read_buffer_reader(); protected: MIOBuffer *_read_buffer = nullptr; @@ -65,6 +70,10 @@ class QUICStreamIO VIO *_read_vio = nullptr; VIO *_write_vio = nullptr; + + // Track how much data is written to _write_vio. When total size of data become clear, + // set it to _write_vio.nbytes. + uint64_t _nwritten = 0; }; /** diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index c4ac423c29c..f2142c02270 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -184,6 +184,7 @@ QUICStream::state_stream_closed(int event, void *data) return EVENT_DONE; } +// this->_read_vio.nbytes should be INT64_MAX until receive FIN flag VIO * QUICStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) { @@ -271,26 +272,18 @@ QUICStream::reenable(VIO *vio) } } -void -QUICStream::set_read_vio_nbytes(int64_t nbytes) -{ - this->_read_vio.nbytes = nbytes; -} - -void -QUICStream::set_write_vio_nbytes(int64_t nbytes) -{ - this->_write_vio.nbytes = nbytes; -} - void QUICStream::_write_to_read_vio(const std::shared_ptr &frame) { SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); - int bytes_added = this->_read_vio.buffer.writer()->write(frame->data(), frame->data_length()); - this->_read_vio.nbytes += bytes_added; - // frame->offset() + frame->data_length() == this->_recv_offset + uint64_t bytes_added = this->_read_vio.buffer.writer()->write(frame->data(), frame->data_length()); + + // Until receive FIN flag, keep nbytes INT64_MAX + if (frame->has_fin_flag() && bytes_added == frame->data_length()) { + this->_read_vio.nbytes = frame->offset() + frame->data_length(); + } + this->_local_flow_controller.forward_limit(frame->offset() + frame->data_length() + this->_flow_control_buffer_size); QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), this->_local_flow_controller.current_limit()); @@ -408,8 +401,9 @@ QUICStream::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_si len = std::min(data_len, static_cast( std::min(static_cast(maximum_frame_size), std::min(this->_remote_flow_controller.credit(), static_cast(connection_credit))))); - if (len >= bytes_avail) { - fin = this->_fin; + + if (this->_write_vio.ntodo() == bytes_avail) { + fin = true; } if (len > 0) { @@ -559,18 +553,6 @@ QUICStream::reset(QUICStreamErrorUPtr error) this->_reset_reason = std::move(error); } -void -QUICStream::shutdown() -{ - this->_fin = true; -} - -size_t -QUICStream::nbytes_to_read() -{ - return this->_read_vio.ntodo(); -} - QUICOffset QUICStream::largest_offset_received() { diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index c7cc01260e0..99c501c27ef 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -74,8 +74,6 @@ class QUICStream : public VConnection, public QUICFrameGenerator void do_io_close(int lerrno = -1) override; void do_io_shutdown(ShutdownHowTo_t howto) override; void reenable(VIO *vio) override; - void set_read_vio_nbytes(int64_t); - void set_write_vio_nbytes(int64_t); QUICErrorUPtr recv(const std::shared_ptr frame); QUICErrorUPtr recv(const std::shared_ptr frame); @@ -83,9 +81,6 @@ class QUICStream : public VConnection, public QUICFrameGenerator QUICErrorUPtr recv(const std::shared_ptr frame); void reset(QUICStreamErrorUPtr error); - void shutdown(); - - size_t nbytes_to_read(); QUICOffset largest_offset_received(); QUICOffset largest_offset_sent(); @@ -106,7 +101,6 @@ class QUICStream : public VConnection, public QUICFrameGenerator void _write_to_read_vio(const std::shared_ptr &); QUICStreamState _state; - bool _fin = false; QUICStreamErrorUPtr _reset_reason = nullptr; QUICConnectionId _connection_id = QUICConnectionId::ZERO(); QUICStreamId _id = 0; diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 3574b65012d..13ad9f64ca3 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -494,9 +494,6 @@ HQClientTransaction::_process_write_vio() int64_t headers_size = headers->read_avail(); reader->consume(headers_size); this->_write_vio.ndone += headers_size; - - // The size of respons to client - this->_stream_io->set_write_vio_nbytes(this->_write_vio.nbytes - headers_size); } // Write HTTP/1.1 response body @@ -520,7 +517,8 @@ HQClientTransaction::_process_write_vio() // NOTE: When Chunked Transfer Coding is supported, check ChunkedState of ChunkedHandler // is CHUNK_READ_DONE and set FIN flag if (this->_write_vio.ntodo() == 0) { - this->_stream_io->shutdown(); + // The size of respons to client + this->_stream_io->write_done(); } return total_written; @@ -541,7 +539,7 @@ HQClientTransaction::transaction_done() int HQClientTransaction::get_transaction_id() const { - return this->_stream_io->get_transaction_id(); + return this->_stream_io->stream_id(); } bool diff --git a/proxy/hq/HQFrameCollector.cc b/proxy/hq/HQFrameCollector.cc index f3165245fce..c19ca194e77 100644 --- a/proxy/hq/HQFrameCollector.cc +++ b/proxy/hq/HQFrameCollector.cc @@ -49,7 +49,7 @@ HQFrameCollector::on_write_ready(QUICStreamIO *stream_io, size_t &nwritten) } if (all_done) { - stream_io->shutdown(); + stream_io->write_done(); } return HQErrorUPtr(new HQNoError()); diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index b06821daba3..8ce397edd46 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -65,7 +65,7 @@ QUICSimpleApp::main_event_handler(int event, Event *data) return -1; } - QUICStreamId stream_id = stream_io->get_transaction_id(); + QUICStreamId stream_id = stream_io->stream_id(); HQClientTransaction *txn = this->_client_session->get_transaction(stream_id); switch (event) { From f045cc7797ea8846b5e376832267f5fc8bdd7b81 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 25 May 2018 09:21:15 +0900 Subject: [PATCH 0563/1313] Remove prepended "_" from public member of VIO in QUIC --- iocore/net/quic/QUICStream.cc | 28 ++++++++++++++-------------- proxy/hq/HQClientTransaction.cc | 28 ++++++++++++++-------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index f2142c02270..a67f226cab3 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -195,7 +195,7 @@ QUICStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) } this->_read_vio.mutex = c ? c->mutex : this->mutex; - this->_read_vio._cont = c; + this->_read_vio.cont = c; this->_read_vio.nbytes = nbytes; this->_read_vio.ndone = 0; this->_read_vio.vc_server = this; @@ -217,7 +217,7 @@ QUICStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bo } this->_write_vio.mutex = c ? c->mutex : this->mutex; - this->_write_vio._cont = c; + this->_write_vio.cont = c; this->_write_vio.nbytes = nbytes; this->_write_vio.ndone = 0; this->_write_vio.vc_server = this; @@ -237,12 +237,12 @@ QUICStream::do_io_close(int lerrno) this->_read_vio.buffer.clear(); this->_read_vio.nbytes = 0; this->_read_vio.op = VIO::NONE; - this->_read_vio._cont = nullptr; + this->_read_vio.cont = nullptr; this->_write_vio.buffer.clear(); this->_write_vio.nbytes = 0; this->_write_vio.op = VIO::NONE; - this->_write_vio._cont = nullptr; + this->_write_vio.cont = nullptr; } void @@ -476,12 +476,12 @@ QUICStream::_send_tracked_event(Event *event, int send_event, VIO *vio) } /** - * @brief Signal event to this->_read_vio._cont + * @brief Signal event to this->_read_vio.cont */ void QUICStream::_signal_read_event() { - if (this->_read_vio._cont == nullptr || this->_read_vio.op == VIO::NONE) { + if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return; } MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread()); @@ -489,21 +489,21 @@ QUICStream::_signal_read_event() int event = this->_read_vio.ntodo() ? VC_EVENT_READ_READY : VC_EVENT_READ_COMPLETE; if (lock.is_locked()) { - this->_read_vio._cont->handleEvent(event, &this->_read_vio); + this->_read_vio.cont->handleEvent(event, &this->_read_vio); } else { - this_ethread()->schedule_imm(this->_read_vio._cont, event, &this->_read_vio); + this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio); } QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); } /** - * @brief Signal event to this->_write_vio._cont + * @brief Signal event to this->_write_vio.cont */ void QUICStream::_signal_write_event() { - if (this->_write_vio._cont == nullptr || this->_write_vio.op == VIO::NONE) { + if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { return; } MUTEX_TRY_LOCK(lock, this->_write_vio.mutex, this_ethread()); @@ -511,9 +511,9 @@ QUICStream::_signal_write_event() int event = this->_write_vio.ntodo() ? VC_EVENT_WRITE_READY : VC_EVENT_WRITE_COMPLETE; if (lock.is_locked()) { - this->_write_vio._cont->handleEvent(event, &this->_write_vio); + this->_write_vio.cont->handleEvent(event, &this->_write_vio); } else { - this_ethread()->schedule_imm(this->_write_vio._cont, event, &this->_write_vio); + this_ethread()->schedule_imm(this->_write_vio.cont, event, &this->_write_vio); } QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); @@ -522,7 +522,7 @@ QUICStream::_signal_write_event() int64_t QUICStream::_process_read_vio() { - if (this->_read_vio._cont == nullptr || this->_read_vio.op == VIO::NONE) { + if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return 0; } @@ -540,7 +540,7 @@ QUICStream::_process_read_vio() int64_t QUICStream::_process_write_vio() { - if (this->_write_vio._cont == nullptr || this->_write_vio.op == VIO::NONE) { + if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { return 0; } diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 13ad9f64ca3..6766b2ccefb 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -215,7 +215,7 @@ HQClientTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) } this->_read_vio.mutex = c ? c->mutex : this->mutex; - this->_read_vio._cont = c; + this->_read_vio.cont = c; this->_read_vio.nbytes = nbytes; this->_read_vio.ndone = 0; this->_read_vio.vc_server = this; @@ -237,7 +237,7 @@ HQClientTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader } this->_write_vio.mutex = c ? c->mutex : this->mutex; - this->_write_vio._cont = c; + this->_write_vio.cont = c; this->_write_vio.nbytes = nbytes; this->_write_vio.ndone = 0; this->_write_vio.vc_server = this; @@ -267,12 +267,12 @@ HQClientTransaction::do_io_close(int lerrno) this->_read_vio.buffer.clear(); this->_read_vio.nbytes = 0; this->_read_vio.op = VIO::NONE; - this->_read_vio._cont = nullptr; + this->_read_vio.cont = nullptr; this->_write_vio.buffer.clear(); this->_write_vio.nbytes = 0; this->_write_vio.op = VIO::NONE; - this->_write_vio._cont = nullptr; + this->_write_vio.cont = nullptr; parent->do_io_close(lerrno); } @@ -342,42 +342,42 @@ HQClientTransaction::destroy() } /** - * @brief Signal event to this->_read_vio._cont + * @brief Signal event to this->_read_vio.cont */ void HQClientTransaction::_signal_read_event() { - if (this->_read_vio._cont == nullptr || this->_read_vio.op == VIO::NONE) { + if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return; } int event = this->_read_vio.ntodo() ? VC_EVENT_READ_READY : VC_EVENT_READ_COMPLETE; MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread()); if (lock.is_locked()) { - this->_read_vio._cont->handleEvent(event, &this->_read_vio); + this->_read_vio.cont->handleEvent(event, &this->_read_vio); } else { - this_ethread()->schedule_imm(this->_read_vio._cont, event, &this->_read_vio); + this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio); } HQTransDebug("%s (%d)", get_vc_event_name(event), event); } /** - * @brief Signal event to this->_write_vio._cont + * @brief Signal event to this->_write_vio.cont */ void HQClientTransaction::_signal_write_event() { - if (this->_write_vio._cont == nullptr || this->_write_vio.op == VIO::NONE) { + if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { return; } int event = this->_write_vio.ntodo() ? VC_EVENT_WRITE_READY : VC_EVENT_WRITE_COMPLETE; MUTEX_TRY_LOCK(lock, this->_write_vio.mutex, this_ethread()); if (lock.is_locked()) { - this->_write_vio._cont->handleEvent(event, &this->_write_vio); + this->_write_vio.cont->handleEvent(event, &this->_write_vio); } else { - this_ethread()->schedule_imm(this->_write_vio._cont, event, &this->_write_vio); + this_ethread()->schedule_imm(this->_write_vio.cont, event, &this->_write_vio); } HQTransDebug("%s (%d)", get_vc_event_name(event), event); @@ -387,7 +387,7 @@ HQClientTransaction::_signal_write_event() int64_t HQClientTransaction::_process_read_vio() { - if (this->_read_vio._cont == nullptr || this->_read_vio.op == VIO::NONE) { + if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return 0; } @@ -466,7 +466,7 @@ static constexpr char http_1_1_version[] = "HTTP/1.1"; int64_t HQClientTransaction::_process_write_vio() { - if (this->_write_vio._cont == nullptr || this->_write_vio.op == VIO::NONE) { + if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { return 0; } From 73e3f9cc0eb4e866717d8c0319647cfc2305adbf Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 25 May 2018 12:31:56 +0900 Subject: [PATCH 0564/1313] Ignore VN when version is already negotiated --- iocore/net/QUICNetVConnection.cc | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5d659b6d253..011f43a2921 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -830,17 +830,21 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack return error; } - error = this->_handshake_handler->negotiate_version(packet.get(), &this->_packet_factory); + if (this->_handshake_handler->is_version_negotiated()) { + QUICConDebug("ignore VN - already negotiated"); + } else { + error = this->_handshake_handler->negotiate_version(packet.get(), &this->_packet_factory); - // discard all transport state except packet number - this->_stream_manager->reset_send_offset(); - this->_stream_manager->reset_recv_offset(); - this->_loss_detector->reset(); + // discard all transport state except packet number + this->_stream_manager->reset_send_offset(); + this->_stream_manager->reset_recv_offset(); + this->_loss_detector->reset(); - // start handshake over - this->_handshake_handler->reset(); - this->_handshake_handler->handleEvent(VC_EVENT_WRITE_READY, nullptr); - this->_schedule_packet_write_ready(); + // start handshake over + this->_handshake_handler->reset(); + this->_handshake_handler->handleEvent(VC_EVENT_WRITE_READY, nullptr); + this->_schedule_packet_write_ready(); + } return error; } From 26a4682b8028deaf663c38b3e5c854aebd961cfd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 25 May 2018 15:07:22 +0900 Subject: [PATCH 0565/1313] Add debug message of QUICRetransmissionFrame --- iocore/net/quic/QUICFrame.cc | 6 ++++++ iocore/net/quic/QUICFrame.h | 1 + 2 files changed, 7 insertions(+) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 1cc10009dd5..8cf0c4fb875 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1959,6 +1959,12 @@ QUICRetransmissionFrame::store(uint8_t *buf, size_t *len, size_t limit) const return *len; } +int +QUICRetransmissionFrame::debug_msg(char *msg, size_t msg_len) const +{ + return snprintf(msg, msg_len, "type=%s size=%zu (retransmission)", QUICDebugNames::frame_type(this->type()), this->size()); +} + QUICPacketType QUICRetransmissionFrame::packet_type() const { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 94bbadb3961..72382f40de3 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -594,6 +594,7 @@ class QUICRetransmissionFrame : public QUICFrame QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet); virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual int debug_msg(char *msg, size_t msg_len) const override; QUICPacketType packet_type() const; private: From 4748395981d4171f2ed7af247aa095354ef557a6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 25 May 2018 16:34:52 +0900 Subject: [PATCH 0566/1313] 3733 --- iocore/net/P_OCSPStapling.h | 5 +++++ iocore/net/SSLUtils.cc | 7 +++++++ lib/ts/HashMD5.cc | 6 ++++++ proxy/InkAPI.cc | 2 ++ 4 files changed, 20 insertions(+) diff --git a/iocore/net/P_OCSPStapling.h b/iocore/net/P_OCSPStapling.h index 1078d8db241..007cc91bef9 100644 --- a/iocore/net/P_OCSPStapling.h +++ b/iocore/net/P_OCSPStapling.h @@ -23,8 +23,13 @@ #include +#ifdef OCSP_sendreq_new #define HAVE_OPENSSL_OCSP_STAPLING 1 +#endif + +#ifdef HAVE_OPENSSL_OCSP_STAPLING void ssl_stapling_ex_init(); bool ssl_stapling_init_cert(SSL_CTX *ctx, X509 *cert, const char *certname); void ocsp_update(); int ssl_callback_ocsp_stapling(SSL *); +#endif diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc index e82420f646f..710115b840b 100644 --- a/iocore/net/SSLUtils.cc +++ b/iocore/net/SSLUtils.cc @@ -888,7 +888,9 @@ void SSLPostConfigInitialize() { if (SSLConfigParams::engine_conf_file) { +#ifndef OPENSSL_IS_BORINGSSL ENGINE_load_dynamic(); +#endif OPENSSL_load_builtin_modules(); if (CONF_modules_load_file(SSLConfigParams::engine_conf_file, nullptr, 0) <= 0) { @@ -1504,9 +1506,14 @@ ssl_callback_info(const SSL *ssl, int where, int ret) #else #ifdef SSL3_ST_SR_CLNT_HELLO_A if (state == SSL3_ST_SR_CLNT_HELLO_A) { +#else +#ifdef SSL_ST_RENEGOTIATE + // This is for BoringSSL + if (state == SSL_ST_RENEGOTIATE) { #else if (state == TLS_ST_SR_CLNT_HELLO) { #endif +#endif #endif netvc->setSSLClientRenegotiationAbort(true); Debug("ssl", "ssl_callback_info trying to renegotiate from the client"); diff --git a/lib/ts/HashMD5.cc b/lib/ts/HashMD5.cc index c8b034095a9..e1fd6ecdd58 100644 --- a/lib/ts/HashMD5.cc +++ b/lib/ts/HashMD5.cc @@ -68,7 +68,13 @@ ATSHashMD5::size() const void ATSHashMD5::clear() { +#ifndef OPENSSL_IS_BORINGSSL int ret = EVP_MD_CTX_reset(ctx); +#else + // OpenSSL's EVP_MD_CTX_reset always returns 1 + int ret = 1; + EVP_MD_CTX_reset(ctx); +#endif ink_assert(ret == 1); ret = EVP_DigestInit_ex(ctx, EVP_md5(), nullptr); ink_assert(ret == 1); diff --git a/proxy/InkAPI.cc b/proxy/InkAPI.cc index b1bf3fe194e..c971f887108 100644 --- a/proxy/InkAPI.cc +++ b/proxy/InkAPI.cc @@ -9279,6 +9279,7 @@ TSSslServerContextCreate(TSSslX509 cert, const char *certname) SSLConfigParams *config = SSLConfig::acquire(); if (config != nullptr) { ret = reinterpret_cast(SSLCreateServerContext(config)); +#ifdef HAVE_OPENSSL_OCSP_STAPLING if (ret && SSLConfigParams::ssl_ocsp_enabled && cert && certname) { if (SSL_CTX_set_tlsext_status_cb(reinterpret_cast(ret), ssl_callback_ocsp_stapling)) { if (!ssl_stapling_init_cert(reinterpret_cast(ret), reinterpret_cast(cert), certname)) { @@ -9286,6 +9287,7 @@ TSSslServerContextCreate(TSSslX509 cert, const char *certname) } } } +#endif SSLConfig::release(config); } return ret; From a881476ddd08d321f7f5e758c9117dd5fe1bddf4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 28 May 2018 10:39:23 +0900 Subject: [PATCH 0567/1313] Update code for boringssl Still cannot compile. Don't see API for setting max_early_data --- iocore/net/quic/QUICConfig.cc | 2 + iocore/net/quic/QUICKeyGenerator.cc | 5 ++ iocore/net/quic/QUICKeyGenerator_boringssl.cc | 25 +++--- iocore/net/quic/QUICTLS.cc | 30 ++++++- iocore/net/quic/QUICTLS.h | 18 +---- iocore/net/quic/QUICTLS_boringssl.cc | 79 +++++++++++-------- 6 files changed, 95 insertions(+), 64 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index bd6294b2d04..fae2788e88a 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -44,8 +44,10 @@ quic_new_ssl_ctx() SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION); +#ifndef OPENSSL_IS_BORINGSSL // FIXME: OpenSSL (1.1.1-alpha) enable this option by default. But this shoule be removed when OpenSSL disable this by default. SSL_CTX_clear_options(ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +#endif SSL_CTX_set_max_early_data(ssl_ctx, UINT32_C(0xFFFFFFFF)); diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 5f97b58716b..701b0325761 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -163,8 +163,13 @@ int QUICKeyGenerator::_generate_0rtt_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, SSL *ssl, size_t length) { *out_len = length; +#ifndef OPENSSL_IS_BORINGSSL SSL_export_keying_material_early(ssl, out, *out_len, LABEL_FOR_CLIENT_0RTT_SECRET.data(), LABEL_FOR_CLIENT_0RTT_SECRET.length(), reinterpret_cast(""), 0); +#else + SSL_export_early_keying_material(ssl, out, *out_len, LABEL_FOR_CLIENT_0RTT_SECRET.data(), LABEL_FOR_CLIENT_0RTT_SECRET.length(), + reinterpret_cast(""), 0); +#endif return 0; } diff --git a/iocore/net/quic/QUICKeyGenerator_boringssl.cc b/iocore/net/quic/QUICKeyGenerator_boringssl.cc index 2f11aab60a5..22473281eb5 100644 --- a/iocore/net/quic/QUICKeyGenerator_boringssl.cc +++ b/iocore/net/quic/QUICKeyGenerator_boringssl.cc @@ -39,24 +39,21 @@ QUICKeyGenerator::_get_iv_len(const QUIC_EVP_CIPHER *cipher) const const QUIC_EVP_CIPHER * QUICKeyGenerator::_get_cipher_for_cleartext() const { - return EVP_aes_128_gcm(); return EVP_aead_aes_128_gcm(); } const QUIC_EVP_CIPHER * QUICKeyGenerator::_get_cipher_for_protected_packet(const SSL *ssl) const { - ink_assert(SSL_CIPHER_is_AEAD(ssl)); - - if (SSL_CIPHER_is_AES128GCM(ssl)) { + switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { + case TLS1_CK_AES_128_GCM_SHA256: return EVP_aead_aes_128_gcm(); - } else if ((cipher->algorithm_enc & 0x00000010L) != 0) { - // SSL_AES256GCM is 0x00000010L ( defined in `ssl/internal.h` ). - // There're no `SSL_CIPHER_is_AES256GCM(const SSL_CIPHER *cipher)`. + case TLS1_CK_AES_256_GCM_SHA384: return EVP_aead_aes_256_gcm(); - } else if (SSL_CIPHER_is_CHACHA20POLY1305(ssl)) { + case TLS1_CK_CHACHA20_POLY1305_SHA256: return EVP_aead_chacha20_poly1305(); - } else { + default: + ink_assert(false); return nullptr; } } @@ -65,14 +62,14 @@ QUICKeyGenerator::_get_cipher_for_protected_packet(const SSL *ssl) const const EVP_MD * QUICKeyGenerator::_get_handshake_digest(const SSL *ssl) const { - switch (ssl->algorithm_prf) { - case 0x2: - // SSL_HANDSHAKE_MAC_SHA256: + 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 0x4: - // SSL_HANDSHAKE_MAC_SHA384: + case TLS1_CK_AES_256_GCM_SHA384: return EVP_sha384(); default: + ink_assert(false); return nullptr; } } diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 76e9d3be1b7..cebfaaa32bb 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -81,7 +81,11 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint // Details in https://github.com/openssl/openssl/issues/5235 if (this->_stateless) { // process stateless retry +#ifndef OPENSSL_IS_BORINGSSL ret = SSL_stateless(this->_ssl); +#else + ink_assert(!"stateless retry is not available with boringssl"); +#endif if (ret > 0) { this->_stateless = false; this->_msg_type = QUICHandshakeMsgType::HANDSHAKE; @@ -95,7 +99,11 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint this->_early_data_processed = true; } +#ifndef OPENSSL_IS_BORINGSSL if (SSL_get_early_data_status(this->_ssl) == SSL_EARLY_DATA_ACCEPTED) { +#else + if (SSL_early_data_accepted(this->_ssl)) { +#endif Debug(tag, "Early data processed"); if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT)) { @@ -110,12 +118,17 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint } else { ret = SSL_connect(this->_ssl); +#ifndef OPENSSL_IS_BORINGSSL // FIXME: if SSL_get_state work well on server side, use this for distinction of HANDSHAKE and RERTY if (SSL_get_state(this->_ssl) == TLS_ST_CW_CLNT_HELLO) { this->_msg_type = QUICHandshakeMsgType::INITIAL; } else { this->_msg_type = QUICHandshakeMsgType::HANDSHAKE; } +#else + // No stateless retry support + this->_msg_type = QUICHandshakeMsgType::INITIAL; +#endif } if (ret < 0) { @@ -249,7 +262,8 @@ QUICTLS::_read_early_data() { uint8_t early_data[8]; size_t early_data_len = 0; - int ret = 0; +#ifndef OPENSSL_IS_BORINGSSL + int ret = 0; do { ERR_clear_error(); @@ -257,6 +271,14 @@ QUICTLS::_read_early_data() } while (ret == SSL_READ_EARLY_DATA_SUCCESS); return ret == SSL_READ_EARLY_DATA_FINISH ? 1 : 0; +#else + do { + ERR_clear_error(); + early_data_len = SSL_read(this->_ssl, early_data, sizeof(early_data)); + } while (SSL_in_early_data(this->_ssl)); + + return 1; +#endif } void @@ -309,7 +331,7 @@ QUICTLS::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, con Debug(tag, "Failed to encrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } - const EVP_CIPHER *aead = this->_get_evp_aead(phase); + const QUIC_EVP_CIPHER *aead = this->_get_evp_aead(phase); bool ret = _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, *km, aead, tag_len); if (!ret) { @@ -345,8 +367,8 @@ QUICTLS::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } - const EVP_CIPHER *aead = this->_get_evp_aead(phase); - bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, *km, aead, tag_len); + const QUIC_EVP_CIPHER *aead = this->_get_evp_aead(phase); + bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, *km, aead, tag_len); if (!ret) { Debug(tag, "Failed to decrypt a packet: pkt_num=%" PRIu64, pkt_num); } diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 0cbf52062ac..a221f9084bd 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -61,26 +61,14 @@ class QUICTLS : public QUICHandshakeProtocol QUICKeyGenerator _keygen_for_client = QUICKeyGenerator(QUICKeyGenerator::Context::CLIENT); QUICKeyGenerator _keygen_for_server = QUICKeyGenerator(QUICKeyGenerator::Context::SERVER); void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; -#ifdef OPENSSL_IS_BORINGSSL - const EVP_AEAD *_get_evp_aead() const; -#else - const EVP_CIPHER *_get_evp_aead(QUICKeyPhase phase) const; -#endif // OPENSSL_IS_BORINGSSL + const QUIC_EVP_CIPHER *_get_evp_aead(QUICKeyPhase phase) const; size_t _get_aead_tag_len(QUICKeyPhase phase) const; -#ifdef OPENSSL_IS_BORINGSSL - bool _encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const EVP_AEAD *aead, - size_t tag_len) const; - bool _decrypt(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 KeyMaterial &km, const EVP_AEAD *aead, size_t tag_len) const; -#else bool _encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const EVP_CIPHER *aead, + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead, size_t tag_len) const; bool _decrypt(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 KeyMaterial &km, const EVP_CIPHER *aead, size_t tag_len) const; -#endif // OPENSSL_IS_BORINGSSL + const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead, size_t tag_len) const; SSL *_ssl = nullptr; QUICPacketProtection *_client_pp = nullptr; diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc index de441b3cf79..081a12fd98d 100644 --- a/iocore/net/quic/QUICTLS_boringssl.cc +++ b/iocore/net/quic/QUICTLS_boringssl.cc @@ -32,49 +32,66 @@ static constexpr char tag[] = "quic_tls"; const EVP_AEAD * -QUICTLS::_get_evp_aead(const SSL_CIPHER *cipher) const +QUICTLS::_get_evp_aead(QUICKeyPhase phase) const { - ink_assert(SSL_CIPHER_is_AEAD(cipher)); - - if (SSL_CIPHER_is_AES128GCM(cipher)) { + if (phase == QUICKeyPhase::CLEARTEXT) { return EVP_aead_aes_128_gcm(); - } else if ((cipher->algorithm_enc & 0x00000010L) != 0) { - // SSL_AES256GCM is 0x00000010L ( defined in `ssl/internal.h` ). - // There're no `SSL_CIPHER_is_AES256GCM(const SSL_CIPHER *cipher)`. - return EVP_aead_aes_256_gcm(); - } else if (SSL_CIPHER_is_CHACHA20POLY1305(cipher)) { - return EVP_aead_chacha20_poly1305(); } else { - return nullptr; + const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); + if (cipher) { + switch (SSL_CIPHER_get_id(cipher)) { + case TLS1_CK_AES_128_GCM_SHA256: + return EVP_aead_aes_128_gcm(); + case TLS1_CK_AES_256_GCM_SHA384: + return EVP_aead_aes_256_gcm(); + case TLS1_CK_CHACHA20_POLY1305_SHA256: + return EVP_aead_chacha20_poly1305(); + default: + ink_assert(false); + return nullptr; + } + } else { + ink_assert(false); + return nullptr; + } } } size_t -QUICTLS::_get_aead_tag_len(const SSL_CIPHER * /* cipher */) const -{ - return EVP_AEAD_DEFAULT_TAG_LENGTH; -} - -int -QUICTLS::_hkdf_expand_label(uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label, - size_t label_len, const EVP_MD *digest) const +QUICTLS::_get_aead_tag_len(QUICKeyPhase phase) const { - uint8_t info[256] = {0}; - size_t info_len = 0; - _gen_info(info, info_len, label, label_len, dst_len); - return HKDF(dst, dst_len, digest, secret, secret_len, nullptr, 0, info, info_len); + if (phase == QUICKeyPhase::CLEARTEXT) { + return EVP_GCM_TLS_TAG_LEN; + } else { + const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); + if (cipher) { + switch (SSL_CIPHER_get_id(cipher)) { + case TLS1_CK_AES_128_GCM_SHA256: + case TLS1_CK_AES_256_GCM_SHA384: + return EVP_GCM_TLS_TAG_LEN; + case TLS1_CK_CHACHA20_POLY1305_SHA256: + return 16; + default: + ink_assert(false); + return -1; + } + } else { + ink_assert(false); + return -1; + } + } } bool QUICTLS::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, - size_t iv_len, size_t tag_len) const + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const EVP_AEAD *aead, + size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; - _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); + _gen_nonce(nonce, nonce_len, pkt_num, km.iv, km.iv_len); - EVP_AEAD_CTX *aead_ctx = EVP_AEAD_CTX_new(this->_aead, key, key_len, tag_len); + EVP_AEAD_CTX *aead_ctx = EVP_AEAD_CTX_new(aead, km.key, km.key_len, tag_len); if (!aead_ctx) { Debug(tag, "Failed to create EVP_AEAD_CTX"); return false; @@ -92,14 +109,14 @@ QUICTLS::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, co bool QUICTLS::_decrypt(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, size_t key_len, const uint8_t *iv, - size_t iv_len, size_t tag_len) const + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const EVP_AEAD *aead, + size_t tag_len) const { uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; size_t nonce_len = 0; - _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); + _gen_nonce(nonce, nonce_len, pkt_num, km.iv, km.iv_len); - EVP_AEAD_CTX *aead_ctx = EVP_AEAD_CTX_new(this->_aead, key, key_len, tag_len); + EVP_AEAD_CTX *aead_ctx = EVP_AEAD_CTX_new(aead, km.key, km.key_len, tag_len); if (!aead_ctx) { Debug(tag, "Failed to create EVP_AEAD_CTX"); return false; From fd837f81d9ab969b4202b805d370288e0ef75143 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 28 May 2018 12:07:54 +0900 Subject: [PATCH 0568/1313] Send PATH_CHALLENGE at the beginning on server side --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 32 +++++++++++++++++++++------- iocore/net/quic/QUICPathValidator.cc | 4 +++- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 8ee8358e723..8112b9c0122 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -316,6 +316,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub const std::shared_ptr &remote_tp); void _handle_error(QUICErrorUPtr error); QUICPacketUPtr _dequeue_recv_packet(QUICPacketCreationResult &result); + void _validate_new_path(); int _complete_handshake_if_possible(); void _switch_to_handshake_state(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 011f43a2921..0b5995e6add 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -212,6 +212,8 @@ QUICNetVConnection::start() this->_frame_dispatcher->add_handler(this->_stream_manager); this->_frame_dispatcher->add_handler(this->_loss_detector); this->_frame_dispatcher->add_handler(this->_path_validator); + + this->_validate_new_path(); } void @@ -602,7 +604,9 @@ QUICNetVConnection::state_connection_established(int event, Event *data) } case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: this->_close_path_validation_timeout(data); - this->_switch_to_close_state(); + if (!this->_path_validator->is_validated()) { + this->_switch_to_close_state(); + } break; case EVENT_IMMEDIATE: { // Start Immediate Close because of Idle Timeout @@ -637,7 +641,9 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) break; case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: this->_close_path_validation_timeout(data); - this->_switch_to_close_state(); + if (!this->_path_validator->is_validated()) { + this->_switch_to_close_state(); + } break; case QUIC_EVENT_CLOSING_TIMEOUT: this->_close_closing_timeout(data); @@ -668,7 +674,9 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) break; case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: this->_close_path_validation_timeout(data); - this->_switch_to_close_state(); + if (!this->_path_validator->is_validated()) { + this->_switch_to_close_state(); + } break; case QUIC_EVENT_CLOSING_TIMEOUT: this->_close_closing_timeout(data); @@ -690,6 +698,7 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) case QUIC_EVENT_SHUTDOWN: { this->_unschedule_packet_write_ready(); this->_unschedule_closing_timeout(); + this->_unschedule_path_validation_timeout(); this->_close_closed_event(data); this->next_inactivity_timeout_at = 0; this->next_activity_timeout_at = 0; @@ -945,11 +954,7 @@ QUICNetVConnection::_state_common_receive_packet() Connection con; con.setRemote(&p->from().sa); this->con.move(con); - this->_path_validator->validate(); - // Not sure how long we should wait. The spec says just "enough time". - // Use the same time amount as the closing timeout. - ink_hrtime rto = this->_loss_detector->current_rto_period(); - this->_schedule_path_validation_timeout(3 * rto); + this->_validate_new_path(); } else { // TODO Send some error? } @@ -1706,6 +1711,7 @@ void QUICNetVConnection::_switch_to_close_state() { this->_unschedule_closing_timeout(); + this->_unschedule_path_validation_timeout(); if (this->_complete_handshake_if_possible() != 0) { QUICConDebug("Switching state without handshake completion"); @@ -1723,3 +1729,13 @@ QUICNetVConnection::_handle_idle_timeout() // TODO: signal VC_EVENT_ACTIVE_TIMEOUT/VC_EVENT_INACTIVITY_TIMEOUT to application } + +void +QUICNetVConnection::_validate_new_path() +{ + this->_path_validator->validate(); + // Not sure how long we should wait. The spec says just "enough time". + // Use the same time amount as the closing timeout. + ink_hrtime rto = this->_loss_detector->current_rto_period(); + this->_schedule_path_validation_timeout(3 * rto); +} diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index 510131c65cd..a6039987ded 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -62,7 +62,9 @@ QUICPathValidator::_validate_response(std::shared_ptr_outgoing_challenge, frame->data(), QUICPathChallengeFrame::DATA_LEN) != 0) { + if (memcmp(this->_outgoing_challenge, frame->data(), QUICPathChallengeFrame::DATA_LEN) == 0) { + this->_state = ValidationState::VALIDATED; + } else { error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE)); } From 0fe2c9d808580a66eeaa07b29cf8ca9fad547df8 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 28 May 2018 15:33:01 +0800 Subject: [PATCH 0569/1313] [QUIC] split retransmit frame --- iocore/net/quic/QUICFrame.cc | 132 +++++++++++++++++++++---- iocore/net/quic/QUICFrame.h | 21 +++- iocore/net/quic/test/test_QUICFrame.cc | 39 +++++++- 3 files changed, 168 insertions(+), 24 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 8cf0c4fb875..ab2870df874 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -97,7 +97,7 @@ QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStrea this->_fin = last; } -QUICStreamFrame * +QUICFrame * QUICStreamFrame::split(size_t size) { if (size <= this->_get_data_field_offset()) { @@ -379,6 +379,12 @@ QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len, bool protection) : QU this->reset(buf, len); } +QUICFrame * +QUICAckFrame::split(size_t size) +{ + return nullptr; +} + QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, bool protection) : QUICFrame(protection) { @@ -828,6 +834,12 @@ QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode { } +QUICFrame * +QUICRstStreamFrame::split(size_t size) +{ + return nullptr; +} + QUICFrameType QUICRstStreamFrame::type() const { @@ -945,6 +957,12 @@ QUICPingFrame::type() const return QUICFrameType::PING; } +QUICFrame * +QUICPingFrame::split(size_t size) +{ + return nullptr; +} + size_t QUICPingFrame::size() const { @@ -996,6 +1014,12 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len, size_t limit) const return *len; } +QUICFrame * +QUICPaddingFrame::split(size_t size) +{ + return nullptr; +} + // // CONNECTION_CLOSE frame // @@ -1008,6 +1032,12 @@ QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode error_code this->_reason_phrase = reason_phrase; } +QUICFrame * +QUICConnectionCloseFrame::split(size_t size) +{ + return nullptr; +} + QUICFrameType QUICConnectionCloseFrame::type() const { @@ -1115,6 +1145,12 @@ QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code this->_reason_phrase = reason_phrase; } +QUICFrame * +QUICApplicationCloseFrame::split(size_t size) +{ + return nullptr; +} + QUICFrameType QUICApplicationCloseFrame::type() const { @@ -1218,6 +1254,12 @@ QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, bool protection) this->_maximum_data = maximum_data; } +QUICFrame * +QUICMaxDataFrame::split(size_t size) +{ + return nullptr; +} + QUICFrameType QUICMaxDataFrame::type() const { @@ -1284,6 +1326,12 @@ QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t this->_maximum_stream_data = maximum_stream_data; } +QUICFrame * +QUICMaxStreamDataFrame::split(size_t size) +{ + return nullptr; +} + QUICFrameType QUICMaxStreamDataFrame::type() const { @@ -1380,6 +1428,12 @@ QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, bool this->_maximum_stream_id = maximum_stream_id; } +QUICFrame * +QUICMaxStreamIdFrame::split(size_t size) +{ + return nullptr; +} + QUICFrameType QUICMaxStreamIdFrame::type() const { @@ -1444,6 +1498,12 @@ QUICBlockedFrame::type() const return QUICFrameType::BLOCKED; } +QUICFrame * +QUICBlockedFrame::split(size_t size) +{ + return nullptr; +} + size_t QUICBlockedFrame::size() const { @@ -1504,6 +1564,12 @@ QUICStreamBlockedFrame::type() const return QUICFrameType::STREAM_BLOCKED; } +QUICFrame * +QUICStreamBlockedFrame::split(size_t size) +{ + return nullptr; +} + size_t QUICStreamBlockedFrame::size() const { @@ -1591,6 +1657,12 @@ QUICStreamIdBlockedFrame::type() const return QUICFrameType::STREAM_ID_BLOCKED; } +QUICFrame * +QUICStreamIdBlockedFrame::split(size_t size) +{ + return nullptr; +} + size_t QUICStreamIdBlockedFrame::size() const { @@ -1652,6 +1724,12 @@ QUICNewConnectionIdFrame::type() const return QUICFrameType::NEW_CONNECTION_ID; } +QUICFrame * +QUICNewConnectionIdFrame::split(size_t size) +{ + return nullptr; +} + size_t QUICNewConnectionIdFrame::size() const { @@ -1754,6 +1832,12 @@ QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorC { } +QUICFrame * +QUICStopSendingFrame::split(size_t size) +{ + return nullptr; +} + QUICFrameType QUICStopSendingFrame::type() const { @@ -1837,6 +1921,12 @@ QUICPathChallengeFrame::type() const return QUICFrameType::PATH_CHALLENGE; } +QUICFrame * +QUICPathChallengeFrame::split(size_t size) +{ + return nullptr; +} + size_t QUICPathChallengeFrame::size() const { @@ -1887,6 +1977,12 @@ QUICPathResponseFrame::type() const return QUICFrameType::PATH_RESPONSE; } +QUICFrame * +QUICPathResponseFrame::split(size_t size) +{ + return nullptr; +} + size_t QUICPathResponseFrame::size() const { @@ -1934,29 +2030,19 @@ QUICPathResponseFrame::_data_offset() const QUICRetransmissionFrame::QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet) : QUICFrame(original_frame->is_protected()), _packet_type(original_packet.type()) { - size_t dummy; - this->_size = original_frame->size(); - this->_data = ats_unique_malloc(this->_size); - this->_buf = this->_data.get(); - original_frame->store(this->_data.get(), &dummy, this->_size); + this->_frame = std::move(original_frame); } size_t QUICRetransmissionFrame::size() const { - return this->_size; + return this->_frame->size(); } size_t QUICRetransmissionFrame::store(uint8_t *buf, size_t *len, size_t limit) const { - if (limit < this->size()) { - return 0; - } - - memcpy(buf, this->_data.get(), this->_size); - *len = this->_size; - return *len; + return this->_frame->store(buf, len, limit); } int @@ -1971,6 +2057,16 @@ QUICRetransmissionFrame::packet_type() const return this->_packet_type; } +QUICFrame * +QUICRetransmissionFrame::split(size_t size) +{ + if (this->_frame->type() != QUICFrameType::STREAM) { + return nullptr; + } + + return this->_frame->split(size); +} + // // QUICFrameFactory // @@ -2104,13 +2200,7 @@ QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUIC QUICFrameUPtr QUICFrameFactory::split_frame(QUICFrame *frame, size_t size) { - if (frame->type() != QUICFrameType::STREAM) { - return QUICFrameFactory::create_null_frame(); - } - - QUICStreamFrame *old_frame = static_cast(frame); - QUICStreamFrame *new_frame = old_frame->split(size); - return QUICFrameUPtr(new_frame, &QUICFrameDeleter::delete_stream_frame); + return QUICFrameUPtr(frame->split(size), &QUICFrameDeleter::delete_stream_frame); } std::unique_ptr diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 72382f40de3..4a96886a7c5 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -42,6 +42,7 @@ class QUICFrame virtual QUICFrameType type() const; virtual size_t size() const = 0; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const = 0; + virtual QUICFrame *split(size_t size) = 0; virtual void reset(const uint8_t *buf, size_t len); virtual bool is_protected() const; virtual int debug_msg(char *msg, size_t msg_len) const; @@ -66,7 +67,7 @@ class QUICStreamFrame : public QUICFrame QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false, bool protection = true); - QUICStreamFrame *split(size_t size); + QUICFrame *split(size_t size) override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -200,6 +201,7 @@ class QUICAckFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual int debug_msg(char *msg, size_t msg_len) const override; + QUICFrame *split(size_t size) override; bool is_protected() const override; @@ -234,6 +236,7 @@ class QUICRstStreamFrame : public QUICFrame QUICRstStreamFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, bool protection = true); + QUICFrame *split(size_t size) override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -263,6 +266,7 @@ class QUICPingFrame : public QUICFrame public: QUICPingFrame() : QUICFrame() {} QUICPingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICFrame *split(size_t size) override; QUICPingFrame(bool protection) : QUICFrame(protection) {} virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -280,6 +284,7 @@ class QUICPaddingFrame : public QUICFrame QUICPaddingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} virtual QUICFrameType type() const override; virtual size_t size() const override; + QUICFrame *split(size_t size) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; }; @@ -297,6 +302,7 @@ class QUICConnectionCloseFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + QUICFrame *split(size_t size) override; QUICTransErrorCode error_code() const; uint64_t reason_phrase_length() const; const char *reason_phrase() const; @@ -325,6 +331,7 @@ class QUICApplicationCloseFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + QUICFrame *split(size_t size) override; QUICAppErrorCode error_code() const; uint64_t reason_phrase_length() const; const char *reason_phrase() const; @@ -352,6 +359,7 @@ class QUICMaxDataFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + QUICFrame *split(size_t size) override; uint64_t maximum_data() const; private: @@ -374,6 +382,7 @@ class QUICMaxStreamDataFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICStreamId stream_id() const; + QUICFrame *split(size_t size) override; uint64_t maximum_stream_data() const; private: @@ -398,6 +407,7 @@ class QUICMaxStreamIdFrame : public QUICFrame QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; + QUICFrame *split(size_t size) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICStreamId maximum_stream_id() const; @@ -420,6 +430,7 @@ class QUICBlockedFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + QUICFrame *split(size_t size) override; QUICOffset offset() const; @@ -443,6 +454,7 @@ class QUICStreamBlockedFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + QUICFrame *split(size_t size) override; QUICStreamId stream_id() const; QUICOffset offset() const; @@ -468,6 +480,7 @@ class QUICStreamIdBlockedFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + QUICFrame *split(size_t size) override; QUICStreamId stream_id() const; @@ -492,6 +505,7 @@ class QUICNewConnectionIdFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + QUICFrame *split(size_t size) override; uint64_t sequence() const; QUICConnectionId connection_id() const; @@ -521,6 +535,7 @@ class QUICStopSendingFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + QUICFrame *split(size_t size) override; QUICStreamId stream_id() const; QUICAppErrorCode error_code() const; @@ -547,6 +562,7 @@ class QUICPathChallengeFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + QUICFrame *split(size_t size) override; const uint8_t *data() const; @@ -570,6 +586,7 @@ class QUICPathResponseFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + QUICFrame *split(size_t size) override; const uint8_t *data() const; @@ -596,11 +613,11 @@ class QUICRetransmissionFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual int debug_msg(char *msg, size_t msg_len) const override; QUICPacketType packet_type() const; + QUICFrame *split(size_t size) override; private: QUICFrameUPtr _frame = QUICFrameUPtr(nullptr, nullptr); ats_unique_buf _data = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); - size_t _size; QUICPacketType _packet_type; }; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 03b8869bd8e..c7c9b3c2dd1 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -340,7 +340,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") CHECK(stream_frame->offset() == 0x100000000); CHECK(stream_frame->stream_id() == 0x01); CHECK(stream_frame->data_length() == 10); - QUICStreamFrame *stream_frame2 = stream_frame->split(16); + QUICStreamFrame *stream_frame2 = dynamic_cast(stream_frame->split(16)); CHECK(stream_frame->stream_id() == 0x01); CHECK(stream_frame->data_length() == 5); CHECK(memcmp(stream_frame->data(), "\x01\x02\x03\x04\x05", stream_frame->data_length()) == 0); @@ -1176,6 +1176,43 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") factory.set_hs_protocol(&hs_protocol); QUICPacketUPtr packet = factory.create_server_protected_packet({reinterpret_cast("\x01\x02\x03\x04"), 4}, 0, {nullptr, [](void *p) { ats_free(p); }}, 0, true); + SECTION("STREAM frame split") + { + size_t len; + uint8_t buf1[] = { + 0x16, // 0b00010OLF (OLF=110) + 0x01, // Stream ID + 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset + 0x0a, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + 0x11, 0x22, 0x33, 0x44, 0x55, + }; + + uint8_t expected[]{ + 0x16, // 0b00010OLF (OLF=110) + 0x01, // Stream ID + 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, // Offset + 0x05, // Data Length + 0x11, 0x22, 0x33, 0x44, 0x55, // Stream Data + }; + + uint8_t expected2[]{ + 0x16, // 0b00010OLF (OLF=110) + 0x01, // Stream ID + 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data + }; + + uint8_t buffer[128]; + + QUICFrameUPtr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + auto frame = QUICFrameFactory::create_retransmission_frame(std::move(frame1), *packet); + auto frame2 = frame->split(16); + + CHECK(frame2->store(buffer, &len, 128)); + CHECK(memcmp(buffer, expected, sizeof(expected)) == 0); + } SECTION("STREAM frame") { From c941afc59e562eb1c60c311167513a3d345b3f60 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 28 May 2018 15:36:19 +0800 Subject: [PATCH 0570/1313] [QUIC] Splits Retransmit frame which exceed limit --- iocore/net/quic/QUICFrame.cc | 109 +++------------------ iocore/net/quic/QUICFrame.h | 19 +--- iocore/net/quic/QUICPacketRetransmitter.cc | 15 ++- iocore/net/quic/test/test_QUICFrame.cc | 2 + 4 files changed, 29 insertions(+), 116 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index ab2870df874..ee0cc077bf2 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -82,6 +82,12 @@ QUICFrame::debug_msg(char *msg, size_t msg_len) const return snprintf(msg, msg_len, "type=%s size=%zu", QUICDebugNames::frame_type(this->type()), this->size()); } +QUICFrame * +QUICFrame::split(size_t size) +{ + return nullptr; +} + // // STREAM Frame // @@ -379,12 +385,6 @@ QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len, bool protection) : QU this->reset(buf, len); } -QUICFrame * -QUICAckFrame::split(size_t size) -{ - return nullptr; -} - QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, bool protection) : QUICFrame(protection) { @@ -834,12 +834,6 @@ QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode { } -QUICFrame * -QUICRstStreamFrame::split(size_t size) -{ - return nullptr; -} - QUICFrameType QUICRstStreamFrame::type() const { @@ -957,12 +951,6 @@ QUICPingFrame::type() const return QUICFrameType::PING; } -QUICFrame * -QUICPingFrame::split(size_t size) -{ - return nullptr; -} - size_t QUICPingFrame::size() const { @@ -1014,12 +1002,6 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len, size_t limit) const return *len; } -QUICFrame * -QUICPaddingFrame::split(size_t size) -{ - return nullptr; -} - // // CONNECTION_CLOSE frame // @@ -1032,12 +1014,6 @@ QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode error_code this->_reason_phrase = reason_phrase; } -QUICFrame * -QUICConnectionCloseFrame::split(size_t size) -{ - return nullptr; -} - QUICFrameType QUICConnectionCloseFrame::type() const { @@ -1145,12 +1121,6 @@ QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code this->_reason_phrase = reason_phrase; } -QUICFrame * -QUICApplicationCloseFrame::split(size_t size) -{ - return nullptr; -} - QUICFrameType QUICApplicationCloseFrame::type() const { @@ -1254,12 +1224,6 @@ QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, bool protection) this->_maximum_data = maximum_data; } -QUICFrame * -QUICMaxDataFrame::split(size_t size) -{ - return nullptr; -} - QUICFrameType QUICMaxDataFrame::type() const { @@ -1326,12 +1290,6 @@ QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t this->_maximum_stream_data = maximum_stream_data; } -QUICFrame * -QUICMaxStreamDataFrame::split(size_t size) -{ - return nullptr; -} - QUICFrameType QUICMaxStreamDataFrame::type() const { @@ -1428,12 +1386,6 @@ QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, bool this->_maximum_stream_id = maximum_stream_id; } -QUICFrame * -QUICMaxStreamIdFrame::split(size_t size) -{ - return nullptr; -} - QUICFrameType QUICMaxStreamIdFrame::type() const { @@ -1498,12 +1450,6 @@ QUICBlockedFrame::type() const return QUICFrameType::BLOCKED; } -QUICFrame * -QUICBlockedFrame::split(size_t size) -{ - return nullptr; -} - size_t QUICBlockedFrame::size() const { @@ -1564,12 +1510,6 @@ QUICStreamBlockedFrame::type() const return QUICFrameType::STREAM_BLOCKED; } -QUICFrame * -QUICStreamBlockedFrame::split(size_t size) -{ - return nullptr; -} - size_t QUICStreamBlockedFrame::size() const { @@ -1657,12 +1597,6 @@ QUICStreamIdBlockedFrame::type() const return QUICFrameType::STREAM_ID_BLOCKED; } -QUICFrame * -QUICStreamIdBlockedFrame::split(size_t size) -{ - return nullptr; -} - size_t QUICStreamIdBlockedFrame::size() const { @@ -1724,12 +1658,6 @@ QUICNewConnectionIdFrame::type() const return QUICFrameType::NEW_CONNECTION_ID; } -QUICFrame * -QUICNewConnectionIdFrame::split(size_t size) -{ - return nullptr; -} - size_t QUICNewConnectionIdFrame::size() const { @@ -1832,12 +1760,6 @@ QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorC { } -QUICFrame * -QUICStopSendingFrame::split(size_t size) -{ - return nullptr; -} - QUICFrameType QUICStopSendingFrame::type() const { @@ -1921,12 +1843,6 @@ QUICPathChallengeFrame::type() const return QUICFrameType::PATH_CHALLENGE; } -QUICFrame * -QUICPathChallengeFrame::split(size_t size) -{ - return nullptr; -} - size_t QUICPathChallengeFrame::size() const { @@ -1977,12 +1893,6 @@ QUICPathResponseFrame::type() const return QUICFrameType::PATH_RESPONSE; } -QUICFrame * -QUICPathResponseFrame::split(size_t size) -{ - return nullptr; -} - size_t QUICPathResponseFrame::size() const { @@ -2200,7 +2110,12 @@ QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUIC QUICFrameUPtr QUICFrameFactory::split_frame(QUICFrame *frame, size_t size) { - return QUICFrameUPtr(frame->split(size), &QUICFrameDeleter::delete_stream_frame); + auto new_frame = frame->split(size); + if (new_frame != nullptr) { + return QUICFrameFactory::create_null_frame(); + } + + return QUICFrameUPtr(new_frame, &QUICFrameDeleter::delete_stream_frame); } std::unique_ptr diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 4a96886a7c5..6f7e837c285 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -42,9 +42,9 @@ class QUICFrame virtual QUICFrameType type() const; virtual size_t size() const = 0; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const = 0; - virtual QUICFrame *split(size_t size) = 0; virtual void reset(const uint8_t *buf, size_t len); virtual bool is_protected() const; + virtual QUICFrame *split(size_t size); virtual int debug_msg(char *msg, size_t msg_len) const; LINK(QUICFrame, link); @@ -201,8 +201,6 @@ class QUICAckFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual int debug_msg(char *msg, size_t msg_len) const override; - QUICFrame *split(size_t size) override; - bool is_protected() const override; QUICPacketNumber largest_acknowledged() const; @@ -236,7 +234,6 @@ class QUICRstStreamFrame : public QUICFrame QUICRstStreamFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, bool protection = true); - QUICFrame *split(size_t size) override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -266,7 +263,6 @@ class QUICPingFrame : public QUICFrame public: QUICPingFrame() : QUICFrame() {} QUICPingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICFrame *split(size_t size) override; QUICPingFrame(bool protection) : QUICFrame(protection) {} virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -284,7 +280,6 @@ class QUICPaddingFrame : public QUICFrame QUICPaddingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} virtual QUICFrameType type() const override; virtual size_t size() const override; - QUICFrame *split(size_t size) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; }; @@ -302,7 +297,6 @@ class QUICConnectionCloseFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - QUICFrame *split(size_t size) override; QUICTransErrorCode error_code() const; uint64_t reason_phrase_length() const; const char *reason_phrase() const; @@ -331,7 +325,6 @@ class QUICApplicationCloseFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - QUICFrame *split(size_t size) override; QUICAppErrorCode error_code() const; uint64_t reason_phrase_length() const; const char *reason_phrase() const; @@ -359,7 +352,6 @@ class QUICMaxDataFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - QUICFrame *split(size_t size) override; uint64_t maximum_data() const; private: @@ -382,7 +374,6 @@ class QUICMaxStreamDataFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICStreamId stream_id() const; - QUICFrame *split(size_t size) override; uint64_t maximum_stream_data() const; private: @@ -407,7 +398,6 @@ class QUICMaxStreamIdFrame : public QUICFrame QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, bool protection = true); virtual QUICFrameType type() const override; virtual size_t size() const override; - QUICFrame *split(size_t size) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICStreamId maximum_stream_id() const; @@ -430,7 +420,6 @@ class QUICBlockedFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - QUICFrame *split(size_t size) override; QUICOffset offset() const; @@ -454,7 +443,6 @@ class QUICStreamBlockedFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - QUICFrame *split(size_t size) override; QUICStreamId stream_id() const; QUICOffset offset() const; @@ -480,7 +468,6 @@ class QUICStreamIdBlockedFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - QUICFrame *split(size_t size) override; QUICStreamId stream_id() const; @@ -505,7 +492,6 @@ class QUICNewConnectionIdFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - QUICFrame *split(size_t size) override; uint64_t sequence() const; QUICConnectionId connection_id() const; @@ -535,7 +521,6 @@ class QUICStopSendingFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - QUICFrame *split(size_t size) override; QUICStreamId stream_id() const; QUICAppErrorCode error_code() const; @@ -562,7 +547,6 @@ class QUICPathChallengeFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - QUICFrame *split(size_t size) override; const uint8_t *data() const; @@ -586,7 +570,6 @@ class QUICPathResponseFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - QUICFrame *split(size_t size) override; const uint8_t *data() const; diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 32c005d3d6b..8951f07ac01 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -68,5 +68,18 @@ QUICPacketRetransmitter::generate_frame(uint16_t connection_credit, uint16_t max frame = std::move(this->_retransmission_frames.front()); this->_retransmission_frames.pop(); } - return frame; + + if (maximum_frame_size >= frame->size()) { + return frame; + } + + auto new_frame = QUICFrameFactory::split_frame(frame.get(), maximum_frame_size); + if (new_frame) { + this->_retransmission_frames.push(std::move(new_frame)); + return frame; + } + + // failed to split frame return nullptr + this->_retransmission_frames.push(std::move(frame)); + return QUICFrameFactory::create_null_frame(); } diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index c7c9b3c2dd1..27d827995c0 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1212,6 +1212,8 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") CHECK(frame2->store(buffer, &len, 128)); CHECK(memcmp(buffer, expected, sizeof(expected)) == 0); + CHECK(frame->store(buffer, &len, 128)); + CHECK(memcmp(buffer, expected2, sizeof(expected2)) == 0); } SECTION("STREAM frame") From ff45ebfc370e11fa498224f1c6eb1c6d67cdf336 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 29 May 2018 11:32:15 +0900 Subject: [PATCH 0571/1313] Send 3 Handshake packets at maximum without path validation --- iocore/net/P_QUICNetVConnection.h | 3 +++ iocore/net/QUICNetVConnection.cc | 20 +++++++++++++------- iocore/net/quic/QUICPathValidator.cc | 24 +++++++++++++++--------- iocore/net/quic/QUICPathValidator.h | 8 ++++---- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 8112b9c0122..e3271588b8d 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -332,6 +332,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet(); QUICStatelessResetToken _reset_token; + + // This is for limiting number of packets that a server can send without path validation + unsigned int _handshake_packets_sent = 0; }; typedef int (QUICNetVConnection::*QUICNetVConnHandler)(int, void *); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 0b5995e6add..ce1ab38f3c6 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1028,12 +1028,20 @@ QUICNetVConnection::_state_common_send_packet() SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); uint32_t packet_count = 0; while ((packet = this->_packet_send_queue.dequeue()) != nullptr) { + if (packet->type() == QUICPacketType::HANDSHAKE && !this->_path_validator->is_validated() && + this->_handshake_packets_sent >= 3) { + this->_packet_send_queue.push(packet); + break; + } if (!this->_congestion_controller->check_credit()) { this->_packet_send_queue.push(packet); break; } this->_packet_handler->send_packet(*packet, this); + if (packet->type() == QUICPacketType::HANDSHAKE) { + ++this->_handshake_packets_sent; + } this->_loss_detector->on_packet_sent(QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet)); packet_count++; } @@ -1192,14 +1200,12 @@ QUICNetVConnection::_packetize_frames() } // PATH_CHALLENGE, PATH_RESPOSNE - frame = this->_path_validator->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); - while (frame) { - ++frame_count; - this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - if (frame_count >= FRAME_PER_EVENT) { - break; - } + if (this->_stream_manager->will_generate_frame()) { frame = this->_path_validator->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); + if (frame) { + ++frame_count; + this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + } } // NEW_CONNECTION_ID diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index a6039987ded..ac68806a405 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -47,7 +47,7 @@ QUICPathValidator::_generate_challenge() // TODO Randomize challenge data this->_outgoing_challenge[i] = i; } - this->_has_outgoing_challenge = true; + this->_has_outgoing_challenge = 3; } void @@ -60,12 +60,16 @@ QUICPathValidator::_generate_response(std::shared_ptr frame) { - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - - if (memcmp(this->_outgoing_challenge, frame->data(), QUICPathChallengeFrame::DATA_LEN) == 0) { - this->_state = ValidationState::VALIDATED; - } else { - error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE)); + QUICErrorUPtr error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE)); + + for (int i = 0; i < 3; ++i) { + if (memcmp(this->_outgoing_challenge + (QUICPathChallengeFrame::DATA_LEN * i), frame->data(), + QUICPathChallengeFrame::DATA_LEN) == 0) { + this->_state = ValidationState::VALIDATED; + this->_has_outgoing_challenge = 0; + error = QUICErrorUPtr(new QUICNoError()); + break; + } } return error; @@ -117,8 +121,10 @@ QUICPathValidator::generate_frame(uint16_t connection_credit, uint16_t maximum_q frame = QUICFrameFactory::create_path_response_frame(this->_incoming_challenge); this->_has_outgoing_response = false; } else if (this->_has_outgoing_challenge) { - frame = QUICFrameFactory::create_path_challenge_frame(this->_outgoing_challenge); - this->_has_outgoing_challenge = false; + frame = QUICFrameFactory::create_path_challenge_frame(this->_outgoing_challenge + + (QUICPathChallengeFrame::DATA_LEN * (this->_has_outgoing_challenge - 1))); + --this->_has_outgoing_challenge; + ink_assert(this->_has_outgoing_challenge >= 0); } return frame; } diff --git a/iocore/net/quic/QUICPathValidator.h b/iocore/net/quic/QUICPathValidator.h index f6e6818e667..60df4f62aca 100644 --- a/iocore/net/quic/QUICPathValidator.h +++ b/iocore/net/quic/QUICPathValidator.h @@ -49,11 +49,11 @@ class QUICPathValidator : public QUICFrameHandler, public QUICFrameGenerator VALIDATING, VALIDATED, }; - ValidationState _state = ValidationState::NOT_VALIDATED; - bool _has_outgoing_challenge = false; - bool _has_outgoing_response = false; + ValidationState _state = ValidationState::NOT_VALIDATED; + int _has_outgoing_challenge = 0; + bool _has_outgoing_response = false; uint8_t _incoming_challenge[QUICPathChallengeFrame::DATA_LEN]; - uint8_t _outgoing_challenge[QUICPathChallengeFrame::DATA_LEN]; + uint8_t _outgoing_challenge[QUICPathChallengeFrame::DATA_LEN * 3]; void _generate_challenge(); void _generate_response(std::shared_ptr frame); From a32e30d333d87560f06c753755f95427d23a0b62 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 29 May 2018 12:02:37 +0900 Subject: [PATCH 0572/1313] Add debug string for PATH_VALIDATION_TIMEOUT --- iocore/net/quic/QUICDebugNames.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index a13e5f24187..c6b4ea749e6 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -158,6 +158,8 @@ QUICDebugNames::quic_event(int event) return "QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE"; case QUIC_EVENT_CLOSING_TIMEOUT: return "QUIC_EVENT_CLOSING_TIMEOUT"; + case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: + return "QUIC_EVENT_PATH_VALIDATION_TIMEOUT"; case QUIC_EVENT_SHUTDOWN: return "QUIC_EVENT_SHUTDOWN"; case QUIC_EVENT_LD_SHUTDOWN: From 50bab2eb5288f496b5fabd7c58be9ff34227d5f1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 29 May 2018 12:24:35 +0900 Subject: [PATCH 0573/1313] Do nothing if retransmission_frames is empty --- iocore/net/quic/QUICPacketRetransmitter.cc | 24 ++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 8951f07ac01..be4c97d9002 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -67,19 +67,17 @@ QUICPacketRetransmitter::generate_frame(uint16_t connection_credit, uint16_t max if (!this->_retransmission_frames.empty()) { frame = std::move(this->_retransmission_frames.front()); this->_retransmission_frames.pop(); - } - - if (maximum_frame_size >= frame->size()) { - return frame; - } - auto new_frame = QUICFrameFactory::split_frame(frame.get(), maximum_frame_size); - if (new_frame) { - this->_retransmission_frames.push(std::move(new_frame)); - return frame; + if (maximum_frame_size < frame->size()) { + auto new_frame = QUICFrameFactory::split_frame(frame.get(), maximum_frame_size); + if (new_frame) { + this->_retransmission_frames.push(std::move(new_frame)); + } else { + // failed to split frame return nullptr + this->_retransmission_frames.push(std::move(frame)); + frame = QUICFrameFactory::create_null_frame(); + } + } } - - // failed to split frame return nullptr - this->_retransmission_frames.push(std::move(frame)); - return QUICFrameFactory::create_null_frame(); + return frame; } From ffc2e7eeac820f2cf0e1c28f687b3c5188094f42 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 29 May 2018 15:04:34 +0900 Subject: [PATCH 0574/1313] RetransmissionFrame should return a type of frame that have --- iocore/net/quic/QUICFrame.cc | 6 ++++++ iocore/net/quic/QUICFrame.h | 1 + 2 files changed, 7 insertions(+) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index ee0cc077bf2..7d57387d95e 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1943,6 +1943,12 @@ QUICRetransmissionFrame::QUICRetransmissionFrame(QUICFrameUPtr original_frame, c this->_frame = std::move(original_frame); } +QUICFrameType +QUICRetransmissionFrame::type() const +{ + return this->_frame->type(); +} + size_t QUICRetransmissionFrame::size() const { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 6f7e837c285..6c58a2e9df2 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -592,6 +592,7 @@ class QUICRetransmissionFrame : public QUICFrame public: QUICRetransmissionFrame() : QUICFrame() {} QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet); + QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual int debug_msg(char *msg, size_t msg_len) const override; From 90d5b413337f67dfe88dde3839fdefbb118cb986 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 29 May 2018 15:06:35 +0900 Subject: [PATCH 0575/1313] Connection credit can be bigger than 16bit --- iocore/net/quic/QUICAckFrameCreator.cc | 2 +- iocore/net/quic/QUICAckFrameCreator.h | 2 +- iocore/net/quic/QUICAltConnectionManager.cc | 2 +- iocore/net/quic/QUICAltConnectionManager.h | 2 +- iocore/net/quic/QUICFrameGenerator.h | 2 +- iocore/net/quic/QUICPacketRetransmitter.cc | 2 +- iocore/net/quic/QUICPacketRetransmitter.h | 2 +- iocore/net/quic/QUICPathValidator.cc | 2 +- iocore/net/quic/QUICPathValidator.h | 2 +- iocore/net/quic/QUICStream.cc | 2 +- iocore/net/quic/QUICStream.h | 2 +- iocore/net/quic/QUICStreamManager.cc | 2 +- iocore/net/quic/QUICStreamManager.h | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 931d3f4b5a9..f6f894964d6 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -124,7 +124,7 @@ QUICAckFrameCreator::will_generate_frame() } QUICFrameUPtr -QUICAckFrameCreator::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) +QUICAckFrameCreator::generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) { // FIXME fix size return this->_create_frame(); diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index d474aadd079..acf53ca8195 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -72,7 +72,7 @@ class QUICAckFrameCreator : public QUICFrameGenerator /* * Calls create directly. */ - QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) override; private: /* diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 3b1ce232021..b24e6a04c15 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -102,7 +102,7 @@ QUICAltConnectionManager::will_generate_frame() } QUICFrameUPtr -QUICAltConnectionManager::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) +QUICAltConnectionManager::generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) { QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); int count = this->_nids; diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index 28637947822..79f27efd69a 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -40,7 +40,7 @@ class QUICAltConnectionManager : public QUICFrameGenerator // QUICFrameGenerator bool will_generate_frame(); - QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size); + QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size); private: class AltConnectionInfo diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index f815437a941..0e4d2655b32 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -30,5 +30,5 @@ class QUICFrameGenerator public: virtual ~QUICFrameGenerator(){}; virtual bool will_generate_frame() = 0; - virtual QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) = 0; + virtual QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) = 0; }; diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index be4c97d9002..843e294f584 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -61,7 +61,7 @@ QUICPacketRetransmitter::will_generate_frame() } QUICFrameUPtr -QUICPacketRetransmitter::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) +QUICPacketRetransmitter::generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) { QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); if (!this->_retransmission_frames.empty()) { diff --git a/iocore/net/quic/QUICPacketRetransmitter.h b/iocore/net/quic/QUICPacketRetransmitter.h index c24d6b5a94b..bef5efa74e0 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.h +++ b/iocore/net/quic/QUICPacketRetransmitter.h @@ -35,7 +35,7 @@ class QUICPacketRetransmitter : public QUICFrameGenerator // QUICFrameGenerator bool will_generate_frame() override; - QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) override; private: std::queue _retransmission_frames; diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index ac68806a405..a210be2a102 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -113,7 +113,7 @@ QUICPathValidator::will_generate_frame() } QUICFrameUPtr -QUICPathValidator::generate_frame(uint16_t connection_credit, uint16_t maximum_quic_packet_size) +QUICPathValidator::generate_frame(uint64_t connection_credit, uint16_t maximum_quic_packet_size) { QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); diff --git a/iocore/net/quic/QUICPathValidator.h b/iocore/net/quic/QUICPathValidator.h index 60df4f62aca..93343dec380 100644 --- a/iocore/net/quic/QUICPathValidator.h +++ b/iocore/net/quic/QUICPathValidator.h @@ -41,7 +41,7 @@ class QUICPathValidator : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameGeneratro bool will_generate_frame() override; - QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) override; private: enum class ValidationState : int { diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index a67f226cab3..5ae63bbf5ae 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -372,7 +372,7 @@ QUICStream::will_generate_frame() } QUICFrameUPtr -QUICStream::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) +QUICStream::generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) { SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 99c501c27ef..5515225c3c3 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -88,7 +88,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator LINK(QUICStream, link); // QUICFrameGenerator - QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) override; bool will_generate_frame() override; private: diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index eff8f53ae06..026a0f9c295 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -370,7 +370,7 @@ QUICStreamManager::will_generate_frame() } QUICFrameUPtr -QUICStreamManager::generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) +QUICStreamManager::generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) { // FIXME We should pick a stream based on priority QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 0edc1142a90..449db9ea275 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -65,7 +65,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameGenerator bool will_generate_frame() override; - QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) override; private: QUICStream *_find_stream(QUICStreamId id); From 43d0c00505a766860392f0a58737f5a93c29de4a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 29 May 2018 15:16:00 +0900 Subject: [PATCH 0576/1313] Start new path validation on only server side --- iocore/net/QUICNetVConnection.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ce1ab38f3c6..a1116aacf2c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -192,6 +192,7 @@ QUICNetVConnection::start() this->_handshake_handler = new QUICHandshake(this, params->client_ssl_ctx()); this->_handshake_handler->start(&this->_packet_factory, params->vn_exercise_enabled()); } + this->_application_map = new QUICApplicationMap(); this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); @@ -213,7 +214,9 @@ QUICNetVConnection::start() this->_frame_dispatcher->add_handler(this->_loss_detector); this->_frame_dispatcher->add_handler(this->_path_validator); - this->_validate_new_path(); + if (this->direction() == NET_VCONNECTION_IN) { + this->_validate_new_path(); + } } void From ab0e46da98251e7ee35c4ef407746153ea072505 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 29 May 2018 16:12:54 +0900 Subject: [PATCH 0577/1313] Cleanup: move read-only QUICConnection APIs into QUICConnectionInfo --- iocore/net/P_QUICNetVConnection.h | 24 +++++++++++++----------- iocore/net/QUICNetVConnection.cc | 20 ++++++++++---------- iocore/net/quic/Mock.h | 20 ++++++++++---------- iocore/net/quic/QUICConnection.h | 28 ++++++++++++++++------------ 4 files changed, 49 insertions(+), 43 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e3271588b8d..07884d27033 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -187,20 +187,22 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void registerNextProtocolSet(SSLNextProtocolSet *s); // QUICConnection - QUICConnectionId peer_connection_id() override; - QUICConnectionId original_connection_id() override; - QUICConnectionId connection_id() override; - const QUICFiveTuple five_tuple() override; - uint32_t maximum_quic_packet_size() override; - uint32_t minimum_quic_packet_size() override; QUICStreamManager *stream_manager() override; - uint32_t pmtu() override; - NetVConnectionContext_t direction() override; - SSLNextProtocolSet *next_protocol_set() override; void close(QUICConnectionErrorUPtr error) override; - QUICPacketNumber largest_acked_packet_number() override; void handle_received_packet(UDPPacket *packet) override; - bool is_closed() override; + + // QUICConnection (QUICConnectionInfo) + QUICConnectionId peer_connection_id() const override; + QUICConnectionId original_connection_id() const override; + QUICConnectionId connection_id() const override; + const QUICFiveTuple five_tuple() const override; + uint32_t maximum_quic_packet_size() const override; + uint32_t minimum_quic_packet_size() override; + uint32_t pmtu() const override; + NetVConnectionContext_t direction() const override; + SSLNextProtocolSet *next_protocol_set() const override; + QUICPacketNumber largest_acked_packet_number() const override; + bool is_closed() const override; // QUICConnection (QUICPacketTransmitter) virtual uint32_t transmit_packet(QUICPacketUPtr packet) override; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a1116aacf2c..701b39e1f69 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -322,37 +322,37 @@ QUICNetVConnection::connectUp(EThread *t, int fd) } QUICConnectionId -QUICNetVConnection::peer_connection_id() +QUICNetVConnection::peer_connection_id() const { return this->_peer_quic_connection_id; } QUICConnectionId -QUICNetVConnection::original_connection_id() +QUICNetVConnection::original_connection_id() const { return this->_original_quic_connection_id; } QUICConnectionId -QUICNetVConnection::connection_id() +QUICNetVConnection::connection_id() const { return this->_quic_connection_id; } const QUICFiveTuple -QUICNetVConnection::five_tuple() +QUICNetVConnection::five_tuple() const { return this->_five_tuple; } uint32_t -QUICNetVConnection::pmtu() +QUICNetVConnection::pmtu() const { return this->_pmtu; } NetVConnectionContext_t -QUICNetVConnection::direction() +QUICNetVConnection::direction() const { return this->netvc_context; } @@ -371,7 +371,7 @@ QUICNetVConnection::minimum_quic_packet_size() } uint32_t -QUICNetVConnection::maximum_quic_packet_size() +QUICNetVConnection::maximum_quic_packet_size() const { if (this->options.ip_family == PF_INET6) { return this->_pmtu - UDP_HEADER_SIZE - IPV6_HEADER_SIZE; @@ -785,19 +785,19 @@ QUICNetVConnection::registerNextProtocolSet(SSLNextProtocolSet *s) } bool -QUICNetVConnection::is_closed() +QUICNetVConnection::is_closed() const { return this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closed); } SSLNextProtocolSet * -QUICNetVConnection::next_protocol_set() +QUICNetVConnection::next_protocol_set() const { return this->_next_protocol_set; } QUICPacketNumber -QUICNetVConnection::largest_acked_packet_number() +QUICNetVConnection::largest_acked_packet_number() const { return this->_loss_detector->largest_acked_packet_number(); } diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index b11eac63c45..b71355426ee 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -146,25 +146,25 @@ class MockQUICConnection : public QUICConnection }; QUICConnectionId - connection_id() override + connection_id() const override { return {reinterpret_cast("\x00"), 1}; } QUICConnectionId - peer_connection_id() override + peer_connection_id() const override { return {reinterpret_cast("\x00"), 1}; } QUICConnectionId - original_connection_id() override + original_connection_id() const override { return {reinterpret_cast("\x00"), 1}; } const QUICFiveTuple - five_tuple() override + five_tuple() const override { return QUICFiveTuple(); } @@ -210,31 +210,31 @@ class MockQUICConnection : public QUICConnection } uint32_t - maximum_quic_packet_size() override + maximum_quic_packet_size() const override { return 1200; } uint32_t - pmtu() override + pmtu() const override { return 1280; } QUICPacketNumber - largest_acked_packet_number() override + largest_acked_packet_number() const override { return 0; } NetVConnectionContext_t - direction() override + direction() const override { return _direction; } SSLNextProtocolSet * - next_protocol_set() override + next_protocol_set() const override { return nullptr; } @@ -257,7 +257,7 @@ class MockQUICConnection : public QUICConnection } bool - is_closed() override + is_closed() const override { return false; } diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index e7d567bf851..f0048cd64a9 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -33,20 +33,20 @@ class QUICStreamManager; class UDPPacket; class SSLNextProtocolSet; -class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler +class QUICConnectionInfo { public: - virtual QUICConnectionId peer_connection_id() = 0; - virtual QUICConnectionId original_connection_id() = 0; - virtual QUICConnectionId connection_id() = 0; - virtual const QUICFiveTuple five_tuple() = 0; + virtual QUICConnectionId peer_connection_id() const = 0; + virtual QUICConnectionId original_connection_id() const = 0; + virtual QUICConnectionId connection_id() const = 0; + virtual const QUICFiveTuple five_tuple() const = 0; /* * Retruns the maximum packet size at the time called * * The size depends on PMTU. */ - virtual uint32_t maximum_quic_packet_size() = 0; + virtual uint32_t maximum_quic_packet_size() const = 0; /* * Returns the mimimum packet size at the time called @@ -56,13 +56,17 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler */ virtual uint32_t minimum_quic_packet_size() = 0; - virtual QUICStreamManager *stream_manager() = 0; + virtual uint32_t pmtu() const = 0; + virtual NetVConnectionContext_t direction() const = 0; + virtual SSLNextProtocolSet *next_protocol_set() const = 0; + virtual bool is_closed() const = 0; + virtual QUICPacketNumber largest_acked_packet_number() const = 0; +}; - virtual uint32_t pmtu() = 0; - virtual NetVConnectionContext_t direction() = 0; - virtual SSLNextProtocolSet *next_protocol_set() = 0; +class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler, public QUICConnectionInfo +{ +public: + virtual QUICStreamManager *stream_manager() = 0; virtual void close(QUICConnectionErrorUPtr error) = 0; - virtual QUICPacketNumber largest_acked_packet_number() = 0; virtual void handle_received_packet(UDPPacket *packeet) = 0; - virtual bool is_closed() = 0; }; From 8fe569ada69e6f39838982815b163e4535cb6fa9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 30 May 2018 11:58:51 +0900 Subject: [PATCH 0578/1313] Fix a condition for turining fin flag on --- iocore/net/quic/QUICStream.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 5ae63bbf5ae..b4d45076e2d 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -402,7 +402,7 @@ QUICStream::generate_frame(uint64_t connection_credit, uint16_t maximum_frame_si std::min(static_cast(maximum_frame_size), std::min(this->_remote_flow_controller.credit(), static_cast(connection_credit))))); - if (this->_write_vio.ntodo() == bytes_avail) { + if (this->_write_vio.nbytes == static_cast(this->_send_offset + len)) { fin = true; } From 7a605d51ecc39926774ed3ec215b38e58ed5c6a0 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 30 May 2018 12:03:04 +0900 Subject: [PATCH 0579/1313] Clone frames when retransmit them Actual buffers were released right after scheduling retransmission --- iocore/net/quic/QUICFrame.cc | 124 +++++++++++++++++++++ iocore/net/quic/QUICFrame.h | 32 +++++- iocore/net/quic/QUICIncomingFrameBuffer.cc | 15 +-- iocore/net/quic/QUICIncomingFrameBuffer.h | 1 - iocore/net/quic/QUICPacketRetransmitter.cc | 3 +- 5 files changed, 159 insertions(+), 16 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 7d57387d95e..067c040e29b 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -141,6 +141,13 @@ QUICStreamFrame::split(size_t size) return frame; } +QUICFrameUPtr +QUICStreamFrame::clone() const +{ + return QUICFrameFactory::create_stream_frame(this->data(), this->data_length(), this->stream_id(), this->offset(), + this->has_fin_flag(), this->is_protected()); +} + QUICFrameType QUICStreamFrame::type() const { @@ -411,6 +418,15 @@ QUICAckFrame::reset(const uint8_t *buf, size_t len) this->_ack_block_section = new AckBlockSection(buf + this->_get_ack_block_section_offset(), this->ack_block_count()); } +QUICFrameUPtr +QUICAckFrame::clone() const +{ + std::unique_ptr newframe = QUICFrameFactory::create_ack_frame( + this->largest_acknowledged(), this->ack_delay(), this->ack_block_section()->first_ack_block(), this->is_protected()); + // TODO Copy ack block section + return newframe; +} + QUICFrameType QUICAckFrame::type() const { @@ -834,6 +850,12 @@ QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode { } +QUICFrameUPtr +QUICRstStreamFrame::clone() const +{ + return QUICFrameFactory::create_rst_stream_frame(this->stream_id(), this->error_code(), this->final_offset()); +} + QUICFrameType QUICRstStreamFrame::type() const { @@ -945,6 +967,13 @@ QUICRstStreamFrame::_get_final_offset_field_length() const // // PING frame // + +QUICFrameUPtr +QUICPingFrame::clone() const +{ + return QUICFrameFactory::create_ping_frame(); +} + QUICFrameType QUICPingFrame::type() const { @@ -978,6 +1007,14 @@ QUICPingFrame::store(uint8_t *buf, size_t *len, size_t limit) const // // PADDING frame // + +QUICFrameUPtr +QUICPaddingFrame::clone() const +{ + ink_assert(!"You shouldn't clone padding frames"); + return QUICFrameFactory::create_null_frame(); +} + QUICFrameType QUICPaddingFrame::type() const { @@ -1014,6 +1051,12 @@ QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode error_code this->_reason_phrase = reason_phrase; } +QUICFrameUPtr +QUICConnectionCloseFrame::clone() const +{ + return QUICFrameFactory::create_connection_close_frame(this->error_code(), this->reason_phrase_length(), this->reason_phrase()); +} + QUICFrameType QUICConnectionCloseFrame::type() const { @@ -1121,6 +1164,12 @@ QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code this->_reason_phrase = reason_phrase; } +QUICFrameUPtr +QUICApplicationCloseFrame::clone() const +{ + return QUICFrameFactory::create_application_close_frame(this->error_code(), this->reason_phrase_length(), this->reason_phrase()); +} + QUICFrameType QUICApplicationCloseFrame::type() const { @@ -1224,6 +1273,12 @@ QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, bool protection) this->_maximum_data = maximum_data; } +QUICFrameUPtr +QUICMaxDataFrame::clone() const +{ + return QUICFrameFactory::create_max_data_frame(this->maximum_data()); +} + QUICFrameType QUICMaxDataFrame::type() const { @@ -1290,6 +1345,12 @@ QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t this->_maximum_stream_data = maximum_stream_data; } +QUICFrameUPtr +QUICMaxStreamDataFrame::clone() const +{ + return QUICFrameFactory::create_max_stream_data_frame(this->stream_id(), this->maximum_stream_data()); +} + QUICFrameType QUICMaxStreamDataFrame::type() const { @@ -1386,6 +1447,12 @@ QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, bool this->_maximum_stream_id = maximum_stream_id; } +QUICFrameUPtr +QUICMaxStreamIdFrame::clone() const +{ + return QUICFrameFactory::create_max_stream_id_frame(this->maximum_stream_id()); +} + QUICFrameType QUICMaxStreamIdFrame::type() const { @@ -1444,6 +1511,12 @@ QUICMaxStreamIdFrame::_get_max_stream_id_field_length() const // // BLOCKED frame // +QUICFrameUPtr +QUICBlockedFrame::clone() const +{ + return QUICFrameFactory::create_blocked_frame(this->offset()); +} + QUICFrameType QUICBlockedFrame::type() const { @@ -1504,6 +1577,12 @@ QUICBlockedFrame::_get_offset_field_length() const // // STREAM_BLOCKED frame // +QUICFrameUPtr +QUICStreamBlockedFrame::clone() const +{ + return QUICFrameFactory::create_stream_blocked_frame(this->stream_id(), this->offset()); +} + QUICFrameType QUICStreamBlockedFrame::type() const { @@ -1591,6 +1670,12 @@ QUICStreamBlockedFrame::_get_offset_field_length() const // // STREAM_ID_BLOCKED frame // +QUICFrameUPtr +QUICStreamIdBlockedFrame::clone() const +{ + return QUICFrameFactory::create_stream_id_blocked_frame(this->stream_id()); +} + QUICFrameType QUICStreamIdBlockedFrame::type() const { @@ -1651,6 +1736,12 @@ QUICStreamIdBlockedFrame::_get_stream_id_field_length() const // // NEW_CONNECTION_ID frame // +QUICFrameUPtr +QUICNewConnectionIdFrame::clone() const +{ + // FIXME: Connection ID and Stateless rese token have to be the same + return QUICFrameFactory::create_stream_id_blocked_frame(this->sequence()); +} QUICFrameType QUICNewConnectionIdFrame::type() const @@ -1760,6 +1851,12 @@ QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorC { } +QUICFrameUPtr +QUICStopSendingFrame::clone() const +{ + return QUICFrameFactory::create_stop_sending_frame(this->stream_id(), this->error_code()); +} + QUICFrameType QUICStopSendingFrame::type() const { @@ -1837,6 +1934,12 @@ QUICStopSendingFrame::_get_error_code_field_offset() const // // PATH_CHALLENGE frame // +QUICFrameUPtr +QUICPathChallengeFrame::clone() const +{ + return QUICFrameFactory::create_path_challenge_frame(this->data()); +} + QUICFrameType QUICPathChallengeFrame::type() const { @@ -1887,6 +1990,12 @@ QUICPathChallengeFrame::_data_offset() const // // PATH_RESPONSE frame // +QUICFrameUPtr +QUICPathResponseFrame::clone() const +{ + return QUICFrameFactory::create_path_response_frame(this->data()); +} + QUICFrameType QUICPathResponseFrame::type() const { @@ -1943,6 +2052,13 @@ QUICRetransmissionFrame::QUICRetransmissionFrame(QUICFrameUPtr original_frame, c this->_frame = std::move(original_frame); } +QUICFrameUPtr +QUICRetransmissionFrame::clone() const +{ + ink_assert(!"Retransmission frames shouldn't be cloned"); + return QUICFrameFactory::create_null_frame(); +} + QUICFrameType QUICRetransmissionFrame::type() const { @@ -2189,6 +2305,14 @@ QUICFrameFactory::create_max_stream_data_frame(QUICStreamId stream_id, uint64_t return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); } +std::unique_ptr +QUICFrameFactory::create_max_stream_id_frame(QUICStreamId maximum_stream_id) +{ + QUICMaxStreamIdFrame *frame = quicMaxStreamIdFrameAllocator.alloc(); + new (frame) QUICMaxStreamIdFrame(maximum_stream_id); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_id_frame); +} + std::unique_ptr QUICFrameFactory::create_ping_frame() { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 6c58a2e9df2..1cb32af0a97 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -31,6 +31,11 @@ #include "QUICTypes.h" #include "QUICPacket.h" +class QUICFrame; + +using QUICFrameDeleterFunc = void (*)(QUICFrame *p); +using QUICFrameUPtr = std::unique_ptr; + class QUICFrame { public: @@ -39,6 +44,7 @@ class QUICFrame virtual ~QUICFrame() {} static QUICFrameType type(const uint8_t *buf); + virtual QUICFrameUPtr clone() const = 0; virtual QUICFrameType type() const; virtual size_t size() const = 0; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const = 0; @@ -68,6 +74,7 @@ class QUICStreamFrame : public QUICFrame bool protection = true); QUICFrame *split(size_t size) override; + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -197,6 +204,7 @@ class QUICAckFrame : public QUICFrame virtual ~QUICAckFrame(); virtual void reset(const uint8_t *buf, size_t len) override; + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -234,6 +242,7 @@ class QUICRstStreamFrame : public QUICFrame QUICRstStreamFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, bool protection = true); + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -264,6 +273,7 @@ class QUICPingFrame : public QUICFrame QUICPingFrame() : QUICFrame() {} QUICPingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICPingFrame(bool protection) : QUICFrame(protection) {} + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -278,6 +288,7 @@ class QUICPaddingFrame : public QUICFrame public: QUICPaddingFrame() : QUICFrame() {} QUICPaddingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -294,6 +305,7 @@ class QUICConnectionCloseFrame : public QUICFrame QUICConnectionCloseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase, bool protection = true); + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -322,6 +334,7 @@ class QUICApplicationCloseFrame : public QUICFrame QUICApplicationCloseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase, bool protection = true); + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -349,6 +362,7 @@ class QUICMaxDataFrame : public QUICFrame QUICMaxDataFrame() : QUICFrame() {} QUICMaxDataFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICMaxDataFrame(uint64_t maximum_data, bool protection = true); + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -370,6 +384,7 @@ class QUICMaxStreamDataFrame : public QUICFrame QUICMaxStreamDataFrame() : QUICFrame() {} QUICMaxStreamDataFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, bool protection = true); + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -396,6 +411,7 @@ class QUICMaxStreamIdFrame : public QUICFrame QUICMaxStreamIdFrame() : QUICFrame() {} QUICMaxStreamIdFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, bool protection = true); + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -417,6 +433,7 @@ class QUICBlockedFrame : public QUICFrame QUICBlockedFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICBlockedFrame(QUICOffset offset, bool protection = true) : QUICFrame(protection), _offset(offset){}; + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -440,6 +457,7 @@ class QUICStreamBlockedFrame : public QUICFrame QUICStreamBlockedFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o, bool protection = true) : QUICFrame(protection), _stream_id(s), _offset(o){}; + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -465,6 +483,7 @@ class QUICStreamIdBlockedFrame : public QUICFrame QUICStreamIdBlockedFrame() : QUICFrame() {} QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICStreamIdBlockedFrame(QUICStreamId s, bool protection = true) : QUICFrame(protection), _stream_id(s) {} + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -489,6 +508,7 @@ class QUICNewConnectionIdFrame : public QUICFrame QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId id, QUICStatelessResetToken token, bool protection = true) : QUICFrame(protection), _sequence(seq), _connection_id(id), _stateless_reset_token(token){}; + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -518,6 +538,7 @@ class QUICStopSendingFrame : public QUICFrame QUICStopSendingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, bool protection = true); + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -544,6 +565,7 @@ class QUICPathChallengeFrame : public QUICFrame QUICPathChallengeFrame() : QUICFrame() {} QUICPathChallengeFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICPathChallengeFrame(ats_unique_buf data, bool protection = true) : QUICFrame(protection), _data(std::move(data)) {} + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -567,6 +589,7 @@ class QUICPathResponseFrame : public QUICFrame QUICPathResponseFrame() : QUICFrame() {} QUICPathResponseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} QUICPathResponseFrame(ats_unique_buf data, bool protection = true) : QUICFrame(protection), _data(std::move(data)) {} + QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -579,9 +602,7 @@ class QUICPathResponseFrame : public QUICFrame ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; }; -using QUICFrameDeleterFunc = void (*)(QUICFrame *p); -using QUICFrameUPtr = std::unique_ptr; -using QUICStreamFrameUPtr = std::unique_ptr; +using QUICStreamFrameUPtr = std::unique_ptr; // // Retransmission Frame @@ -592,6 +613,7 @@ class QUICRetransmissionFrame : public QUICFrame public: QUICRetransmissionFrame() : QUICFrame() {} QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet); + QUICFrameUPtr clone() const override; QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -831,6 +853,10 @@ class QUICFrameFactory */ static std::unique_ptr create_max_stream_data_frame(QUICStreamId stream_id, uint64_t maximum_stream_data); + /* + * Creates a MAX_STREAM_ID frame. + */ + static std::unique_ptr create_max_stream_id_frame(QUICStreamId maximum_stream_id); /* * Creates a PING frame diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index f2cea29d5ae..04c5fe0b8f1 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -68,10 +68,12 @@ QUICIncomingFrameBuffer::insert(const std::shared_ptr fra // dup frame; return QUICErrorUPtr(new QUICNoError()); } else if (this->_recv_offset == offset) { - this->_recv_offset = offset + len; - this->_recv_buffer.push(this->_clone(frame)); + this->_recv_offset = offset + len; + std::shared_ptr cloned = frame->clone(); + this->_recv_buffer.push(std::static_pointer_cast(cloned)); } else { - this->_out_of_order_queue.insert(std::make_pair(offset, this->_clone(frame))); + std::shared_ptr cloned = frame->clone(); + this->_out_of_order_queue.insert(std::make_pair(offset, std::static_pointer_cast(cloned))); } return QUICErrorUPtr(new QUICNoError()); @@ -97,13 +99,6 @@ QUICIncomingFrameBuffer::empty() return this->_out_of_order_queue.empty() && this->_recv_buffer.empty(); } -std::shared_ptr -QUICIncomingFrameBuffer::_clone(std::shared_ptr frame) -{ - return QUICFrameFactory::create_stream_frame(frame->data(), frame->data_length(), frame->stream_id(), frame->offset(), - frame->has_fin_flag(), frame->is_protected()); -} - QUICErrorUPtr QUICIncomingFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, bool fin_flag) { diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index 5ecfb6ec8d8..e945303bf24 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -51,7 +51,6 @@ class QUICIncomingFrameBuffer QUICOffset _max_offset = 0; QUICOffset _fin_offset = UINT64_MAX; - std::shared_ptr _clone(std::shared_ptr frame); QUICErrorUPtr _check_and_set_fin_flag(QUICOffset offset, size_t len = 0, bool fin_flag = false); std::queue> _recv_buffer; diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 843e294f584..24e7946a154 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -46,8 +46,7 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) case QUICFrameType::ACK: break; default: - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), packet); - // FIXME We should probably reframe STREAM frames so that it can fit in new packets + frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); this->_retransmission_frames.push(std::move(frame)); break; } From 4c2db196bb1ff9f24bab5c2921b5c98a7ffe4d27 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 30 May 2018 12:17:48 +0900 Subject: [PATCH 0580/1313] Prevent logging "not ready" when no packets are in queue --- iocore/net/QUICNetVConnection.cc | 4 ++++ iocore/net/quic/QUICPacketReceiveQueue.cc | 2 +- iocore/net/quic/QUICTypes.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 701b39e1f69..8126bacf49a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -938,6 +938,8 @@ QUICNetVConnection::_state_common_receive_packet() QUICPacketUPtr p = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::FAILED) { return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); + } else if (result == QUICPacketCreationResult::NO_PACKET) { + return QUICErrorUPtr(new QUICNoError()); } else if (result == QUICPacketCreationResult::NOT_READY) { return QUICErrorUPtr(new QUICNoError()); } else if (result == QUICPacketCreationResult::IGNORED) { @@ -1460,6 +1462,8 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) // Debug prints switch (result) { + case QUICPacketCreationResult::NO_PACKET: + break; case QUICPacketCreationResult::NOT_READY: QUICConDebug("Not ready to decrypt the packet"); break; diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 04f8602348c..887b965ecd7 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -71,7 +71,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) if (!this->_payload) { udp_packet = this->_queue.dequeue(); if (!udp_packet) { - result = QUICPacketCreationResult::NOT_READY; + result = QUICPacketCreationResult::NO_PACKET; return quic_packet; } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 715b37c6d40..abc8ea1edb6 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -124,6 +124,7 @@ enum class QUICKeyPhase : int { enum class QUICPacketCreationResult { SUCCESS, FAILED, + NO_PACKET, NOT_READY, IGNORED, UNSUPPORTED, From 997729b69d43de6bf3d39ff28ae672161a562a0c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 31 May 2018 11:35:37 +0900 Subject: [PATCH 0581/1313] Fix deleter of QUICPathResponseFrame unique pointer --- iocore/net/quic/QUICFrame.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 067c040e29b..a79ef85d550 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2340,7 +2340,7 @@ QUICFrameFactory::create_path_response_frame(const uint8_t *data) QUICPathResponseFrame *frame = quicPathResponseFrameAllocator.alloc(); new (frame) QUICPathResponseFrame(std::move(buf), false); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_challenge_frame); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_response_frame); } std::unique_ptr From e2c5a0fdf4762592fec406eff9cc89ec79567596 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 31 May 2018 10:59:58 +0900 Subject: [PATCH 0582/1313] Rename QUICConnectionInfo QUICConnectionInfoProvider --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/quic/QUICConnection.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 07884d27033..94f6ccfae50 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -191,7 +191,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void close(QUICConnectionErrorUPtr error) override; void handle_received_packet(UDPPacket *packet) override; - // QUICConnection (QUICConnectionInfo) + // QUICConnection (QUICConnectionInfoProvider) QUICConnectionId peer_connection_id() const override; QUICConnectionId original_connection_id() const override; QUICConnectionId connection_id() const override; diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index f0048cd64a9..1f7cd8fef4f 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -33,7 +33,7 @@ class QUICStreamManager; class UDPPacket; class SSLNextProtocolSet; -class QUICConnectionInfo +class QUICConnectionInfoProvider { public: virtual QUICConnectionId peer_connection_id() const = 0; @@ -63,7 +63,7 @@ class QUICConnectionInfo virtual QUICPacketNumber largest_acked_packet_number() const = 0; }; -class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler, public QUICConnectionInfo +class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler, public QUICConnectionInfoProvider { public: virtual QUICStreamManager *stream_manager() = 0; From 976cec2ac7fc7932a0890ab8decdd532a7c1f3b5 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 29 May 2018 14:05:41 +0900 Subject: [PATCH 0583/1313] Print dcid and scid in debug log to identify quic connection Only change logs in QUICNetVConnection. Other components will be fixed. --- iocore/net/P_QUICNetVConnection.h | 16 ++++++-- iocore/net/QUICNetVConnection.cc | 64 ++++++++++++++++++++++--------- iocore/net/quic/Mock.h | 6 +++ iocore/net/quic/QUICConnection.h | 1 + iocore/net/quic/QUICTypes.cc | 6 +++ iocore/net/quic/QUICTypes.h | 1 + 6 files changed, 73 insertions(+), 21 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 94f6ccfae50..3398aa61315 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -74,6 +74,9 @@ #define QUIC_OP_HANDSHAKE 0x16 +// Size of connection ids for debug log : e.g. aaaaaaaa-bbbbbbbb\0 +static constexpr size_t MAX_CIDS_SIZE = 8 + 1 + 8 + 1; + // class QUICNextProtocolSet; // struct QUICCertLookup; @@ -195,6 +198,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICConnectionId peer_connection_id() const override; QUICConnectionId original_connection_id() const override; QUICConnectionId connection_id() const override; + std::string_view cids() const override; const QUICFiveTuple five_tuple() const override; uint32_t maximum_quic_packet_size() const override; uint32_t minimum_quic_packet_size() override; @@ -228,11 +232,14 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketType _last_received_packet_type = QUICPacketType::UNINITIALIZED; std::random_device _rnd; - QUICConnectionId _peer_quic_connection_id; - QUICConnectionId _original_quic_connection_id; - QUICConnectionId _quic_connection_id; + QUICConnectionId _peer_quic_connection_id; // dst cid + QUICConnectionId _original_quic_connection_id; // dst cid of initial packet from client + QUICConnectionId _quic_connection_id; // src cid QUICFiveTuple _five_tuple; + char _cids_data[MAX_CIDS_SIZE] = {0}; + std::string_view _cids; + UDPConnection *_udp_con = nullptr; QUICPacketHandler *_packet_handler = nullptr; QUICPacketFactory _packet_factory; @@ -332,6 +339,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _handle_idle_timeout(); + void _update_cids(); + void _update_peer_cid(const QUICConnectionId &new_cid); + QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet(); QUICStatelessResetToken _reset_token; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8126bacf49a..bd216a7472e 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -42,13 +42,15 @@ #define STATE_FROM_VIO(_x) ((NetState *)(((char *)(_x)) - STATE_VIO_OFFSET)) #define STATE_VIO_OFFSET ((uintptr_t) & ((NetState *)0)->vio) -#define QUICConDebug(fmt, ...) Debug("quic_net", "[%" PRIx64 "] " fmt, this->_peer_quic_connection_id.l64(), ##__VA_ARGS__) +#define QUICConDebug(fmt, ...) Debug("quic_net", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__) -#define QUICConVDebug(fmt, ...) Debug("v_quic_net", "[%" PRIx64 "] " fmt, this->_peer_quic_connection_id.l64(), ##__VA_ARGS__) +#define QUICConVDebug(fmt, ...) Debug("v_quic_net", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__) -#define QUICError(fmt, ...) \ - Debug("quic_net", "[%" PRIx64 "] " fmt, this->_peer_quic_connection_id.l64(), ##__VA_ARGS__); \ - Error("quic_net [%" PRIx64 "] " fmt, this->_peer_quic_connection_id.l64(), ##__VA_ARGS__) +#define QUICFCDebug(fmt, ...) Debug("quic_flow_ctrl", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__) + +#define QUICError(fmt, ...) \ + Debug("quic_net", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__); \ + Error("quic_net [%s] " fmt, this->cids().data(), ##__VA_ARGS__) static constexpr uint32_t IPV4_HEADER_SIZE = 20; static constexpr uint32_t IPV6_HEADER_SIZE = 40; @@ -84,8 +86,10 @@ QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_ci this->_ctable->insert(this->_original_quic_connection_id, this); } - QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, this->_original_quic_connection_id.l64(), - this->_quic_connection_id.l64()); + this->_update_cids(); + + // TODO: print full cids + QUICConDebug("dcid=%08" PRIx32 " scid=%08" PRIx32, this->_peer_quic_connection_id.h32(), this->_quic_connection_id.h32()); } bool @@ -339,6 +343,12 @@ QUICNetVConnection::connection_id() const return this->_quic_connection_id; } +std::string_view +QUICNetVConnection::cids() const +{ + return this->_cids; +} + const QUICFiveTuple QUICNetVConnection::five_tuple() const { @@ -457,8 +467,8 @@ QUICNetVConnection::handle_frame(std::shared_ptr frame) switch (frame->type()) { case QUICFrameType::MAX_DATA: this->_remote_flow_controller->forward_limit(std::static_pointer_cast(frame)->maximum_data()); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, this->_peer_quic_connection_id.l64(), - this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); + QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); this->_schedule_packet_write_ready(); break; @@ -1247,8 +1257,8 @@ QUICNetVConnection::_packetize_frames() ++frame_count; if (frame->type() == QUICFrameType::STREAM) { int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, this->_peer_quic_connection_id.l64(), - this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); + QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); ink_assert(ret == 0); } this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); @@ -1319,8 +1329,8 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) } int ret = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, this->_peer_quic_connection_id.l64(), - this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); + QUICFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); if (ret != 0) { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } @@ -1410,10 +1420,10 @@ QUICNetVConnection::_init_flow_control_params(const std::shared_ptr_local_flow_controller->set_limit(local_initial_max_data); this->_remote_flow_controller->set_limit(remote_initial_max_data); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64, this->_peer_quic_connection_id.l64(), - this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); - Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [REMOTE] %" PRIu64 "/%" PRIu64, this->_peer_quic_connection_id.l64(), - this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); + QUICFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); + QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); } void @@ -1451,7 +1461,7 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) // 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->_peer_quic_connection_id = src_cid; + this->_update_peer_cid(src_cid); } } } @@ -1752,3 +1762,21 @@ QUICNetVConnection::_validate_new_path() ink_hrtime rto = this->_loss_detector->current_rto_period(); this->_schedule_path_validation_timeout(3 * rto); } + +void +QUICNetVConnection::_update_cids() +{ + snprintf(this->_cids_data, sizeof(this->_cids_data), "%08" PRIx32 "-%08" PRIx32 "", this->_peer_quic_connection_id.h32(), + this->_quic_connection_id.h32()); + + this->_cids = {this->_cids_data, sizeof(this->_cids_data)}; +} + +void +QUICNetVConnection::_update_peer_cid(const QUICConnectionId &new_cid) +{ + QUICConDebug("dcid: %08" PRIx32 " -> %08" PRIx32, this->_peer_quic_connection_id.h32(), new_cid.h32()); + + this->_peer_quic_connection_id = new_cid; + this->_update_cids(); +} diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index b71355426ee..761e96f157c 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -169,6 +169,12 @@ class MockQUICConnection : public QUICConnection return QUICFiveTuple(); } + std::string_view + cids() const override + { + return std::string_view("00000000-00000000"sv); + } + uint32_t transmit_packet(QUICPacketUPtr packet) override { diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 1f7cd8fef4f..2b4b5e16f6e 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -39,6 +39,7 @@ class QUICConnectionInfoProvider virtual QUICConnectionId peer_connection_id() const = 0; virtual QUICConnectionId original_connection_id() const = 0; virtual QUICConnectionId connection_id() const = 0; + virtual std::string_view cids() const = 0; virtual const QUICFiveTuple five_tuple() const = 0; /* diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 33a43e2b68a..be89426fcd4 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -285,3 +285,9 @@ QUICConnectionId::l64() const } return v; } + +uint32_t +QUICConnectionId::h32() const +{ + return static_cast(QUICIntUtil::read_nbytes_as_uint(this->_id, 4)); +} diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index abc8ea1edb6..7b267774578 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -245,6 +245,7 @@ class QUICConnectionId * This is just for debugging. */ uint64_t l64() const; + uint32_t h32() const; uint8_t length() const; bool is_zero() const; From 4712f8a260aefb3e2c0a2c21af98074660d18650 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 31 May 2018 10:34:14 +0900 Subject: [PATCH 0584/1313] Refer QUICConnectionInfoProviter when print debug log --- cmd/traffic_quic/quic_client.cc | 3 +- iocore/net/P_QUICNetVConnection.h | 4 +- iocore/net/QUICNetProcessor.cc | 8 +- iocore/net/QUICNetVConnection.cc | 16 +++- iocore/net/QUICPacketHandler.cc | 37 +++++---- iocore/net/quic/Mock.h | 81 ++++++++++++++++++- iocore/net/quic/QUICApplication.cc | 2 +- iocore/net/quic/QUICCongestionController.cc | 12 ++- iocore/net/quic/QUICHandshake.cc | 4 +- iocore/net/quic/QUICLossDetector.cc | 11 +-- iocore/net/quic/QUICLossDetector.h | 11 ++- iocore/net/quic/QUICPacketRetransmitter.cc | 1 - iocore/net/quic/QUICStream.cc | 18 ++--- iocore/net/quic/QUICStream.h | 5 +- iocore/net/quic/QUICStreamManager.cc | 6 +- iocore/net/quic/QUICStreamManager.h | 6 +- iocore/net/quic/test/test_QUICFrame.cc | 2 +- .../net/quic/test/test_QUICFrameDispatcher.cc | 6 +- iocore/net/quic/test/test_QUICLossDetector.cc | 18 +++-- iocore/net/quic/test/test_QUICStream.cc | 11 +-- .../net/quic/test/test_QUICStreamManager.cc | 8 +- proxy/hq/HQClientSession.cc | 2 +- proxy/hq/HQClientTransaction.cc | 7 +- 23 files changed, 186 insertions(+), 93 deletions(-) diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc index da435832f2a..d01bd0987e3 100644 --- a/cmd/traffic_quic/quic_client.cc +++ b/cmd/traffic_quic/quic_client.cc @@ -112,8 +112,7 @@ QUICClient::state_http_server_open(int event, void *data) // // QUICClientApp // -#define QUICClientAppDebug(fmt, ...) \ - Debug("quic_client_app", "[%" PRIx64 "] " fmt, static_cast(this->_qc->connection_id()), ##__VA_ARGS__) +#define QUICClientAppDebug(fmt, ...) Debug("quic_client_app", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) QUICClientApp::QUICClientApp(QUICNetVConnection *qvc, const char *filename) : QUICApplication(qvc), _filename(filename) { diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 3398aa61315..3b255f28f03 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -232,9 +232,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketType _last_received_packet_type = QUICPacketType::UNINITIALIZED; std::random_device _rnd; - QUICConnectionId _peer_quic_connection_id; // dst cid + QUICConnectionId _peer_quic_connection_id; // dst cid in local QUICConnectionId _original_quic_connection_id; // dst cid of initial packet from client - QUICConnectionId _quic_connection_id; // src cid + QUICConnectionId _quic_connection_id; // src cid in local QUICFiveTuple _five_tuple; char _cids_data[MAX_CIDS_SIZE] = {0}; diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 1d55a734580..8807a1517cf 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -139,11 +139,9 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne } // Setup QUICNetVConnection - QUICConnectionId scid; - QUICConnectionId dcid; - scid.randomize(); - dcid.randomize(); - vc->init(scid, dcid, con, packet_handler); + QUICConnectionId client_dst_cid; + client_dst_cid.randomize(); + vc->init(client_dst_cid, client_dst_cid, con, packet_handler); packet_handler->init(vc); // Connection ID will be changed diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index bd216a7472e..2c1f1a52dd9 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -205,13 +205,12 @@ QUICNetVConnection::start() this->_packet_factory.set_hs_protocol(this->_hs_protocol); // Create frame handlers - this->_congestion_controller = new QUICCongestionController(this->peer_connection_id()); - this->_loss_detector = new QUICLossDetector(this, this->_congestion_controller); + this->_congestion_controller = new QUICCongestionController(this); + this->_loss_detector = new QUICLossDetector(this, this, this->_congestion_controller); this->_remote_flow_controller = new QUICRemoteConnectionFlowController(UINT64_MAX); this->_local_flow_controller = new QUICLocalConnectionFlowController(this->_loss_detector, UINT64_MAX); this->_path_validator = new QUICPathValidator(); - this->_stream_manager = - new QUICStreamManager(this->_loss_detector, this->peer_connection_id(), this->_application_map, this->netvc_context); + this->_stream_manager = new QUICStreamManager(this->_loss_detector, this, this->_application_map, this->netvc_context); this->_frame_dispatcher->add_handler(this); this->_frame_dispatcher->add_handler(this->_stream_manager); @@ -343,6 +342,12 @@ QUICNetVConnection::connection_id() const return this->_quic_connection_id; } +/* + Return combination of dst connection id and src connection id for debug log + e.g. "aaaaaaaa-bbbbbbbb" + - "aaaaaaaa" : high 32 bit of dst connection id + - "bbbbbbbb" : high 32 bit of src connection id + */ std::string_view QUICNetVConnection::cids() const { @@ -427,6 +432,8 @@ QUICNetVConnection::transmit_packet(QUICPacketUPtr packet) void QUICNetVConnection::retransmit_packet(const QUICPacket &packet) { + QUICConDebug("Retransmit packet #%" PRIu64 " type %s", packet.packet_number(), QUICDebugNames::packet_type(packet.type())); + this->_packet_retransmitter.retransmit_packet(packet); } @@ -1775,6 +1782,7 @@ QUICNetVConnection::_update_cids() void QUICNetVConnection::_update_peer_cid(const QUICConnectionId &new_cid) { + // TODO: print full cids QUICConDebug("dcid: %08" PRIx32 " -> %08" PRIx32, this->_peer_quic_connection_id.h32(), new_cid.h32()); this->_peer_quic_connection_id = new_cid; diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 17241a8c4c5..6717880e62a 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -30,6 +30,12 @@ #include "QUICDebugNames.h" #include "QUICEvents.h" +#define QUICDebugQC(qc, fmt, ...) Debug("quic_sec", "[%s] " fmt, qc->cids().data(), ##__VA_ARGS__) + +// ["local dcid" - "local scid"] +#define QUICDebugDS(dcid, scid, fmt, ...) \ + Debug("quic_sec", "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__) + // // QUICPacketHandler // @@ -74,8 +80,13 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo // NOTE: p will be enqueued to udpOutQueue of UDPNetHandler ip_port_text_buffer ipb; - Debug("quic_sec", "[%" PRIx64 "] send %s packet to %s, size=%" PRId64, packet.destination_cid().l64(), - QUICDebugNames::packet_type(packet.type()), ats_ip_nptop(&udp_packet->to.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); + QUICConnectionId dcid = packet.destination_cid(); + QUICConnectionId scid = QUICConnectionId::ZERO(); + if (packet.type() != QUICPacketType::PROTECTED) { + scid = packet.source_cid(); + } + QUICDebugDS(dcid, scid, "send %s packet to %s size=%" PRId64, QUICDebugNames::packet_type(packet.type()), + ats_ip_nptop(&udp_packet->to.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); udp_con->send(c, udp_packet); } @@ -178,14 +189,15 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) if (is_debug_tag_set("quic_sec")) { ip_port_text_buffer ipb; + QUICConnectionId dcid = this->_read_destination_connection_id(block); + QUICConnectionId scid = QUICConnectionId::ZERO(); if (QUICTypeUtil::has_long_header(reinterpret_cast(block->buf()))) { - QUICConnectionId cid = this->_read_source_connection_id(block); - Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, cid.l64(), - ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); - } else { - Debug("quic_sec", "received packet from %s, size=%" PRId64, ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), - udp_packet->getPktLength()); + scid = this->_read_source_connection_id(block); } + // Remote dst cid is src cid in local + // TODO: print packet type + QUICDebugDS(scid, dcid, "recv packet from %s, size=%" PRId64, ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), + udp_packet->getPktLength()); } QUICConnection *qc = @@ -299,13 +311,10 @@ QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection * void QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet) { - IOBufferBlock *block = udp_packet->getIOBlockChain(); - - QUICConnectionId cid = this->_read_destination_connection_id(block); - ip_port_text_buffer ipb; - Debug("quic_sec", "[%" PRIx64 "] received packet from %s, size=%" PRId64, cid.l64(), - ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); + // TODO: print packet type + QUICDebugQC(this->_vc, "recv packet from %s size=%" PRId64, ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), + udp_packet->getPktLength()); 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/Mock.h b/iocore/net/quic/Mock.h index 761e96f157c..a798a342265 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -284,6 +284,81 @@ class MockQUICConnection : public QUICConnection NetVConnectionContext_t _direction; }; +class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider +{ + QUICConnectionId + connection_id() const override + { + return {reinterpret_cast("\x00"), 1}; + } + + QUICConnectionId + peer_connection_id() const override + { + return {reinterpret_cast("\x00"), 1}; + } + + QUICConnectionId + original_connection_id() const override + { + return {reinterpret_cast("\x00"), 1}; + } + + const QUICFiveTuple + five_tuple() const override + { + return QUICFiveTuple(); + } + + std::string_view + cids() const override + { + return std::string_view("00000000-00000000"sv); + } + + uint32_t + minimum_quic_packet_size() override + { + return 1200; + } + + uint32_t + maximum_quic_packet_size() const override + { + return 1200; + } + + uint32_t + pmtu() const override + { + return 1280; + } + + QUICPacketNumber + largest_acked_packet_number() const override + { + return 0; + } + + NetVConnectionContext_t + direction() const override + { + return NET_VCONNECTION_OUT; + } + + SSLNextProtocolSet * + next_protocol_set() const override + { + return nullptr; + } + + bool + is_closed() const override + { + return false; + } +}; + class MockQUICPacketTransmitter : public QUICPacketTransmitter { public: @@ -319,6 +394,7 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter class MockQUICCongestionController : public QUICCongestionController { public: + MockQUICCongestionController(QUICConnectionInfoProvider *info) : QUICCongestionController(info) {} // Override virtual void on_packets_lost(std::map &packets) override @@ -363,7 +439,10 @@ class MockQUICCongestionController : public QUICCongestionController class MockQUICLossDetector : public QUICLossDetector { public: - MockQUICLossDetector() : QUICLossDetector(new MockQUICPacketTransmitter(), new MockQUICCongestionController()) {} + MockQUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, QUICCongestionController *cc) + : QUICLossDetector(transmitter, info, cc) + { + } void rcv_frame(std::shared_ptr) { diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index cd178f0105e..4a960d5b204 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -199,7 +199,7 @@ QUICApplication::reenable(QUICStream *stream) stream_io->read_reenable(); stream_io->write_reenable(); } else { - Debug(tag, "[%" PRIx64 "] Unknown Stream, id: %" PRIx64, this->_qc->connection_id().l64(), stream->id()); + Debug(tag, "[%s] Unknown Stream id=%" PRIx64, this->_qc->cids().data(), stream->id()); } return; diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 9a756d8a4dc..fa580e6adfa 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -28,19 +28,17 @@ #define QUICCCDebug(fmt, ...) \ Debug("quic_cc", \ - "[%" PRIx64 "] " \ + "[%s] " \ "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ - this->_connection_id.l64(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, ##__VA_ARGS__) + this->_info->cids().data(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, ##__VA_ARGS__) #define QUICCCError(fmt, ...) \ Error("quic_cc", \ - "[%" PRIx64 "] " \ + "[%s] " \ "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ - this->_connection_id.l64(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, ##__VA_ARGS__) + this->_info->cids().data(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, ##__VA_ARGS__) -QUICCongestionController::QUICCongestionController() : QUICCongestionController(QUICConnectionId::ZERO()) {} - -QUICCongestionController::QUICCongestionController(QUICConnectionId connection_id) : _connection_id(connection_id) +QUICCongestionController::QUICCongestionController(QUICConnectionInfoProvider *info) : _info(info) { QUICConfig::scoped_config params; this->_k_default_mss = params->cc_default_mss(); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 715c01cf7a3..e765e67c1c8 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -36,9 +36,9 @@ static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; -#define QUICHSDebug(fmt, ...) Debug("quic_handshake", "[%" PRIx64 "] " fmt, this->_qc->peer_connection_id().l64(), ##__VA_ARGS__) +#define QUICHSDebug(fmt, ...) Debug("quic_handshake", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) -#define QUICVHSDebug(fmt, ...) Debug("v_quic_handshake", "[%" PRIx64 "] " fmt, this->_qc->peer_connection_id().l64(), ##__VA_ARGS__) +#define QUICVHSDebug(fmt, ...) Debug("v_quic_handshake", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) #define I_WANNA_DUMP_THIS_BUF(buf, len) \ { \ diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index e58fce22139..a2eca1349e7 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -28,10 +28,11 @@ #include "QUICConfig.h" #include "QUICEvents.h" -#define QUICLDDebug(fmt, ...) Debug("quic_loss_detector", "[%" PRIx64 "] " fmt, this->_connection_id.l64(), ##__VA_ARGS__) +#define QUICLDDebug(fmt, ...) Debug("quic_loss_detector", "[%s] " fmt, this->_info->cids().data(), ##__VA_ARGS__) -QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICCongestionController *cc) - : _transmitter(transmitter), _cc(cc) +QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, + QUICCongestionController *cc) + : _transmitter(transmitter), _info(info), _cc(cc) { this->mutex = new_ProxyMutex(); this->_loss_detection_mutex = new_ProxyMutex(); @@ -131,10 +132,6 @@ QUICLossDetector::largest_acked_packet_number() void QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) { - if (this->_connection_id.is_zero() && packet->type() != QUICPacketType::VERSION_NEGOTIATION) { - this->_connection_id = packet->destination_cid(); - } - bool is_handshake = false; QUICPacketType type = packet->type(); diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index c44872753d2..c8a1deb88f5 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -36,6 +36,7 @@ #include "QUICFrame.h" #include "QUICFrameHandler.h" #include "QUICPacketTransmitter.h" +#include "QUICConnection.h" class QUICLossDetector; @@ -57,8 +58,7 @@ class QUICRTTProvider class QUICCongestionController { public: - QUICCongestionController(); - QUICCongestionController(QUICConnectionId connection_id); + QUICCongestionController(QUICConnectionInfoProvider *info); virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); void on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size); @@ -85,7 +85,7 @@ class QUICCongestionController QUICPacketNumber _end_of_recovery = 0; uint32_t _ssthresh = UINT32_MAX; - QUICConnectionId _connection_id = QUICConnectionId::ZERO(); + QUICConnectionInfoProvider *_info = nullptr; bool _in_recovery(QUICPacketNumber packet_number); }; @@ -93,7 +93,7 @@ class QUICCongestionController class QUICLossDetector : public Continuation, public QUICFrameHandler, public QUICRTTProvider { public: - QUICLossDetector(QUICPacketTransmitter *transmitter, QUICCongestionController *cc); + QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, QUICCongestionController *cc); ~QUICLossDetector(); int event_handler(int event, Event *edata); @@ -109,8 +109,6 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU private: Ptr _loss_detection_mutex; - QUICConnectionId _connection_id = QUICConnectionId::ZERO(); - // TODO QUICCongestionController *cc = nullptr; // 3.4.1. Constants of interest (draft-10) @@ -174,5 +172,6 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU void _send_two_packets(); QUICPacketTransmitter *_transmitter = nullptr; + QUICConnectionInfoProvider *_info = nullptr; QUICCongestionController *_cc = nullptr; }; diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 24e7946a154..5f9ba333509 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -27,7 +27,6 @@ void QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) { - Debug("quic_con", "Retransmit packet #%" PRIu64 " type %s", packet.packet_number(), QUICDebugNames::packet_type(packet.type())); ink_assert(packet.type() != QUICPacketType::VERSION_NEGOTIATION && packet.type() != QUICPacketType::UNINITIALIZED); // Get payload from a header because packet.payload() is encrypted diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index b4d45076e2d..61df854081b 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -28,22 +28,22 @@ #include "QUICStreamManager.h" #include "QUICDebugNames.h" -#define QUICStreamDebug(fmt, ...) \ - Debug("quic_stream", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, this->_connection_id.l64(), this->_id, \ +#define QUICStreamDebug(fmt, ...) \ + Debug("quic_stream", "[%s] [%" PRIx64 "] [%s] " fmt, this->_info->cids().data(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) -#define QUICVStreamDebug(fmt, ...) \ - Debug("v_quic_stream", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, this->_connection_id.l64(), this->_id, \ +#define QUICVStreamDebug(fmt, ...) \ + Debug("v_quic_stream", "[%s] [%" PRIx64 "] [%s] " fmt, this->_info->cids().data(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) -#define QUICStreamFCDebug(fmt, ...) \ - Debug("quic_flow_ctrl", "[%" PRIx64 "] [%" PRIx64 "] [%s] " fmt, this->_connection_id.l64(), this->_id, \ +#define QUICStreamFCDebug(fmt, ...) \ + Debug("quic_flow_ctrl", "[%s] [%" PRIx64 "] [%s] " fmt, this->_info->cids().data(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) -QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data, - uint64_t send_max_stream_data) +QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICStreamId sid, + uint64_t recv_max_stream_data, uint64_t send_max_stream_data) : VConnection(nullptr), - _connection_id(cid), + _info(info), _id(sid), _remote_flow_controller(send_max_stream_data, _id), _local_flow_controller(rtt_provider, recv_max_stream_data, _id), diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 5515225c3c3..af3afcc63f9 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -34,6 +34,7 @@ #include "QUICIncomingFrameBuffer.h" #include "QUICFrameGenerator.h" #include "QUICLossDetector.h" +#include "QUICConnection.h" class QUICNetVConnection; class QUICStreamState; @@ -53,7 +54,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator _received_stream_frame_buffer(this) { } - QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICStreamId sid, uint64_t recv_max_stream_data = 0, + QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICStreamId sid, uint64_t recv_max_stream_data = 0, uint64_t send_max_stream_data = 0); ~QUICStream(); // void start(); @@ -102,7 +103,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator QUICStreamState _state; QUICStreamErrorUPtr _reset_reason = nullptr; - QUICConnectionId _connection_id = QUICConnectionId::ZERO(); + QUICConnectionInfoProvider *_info = nullptr; QUICStreamId _id = 0; QUICOffset _send_offset = 0; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 026a0f9c295..b5cd442349d 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -32,9 +32,9 @@ static constexpr char tag[] = "quic_stream_manager"; ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); ClassAllocator quicStreamAllocator("quicStreamAllocator"); -QUICStreamManager::QUICStreamManager(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICApplicationMap *app_map, +QUICStreamManager::QUICStreamManager(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICApplicationMap *app_map, NetVConnectionContext_t context) - : _connection_id(cid), _app_map(app_map), _netvc_context(context), _rtt_provider(rtt_provider) + : _info(info), _rtt_provider(rtt_provider), _app_map(app_map), _netvc_context(context) { if (this->_netvc_context == NET_VCONNECTION_OUT) { // stream 0 is for handshake, smallest client bidi stream id is 4 @@ -290,7 +290,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) // TODO Free the stream somewhere stream = THREAD_ALLOC(quicStreamAllocator, this_ethread()); - new (stream) QUICStream(this->_rtt_provider, this->_connection_id, stream_id, local_max_stream_data, remote_max_stream_data); + new (stream) QUICStream(this->_rtt_provider, this->_info, stream_id, local_max_stream_data, remote_max_stream_data); this->stream_list.push(stream); } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 449db9ea275..88ae800b1c4 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -38,7 +38,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator { public: QUICStreamManager(){}; - QUICStreamManager(QUICRTTProvider *rtt_provider, QUICConnectionId cid, QUICApplicationMap *app_map, + QUICStreamManager(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICApplicationMap *app_map, NetVConnectionContext_t context); void init_flow_control_params(const std::shared_ptr &local_tp, @@ -77,7 +77,8 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICErrorUPtr _handle_frame(const std::shared_ptr &); - QUICConnectionId _connection_id = QUICConnectionId::ZERO(); + QUICConnectionInfoProvider *_info = nullptr; + QUICRTTProvider *_rtt_provider = nullptr; QUICApplicationMap *_app_map = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; std::shared_ptr _local_tp = nullptr; @@ -89,5 +90,4 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICStreamId _next_stream_id_uni = 0; QUICStreamId _next_stream_id_bidi = 0; uint64_t _total_offset_sent = 0; - QUICRTTProvider *_rtt_provider = nullptr; }; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 27d827995c0..c455be45eb1 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1158,7 +1158,7 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") { - QUICStream stream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), 0x1234, 0, 0); + QUICStream stream(new MockQUICRTTProvider(), new MockQUICConnection(), 0x1234, 0, 0); std::unique_ptr error = std::unique_ptr(new QUICStreamError(&stream, static_cast(0x01))); std::unique_ptr rst_stream_frame1 = diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index d307d29e13d..e1cbddfbf84 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -37,7 +37,11 @@ TEST_CASE("QUICFrameHandler", "[quic]") auto connection = new MockQUICConnection(); auto streamManager = new MockQUICStreamManager(); - auto lossDetector = new MockQUICLossDetector(); + auto tx = new MockQUICPacketTransmitter(); + auto info = new MockQUICConnectionInfoProvider(); + auto cc = new MockQUICCongestionController(info); + auto lossDetector = new MockQUICLossDetector(tx, info, cc); + QUICFrameDispatcher quicFrameDispatcher; quicFrameDispatcher.add_handler(connection); quicFrameDispatcher.add_handler(streamManager); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index ae3dce77734..26d0f561798 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -34,11 +34,12 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") QUICPacketFactory pf; pf.set_hs_protocol(&hs_protocol); - QUICAckFrameCreator *afc = new QUICAckFrameCreator(); - QUICConnectionId connection_id = {reinterpret_cast("\x01"), 1}; - MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); - MockQUICCongestionController *cc = new MockQUICCongestionController(); - QUICLossDetector detector(tx, cc); + QUICAckFrameCreator *afc = new QUICAckFrameCreator(); + QUICConnectionId connection_id = {reinterpret_cast("\x01"), 1}; + MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); + MockQUICConnectionInfoProvider *info = new MockQUICConnectionInfoProvider(); + MockQUICCongestionController *cc = new MockQUICCongestionController(info); + QUICLossDetector detector(tx, info, cc); ats_unique_buf payload = ats_unique_malloc(16); size_t payload_len = 16; QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); @@ -160,9 +161,10 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") TEST_CASE("QUICLossDetector_HugeGap", "[quic]") { - MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); - MockQUICCongestionController *cc = new MockQUICCongestionController(); - QUICLossDetector detector(tx, cc); + MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); + MockQUICConnectionInfoProvider *info = new MockQUICConnectionInfoProvider(); + MockQUICCongestionController *cc = new MockQUICCongestionController(info); + QUICLossDetector detector(tx, info, cc); // Check initial state CHECK(tx->retransmitted.size() == 0); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index b942b0337ef..28d61662e40 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -69,7 +69,8 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id, 1024, 1024)); + std::unique_ptr stream( + new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, 1024, 1024)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_1); @@ -95,7 +96,7 @@ TEST_CASE("QUICStream", "[quic]") IOBufferReader *reader = read_buffer->alloc_reader(); std::unique_ptr stream( - new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id, UINT64_MAX, UINT64_MAX)); + new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -121,7 +122,7 @@ TEST_CASE("QUICStream", "[quic]") IOBufferReader *reader = read_buffer->alloc_reader(); std::unique_ptr stream( - new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id, UINT64_MAX, UINT64_MAX)); + new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, 0, read_buffer); stream->recv(frame_8); @@ -150,7 +151,7 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id)); + std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id)); stream->init_flow_control_params(4096, 4096); stream->do_io_read(nullptr, 0, read_buffer); @@ -186,7 +187,7 @@ TEST_CASE("QUICStream", "[quic]") IOBufferReader *read_buffer_reader = read_buffer->alloc_reader(); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), stream_id)); + std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id)); stream->init_flow_control_params(4096, 4096); MockContinuation mock_cont(stream->mutex); stream->do_io_read(nullptr, 0, read_buffer); diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index e500db00469..4ee6f1003c1 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -34,7 +34,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), &app_map, NET_VCONNECTION_IN); + QUICStreamManager sm(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), &app_map, NET_VCONNECTION_IN); std::shared_ptr local_tp = std::make_shared(static_cast(0)); std::shared_ptr remote_tp = @@ -80,7 +80,7 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), &app_map, NET_VCONNECTION_IN); + QUICStreamManager sm(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), &app_map, NET_VCONNECTION_IN); std::shared_ptr local_tp = std::make_shared(static_cast(0)); std::shared_ptr remote_tp = @@ -100,7 +100,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), &app_map, NET_VCONNECTION_IN); + QUICStreamManager sm(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), &app_map, NET_VCONNECTION_IN); std::shared_ptr local_tp = std::make_shared(static_cast(0)); local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); @@ -133,7 +133,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICRTTProvider(), QUICConnectionId::ZERO(), &app_map, NET_VCONNECTION_IN); + QUICStreamManager sm(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), &app_map, NET_VCONNECTION_IN); std::shared_ptr local_tp = std::make_shared(static_cast(0)); local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); diff --git a/proxy/hq/HQClientSession.cc b/proxy/hq/HQClientSession.cc index f9468474d7b..3761e7f7996 100644 --- a/proxy/hq/HQClientSession.cc +++ b/proxy/hq/HQClientSession.cc @@ -85,7 +85,7 @@ HQClientSession::start() void HQClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader, bool backdoor) { - this->con_id = ProxyClientSession::next_connection_id(); + this->con_id = static_cast(reinterpret_cast(new_vc))->connection_id(); return; } diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 6766b2ccefb..455f64536c2 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -32,10 +32,9 @@ #include "HQDataFramer.h" #include "HttpSM.h" -#define HQTransDebug(fmt, ...) \ - Debug("hq_trans", "[%" PRIx64 "] [%" PRIx32 "] " fmt, \ - static_cast( \ - static_cast(reinterpret_cast(this->parent->get_netvc()))->connection_id()), \ +#define HQTransDebug(fmt, ...) \ + Debug("hq_trans", "[%s] [%" PRIx32 "] " fmt, \ + static_cast(reinterpret_cast(this->parent->get_netvc()))->cids().data(), \ this->get_transaction_id(), ##__VA_ARGS__) // static void From 93edda2ab4d5e99780d812550a6fed0e320a1a50 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 31 May 2018 14:41:46 +0900 Subject: [PATCH 0585/1313] Cleanup: remove NetVConnectionContext_t if it could be referred by QUICConnectionInfoProvider::direction() --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICHandshake.cc | 5 ++--- iocore/net/quic/QUICHandshake.h | 1 - iocore/net/quic/QUICStreamManager.cc | 7 +++---- iocore/net/quic/QUICStreamManager.h | 4 +--- iocore/net/quic/test/test_QUICStreamManager.cc | 8 ++++---- 6 files changed, 11 insertions(+), 16 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2c1f1a52dd9..75501238043 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -210,7 +210,7 @@ QUICNetVConnection::start() this->_remote_flow_controller = new QUICRemoteConnectionFlowController(UINT64_MAX); this->_local_flow_controller = new QUICLocalConnectionFlowController(this->_loss_detector, UINT64_MAX); this->_path_validator = new QUICPathValidator(); - this->_stream_manager = new QUICStreamManager(this->_loss_detector, this, this->_application_map, this->netvc_context); + this->_stream_manager = new QUICStreamManager(this, this->_loss_detector, this->_application_map); this->_frame_dispatcher->add_handler(this); this->_frame_dispatcher->add_handler(this->_stream_manager); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index e765e67c1c8..57f00f1691b 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -94,7 +94,6 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless _ssl(SSL_new(ssl_ctx)), _hs_protocol(new QUICTLS(this->_ssl, qc->direction(), stateless_retry)), _version_negotiator(new QUICVersionNegotiator()), - _netvc_context(qc->direction()), _reset_token(token), _stateless_retry(stateless_retry) { @@ -102,7 +101,7 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_hs_index, this); this->_hs_protocol->initialize_key_materials(this->_qc->original_connection_id()); - if (this->_netvc_context == NET_VCONNECTION_OUT) { + if (this->_qc->direction() == NET_VCONNECTION_OUT) { this->_initial = true; } @@ -156,7 +155,7 @@ QUICErrorUPtr QUICHandshake::negotiate_version(const QUICPacket *vn, QUICPacketFactory *packet_factory) { // Client side only - ink_assert(this->_netvc_context == NET_VCONNECTION_OUT); + ink_assert(this->_qc->direction() == NET_VCONNECTION_OUT); // If already negotiated, just ignore it if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED || diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 5274a668ab3..95820c24f2d 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -90,7 +90,6 @@ class QUICHandshake : public QUICApplication std::shared_ptr _remote_transport_parameters = nullptr; QUICVersionNegotiator *_version_negotiator = nullptr; - NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; QUICStatelessResetToken _reset_token; bool _initial = false; bool _stateless_retry = false; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index b5cd442349d..4bb1d7b982e 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -32,11 +32,10 @@ static constexpr char tag[] = "quic_stream_manager"; ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); ClassAllocator quicStreamAllocator("quicStreamAllocator"); -QUICStreamManager::QUICStreamManager(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICApplicationMap *app_map, - NetVConnectionContext_t context) - : _info(info), _rtt_provider(rtt_provider), _app_map(app_map), _netvc_context(context) +QUICStreamManager::QUICStreamManager(QUICConnectionInfoProvider *info, QUICRTTProvider *rtt_provider, QUICApplicationMap *app_map) + : _info(info), _rtt_provider(rtt_provider), _app_map(app_map) { - if (this->_netvc_context == NET_VCONNECTION_OUT) { + if (this->_info->direction() == NET_VCONNECTION_OUT) { // stream 0 is for handshake, smallest client bidi stream id is 4 this->_next_stream_id_bidi = static_cast(QUICStreamType::CLIENT_BIDI) + 4; this->_next_stream_id_uni = static_cast(QUICStreamType::CLIENT_UNI); diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 88ae800b1c4..8ca79d53f5f 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -38,8 +38,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator { public: QUICStreamManager(){}; - QUICStreamManager(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICApplicationMap *app_map, - NetVConnectionContext_t context); + QUICStreamManager(QUICConnectionInfoProvider *info, QUICRTTProvider *rtt_provider, QUICApplicationMap *app_map); void init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); @@ -80,7 +79,6 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICConnectionInfoProvider *_info = nullptr; QUICRTTProvider *_rtt_provider = nullptr; QUICApplicationMap *_app_map = nullptr; - NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; std::shared_ptr _local_tp = nullptr; std::shared_ptr _remote_tp = nullptr; QUICStreamId _local_maximum_stream_id_bidi = 0; diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 4ee6f1003c1..269cd3696e9 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -34,7 +34,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), &app_map, NET_VCONNECTION_IN); + QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); std::shared_ptr local_tp = std::make_shared(static_cast(0)); std::shared_ptr remote_tp = @@ -80,7 +80,7 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), &app_map, NET_VCONNECTION_IN); + QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); std::shared_ptr local_tp = std::make_shared(static_cast(0)); std::shared_ptr remote_tp = @@ -100,7 +100,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), &app_map, NET_VCONNECTION_IN); + QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); std::shared_ptr local_tp = std::make_shared(static_cast(0)); local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); @@ -133,7 +133,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), &app_map, NET_VCONNECTION_IN); + QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); std::shared_ptr local_tp = std::make_shared(static_cast(0)); local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); From 27a2f3069ada506d473d65753c9decedba47c103 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 31 May 2018 15:15:37 +0900 Subject: [PATCH 0586/1313] Update stream state machine --- iocore/net/quic/QUICDebugNames.cc | 38 ++-- iocore/net/quic/QUICDebugNames.h | 2 +- iocore/net/quic/QUICStream.cc | 7 +- iocore/net/quic/QUICStream.h | 4 +- iocore/net/quic/QUICStreamState.cc | 343 +++++++++++++++++++++-------- iocore/net/quic/QUICStreamState.h | 89 ++++++-- 6 files changed, 354 insertions(+), 129 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index c6b4ea749e6..d9a700cc4c0 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -195,21 +195,33 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) } const char * -QUICDebugNames::stream_state(QUICStreamState state) +QUICDebugNames::stream_state(const QUICStreamState &state) { switch (state.get()) { - case QUICStreamState::State::idle: - return "IDLE"; - case QUICStreamState::State::open: - return "OPEN"; - case QUICStreamState::State::half_closed_remote: - return "HC_REMOTE"; - case QUICStreamState::State::half_closed_local: - return "HC_LOCAL"; - case QUICStreamState::State::closed: - return "CLOSED"; - case QUICStreamState::State::illegal: - return "ILLEGAL"; + case QUICStreamState::State::_Init: + return "INIT"; + case QUICStreamState::State::Ready: + return "READY"; + case QUICStreamState::State::Send: + return "SEND"; + case QUICStreamState::State::DataSent: + return "DATA_SENT"; + case QUICStreamState::State::DataRecvd: + return "DATA_RECVD"; + case QUICStreamState::State::ResetSent: + return "RESET_SENT"; + case QUICStreamState::State::ResetRecvd: + return "RESET_RECVD"; + case QUICStreamState::State::Recv: + return "RECV"; + case QUICStreamState::State::SizeKnown: + return "SIZE_KNOWN"; + case QUICStreamState::State::DataRead: + return "DATA_READ"; + case QUICStreamState::State::ResetRead: + return "RESET_READ"; + case QUICStreamState::State::_Invalid: + return "INVALID"; default: return "UNKNOWN"; } diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index bb4e7d7f221..7e813b64e05 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -36,7 +36,7 @@ class QUICDebugNames static const char *error_class(QUICErrorClass cls); static const char *error_code(QUICTransErrorCode code); static const char *transport_parameter_id(QUICTransportParameterId id); - static const char *stream_state(QUICStreamState state); + static const char *stream_state(const QUICStreamState &state); static const char *quic_event(int event); static const char *key_phase(QUICKeyPhase phase); }; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 61df854081b..86cfb14d2a8 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -288,7 +288,7 @@ QUICStream::_write_to_read_vio(const std::shared_ptr &fra QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), this->_local_flow_controller.current_limit()); - this->_state.update_with_received_frame(*frame); + this->_state.update_with_receiving_frame(*frame); } /** @@ -305,6 +305,7 @@ QUICStream::recv(const std::shared_ptr frame) // Check stream state - Do this first before accept the frame if (!this->_state.is_allowed_to_receive(*frame)) { + QUICStreamDebug("Canceled receiving %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); return QUICErrorUPtr(new QUICStreamError(this, QUICTransErrorCode::STREAM_STATE_ERROR)); } @@ -359,7 +360,7 @@ QUICStream::recv(const std::shared_ptr frame) QUICErrorUPtr QUICStream::recv(const std::shared_ptr frame) { - this->_state.update_with_received_frame(*frame); + this->_state.update_with_receiving_frame(*frame); this->_reset_reason = QUICStreamErrorUPtr(new QUICStreamError(this, QUIC_APP_ERROR_CODE_STOPPING)); // We received and processed STOP_SENDING frame, so return NO_ERROR here return QUICErrorUPtr(new QUICNoError()); @@ -428,7 +429,7 @@ QUICStream::generate_frame(uint64_t connection_credit, uint16_t maximum_frame_si reader->consume(len); this->_write_vio.ndone += len; this->_signal_write_event(); - this->_state.update_with_sent_frame(*frame); + this->_state.update_with_sending_frame(*frame); } else if (ret != 0) { QUICStreamDebug("Flow Controller blocked sending a STREAM frame"); frame = this->_remote_flow_controller.generate_frame(); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index af3afcc63f9..96f8486364e 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -101,7 +101,9 @@ class QUICStream : public VConnection, public QUICFrameGenerator void _write_to_read_vio(const std::shared_ptr &); - QUICStreamState _state; + // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState + QUICBidirectionalStreamState _state; + QUICStreamErrorUPtr _reset_reason = nullptr; QUICConnectionInfoProvider *_info = nullptr; QUICStreamId _id = 0; diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index 2f78c3c7652..2c7337c0fb7 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -24,172 +24,329 @@ #include "QUICStreamState.h" #include "ts/ink_assert.h" -const QUICStreamState::State -QUICStreamState::get() const +void +QUICStreamState::_set_state(State s) { - return this->_state; + ink_assert(s != State::_Init); + ink_assert(s != State::_Invalid); + this->_state = s; } +// ---------QUICReceiveStreamState ----------- + bool -QUICStreamState::is_allowed_to_send(const QUICFrame &frame) const +QUICReceiveStreamState::is_allowed_to_send(const QUICFrame &frame) const { - switch (this->_state) { - case State::idle: + QUICFrameType type = frame.type(); + + // Return true or break out the switch to return false + switch (this->get()) { + case State::_Init: + if (type == QUICFrameType::STREAM || type == QUICFrameType::RST_STREAM || type == QUICFrameType::MAX_STREAM_DATA || + type == QUICFrameType::STREAM_BLOCKED) { + return true; + } break; - case State::open: + case State::_Invalid: + // Everthing is invalid on this state break; - case State::half_closed_local: - if (frame.type() == QUICFrameType::STREAM) { - return false; + case State::Recv: + if (type == QUICFrameType::NEW_CONNECTION_ID || type == QUICFrameType::PATH_CHALLENGE) { + return true; + } + if (type == QUICFrameType::ACK) { + return true; + } + if (type == QUICFrameType::MAX_STREAM_DATA || type == QUICFrameType::STOP_SENDING) { + return true; } break; - case State::half_closed_remote: + case State::SizeKnown: + if (type == QUICFrameType::ACK) { + return true; + } + if (type == QUICFrameType::STOP_SENDING) { + return true; + } break; - case State::closed: - // Once a stream reaches this state, no frames can be sent that mention the stream - if (frame.type() == QUICFrameType::STREAM) { - return false; - } else if (frame.type() == QUICFrameType::RST_STREAM) { - return false; - } else if (frame.type() == QUICFrameType::MAX_STREAM_DATA) { - return false; + case State::DataRecvd: + if (type != QUICFrameType::STREAM && type != QUICFrameType::RST_STREAM && type != QUICFrameType::STREAM_BLOCKED) { + return true; + } + break; + case State::DataRead: + if (type == QUICFrameType::STOP_SENDING) { + return true; } break; - case State::illegal: - return false; + case State::ResetRecvd: + // It should not send any frame after receiving RST_STREAM + break; + case State::ResetRead: + // It should not send any frame after receiving RST_STREAM + break; + default: + ink_assert(!"Unknown state"); + break; } - return true; + + return false; } bool -QUICStreamState::is_allowed_to_receive(const QUICFrame &frame) const +QUICReceiveStreamState::is_allowed_to_receive(const QUICFrame &frame) const { - switch (this->_state) { - case State::idle: - break; - case State::open: - break; - case State::half_closed_local: + QUICFrameType type = frame.type(); + + // Return true or break out the switch to return false + switch (this->get()) { + case State::_Init: + if (type == QUICFrameType::STREAM || type == QUICFrameType::RST_STREAM || type == QUICFrameType::MAX_STREAM_DATA || + type == QUICFrameType::STREAM_BLOCKED) { + return true; + } break; - case State::half_closed_remote: + case State::_Invalid: + // Everthing is invalid on this state break; - case State::closed: - // Reordering might cause frames to be received after closing + case State::Recv: + return true; + case State::SizeKnown: + return true; + case State::DataRecvd: + return true; + case State::DataRead: + return true; + case State::ResetRecvd: + return true; + case State::ResetRead: + return true; + default: + ink_assert(!"Unknown state"); break; - case State::illegal: - return false; } - return true; + + return false; +} + +void +QUICReceiveStreamState::update_with_sending_frame(const QUICFrame &frame) +{ } void -QUICStreamState::update_with_received_frame(const QUICFrame &frame) +QUICReceiveStreamState::update_with_receiving_frame(const QUICFrame &frame) { - switch (this->_state) { - case State::idle: + switch (this->get()) { + case State::_Init: if (frame.type() == QUICFrameType::STREAM) { + this->_set_state(State::Recv); if (static_cast(frame).has_fin_flag()) { - this->_set_state(State::half_closed_remote); - } else { - this->_set_state(State::open); + this->_set_state(State::SizeKnown); } } else if (frame.type() == QUICFrameType::RST_STREAM) { - this->_set_state(State::half_closed_remote); + this->_set_state(State::Recv); + this->_set_state(State::ResetRecvd); } else if (frame.type() == QUICFrameType::MAX_STREAM_DATA || frame.type() == QUICFrameType::STREAM_BLOCKED) { - this->_set_state(State::open); + this->_set_state(State::Recv); } else { - this->_set_state(State::illegal); + this->_set_state(State::_Invalid); } break; - case State::open: + case State::Recv: if (frame.type() == QUICFrameType::STREAM) { if (static_cast(frame).has_fin_flag()) { - this->_set_state(State::half_closed_remote); + this->_set_state(State::SizeKnown); } } else if (frame.type() == QUICFrameType::RST_STREAM) { - this->_set_state(State::half_closed_remote); - } else { - this->_set_state(State::illegal); + this->_set_state(State::ResetRecvd); } break; - case State::half_closed_local: - if (frame.type() == QUICFrameType::STREAM) { - if (static_cast(frame).has_fin_flag()) { - this->_set_state(State::closed); - } - } else if (frame.type() == QUICFrameType::RST_STREAM) { - this->_set_state(State::closed); - } else { - this->_set_state(State::illegal); + case State::SizeKnown: + if (frame.type() == QUICFrameType::RST_STREAM) { + this->_set_state(State::ResetRecvd); } break; - case State::half_closed_remote: + case State::DataRecvd: + if (frame.type() == QUICFrameType::RST_STREAM) { + this->_set_state(State::ResetRecvd); + } break; - case State::closed: + case State::DataRead: break; - case State::illegal: + case State::ResetRecvd: + break; + case State::ResetRead: + break; + case State::_Invalid: // Once we get illegal state, no way to recover it break; default: + ink_assert(!"Unknown state"); break; } } void -QUICStreamState::update_with_sent_frame(const QUICFrame &frame) +QUICReceiveStreamState::update(const QUICStreamState &opposite_side) { - switch (this->_state) { - case State::idle: - if (frame.type() == QUICFrameType::STREAM) { - if (static_cast(frame).has_fin_flag()) { - this->_set_state(State::half_closed_local); - } else { - this->_set_state(State::open); - } - } else if (frame.type() == QUICFrameType::RST_STREAM) { - this->_set_state(State::half_closed_local); - } else { - this->_set_state(State::illegal); + switch (this->get()) { + case State::_Init: + ink_assert(opposite_side.get() != State::_Init); + this->_set_state(State::Recv); + break; + default: + ink_assert(!"This shouldn't be happen"); + break; + } +} + +// ---------- QUICSendStreamState ------------- + +bool +QUICSendStreamState::is_allowed_to_send(const QUICFrame &frame) const +{ + QUICFrameType type = frame.type(); + + switch (this->get()) { + case State::_Init: + break; + case State::Ready: + if (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_BLOCKED || type == QUICFrameType::RST_STREAM) { + return true; } break; - case State::open: + case State::Send: + if (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_BLOCKED || type == QUICFrameType::RST_STREAM) { + return true; + } + break; + case State::DataSent: + if (type != QUICFrameType::STREAM || type != QUICFrameType::STREAM_BLOCKED || type != QUICFrameType::RST_STREAM) { + return true; + } + break; + case State::DataRecvd: + if (type != QUICFrameType::STREAM || type != QUICFrameType::STREAM_BLOCKED || type != QUICFrameType::RST_STREAM) { + return true; + } + break; + case State::ResetSent: + if (type != QUICFrameType::STREAM || type != QUICFrameType::STREAM_BLOCKED || type != QUICFrameType::RST_STREAM) { + return true; + } + break; + case State::ResetRecvd: + break; + case State::_Invalid: + break; + default: + ink_assert("This shouuldn't be happen"); + break; + } + + return false; +} + +bool +QUICSendStreamState::is_allowed_to_receive(const QUICFrame &frame) const +{ + return false; +} + +void +QUICSendStreamState::update_with_sending_frame(const QUICFrame &frame) +{ + switch (this->get()) { + case State::_Init: + break; + case State::Ready: if (frame.type() == QUICFrameType::STREAM) { + this->_set_state(State::Send); if (static_cast(frame).has_fin_flag()) { - this->_set_state(State::half_closed_local); + this->_set_state(State::DataSent); } + } else if (frame.type() == QUICFrameType::STREAM_BLOCKED) { + this->_set_state(State::Send); } else if (frame.type() == QUICFrameType::RST_STREAM) { - this->_set_state(State::half_closed_local); - } else { - this->_set_state(State::illegal); + this->_set_state(State::ResetSent); } break; - case State::half_closed_local: - break; - case State::half_closed_remote: + case State::Send: if (frame.type() == QUICFrameType::STREAM) { if (static_cast(frame).has_fin_flag()) { - this->_set_state(State::closed); + this->_set_state(State::DataSent); } } else if (frame.type() == QUICFrameType::RST_STREAM) { - this->_set_state(State::closed); - } else { - this->_set_state(State::illegal); + this->_set_state(State::ResetSent); + } + break; + case State::DataSent: + if (frame.type() == QUICFrameType::RST_STREAM) { + this->_set_state(State::ResetSent); } break; - case State::closed: + case State::DataRecvd: break; - case State::illegal: - // Once we get illegal state, no way to recover it + case State::ResetSent: + break; + case State::ResetRecvd: + break; + case State::_Invalid: break; default: + ink_assert(!"Unknown state"); break; } } void -QUICStreamState::_set_state(State s) +QUICSendStreamState::update_with_receiving_frame(const QUICFrame &frame) { - ink_assert(s != State::idle); - ink_assert(s != State::illegal); - this->_state = s; +} + +void +QUICSendStreamState::update(const QUICStreamState &opposite_side) +{ + switch (this->get()) { + case State::_Init: + ink_assert(opposite_side.get() != State::_Init); + this->_set_state(State::Ready); + break; + default: + ink_assert(!"This shouldn't be happen"); + break; + } +} + +// ---------QUICBidirectionalStreamState ----------- + +void +QUICBidirectionalStreamState::update_with_sending_frame(const QUICFrame &frame) +{ + this->_send_stream_state.update_with_sending_frame(frame); + if (this->_recv_stream_state.get() == State::_Init) { + this->_recv_stream_state.update(this->_send_stream_state); + } +} + +void +QUICBidirectionalStreamState::update_with_receiving_frame(const QUICFrame &frame) +{ + this->_recv_stream_state.update_with_receiving_frame(frame); + if (this->_send_stream_state.get() == State::_Init) { + this->_send_stream_state.update(this->_recv_stream_state); + } +} + +bool +QUICBidirectionalStreamState::is_allowed_to_send(const QUICFrame &frame) const +{ + return this->_send_stream_state.is_allowed_to_send(frame) || this->_recv_stream_state.is_allowed_to_send(frame); +} + +bool +QUICBidirectionalStreamState::is_allowed_to_receive(const QUICFrame &frame) const +{ + return this->_send_stream_state.is_allowed_to_receive(frame) || this->_recv_stream_state.is_allowed_to_receive(frame); } diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h index 047930847b0..6cdc014c476 100644 --- a/iocore/net/quic/QUICStreamState.h +++ b/iocore/net/quic/QUICStreamState.h @@ -28,27 +28,80 @@ class QUICStreamState { public: - // 10.1. Life of a Stream enum class State { - idle, - open, - half_closed_remote, - half_closed_local, - closed, - illegal // not on the specification, just for internal use + _Init, + Ready, + Send, + DataSent, + DataRecvd, + ResetSent, + ResetRecvd, + Recv, + SizeKnown, + /* DataRecvd, */ DataRead, + /* ResetRecvd, */ ResetRead, + _Invalid }; - const State get() const; - bool is_allowed_to_send(const QUICFrame &frame) const; - bool is_allowed_to_receive(const QUICFrame &frame) const; - /* - * Updates its internal state - * Internal state will be "illegal" state if inappropriate frame was passed - */ - void update_with_received_frame(const QUICFrame &frame); - void update_with_sent_frame(const QUICFrame &frame); + virtual ~QUICStreamState() {} -private: + State + get() const + { + return this->_state; + } + + virtual void update_with_sending_frame(const QUICFrame &frame) = 0; + virtual void update_with_receiving_frame(const QUICFrame &frame) = 0; + + virtual bool is_allowed_to_send(const QUICFrame &frame) const = 0; + virtual bool is_allowed_to_receive(const QUICFrame &frame) const = 0; + +protected: void _set_state(State s); - State _state = State::idle; + +private: + State _state = State::_Init; +}; + +class QUICUnidirectionalStreamState : public QUICStreamState +{ +public: + virtual void update(const QUICStreamState &opposite_side) = 0; +}; + +class QUICSendStreamState : public QUICUnidirectionalStreamState +{ +public: + void update_with_sending_frame(const QUICFrame &frame) override; + void update_with_receiving_frame(const QUICFrame &frame) override; + void update(const QUICStreamState &opposite_side) override; + + bool is_allowed_to_send(const QUICFrame &frame) const override; + bool is_allowed_to_receive(const QUICFrame &frame) const override; +}; + +class QUICReceiveStreamState : public QUICUnidirectionalStreamState +{ +public: + void update_with_sending_frame(const QUICFrame &frame) override; + void update_with_receiving_frame(const QUICFrame &frame) override; + void update(const QUICStreamState &opposite_side) override; + + bool is_allowed_to_send(const QUICFrame &frame) const override; + bool is_allowed_to_receive(const QUICFrame &frame) const override; +}; + +class QUICBidirectionalStreamState : public QUICStreamState +{ +public: + void update_with_sending_frame(const QUICFrame &frame) override; + void update_with_receiving_frame(const QUICFrame &frame) override; + + bool is_allowed_to_send(const QUICFrame &frame) const override; + bool is_allowed_to_receive(const QUICFrame &frame) const override; + +private: + QUICSendStreamState _send_stream_state; + QUICReceiveStreamState _recv_stream_state; }; From f6d2922fe074d14fff7eb57e249367974e8cd782 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 31 May 2018 16:09:04 +0900 Subject: [PATCH 0587/1313] Print bidirectional stream state appropriately --- iocore/net/quic/QUICDebugNames.cc | 8 ++++++ iocore/net/quic/QUICStreamState.cc | 41 ++++++++++++++++++++++++++++++ iocore/net/quic/QUICStreamState.h | 20 ++++++++++++--- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index d9a700cc4c0..df250d6dad8 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -220,6 +220,14 @@ QUICDebugNames::stream_state(const QUICStreamState &state) return "DATA_READ"; case QUICStreamState::State::ResetRead: return "RESET_READ"; + case QUICStreamState::State::Open: + return "OPEN"; + case QUICStreamState::State::HC_L: + return "HC_L"; + case QUICStreamState::State::HC_R: + return "HC_R"; + case QUICStreamState::State::Closed: + return "CLOSED"; case QUICStreamState::State::_Invalid: return "INVALID"; default: diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index 2c7337c0fb7..9d8e864e3f7 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -321,6 +321,47 @@ QUICSendStreamState::update(const QUICStreamState &opposite_side) // ---------QUICBidirectionalStreamState ----------- +QUICStreamState::State +QUICBidirectionalStreamState::get() const +{ + QUICStreamState::State s_state = this->_send_stream_state.get(); + QUICStreamState::State r_state = this->_recv_stream_state.get(); + + if (s_state == State::Ready || s_state == State::Send || s_state == State::DataSent) { + if (r_state == State::Recv || r_state == State::SizeKnown) { + return State::Open; + } else if (r_state == State::DataRecvd || r_state == State::DataRead) { + return State::HC_R; + } else if (r_state == State::ResetRecvd || r_state == State::ResetRead) { + return State::HC_R; + } else { + return State::_Invalid; + } + } else if (s_state == State::DataRecvd) { + if (r_state == State::Recv || r_state == State::SizeKnown) { + return State::HC_L; + } else if (r_state == State::DataRecvd || r_state == State::DataRead) { + return State::Closed; + } else if (r_state == State::ResetRecvd || r_state == State::ResetRead) { + return State::Closed; + } else { + return State::_Invalid; + } + } else if (s_state == State::ResetSent || s_state == State::ResetRecvd) { + if (r_state == State::Recv || r_state == State::SizeKnown) { + return State::HC_L; + } else if (r_state == State::DataRecvd || r_state == State::DataRead) { + return State::Closed; + } else if (r_state == State::ResetRecvd || r_state == State::ResetRead) { + return State::Closed; + } else { + return State::_Invalid; + } + } else { + return State::_Invalid; + } +} + void QUICBidirectionalStreamState::update_with_sending_frame(const QUICFrame &frame) { diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h index 6cdc014c476..0cc11a594db 100644 --- a/iocore/net/quic/QUICStreamState.h +++ b/iocore/net/quic/QUICStreamState.h @@ -29,23 +29,33 @@ class QUICStreamState { public: enum class State { + // Common _Init, + _Invalid, + // SendStreamState Ready, Send, DataSent, DataRecvd, ResetSent, ResetRecvd, + // ReceiveStreamState Recv, SizeKnown, - /* DataRecvd, */ DataRead, - /* ResetRecvd, */ ResetRead, - _Invalid + /* DataRecvd, */ + DataRead, + /* ResetRecvd, */ + ResetRead, + // Bidirectional + Open, + HC_R, + HC_L, + Closed }; virtual ~QUICStreamState() {} - State + virtual State get() const { return this->_state; @@ -95,6 +105,8 @@ class QUICReceiveStreamState : public QUICUnidirectionalStreamState class QUICBidirectionalStreamState : public QUICStreamState { public: + State get() const override; + void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; From 38f6a321bc70e7ba98874150f98d168e3c29b659 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 31 May 2018 16:37:59 +0900 Subject: [PATCH 0588/1313] add some const --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICIncomingFrameBuffer.h | 4 ++-- iocore/net/quic/QUICStream.cc | 2 +- iocore/net/quic/QUICStream.h | 2 +- iocore/net/quic/QUICStreamManager.cc | 7 +++++++ iocore/net/quic/QUICStreamManager.h | 1 + iocore/net/quic/QUICTypes.h | 6 +++--- 7 files changed, 16 insertions(+), 8 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 75501238043..6642dbdae7a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1447,7 +1447,7 @@ QUICNetVConnection::_handle_error(QUICErrorUPtr error) if (dynamic_cast(error.get()) != nullptr) { // Stream Error QUICStreamError *serror = static_cast(error.release()); - serror->stream->reset(QUICStreamErrorUPtr(serror)); + this->_stream_manager->reset_stream(serror->stream->id(), QUICStreamErrorUPtr(serror)); } else { // Connection Error QUICConnectionError *cerror = static_cast(error.release()); diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index e945303bf24..0f020132371 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -32,7 +32,7 @@ class QUICIncomingFrameBuffer { public: - QUICIncomingFrameBuffer(QUICStream *stream) : _stream(stream) {} + QUICIncomingFrameBuffer(const QUICStream *stream) : _stream(stream) {} ~QUICIncomingFrameBuffer(); std::shared_ptr pop(); @@ -56,5 +56,5 @@ class QUICIncomingFrameBuffer std::queue> _recv_buffer; std::map> _out_of_order_queue; - QUICStream *_stream = nullptr; + const QUICStream *_stream = nullptr; }; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 86cfb14d2a8..869cbcea69f 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -87,7 +87,7 @@ QUICStream::id() const } QUICOffset -QUICStream::final_offset() +QUICStream::final_offset() const { // TODO Return final offset return 0; diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 96f8486364e..96796c11f4c 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -64,7 +64,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator void init_flow_control_params(uint64_t recv_max_stream_data, uint64_t send_max_stream_data); QUICStreamId id() const; - QUICOffset final_offset(); + QUICOffset final_offset() const; void reset_send_offset(); void reset_recv_offset(); QUICStreamFrameUPtr generete_frame(uint16_t flow_control_credit, uint16_t maximum_frame_size); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 4bb1d7b982e..5b2299ebd40 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -134,6 +134,13 @@ QUICStreamManager::create_bidi_stream(QUICStreamId &new_stream_id) return error; } +void +QUICStreamManager::reset_stream(QUICStreamId stream_id, QUICStreamErrorUPtr error) +{ + auto stream = this->_find_stream(stream_id); + stream->reset(std::move(error)); +} + QUICErrorUPtr QUICStreamManager::handle_frame(std::shared_ptr frame) { diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 8ca79d53f5f..51d38dc4622 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -51,6 +51,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICErrorUPtr create_stream(QUICStreamId stream_id); QUICErrorUPtr create_uni_stream(QUICStreamId &new_stream_id); QUICErrorUPtr create_bidi_stream(QUICStreamId &new_stream_id); + void reset_stream(QUICStreamId stream_id, QUICStreamErrorUPtr error); void set_default_application(QUICApplication *app); void reset_send_offset(); diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 7b267774578..197e689b957 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -200,12 +200,12 @@ class QUICStreamError : public QUICError { public: QUICStreamError() : QUICError() {} - QUICStreamError(QUICStream *s, const QUICTransErrorCode error_code, const char *error_msg = nullptr) + QUICStreamError(const QUICStream *s, const QUICTransErrorCode error_code, const char *error_msg = nullptr) : QUICError(error_code, error_msg), stream(s){}; - QUICStreamError(QUICStream *s, const QUICAppErrorCode error_code, const char *error_msg = nullptr) + QUICStreamError(const QUICStream *s, const QUICAppErrorCode error_code, const char *error_msg = nullptr) : QUICError(error_code, error_msg), stream(s){}; - QUICStream *stream; + const QUICStream *stream; }; using QUICErrorUPtr = std::unique_ptr; From 97fa0b3ac1c9052333cc6f21331f8aae69920af0 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 1 Jun 2018 08:31:28 +0900 Subject: [PATCH 0589/1313] Print full connection id --- iocore/net/QUICNetVConnection.cc | 16 ++++++++++++---- iocore/net/QUICPacketHandler.cc | 7 ++++++- iocore/net/quic/QUICTypes.cc | 26 ++++++++++++++++++++++++++ iocore/net/quic/QUICTypes.h | 4 +++- 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6642dbdae7a..62a1ff70876 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -88,8 +88,12 @@ QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_ci this->_update_cids(); - // TODO: print full cids - QUICConDebug("dcid=%08" PRIx32 " scid=%08" PRIx32, this->_peer_quic_connection_id.h32(), this->_quic_connection_id.h32()); + 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); } bool @@ -1782,8 +1786,12 @@ QUICNetVConnection::_update_cids() void QUICNetVConnection::_update_peer_cid(const QUICConnectionId &new_cid) { - // TODO: print full cids - QUICConDebug("dcid: %08" PRIx32 " -> %08" PRIx32, this->_peer_quic_connection_id.h32(), new_cid.h32()); + 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); this->_peer_quic_connection_id = new_cid; this->_update_cids(); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 6717880e62a..6d68cd9acdc 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -230,7 +230,12 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // Create a new NetVConnection QUICConnectionId original_cid = this->_read_destination_connection_id(block); QUICConnectionId peer_cid = this->_read_source_connection_id(block); - vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); + + 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); + + vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); vc->init(peer_cid, original_cid, udp_packet->getConnection(), this, this->_ctable); vc->id = net_next_connection_number(); vc->con.move(con); diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index be89426fcd4..626cce35daa 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -25,6 +25,26 @@ #include "QUICTypes.h" #include "QUICIntUtil.h" +// TODO: move to somewhere in lib/ts/ +static int +to_hex_str(char *dst, size_t dst_len, const uint8_t *src, size_t src_len) +{ + if (dst_len < src_len * 2 + 1) { + return -1; + } + + static char hex_digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + for (size_t i = 0; i < src_len; ++i) { + *dst = hex_digits[src[i] >> 4]; + *(dst + 1) = hex_digits[src[i] & 0xf]; + dst += 2; + } + *dst = '\0'; + + return 0; +} + bool #include QUICTypeUtil::has_long_header(const uint8_t *buf) @@ -291,3 +311,9 @@ QUICConnectionId::h32() const { return static_cast(QUICIntUtil::read_nbytes_as_uint(this->_id, 4)); } + +int +QUICConnectionId::hex(char *buf, size_t len) const +{ + return to_hex_str(buf, len, this->_id, this->_len); +} diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 197e689b957..2547a7c986a 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -215,7 +215,8 @@ using QUICStreamErrorUPtr = std::unique_ptr; class QUICConnectionId { public: - static const int MAX_LENGTH = 18; + static const int MAX_LENGTH = 18; + static const size_t MAX_HEX_STR_LENGTH = MAX_LENGTH * 2 + 1; static QUICConnectionId ZERO(); QUICConnectionId(); QUICConnectionId(const uint8_t *buf, uint8_t len); @@ -246,6 +247,7 @@ class QUICConnectionId */ uint64_t l64() const; uint32_t h32() const; + int hex(char *buf, size_t len) const; uint8_t length() const; bool is_zero() const; From cc2060720722482d44e812475f65e56d85f4d21e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 1 Jun 2018 12:40:08 +0900 Subject: [PATCH 0590/1313] Format debug log on changing connection id --- iocore/net/P_QUICNetVConnection.h | 2 ++ iocore/net/QUICNetVConnection.cc | 35 +++++++++++++++++++++++++++---- iocore/net/quic/QUICTypes.cc | 12 ----------- iocore/net/quic/QUICTypes.h | 1 - 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 3b255f28f03..e3ba5822b00 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -341,6 +341,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _update_cids(); void _update_peer_cid(const QUICConnectionId &new_cid); + void _update_local_cid(const QUICConnectionId &new_cid); + void _rerandomize_original_cid(); QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet(); QUICStatelessResetToken _reset_token; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 62a1ff70876..cee2e527259 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -917,9 +917,7 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) this->_stream_manager->reset_recv_offset(); // Generate new Connection ID - QUICConnectionId tmp = this->_original_quic_connection_id; - this->_original_quic_connection_id.randomize(); - QUICConDebug("Connection ID %" PRIx64 " has been changed to %" PRIx64, tmp.l64(), this->_original_quic_connection_id.l64()); + this->_rerandomize_original_cid(); this->_hs_protocol->initialize_key_materials(this->_original_quic_connection_id); @@ -976,7 +974,7 @@ QUICNetVConnection::_state_common_receive_packet() // Migrate connection // TODO Address Validation // TODO Adjust expected packet number with a gap computed based on info.seq_num - this->_quic_connection_id = p->destination_cid(); + this->_update_local_cid(p->destination_cid()); Connection con; con.setRemote(&p->from().sa); this->con.move(con); @@ -1796,3 +1794,32 @@ QUICNetVConnection::_update_peer_cid(const QUICConnectionId &new_cid) this->_peer_quic_connection_id = new_cid; this->_update_cids(); } + +void +QUICNetVConnection::_update_local_cid(const QUICConnectionId &new_cid) +{ + 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); + + this->_quic_connection_id = new_cid; + this->_update_cids(); +} + +void +QUICNetVConnection::_rerandomize_original_cid() +{ + char old_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH]; + char new_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH]; + + QUICConnectionId tmp = this->_original_quic_connection_id; + tmp.hex(old_cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH); + + this->_original_quic_connection_id.randomize(); + 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); +} diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 626cce35daa..ecd4df67fb3 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -294,18 +294,6 @@ QUICConnectionId::_hashcode() const (this->_id[5] << 16) + (this->_id[6] << 8) + this->_id[7]; } -uint64_t -QUICConnectionId::l64() const -{ - uint64_t v = 0; - int ndigit = std::min(8U, static_cast(this->_len)); - int offset = static_cast(this->_len) - ndigit; - for (int i = 0; i < ndigit; i++) { - v += static_cast(this->_id[offset + i]) << (8 * (ndigit - i - 1)); - } - return v; -} - uint32_t QUICConnectionId::h32() const { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 2547a7c986a..bdf1a3aa5c1 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -245,7 +245,6 @@ class QUICConnectionId /* * This is just for debugging. */ - uint64_t l64() const; uint32_t h32() const; int hex(char *buf, size_t len) const; From 047a258b8c93e940110b1aab6cddc2bde45417a3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Jun 2018 14:09:25 +0900 Subject: [PATCH 0591/1313] Added TransferProgressProvider --- iocore/net/quic/QUICIncomingFrameBuffer.cc | 27 ++++++++++++++++++++++ iocore/net/quic/QUICIncomingFrameBuffer.h | 9 +++++++- iocore/net/quic/QUICStream.cc | 3 ++- iocore/net/quic/QUICStream.h | 9 ++++---- iocore/net/quic/QUICStreamState.cc | 14 ++++++++++- iocore/net/quic/QUICStreamState.h | 23 ++++++++++++++++++ 6 files changed, 78 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index 04c5fe0b8f1..66eca10ff53 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -134,3 +134,30 @@ QUICIncomingFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, return QUICErrorUPtr(new QUICNoError()); } + +/* + *QUICTransferProgressProvider + */ +bool +QUICIncomingFrameBuffer::is_transfer_goal_set() const +{ + return this->_fin_offset != UINT64_MAX; +} + +bool +QUICIncomingFrameBuffer::is_transfer_complete() const +{ + return this->is_transfer_goal_set() && this->transfer_progress() == this->transfer_goal(); +} + +uint64_t +QUICIncomingFrameBuffer::transfer_progress() const +{ + return this->_max_offset; +} + +uint64_t +QUICIncomingFrameBuffer::transfer_goal() const +{ + return this->_fin_offset; +} diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index 0f020132371..66143017afb 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -28,8 +28,9 @@ #include "QUICTypes.h" #include "QUICFrame.h" +#include "QUICTransferProgressProvider.h" -class QUICIncomingFrameBuffer +class QUICIncomingFrameBuffer : public QUICTransferProgressProvider { public: QUICIncomingFrameBuffer(const QUICStream *stream) : _stream(stream) {} @@ -46,6 +47,12 @@ class QUICIncomingFrameBuffer bool empty(); + // QUICTransferProgressProvider + bool is_transfer_goal_set() const override; + bool is_transfer_complete() const override; + uint64_t transfer_progress() const override; + uint64_t transfer_goal() const override; + private: QUICOffset _recv_offset = 0; QUICOffset _max_offset = 0; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 869cbcea69f..ed3a0112a16 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -47,7 +47,8 @@ QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider _id(sid), _remote_flow_controller(send_max_stream_data, _id), _local_flow_controller(rtt_provider, recv_max_stream_data, _id), - _received_stream_frame_buffer(this) + _received_stream_frame_buffer(this), + _state(nullptr, nullptr, &_received_stream_frame_buffer, nullptr) { SET_HANDLER(&QUICStream::state_stream_open); mutex = new_ProxyMutex(); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 96796c11f4c..8cfd394e1df 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -51,7 +51,8 @@ class QUICStream : public VConnection, public QUICFrameGenerator : VConnection(nullptr), _remote_flow_controller(0, 0), _local_flow_controller(nullptr, 0, 0), - _received_stream_frame_buffer(this) + _received_stream_frame_buffer(this), + _state(nullptr, nullptr, nullptr, nullptr) { } QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICStreamId sid, uint64_t recv_max_stream_data = 0, @@ -101,9 +102,6 @@ class QUICStream : public VConnection, public QUICFrameGenerator void _write_to_read_vio(const std::shared_ptr &); - // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState - QUICBidirectionalStreamState _state; - QUICStreamErrorUPtr _reset_reason = nullptr; QUICConnectionInfoProvider *_info = nullptr; QUICStreamId _id = 0; @@ -122,4 +120,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator // Fragments of received STREAM frame (offset is unmatched) // TODO: Consider to replace with ts/RbTree.h or other data structure QUICIncomingFrameBuffer _received_stream_frame_buffer; + + // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState + QUICBidirectionalStreamState _state; }; diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index 9d8e864e3f7..dda51f09f7a 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -143,6 +143,9 @@ QUICReceiveStreamState::update_with_receiving_frame(const QUICFrame &frame) this->_set_state(State::Recv); if (static_cast(frame).has_fin_flag()) { this->_set_state(State::SizeKnown); + if (this->_in_progress->is_transfer_complete()) { + this->_set_state(State::DataRecvd); + } } } else if (frame.type() == QUICFrameType::RST_STREAM) { this->_set_state(State::Recv); @@ -157,13 +160,20 @@ QUICReceiveStreamState::update_with_receiving_frame(const QUICFrame &frame) if (frame.type() == QUICFrameType::STREAM) { if (static_cast(frame).has_fin_flag()) { this->_set_state(State::SizeKnown); + if (this->_in_progress->is_transfer_complete()) { + this->_set_state(State::DataRecvd); + } } } else if (frame.type() == QUICFrameType::RST_STREAM) { this->_set_state(State::ResetRecvd); } break; case State::SizeKnown: - if (frame.type() == QUICFrameType::RST_STREAM) { + if (frame.type() == QUICFrameType::STREAM) { + if (this->_in_progress->is_transfer_complete()) { + this->_set_state(State::DataRecvd); + } + } else if (frame.type() == QUICFrameType::RST_STREAM) { this->_set_state(State::ResetRecvd); } break; @@ -357,6 +367,8 @@ QUICBidirectionalStreamState::get() const } else { return State::_Invalid; } + } else if (s_state == State::_Init && r_state == State::_Init) { + return State::_Init; } else { return State::_Invalid; } diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h index 0cc11a594db..f0508153a5e 100644 --- a/iocore/net/quic/QUICStreamState.h +++ b/iocore/net/quic/QUICStreamState.h @@ -24,6 +24,7 @@ #pragma once #include "QUICFrame.h" +#include "QUICTransferProgressProvider.h" class QUICStreamState { @@ -77,12 +78,24 @@ class QUICStreamState class QUICUnidirectionalStreamState : public QUICStreamState { public: + QUICUnidirectionalStreamState(QUICTransferProgressProvider *in, QUICTransferProgressProvider *out) + : _in_progress(in), _out_progress(out) + { + } virtual void update(const QUICStreamState &opposite_side) = 0; + +protected: + QUICTransferProgressProvider *_in_progress = nullptr; + QUICTransferProgressProvider *_out_progress = nullptr; }; class QUICSendStreamState : public QUICUnidirectionalStreamState { public: + QUICSendStreamState(QUICTransferProgressProvider *in, QUICTransferProgressProvider *out) : QUICUnidirectionalStreamState(in, out) + { + } + void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; void update(const QUICStreamState &opposite_side) override; @@ -94,6 +107,11 @@ class QUICSendStreamState : public QUICUnidirectionalStreamState class QUICReceiveStreamState : public QUICUnidirectionalStreamState { public: + QUICReceiveStreamState(QUICTransferProgressProvider *in, QUICTransferProgressProvider *out) + : QUICUnidirectionalStreamState(in, out) + { + } + void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; void update(const QUICStreamState &opposite_side) override; @@ -105,6 +123,11 @@ class QUICReceiveStreamState : public QUICUnidirectionalStreamState class QUICBidirectionalStreamState : public QUICStreamState { public: + QUICBidirectionalStreamState(QUICTransferProgressProvider *send_in, QUICTransferProgressProvider *send_out, + QUICTransferProgressProvider *recv_in, QUICTransferProgressProvider *recv_out) + : _send_stream_state(send_in, send_out), _recv_stream_state(recv_in, recv_out) + { + } State get() const override; void update_with_sending_frame(const QUICFrame &frame) override; From 939cdfe2169633f7bd4f3a3aad17f710eb2508c1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Jun 2018 14:10:57 +0900 Subject: [PATCH 0592/1313] Add QUICTransferProgressProvider.h --- .../net/quic/QUICTransferProgressProvider.h | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 iocore/net/quic/QUICTransferProgressProvider.h diff --git a/iocore/net/quic/QUICTransferProgressProvider.h b/iocore/net/quic/QUICTransferProgressProvider.h new file mode 100644 index 00000000000..e30cc24f4bf --- /dev/null +++ b/iocore/net/quic/QUICTransferProgressProvider.h @@ -0,0 +1,33 @@ +/** @file + * + * Interface for providing transfer progress + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +class QUICTransferProgressProvider +{ +public: + virtual bool is_transfer_goal_set() const = 0; + virtual bool is_transfer_complete() const = 0; + virtual uint64_t transfer_progress() const = 0; + virtual uint64_t transfer_goal() const = 0; +}; From 2ccd112e536e346aac9c52efd78dd198c834d39c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 1 Jun 2018 14:40:21 +0900 Subject: [PATCH 0593/1313] Print full connection id only if QUIC_DEBUG_TAG is set --- iocore/net/QUICNetVConnection.cc | 55 +++++++++++++++++++------------- iocore/net/QUICPacketHandler.cc | 8 +++-- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index cee2e527259..f38506d78ad 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -42,7 +42,9 @@ #define STATE_FROM_VIO(_x) ((NetState *)(((char *)(_x)) - STATE_VIO_OFFSET)) #define STATE_VIO_OFFSET ((uintptr_t) & ((NetState *)0)->vio) -#define QUICConDebug(fmt, ...) Debug("quic_net", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__) +static constexpr std::string_view QUIC_DEBUG_TAG = "quic_net"sv; + +#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__) @@ -88,12 +90,14 @@ QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_ci this->_update_cids(); - 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); + 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", dcid_hex_str, scid_hex_str); + } } bool @@ -1784,12 +1788,14 @@ QUICNetVConnection::_update_cids() void QUICNetVConnection::_update_peer_cid(const QUICConnectionId &new_cid) { - 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); + 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("dcid: %s -> %s", old_cid_str, new_cid_str); + } this->_peer_quic_connection_id = new_cid; this->_update_cids(); @@ -1798,12 +1804,14 @@ QUICNetVConnection::_update_peer_cid(const QUICConnectionId &new_cid) void QUICNetVConnection::_update_local_cid(const QUICConnectionId &new_cid) { - 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); + 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("scid: %s -> %s", old_cid_str, new_cid_str); + } this->_quic_connection_id = new_cid; this->_update_cids(); @@ -1812,14 +1820,15 @@ QUICNetVConnection::_update_local_cid(const QUICConnectionId &new_cid) void QUICNetVConnection::_rerandomize_original_cid() { - char old_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH]; - char new_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH]; - QUICConnectionId tmp = this->_original_quic_connection_id; - tmp.hex(old_cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH); - this->_original_quic_connection_id.randomize(); - 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); + 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); + } } diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 6d68cd9acdc..732a1aef4bd 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -231,9 +231,11 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) QUICConnectionId original_cid = this->_read_destination_connection_id(block); QUICConnectionId peer_cid = this->_read_source_connection_id(block); - 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); + 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); + } vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); vc->init(peer_cid, original_cid, udp_packet->getConnection(), this, this->_ctable); From 8d56b73aad6d58c164aa93f8131f9032ceb32377 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 1 Jun 2018 16:26:05 +0900 Subject: [PATCH 0594/1313] Print "[dcid-scid]" in debug log --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/QUICNextProtocolAccept.cc | 2 +- iocore/net/quic/QUICFrameDispatcher.cc | 10 ++++++---- iocore/net/quic/QUICFrameDispatcher.h | 7 ++++++- iocore/net/quic/QUICPacket.cc | 19 ++++++++++++++++--- iocore/net/quic/QUICTLS.cc | 2 -- proxy/hq/HQSessionAccept.cc | 6 +++--- proxy/hq/QUICSimpleApp.cc | 7 ++++--- 8 files changed, 37 insertions(+), 18 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index f38506d78ad..5d825576d5c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -209,7 +209,7 @@ QUICNetVConnection::start() this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); this->_hs_protocol = this->_handshake_handler->protocol(); - this->_frame_dispatcher = new QUICFrameDispatcher(); + this->_frame_dispatcher = new QUICFrameDispatcher(this); this->_packet_factory.set_hs_protocol(this->_hs_protocol); // Create frame handlers diff --git a/iocore/net/QUICNextProtocolAccept.cc b/iocore/net/QUICNextProtocolAccept.cc index d96d275dc91..1f721fa5bfc 100644 --- a/iocore/net/QUICNextProtocolAccept.cc +++ b/iocore/net/QUICNextProtocolAccept.cc @@ -50,7 +50,7 @@ QUICNextProtocolAccept::mainEvent(int event, void *edata) { QUICNetVConnection *netvc = quic_netvc_cast(event, edata); - Debug("quic", "[QUICNextProtocolAccept:mainEvent] event %d netvc %p", event, netvc); + Debug("v_quic", "[%s] event %d netvc %p", netvc->cids().data(), event, netvc); switch (event) { case NET_EVENT_ACCEPT: ink_release_assert(netvc != nullptr); diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index a6e58761102..2419526c3f5 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -26,9 +26,12 @@ static constexpr char tag[] = "quic_net"; +#define QUICDebug(fmt, ...) Debug(tag, "[%s] " fmt, this->_info->cids().data(), ##__VA_ARGS__) + // // Frame Dispatcher // +QUICFrameDispatcher::QUICFrameDispatcher(QUICConnectionInfoProvider *info) : _info(info) {} void QUICFrameDispatcher::add_handler(QUICFrameHandler *handler) @@ -49,18 +52,17 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size, bool while (cursor < size) { frame = this->_frame_factory.fast_create(payload + cursor, size - cursor); if (frame == nullptr) { - Debug(tag, "Failed to create a frame (%u bytes skipped)", size - cursor); + QUICDebug("Failed to create a frame (%u bytes skipped)", size - cursor); break; } cursor += frame->size(); QUICFrameType type = frame->type(); - // TODO: check debug build - if (type != QUICFrameType::PADDING) { + if (is_debug_tag_set(tag) && type != QUICFrameType::PADDING) { char msg[1024]; frame->debug_msg(msg, sizeof(msg)); - Debug(tag, "[RX] %s", msg); + QUICDebug("[RX] %s", msg); } should_send_ack |= (type != QUICFrameType::PADDING && type != QUICFrameType::ACK); diff --git a/iocore/net/quic/QUICFrameDispatcher.h b/iocore/net/quic/QUICFrameDispatcher.h index 397f0d38c7e..e9e3a0149ad 100644 --- a/iocore/net/quic/QUICFrameDispatcher.h +++ b/iocore/net/quic/QUICFrameDispatcher.h @@ -23,13 +23,17 @@ #pragma once +#include + +#include "QUICConnection.h" #include "QUICFrame.h" #include "QUICFrameHandler.h" -#include class QUICFrameDispatcher { public: + QUICFrameDispatcher(QUICConnectionInfoProvider *info); + /* * Returns true if ACK frame should be sent */ @@ -38,6 +42,7 @@ class QUICFrameDispatcher void add_handler(QUICFrameHandler *handler); private: + QUICConnectionInfoProvider *_info = nullptr; QUICFrameFactory _frame_factory; std::vector _handlers[256]; }; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 6d27cc398b0..945bee97253 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -27,6 +27,11 @@ #include "QUICPacket.h" #include "QUICDebugNames.h" +static constexpr std::string_view tag = "quic_packet"sv; + +#define QUICDebug(dcid, scid, fmt, ...) \ + Debug(tag.data(), "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__); + ClassAllocator quicPacketAllocator("quicPacketAllocator"); ClassAllocator quicPacketLongHeaderAllocator("quicPacketLongHeaderAllocator"); ClassAllocator quicPacketShortHeaderAllocator("quicPacketShortHeaderAllocator"); @@ -719,6 +724,11 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP QUICPacketHeaderUPtr header = QUICPacketHeader::load(from, std::move(buf), len, base_packet_number, this->_dcil); + QUICConnectionId dcid = header->destination_cid(); + QUICConnectionId scid = header->source_cid(); + QUICDebug(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 @@ -732,7 +742,6 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP memcpy(plain_txt.get(), header->payload(), header->payload_size()); plain_txt_len = header->payload_size(); } else { - Debug("quic_packet", "Decrypting %s packet #%" PRIu64, QUICDebugNames::packet_type(header->type()), header->packet_number()); switch (header->type()) { case QUICPacketType::STATELESS_RESET: // These packets are unprotected. Just copy the payload @@ -935,14 +944,18 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool re ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); size_t cipher_txt_len = 0; - Debug("quic_packet", "Encrypting %s packet #%" PRIu64, QUICDebugNames::packet_type(header->type()), header->packet_number()); + QUICConnectionId dcid = header->destination_cid(); + QUICConnectionId scid = header->source_cid(); + QUICDebug(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; if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable); } else { - Debug("quic_packet", "Failed to encrypt a packet"); + QUICDebug(dcid, scid, "Failed to encrypt a packet"); } return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index cebfaaa32bb..d6b49cf9b40 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -309,7 +309,6 @@ QUICTLS::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, con uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const { QUICPacketProtection *pp = nullptr; - Debug(tag, "Encrypting packet using %s key", QUICDebugNames::key_phase(phase)); switch (this->_netvc_context) { case NET_VCONNECTION_IN: { @@ -345,7 +344,6 @@ QUICTLS::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const { QUICPacketProtection *pp = nullptr; - Debug(tag, "Decrypting packet using %s key", QUICDebugNames::key_phase(phase)); switch (this->_netvc_context) { case NET_VCONNECTION_IN: { diff --git a/proxy/hq/HQSessionAccept.cc b/proxy/hq/HQSessionAccept.cc index 9906a457c2e..4f9299f78c3 100644 --- a/proxy/hq/HQSessionAccept.cc +++ b/proxy/hq/HQSessionAccept.cc @@ -47,11 +47,11 @@ HQSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader } netvc->attributes = this->options.transport_type; - if (is_debug_tag_set("quic_seq")) { + if (is_debug_tag_set("hq")) { ip_port_text_buffer ipb; - Debug("quic_seq", "[%" PRIx64 "] accepted connection from %s transport type = %d", - static_cast(static_cast(static_cast(netvc))->connection_id()), + Debug("hq", "[%s] accepted connection from %s transport type = %d", + static_cast(static_cast(netvc))->cids().data(), ats_ip_nptop(client_ip, ipb, sizeof(ipb)), netvc->attributes); } diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index 8ce397edd46..7dc50272582 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -31,7 +31,8 @@ #include "HQClientTransaction.h" #include "../IPAllow.h" -static constexpr char tag[] = "quic_simple_app"; +static constexpr char tag[] = "quic_simple_app"; +static constexpr char tag_v[] = "v_quic_simple_app"; QUICSimpleApp::QUICSimpleApp(QUICNetVConnection *client_vc) : QUICApplication(client_vc) { @@ -55,13 +56,13 @@ QUICSimpleApp::~QUICSimpleApp() int QUICSimpleApp::main_event_handler(int event, Event *data) { - Debug(tag, "[%" PRIx64 "] %s (%d)", static_cast(this->_qc->connection_id()), get_vc_event_name(event), event); + Debug(tag_v, "[%s] %s (%d)", this->_qc->cids().data(), get_vc_event_name(event), event); VIO *vio = reinterpret_cast(data); QUICStreamIO *stream_io = this->_find_stream_io(vio); if (stream_io == nullptr) { - Debug(tag, "[%" PRIx64 "] Unknown Stream", static_cast(this->_qc->connection_id())); + Debug(tag, "[%s] Unknown Stream", this->_qc->cids().data()); return -1; } From 94d86f4f899ad3a34179b920ae350cf821e6add5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Jun 2018 16:55:42 +0900 Subject: [PATCH 0595/1313] Maybe we should not retransmit PATH_CHALLENGE frames --- iocore/net/quic/QUICPacketRetransmitter.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 5f9ba333509..e1bd1637b0b 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -43,6 +43,7 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) switch (frame->type()) { case QUICFrameType::PADDING: case QUICFrameType::ACK: + case QUICFrameType::PATH_CHALLENGE: break; default: frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); From 79ee060bd1cd7178944208884fff26e89ba01031 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Jun 2018 19:59:05 +0900 Subject: [PATCH 0596/1313] Fix QUICFrameFactory::split_fram The new frame was not used. --- iocore/net/quic/QUICFrame.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index a79ef85d550..168033dbbfe 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2233,7 +2233,7 @@ QUICFrameUPtr QUICFrameFactory::split_frame(QUICFrame *frame, size_t size) { auto new_frame = frame->split(size); - if (new_frame != nullptr) { + if (!new_frame) { return QUICFrameFactory::create_null_frame(); } From 06bdc448840c08e611e776408c1488cd4276c919 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Jun 2018 20:02:41 +0900 Subject: [PATCH 0597/1313] Improve log output from LossDetector --- iocore/net/quic/QUICLossDetector.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index a2eca1349e7..524bfd78b1a 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -382,13 +382,14 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num ink_hrtime time_since_sent = Thread::get_hrtime() - unacked.second->time; uint64_t packet_delta = largest_acked_packet_number - unacked.second->packet_number; if (time_since_sent > delay_until_lost) { - QUICLDDebug("Lost: time since sent is too long (sent=%" PRId64 ", delay=%lf, fraction=%lf, lrtt=%" PRId64 ", srtt=%" PRId64 - ")", - time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, this->_smoothed_rtt); + QUICLDDebug("Lost: time since sent is too long (PN=%" PRId64 " sent=%" PRId64 ", delay=%lf, fraction=%lf, lrtt=%" PRId64 + ", srtt=%" PRId64 ")", + unacked.first, time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, + this->_smoothed_rtt); lost_packets.insert({unacked.first, unacked.second.get()}); } else if (packet_delta > this->_reordering_threshold) { - QUICLDDebug("Lost: packet delta is too large (largest=%" PRId64 " unacked=%" PRId64 " threshold=%" PRId32 ")", - largest_acked_packet_number, unacked.second->packet_number, this->_reordering_threshold); + QUICLDDebug("Lost: packet delta is too large (PN=%" PRId64 " largest=%" PRId64 " unacked=%" PRId64 " threshold=%" PRId32 ")", + unacked.first, largest_acked_packet_number, unacked.second->packet_number, this->_reordering_threshold); lost_packets.insert({unacked.first, unacked.second.get()}); } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) { this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent; From d4e34a5bdb66934ba4ad7f1cfc488499e9687609 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Jun 2018 21:20:22 +0900 Subject: [PATCH 0598/1313] Fixs QUICNewConnectionIdFrame::clone() A wrong frame was created. --- iocore/net/quic/QUICFrame.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 168033dbbfe..45db0d5a5bf 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1740,7 +1740,7 @@ QUICFrameUPtr QUICNewConnectionIdFrame::clone() const { // FIXME: Connection ID and Stateless rese token have to be the same - return QUICFrameFactory::create_stream_id_blocked_frame(this->sequence()); + return QUICFrameFactory::create_new_connection_id_frame(this->sequence(), this->connection_id(), this->stateless_reset_token()); } QUICFrameType From e8bb31603624a47a24b43bab45194c9dfe6f413e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Jun 2018 22:05:59 +0900 Subject: [PATCH 0599/1313] Fix a bug that bytes_in_flight is not decreased when retransmit HANDSHAKE packets --- iocore/net/quic/QUICLossDetector.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 524bfd78b1a..b19b133e9e4 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -420,12 +420,15 @@ QUICLossDetector::_retransmit_handshake_packets() SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); std::set retransmitted_handshake_packets; + std::map lost_packets; for (auto &info : this->_sent_packets) { retransmitted_handshake_packets.insert(info.first); + lost_packets.insert({info.first, info.second.get()}); this->_transmitter->retransmit_packet(*info.second->packet); } + this->_cc->on_packets_lost(lost_packets); for (auto packet_number : retransmitted_handshake_packets) { this->_remove_from_sent_packet_list(packet_number); } From c3d89e4e5299d29be1049ed9a3725f998ac8077a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Jun 2018 22:34:42 +0900 Subject: [PATCH 0600/1313] maximum_frame_size is for STREAM data size --- iocore/net/quic/QUICPacketRetransmitter.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index e1bd1637b0b..5fcd4a84b30 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -67,7 +67,19 @@ QUICPacketRetransmitter::generate_frame(uint64_t connection_credit, uint16_t max frame = std::move(this->_retransmission_frames.front()); this->_retransmission_frames.pop(); - if (maximum_frame_size < frame->size()) { + // maximum_frame_size is actually for payload size. So we should compare it + // with data_length(). Howeever, because data_length() is STREAM frame + // specific, we need a branch here. + // See also where maximum_frame_size come from. + bool split = false; + if (frame->type() == QUICFrameType::STREAM) { + QUICStreamFrame *stream_frame = static_cast(frame.get()); + split = stream_frame->data_length() > maximum_frame_size; + } else { + split = frame->size() > maximum_frame_size; + } + + if (split) { auto new_frame = QUICFrameFactory::split_frame(frame.get(), maximum_frame_size); if (new_frame) { this->_retransmission_frames.push(std::move(new_frame)); From aea857dc20a372e72c769b8381dbb764bf233e15 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 4 Jun 2018 21:02:13 +0900 Subject: [PATCH 0601/1313] Add a validation of payload length of Long Header Packet --- iocore/net/quic/QUICPacket.cc | 48 +++++++++++++++++++++++++++-------- iocore/net/quic/QUICPacket.h | 5 +++- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 945bee97253..0178f02c421 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -138,21 +138,21 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf if (scil) { scil += 3; } - uint8_t *offset = raw_buf + LONG_HDR_OFFSET_CONNECTION_ID; - this->_destination_cid = {offset, dcil}; + size_t offset = LONG_HDR_OFFSET_CONNECTION_ID; + this->_destination_cid = {raw_buf + offset, dcil}; offset += dcil; - this->_source_cid = {offset, scil}; + this->_source_cid = {raw_buf + offset, scil}; offset += scil; if (this->type() == QUICPacketType::VERSION_NEGOTIATION) { - this->_payload_start = offset; - this->_payload_length = len - (offset - raw_buf); + this->_payload_offset = offset; + this->_payload_length = len - offset; } else { - this->_payload_length = QUICIntUtil::read_QUICVariableInt(offset); - offset += QUICVariableInt::size(offset); - QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(offset, 4), 4, + this->_payload_length = QUICIntUtil::read_QUICVariableInt(raw_buf + offset); + offset += QUICVariableInt::size(raw_buf + offset); + QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset, 4), 4, this->_base_packet_number); - this->_payload_start = offset + 4; + this->_payload_offset = offset + 4; } } @@ -219,6 +219,22 @@ QUICPacketLongHeader::has_version() const return true; } +bool +QUICPacketLongHeader::is_valid() 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); + + return false; + } + + return true; +} + QUICVersion QUICPacketLongHeader::version() const { @@ -233,7 +249,8 @@ const uint8_t * QUICPacketLongHeader::payload() const { if (this->_buf) { - return this->_payload_start; + uint8_t *raw = this->_buf.get(); + return raw + this->_payload_offset; } else { return this->_payload.get(); } @@ -384,6 +401,12 @@ QUICPacketShortHeader::has_version() const return false; } +bool +QUICPacketShortHeader::is_valid() const +{ + return true; +} + QUICVersion QUICPacketShortHeader::version() const { @@ -723,6 +746,11 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP size_t plain_txt_len = 0; QUICPacketHeaderUPtr header = QUICPacketHeader::load(from, std::move(buf), len, base_packet_number, this->_dcil); + if (!header->is_valid()) { + // PROTOCOL_VIOLATION ? + result = QUICPacketCreationResult::FAILED; + return QUICPacketUPtr(nullptr, &QUICPacketDeleter::delete_packet); + } QUICConnectionId dcid = header->destination_cid(); QUICConnectionId scid = header->source_cid(); diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 8d72f36511f..f54073d2b9f 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -108,6 +108,7 @@ class QUICPacketHeader virtual bool has_key_phase() const = 0; virtual bool has_version() const = 0; + virtual bool is_valid() const = 0; /***** STATIC members *****/ @@ -181,6 +182,7 @@ class QUICPacketLongHeader : public QUICPacketHeader QUICConnectionId source_cid() const; QUICPacketNumber packet_number() const; bool has_version() const; + bool is_valid() const; QUICVersion version() const; const uint8_t *payload() const; QUICKeyPhase key_phase() const; @@ -192,7 +194,7 @@ class QUICPacketLongHeader : public QUICPacketHeader QUICPacketNumber _packet_number; QUICConnectionId _destination_cid = QUICConnectionId::ZERO(); QUICConnectionId _source_cid = QUICConnectionId::ZERO(); - uint8_t *_payload_start; + size_t _payload_offset = 0; }; class QUICPacketShortHeader : public QUICPacketHeader @@ -214,6 +216,7 @@ class QUICPacketShortHeader : public QUICPacketHeader } QUICPacketNumber packet_number() const; bool has_version() const; + bool is_valid() const; QUICVersion version() const; const uint8_t *payload() const; QUICKeyPhase key_phase() const; From 7b8f86e28457b96d2aa61e70be0b92bd99a03546 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Jun 2018 14:30:31 +0200 Subject: [PATCH 0602/1313] Use this->thread instead of this_ethread() On some pathes, this_ethread() can be UDP thread, and it shouldn't be used. --- iocore/net/QUICNetVConnection.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5d825576d5c..326250d7e61 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -598,6 +598,12 @@ QUICNetVConnection::state_handshake(int event, Event *data) break; } + case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: + this->_close_path_validation_timeout(data); + if (!this->_path_validator->is_validated()) { + this->_switch_to_close_state(); + } + break; case EVENT_IMMEDIATE: // Start Immediate Close because of Idle Timeout this->_handle_idle_timeout(); @@ -1519,9 +1525,9 @@ QUICNetVConnection::_schedule_packet_write_ready(bool delay) if (!this->_packet_write_ready) { QUICConVDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); if (delay) { - this->_packet_write_ready = this_ethread()->schedule_in(this, WRITE_READY_INTERVAL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + this->_packet_write_ready = this->thread->schedule_in(this, WRITE_READY_INTERVAL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); } else { - this->_packet_write_ready = this_ethread()->schedule_imm(this, QUIC_EVENT_PACKET_WRITE_READY, nullptr); + this->_packet_write_ready = this->thread->schedule_imm(this, QUIC_EVENT_PACKET_WRITE_READY, nullptr); } } } @@ -1549,7 +1555,7 @@ QUICNetVConnection::_schedule_closing_timeout(ink_hrtime interval) { if (!this->_closing_timeout) { QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_CLOSING_TIMEOUT)); - this->_closing_timeout = this_ethread()->schedule_in_local(this, interval, QUIC_EVENT_CLOSING_TIMEOUT); + this->_closing_timeout = this->thread->schedule_in_local(this, interval, QUIC_EVENT_CLOSING_TIMEOUT); } } @@ -1574,7 +1580,7 @@ QUICNetVConnection::_schedule_closed_event() { if (!this->_closed_event) { QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_SHUTDOWN)); - this->_closed_event = this_ethread()->schedule_imm(this, QUIC_EVENT_SHUTDOWN, nullptr); + this->_closed_event = this->thread->schedule_imm(this, QUIC_EVENT_SHUTDOWN, nullptr); } } @@ -1618,7 +1624,7 @@ QUICNetVConnection::_schedule_path_validation_timeout(ink_hrtime interval) { if (!this->_path_validation_timeout) { QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PATH_VALIDATION_TIMEOUT)); - this->_path_validation_timeout = this_ethread()->schedule_in_local(this, interval, QUIC_EVENT_PATH_VALIDATION_TIMEOUT); + this->_path_validation_timeout = this->thread->schedule_in_local(this, interval, QUIC_EVENT_PATH_VALIDATION_TIMEOUT); } } From 7f2038314bf54739ad498b38afd9f7a29515f4d4 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Jun 2018 16:02:43 +0900 Subject: [PATCH 0603/1313] Check Version Negotiation packet in QUICPacketReceiveQueue::dequeue() To avoid heap-buffer-overflow in long_hdr_pkt_len() --- iocore/net/quic/QUICPacketReceiveQueue.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 887b965ecd7..00c69041e1b 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -26,9 +26,16 @@ #include "QUICIntUtil.h" // FIXME: workaround for coalescing packets +static constexpr int LONG_HDR_OFFSET_VERSION = 1; static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6; static constexpr int LONG_HDR_PKT_NUM_LEN = 4; +static bool +is_vn(uint8_t *buf) +{ + return QUICTypeUtil::read_QUICVersion(buf + LONG_HDR_OFFSET_VERSION) == 0x00; +} + static size_t long_hdr_pkt_len(uint8_t *buf) { @@ -92,10 +99,13 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) size_t pkt_len = 0; if (QUICTypeUtil::has_long_header(this->_payload.get())) { - if (QUICTypeUtil::has_long_header(this->_payload.get() + this->_offset)) { + size_t remaining_len = this->_payload_len - this->_offset; + if (is_vn(this->_payload.get() + this->_offset)) { + pkt_len = remaining_len; + } else if (QUICTypeUtil::has_long_header(this->_payload.get() + this->_offset)) { pkt_len = long_hdr_pkt_len(this->_payload.get() + this->_offset); } else { - pkt_len = this->_payload_len - this->_offset; + pkt_len = remaining_len; } if (pkt_len < this->_payload_len) { From 25ab32e5c81ece13de55294776b6521ecea59ad5 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Jun 2018 16:57:47 +0900 Subject: [PATCH 0604/1313] Move SendStreamState Ready when it is created --- iocore/net/quic/QUICStreamState.h | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h index f0508153a5e..2bf7ed790b7 100644 --- a/iocore/net/quic/QUICStreamState.h +++ b/iocore/net/quic/QUICStreamState.h @@ -94,6 +94,7 @@ class QUICSendStreamState : public QUICUnidirectionalStreamState public: QUICSendStreamState(QUICTransferProgressProvider *in, QUICTransferProgressProvider *out) : QUICUnidirectionalStreamState(in, out) { + this->_set_state(State::Ready); } void update_with_sending_frame(const QUICFrame &frame) override; From e06bd43bcae99fe28a0f484f617d8ee1c0678f24 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 5 Jun 2018 11:14:59 +0200 Subject: [PATCH 0605/1313] Fix a bug in ConnectionId comparation operators --- iocore/net/quic/QUICTypes.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index bdf1a3aa5c1..7801295051f 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -233,13 +233,16 @@ class QUICConnectionId if (this->_len != x._len) { return false; } - return memcmp(this->_id, x._id, sizeof(this->_len)) == 0; + return memcmp(this->_id, x._id, this->_len) == 0; } bool operator!=(const QUICConnectionId &x) const { - return memcmp(this->_id, x._id, sizeof(this->_id)) != 0; + if (this->_len != x._len) { + return true; + } + return memcmp(this->_id, x._id, this->_len) != 0; } /* From 1c8264b5fd92ab8b446dc2fb1824ddd6a0f86f5e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 5 Jun 2018 11:16:20 +0200 Subject: [PATCH 0606/1313] Remove redundant remove_connection_ids() call --- iocore/net/QUICNetVConnection.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 326250d7e61..fba95e63783 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -234,7 +234,6 @@ void QUICNetVConnection::free(EThread *t) { QUICConDebug("Free connection"); - this->remove_connection_ids(); /* TODO: Uncmment these blocks after refactoring read / write process this->_udp_con = nullptr; From 0a9fe522731ca820901781b08c6f9f892870e757 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Jun 2018 21:35:11 +0900 Subject: [PATCH 0607/1313] Fix unsupported version packet handling - Do not copy payload, because payload size is unknown - Do not set largest received packet number, because packet number is unknown --- iocore/net/quic/QUICPacket.cc | 11 ++------ iocore/net/quic/QUICPacketReceiveQueue.cc | 34 ++++++++++++++++------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 0178f02c421..1e3ed1328c2 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -746,11 +746,6 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP size_t plain_txt_len = 0; QUICPacketHeaderUPtr header = QUICPacketHeader::load(from, std::move(buf), len, base_packet_number, this->_dcil); - if (!header->is_valid()) { - // PROTOCOL_VIOLATION ? - result = QUICPacketCreationResult::FAILED; - return QUICPacketUPtr(nullptr, &QUICPacketDeleter::delete_packet); - } QUICConnectionId dcid = header->destination_cid(); QUICConnectionId scid = header->source_cid(); @@ -762,13 +757,13 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP // 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; } - - memcpy(plain_txt.get(), header->payload(), header->payload_size()); - plain_txt_len = header->payload_size(); } else { switch (header->type()) { case QUICPacketType::STATELESS_RESET: diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 00c69041e1b..1c30f3ac2d0 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -31,9 +31,9 @@ static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6; static constexpr int LONG_HDR_PKT_NUM_LEN = 4; static bool -is_vn(uint8_t *buf) +is_vn(QUICVersion v) { - return QUICTypeUtil::read_QUICVersion(buf + LONG_HDR_OFFSET_VERSION) == 0x00; + return v == 0x0; } static size_t @@ -99,11 +99,19 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) size_t pkt_len = 0; if (QUICTypeUtil::has_long_header(this->_payload.get())) { + uint8_t *buf = this->_payload.get() + this->_offset; size_t remaining_len = this->_payload_len - this->_offset; - if (is_vn(this->_payload.get() + this->_offset)) { - pkt_len = remaining_len; - } else if (QUICTypeUtil::has_long_header(this->_payload.get() + this->_offset)) { - pkt_len = long_hdr_pkt_len(this->_payload.get() + this->_offset); + + if (QUICTypeUtil::has_long_header(buf)) { + QUICVersion version = QUICTypeUtil::read_QUICVersion(buf + LONG_HDR_OFFSET_VERSION); + if (is_vn(version)) { + pkt_len = remaining_len; + } else if (!QUICTypeUtil::is_supported_version(version)) { + result = QUICPacketCreationResult::UNSUPPORTED; + pkt_len = remaining_len; + } else { + pkt_len = long_hdr_pkt_len(this->_payload.get() + this->_offset); + } } else { pkt_len = remaining_len; } @@ -140,15 +148,21 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) udp_packet->free(); } - if (result == QUICPacketCreationResult::NOT_READY) { + switch (result) { + case QUICPacketCreationResult::NOT_READY: // FIXME: unordered packet should be buffered and retried if (this->_queue.size > 0) { result = QUICPacketCreationResult::IGNORED; } - } - if (quic_packet && quic_packet->packet_number() > this->_largest_received_packet_number) { - this->_largest_received_packet_number = quic_packet->packet_number(); + break; + case QUICPacketCreationResult::UNSUPPORTED: + // 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) { + this->_largest_received_packet_number = quic_packet->packet_number(); + } } return quic_packet; From cd041706743783a52144e0bc367e1b75680301aa Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 6 Jun 2018 15:15:30 +0900 Subject: [PATCH 0608/1313] Check debug tag before print debug msg of frame --- iocore/net/QUICNetVConnection.cc | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index fba95e63783..3bf73aa7da7 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1169,13 +1169,14 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans ink_assert(max_size > len); - char msg[1024]; size_t l = 0; size_t n = frame->store(buf.get() + len, &l, max_size - len); if (n > 0) { - // TODO: check debug build - frame->debug_msg(msg, sizeof(msg)); - QUICConDebug("[TX] %s", msg); + if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) { + char msg[1024]; + frame->debug_msg(msg, sizeof(msg)); + QUICConDebug("[TX] %s", msg); + } len += l; return; @@ -1184,9 +1185,11 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans // split frame auto new_frame = QUICFrameFactory::split_frame(frame.get(), max_size - len); - // TODO: check debug build - frame->debug_msg(msg, sizeof(msg)); - QUICConDebug("[TX] %s", msg); + if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) { + char msg[1024]; + frame->debug_msg(msg, sizeof(msg)); + QUICConDebug("[TX] %s", msg); + } ink_assert(frame->store(buf.get() + len, &l, max_size - len) > 0); ink_assert(new_frame != nullptr); From a111b9c585d5fcfb9bdb616fd1206a60d7dc63a7 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 6 Jun 2018 16:00:47 +0900 Subject: [PATCH 0609/1313] Reset QUICPacketRetransmitter when QUICNetVC discards all transport state --- iocore/net/QUICNetVConnection.cc | 4 ++++ iocore/net/quic/QUICPacketRetransmitter.cc | 8 ++++++++ iocore/net/quic/QUICPacketRetransmitter.h | 1 + 3 files changed, 13 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3bf73aa7da7..51e9d57b0f4 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -881,6 +881,8 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack this->_stream_manager->reset_send_offset(); this->_stream_manager->reset_recv_offset(); this->_loss_detector->reset(); + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); + this->_packet_retransmitter.reset(); // start handshake over this->_handshake_handler->reset(); @@ -918,6 +920,8 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) // discard all transport state this->_stream_manager->reset_send_offset(); this->_loss_detector->reset(); + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); + this->_packet_retransmitter.reset(); QUICErrorUPtr error = this->_recv_and_ack(std::move(packet)); diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 5fcd4a84b30..2186540a27f 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -53,6 +53,14 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) } } +void +QUICPacketRetransmitter::reset() +{ + while (!this->_retransmission_frames.empty()) { + this->_retransmission_frames.pop(); + } +} + bool QUICPacketRetransmitter::will_generate_frame() { diff --git a/iocore/net/quic/QUICPacketRetransmitter.h b/iocore/net/quic/QUICPacketRetransmitter.h index bef5efa74e0..c468b850400 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.h +++ b/iocore/net/quic/QUICPacketRetransmitter.h @@ -32,6 +32,7 @@ class QUICPacketRetransmitter : public QUICFrameGenerator { public: void retransmit_packet(const QUICPacket &packet); + void reset(); // QUICFrameGenerator bool will_generate_frame() override; From 5809e30ea8547c2fec2ac4c27bf35e482e03ca88 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Jun 2018 11:19:34 +0200 Subject: [PATCH 0610/1313] Initialize bidirectional stream state appropriately --- iocore/net/quic/QUICStreamState.cc | 4 ++++ iocore/net/quic/QUICStreamState.h | 1 + 2 files changed, 5 insertions(+) diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index dda51f09f7a..8fb3972e2c3 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -345,6 +345,7 @@ QUICBidirectionalStreamState::get() const } else if (r_state == State::ResetRecvd || r_state == State::ResetRead) { return State::HC_R; } else { + ink_assert(false); return State::_Invalid; } } else if (s_state == State::DataRecvd) { @@ -355,6 +356,7 @@ QUICBidirectionalStreamState::get() const } else if (r_state == State::ResetRecvd || r_state == State::ResetRead) { return State::Closed; } else { + ink_assert(false); return State::_Invalid; } } else if (s_state == State::ResetSent || s_state == State::ResetRecvd) { @@ -365,11 +367,13 @@ QUICBidirectionalStreamState::get() const } else if (r_state == State::ResetRecvd || r_state == State::ResetRead) { return State::Closed; } else { + ink_assert(false); return State::_Invalid; } } else if (s_state == State::_Init && r_state == State::_Init) { return State::_Init; } else { + ink_assert(false); return State::_Invalid; } } diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h index 2bf7ed790b7..7d3bcfc15dc 100644 --- a/iocore/net/quic/QUICStreamState.h +++ b/iocore/net/quic/QUICStreamState.h @@ -128,6 +128,7 @@ class QUICBidirectionalStreamState : public QUICStreamState QUICTransferProgressProvider *recv_in, QUICTransferProgressProvider *recv_out) : _send_stream_state(send_in, send_out), _recv_stream_state(recv_in, recv_out) { + this->_recv_stream_state.update(this->_send_stream_state); } State get() const override; From 455c8a920003b425b99e1a5f827e1ccdf7384d0d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 22 May 2018 16:50:52 +0900 Subject: [PATCH 0611/1313] Update QUIC/HTTP versions --- iocore/net/quic/QUICTypes.h | 4 ++-- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- lib/ts/ink_inet.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 7801295051f..21ed0f1e6a6 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -47,7 +47,7 @@ using QUICOffset = uint64_t; // Note: You also need to update tests for VersionNegotiationPacket creation, if you change the number of versions // Prefix for drafts (0xff000000) + draft number constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff00000b, + 0xff00000c, }; constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; @@ -56,7 +56,7 @@ constexpr QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; // OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings) // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html // Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? -constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-11"sv); +constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-12"sv); enum class QUICHandshakeMsgType { NONE = 0, diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 533fbd5588c..35fc1e86ea7 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -69,7 +69,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x55, // DCIL/SCIL 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Destination Connection ID 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection ID - 0xff, 0x00, 0x00, 0x0b, // Supported Version + 0xff, 0x00, 0x00, 0x0c, // Supported Version }; uint8_t buf[1024] = {0}; size_t buf_len; diff --git a/lib/ts/ink_inet.cc b/lib/ts/ink_inet.cc index b1b4d92ae5a..684f1949fb8 100644 --- a/lib/ts/ink_inet.cc +++ b/lib/ts/ink_inet.cc @@ -51,7 +51,7 @@ const std::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"sv); const std::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"sv); const std::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"sv); const std::string_view IP_PROTO_TAG_HTTP_2_0("h2"sv); // HTTP/2 over TLS -const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-11"sv); // HTTP over QUIC +const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-12"sv); // HTTP over QUIC uint32_t ink_inet_addr(const char *s) From 14643af079b0309d5a283958e4ad556dc7206160 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 22 May 2018 17:32:58 +0900 Subject: [PATCH 0612/1313] Rename INITIAL_MAX_STREAM_ID_{BIDI,UNI} parameters to INITIAL_MAX_{BIDI,UNI}_STREAMS --- iocore/net/quic/QUICConfig.cc | 16 ++++++++-------- iocore/net/quic/QUICConfig.h | 16 ++++++++-------- iocore/net/quic/QUICDebugNames.cc | 8 ++++---- iocore/net/quic/QUICHandshake.cc | 8 ++++---- iocore/net/quic/QUICStreamManager.cc | 8 ++++---- iocore/net/quic/QUICTransportParameters.cc | 8 ++++---- iocore/net/quic/QUICTransportParameters.h | 4 ++-- .../quic/test/test_QUICTransportParameters.cc | 2 +- 8 files changed, 35 insertions(+), 35 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index fae2788e88a..6010b232151 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -217,27 +217,27 @@ QUICConfigParams::initial_max_stream_data() const } uint16_t -QUICConfigParams::initial_max_stream_id_bidi_in() const +QUICConfigParams::initial_max_bidi_streams_in() const { - return this->_initial_max_stream_id_bidi_in; + return this->_initial_max_bidi_streams_in; } uint16_t -QUICConfigParams::initial_max_stream_id_bidi_out() const +QUICConfigParams::initial_max_bidi_streams_out() const { - return this->_initial_max_stream_id_bidi_out; + return this->_initial_max_bidi_streams_out; } uint16_t -QUICConfigParams::initial_max_stream_id_uni_in() const +QUICConfigParams::initial_max_uni_streams_in() const { - return this->_initial_max_stream_id_uni_in; + return this->_initial_max_uni_streams_in; } uint16_t -QUICConfigParams::initial_max_stream_id_uni_out() const +QUICConfigParams::initial_max_uni_streams_out() const { - return this->_initial_max_stream_id_uni_out; + return this->_initial_max_uni_streams_out; } const char * diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index d6e17905435..36a7ee4e6e8 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -39,10 +39,10 @@ class QUICConfigParams : public ConfigInfo uint32_t no_activity_timeout_out() const; uint32_t initial_max_data() const; uint32_t initial_max_stream_data() const; - uint16_t initial_max_stream_id_bidi_in() const; - uint16_t initial_max_stream_id_bidi_out() const; - uint16_t initial_max_stream_id_uni_in() const; - uint16_t initial_max_stream_id_uni_out() const; + uint16_t initial_max_bidi_streams_in() const; + uint16_t initial_max_bidi_streams_out() const; + uint16_t initial_max_uni_streams_in() const; + uint16_t initial_max_uni_streams_out() const; uint32_t server_id() const; static int connection_table_size(); uint32_t max_alt_connection_ids() const; @@ -82,10 +82,10 @@ class QUICConfigParams : public ConfigInfo uint32_t _stateless_retry = 0; uint32_t _vn_exercise_enabled = 0; - uint32_t _initial_max_stream_id_bidi_in = 100; - uint32_t _initial_max_stream_id_bidi_out = 100; - uint32_t _initial_max_stream_id_uni_in = 100; - uint32_t _initial_max_stream_id_uni_out = 100; + uint32_t _initial_max_bidi_streams_in = 100; + uint32_t _initial_max_bidi_streams_out = 100; + uint32_t _initial_max_uni_streams_in = 100; + uint32_t _initial_max_uni_streams_out = 100; char *_server_supported_groups = nullptr; char *_client_supported_groups = nullptr; diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index df250d6dad8..def2f66dcf2 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -177,8 +177,8 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) return "INITIAL_MAX_STREAM_DATA"; case QUICTransportParameterId::INITIAL_MAX_DATA: return "INITIAL_MAX_DATA"; - case QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI: - return "INITIAL_MAX_STREAM_ID_BIDI"; + case QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS: + return "INITIAL_MAX_BIDI_STREAMS"; case QUICTransportParameterId::IDLE_TIMEOUT: return "IDLE_TIMEOUT"; case QUICTransportParameterId::MAX_PACKET_SIZE: @@ -187,8 +187,8 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) return "STATELESS_RESET_TOKEN"; case QUICTransportParameterId::ACK_DELAY_EXPONENT: return "ACK_DELAY_EXPONENT"; - case QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI: - return "INITIAL_MAX_STREAM_ID_UNI"; + case QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS: + return "INITIAL_MAX_UNI_STREAMS"; default: return "UNKNOWN"; } diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 57f00f1691b..ea1c7fec734 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -397,8 +397,8 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); // MAYs - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi_in()); - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni_in()); + tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_in()); + tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_in()); // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); this->_local_transport_parameters = std::unique_ptr(tp); @@ -417,8 +417,8 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_out())); // MAYs - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, params->initial_max_stream_id_bidi_out()); - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI, params->initial_max_stream_id_uni_out()); + tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_out()); + tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_out()); this->_local_transport_parameters = std::unique_ptr(tp); } diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 5b2299ebd40..24cd4923652 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -68,12 +68,12 @@ QUICStreamManager::init_flow_control_params(const std::shared_ptr_local_tp) { - this->_local_maximum_stream_id_bidi = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI); - this->_local_maximum_stream_id_uni = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI); + this->_local_maximum_stream_id_bidi = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS); + this->_local_maximum_stream_id_uni = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS); } if (this->_remote_tp) { - this->_remote_maximum_stream_id_bidi = this->_remote_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI); - this->_remote_maximum_stream_id_uni = this->_remote_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI); + this->_remote_maximum_stream_id_bidi = this->_remote_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS); + this->_remote_maximum_stream_id_uni = this->_remote_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS); } } diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index ea168013f7e..ea3ce3a3f39 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -188,13 +188,13 @@ QUICTransportParameters::_validate_parameters() const } // MAYs - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI)) != this->_parameters.end()) { + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS)) != this->_parameters.end()) { if (ite->second->len() != 2) { return -3; } } - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI)) != this->_parameters.end()) { + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS)) != this->_parameters.end()) { if (ite->second->len() != 2) { return -5; } @@ -508,7 +508,7 @@ QUICTransportParametersInNewSessionTicket::_validate_parameters() const } // MAYs - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI)) != this->_parameters.end()) { + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS)) != this->_parameters.end()) { if (ite->second->len() != 4) { return -3; } @@ -518,7 +518,7 @@ QUICTransportParametersInNewSessionTicket::_validate_parameters() const } } - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_UNI)) != this->_parameters.end()) { + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS)) != this->_parameters.end()) { if (ite->second->len() != 4) { return -5; } diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index cf5695789d7..12c16111070 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -36,13 +36,13 @@ class QUICTransportParameterId enum { INITIAL_MAX_STREAM_DATA = 0, INITIAL_MAX_DATA, - INITIAL_MAX_STREAM_ID_BIDI, + INITIAL_MAX_BIDI_STREAMS, IDLE_TIMEOUT, X_RESERVED, MAX_PACKET_SIZE, STATELESS_RESET_TOKEN, ACK_DELAY_EXPONENT, - INITIAL_MAX_STREAM_ID_UNI + INITIAL_MAX_UNI_STREAMS }; explicit operator bool() const { return true; } diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index dc793693629..9dff13cb5fa 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -61,7 +61,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") CHECK(len == 4); CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); - data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_ID_BIDI, len); + data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, len); CHECK(len == 2); CHECK(memcmp(data, "\x0a\x0b", 2) == 0); From f6139ab26b2cb1531f24723ff9a48cb5636edf5c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 23 May 2018 11:41:52 +0900 Subject: [PATCH 0613/1313] Check existence of PreferredAddress transsport parameter --- iocore/net/quic/QUICDebugNames.cc | 2 ++ iocore/net/quic/QUICTransportParameters.cc | 11 +++++++++++ iocore/net/quic/QUICTransportParameters.h | 2 +- iocore/net/quic/QUICTypes.h | 9 +++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index def2f66dcf2..2eeb2943b2b 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -181,6 +181,8 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) return "INITIAL_MAX_BIDI_STREAMS"; case QUICTransportParameterId::IDLE_TIMEOUT: return "IDLE_TIMEOUT"; + case QUICTransportParameterId::PREFERRED_ADDRESS: + return "PREFERRED_ADDRESS"; case QUICTransportParameterId::MAX_PACKET_SIZE: return "MAX_PACKET_SIZE"; case QUICTransportParameterId::STATELESS_RESET_TOKEN: diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index ea3ce3a3f39..fbf402b4b80 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -369,6 +369,10 @@ QUICTransportParametersInClientHello::_validate_parameters() const return -1; } + if ((ite = this->_parameters.find(QUICTransportParameterId::PREFERRED_ADDRESS)) != this->_parameters.end()) { + return -2; + } + return 0; } @@ -462,6 +466,13 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const return -2; } + // MAYs + if ((ite = this->_parameters.find(QUICTransportParameterId::PREFERRED_ADDRESS)) != this->_parameters.end()) { + if (ite->second->len() < QUICPreferredAddress::MIN_LEN || QUICPreferredAddress::MAX_LEN < ite->second->len()) { + return -3; + } + } + return 0; } diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 12c16111070..3c5aa65718c 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -38,7 +38,7 @@ class QUICTransportParameterId INITIAL_MAX_DATA, INITIAL_MAX_BIDI_STREAMS, IDLE_TIMEOUT, - X_RESERVED, + PREFERRED_ADDRESS, MAX_PACKET_SIZE, STATELESS_RESET_TOKEN, ACK_DELAY_EXPONENT, diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 21ed0f1e6a6..b17d1219216 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -286,6 +286,15 @@ class QUICStatelessResetToken void _gen_token(uint64_t data); }; +class QUICPreferredAddress +{ +public: + constexpr static int16_t MIN_LEN = 26; + constexpr static int16_t MAX_LEN = 295; + + QUICPreferredAddress() {} +}; + enum class QUICStreamType : uint8_t { CLIENT_BIDI = 0x00, SERVER_BIDI, From f4d4a10ed3708aa4e89a3bb9b32146e24d319cb1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 23 May 2018 12:29:26 +0900 Subject: [PATCH 0614/1313] Initial packet number is 0 on draft-12 --- iocore/net/quic/QUICPacket.cc | 15 ++------------- iocore/net/quic/QUICPacket.h | 3 +-- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 1e3ed1328c2..a76c69254bb 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -1005,22 +1005,11 @@ QUICPacketFactory::set_dcil(uint8_t len) // // QUICPacketNumberGenerator // -QUICPacketNumberGenerator::QUICPacketNumberGenerator() -{ - this->randomize(); -} - -QUICPacketNumber -QUICPacketNumberGenerator::randomize() -{ - std::random_device rnd; - this->_current = (rnd() & 0xFFFFFFFF) - 1024; - - return this->_current; -} +QUICPacketNumberGenerator::QUICPacketNumberGenerator() {} QUICPacketNumber QUICPacketNumberGenerator::next() { + // TODO Increment the number at least one but not only always one return this->_current++; } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index f54073d2b9f..5a76a85d7e7 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -333,11 +333,10 @@ class QUICPacketNumberGenerator { public: QUICPacketNumberGenerator(); - QUICPacketNumber randomize(); QUICPacketNumber next(); private: - std::atomic _current; + std::atomic _current = 0; }; using QUICPacketDeleterFunc = void (*)(QUICPacket *p); From bb89b2367a805507ae6060aaf34b229c87211c85 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 23 May 2018 14:17:18 +0900 Subject: [PATCH 0615/1313] Packet number for Retry packets is always 0 --- iocore/net/QUICNetVConnection.cc | 3 +-- iocore/net/quic/QUICPacket.cc | 11 ++++------- iocore/net/quic/QUICPacket.h | 4 ++-- iocore/net/quic/QUICPacketReceiveQueue.cc | 8 +------- iocore/net/quic/QUICPacketReceiveQueue.h | 1 - iocore/net/quic/test/test_QUICPacketFactory.cc | 4 ++-- 6 files changed, 10 insertions(+), 21 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 51e9d57b0f4..b9e3e409e16 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1396,8 +1396,7 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi break; case QUICPacketType::RETRY: // Echo "_largest_received_packet_number" as packet number. Probably this is the packet number from triggering client packet. - packet = this->_packet_factory.create_retry_packet(this->_peer_quic_connection_id, this->_quic_connection_id, - this->_packet_recv_queue.largest_received_packet_number(), std::move(buf), + packet = this->_packet_factory.create_retry_packet(this->_peer_quic_connection_id, this->_quic_connection_id, std::move(buf), len, retransmittable); break; case QUICPacketType::HANDSHAKE: diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index a76c69254bb..98b22b5a030 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -889,15 +889,12 @@ QUICPacketFactory::create_initial_packet(QUICConnectionId destination_cid, QUICC return this->_create_encrypted_packet(std::move(header), true); } -/* - * Unlike other create_*_packet, the 2nd argument is not base packet number. - */ QUICPacketUPtr -QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, - QUICPacketNumber packet_number, ats_unique_buf payload, size_t len, bool retransmittable) +QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, ats_unique_buf payload, + size_t len, bool retransmittable) { - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, destination_cid, source_cid, packet_number, 0, - this->_version, std::move(payload), len); + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::RETRY, destination_cid, source_cid, 0, 0, this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), retransmittable); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 5a76a85d7e7..0ef5cf3de7f 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -370,8 +370,8 @@ class QUICPacketFactory QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client); QUICPacketUPtr create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len); - QUICPacketUPtr create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber packet_number, - ats_unique_buf payload, size_t len, bool retransmittable); + QUICPacketUPtr create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, ats_unique_buf payload, + size_t len, bool retransmittable); QUICPacketUPtr create_handshake_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 1c30f3ac2d0..c742118a147 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -142,7 +142,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) this->_offset = 0; } - quic_packet = this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->largest_received_packet_number(), result); + quic_packet = this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->_largest_received_packet_number, result); if (udp_packet) { udp_packet->free(); @@ -174,12 +174,6 @@ QUICPacketReceiveQueue::size() return this->_queue.size; } -QUICPacketNumber -QUICPacketReceiveQueue::largest_received_packet_number() -{ - return this->_largest_received_packet_number; -} - void QUICPacketReceiveQueue::reset() { diff --git a/iocore/net/quic/QUICPacketReceiveQueue.h b/iocore/net/quic/QUICPacketReceiveQueue.h index 911c0cf72e9..6349d261b6b 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.h +++ b/iocore/net/quic/QUICPacketReceiveQueue.h @@ -36,7 +36,6 @@ class QUICPacketReceiveQueue void enqueue(UDPPacket *packet); QUICPacketUPtr dequeue(QUICPacketCreationResult &result); uint32_t size(); - QUICPacketNumber largest_received_packet_number(); void reset(); private: diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 35fc1e86ea7..0ebc38b6bf0 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -90,11 +90,11 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") QUICPacketUPtr packet = factory.create_retry_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), - 1234, std::move(payload), sizeof(raw), false); + std::move(payload), sizeof(raw), false); CHECK(packet->type() == QUICPacketType::RETRY); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); - CHECK(packet->packet_number() == 1234); + CHECK(packet->packet_number() == 0); CHECK(packet->version() == 0x11223344); } From 538e78f99d5ab61018f069feb4d4433084949338 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 23 May 2018 16:27:30 +0900 Subject: [PATCH 0616/1313] Packet number is encoded into the first 1-2 bits of the packet number itself Short Header doesn't have bits anymore. --- iocore/net/quic/QUICPacket.cc | 63 +++++-------------------- iocore/net/quic/QUICPacket.h | 4 +- iocore/net/quic/QUICTypes.cc | 38 +++++++++++++-- iocore/net/quic/QUICTypes.h | 11 +---- iocore/net/quic/test/test_QUICPacket.cc | 24 +++++----- 5 files changed, 62 insertions(+), 78 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 98b22b5a030..cc4082057d2 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -150,9 +150,10 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf } else { this->_payload_length = QUICIntUtil::read_QUICVariableInt(raw_buf + offset); offset += QUICVariableInt::size(raw_buf + offset); - QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset, 4), 4, + int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf + offset); + QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset), pn_len, this->_base_packet_number); - this->_payload_offset = offset + 4; + this->_payload_start = offset + pn_len; } } @@ -327,11 +328,11 @@ QUICPacketShortHeader::QUICPacketShortHeader(const IpEndpoint from, ats_unique_b { this->_connection_id = QUICTypeUtil::read_QUICConnectionId(this->_buf.get() + 1, dcil); - int n = this->_packet_number_len(); - int offset = 1 + this->_connection_id.length(); - QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + offset, n); - QUICPacket::decode_packet_number(this->_packet_number, src, n, this->_base_packet_number); - this->_payload_length = len - (1 + this->_dcil + this->_packet_number_len()); + int offset = 1 + this->_connection_id.length(); + this->_packet_number_len = QUICTypeUtil::read_QUICPacketNumberLen(this->_buf.get() + offset); + QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + offset); + QUICPacket::decode_packet_number(this->_packet_number, src, this->_packet_number_len, this->_base_packet_number); + this->_payload_length = len - (1 + this->_dcil + this->_packet_number_len); } QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, @@ -342,7 +343,7 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase k this->_key_phase = key_phase; this->_packet_number = packet_number; this->_base_packet_number = base_packet_number; - this->_packet_number_type = this->_discover_packet_number_type(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; } @@ -357,7 +358,7 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase k this->_connection_id = connection_id; this->_packet_number = packet_number; this->_base_packet_number = base_packet_number; - this->_packet_number_type = this->_discover_packet_number_type(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; } @@ -413,43 +414,6 @@ QUICPacketShortHeader::version() const return 0; } -int -QUICPacketShortHeader::_packet_number_len() const -{ - QUICPacketShortHeaderType type; - if (this->_buf) { - type = static_cast(this->_buf.get()[0] & 0x03); - } else { - type = this->_packet_number_type; - } - - switch (type) { - case QUICPacketShortHeaderType::ONE: - return 1; - case QUICPacketShortHeaderType::TWO: - return 2; - case QUICPacketShortHeaderType::THREE: - return 4; - default: - ink_assert(false); - return 0; - } -} - -QUICPacketShortHeaderType -QUICPacketShortHeader::_discover_packet_number_type(QUICPacketNumber packet_number, QUICPacketNumber base_packet_number) const -{ - uint64_t d = (packet_number - base_packet_number) * 2; - - if (d > 0xFFFF) { - return QUICPacketShortHeaderType::THREE; - } else if (d > 0xFF) { - return QUICPacketShortHeaderType::TWO; - } else { - return QUICPacketShortHeaderType::ONE; - } -} - const uint8_t * QUICPacketShortHeader::payload() const { @@ -488,7 +452,7 @@ QUICPacketShortHeader::size() const { uint16_t len = 1; len += this->_connection_id.length(); - len += this->_packet_number_len(); + len += this->_packet_number_len; return len; } @@ -503,13 +467,12 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const buf[0] += 0x40; } buf[0] += 0x30; - buf[0] += static_cast(this->_packet_number_type); *len += 1; QUICTypeUtil::write_QUICConnectionId(this->_connection_id, buf + *len, &n); *len += n; QUICPacketNumber dst = 0; - size_t dst_len = this->_packet_number_len(); + 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); @@ -640,8 +603,6 @@ QUICPacket::store(uint8_t *buf, size_t *len) const uint8_t QUICPacket::calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base) { - ink_assert(num > base); - uint64_t d = (num - base) * 2; uint8_t len = 0; diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 0ef5cf3de7f..febd398bee5 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -225,9 +225,7 @@ class QUICPacketShortHeader : public QUICPacketHeader void store(uint8_t *buf, size_t *len) const; private: - QUICPacketShortHeaderType _discover_packet_number_type(QUICPacketNumber packet_number, QUICPacketNumber base_packet_number) const; - int _packet_number_len() const; - QUICPacketShortHeaderType _packet_number_type = QUICPacketShortHeaderType::UNINITIALIZED; + int _packet_number_len; uint8_t _dcil; }; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index ecd4df67fb3..b84b5682f74 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -86,10 +86,32 @@ QUICTypeUtil::read_QUICConnectionId(const uint8_t *buf, uint8_t len) return {buf, len}; } +int +QUICTypeUtil::read_QUICPacketNumberLen(const uint8_t *buf) +{ + if (buf[0] & 0xC0) { + return 4; + } else if (buf[0] & 0x10) { + return 2; + } else { + return 1; + } +} + QUICPacketNumber -QUICTypeUtil::read_QUICPacketNumber(const uint8_t *buf, uint8_t len) +QUICTypeUtil::read_QUICPacketNumber(const uint8_t *buf) { - return static_cast(QUICIntUtil::read_nbytes_as_uint(buf, len)); + int encoded_length = QUICTypeUtil::read_QUICPacketNumberLen(buf); + uint64_t pn = QUICIntUtil::read_nbytes_as_uint(buf, encoded_length); + + // Remove length indicator + if (encoded_length == 1) { + pn &= 0x7F; + } else { + pn &= (0x3FFFFFFF >> ((4 - encoded_length) * 8)); + } + + return static_cast(pn); } QUICVersion @@ -138,7 +160,17 @@ QUICTypeUtil::write_QUICConnectionId(QUICConnectionId connection_id, uint8_t *bu void QUICTypeUtil::write_QUICPacketNumber(QUICPacketNumber packet_number, uint8_t n, uint8_t *buf, size_t *len) { - QUICIntUtil::write_uint_as_nbytes(static_cast(packet_number), n, buf, len); + uint64_t pn = static_cast(packet_number); + if (n == 1) { + // Do nothing + } else if (n == 2) { + pn |= 0x8000; + } else if (n == 4) { + pn |= 0xC0000000; + } else { + ink_assert(!"Encoded length must be 1, 2 or 4"); + } + QUICIntUtil::write_uint_as_nbytes(static_cast(pn), n, buf, len); } void diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index b17d1219216..54646f8ce89 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -77,14 +77,6 @@ enum class QUICPacketType : uint8_t { UNINITIALIZED = 0xFF, // Not on the spec. but just for convenience }; -// To detect length of Packet Number -enum class QUICPacketShortHeaderType : int { - ONE = 0x0, - TWO = 0x1, - THREE = 0x2, - UNINITIALIZED = 0x3, -}; - // XXX If you add or remove QUICFrameType, you might also need to change QUICFrame::type(const uint8_t *) enum class QUICFrameType : uint8_t { PADDING = 0x00, @@ -329,7 +321,8 @@ class QUICTypeUtil static QUICStreamType detect_stream_type(QUICStreamId id); static QUICConnectionId read_QUICConnectionId(const uint8_t *buf, uint8_t n); - static QUICPacketNumber read_QUICPacketNumber(const uint8_t *buf, uint8_t n); + static int read_QUICPacketNumberLen(const uint8_t *buf); + static QUICPacketNumber read_QUICPacketNumber(const uint8_t *buf); static QUICVersion read_QUICVersion(const uint8_t *buf); static QUICStreamId read_QUICStreamId(const uint8_t *buf); static QUICOffset read_QUICOffset(const uint8_t *buf); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 0d5c8303f29..dbd30d9cb94 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -60,7 +60,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID 0x02, // Payload length - 0x12, 0x34, 0x56, 0x78, // Packet number + 0xC1, 0x23, 0x45, 0x67, // Packet number 0xff, 0xff, // Payload (dummy) }; @@ -71,7 +71,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") CHECK( (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); CHECK((header->source_cid() == QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8))); - CHECK(header->packet_number() == 0x12345678); + CHECK(header->packet_number() == 0x01234567); CHECK(header->has_version() == true); CHECK(header->version() == 0x11223344); CHECK(header->has_key_phase() == false); @@ -89,7 +89,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID 0x15, // Payload length (Not 0x05 because it will have 16 bytes of AEAD tag) - 0x12, 0x34, 0x56, 0x78, // Packet number + 0xC1, 0x23, 0x45, 0x67, // Packet number 0x11, 0x22, 0x33, 0x44, 0x55, // Payload (dummy) }; ats_unique_buf payload = ats_unique_malloc(5); @@ -97,7 +97,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") QUICPacketHeaderUPtr header = QUICPacketHeader::build( QUICPacketType::INITIAL, {reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, - {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x12345678, 0, 0x11223344, std::move(payload), 5); + {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x01234567, 0, 0x11223344, std::move(payload), 5); CHECK(header->size() == 27); CHECK(header->has_key_phase() == false); @@ -106,7 +106,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") CHECK( (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); CHECK((header->source_cid() == QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8))); - CHECK(header->packet_number() == 0x12345678); + CHECK(header->packet_number() == 0x01234567); CHECK(header->has_version() == true); CHECK(header->version() == 0x11223344); @@ -121,9 +121,9 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") SECTION("Short Header (load)") { const uint8_t input[] = { - 0x32, // Short header with (K=0, Type=0x2) + 0x30, // Short header with (K=0) 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID - 0x12, 0x34, 0x56, 0x78, // Packet number + 0xC1, 0x23, 0x45, 0x67, // Packet number 0xff, 0xff, // Payload (dummy) }; @@ -134,7 +134,7 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") CHECK(header->key_phase() == QUICKeyPhase::PHASE_0); CHECK( (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); - CHECK(header->packet_number() == 0x12345678); + CHECK(header->packet_number() == 0x01234567); CHECK(header->has_version() == false); } @@ -144,9 +144,9 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") size_t len = 0; const uint8_t expected[] = { - 0x32, // Short header with (C=0, K=0, Type=0x2) + 0x30, // Short header with (K=0) 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID - 0x12, 0x34, 0x56, 0x78, // Packet number + 0xC1, 0x23, 0x45, 0x67, // Packet number 0x11, 0x22, 0x33, 0x44, 0x55, // Protected Payload }; @@ -154,7 +154,7 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") memcpy(payload.get(), expected + 13, 5); QUICPacketHeaderUPtr header = QUICPacketHeader::build( QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, {reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, - 0x12345678, 0, std::move(payload), 32); + 0x01234567, 0, std::move(payload), 32); CHECK(header->size() == 13); CHECK(header->packet_size() == 0); CHECK(header->has_key_phase() == true); @@ -162,7 +162,7 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") CHECK(header->type() == QUICPacketType::PROTECTED); CHECK( (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); - CHECK(header->packet_number() == 0x12345678); + CHECK(header->packet_number() == 0x01234567); CHECK(header->has_version() == false); header->store(buf, &len); From 42b69b76558631b2b344c28b4a0730dcdaec3a16 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 23 May 2018 16:59:48 +0900 Subject: [PATCH 0617/1313] Packet number gap for connection migration is gone --- iocore/net/QUICNetVConnection.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b9e3e409e16..a6f49e8a8e3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -986,8 +986,7 @@ QUICNetVConnection::_state_common_receive_packet() if (this->_alt_con_manager->migrate_to(p->destination_cid(), this->_reset_token)) { // Migrate connection // TODO Address Validation - // TODO Adjust expected packet number with a gap computed based on info.seq_num - this->_update_local_cid(p->destination_cid()); + this->_quic_connection_id = p->destination_cid(); Connection con; con.setRemote(&p->from().sa); this->con.move(con); From c345ed74d0bca99a60ae5820103d6095047750b5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 25 May 2018 10:05:02 +0900 Subject: [PATCH 0618/1313] Generate a key for packet number protection --- iocore/net/quic/QUICKeyGenerator.cc | 24 +++++++++++++++++------- iocore/net/quic/QUICKeyGenerator.h | 6 ++++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 701b0325761..cf2b9979d3c 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -38,6 +38,7 @@ constexpr static std::string_view LABEL_FOR_CLIENT_PP_SECRET("EXPORTER-QUIC clie constexpr static std::string_view LABEL_FOR_SERVER_PP_SECRET("EXPORTER-QUIC server 1rtt"sv); constexpr static std::string_view LABEL_FOR_KEY("key"sv); constexpr static std::string_view LABEL_FOR_IV("iv"sv); +constexpr static std::string_view LABEL_FOR_PN("pn"sv); std::unique_ptr QUICKeyGenerator::generate(QUICConnectionId cid) @@ -61,7 +62,7 @@ QUICKeyGenerator::generate(QUICConnectionId cid) break; } - this->_generate(km->key, &km->key_len, km->iv, &km->iv_len, hkdf, secret, secret_len, cipher); + this->_generate(*km, hkdf, secret, secret_len, cipher); return km; } @@ -78,7 +79,7 @@ QUICKeyGenerator::generate_0rtt(SSL *ssl) QUICHKDF hkdf(md); this->_generate_0rtt_secret(secret, &secret_len, hkdf, ssl, EVP_MD_size(md)); - this->_generate(km->key, &km->key_len, km->iv, &km->iv_len, hkdf, secret, secret_len, cipher); + this->_generate(*km, hkdf, secret, secret_len, cipher); return km; } @@ -105,20 +106,22 @@ QUICKeyGenerator::generate(SSL *ssl) break; } - this->_generate(km->key, &km->key_len, km->iv, &km->iv_len, hkdf, secret, secret_len, cipher); + this->_generate(*km, hkdf, secret, secret_len, cipher); return km; } int -QUICKeyGenerator::_generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, QUICHKDF &hkdf, const uint8_t *secret, - size_t secret_len, const QUIC_EVP_CIPHER *cipher) +QUICKeyGenerator::_generate(KeyMaterial &km, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, + const QUIC_EVP_CIPHER *cipher) { // Generate a key and a IV // key = QHKDF-Expand(S, "key", "", key_length) // iv = QHKDF-Expand(S, "iv", "", iv_length) - this->_generate_key(key, key_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); - this->_generate_iv(iv, iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher)); + // pn_key = QHKDF-Expand(S, "pn", pn_key_length) + this->_generate_key(km.key, &km.key_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); + this->_generate_iv(km.iv, &km.iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher)); + this->_generate_pn(km.pn, &km.pn_len, hkdf, secret, secret_len, 12); return 0; } @@ -187,3 +190,10 @@ QUICKeyGenerator::_generate_iv(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, co { return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_IV.data(), LABEL_FOR_IV.length(), iv_length); } + +int +QUICKeyGenerator::_generate_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, + size_t pn_length) const +{ + return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_PN.data(), LABEL_FOR_PN.length(), pn_length); +} diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index 0779a915c74..235eab4f474 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -38,8 +38,10 @@ struct KeyMaterial { // uint8_t iv[EVP_MAX_IV_LENGTH] = {0}; uint8_t key[512] = {0}; uint8_t iv[512] = {0}; + uint8_t pn[512] = {0}; size_t key_len = 512; size_t iv_len = 512; + size_t pn_len = 512; }; class QUICKeyGenerator @@ -70,8 +72,7 @@ class QUICKeyGenerator uint8_t _last_secret[256]; size_t _last_secret_len = 0; - int _generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, QUICHKDF &hkdf, const uint8_t *secret, - size_t secret_len, const QUIC_EVP_CIPHER *cipher); + int _generate(KeyMaterial &km, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher); int _generate_cleartext_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid, const char *label, size_t label_len, size_t length); int _generate_pp_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, SSL *ssl, const char *label, size_t label_len, @@ -80,6 +81,7 @@ class QUICKeyGenerator 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_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t pn_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_cleartext() const; From 8d6359a243896c6d60cfdc512cfbdc3d15b45ae6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 8 Jun 2018 11:55:52 +0900 Subject: [PATCH 0619/1313] Fix build error --- iocore/net/quic/QUICPacket.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index cc4082057d2..373de9be5c6 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -153,7 +153,7 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf + offset); QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset), pn_len, this->_base_packet_number); - this->_payload_start = offset + pn_len; + this->_payload_offset = offset + pn_len; } } From 3f549f468bff0906230b47395c05eb7a2d8b8beb Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 8 Jun 2018 11:57:04 +0900 Subject: [PATCH 0620/1313] Add aead_tag_len in long packet header size calculation --- iocore/net/quic/QUICPacket.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 373de9be5c6..247e6cd0638 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -27,7 +27,8 @@ #include "QUICPacket.h" #include "QUICDebugNames.h" -static constexpr std::string_view tag = "quic_packet"sv; +static constexpr std::string_view tag = "quic_packet"sv; +static constexpr uint64_t aead_tag_len = 16; #define QUICDebug(dcid, scid, fmt, ...) \ Debug(tag.data(), "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__); @@ -176,7 +177,7 @@ QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICConnectionId LONG_HDR_OFFSET_CONNECTION_ID + this->_destination_cid.length() + this->_source_cid.length() + this->_payload_length; } else { this->_buf_len = LONG_HDR_OFFSET_CONNECTION_ID + this->_destination_cid.length() + this->_source_cid.length() + - QUICVariableInt::size(this->_payload_length) + 4 + this->_payload_length; + QUICVariableInt::size(this->_payload_length + aead_tag_len) + 4 + this->_payload_length; } } @@ -307,7 +308,7 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const *len += n; if (this->_type != QUICPacketType::VERSION_NEGOTIATION) { - QUICIntUtil::write_QUICVariableInt(this->_payload_length + 16, buf + *len, &n); + QUICIntUtil::write_QUICVariableInt(this->_payload_length + aead_tag_len, buf + *len, &n); *len += n; QUICPacketNumber dst = 0; From 02e9022fbd41df5ac365a3e10528b87c0bd7b50a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 8 Jun 2018 14:28:21 +0900 Subject: [PATCH 0621/1313] Fix unit tests --- iocore/net/quic/Mock.h | 27 +++ .../net/quic/test/test_QUICFrameDispatcher.cc | 2 +- iocore/net/quic/test/test_QUICStreamState.cc | 157 +++++++----------- 3 files changed, 84 insertions(+), 102 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index a798a342265..7715dfab0f1 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -597,3 +597,30 @@ class MockQUICRTTProvider : public QUICRTTProvider return HRTIME_MSECONDS(1); } }; + +class MockQUICTransferProgressProvider : public QUICTransferProgressProvider +{ + bool + is_transfer_goal_set() const override + { + return false; + } + + bool + is_transfer_complete() const override + { + return false; + } + + uint64_t + transfer_progress() const override + { + return 0; + } + + uint64_t + transfer_goal() const override + { + return 0; + } +}; diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index e1cbddfbf84..8be50c29666 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -42,7 +42,7 @@ TEST_CASE("QUICFrameHandler", "[quic]") auto cc = new MockQUICCongestionController(info); auto lossDetector = new MockQUICLossDetector(tx, info, cc); - QUICFrameDispatcher quicFrameDispatcher; + QUICFrameDispatcher quicFrameDispatcher(info); quicFrameDispatcher.add_handler(connection); quicFrameDispatcher.add_handler(streamManager); quicFrameDispatcher.add_handler(lossDetector); diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index c124a70b11a..875072a6539 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -27,118 +27,73 @@ #include "quic/QUICFrame.h" #include "quic/QUICStreamState.h" +#include "quic/Mock.h" -TEST_CASE("QUICStreamState_Idle", "[quic]") -{ - auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); - auto max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(0, 0); - auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0, 0); - - // Case1. Send STREAM - QUICStreamState ss1; - ss1.update_with_sent_frame(*stream_frame); - CHECK(ss1.get() == QUICStreamState::State::open); - - // Case2. Send RST_STREAM - QUICStreamState ss2; - ss2.update_with_sent_frame(*rst_stream_frame); - CHECK(ss2.get() == QUICStreamState::State::half_closed_local); - - // Case3. Recv STREAM - QUICStreamState ss3; - ss3.update_with_received_frame(*stream_frame); - CHECK(ss3.get() == QUICStreamState::State::open); - - // Case4. Recv RST_STREAM - QUICStreamState ss4; - ss4.update_with_received_frame(*rst_stream_frame); - CHECK(ss4.get() == QUICStreamState::State::half_closed_remote); - - // Case5. Recv MAX_STREAM_DATA - QUICStreamState ss5; - ss5.update_with_received_frame(*max_stream_data_frame); - CHECK(ss5.get() == QUICStreamState::State::open); - - // Case6. Recv STREAM_BLOCKED - QUICStreamState ss6; - ss6.update_with_received_frame(*stream_blocked_frame); - CHECK(ss6.get() == QUICStreamState::State::open); -} - -TEST_CASE("QUICStreamState_Open", "[quic]") -{ - auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); - auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); - - // Case1. Send FIN in a STREAM - QUICStreamState ss1; - ss1.update_with_sent_frame(*stream_frame); // OPEN - CHECK(ss1.get() == QUICStreamState::State::open); - ss1.update_with_sent_frame(*stream_frame_with_fin); - CHECK(ss1.get() == QUICStreamState::State::half_closed_local); - - // Case2. Send RST_STREAM - QUICStreamState ss2; - ss2.update_with_sent_frame(*stream_frame); // OPEN - CHECK(ss2.get() == QUICStreamState::State::open); - ss2.update_with_sent_frame(*rst_stream_frame); - CHECK(ss2.get() == QUICStreamState::State::half_closed_local); - - // Case3. Recv FIN in a STREAM - QUICStreamState ss3; - ss3.update_with_received_frame(*stream_frame); // OPEN - CHECK(ss3.get() == QUICStreamState::State::open); - ss3.update_with_received_frame(*stream_frame_with_fin); - CHECK(ss3.get() == QUICStreamState::State::half_closed_remote); - - // Case4. Recv RST_STREAM - QUICStreamState ss4; - ss4.update_with_received_frame(*stream_frame); // OPEN - CHECK(ss4.get() == QUICStreamState::State::open); - ss4.update_with_received_frame(*rst_stream_frame); - CHECK(ss4.get() == QUICStreamState::State::half_closed_remote); -} - -TEST_CASE("QUICStreamState_Half_Closed_Remote", "[quic]") +TEST_CASE("QUICSendStreamState", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); + auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0, 0); - // Case1. Send FIN in a STREAM - QUICStreamState ss1; - ss1.update_with_received_frame(*stream_frame_with_fin); // HALF CLOSED REMOTE - CHECK(ss1.get() == QUICStreamState::State::half_closed_remote); - ss1.update_with_sent_frame(*stream_frame_with_fin); - CHECK(ss1.get() == QUICStreamState::State::closed); - - // Case2. Send RST - QUICStreamState ss2; - ss2.update_with_received_frame(*stream_frame_with_fin); // HALF CLOSED REMOTE - CHECK(ss2.get() == QUICStreamState::State::half_closed_remote); - ss2.update_with_sent_frame(*rst_stream_frame); - CHECK(ss2.get() == QUICStreamState::State::closed); + SECTION("_Init") + { + // Case1. Create Stream (Sending) + QUICSendStreamState ss1(nullptr, nullptr); + CHECK(ss1.get() == QUICStreamState::State::Ready); + + // Case2. Send STREAM + QUICSendStreamState ss2(nullptr, nullptr); + ss2.update_with_sending_frame(*stream_frame); + CHECK(ss2.get() == QUICStreamState::State::Send); + + // Case3. Send RST_STREAM + QUICSendStreamState ss3(nullptr, nullptr); + ss3.update_with_sending_frame(*rst_stream_frame); + CHECK(ss3.get() == QUICStreamState::State::ResetSent); + + // Case4. Send FIN in a STREAM + QUICSendStreamState ss4(nullptr, nullptr); + ss4.update_with_sending_frame(*stream_frame_with_fin); + CHECK(ss4.get() == QUICStreamState::State::DataSent); + } } -TEST_CASE("QUICStreamState_Half_Closed_Local", "[quic]") +TEST_CASE("QUICReceiveStreamState", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); + auto max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(0, 0); + auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0, 0); - // Case1. Recv FIN in a STREAM - QUICStreamState ss1; - ss1.update_with_sent_frame(*stream_frame_with_fin); // HALF CLOSED LOCAL - CHECK(ss1.get() == QUICStreamState::State::half_closed_local); - ss1.update_with_received_frame(*stream_frame_with_fin); - CHECK(ss1.get() == QUICStreamState::State::closed); - - // Case2. Recv RST - QUICStreamState ss2; - ss2.update_with_sent_frame(*stream_frame_with_fin); // HALF CLOSED LOCAL - CHECK(ss2.get() == QUICStreamState::State::half_closed_local); - ss2.update_with_received_frame(*rst_stream_frame); - CHECK(ss2.get() == QUICStreamState::State::closed); + SECTION("_Init") + { + MockQUICTransferProgressProvider in_progress; + + // Case1. Recv STREAM + QUICReceiveStreamState ss1(&in_progress, nullptr); + ss1.update_with_receiving_frame(*stream_frame); + CHECK(ss1.get() == QUICStreamState::State::Recv); + + // Case2. Recv STREAM_BLOCKED + QUICReceiveStreamState ss2(&in_progress, nullptr); + ss2.update_with_receiving_frame(*stream_blocked_frame); + CHECK(ss2.get() == QUICStreamState::State::Recv); + + // Case3. Recv RST_STREAM + QUICReceiveStreamState ss3(&in_progress, nullptr); + ss3.update_with_receiving_frame(*rst_stream_frame); + CHECK(ss3.get() == QUICStreamState::State::ResetRecvd); + + // Case4. Recv MAX_STREAM_DATA + QUICReceiveStreamState ss4(&in_progress, nullptr); + ss4.update_with_receiving_frame(*max_stream_data_frame); + CHECK(ss4.get() == QUICStreamState::State::Recv); + + // Case5. Recv FIN in a STREAM + QUICReceiveStreamState ss5(&in_progress, nullptr); + ss5.update_with_receiving_frame(*stream_frame_with_fin); + CHECK(ss5.get() == QUICStreamState::State::SizeKnown); + } } From 43908f1799b291224f2410005f93384b71c91209 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 8 Jun 2018 15:44:27 +0900 Subject: [PATCH 0622/1313] More format debug log --- cmd/traffic_quic/quic_client.cc | 3 ++- iocore/net/QUICNetVConnection.cc | 6 +++--- iocore/net/quic/QUICApplication.cc | 19 +++++++++++++++---- iocore/net/quic/QUICStream.cc | 6 ++++++ iocore/net/quic/QUICStream.h | 1 + iocore/net/quic/QUICTLS.cc | 4 ++-- proxy/hq/HQClientTransaction.cc | 15 +++++++++------ 7 files changed, 38 insertions(+), 16 deletions(-) diff --git a/cmd/traffic_quic/quic_client.cc b/cmd/traffic_quic/quic_client.cc index d01bd0987e3..119b9c33bb9 100644 --- a/cmd/traffic_quic/quic_client.cc +++ b/cmd/traffic_quic/quic_client.cc @@ -113,6 +113,7 @@ QUICClient::state_http_server_open(int event, void *data) // QUICClientApp // #define QUICClientAppDebug(fmt, ...) Debug("quic_client_app", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) +#define QUICClientAppVDebug(fmt, ...) Debug("v_quic_client_app", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) QUICClientApp::QUICClientApp(QUICNetVConnection *qvc, const char *filename) : QUICApplication(qvc), _filename(filename) { @@ -153,7 +154,7 @@ QUICClientApp::start(const char *path) int QUICClientApp::main_event_handler(int event, Event *data) { - QUICClientAppDebug("%s (%d)", get_vc_event_name(event), event); + QUICClientAppVDebug("%s (%d)", get_vc_event_name(event), event); VIO *vio = reinterpret_cast(data); QUICStreamIO *stream_io = this->_find_stream_io(vio); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a6f49e8a8e3..b7d53b35c8b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -420,7 +420,7 @@ QUICNetVConnection::_transmit_packet(QUICPacketUPtr packet) SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); if (packet) { - QUICConDebug("Enqueue %s pkt_num=%" PRIu64 " size=%hu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), + QUICConDebug("Enqueue %s packet #%" PRIu64 " size=%hu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), packet->size()); // TODO Remove const_cast this->_packet_send_queue.enqueue(const_cast(packet.release())); @@ -439,7 +439,7 @@ QUICNetVConnection::transmit_packet(QUICPacketUPtr packet) void QUICNetVConnection::retransmit_packet(const QUICPacket &packet) { - QUICConDebug("Retransmit packet #%" PRIu64 " type %s", packet.packet_number(), QUICDebugNames::packet_type(packet.type())); + QUICConDebug("Retransmit %s packet #%" PRIu64, QUICDebugNames::packet_type(packet.type()), packet.packet_number()); this->_packet_retransmitter.retransmit_packet(packet); } @@ -1510,7 +1510,7 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) if (packet->type() == QUICPacketType::VERSION_NEGOTIATION) { QUICConDebug("Dequeue %s size=%u", QUICDebugNames::packet_type(packet->type()), packet->size()); } else { - QUICConDebug("Dequeue %s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), + QUICConDebug("Dequeue %s packet #%" PRIu64 " size=%u", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), packet->size()); } break; diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 4a960d5b204..46863985719 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -24,7 +24,11 @@ #include "QUICApplication.h" #include "QUICStream.h" -static constexpr char tag[] = "quic_app"; +static constexpr char tag_stream_io[] = "quic_stream_io"; +static constexpr char tag_app[] = "quic_app"; + +#define QUICStreamIODebug(fmt, ...) \ + Debug(tag_stream_io, "[%s] [%" PRIu64 "] " fmt, this->_stream->info()->cids().data(), this->_stream->id(), ##__VA_ARGS__) // // QUICStreamIO @@ -57,6 +61,11 @@ QUICStreamIO::stream_id() const int64_t QUICStreamIO::read(uint8_t *buf, int64_t len) { + if (is_debug_tag_set(tag_stream_io)) { + QUICStreamIODebug("nbytes=%" PRId64 " ndone=%" PRId64 " read_avail=%" PRId64 " read_len=%" PRId64, this->_read_vio->nbytes, + this->_read_vio->ndone, this->_read_buffer_reader->read_avail(), len); + } + int64_t nread = this->_read_buffer_reader->read(const_cast(buf), len); if (nread > 0) { this->_read_vio->ndone += nread; @@ -92,8 +101,10 @@ QUICStreamIO::write(IOBufferReader *r, int64_t len) int64_t bytes_avail = this->_write_buffer->write_avail(); if (bytes_avail > 0) { - Debug(tag, "nbytes=%" PRId64 " ndone=%" PRId64 " write_avail=%" PRId64 " write_len=%" PRId64, this->_write_vio->nbytes, - this->_write_vio->ndone, bytes_avail, len); + if (is_debug_tag_set(tag_stream_io)) { + QUICStreamIODebug("nbytes=%" PRId64 " ndone=%" PRId64 " write_avail=%" PRId64 " write_len=%" PRId64, this->_write_vio->nbytes, + this->_write_vio->ndone, bytes_avail, len); + } int64_t bytes_len = std::min(bytes_avail, len); int64_t nwritten = this->_write_buffer->write(r, bytes_len); @@ -199,7 +210,7 @@ QUICApplication::reenable(QUICStream *stream) stream_io->read_reenable(); stream_io->write_reenable(); } else { - Debug(tag, "[%s] Unknown Stream id=%" PRIx64, this->_qc->cids().data(), stream->id()); + Debug(tag_app, "[%s] Unknown Stream id=%" PRIx64, this->_qc->cids().data(), stream->id()); } return; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index ed3a0112a16..c7f6e13be16 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -87,6 +87,12 @@ QUICStream::id() const return this->_id; } +const QUICConnectionInfoProvider * +QUICStream::info() const +{ + return this->_info; +} + QUICOffset QUICStream::final_offset() const { diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 8cfd394e1df..1d880091881 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -65,6 +65,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator void init_flow_control_params(uint64_t recv_max_stream_data, uint64_t send_max_stream_data); QUICStreamId id() const; + const QUICConnectionInfoProvider *info() const; QUICOffset final_offset() const; void reset_send_offset(); void reset_recv_offset(); diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index d6b49cf9b40..08cccf02c2c 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -334,7 +334,7 @@ QUICTLS::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, con bool ret = _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, *km, aead, tag_len); if (!ret) { - Debug(tag, "Failed to encrypt a packet: pkt_num=%" PRIu64, pkt_num); + Debug(tag, "Failed to encrypt a packet #%" PRIu64, pkt_num); } return ret; } @@ -368,7 +368,7 @@ QUICTLS::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const const QUIC_EVP_CIPHER *aead = this->_get_evp_aead(phase); bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, *km, aead, tag_len); if (!ret) { - Debug(tag, "Failed to decrypt a packet: pkt_num=%" PRIu64, pkt_num); + Debug(tag, "Failed to decrypt a packet #%" PRIu64, pkt_num); } return ret; } diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 455f64536c2..0d49914f47c 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -37,6 +37,11 @@ static_cast(reinterpret_cast(this->parent->get_netvc()))->cids().data(), \ this->get_transaction_id(), ##__VA_ARGS__) +#define HQTransVDebug(fmt, ...) \ + Debug("v_hq_trans", "[%s] [%" PRIx32 "] " fmt, \ + static_cast(reinterpret_cast(this->parent->get_netvc()))->cids().data(), \ + this->get_transaction_id(), ##__VA_ARGS__) + // static void // dump_io_buffer(IOBufferReader *reader) // { @@ -119,7 +124,7 @@ int HQClientTransaction::state_stream_open(int event, void *edata) { // TODO: should check recursive call? - HQTransDebug("%s (%d)", get_vc_event_name(event), event); + HQTransVDebug("%s (%d)", get_vc_event_name(event), event); if (this->_thread != this_ethread()) { // Send on to the owning thread @@ -176,7 +181,7 @@ HQClientTransaction::state_stream_open(int event, void *edata) int HQClientTransaction::state_stream_closed(int event, void *data) { - HQTransDebug("%s (%d)", get_vc_event_name(event), event); + HQTransVDebug("%s (%d)", get_vc_event_name(event), event); switch (event) { case VC_EVENT_READ_READY: @@ -358,7 +363,7 @@ HQClientTransaction::_signal_read_event() this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio); } - HQTransDebug("%s (%d)", get_vc_event_name(event), event); + HQTransVDebug("%s (%d)", get_vc_event_name(event), event); } /** @@ -379,7 +384,7 @@ HQClientTransaction::_signal_write_event() this_ethread()->schedule_imm(this->_write_vio.cont, event, &this->_write_vio); } - HQTransDebug("%s (%d)", get_vc_event_name(event), event); + HQTransVDebug("%s (%d)", get_vc_event_name(event), event); } // Convert HTTP/0.9 to HTTP/1.1 @@ -499,8 +504,6 @@ HQClientTransaction::_process_write_vio() int64_t bytes_avail = reader->read_avail(); int64_t total_written = 0; - HQTransDebug("%" PRId64, bytes_avail); - while (total_written < bytes_avail) { int64_t data_len = reader->block_read_avail(); int64_t bytes_written = this->_stream_io->write(reader, data_len); From 648b7cd1073e8a0556d1f2dd98ce5650befde1dd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 8 Jun 2018 16:12:52 +0900 Subject: [PATCH 0623/1313] Fix unit tests --- iocore/net/quic/Mock.h | 7 +++++++ iocore/net/quic/test/test_QUICHandshake.cc | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 7715dfab0f1..fad20eb8b70 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -480,6 +480,13 @@ class MockQUICApplication : public QUICApplication class MockQUICStream : public QUICStream { +public: + MockQUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICStreamId sid, uint64_t recv_max_stream_data, + uint64_t send_max_stream_data) + : QUICStream(rtt_provider, info, sid, recv_max_stream_data, send_max_stream_data) + { + } + private: int64_t _process_read_vio() override diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc index 410bb505898..f55cdb95b9a 100644 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -61,7 +61,9 @@ TEST_CASE("1-RTT handshake ", "[quic]") QUICHandshake *server = new QUICHandshake(server_qc, server_ssl_ctx, server_token, false); // setup stream 0 - QUICStream *stream = new MockQUICStream(); + MockQUICRTTProvider rtt; + MockQUICConnectionInfoProvider info; + QUICStream *stream = new MockQUICStream(&rtt, &info, STREAM_ID_FOR_HANDSHAKE, UINT64_MAX, UINT64_MAX); MockQUICStreamIO *stream_io = new MockQUICStreamIO(nullptr, stream); client->set_stream(stream, stream_io); From dbdd3d29115d11d474c3d18c2474c0cd530b5a24 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Jun 2018 10:25:30 +0900 Subject: [PATCH 0624/1313] Check version in QUICPacketHandlerIn --- .gitignore | 1 + iocore/net/P_QUICPacketHandler.h | 2 - iocore/net/QUICPacketHandler.cc | 136 +++++++++------- iocore/net/quic/QUICConfig.h | 2 + iocore/net/quic/QUICHandshake.cc | 3 +- iocore/net/quic/QUICPacket.cc | 10 +- iocore/net/quic/QUICPacket.h | 10 +- iocore/net/quic/QUICTypes.cc | 96 +++++++++++- iocore/net/quic/QUICTypes.h | 21 ++- iocore/net/quic/test/Makefile.am | 17 ++ iocore/net/quic/test/test_QUICInvariants.cc | 147 ++++++++++++++++++ .../net/quic/test/test_QUICPacketFactory.cc | 30 +--- .../quic/test/test_QUICVersionNegotiator.cc | 3 +- 13 files changed, 385 insertions(+), 93 deletions(-) create mode 100644 iocore/net/quic/test/test_QUICInvariants.cc diff --git a/.gitignore b/.gitignore index 5514f1c48a6..2f586944c0f 100644 --- a/.gitignore +++ b/.gitignore @@ -99,6 +99,7 @@ iocore/net/quic/test/test_QUICFrameDispatcher iocore/net/quic/test/test_QUICLossDetector iocore/net/quic/test/test_QUICHandshake iocore/net/quic/test/test_QUICIncomingFrameBuffer +iocore/net/quic/test/test_QUICInvariants iocore/net/quic/test/test_QUICKeyGenerator iocore/net/quic/test/test_QUICPacket iocore/net/quic/test/test_QUICPacketFactory diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index dd7067d2e53..3e982bc891f 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -44,8 +44,6 @@ class QUICPacketHandler protected: static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu); - static QUICConnectionId _read_destination_connection_id(IOBufferBlock *block); - static QUICConnectionId _read_source_connection_id(IOBufferBlock *block); Event *_collector_event = nullptr; QUICClosedConCollector *_closed_con_collector = nullptr; diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 732a1aef4bd..a596c35bf2e 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -30,11 +30,13 @@ #include "QUICDebugNames.h" #include "QUICEvents.h" -#define QUICDebugQC(qc, fmt, ...) Debug("quic_sec", "[%s] " fmt, qc->cids().data(), ##__VA_ARGS__) +static constexpr char tag[] = "quic_sec"; + +#define QUICDebug(fmt, ...) Debug(tag, fmt, ##__VA_ARGS__) +#define QUICDebugQC(qc, fmt, ...) Debug(tag, "[%s] " fmt, qc->cids().data(), ##__VA_ARGS__) // ["local dcid" - "local scid"] -#define QUICDebugDS(dcid, scid, fmt, ...) \ - Debug("quic_sec", "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__) +#define QUICDebugDS(dcid, scid, fmt, ...) Debug(tag, "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__) // // QUICPacketHandler @@ -78,33 +80,21 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo UDPPacket *udp_packet = new_UDPPacket(addr, 0, udp_payload); - // NOTE: p will be enqueued to udpOutQueue of UDPNetHandler - ip_port_text_buffer ipb; - QUICConnectionId dcid = packet.destination_cid(); - QUICConnectionId scid = QUICConnectionId::ZERO(); - if (packet.type() != QUICPacketType::PROTECTED) { - scid = packet.source_cid(); + if (is_debug_tag_set(tag)) { + ip_port_text_buffer ipb; + QUICConnectionId dcid = packet.destination_cid(); + QUICConnectionId scid = QUICConnectionId::ZERO(); + if (packet.type() != QUICPacketType::PROTECTED) { + scid = packet.source_cid(); + } + QUICDebugDS(dcid, scid, "send %s packet to %s size=%" PRId64, QUICDebugNames::packet_type(packet.type()), + ats_ip_nptop(&udp_packet->to.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); } - QUICDebugDS(dcid, scid, "send %s packet to %s size=%" PRId64, QUICDebugNames::packet_type(packet.type()), - ats_ip_nptop(&udp_packet->to.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); + // NOTE: packet will be enqueued to udpOutQueue of UDPNetHandler udp_con->send(c, udp_packet); } -QUICConnectionId -QUICPacketHandler::_read_destination_connection_id(IOBufferBlock *block) -{ - const uint8_t *buf = reinterpret_cast(block->buf()); - return QUICPacket::destination_connection_id(buf); -} - -QUICConnectionId -QUICPacketHandler::_read_source_connection_id(IOBufferBlock *block) -{ - const uint8_t *buf = reinterpret_cast(block->buf()); - return QUICPacket::source_connection_id(buf); -} - // // QUICPacketHandlerIn // @@ -182,54 +172,91 @@ QUICPacketHandlerIn::init_accept(EThread *t = nullptr) void QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) { - EThread *eth = nullptr; - QUICPollEvent *qe = nullptr; - QUICNetVConnection *vc = nullptr; - IOBufferBlock *block = udp_packet->getIOBlockChain(); + // Assumption: udp_packet has only one IOBufferBlock + IOBufferBlock *block = udp_packet->getIOBlockChain(); + const uint8_t *buf = reinterpret_cast(block->buf()); + uint64_t buf_len = block->size(); - if (is_debug_tag_set("quic_sec")) { - ip_port_text_buffer ipb; - QUICConnectionId dcid = this->_read_destination_connection_id(block); - QUICConnectionId scid = QUICConnectionId::ZERO(); - if (QUICTypeUtil::has_long_header(reinterpret_cast(block->buf()))) { - scid = this->_read_source_connection_id(block); + if (buf_len == 0) { + QUICDebug("Ignore packet - payload is too small"); + udp_packet->free(); + return; + } + + QUICConnectionId dcid = QUICConnectionId::ZERO(); + QUICConnectionId scid = QUICConnectionId::ZERO(); + + // TODO: lookup by 5-Tuple + // When ATS omits SCID, endpoint omits DCID. In this case, we can't get DCID from SH packet, we need to lookup QC by 5-Tuple. + if (!QUICInvariants::dcid(dcid, buf, buf_len)) { + QUICDebug("Ignore packet - payload is too small"); + udp_packet->free(); + return; + } + + if (QUICInvariants::is_long_header(buf)) { + if (!QUICInvariants::scid(scid, buf, buf_len)) { + QUICDebug("Ignore packet - payload is too small"); + udp_packet->free(); + return; + } + + if (is_debug_tag_set(tag)) { + ip_port_text_buffer ipb; + QUICDebugDS(scid, dcid, "recv LH packet from %s size=%" PRId64, ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), + udp_packet->getPktLength()); + } + + QUICVersion v; + if (unlikely(!QUICInvariants::version(v, buf, buf_len))) { + QUICDebug("Ignore packet - payload is too small"); + udp_packet->free(); + return; + } + + if (!QUICInvariants::is_version_negotiation(v) && !QUICTypeUtil::is_supported_version(v)) { + QUICDebugDS(scid, dcid, "Unsupported version: 0x%x", v); + + QUICPacketUPtr vn = QUICPacketFactory::create_version_negotiation_packet(scid, dcid); + this->_send_packet(this, *vn, udp_packet->getConnection(), udp_packet->from, 1200); + udp_packet->free(); + return; + } + } else { + if (is_debug_tag_set(tag)) { + ip_port_text_buffer ipb; + QUICDebugDS(scid, dcid, "recv SH packet from %s size=%" PRId64, ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), + udp_packet->getPktLength()); } - // Remote dst cid is src cid in local - // TODO: print packet type - QUICDebugDS(scid, dcid, "recv packet from %s, size=%" PRId64, ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), - udp_packet->getPktLength()); } - QUICConnection *qc = - this->_ctable->lookup(reinterpret_cast(block->buf()), {udp_packet->from, udp_packet->to, SOCK_DGRAM}); + QUICConnection *qc = this->_ctable->lookup(buf, {udp_packet->from, udp_packet->to, SOCK_DGRAM}); + QUICNetVConnection *vc = static_cast(qc); - vc = static_cast(qc); // 7.1. Matching Packets to Connections // A server that discards a packet that cannot be associated with a connection MAY also generate a stateless reset // Send stateless reset if the packet is not a initial packet or connection is closed. if ((!vc && !QUICTypeUtil::has_long_header(reinterpret_cast(block->buf()))) || (vc && vc->in_closed_queue)) { - Connection con; - con.setRemote(&udp_packet->from.sa); - QUICConnectionId cid = this->_read_destination_connection_id(block); QUICStatelessResetToken token; { QUICConfig::scoped_config params; - token.generate(cid, params->server_id()); + token.generate(dcid, params->server_id()); } - auto packet = QUICPacketFactory::create_stateless_reset_packet(cid, token); - this->_send_packet(this, *packet, udp_packet->getConnection(), con.addr, 1200); + auto packet = QUICPacketFactory::create_stateless_reset_packet(dcid, token); + this->_send_packet(this, *packet, udp_packet->getConnection(), udp_packet->from, 1200); udp_packet->free(); return; } + EThread *eth = nullptr; if (!vc) { + // Create a new NetVConnection Connection con; con.setRemote(&udp_packet->from.sa); - eth = eventProcessor.assign_thread(ET_NET); - // Create a new NetVConnection - QUICConnectionId original_cid = this->_read_destination_connection_id(block); - QUICConnectionId peer_cid = this->_read_source_connection_id(block); + eth = eventProcessor.assign_thread(ET_NET); + QUICConnectionId original_cid = dcid; + QUICConnectionId peer_cid = scid; if (is_debug_tag_set("quic_sec")) { char client_dcid_hex_str[QUICConnectionId::MAX_HEX_STR_LENGTH]; @@ -256,11 +283,12 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) eth = vc->thread; } - qe = quicPollEventAllocator.alloc(); - + QUICPollEvent *qe = quicPollEventAllocator.alloc(); qe->init(qc, static_cast(udp_packet)); // Push the packet into QUICPollCont get_QUICPollCont(eth)->inQueue.push(qe); + + return; } // TODO: Should be called via eventProcessor? diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 36a7ee4e6e8..5b403bb6e5e 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -69,6 +69,8 @@ class QUICConfigParams : public ConfigInfo uint32_t cc_minimum_window() const; float cc_loss_reduction_factor() const; + static const uint8_t SCIL = 5; + private: static int _connection_table_size; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index ea1c7fec734..7ef84aecfa6 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -141,8 +141,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet this->_load_local_server_transport_parameters(initial_packet->version()); packet_factory->set_version(this->_version_negotiator->negotiated_version()); } else { - this->_qc->transmit_packet(packet_factory->create_version_negotiation_packet(initial_packet)); - QUICHSDebug("Version negotiation failed: %x", initial_packet->version()); + ink_assert(!"Unsupported version initial packet should be droped QUICPakcetHandler"); } } else { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 247e6cd0638..9b09c6d4c11 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -21,11 +21,14 @@ * limitations under the License. */ +#include "QUICPacket.h" + #include #include + #include "QUICIntUtil.h" -#include "QUICPacket.h" #include "QUICDebugNames.h" +#include "QUICConfig.h" static constexpr std::string_view tag = "quic_packet"sv; static constexpr uint64_t aead_tag_len = 16; @@ -821,7 +824,7 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } QUICPacketUPtr -QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_sent_by_client) +QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUICConnectionId scid) { size_t len = sizeof(QUICVersion) * countof(QUIC_SUPPORTED_VERSIONS); ats_unique_buf versions(reinterpret_cast(ats_malloc(len)), [](void *p) { ats_free(p); }); @@ -835,8 +838,7 @@ QUICPacketFactory::create_version_negotiation_packet(const QUICPacket *packet_se // VN packet dosen't have packet number field and version field is always 0x00000000 QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, packet_sent_by_client->source_cid(), - packet_sent_by_client->destination_cid(), 0x00, 0x00, 0x00, std::move(versions), len); + QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, dcid, scid, 0x00, 0x00, 0x00, std::move(versions), len); return QUICPacketFactory::_create_unprotected_packet(std::move(header)); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index febd398bee5..f95c9bf1085 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -362,10 +362,12 @@ 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); QUICPacketUPtr create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result); - QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client); QUICPacketUPtr create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len); QUICPacketUPtr create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, ats_unique_buf payload, @@ -375,18 +377,16 @@ class QUICPacketFactory bool retransmittable); QUICPacketUPtr create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); - static QUICPacketUPtr create_stateless_reset_packet(QUICConnectionId connection_id, - QUICStatelessResetToken stateless_reset_token); void set_version(QUICVersion negotiated_version); void set_hs_protocol(QUICHandshakeProtocol *hs_protocol); - void set_dcil(uint8_t len); + [[deprecated]] void set_dcil(uint8_t len); private: QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; QUICHandshakeProtocol *_hs_protocol = nullptr; QUICPacketNumberGenerator _packet_number_generator; - uint8_t _dcil = 0; static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeaderUPtr header); QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable); + [[deprecated]] uint8_t _dcil = 0; }; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index b84b5682f74..faf3bb66b72 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -24,6 +24,7 @@ #include #include "QUICTypes.h" #include "QUICIntUtil.h" +#include "QUICConfig.h" // TODO: move to somewhere in lib/ts/ static int @@ -46,7 +47,6 @@ to_hex_str(char *dst, size_t dst_len, const uint8_t *src, size_t src_len) } bool -#include QUICTypeUtil::has_long_header(const uint8_t *buf) { return (buf[0] & 0x80) != 0; @@ -337,3 +337,97 @@ QUICConnectionId::hex(char *buf, size_t len) const { return to_hex_str(buf, len, this->_id, this->_len); } + +// +// QUICInvariants +// +bool +QUICInvariants::is_long_header(const uint8_t *buf) +{ + return (buf[0] & 0x80) != 0; +} + +bool +QUICInvariants::is_version_negotiation(QUICVersion v) +{ + return v == 0x0; +} + +bool +QUICInvariants::version(QUICVersion &dst, const uint8_t *buf, uint64_t buf_len) +{ + if (!QUICInvariants::is_long_header(buf) || buf_len < QUICInvariants::LH_DCIL_OFFSET) { + return false; + } + + dst = QUICTypeUtil::read_QUICVersion(buf + QUICInvariants::LH_VERSION_OFFSET); + + return true; +} + +bool +QUICInvariants::dcid(QUICConnectionId &dst, const uint8_t *buf, uint64_t buf_len) +{ + uint8_t dcil = 0; + size_t dcid_offset = 0; + + if (QUICInvariants::is_long_header(buf)) { + if (buf_len < QUICInvariants::LH_DCIL_OFFSET) { + return false; + } + + dcil = buf[QUICInvariants::LH_DCIL_OFFSET] >> 4; + if (dcil) { + dcil += QUICInvariants::CIL_BASE; + } else { + dst = QUICConnectionId::ZERO(); + return true; + } + + dcid_offset = QUICInvariants::LH_DCID_OFFSET; + } else { + // remote dcil is local scil + dcil = QUICConfigParams::SCIL + QUICInvariants::CIL_BASE; + dcid_offset = QUICInvariants::SH_DCID_OFFSET; + } + + if (dcid_offset + dcil > buf_len) { + return false; + } + + dst = QUICTypeUtil::read_QUICConnectionId(buf + dcid_offset, dcil); + + return true; +} + +bool +QUICInvariants::scid(QUICConnectionId &dst, const uint8_t *buf, uint64_t buf_len) +{ + ink_assert(QUICInvariants::is_long_header(buf)); + + if (buf_len < QUICInvariants::LH_DCIL_OFFSET) { + return false; + } + + uint8_t dcil = buf[QUICInvariants::LH_DCIL_OFFSET] >> 4; + if (dcil) { + dcil += CIL_BASE; + } + + uint8_t scid_offset = QUICInvariants::LH_DCID_OFFSET + dcil; + uint8_t scil = buf[QUICInvariants::LH_DCIL_OFFSET] & 0x0F; + if (scil) { + scil += CIL_BASE; + } else { + dst = QUICConnectionId::ZERO(); + return true; + } + + if (scid_offset + scil > buf_len) { + return false; + } + + dst = QUICTypeUtil::read_QUICConnectionId(buf + scid_offset, scil); + + return true; +} diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 54646f8ce89..307a447748c 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -312,10 +312,11 @@ class QUICFiveTuple uint64_t _hash_code = 0; }; +// TODO: move version independent functions to QUICInvariants class QUICTypeUtil { public: - static bool has_long_header(const uint8_t *buf); + [[deprecated]] static bool has_long_header(const uint8_t *buf); static bool has_connection_id(const uint8_t *buf); static bool is_supported_version(QUICVersion version); static QUICStreamType detect_stream_type(QUICStreamId id); @@ -341,3 +342,21 @@ class QUICTypeUtil private: }; + +class QUICInvariants +{ +public: + static bool is_long_header(const uint8_t *buf); + static bool is_version_negotiation(QUICVersion v); + static bool version(QUICVersion &dst, const uint8_t *buf, uint64_t buf_len); + static bool dcid(QUICConnectionId &dst, const uint8_t *buf, uint64_t buf_len); + static bool scid(QUICConnectionId &dst, const uint8_t *buf, uint64_t buf_len); + + const static size_t CIL_BASE = 3; + const static size_t LH_VERSION_OFFSET = 1; + const static size_t LH_DCIL_OFFSET = 5; + const static size_t LH_DCID_OFFSET = 6; + const static size_t SH_DCID_OFFSET = 1; + const static size_t LH_MIN_LEN = 6; + const static size_t SH_MIN_LEN = 1; +}; diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index 3634ae5b091..b28e6544867 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -18,6 +18,7 @@ TESTS = $(check_PROGRAMS) check_PROGRAMS = \ + test_QUICInvariants \ test_QUICPacket \ test_QUICPacketFactory \ test_QUICFrame \ @@ -79,6 +80,22 @@ test_LDADD = \ @LIBTCL@ @OPENSSL_LIBS@ \ @HWLOC_LIBS@ +# +# test_QUICInvariants +# +test_QUICInvariants_CPPFLAGS = \ + $(AM_CPPFLAGS) + +test_QUICInvariants_LDFLAGS = \ + @AM_LDFLAGS@ + +test_QUICInvariants_SOURCES = \ + $(catch_main) \ + test_QUICInvariants.cc + +test_QUICInvariants_LDADD = \ + $(test_LDADD) + # # test_QUICPacket # diff --git a/iocore/net/quic/test/test_QUICInvariants.cc b/iocore/net/quic/test/test_QUICInvariants.cc new file mode 100644 index 00000000000..4f7ad052588 --- /dev/null +++ b/iocore/net/quic/test/test_QUICInvariants.cc @@ -0,0 +1,147 @@ +/** @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 "catch.hpp" + +#include "quic/QUICTypes.h" + +TEST_CASE("Long Header - regular case", "[quic]") +{ + const uint8_t buf[] = { + 0x80, // Long header, Type: NONE + 0x11, 0x22, 0x33, 0x44, // Version + 0x55, // DCIL/SCIL + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID + }; + uint64_t buf_len = sizeof(buf); + + const uint8_t raw_dcid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + const uint8_t raw_scid[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; + QUICConnectionId expected_dcid(raw_dcid, 8); + QUICConnectionId expected_scid(raw_scid, 8); + + QUICVersion version = 0; + QUICConnectionId dcid = QUICConnectionId::ZERO(); + QUICConnectionId scid = QUICConnectionId::ZERO(); + + CHECK(QUICInvariants::version(version, buf, buf_len)); + CHECK(version == 0x11223344); + CHECK(QUICInvariants::dcid(dcid, buf, buf_len)); + CHECK(dcid == expected_dcid); + CHECK(QUICInvariants::scid(scid, buf, buf_len)); + CHECK(scid == expected_scid); +} + +TEST_CASE("Long Header - error cases", "[quic]") +{ + SECTION("version") + { + const uint8_t buf[] = { + 0x80, // Long header, Type: NONE + }; + uint64_t buf_len = sizeof(buf); + + QUICVersion version = 0; + + CHECK(QUICInvariants::version(version, buf, buf_len) == false); + } + + SECTION("dcid") + { + const uint8_t buf[] = { + 0x80, // Long header, Type: NONE + 0x11, 0x22, 0x33, 0x44, // Version + 0x55, // DCIL/SCIL + 0x01, 0x02, 0x03, 0x04, // Invalid Destination Connection ID + }; + uint64_t buf_len = sizeof(buf); + + const uint8_t raw_dcid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + QUICConnectionId expected_dcid(raw_dcid, 8); + + QUICVersion version = 0; + QUICConnectionId dcid = QUICConnectionId::ZERO(); + + CHECK(QUICInvariants::version(version, buf, buf_len)); + CHECK(version == 0x11223344); + CHECK(QUICInvariants::dcid(dcid, buf, buf_len) == false); + } + + SECTION("scid") + { + const uint8_t buf[] = { + 0x80, // Long header, Type: NONE + 0x11, 0x22, 0x33, 0x44, // Version + 0x55, // DCIL/SCIL + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + 0x11, 0x12, 0x13, 0x14, // Invalid Source Connection ID + }; + uint64_t buf_len = sizeof(buf); + + const uint8_t raw_dcid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + const uint8_t raw_scid[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; + QUICConnectionId expected_dcid(raw_dcid, 8); + QUICConnectionId expected_scid(raw_scid, 8); + + QUICVersion version = 0; + QUICConnectionId dcid = QUICConnectionId::ZERO(); + QUICConnectionId scid = QUICConnectionId::ZERO(); + + CHECK(QUICInvariants::version(version, buf, buf_len)); + CHECK(version == 0x11223344); + CHECK(QUICInvariants::dcid(dcid, buf, buf_len)); + CHECK(dcid == expected_dcid); + CHECK(QUICInvariants::scid(scid, buf, buf_len) == false); + } +} + +TEST_CASE("Short Header - regular case", "[quic]") +{ + const uint8_t buf[] = { + 0x00, // Long header, Type: NONE + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + }; + uint64_t buf_len = sizeof(buf); + + const uint8_t raw_dcid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + QUICConnectionId expected_dcid(raw_dcid, 8); + + QUICConnectionId dcid = QUICConnectionId::ZERO(); + + CHECK(QUICInvariants::dcid(dcid, buf, buf_len)); + CHECK(dcid == expected_dcid); +} + +// When ATS change QUICConfigParams::SCIL, this test should be failed +TEST_CASE("Short Header - error case", "[quic]") +{ + const uint8_t buf[] = { + 0x00, // Long header, Type: NONE + 0x01, 0x02, 0x03, 0x04, // Invalid Destination Connection ID + }; + uint64_t buf_len = sizeof(buf); + + QUICConnectionId dcid = QUICConnectionId::ZERO(); + CHECK(QUICInvariants::dcid(dcid, buf, buf_len) == false); +} diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 0ebc38b6bf0..cd3bb507b82 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -32,32 +32,16 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); - uint8_t initial_packet_header[] = { - 0xFF, // Type - 0xaa, 0xbb, 0xcc, 0xdd, // Version - 0x55, // DCIL/SCIL - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection id - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection id - 0x01, // Payload Length - 0x00, 0x00, 0x00, 0x00, // Packet number - }; - uint8_t initial_packet_payload[] = { - 0x00 // Payload - }; - - QUICPacketHeaderUPtr header = - QUICPacketHeader::load({}, {initial_packet_header, [](void *) {}}, sizeof(initial_packet_header), 0, 8); - - QUICPacket initial_packet(std::move(header), ats_unique_buf(initial_packet_payload, [](void *) {}), - sizeof(initial_packet_payload), 0); + const uint8_t raw_dcid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + const uint8_t raw_scid[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; + QUICConnectionId dcid(raw_dcid, 8); + QUICConnectionId scid(raw_scid, 8); - QUICPacketUPtr vn_packet = factory.create_version_negotiation_packet(&initial_packet); + QUICPacketUPtr vn_packet = factory.create_version_negotiation_packet(scid, dcid); CHECK(vn_packet->type() == QUICPacketType::VERSION_NEGOTIATION); - uint8_t dst_cid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; - uint8_t src_cid[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; - CHECK((vn_packet->source_cid() == QUICConnectionId(dst_cid, sizeof(dst_cid)))); - CHECK((vn_packet->destination_cid() == QUICConnectionId(src_cid, sizeof(src_cid)))); + CHECK(vn_packet->destination_cid() == scid); + CHECK(vn_packet->source_cid() == dcid); CHECK(vn_packet->version() == 0x00); QUICVersion supported_version = QUICTypeUtil::read_QUICVersion(vn_packet->payload()); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 07dcdd7ee27..78142b62bda 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -121,7 +121,8 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0); // Server send VN packet based on Initial packet - QUICPacketUPtr vn_packet = packet_factory.create_version_negotiation_packet(initial_packet.get()); + QUICPacketUPtr vn_packet = + packet_factory.create_version_negotiation_packet(initial_packet->source_cid(), initial_packet->destination_cid()); // Negotiate version vn.negotiate(vn_packet.get()); From ac60e738390cb19871955a3017c1f14bd7cf5297 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Jun 2018 14:00:04 +0900 Subject: [PATCH 0625/1313] Make sure length of scid is 18 bytes --- iocore/net/quic/QUICConfig.cc | 6 + iocore/net/quic/QUICConfig.h | 6 +- iocore/net/quic/QUICPacket.h | 4 +- iocore/net/quic/QUICTypes.cc | 78 +++++++++---- iocore/net/quic/QUICTypes.h | 20 ++-- iocore/net/quic/test/test_QUICInvariants.cc | 121 ++++++++++++++++---- 6 files changed, 180 insertions(+), 55 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 6010b232151..b03d1bbc584 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -336,6 +336,12 @@ QUICConfigParams::cc_loss_reduction_factor() const return _cc_loss_reduction_factor; } +uint8_t +QUICConfigParams::scid_len() +{ + return QUICConfigParams::_scid_len; +} + // // QUICConfig // diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 5b403bb6e5e..204cc18ff50 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -44,7 +44,6 @@ class QUICConfigParams : public ConfigInfo uint16_t initial_max_uni_streams_in() const; uint16_t initial_max_uni_streams_out() const; uint32_t server_id() const; - static int connection_table_size(); uint32_t max_alt_connection_ids() const; uint32_t stateless_retry() const; uint32_t vn_exercise_enabled() const; @@ -69,10 +68,13 @@ class QUICConfigParams : public ConfigInfo uint32_t cc_minimum_window() const; float cc_loss_reduction_factor() const; - static const uint8_t SCIL = 5; + static int connection_table_size(); + static uint8_t scid_len(); private: static int _connection_table_size; + // TODO: make configurable + static const uint8_t _scid_len = 18; //< Length of Source Connection ID // FIXME Fill appropriate default values in RecordsConfig.cc uint32_t _no_activity_timeout_in = 0; diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index f95c9bf1085..2d022e870e2 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -291,8 +291,8 @@ class QUICPacket const uint8_t *payload() const; bool is_retransmittable() const; - static QUICConnectionId destination_connection_id(const uint8_t *packet); - static QUICConnectionId source_connection_id(const uint8_t *packet); + [[deprecated]] static QUICConnectionId destination_connection_id(const uint8_t *packet); + [[deprecated]] static QUICConnectionId source_connection_id(const uint8_t *packet); /* * Size of whole QUIC packet (header + payload + integrity check) diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index faf3bb66b72..8bafd4bb95a 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -273,7 +273,7 @@ QUICFiveTuple::protocol() const QUICConnectionId QUICConnectionId::ZERO() { - uint8_t zero[18] = {0}; + uint8_t zero[MAX_LENGTH] = {0}; return QUICConnectionId(zero, sizeof(zero)); } @@ -309,13 +309,13 @@ QUICConnectionId::randomize() { std::random_device rnd; uint32_t x; - for (int i = sizeof(this->_id) - 1; i >= 0; --i) { + for (int i = QUICConfigParams::scid_len(); i >= 0; --i) { if (i % 4 == 0) { x = rnd(); } this->_id[i] = (x >> (8 * (i % 4))) & 0xFF; } - this->_len = 18; + this->_len = QUICConfigParams::scid_len(); } uint64_t @@ -356,7 +356,7 @@ QUICInvariants::is_version_negotiation(QUICVersion v) bool QUICInvariants::version(QUICVersion &dst, const uint8_t *buf, uint64_t buf_len) { - if (!QUICInvariants::is_long_header(buf) || buf_len < QUICInvariants::LH_DCIL_OFFSET) { + if (!QUICInvariants::is_long_header(buf) || buf_len < QUICInvariants::LH_CIL_OFFSET) { return false; } @@ -365,20 +365,48 @@ QUICInvariants::version(QUICVersion &dst, const uint8_t *buf, uint64_t buf_len) return true; } +bool +QUICInvariants::dcil(uint8_t &dst, const uint8_t *buf, uint64_t buf_len) +{ + ink_assert(QUICInvariants::is_long_header(buf)); + + if (buf_len < QUICInvariants::LH_CIL_OFFSET) { + return false; + } + + dst = buf[QUICInvariants::LH_CIL_OFFSET] >> 4; + + return true; +} + +bool +QUICInvariants::scil(uint8_t &dst, const uint8_t *buf, uint64_t buf_len) +{ + ink_assert(QUICInvariants::is_long_header(buf)); + + if (buf_len < QUICInvariants::LH_CIL_OFFSET) { + return false; + } + + dst = buf[QUICInvariants::LH_CIL_OFFSET] & 0x0F; + + return true; +} + bool QUICInvariants::dcid(QUICConnectionId &dst, const uint8_t *buf, uint64_t buf_len) { - uint8_t dcil = 0; - size_t dcid_offset = 0; + uint8_t dcid_offset = 0; + uint8_t dcid_len = 0; if (QUICInvariants::is_long_header(buf)) { - if (buf_len < QUICInvariants::LH_DCIL_OFFSET) { + uint8_t dcil = 0; + if (!QUICInvariants::dcil(dcil, buf, buf_len)) { return false; } - dcil = buf[QUICInvariants::LH_DCIL_OFFSET] >> 4; if (dcil) { - dcil += QUICInvariants::CIL_BASE; + dcid_len = dcil + QUICInvariants::CIL_BASE; } else { dst = QUICConnectionId::ZERO(); return true; @@ -387,15 +415,15 @@ QUICInvariants::dcid(QUICConnectionId &dst, const uint8_t *buf, uint64_t buf_len dcid_offset = QUICInvariants::LH_DCID_OFFSET; } else { // remote dcil is local scil - dcil = QUICConfigParams::SCIL + QUICInvariants::CIL_BASE; + dcid_len = QUICConfigParams::scid_len(); dcid_offset = QUICInvariants::SH_DCID_OFFSET; } - if (dcid_offset + dcil > buf_len) { + if (dcid_offset + dcid_len > buf_len) { return false; } - dst = QUICTypeUtil::read_QUICConnectionId(buf + dcid_offset, dcil); + dst = QUICTypeUtil::read_QUICConnectionId(buf + dcid_offset, dcid_len); return true; } @@ -405,29 +433,39 @@ QUICInvariants::scid(QUICConnectionId &dst, const uint8_t *buf, uint64_t buf_len { ink_assert(QUICInvariants::is_long_header(buf)); - if (buf_len < QUICInvariants::LH_DCIL_OFFSET) { + if (buf_len < QUICInvariants::LH_CIL_OFFSET) { + return false; + } + + uint8_t scid_offset = QUICInvariants::LH_DCID_OFFSET; + uint8_t scid_len = 0; + + uint8_t dcil = 0; + if (!QUICInvariants::dcil(dcil, buf, buf_len)) { return false; } - uint8_t dcil = buf[QUICInvariants::LH_DCIL_OFFSET] >> 4; if (dcil) { - dcil += CIL_BASE; + scid_offset += (dcil + QUICInvariants::CIL_BASE); + } + + uint8_t scil = 0; + if (!QUICInvariants::scil(scil, buf, buf_len)) { + return false; } - uint8_t scid_offset = QUICInvariants::LH_DCID_OFFSET + dcil; - uint8_t scil = buf[QUICInvariants::LH_DCIL_OFFSET] & 0x0F; if (scil) { - scil += CIL_BASE; + scid_len = scil + QUICInvariants::CIL_BASE; } else { dst = QUICConnectionId::ZERO(); return true; } - if (scid_offset + scil > buf_len) { + if (scid_offset + scid_len > buf_len) { return false; } - dst = QUICTypeUtil::read_QUICConnectionId(buf + scid_offset, scil); + dst = QUICTypeUtil::read_QUICConnectionId(buf + scid_offset, scid_len); return true; } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 307a447748c..278398d9dfb 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -249,7 +249,7 @@ class QUICConnectionId private: uint64_t _hashcode() const; - uint8_t _id[18]; + uint8_t _id[MAX_LENGTH]; uint8_t _len = 0; }; @@ -317,7 +317,7 @@ class QUICTypeUtil { public: [[deprecated]] static bool has_long_header(const uint8_t *buf); - static bool has_connection_id(const uint8_t *buf); + [[deprecated]] static bool has_connection_id(const uint8_t *buf); static bool is_supported_version(QUICVersion version); static QUICStreamType detect_stream_type(QUICStreamId id); @@ -349,14 +349,16 @@ class QUICInvariants static bool is_long_header(const uint8_t *buf); static bool is_version_negotiation(QUICVersion v); static bool version(QUICVersion &dst, const uint8_t *buf, uint64_t buf_len); + static bool dcil(uint8_t &dst, const uint8_t *buf, uint64_t buf_len); + static bool scil(uint8_t &dst, const uint8_t *buf, uint64_t buf_len); static bool dcid(QUICConnectionId &dst, const uint8_t *buf, uint64_t buf_len); static bool scid(QUICConnectionId &dst, const uint8_t *buf, uint64_t buf_len); - const static size_t CIL_BASE = 3; - const static size_t LH_VERSION_OFFSET = 1; - const static size_t LH_DCIL_OFFSET = 5; - const static size_t LH_DCID_OFFSET = 6; - const static size_t SH_DCID_OFFSET = 1; - const static size_t LH_MIN_LEN = 6; - const static size_t SH_MIN_LEN = 1; + static const size_t CIL_BASE = 3; + static const size_t LH_VERSION_OFFSET = 1; + static const size_t LH_CIL_OFFSET = 5; + static const size_t LH_DCID_OFFSET = 6; + static const size_t SH_DCID_OFFSET = 1; + static const size_t LH_MIN_LEN = 6; + static const size_t SH_MIN_LEN = 1; }; diff --git a/iocore/net/quic/test/test_QUICInvariants.cc b/iocore/net/quic/test/test_QUICInvariants.cc index 4f7ad052588..dc1c8d71258 100644 --- a/iocore/net/quic/test/test_QUICInvariants.cc +++ b/iocore/net/quic/test/test_QUICInvariants.cc @@ -27,30 +27,101 @@ TEST_CASE("Long Header - regular case", "[quic]") { - const uint8_t buf[] = { - 0x80, // Long header, Type: NONE - 0x11, 0x22, 0x33, 0x44, // Version - 0x55, // DCIL/SCIL - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID - }; - uint64_t buf_len = sizeof(buf); - const uint8_t raw_dcid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; const uint8_t raw_scid[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; QUICConnectionId expected_dcid(raw_dcid, 8); QUICConnectionId expected_scid(raw_scid, 8); - QUICVersion version = 0; - QUICConnectionId dcid = QUICConnectionId::ZERO(); - QUICConnectionId scid = QUICConnectionId::ZERO(); + SECTION("dcid & scid") + { + const uint8_t buf[] = { + 0x80, // Long header, Type: NONE + 0x11, 0x22, 0x33, 0x44, // Version + 0x55, // DCIL/SCIL + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID + }; + uint64_t buf_len = sizeof(buf); - CHECK(QUICInvariants::version(version, buf, buf_len)); - CHECK(version == 0x11223344); - CHECK(QUICInvariants::dcid(dcid, buf, buf_len)); - CHECK(dcid == expected_dcid); - CHECK(QUICInvariants::scid(scid, buf, buf_len)); - CHECK(scid == expected_scid); + QUICVersion version = 0; + uint8_t dcil = 0; + uint8_t scil = 0; + QUICConnectionId dcid = QUICConnectionId::ZERO(); + QUICConnectionId scid = QUICConnectionId::ZERO(); + + CHECK(QUICInvariants::version(version, buf, buf_len)); + CHECK(version == 0x11223344); + + CHECK(QUICInvariants::dcil(dcil, buf, buf_len)); + CHECK(dcil == 5); + CHECK(QUICInvariants::dcid(dcid, buf, buf_len)); + CHECK(dcid == expected_dcid); + + CHECK(QUICInvariants::scil(scil, buf, buf_len)); + CHECK(scil == 5); + CHECK(QUICInvariants::scid(scid, buf, buf_len)); + CHECK(scid == expected_scid); + } + + SECTION("omitted dcid") + { + const uint8_t buf[] = { + 0x80, // Long header, Type: NONE + 0x11, 0x22, 0x33, 0x44, // Version + 0x05, // DCIL/SCIL + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID + }; + uint64_t buf_len = sizeof(buf); + + QUICVersion version = 0; + uint8_t dcil = 0; + uint8_t scil = 0; + QUICConnectionId dcid = QUICConnectionId::ZERO(); + QUICConnectionId scid = QUICConnectionId::ZERO(); + + CHECK(QUICInvariants::version(version, buf, buf_len)); + CHECK(version == 0x11223344); + + CHECK(QUICInvariants::dcil(dcil, buf, buf_len)); + CHECK(dcil == 0); + CHECK(QUICInvariants::dcid(dcid, buf, buf_len)); + CHECK(dcid == QUICConnectionId::ZERO()); + + CHECK(QUICInvariants::scil(scil, buf, buf_len)); + CHECK(scil == 5); + CHECK(QUICInvariants::scid(scid, buf, buf_len)); + CHECK(scid == expected_scid); + } + + SECTION("omitted scid") + { + const uint8_t buf[] = { + 0x80, // Long header, Type: NONE + 0x11, 0x22, 0x33, 0x44, // Version + 0x50, // DCIL/SCIL + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + }; + uint64_t buf_len = sizeof(buf); + + QUICVersion version = 0; + uint8_t dcil = 0; + uint8_t scil = 0; + QUICConnectionId dcid = QUICConnectionId::ZERO(); + QUICConnectionId scid = QUICConnectionId::ZERO(); + + CHECK(QUICInvariants::version(version, buf, buf_len)); + CHECK(version == 0x11223344); + + CHECK(QUICInvariants::dcil(dcil, buf, buf_len)); + CHECK(dcil == 5); + CHECK(QUICInvariants::dcid(dcid, buf, buf_len)); + CHECK(dcid == expected_dcid); + + CHECK(QUICInvariants::scil(scil, buf, buf_len)); + CHECK(scil == 0); + CHECK(QUICInvariants::scid(scid, buf, buf_len)); + CHECK(scid == QUICConnectionId::ZERO()); + } } TEST_CASE("Long Header - error cases", "[quic]") @@ -116,16 +187,23 @@ TEST_CASE("Long Header - error cases", "[quic]") } } +// When ATS change QUICConfigParams::_scid_len shorter, this test should be failed TEST_CASE("Short Header - regular case", "[quic]") { const uint8_t buf[] = { 0x00, // Long header, Type: NONE - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Destination Connection ID (144) + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, // + 0x10, 0x11, // }; uint64_t buf_len = sizeof(buf); - const uint8_t raw_dcid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; - QUICConnectionId expected_dcid(raw_dcid, 8); + const uint8_t raw_dcid[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, // + 0x10, 0x11, // + }; + QUICConnectionId expected_dcid(raw_dcid, 18); QUICConnectionId dcid = QUICConnectionId::ZERO(); @@ -133,7 +211,6 @@ TEST_CASE("Short Header - regular case", "[quic]") CHECK(dcid == expected_dcid); } -// When ATS change QUICConfigParams::SCIL, this test should be failed TEST_CASE("Short Header - error case", "[quic]") { const uint8_t buf[] = { From 25fc9182111ddddefa55a750d0514d58b4639919 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Jun 2018 15:10:30 +0900 Subject: [PATCH 0626/1313] Cleanup: Remove QUICPacketFactory::_dcil and QUICPacketShortHeader::_dcil We don't need to track dcil for Short Header packet, becasue it's same to scil in local. In other words, when we need dcil while reading Short Header packet, we should refer it via `QUICConfigParams::scid_len()`; --- iocore/net/QUICNetVConnection.cc | 1 - iocore/net/quic/QUICPacket.cc | 27 +++++------- iocore/net/quic/QUICPacket.h | 7 +--- iocore/net/quic/test/test_QUICInvariants.cc | 2 +- iocore/net/quic/test/test_QUICPacket.cc | 46 +++++++++++++-------- 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b7d53b35c8b..b17d93c23e6 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1490,7 +1490,6 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) } this->_last_received_packet_type = packet->type(); - this->_packet_factory.set_dcil(packet->destination_cid().length()); } // Debug prints diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 9b09c6d4c11..e4a9e2a4b95 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -43,8 +43,6 @@ ClassAllocator quicPacketShortHeaderAllocator("quicPacket static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6; static constexpr int LONG_HDR_OFFSET_VERSION = 1; -static constexpr int SHORT_HDR_OFFSET_CONNECTION_ID = 1; - // // QUICPacketHeader // @@ -74,7 +72,7 @@ QUICPacketHeader::packet_size() const } QUICPacketHeaderUPtr -QUICPacketHeader::load(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base, uint8_t dcil) +QUICPacketHeader::load(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base) { QUICPacketHeaderUPtr header = QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header); if (QUICTypeUtil::has_long_header(buf.get())) { @@ -83,7 +81,7 @@ QUICPacketHeader::load(const IpEndpoint from, ats_unique_buf buf, size_t len, QU header = QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); } else { QUICPacketShortHeader *short_header = quicPacketShortHeaderAllocator.alloc(); - new (short_header) QUICPacketShortHeader(from, std::move(buf), len, base, dcil); + new (short_header) QUICPacketShortHeader(from, std::move(buf), len, base); header = QUICPacketHeaderUPtr(short_header, &QUICPacketHeaderDeleter::delete_short_header); } return header; @@ -326,17 +324,16 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const // QUICPacketShortHeader // -QUICPacketShortHeader::QUICPacketShortHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base, - uint8_t dcil) - : QUICPacketHeader(from, std::move(buf), len, base), _dcil(dcil) +QUICPacketShortHeader::QUICPacketShortHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base) + : QUICPacketHeader(from, std::move(buf), len, base) { - this->_connection_id = QUICTypeUtil::read_QUICConnectionId(this->_buf.get() + 1, dcil); + 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() + offset); QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + offset); QUICPacket::decode_packet_number(this->_packet_number, src, this->_packet_number_len, this->_base_packet_number); - this->_payload_length = len - (1 + this->_dcil + this->_packet_number_len); + this->_payload_length = len - (1 + QUICConfigParams::scid_len() + this->_packet_number_len); } QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, @@ -388,7 +385,9 @@ QUICConnectionId QUICPacketShortHeader::destination_cid() const { if (this->_buf) { - return QUICTypeUtil::read_QUICConnectionId(this->_buf.get() + SHORT_HDR_OFFSET_CONNECTION_ID, this->_dcil); + QUICConnectionId dcid = QUICConnectionId::ZERO(); + QUICInvariants::dcid(dcid, this->_buf.get(), this->_buf_len); + return dcid; } else { return _connection_id; } @@ -710,7 +709,7 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP ats_unique_buf plain_txt = ats_unique_malloc(max_plain_txt_len); size_t plain_txt_len = 0; - QUICPacketHeaderUPtr header = QUICPacketHeader::load(from, std::move(buf), len, base_packet_number, this->_dcil); + QUICPacketHeaderUPtr header = QUICPacketHeader::load(from, std::move(buf), len, base_packet_number); QUICConnectionId dcid = header->destination_cid(); QUICConnectionId scid = header->source_cid(); @@ -957,12 +956,6 @@ QUICPacketFactory::set_hs_protocol(QUICHandshakeProtocol *hs_protocol) this->_hs_protocol = hs_protocol; } -void -QUICPacketFactory::set_dcil(uint8_t len) -{ - this->_dcil = len; -} - // // QUICPacketNumberGenerator // diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 2d022e870e2..ec8dc1c6fb3 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -117,7 +117,7 @@ class QUICPacketHeader * * This creates either a QUICPacketShortHeader or a QUICPacketLongHeader. */ - static QUICPacketHeaderUPtr load(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base, uint8_t dcil = 0); + static QUICPacketHeaderUPtr load(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base); /* * Build a QUICPacketHeader @@ -202,7 +202,7 @@ class QUICPacketShortHeader : public QUICPacketHeader public: QUICPacketShortHeader() : QUICPacketHeader(){}; virtual ~QUICPacketShortHeader(){}; - QUICPacketShortHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base, uint8_t dcil); + QUICPacketShortHeader(const IpEndpoint from, 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, QUICConnectionId connection_id, QUICPacketNumber packet_number, @@ -226,7 +226,6 @@ class QUICPacketShortHeader : public QUICPacketHeader private: int _packet_number_len; - uint8_t _dcil; }; class QUICPacketHeaderDeleter @@ -379,7 +378,6 @@ class QUICPacketFactory ats_unique_buf payload, size_t len, bool retransmittable); void set_version(QUICVersion negotiated_version); void set_hs_protocol(QUICHandshakeProtocol *hs_protocol); - [[deprecated]] void set_dcil(uint8_t len); private: QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; @@ -388,5 +386,4 @@ class QUICPacketFactory static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeaderUPtr header); QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable); - [[deprecated]] uint8_t _dcil = 0; }; diff --git a/iocore/net/quic/test/test_QUICInvariants.cc b/iocore/net/quic/test/test_QUICInvariants.cc index dc1c8d71258..5cdbc28b632 100644 --- a/iocore/net/quic/test/test_QUICInvariants.cc +++ b/iocore/net/quic/test/test_QUICInvariants.cc @@ -203,7 +203,7 @@ TEST_CASE("Short Header - regular case", "[quic]") 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, // 0x10, 0x11, // }; - QUICConnectionId expected_dcid(raw_dcid, 18); + QUICConnectionId expected_dcid(raw_dcid, sizeof(raw_dcid)); QUICConnectionId dcid = QUICConnectionId::ZERO(); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index dbd30d9cb94..abf53669143 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -118,22 +118,30 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") TEST_CASE("QUICPacketHeader - Short", "[quic]") { + const uint8_t raw_dcid[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Destination Connection ID (144) + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, // + 0x10, 0x11, // + }; + QUICConnectionId dcid(raw_dcid, sizeof(raw_dcid)); + SECTION("Short Header (load)") { const uint8_t input[] = { 0x30, // Short header with (K=0) - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Destination Connection ID (144) + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, // + 0x10, 0x11, // 0xC1, 0x23, 0x45, 0x67, // Packet number 0xff, 0xff, // Payload (dummy) }; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0, 8); - CHECK(header->size() == 13); - CHECK(header->packet_size() == 15); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); + CHECK(header->size() == 23); + CHECK(header->packet_size() == 25); CHECK(header->has_key_phase() == true); CHECK(header->key_phase() == QUICKeyPhase::PHASE_0); - CHECK( - (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); + CHECK(header->destination_cid() == dcid); CHECK(header->packet_number() == 0x01234567); CHECK(header->has_version() == false); } @@ -145,29 +153,33 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") const uint8_t expected[] = { 0x30, // Short header with (K=0) - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Destination Connection ID (144) + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, // + 0x10, 0x11, // 0xC1, 0x23, 0x45, 0x67, // Packet number 0x11, 0x22, 0x33, 0x44, 0x55, // Protected Payload }; + size_t payload_len = 5; + size_t header_len = sizeof(expected) - 5; - ats_unique_buf payload = ats_unique_malloc(5); - memcpy(payload.get(), expected + 13, 5); - QUICPacketHeaderUPtr header = QUICPacketHeader::build( - QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, {reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, - 0x01234567, 0, std::move(payload), 32); - CHECK(header->size() == 13); + ats_unique_buf payload = ats_unique_malloc(payload_len); + memcpy(payload.get(), expected + header_len, payload_len); + + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, dcid, 0x01234567, 0, std::move(payload), 32); + + CHECK(header->size() == 23); CHECK(header->packet_size() == 0); CHECK(header->has_key_phase() == true); CHECK(header->key_phase() == QUICKeyPhase::PHASE_0); CHECK(header->type() == QUICPacketType::PROTECTED); - CHECK( - (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); + CHECK(header->destination_cid() == dcid); CHECK(header->packet_number() == 0x01234567); CHECK(header->has_version() == false); header->store(buf, &len); - CHECK(len == 13); - CHECK(memcmp(buf, expected, len) == 0); + CHECK(len == header_len); + CHECK(memcmp(buf, expected, header_len) == 0); } } From ba07bd2001fd645bdc39ce7f314c34c61c96a2f9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Jun 2018 15:35:38 +0900 Subject: [PATCH 0627/1313] Cleanup: remove deprecated apis of QUICPacket --- iocore/net/QUICPacketHandler.cc | 2 +- iocore/net/quic/QUICConnectionTable.cc | 19 ++++++------ iocore/net/quic/QUICConnectionTable.h | 11 ++++--- iocore/net/quic/QUICPacket.cc | 42 -------------------------- iocore/net/quic/QUICPacket.h | 3 -- 5 files changed, 18 insertions(+), 59 deletions(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index a596c35bf2e..ab8727b09ae 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -230,7 +230,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) } } - QUICConnection *qc = this->_ctable->lookup(buf, {udp_packet->from, udp_packet->to, SOCK_DGRAM}); + QUICConnection *qc = this->_ctable->lookup(dcid); QUICNetVConnection *vc = static_cast(qc); // 7.1. Matching Packets to Connections diff --git a/iocore/net/quic/QUICConnectionTable.cc b/iocore/net/quic/QUICConnectionTable.cc index 8337549adc1..cda8c9a07dd 100644 --- a/iocore/net/quic/QUICConnectionTable.cc +++ b/iocore/net/quic/QUICConnectionTable.cc @@ -55,16 +55,17 @@ QUICConnectionTable::erase(QUICConnectionId cid) } QUICConnection * -QUICConnectionTable::lookup(const uint8_t *packet, QUICFiveTuple endpoint) +QUICConnectionTable::lookup(QUICFiveTuple endpoint) +{ + ink_assert(false); + // TODO: find cid with five tuples + // cid = this->_cids.get(endpoint); + return nullptr; +} + +QUICConnection * +QUICConnectionTable::lookup(QUICConnectionId cid) { - QUICConnectionId cid; - if (QUICTypeUtil::has_connection_id(packet)) { - cid = QUICPacket::destination_connection_id(packet); - } else { - // TODO: find cid with five tuples - // cid = this->_cids.get(endpoint); - ink_assert(false); - } SCOPED_MUTEX_LOCK(lock, _connections.lock_for_key(cid), this_ethread()); return _connections.lookup_entry(cid); } diff --git a/iocore/net/quic/QUICConnectionTable.h b/iocore/net/quic/QUICConnectionTable.h index d210e84135c..45a6ebaea86 100644 --- a/iocore/net/quic/QUICConnectionTable.h +++ b/iocore/net/quic/QUICConnectionTable.h @@ -49,11 +49,14 @@ class QUICConnectionTable QUICConnection *erase(QUICConnectionId cid); /* - * Lookup QUICConnection - * - * If packet doesn't have CID, 5-tuple(endpoint) will be used to lookup CID. + * Lookup QUICConnection by 5-tuple + */ + QUICConnection *lookup(QUICFiveTuple endpoint); + + /* + * Lookup QUICConnection by cid */ - QUICConnection *lookup(const uint8_t *packet, QUICFiveTuple endpoint); + QUICConnection *lookup(QUICConnectionId cid); private: MTHashTable _connections; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index e4a9e2a4b95..6a8b7e8b13e 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -650,48 +650,6 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si return true; } -QUICConnectionId -QUICPacket::destination_connection_id(const uint8_t *buf) -{ - uint8_t cid_offset; - uint8_t cid_len; - QUICConnectionId cid; - if (QUICTypeUtil::has_long_header(buf)) { - cid_offset = 6; - cid_len = buf[5] >> 4; - if (cid_len) { - cid_len += 3; - } - } else { - cid_offset = 1; - // TODO Read CID length from records.config - cid_len = 18; - } - cid = QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); - - return cid; -} - -QUICConnectionId -QUICPacket::source_connection_id(const uint8_t *buf) -{ - ink_assert(QUICTypeUtil::has_long_header(buf)); - - uint8_t cid_offset = 6; - uint8_t cid_len = 0; - - cid_len = buf[5] >> 4; - if (cid_len) { - cid_len += 3; - } - cid_offset += cid_len; - cid_len = buf[5] & 0x0F; - if (cid_len) { - cid_len += 3; - } - return QUICTypeUtil::read_QUICConnectionId(buf + cid_offset, cid_len); -} - // // QUICPacketFactory // diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index ec8dc1c6fb3..0245f3e2990 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -290,9 +290,6 @@ class QUICPacket const uint8_t *payload() const; bool is_retransmittable() const; - [[deprecated]] static QUICConnectionId destination_connection_id(const uint8_t *packet); - [[deprecated]] static QUICConnectionId source_connection_id(const uint8_t *packet); - /* * Size of whole QUIC packet (header + payload + integrity check) */ From 3c53ce8fb9125361983cbcfb26b5374cc68d22de Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 18 Jun 2018 11:08:31 +0900 Subject: [PATCH 0628/1313] Cleanup: remove unused function When ATS support omitting SCID, parsing Short Header packet and QUICConnectionTable structure should be revisited. --- iocore/net/QUICPacketHandler.cc | 14 +++++++++----- iocore/net/quic/QUICConnectionTable.cc | 9 --------- iocore/net/quic/QUICConnectionTable.h | 5 ----- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index ab8727b09ae..fe84d230737 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -186,8 +186,6 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) QUICConnectionId dcid = QUICConnectionId::ZERO(); QUICConnectionId scid = QUICConnectionId::ZERO(); - // TODO: lookup by 5-Tuple - // When ATS omits SCID, endpoint omits DCID. In this case, we can't get DCID from SH packet, we need to lookup QC by 5-Tuple. if (!QUICInvariants::dcid(dcid, buf, buf_len)) { QUICDebug("Ignore packet - payload is too small"); udp_packet->free(); @@ -222,7 +220,13 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) udp_packet->free(); return; } + + if (dcid == QUICConnectionId::ZERO()) { + // TODO: lookup DCID by 5-tuple when ATS omits SCID + return; + } } else { + // TODO: lookup DCID by 5-tuple when ATS omits SCID if (is_debug_tag_set(tag)) { ip_port_text_buffer ipb; QUICDebugDS(scid, dcid, "recv SH packet from %s size=%" PRId64, ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), @@ -233,9 +237,9 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) QUICConnection *qc = this->_ctable->lookup(dcid); QUICNetVConnection *vc = static_cast(qc); - // 7.1. Matching Packets to Connections - // A server that discards a packet that cannot be associated with a connection MAY also generate a stateless reset - // Send stateless reset if the packet is not a initial packet or connection is closed. + // [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 && !QUICTypeUtil::has_long_header(reinterpret_cast(block->buf()))) || (vc && vc->in_closed_queue)) { QUICStatelessResetToken token; { diff --git a/iocore/net/quic/QUICConnectionTable.cc b/iocore/net/quic/QUICConnectionTable.cc index cda8c9a07dd..2403a6da6d4 100644 --- a/iocore/net/quic/QUICConnectionTable.cc +++ b/iocore/net/quic/QUICConnectionTable.cc @@ -54,15 +54,6 @@ QUICConnectionTable::erase(QUICConnectionId cid) return _connections.remove_entry(cid); } -QUICConnection * -QUICConnectionTable::lookup(QUICFiveTuple endpoint) -{ - ink_assert(false); - // TODO: find cid with five tuples - // cid = this->_cids.get(endpoint); - return nullptr; -} - QUICConnection * QUICConnectionTable::lookup(QUICConnectionId cid) { diff --git a/iocore/net/quic/QUICConnectionTable.h b/iocore/net/quic/QUICConnectionTable.h index 45a6ebaea86..b3576de8ec4 100644 --- a/iocore/net/quic/QUICConnectionTable.h +++ b/iocore/net/quic/QUICConnectionTable.h @@ -48,11 +48,6 @@ class QUICConnectionTable void erase(QUICConnectionId cid, QUICConnection *connection); QUICConnection *erase(QUICConnectionId cid); - /* - * Lookup QUICConnection by 5-tuple - */ - QUICConnection *lookup(QUICFiveTuple endpoint); - /* * Lookup QUICConnection by cid */ From 4e0cbe4324975aaf26fabccd71c613293836ce6a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 18 Jun 2018 11:40:42 +0900 Subject: [PATCH 0629/1313] Cleanup: Remove QUICTypeUtil::has_connection_id(const uint8_t *) The omit_connection_id flag is removed by draft-10, This function doesn't work any more. --- iocore/net/QUICNet.cc | 16 ---------------- iocore/net/quic/QUICTypes.cc | 6 ------ iocore/net/quic/QUICTypes.h | 1 - 3 files changed, 23 deletions(-) diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index 83411ef0c36..319bbafeb7d 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -67,13 +67,6 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) QUICNetVConnection *vc = static_cast(e->con); uint8_t *buf = (uint8_t *)p->getIOBlockChain()->buf(); - if (!QUICTypeUtil::has_connection_id(reinterpret_cast(buf))) { - // TODO: Some packets may not have connection id - e->free(); - p->free(); - return; - } - QUICPacketType ptype = static_cast(buf[0] & 0x7f); if (ptype == QUICPacketType::INITIAL && !vc->read.triggered) { vc->read.triggered = 1; @@ -105,17 +98,8 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) void QUICPollCont::_process_short_header_packet(QUICPollEvent *e, NetHandler *nh) { - uint8_t *buf; UDPPacketInternal *p = e->packet; QUICNetVConnection *vc = static_cast(e->con); - buf = (uint8_t *)p->getIOBlockChain()->buf(); - - if (!QUICTypeUtil::has_connection_id(reinterpret_cast(buf))) { - // TODO: Some packets may not have connection id - p->free(); - e->free(); - return; - } vc->read.triggered = 1; vc->handle_received_packet(p); diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 8bafd4bb95a..acc313015ce 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -52,12 +52,6 @@ QUICTypeUtil::has_long_header(const uint8_t *buf) return (buf[0] & 0x80) != 0; } -bool -QUICTypeUtil::has_connection_id(const uint8_t *buf) -{ - return ((buf[0] & 0x80) != 0) || ((buf[0] & 0x40) == 0); -} - bool QUICTypeUtil::is_supported_version(QUICVersion version) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 278398d9dfb..02f9967784e 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -317,7 +317,6 @@ class QUICTypeUtil { public: [[deprecated]] static bool has_long_header(const uint8_t *buf); - [[deprecated]] static bool has_connection_id(const uint8_t *buf); static bool is_supported_version(QUICVersion version); static QUICStreamType detect_stream_type(QUICStreamId id); From 8b852ab59c9a5bb2b74e349f2d0d575248a84d8f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 18 Jun 2018 11:47:39 +0900 Subject: [PATCH 0630/1313] Cleanup: Change QUICTypeUtil::has_long_header(const uint8_t *) to QUICInvariants::is_long_header(const uint8_t *) --- iocore/net/QUICNet.cc | 6 ++++-- iocore/net/QUICPacketHandler.cc | 2 +- iocore/net/quic/QUICPacket.cc | 2 +- iocore/net/quic/QUICPacketReceiveQueue.cc | 4 ++-- iocore/net/quic/QUICTypes.cc | 6 ------ iocore/net/quic/QUICTypes.h | 1 - 6 files changed, 8 insertions(+), 13 deletions(-) diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index 319bbafeb7d..85682803fbd 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -143,9 +143,11 @@ QUICPollCont::pollEvent(int, Event *) while ((e = result.pop())) { buf = (uint8_t *)e->packet->getIOBlockChain()->buf(); - if (QUICTypeUtil::has_long_header(buf)) { // Long Header Packet with Connection ID, has a valid type value. + if (QUICInvariants::is_long_header(buf)) { + // Long Header Packet with Connection ID, has a valid type value. this->_process_long_header_packet(e, nh); - } else { // Short Header Packet with Connection ID, has a valid type value. + } else { + // Short Header Packet with Connection ID, has a valid type value. this->_process_short_header_packet(e, nh); } } diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index fe84d230737..ab2a5732290 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -240,7 +240,7 @@ 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 && !QUICTypeUtil::has_long_header(reinterpret_cast(block->buf()))) || (vc && vc->in_closed_queue)) { + if ((!vc && !QUICInvariants::is_long_header(buf)) || (vc && vc->in_closed_queue)) { QUICStatelessResetToken token; { QUICConfig::scoped_config params; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 6a8b7e8b13e..1ebed09f0a6 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -75,7 +75,7 @@ QUICPacketHeaderUPtr QUICPacketHeader::load(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base) { QUICPacketHeaderUPtr header = QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header); - if (QUICTypeUtil::has_long_header(buf.get())) { + if (QUICInvariants::is_long_header(buf.get())) { QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); new (long_header) QUICPacketLongHeader(from, std::move(buf), len, base); header = QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index c742118a147..3a7f435e2bb 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -98,11 +98,11 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) ats_unique_buf pkt = {nullptr, [](void *p) { ats_free(p); }}; size_t pkt_len = 0; - if (QUICTypeUtil::has_long_header(this->_payload.get())) { + if (QUICInvariants::is_long_header(this->_payload.get())) { uint8_t *buf = this->_payload.get() + this->_offset; size_t remaining_len = this->_payload_len - this->_offset; - if (QUICTypeUtil::has_long_header(buf)) { + if (QUICInvariants::is_long_header(buf)) { QUICVersion version = QUICTypeUtil::read_QUICVersion(buf + LONG_HDR_OFFSET_VERSION); if (is_vn(version)) { pkt_len = remaining_len; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index acc313015ce..5fd6336d5b5 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -46,12 +46,6 @@ to_hex_str(char *dst, size_t dst_len, const uint8_t *src, size_t src_len) return 0; } -bool -QUICTypeUtil::has_long_header(const uint8_t *buf) -{ - return (buf[0] & 0x80) != 0; -} - bool QUICTypeUtil::is_supported_version(QUICVersion version) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 02f9967784e..41b0efd98c8 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -316,7 +316,6 @@ class QUICFiveTuple class QUICTypeUtil { public: - [[deprecated]] static bool has_long_header(const uint8_t *buf); static bool is_supported_version(QUICVersion version); static QUICStreamType detect_stream_type(QUICStreamId id); From 4eb37f2589138b8c41c3fbca776c8373d75b75b1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 18 Jun 2018 14:04:29 +0900 Subject: [PATCH 0631/1313] Add encrypt_pn() and decrypt_pn() --- iocore/net/quic/Mock.h | 14 +++ iocore/net/quic/QUICHandshakeProtocol.h | 4 + iocore/net/quic/QUICTLS.cc | 97 ++++++++++++------- iocore/net/quic/QUICTLS.h | 11 ++- iocore/net/quic/QUICTLS_boringssl.cc | 17 ++++ iocore/net/quic/QUICTLS_openssl.cc | 75 ++++++++++++++ .../quic/test/test_QUICHandshakeProtocol.cc | 87 +++++++++++++++++ 7 files changed, 271 insertions(+), 34 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index fad20eb8b70..949399c0a47 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -576,6 +576,20 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol memcpy(plain, cipher, cipher_len); return true; } + + bool + encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, + const uint8_t *sample, QUICKeyPhase phase) const override + { + return true; + } + + bool + decrypt_pn(uint8_t *unprotected_pn, size_t &unprotected_pn_len, const uint8_t *protected_pn, size_t protected_pn_len, + const uint8_t *sample, QUICKeyPhase phase) const override + { + return true; + } }; void NetVConnection::cancel_OOB(){}; diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index e8760d333ec..145b7b76d1b 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -59,6 +59,10 @@ class QUICHandshakeProtocol uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; virtual bool decrypt(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, QUICKeyPhase phase) const = 0; + virtual bool encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, + const uint8_t *sample, QUICKeyPhase phase) const = 0; + virtual bool decrypt_pn(uint8_t *unprotected_pn, size_t &unprotected_pn_len, const uint8_t *protected_pn, size_t protected_pn_len, + const uint8_t *sample, QUICKeyPhase phase) const = 0; virtual QUICHandshakeMsgType msg_type() const; protected: diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 08cccf02c2c..4ac7d5660a0 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -308,24 +308,8 @@ bool QUICTLS::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const { - QUICPacketProtection *pp = nullptr; - - switch (this->_netvc_context) { - case NET_VCONNECTION_IN: { - pp = this->_server_pp; - break; - } - case NET_VCONNECTION_OUT: { - pp = this->_client_pp; - break; - } - default: - ink_assert(false); - return false; - } - size_t tag_len = this->_get_aead_tag_len(phase); - const KeyMaterial *km = pp->get_key(phase); + const KeyMaterial *km = this->_get_km(phase, true); if (!km) { Debug(tag, "Failed to encrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; @@ -343,32 +327,52 @@ bool QUICTLS::decrypt(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, QUICKeyPhase phase) const { - QUICPacketProtection *pp = nullptr; - - switch (this->_netvc_context) { - case NET_VCONNECTION_IN: { - pp = this->_client_pp; - break; + size_t tag_len = this->_get_aead_tag_len(phase); + const KeyMaterial *km = this->_get_km(phase, false); + if (!km) { + Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); + return false; } - case NET_VCONNECTION_OUT: { - pp = this->_server_pp; - break; + const QUIC_EVP_CIPHER *aead = this->_get_evp_aead(phase); + bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, *km, aead, tag_len); + if (!ret) { + Debug(tag, "Failed to decrypt a packet #%" PRIu64, pkt_num); } - default: - ink_assert(false); + return ret; +} + +bool +QUICTLS::encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, + const uint8_t *sample, QUICKeyPhase phase) const +{ + const KeyMaterial *km = this->_get_km(phase, true); + if (!km) { + Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } - size_t tag_len = this->_get_aead_tag_len(phase); - const KeyMaterial *km = pp->get_key(phase); + const QUIC_EVP_CIPHER *aead = this->_get_evp_aead_for_pne(phase); + bool ret = this->_encrypt_pn(protected_pn, protected_pn_len, unprotected_pn, unprotected_pn_len, sample, *km, aead); + if (!ret) { + Debug(tag, "Failed to encrypt a packet number"); + } + return ret; +} + +bool +QUICTLS::decrypt_pn(uint8_t *unprotected_pn, size_t &unprotected_pn_len, const uint8_t *protected_pn, size_t protected_pn_len, + const uint8_t *sample, QUICKeyPhase phase) const +{ + const KeyMaterial *km = this->_get_km(phase, false); if (!km) { Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } - const QUIC_EVP_CIPHER *aead = this->_get_evp_aead(phase); - bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, *km, aead, tag_len); + + const QUIC_EVP_CIPHER *aead = this->_get_evp_aead_for_pne(phase); + bool ret = this->_decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, *km, aead); if (!ret) { - Debug(tag, "Failed to decrypt a packet #%" PRIu64, pkt_num); + Debug(tag, "Failed to decrypt a packet number"); } return ret; } @@ -400,3 +404,30 @@ QUICTLS::_gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const u nonce[iv_len - 8 + i] ^= p[i]; } } + +const KeyMaterial * +QUICTLS::_get_km(QUICKeyPhase phase, bool for_encryption) const +{ + QUICPacketProtection *pp = nullptr; + + switch (this->_netvc_context) { + case NET_VCONNECTION_IN: + if (for_encryption) { + pp = this->_server_pp; + } else { + pp = this->_client_pp; + } + break; + case NET_VCONNECTION_OUT: + if (for_encryption) { + pp = this->_client_pp; + } else { + pp = this->_server_pp; + } + break; + default: + return nullptr; + } + + return pp->get_key(phase); +} diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index a221f9084bd..86d4db70c33 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -53,6 +53,10 @@ class QUICTLS : public QUICHandshakeProtocol const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override; bool decrypt(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, QUICKeyPhase phase) const override; + bool encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, + const uint8_t *sample, QUICKeyPhase phase) const override; + bool decrypt_pn(uint8_t *unprotected_pn, size_t &unprotected_pn_len, const uint8_t *protected_pn, size_t protected_pn_lenn, + const uint8_t *sample, QUICKeyPhase phase) const override; // FIXME SSL handle should not be exported SSL *ssl_handle(); @@ -62,14 +66,19 @@ class QUICTLS : public QUICHandshakeProtocol QUICKeyGenerator _keygen_for_server = QUICKeyGenerator(QUICKeyGenerator::Context::SERVER); void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; const QUIC_EVP_CIPHER *_get_evp_aead(QUICKeyPhase phase) const; + const QUIC_EVP_CIPHER *_get_evp_aead_for_pne(QUICKeyPhase phase) const; size_t _get_aead_tag_len(QUICKeyPhase phase) const; + const KeyMaterial *_get_km(QUICKeyPhase phase, bool for_encryption) const; bool _encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead, size_t tag_len) const; bool _decrypt(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 KeyMaterial &km, const QUIC_EVP_CIPHER *aead, size_t tag_len) const; - + bool _encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, + const uint8_t *sample, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead) const; + bool _decrypt_pn(uint8_t *unprotected_pn, size_t &unprotected_pn_len, const uint8_t *protected_pn, size_t protected_pn_len, + const uint8_t *sample, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead) const; SSL *_ssl = nullptr; QUICPacketProtection *_client_pp = nullptr; QUICPacketProtection *_server_pp = nullptr; diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc index 081a12fd98d..2e14f6ba6f3 100644 --- a/iocore/net/quic/QUICTLS_boringssl.cc +++ b/iocore/net/quic/QUICTLS_boringssl.cc @@ -131,3 +131,20 @@ QUICTLS::_decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const return true; } + +bool +QUICTLS::_encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, + const uint8_t *sample, const KeyMaterial &km, const EVP_AEAD *aead) +{ + { + ink_assert(!"not implemented"); + return false; + } + + bool QUICTLS::_decrypt_pn(uint8_t * protected_pn, size_t & protected_pn_len, const uint8_t *unprotected_pn, + size_t unprotected_pn_len, const uint8_t *sample, const KeyMaterial &km, const EVP_AEAD *aead) + { + { + ink_assert(!"not implemented"); + return false; + } diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index c92116aed47..0aae1d5f904 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -59,6 +59,35 @@ QUICTLS::_get_evp_aead(QUICKeyPhase phase) const } } +const EVP_CIPHER * +QUICTLS::_get_evp_aead_for_pne(QUICKeyPhase phase) const +{ + if (phase == QUICKeyPhase::CLEARTEXT) { + return EVP_aes_128_ctr(); + } else { + const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); + if (cipher) { + switch (SSL_CIPHER_get_id(cipher)) { + case TLS1_3_CK_AES_128_GCM_SHA256: + return EVP_aes_128_ctr(); + case TLS1_3_CK_AES_256_GCM_SHA384: + return EVP_aes_256_ctr(); + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + return EVP_chacha20(); + case TLS1_3_CK_AES_128_CCM_SHA256: + case TLS1_3_CK_AES_128_CCM_8_SHA256: + return EVP_aes_128_ctr(); + default: + ink_assert(false); + return nullptr; + } + } else { + ink_assert(false); + return nullptr; + } + } +} + size_t QUICTLS::_get_aead_tag_len(QUICKeyPhase phase) const { @@ -191,3 +220,49 @@ QUICTLS::_decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const return false; } } + +bool +QUICTLS::_encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, + const uint8_t *sample, const KeyMaterial &km, const EVP_CIPHER *aead) const +{ + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + int len = 0; + + if (!ctx || !EVP_EncryptInit_ex(ctx, aead, nullptr, km.pn, sample)) { + return false; + } + if (!EVP_EncryptUpdate(ctx, protected_pn, &len, unprotected_pn, unprotected_pn_len)) { + return false; + } + protected_pn_len = len; + if (!EVP_EncryptFinal_ex(ctx, protected_pn + len, &len)) { + return false; + } + protected_pn_len += len; + EVP_CIPHER_CTX_free(ctx); + + return true; +} + +bool +QUICTLS::_decrypt_pn(uint8_t *unprotected_pn, size_t &unprotected_pn_len, const uint8_t *protected_pn, size_t protected_pn_len, + const uint8_t *sample, const KeyMaterial &km, const EVP_CIPHER *aead) const +{ + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + int len = 0; + + if (!ctx || !EVP_DecryptInit_ex(ctx, aead, nullptr, km.pn, sample)) { + return false; + } + if (!EVP_DecryptUpdate(ctx, unprotected_pn, &len, protected_pn, protected_pn_len)) { + return false; + } + unprotected_pn_len = len; + if (!EVP_DecryptFinal_ex(ctx, unprotected_pn, &len)) { + return false; + } + unprotected_pn_len += len; + EVP_CIPHER_CTX_free(ctx); + + return true; +} diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index a41dd612fd5..0e0d3f426e5 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -596,3 +596,90 @@ TEST_CASE("QUICHandshakeProtocol 1-RTT HRR statless & key_share mismatch", "[qui delete client; delete server; } + +TEST_CASE("QUICHandshakeProtocol PNE", "[quic]") +{ + // Client + SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + + // Server + SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); + SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); + BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); + SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); + QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + + uint8_t expected[] = {0x01, 0x02, 0x03, 0x04, 0x05}; + uint8_t sample[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; + uint8_t protected_pn[18], unprotected_pn[18]; + size_t protected_pn_len = 0, unprotected_pn_len = 0; + + // # Before handshake + CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + + // ## Client -> Server + client->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::CLEARTEXT); + server->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::CLEARTEXT); + CHECK(unprotected_pn_len == sizeof(expected)); + CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); + // ## Server -> Client + server->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::CLEARTEXT); + client->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::CLEARTEXT); + CHECK(unprotected_pn_len == sizeof(expected)); + CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); + + // # After handshake + uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t client_hello_len = 0; + CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); + std::cout << "### Client Hello" << std::endl; + print_hex(client_hello, client_hello_len); + + // Server Hello + uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t server_hello_len = 0; + CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == + SSL_ERROR_WANT_READ); + std::cout << "### Server Hello" << std::endl; + print_hex(server_hello, server_hello_len); + + // Client Fnished + uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t client_finished_len = 0; + CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == + SSL_ERROR_NONE); + std::cout << "### Client Finished" << std::endl; + print_hex(client_finished, client_finished_len); + + CHECK(client->update_key_materials()); + + // Post Handshake Msg + uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; + size_t post_handshake_msg_len = 0; + CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, + client_finished_len) == SSL_ERROR_NONE); + std::cout << "### Post Handshake Message" << std::endl; + print_hex(post_handshake_msg, post_handshake_msg_len); + + CHECK(server->update_key_materials()); + + // ## Client -> Server + client->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::CLEARTEXT); + server->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::CLEARTEXT); + CHECK(unprotected_pn_len == sizeof(expected)); + CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); + // ## Server -> Client + server->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::CLEARTEXT); + client->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::CLEARTEXT); + CHECK(unprotected_pn_len == sizeof(expected)); + CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); +} From c64b47636d9aa4b42b38c56c4dd5fe75fb925d98 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 18 Jun 2018 14:12:10 +0900 Subject: [PATCH 0632/1313] Fix key pahses for PNE tests --- iocore/net/quic/test/test_QUICHandshakeProtocol.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 0e0d3f426e5..096b9c9c4c3 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -673,13 +673,13 @@ TEST_CASE("QUICHandshakeProtocol PNE", "[quic]") CHECK(server->update_key_materials()); // ## Client -> Server - client->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::CLEARTEXT); - server->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::CLEARTEXT); + client->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); + server->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); CHECK(unprotected_pn_len == sizeof(expected)); CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); // ## Server -> Client - server->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::CLEARTEXT); - client->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::CLEARTEXT); + server->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); + client->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); CHECK(unprotected_pn_len == sizeof(expected)); CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); } From 9ba6ff7af72a68b470d361092825dfa196fa64f9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 18 Jun 2018 16:17:57 +0900 Subject: [PATCH 0633/1313] [draft-11] Initialize min_rtt with INT64_MAX --- iocore/net/quic/QUICConfig.h | 4 ++-- iocore/net/quic/QUICCongestionController.cc | 2 +- iocore/net/quic/QUICLossDetector.cc | 1 + iocore/net/quic/QUICLossDetector.h | 10 +++++----- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 204cc18ff50..1c0d46692bc 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -98,7 +98,7 @@ class QUICConfigParams : public ConfigInfo SSL_CTX *_server_ssl_ctx = nullptr; SSL_CTX *_client_ssl_ctx = nullptr; - // [draft-10 recovery] - 3.4.1. Constants of interest + // [draft-11 recovery] 3.5.1. Constants of interest uint32_t _ld_max_tlps = 2; uint32_t _ld_reordering_threshold = 3; float _ld_time_reordering_fraction = 0.125; @@ -108,7 +108,7 @@ class QUICConfigParams : public ConfigInfo ink_hrtime _ld_delayed_ack_timeout = HRTIME_MSECONDS(25); ink_hrtime _ld_default_initial_rtt = HRTIME_MSECONDS(100); - // [draft-10 recovery] - 4.7.1. Constants of interest + // [draft-11 recovery] 4.7.1. Constants of interest uint32_t _cc_default_mss = 1460; uint32_t _cc_initial_window_scale = 10; // Actual initial window size is this value multiplied by the _cc_default_mss uint32_t _cc_minimum_window_scale = 2; // Actual minimum window size is this value multiplied by the _cc_default_mss diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index fa580e6adfa..098809de64d 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -46,7 +46,7 @@ QUICCongestionController::QUICCongestionController(QUICConnectionInfoProvider *i this->_k_minimum_window = params->cc_minimum_window(); this->_k_loss_reduction_factor = params->cc_loss_reduction_factor(); - // 4.7.3. Initialization + // [draft-11 recovery] 4.7.3. Initialization this->_congestion_window = this->_k_initial_window; } diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index b19b133e9e4..89ce1f73fd9 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -47,6 +47,7 @@ QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConne this->_k_delayed_ack_timeout = params->ld_delayed_ack_timeout(); this->_k_default_initial_rtt = params->ld_default_initial_rtt(); + // [draft-11 recovery] 3.5.3. Initialization if (this->_k_using_time_loss_detection) { this->_reordering_threshold = UINT32_MAX; this->_time_reordering_fraction = this->_k_time_reordering_fraction; diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index c8a1deb88f5..156db8c07fe 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -72,14 +72,14 @@ class QUICCongestionController uint32_t current_ssthresh() const; private: - // 4.7.1. Constants of interest (draft-10) + // [draft-11 recovery] 4.7.1. Constants of interest // Values will be loaded from records.config via QUICConfig at constructor uint32_t _k_default_mss = 0; uint32_t _k_initial_window = 0; uint32_t _k_minimum_window = 0; float _k_loss_reduction_factor = 0.0; - // 4.7.2. Variables of interest + // [draft-11 recovery] 4.7.2. Variables of interest uint32_t _bytes_in_flight = 0; uint32_t _congestion_window = 0; QUICPacketNumber _end_of_recovery = 0; @@ -111,7 +111,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU // TODO QUICCongestionController *cc = nullptr; - // 3.4.1. Constants of interest (draft-10) + // [draft-11 recovery] 3.5.1. Constants of interest // Values will be loaded from records.config via QUICConfig at constructor uint32_t _k_max_tlps = 0; uint32_t _k_reordering_threshold = 0; @@ -122,7 +122,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU ink_hrtime _k_delayed_ack_timeout = 0; ink_hrtime _k_default_initial_rtt = 0; - // 3.4.2. Variables of interest (draft-10) + // [draft-11 recovery] 3.5.2. Variables of interest // Keep the order as the same as the spec so that we can see the difference easily. Action *_loss_detection_alarm = nullptr; uint32_t _handshake_count = 0; @@ -135,7 +135,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU ink_hrtime _latest_rtt = 0; ink_hrtime _smoothed_rtt = 0; ink_hrtime _rttvar = 0; - ink_hrtime _min_rtt = 0; + ink_hrtime _min_rtt = INT64_MAX; ink_hrtime _max_ack_delay = 0; uint32_t _reordering_threshold = 0; double _time_reordering_fraction = 0.0; From f48b47bdbf22ce37958bf7b23a7df5be6e5357c6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 19 Jun 2018 14:59:28 +0900 Subject: [PATCH 0634/1313] [draft-11] Add time_of_last_sent_handshake_packet --- iocore/net/quic/QUICLossDetector.cc | 17 ++++++++++----- iocore/net/quic/QUICLossDetector.h | 33 +++++++++++++++-------------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 89ce1f73fd9..36d627982f3 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -170,14 +170,19 @@ QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_ack_on QUICPacketUPtr packet) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - this->_time_of_last_sent_packet = Thread::get_hrtime(); - this->_largest_sent_packet = packet_number; + ink_hrtime now = Thread::get_hrtime(); + this->_largest_sent_packet = packet_number; // FIXME Should we really keep actual packet object? std::unique_ptr packet_info( - new PacketInfo({packet_number, this->_time_of_last_sent_packet, is_ack_only, is_handshake, sent_bytes, std::move(packet)})); + new PacketInfo({packet_number, now, is_ack_only, is_handshake, sent_bytes, std::move(packet)})); this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); + if (!is_ack_only) { + if (is_handshake) { + this->_time_of_last_sent_handshake_packet = now; + } + this->_time_of_last_sent_retransmittable_packet = now; this->_cc->on_packet_sent(sent_bytes); this->_set_loss_detection_alarm(); } @@ -293,10 +298,12 @@ QUICLossDetector::_set_loss_detection_alarm() } alarm_duration = std::max(alarm_duration + this->_max_ack_delay, this->_k_min_tlp_timeout); alarm_duration = alarm_duration * (1 << this->_handshake_count); + + this->_loss_detection_alarm_at = this->_time_of_last_sent_handshake_packet + alarm_duration; QUICLDDebug("Handshake retransmission alarm will be set"); } else if (this->_loss_time != 0) { // Early retransmit timer or time loss detection. - alarm_duration = this->_loss_time - this->_time_of_last_sent_packet; + alarm_duration = this->_loss_time - this->_time_of_last_sent_retransmittable_packet; QUICLDDebug("Early retransmit timer or time loss detection will be set"); } else if (this->_tlp_count < this->_k_max_tlps) { // Tail Loss Probe @@ -321,7 +328,7 @@ QUICLossDetector::_set_loss_detection_alarm() if (this->_loss_detection_alarm_at) { this->_loss_detection_alarm_at = std::min(this->_loss_detection_alarm_at, Thread::get_hrtime() + alarm_duration); } else { - this->_loss_detection_alarm_at = this->_time_of_last_sent_packet + alarm_duration; + this->_loss_detection_alarm_at = this->_time_of_last_sent_retransmittable_packet + alarm_duration; } QUICLDDebug("Loss detection alarm has been set to %" PRId64 "ms", alarm_duration / HRTIME_MSECOND); diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 156db8c07fe..69f811f6b83 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -124,22 +124,23 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU // [draft-11 recovery] 3.5.2. Variables of interest // Keep the order as the same as the spec so that we can see the difference easily. - Action *_loss_detection_alarm = nullptr; - uint32_t _handshake_count = 0; - uint32_t _tlp_count = 0; - uint32_t _rto_count = 0; - uint32_t _largest_sent_before_rto = 0; - ink_hrtime _time_of_last_sent_packet = 0; - uint32_t _largest_sent_packet = 0; - uint32_t _largest_acked_packet = 0; - ink_hrtime _latest_rtt = 0; - ink_hrtime _smoothed_rtt = 0; - ink_hrtime _rttvar = 0; - ink_hrtime _min_rtt = INT64_MAX; - ink_hrtime _max_ack_delay = 0; - uint32_t _reordering_threshold = 0; - double _time_reordering_fraction = 0.0; - ink_hrtime _loss_time = 0; + Action *_loss_detection_alarm = nullptr; + uint32_t _handshake_count = 0; + uint32_t _tlp_count = 0; + uint32_t _rto_count = 0; + uint32_t _largest_sent_before_rto = 0; + ink_hrtime _time_of_last_sent_retransmittable_packet = 0; + ink_hrtime _time_of_last_sent_handshake_packet = 0; + uint32_t _largest_sent_packet = 0; + uint32_t _largest_acked_packet = 0; + ink_hrtime _latest_rtt = 0; + ink_hrtime _smoothed_rtt = 0; + ink_hrtime _rttvar = 0; + ink_hrtime _min_rtt = INT64_MAX; + ink_hrtime _max_ack_delay = 0; + uint32_t _reordering_threshold = 0; + double _time_reordering_fraction = 0.0; + ink_hrtime _loss_time = 0; std::map> _sent_packets; // These are not defined on the spec but expected to be count From 499aa73bab749ba1007e4849b1b2b789ebda5138 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 19 Jun 2018 17:21:16 +0900 Subject: [PATCH 0635/1313] Chaange type of packet number length parameters --- iocore/net/quic/QUICHandshakeProtocol.h | 8 ++++---- iocore/net/quic/QUICTLS.cc | 4 ++-- iocore/net/quic/QUICTLS.h | 8 ++++---- iocore/net/quic/QUICTLS_openssl.cc | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 145b7b76d1b..0701c4d4c5b 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -59,10 +59,10 @@ class QUICHandshakeProtocol uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; virtual bool decrypt(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, QUICKeyPhase phase) const = 0; - virtual bool encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, - const uint8_t *sample, QUICKeyPhase phase) const = 0; - virtual bool decrypt_pn(uint8_t *unprotected_pn, size_t &unprotected_pn_len, const uint8_t *protected_pn, size_t protected_pn_len, - const uint8_t *sample, QUICKeyPhase phase) const = 0; + virtual bool encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, + uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const = 0; + virtual bool decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, + uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const = 0; virtual QUICHandshakeMsgType msg_type() const; protected: diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 4ac7d5660a0..09250c301b4 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -342,7 +342,7 @@ QUICTLS::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const } bool -QUICTLS::encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, +QUICTLS::encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const { const KeyMaterial *km = this->_get_km(phase, true); @@ -360,7 +360,7 @@ QUICTLS::encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8 } bool -QUICTLS::decrypt_pn(uint8_t *unprotected_pn, size_t &unprotected_pn_len, const uint8_t *protected_pn, size_t protected_pn_len, +QUICTLS::decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const { const KeyMaterial *km = this->_get_km(phase, false); diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 86d4db70c33..ec2c9dffdb0 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -53,9 +53,9 @@ class QUICTLS : public QUICHandshakeProtocol const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override; bool decrypt(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, QUICKeyPhase phase) const override; - bool encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, + bool encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const override; - bool decrypt_pn(uint8_t *unprotected_pn, size_t &unprotected_pn_len, const uint8_t *protected_pn, size_t protected_pn_lenn, + bool decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const override; // FIXME SSL handle should not be exported @@ -75,9 +75,9 @@ class QUICTLS : public QUICHandshakeProtocol size_t tag_len) const; bool _decrypt(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 KeyMaterial &km, const QUIC_EVP_CIPHER *aead, size_t tag_len) const; - bool _encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, + bool _encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, const uint8_t *sample, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead) const; - bool _decrypt_pn(uint8_t *unprotected_pn, size_t &unprotected_pn_len, const uint8_t *protected_pn, size_t protected_pn_len, + bool _decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, const uint8_t *sample, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead) const; SSL *_ssl = nullptr; QUICPacketProtection *_client_pp = nullptr; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 0aae1d5f904..a1030b03956 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -222,7 +222,7 @@ QUICTLS::_decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const } bool -QUICTLS::_encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, +QUICTLS::_encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, const uint8_t *sample, const KeyMaterial &km, const EVP_CIPHER *aead) const { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); @@ -245,7 +245,7 @@ QUICTLS::_encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint } bool -QUICTLS::_decrypt_pn(uint8_t *unprotected_pn, size_t &unprotected_pn_len, const uint8_t *protected_pn, size_t protected_pn_len, +QUICTLS::_decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, const uint8_t *sample, const KeyMaterial &km, const EVP_CIPHER *aead) const { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); From 3ffa6b252cb5d60a2a738648d13ae61676e16673 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 19 Jun 2018 17:23:16 +0900 Subject: [PATCH 0636/1313] Print keys for packet number encryption --- iocore/net/quic/QUICTLS.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 09250c301b4..8784c94e734 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -194,6 +194,8 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) Debug("vv_quic_crypto", "client key 0x%s", print_buf); to_hex(print_buf, km->iv, km->iv_len); Debug("vv_quic_crypto", "client iv 0x%s", print_buf); + to_hex(print_buf, km->pn, km->pn_len); + Debug("vv_quic_crypto", "client pn 0x%s", print_buf); } this->_client_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); @@ -203,6 +205,8 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) Debug("vv_quic_crypto", "server key 0x%s", print_buf); to_hex(print_buf, km->iv, km->iv_len); Debug("vv_quic_crypto", "server iv 0x%s", print_buf); + to_hex(print_buf, km->pn, km->pn_len); + Debug("vv_quic_crypto", "server pn 0x%s", print_buf); } this->_server_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); From 9a0f6635e8c251ad7fdb44f7f4b6d90204afeaff Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 19 Jun 2018 17:27:51 +0900 Subject: [PATCH 0637/1313] Add static accessor methods for QUICPacket header fields --- iocore/net/quic/QUICPacket.cc | 104 +++++++++++++++++++++++++++++----- iocore/net/quic/QUICPacket.h | 14 +++++ iocore/net/quic/QUICTypes.h | 6 ++ 3 files changed, 110 insertions(+), 14 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 1ebed09f0a6..ca3bc45c590 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -186,18 +186,80 @@ QUICPacketType QUICPacketLongHeader::type() const { if (this->_buf) { - uint8_t type = this->_buf.get()[0] & 0x7F; - if (this->version() == 0x00) { - return QUICPacketType::VERSION_NEGOTIATION; - } else { - // any other version-specific type? - return static_cast(type); - } + QUICPacketType type; + QUICPacketLongHeader::type(type, this->_buf.get(), this->_buf_len); + return type; } else { return this->_type; } } +bool +QUICPacketLongHeader::type(QUICPacketType &type, const uint8_t *packet, size_t packet_len) +{ + if (packet_len < 1) { + return false; + } + + uint8_t raw_type = packet[0] & 0x7F; + QUICVersion version; + if (QUICPacketLongHeader::version(version, packet, packet_len) && version == 0x00) { + type = QUICPacketType::VERSION_NEGOTIATION; + } else { + type = static_cast(raw_type); + } + return true; +} + +bool +QUICPacketLongHeader::version(QUICVersion &version, const uint8_t *packet, size_t packet_len) +{ + if (packet_len < 5) { + return false; + } + + version = QUICTypeUtil::read_QUICVersion(packet + LONG_HDR_OFFSET_VERSION); + return true; +} + +bool +QUICPacketLongHeader::dcil(uint8_t &dcil, const uint8_t *packet, size_t packet_len) +{ + if (QUICInvariants::dcil(dcil, packet, packet_len)) { + dcil += 3; + 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)) { + scil += 3; + return true; + } else { + return false; + } +} + +bool +QUICPacketLongHeader::payload_length(size_t &length, uint8_t *field_len, const uint8_t *packet, size_t packet_len) +{ + uint8_t dcil, scil; + + QUICPacketLongHeader::dcil(dcil, packet, packet_len); + QUICPacketLongHeader::scil(scil, packet, packet_len); + + size_t payload_len_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; + length = QUICIntUtil::read_QUICVariableInt(packet + payload_len_offset); + if (field_len) { + *field_len = QUICVariableInt::size(packet + payload_len_offset); + } + return true; +} + QUICConnectionId QUICPacketLongHeader::destination_cid() const { @@ -242,7 +304,9 @@ QUICVersion QUICPacketLongHeader::version() const { if (this->_buf) { - return QUICTypeUtil::read_QUICVersion(this->_buf.get() + LONG_HDR_OFFSET_VERSION); + QUICVersion version; + QUICPacketLongHeader::version(version, this->_buf.get(), this->_buf_len); + return version; } else { return this->_version; } @@ -437,16 +501,28 @@ QUICKeyPhase QUICPacketShortHeader::key_phase() const { if (this->_buf) { - if (this->_buf.get()[0] & 0x40) { - return QUICKeyPhase::PHASE_1; - } else { - return QUICKeyPhase::PHASE_0; - } + QUICKeyPhase phase; + QUICPacketShortHeader::key_phase(phase, this->_buf.get(), this->_buf_len); + return phase; } else { - return _key_phase; + return this->_key_phase; } } +bool +QUICPacketShortHeader::key_phase(QUICKeyPhase &phase, const uint8_t *packet, size_t packet_len) +{ + if (packet_len < 1) { + return false; + } + if (packet[0] & 0x40) { + phase = QUICKeyPhase::PHASE_1; + } else { + phase = QUICKeyPhase::PHASE_0; + } + return true; +} + /** * Header Length (doesn't include payload length) */ diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 0245f3e2990..bf6cfb7f55c 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -190,6 +190,18 @@ class QUICPacketLongHeader : public QUICPacketHeader uint16_t size() const; void store(uint8_t *buf, size_t *len) 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); + /** + * Unlike QUICInvariants::dcil(), this returns actual connection id length + */ + static bool dcil(uint8_t &dcil, const uint8_t *packet, size_t packet_len); + /** + * Unlike QUICInvariants::scil(), this returns actual connection id length + */ + static bool scil(uint8_t &scil, const uint8_t *packet, size_t packet_len); + static bool payload_length(size_t &payload_length, uint8_t *field_len, const uint8_t *packet, size_t packet_len); + private: QUICPacketNumber _packet_number; QUICConnectionId _destination_cid = QUICConnectionId::ZERO(); @@ -224,6 +236,8 @@ class QUICPacketShortHeader : public QUICPacketHeader uint16_t size() const; void store(uint8_t *buf, size_t *len) const; + static bool key_phase(QUICKeyPhase &key_phase, const uint8_t *packet, size_t packet_len); + private: int _packet_number_len; }; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 41b0efd98c8..c7b3f42f112 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -347,7 +347,13 @@ class QUICInvariants static bool is_long_header(const uint8_t *buf); static bool is_version_negotiation(QUICVersion v); static bool version(QUICVersion &dst, const uint8_t *buf, uint64_t buf_len); + /** + * This function returns the raw value. You'll need to add 3 to the returned value to get the actual connection id length. + */ static bool dcil(uint8_t &dst, const uint8_t *buf, uint64_t buf_len); + /** + * This function returns the raw value. You'll need to add 3 to the returned value to get the actual connection id length. + */ static bool scil(uint8_t &dst, const uint8_t *buf, uint64_t buf_len); static bool dcid(QUICConnectionId &dst, const uint8_t *buf, uint64_t buf_len); static bool scid(QUICConnectionId &dst, const uint8_t *buf, uint64_t buf_len); From c753466bb394ea4b25b91b8792020e8fc07c8d6c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 19 Jun 2018 17:30:17 +0900 Subject: [PATCH 0638/1313] Add QUICPacketNumberProtector --- iocore/net/P_QUICNetVConnection.h | 3 +- iocore/net/QUICNetVConnection.cc | 1 + iocore/net/quic/QUICHandshakeProtocol.cc | 26 +++++++ iocore/net/quic/QUICHandshakeProtocol.h | 17 +++++ iocore/net/quic/QUICPacketReceiveQueue.cc | 90 +++++++++++++++++------ iocore/net/quic/QUICPacketReceiveQueue.h | 5 +- 6 files changed, 119 insertions(+), 23 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e3ba5822b00..543b3304ffd 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -246,6 +246,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICFrameFactory _frame_factory; QUICAckFrameCreator _ack_frame_creator; QUICPacketRetransmitter _packet_retransmitter; + QUICPacketNumberProtector _pn_protector; QUICApplicationMap *_application_map = nullptr; uint32_t _pmtu = 1280; @@ -266,7 +267,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICAltConnectionManager *_alt_con_manager = nullptr; QUICPathValidator *_path_validator = nullptr; - QUICPacketReceiveQueue _packet_recv_queue = {this->_packet_factory}; + QUICPacketReceiveQueue _packet_recv_queue = {this->_packet_factory, this->_pn_protector}; CountQueue _packet_send_queue; QUICConnectionErrorUPtr _connection_error = nullptr; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b17d93c23e6..8e3967685c6 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -211,6 +211,7 @@ QUICNetVConnection::start() this->_hs_protocol = this->_handshake_handler->protocol(); this->_frame_dispatcher = new QUICFrameDispatcher(this); this->_packet_factory.set_hs_protocol(this->_hs_protocol); + this->_pn_protector.set_hs_protocol(this->_hs_protocol); // Create frame handlers this->_congestion_controller = new QUICCongestionController(this); diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index 8d463700f4e..94bf852a245 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -77,6 +77,32 @@ QUICPacketProtection::key_phase() const return this->_key_phase; } +// +// QUICPacketNumberProtector +// + +bool +QUICPacketNumberProtector::protect(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, + uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const +{ + // FIXME HandshakeProtocol shouldn't do this. The logic should be moved from there to here. + return this->_hs_protocol->encrypt_pn(protected_pn, protected_pn_len, unprotected_pn, unprotected_pn_len, sample, phase); +} + +bool +QUICPacketNumberProtector::unprotect(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, + uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const +{ + // FIXME HandshakeProtocol shouldn't do this. The logic should be moved from there to here. + return this->_hs_protocol->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, phase); +} + +void +QUICPacketNumberProtector::set_hs_protocol(QUICHandshakeProtocol *hs_protocol) +{ + this->_hs_protocol = hs_protocol; +} + // // QUICHandshakeProtocol // diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 0701c4d4c5b..aec814c4288 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -26,6 +26,8 @@ #include "QUICKeyGenerator.h" #include "QUICTypes.h" +class QUICHandshakeProtocol; + class QUICPacketProtection { public: @@ -43,6 +45,21 @@ class QUICPacketProtection QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; }; +class QUICPacketNumberProtector +{ +public: + bool protect(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, + const uint8_t *sample, QUICKeyPhase phase) const; + bool unprotect(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, + const uint8_t *sample, QUICKeyPhase phase) const; + + // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICPacketProtection instead. + void set_hs_protocol(QUICHandshakeProtocol *hs_protocol); + +private: + QUICHandshakeProtocol *_hs_protocol = nullptr; +}; + class QUICHandshakeProtocol { public: diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 3a7f435e2bb..4fd2ad3348f 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -24,11 +24,10 @@ #include "QUICPacketReceiveQueue.h" #include "QUICIntUtil.h" +#include "QUICConfig.h" // FIXME: workaround for coalescing packets -static constexpr int LONG_HDR_OFFSET_VERSION = 1; static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6; -static constexpr int LONG_HDR_PKT_NUM_LEN = 4; static bool is_vn(QUICVersion v) @@ -39,27 +38,22 @@ is_vn(QUICVersion v) static size_t long_hdr_pkt_len(uint8_t *buf) { - uint8_t dcil = (buf[5] >> 4); - if (dcil) { - dcil += 3; - } - uint8_t scil = (buf[5] & 0x0F); - if (scil) { - scil += 3; - } - size_t offset = LONG_HDR_OFFSET_CONNECTION_ID; - offset += dcil; - offset += scil; + uint8_t dcil, scil; + QUICPacketLongHeader::dcil(dcil, buf, 6); + QUICPacketLongHeader::scil(scil, buf, 6); - size_t payload_len = QUICIntUtil::read_QUICVariableInt(buf + offset); - offset += QUICVariableInt::size(buf + offset); - offset += LONG_HDR_PKT_NUM_LEN; - offset += payload_len; + size_t payload_len_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; - return offset; + size_t payload_len; + uint8_t payload_len_field_len; + QUICPacketLongHeader::payload_length(payload_len, &payload_len_field_len, buf, payload_len_offset + 4); + return payload_len_offset + payload_len_field_len + QUICTypeUtil::read_QUICPacketNumberLen(buf) + payload_len; } -QUICPacketReceiveQueue::QUICPacketReceiveQueue(QUICPacketFactory &packet_factory) : _packet_factory(packet_factory) {} +QUICPacketReceiveQueue::QUICPacketReceiveQueue(QUICPacketFactory &packet_factory, QUICPacketNumberProtector &pn_protector) + : _packet_factory(packet_factory), _pn_protector(pn_protector) +{ +} void QUICPacketReceiveQueue::enqueue(UDPPacket *packet) @@ -103,7 +97,8 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) size_t remaining_len = this->_payload_len - this->_offset; if (QUICInvariants::is_long_header(buf)) { - QUICVersion version = QUICTypeUtil::read_QUICVersion(buf + LONG_HDR_OFFSET_VERSION); + QUICVersion version; + QUICPacketLongHeader::version(version, buf, remaining_len); if (is_vn(version)) { pkt_len = remaining_len; } else if (!QUICTypeUtil::is_supported_version(version)) { @@ -142,7 +137,11 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) this->_offset = 0; } - quic_packet = this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->_largest_received_packet_number, result); + if (this->_unprotect_packet_number(pkt.get(), pkt_len)) { + quic_packet = this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->_largest_received_packet_number, result); + } else { + result = QUICPacketCreationResult::FAILED; + } if (udp_packet) { udp_packet->free(); @@ -179,3 +178,52 @@ QUICPacketReceiveQueue::reset() { this->_largest_received_packet_number = 0; } + +bool +QUICPacketReceiveQueue::_unprotect_packet_number(uint8_t *packet, size_t packet_len) +{ + size_t pn_offset = 0; + uint8_t pn_len = 4; + size_t sample_offset = 0; + uint8_t sample_len = 0; + constexpr int aead_expansion = 16; // Currently, AEAD expansion (which is probably AEAD tag) length is always 16 + int connection_id_len = QUICConfigParams::scid_len(); + QUICKeyPhase phase; + + if (QUICInvariants::is_long_header(packet)) { + QUICPacketType type; + QUICPacketLongHeader::type(type, packet, packet_len); + switch (type) { + case QUICPacketType::ZERO_RTT_PROTECTED: + phase = QUICKeyPhase::ZERORTT; + break; + default: + phase = QUICKeyPhase::CLEARTEXT; + break; + } + + uint8_t dcil, scil; + size_t payload_length; + uint8_t payload_length_field_len; + if (!QUICPacketLongHeader::dcil(dcil, packet, packet_len) || !QUICPacketLongHeader::scil(scil, packet, packet_len) || + !QUICPacketLongHeader::payload_length(payload_length, &payload_length_field_len, packet, packet_len)) { + return false; + } + pn_offset = 6 + dcil + scil + payload_length_field_len; + } else { + QUICPacketShortHeader::key_phase(phase, packet, packet_len); + pn_offset = 1 + connection_id_len; + } + sample_offset = std::min(pn_offset + 4, packet_len - aead_expansion); + sample_len = 16; // On draft-12, the length is always 16 (See 5.6.1 and 5.6.2) + + uint8_t unprotected_pn[4] = {0}; + uint8_t unprotected_pn_len = 0; + if (!this->_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, packet + pn_offset, pn_len, packet + sample_offset, + phase)) { + return false; + } + unprotected_pn_len = QUICTypeUtil::read_QUICPacketNumberLen(unprotected_pn); + memcpy(packet + pn_offset, unprotected_pn, unprotected_pn_len); + return true; +} diff --git a/iocore/net/quic/QUICPacketReceiveQueue.h b/iocore/net/quic/QUICPacketReceiveQueue.h index 6349d261b6b..230fc8a3352 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.h +++ b/iocore/net/quic/QUICPacketReceiveQueue.h @@ -31,7 +31,7 @@ class QUICPacketReceiveQueue { public: - QUICPacketReceiveQueue(QUICPacketFactory &packet_factory); + QUICPacketReceiveQueue(QUICPacketFactory &packet_factory, QUICPacketNumberProtector &pn_protector); void enqueue(UDPPacket *packet); QUICPacketUPtr dequeue(QUICPacketCreationResult &result); @@ -41,10 +41,13 @@ class QUICPacketReceiveQueue private: CountQueue _queue; QUICPacketFactory &_packet_factory; + QUICPacketNumberProtector &_pn_protector; QUICPacketNumber _largest_received_packet_number = 0; // FIXME: workaround code for coalescing packets ats_unique_buf _payload = {nullptr, [](void *p) { ats_free(p); }}; size_t _payload_len = 0; size_t _offset = 0; IpEndpoint _from; + + bool _unprotect_packet_number(uint8_t *packet, size_t packet_len); }; From 41a18db2392dbec17d7cf7a3e8c77e2b47f2c7e2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 20 Jun 2018 12:22:25 +0900 Subject: [PATCH 0639/1313] Reset CongestionController when QUICNetVC need to discard all transport state --- iocore/net/QUICNetVConnection.cc | 2 ++ iocore/net/quic/QUICCongestionController.cc | 13 ++++++++++-- iocore/net/quic/QUICLossDetector.cc | 23 +++++++++++---------- iocore/net/quic/QUICLossDetector.h | 1 + 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8e3967685c6..77f2a779195 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -882,6 +882,7 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack this->_stream_manager->reset_send_offset(); this->_stream_manager->reset_recv_offset(); this->_loss_detector->reset(); + this->_congestion_controller->reset(); SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); this->_packet_retransmitter.reset(); @@ -921,6 +922,7 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) // discard all transport state this->_stream_manager->reset_send_offset(); this->_loss_detector->reset(); + this->_congestion_controller->reset(); SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); this->_packet_retransmitter.reset(); diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 098809de64d..70510a8594d 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -46,8 +46,7 @@ QUICCongestionController::QUICCongestionController(QUICConnectionInfoProvider *i this->_k_minimum_window = params->cc_minimum_window(); this->_k_loss_reduction_factor = params->cc_loss_reduction_factor(); - // [draft-11 recovery] 4.7.3. Initialization - this->_congestion_window = this->_k_initial_window; + this->reset(); } void @@ -134,3 +133,13 @@ QUICCongestionController::current_ssthresh() const { return this->_ssthresh; } + +// [draft-11 recovery] 4.7.3. Initialization +void +QUICCongestionController::reset() +{ + this->_bytes_in_flight = 0; + this->_congestion_window = this->_k_initial_window;; + this->_end_of_recovery = 0; + this->_ssthresh = UINT32_MAX; +} diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 36d627982f3..327b253e052 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -47,17 +47,7 @@ QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConne this->_k_delayed_ack_timeout = params->ld_delayed_ack_timeout(); this->_k_default_initial_rtt = params->ld_default_initial_rtt(); - // [draft-11 recovery] 3.5.3. Initialization - if (this->_k_using_time_loss_detection) { - this->_reordering_threshold = UINT32_MAX; - this->_time_reordering_fraction = this->_k_time_reordering_fraction; - } else { - this->_reordering_threshold = this->_k_reordering_threshold; - this->_time_reordering_fraction = INFINITY; - } - - this->_handshake_outstanding = 0; - this->_retransmittable_outstanding = 0; + this->reset(); SET_HANDLER(&QUICLossDetector::event_handler); } @@ -69,6 +59,8 @@ QUICLossDetector::~QUICLossDetector() this->_loss_detection_alarm = nullptr; } + this->_sent_packets.clear(); + this->_transmitter = nullptr; this->_cc = nullptr; } @@ -161,8 +153,17 @@ QUICLossDetector::reset() this->_sent_packets.clear(); + // [draft-11 recovery] 3.5.3. Initialization this->_handshake_outstanding = 0; this->_retransmittable_outstanding = 0; + + if (this->_k_using_time_loss_detection) { + this->_reordering_threshold = UINT32_MAX; + this->_time_reordering_fraction = this->_k_time_reordering_fraction; + } else { + this->_reordering_threshold = this->_k_reordering_threshold; + this->_time_reordering_fraction = INFINITY; + } } void diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 69f811f6b83..023d135a14e 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -65,6 +65,7 @@ class QUICCongestionController virtual void on_packets_lost(std::map &packets); void on_retransmission_timeout_verified(); bool check_credit() const; + void reset(); // Debug uint32_t bytes_in_flight() const; From f7473556c7cf541fff398d1b13197531fb65e715 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 20 Jun 2018 14:50:50 +0900 Subject: [PATCH 0640/1313] [draft-11] Follow pseudocode updates of draft-ietf-quic-recovery --- iocore/net/quic/QUICCongestionController.cc | 10 +- iocore/net/quic/QUICLossDetector.cc | 143 +++++++++++++------- iocore/net/quic/QUICLossDetector.h | 10 +- 3 files changed, 102 insertions(+), 61 deletions(-) diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 70510a8594d..606449c9c2a 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -62,21 +62,21 @@ QUICCongestionController::_in_recovery(QUICPacketNumber packet_number) } void -QUICCongestionController::on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size) +QUICCongestionController::on_packet_acked(const PacketInfo &acked_packet) { // Remove from bytes_in_flight. - this->_bytes_in_flight -= acked_packet_size; - if (this->_in_recovery(acked_packet_number)) { + this->_bytes_in_flight -= acked_packet.bytes; + if (this->_in_recovery(acked_packet.packet_number)) { // Do not increase congestion window in recovery period. return; } if (this->_congestion_window < this->_ssthresh) { // Slow start. - this->_congestion_window += acked_packet_size; + this->_congestion_window += acked_packet.bytes; QUICCCDebug("slow start window chaged"); } else { // Congestion avoidance. - this->_congestion_window += this->_k_default_mss * acked_packet_size / this->_congestion_window; + this->_congestion_window += this->_k_default_mss * acked_packet.bytes / this->_congestion_window; QUICCCDebug("Congestion avoidance window changed"); } } diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 327b253e052..d82dbe8ca12 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -29,6 +29,7 @@ #include "QUICEvents.h" #define QUICLDDebug(fmt, ...) Debug("quic_loss_detector", "[%s] " fmt, this->_info->cids().data(), ##__VA_ARGS__) +#define QUICLDVDebug(fmt, ...) Debug("v_quic_loss_detector", "[%s] " fmt, this->_info->cids().data(), ##__VA_ARGS__) QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, QUICCongestionController *cc) @@ -175,17 +176,22 @@ QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_ack_on this->_largest_sent_packet = packet_number; // FIXME Should we really keep actual packet object? - std::unique_ptr packet_info( - new PacketInfo({packet_number, now, is_ack_only, is_handshake, sent_bytes, std::move(packet)})); - this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); - if (!is_ack_only) { + PacketInfoUPtr packet_info(new PacketInfo({packet_number, now, is_ack_only, is_handshake, sent_bytes, std::move(packet)})); + this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); + if (is_handshake) { this->_time_of_last_sent_handshake_packet = now; } this->_time_of_last_sent_retransmittable_packet = now; this->_cc->on_packet_sent(sent_bytes); this->_set_loss_detection_alarm(); + } else { + // -- ADDITIONAL CODE -- + // To simplify code - setting sent_bytes only if the packet is not ack_only. + PacketInfoUPtr packet_info(new PacketInfo({packet_number, now, is_ack_only, is_handshake, 0, std::move(packet)})); + this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); + // -- END OF ADDITIONAL CODE -- } } @@ -216,7 +222,7 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac auto tmp_ite = ite; tmp_ite++; if (range.contains(ite->first)) { - this->_on_packet_acked(ite->first, ite->second->bytes); + this->_on_packet_acked(*(ite->second)); } ite = tmp_ite; } @@ -259,21 +265,25 @@ QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICP } void -QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size) +QUICLossDetector::_on_packet_acked(const PacketInfo &acked_packet) { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number); - this->_cc->on_packet_acked(acked_packet_number, acked_packet_size); + + if (!acked_packet.ack_only) { + this->_cc->on_packet_acked(acked_packet); + } + // If a packet sent prior to RTO was acked, then the RTO // was spurious. Otherwise, inform congestion control. - if (this->_rto_count > 0 && acked_packet_number > this->_largest_sent_before_rto) { + if (this->_rto_count > 0 && acked_packet.packet_number > this->_largest_sent_before_rto) { this->_cc->on_retransmission_timeout_verified(); } this->_handshake_count = 0; this->_tlp_count = 0; this->_rto_count = 0; - this->_remove_from_sent_packet_list(acked_packet_number); + this->_remove_from_sent_packet_list(acked_packet.packet_number); } void @@ -282,14 +292,17 @@ QUICLossDetector::_set_loss_detection_alarm() ink_hrtime alarm_duration; // Don't arm the alarm if there are no packets with // retransmittable data in flight. - if (this->_retransmittable_outstanding == 0 && this->_loss_detection_alarm) { + if (this->_cc->bytes_in_flight() == 0 && this->_loss_detection_alarm) { this->_loss_detection_alarm_at = 0; this->_loss_detection_alarm->cancel(); this->_loss_detection_alarm = nullptr; QUICLDDebug("Loss detection alarm has been unset"); return; + } else { + QUICLDDebug("bytes_in_flight=%" PRIu32, this->_cc->bytes_in_flight()); } + if (this->_handshake_outstanding) { // Handshake retransmission alarm. if (this->_smoothed_rtt == 0) { @@ -302,35 +315,41 @@ QUICLossDetector::_set_loss_detection_alarm() this->_loss_detection_alarm_at = this->_time_of_last_sent_handshake_packet + alarm_duration; QUICLDDebug("Handshake retransmission alarm will be set"); - } else if (this->_loss_time != 0) { - // Early retransmit timer or time loss detection. - alarm_duration = this->_loss_time - this->_time_of_last_sent_retransmittable_packet; - QUICLDDebug("Early retransmit timer or time loss detection will be set"); - } else if (this->_tlp_count < this->_k_max_tlps) { - // Tail Loss Probe - alarm_duration = std::max(static_cast(1.5 * this->_smoothed_rtt + this->_max_ack_delay), this->_k_min_tlp_timeout); - QUICLDDebug("TLP alarm will be set"); + // -- ADDITIONAL CODE -- + // In psudocode returning here, but we don't do for scheduling _loss_detection_alarm event. + // -- END OF ADDITIONAL CODE -- } else { - // RTO alarm - alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; - alarm_duration = std::max(alarm_duration, this->_k_min_rto_timeout); - alarm_duration = alarm_duration * (1 << this->_rto_count); - QUICLDDebug("RTO alarm will be set"); - } + if (this->_loss_time != 0) { + // Early retransmit timer or time loss detection. + alarm_duration = this->_loss_time - this->_time_of_last_sent_retransmittable_packet; + QUICLDDebug("Early retransmit timer or time loss detection will be set"); - // ADDITIONAL CODE - // alarm_curation can be negative value because _loss_time is updated in _detect_lost_packets() - // In that case, perhaps we should trigger the alarm immediately. - if (alarm_duration < 0) { - alarm_duration = 1; - } - // END OF ADDITONAL CODE + } else { + // RTO or TLP alarm + alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; + alarm_duration = std::max(alarm_duration, this->_k_min_rto_timeout); + alarm_duration = alarm_duration * (1 << this->_rto_count); + + if (this->_tlp_count < this->_k_max_tlps) { + // Tail Loss Probe + ink_hrtime tlp_alarm_duration = + std::max(static_cast(1.5 * this->_smoothed_rtt + this->_max_ack_delay), this->_k_min_tlp_timeout); + alarm_duration = std::min(tlp_alarm_duration, alarm_duration); + } + QUICLDDebug("RTO or TLP alarm will be set"); + } + + // -- ADDITIONAL CODE -- + // alarm_curation can be negative value because _loss_time is updated in _detect_lost_packets() + // In that case, perhaps we should trigger the alarm immediately. + if (alarm_duration < 0) { + alarm_duration = 1; + } + // -- END OF ADDITONAL CODE -- - if (this->_loss_detection_alarm_at) { - this->_loss_detection_alarm_at = std::min(this->_loss_detection_alarm_at, Thread::get_hrtime() + alarm_duration); - } else { this->_loss_detection_alarm_at = this->_time_of_last_sent_retransmittable_packet + alarm_duration; } + QUICLDDebug("Loss detection alarm has been set to %" PRId64 "ms", alarm_duration / HRTIME_MSECOND); if (!this->_loss_detection_alarm) { @@ -343,7 +362,7 @@ QUICLossDetector::_on_loss_detection_alarm() { if (this->_handshake_outstanding) { // Handshake retransmission alarm. - this->_retransmit_handshake_packets(); + this->_retransmit_all_unacked_handshake_data(); this->_handshake_count++; } else if (this->_loss_time != 0) { // Early retransmit or Time Loss Detection @@ -363,8 +382,16 @@ QUICLossDetector::_on_loss_detection_alarm() this->_send_two_packets(); this->_rto_count++; } + QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); + + if (is_debug_tag_set("v_quic_loss_detector")) { + for (auto &unacked : this->_sent_packets) { + QUICLDVDebug("#%" PRIu64 " is_handshake=%i is_ack_only=%i size=%zu", unacked.first, unacked.second->handshake, unacked.second->ack_only, unacked.second->bytes); + } + } + this->_set_loss_detection_alarm(); } @@ -389,17 +416,27 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num break; } ink_hrtime time_since_sent = Thread::get_hrtime() - unacked.second->time; - uint64_t packet_delta = largest_acked_packet_number - unacked.second->packet_number; - if (time_since_sent > delay_until_lost) { - QUICLDDebug("Lost: time since sent is too long (PN=%" PRId64 " sent=%" PRId64 ", delay=%lf, fraction=%lf, lrtt=%" PRId64 - ", srtt=%" PRId64 ")", - unacked.first, time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, - this->_smoothed_rtt); - lost_packets.insert({unacked.first, unacked.second.get()}); - } else if (packet_delta > this->_reordering_threshold) { - QUICLDDebug("Lost: packet delta is too large (PN=%" PRId64 " largest=%" PRId64 " unacked=%" PRId64 " threshold=%" PRId32 ")", - unacked.first, largest_acked_packet_number, unacked.second->packet_number, this->_reordering_threshold); - lost_packets.insert({unacked.first, unacked.second.get()}); + uint64_t delta = largest_acked_packet_number - unacked.second->packet_number; + if (time_since_sent > delay_until_lost || delta > this->_reordering_threshold) { + if (time_since_sent > delay_until_lost) { + QUICLDDebug("Lost: time since sent is too long (PN=%" PRId64 " sent=%" PRId64 ", delay=%lf, fraction=%lf, lrtt=%" PRId64 + ", srtt=%" PRId64 ")", + unacked.first, time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, + this->_smoothed_rtt); + } else { + QUICLDDebug("Lost: packet delta is too large (PN=%" PRId64 " largest=%" PRId64 " unacked=%" PRId64 " threshold=%" PRId32 ")", + unacked.first, largest_acked_packet_number, unacked.second->packet_number, this->_reordering_threshold); + } + + if (!unacked.second->ack_only) { + lost_packets.insert({unacked.first, unacked.second.get()}); + } else { + // -- ADDITIONAL CODE -- + // We remove only "ack-only" packets for life time management of packets. + // Packets in lost_packets will be removed from sent_packet later. + this->_remove_from_sent_packet_list(unacked.first); + // -- END OF ADDITIONAL CODE -- + } } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) { this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent; } @@ -409,14 +446,16 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num // lets it decide whether to retransmit immediately. if (!lost_packets.empty()) { this->_cc->on_packets_lost(lost_packets); - for (auto lost_packet : lost_packets) { - // ADDITIONAL CODE + for (auto &lost_packet : lost_packets) { + // -- ADDITIONAL CODE -- // Not sure how we can get feedback from congestion control and when we should retransmit the lost packets but we need to send // them somewhere. // I couldn't find the place so just send them here for now. this->_retransmit_lost_packet(*lost_packet.second->packet); - // END OF ADDITIONAL CODE + // -- END OF ADDITIONAL CODE -- + // -- ADDITIONAL CODE -- this->_remove_from_sent_packet_list(lost_packet.first); + // -- END OF ADDITIONAL CODE -- } } } @@ -424,7 +463,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num // ===== Functions below are used on the spec but there're no pseudo code ===== void -QUICLossDetector::_retransmit_handshake_packets() +QUICLossDetector::_retransmit_all_unacked_handshake_data() { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); @@ -500,12 +539,12 @@ QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame) } void -QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr packet_info) +QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, PacketInfoUPtr packet_info) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // Add to the list - this->_sent_packets.insert(std::pair>(packet_number, std::move(packet_info))); + this->_sent_packets.insert(std::pair(packet_number, std::move(packet_info))); // Increment counters auto ite = this->_sent_packets.find(packet_number); diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 023d135a14e..3b2d7a14e6f 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -49,6 +49,8 @@ struct PacketInfo { QUICPacketUPtr packet; }; +using PacketInfoUPtr = std::unique_ptr; + class QUICRTTProvider { public: @@ -61,7 +63,7 @@ class QUICCongestionController QUICCongestionController(QUICConnectionInfoProvider *info); virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); - void on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size); + void on_packet_acked(const PacketInfo &acked_packet); virtual void on_packets_lost(std::map &packets); void on_retransmission_timeout_verified(); bool check_credit() const; @@ -142,7 +144,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU uint32_t _reordering_threshold = 0; double _time_reordering_fraction = 0.0; ink_hrtime _loss_time = 0; - std::map> _sent_packets; + std::map _sent_packets; // These are not defined on the spec but expected to be count // These counter have to be updated when inserting / erasing packets from _sent_packets with following functions. @@ -160,7 +162,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU void _on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes, QUICPacketUPtr packet); void _on_ack_received(const std::shared_ptr &ack_frame); - void _on_packet_acked(QUICPacketNumber acked_packet_number, size_t acked_packet_size); + void _on_packet_acked(const PacketInfo &acked_packet); void _update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICPacketNumber largest_acked); void _detect_lost_packets(QUICPacketNumber largest_acked); void _set_loss_detection_alarm(); @@ -169,7 +171,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU std::set _determine_newly_acked_packets(const QUICAckFrame &ack_frame); - void _retransmit_handshake_packets(); + void _retransmit_all_unacked_handshake_data(); void _send_one_packet(); void _send_two_packets(); From 5b0c618f300b277dfbc37de80d17da6bf73a87dc Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 20 Jun 2018 14:54:22 +0900 Subject: [PATCH 0641/1313] Print "ack_only" when sending ack only packet --- iocore/net/QUICNetVConnection.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 77f2a779195..e4727565864 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -421,8 +421,8 @@ QUICNetVConnection::_transmit_packet(QUICPacketUPtr packet) SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); if (packet) { - QUICConDebug("Enqueue %s packet #%" PRIu64 " size=%hu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), - packet->size()); + QUICConDebug("Enqueue %s packet #%" PRIu64 " size=%hu %s", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), + packet->size(), (!packet->is_retransmittable()) ? "ack_only" : ""); // TODO Remove const_cast this->_packet_send_queue.enqueue(const_cast(packet.release())); } From 162d6cf735e4d9e97e2f3eb3b11a96cad0978943 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 20 Jun 2018 15:05:13 +0900 Subject: [PATCH 0642/1313] Const Correctness --- iocore/net/quic/Mock.h | 2 +- iocore/net/quic/QUICCongestionController.cc | 2 +- iocore/net/quic/QUICLossDetector.cc | 4 ++-- iocore/net/quic/QUICLossDetector.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 949399c0a47..898b97c2703 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -397,7 +397,7 @@ class MockQUICCongestionController : public QUICCongestionController MockQUICCongestionController(QUICConnectionInfoProvider *info) : QUICCongestionController(info) {} // Override virtual void - on_packets_lost(std::map &packets) override + on_packets_lost(const std::map &packets) override { for (auto &p : packets) { lost_packets.insert(p.first); diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 606449c9c2a..cd01979bd60 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -82,7 +82,7 @@ QUICCongestionController::on_packet_acked(const PacketInfo &acked_packet) } void -QUICCongestionController::on_packets_lost(std::map &lost_packets) +QUICCongestionController::on_packets_lost(const std::map &lost_packets) { // Remove lost packets from bytes_in_flight. for (auto &lost_packet : lost_packets) { diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index d82dbe8ca12..bc16613306f 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -401,7 +401,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); this->_loss_time = 0; - std::map lost_packets; + std::map lost_packets; double delay_until_lost = INFINITY; if (this->_k_using_time_loss_detection) { @@ -468,7 +468,7 @@ QUICLossDetector::_retransmit_all_unacked_handshake_data() SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); std::set retransmitted_handshake_packets; - std::map lost_packets; + std::map lost_packets; for (auto &info : this->_sent_packets) { retransmitted_handshake_packets.insert(info.first); diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 3b2d7a14e6f..2f2e3c889b5 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -64,7 +64,7 @@ class QUICCongestionController virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); void on_packet_acked(const PacketInfo &acked_packet); - virtual void on_packets_lost(std::map &packets); + virtual void on_packets_lost(const std::map &packets); void on_retransmission_timeout_verified(); bool check_credit() const; void reset(); From 51fecc1cc714f7a6d34556dd0d3b9c5399d592e5 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 20 Jun 2018 15:21:15 +0900 Subject: [PATCH 0643/1313] Fix unit tests --- iocore/net/quic/Mock.h | 4 ++-- iocore/net/quic/test/test_QUICHandshakeProtocol.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 898b97c2703..9c578deffd6 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -578,14 +578,14 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol } bool - encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, + encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const override { return true; } bool - decrypt_pn(uint8_t *unprotected_pn, size_t &unprotected_pn_len, const uint8_t *protected_pn, size_t protected_pn_len, + decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const override { return true; diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 096b9c9c4c3..f24c6577a5b 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -620,7 +620,7 @@ TEST_CASE("QUICHandshakeProtocol PNE", "[quic]") uint8_t expected[] = {0x01, 0x02, 0x03, 0x04, 0x05}; uint8_t sample[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; uint8_t protected_pn[18], unprotected_pn[18]; - size_t protected_pn_len = 0, unprotected_pn_len = 0; + uint8_t protected_pn_len = 0, unprotected_pn_len = 0; // # Before handshake CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); From 7b03ca1281046962d086c1b7bd35d4b2f78029e3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 20 Jun 2018 15:26:01 +0900 Subject: [PATCH 0644/1313] Fix test_QUICFrameDispatcher --- iocore/net/quic/test/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am index b28e6544867..b80c094d129 100644 --- a/iocore/net/quic/test/Makefile.am +++ b/iocore/net/quic/test/Makefile.am @@ -180,7 +180,7 @@ test_QUICFrameDispatcher_LDFLAGS = \ @AM_LDFLAGS@ test_QUICFrameDispatcher_SOURCES = \ - $(catch_main) \ + $(catch_event_processor_main) \ test_QUICFrameDispatcher.cc \ ../QUICGlobals.cc \ ../QUICConfig.cc \ From 3c73a156a0df9ebf68c43eba5d181500da817eb9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Jun 2018 10:57:08 +0900 Subject: [PATCH 0645/1313] Print keys for PNE when keys are updated --- iocore/net/quic/QUICTLS.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 8784c94e734..dad654237fa 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -247,6 +247,8 @@ QUICTLS::update_key_materials() Debug("vv_quic_crypto", "client key 0x%s", print_buf); to_hex(print_buf, km->iv, km->iv_len); Debug("vv_quic_crypto", "client iv 0x%s", print_buf); + to_hex(print_buf, km->pn, km->pn_len); + Debug("vv_quic_crypto", "client pn 0x%s", print_buf); } this->_client_pp->set_key(std::move(km), next_key_phase); km = this->_keygen_for_server.generate(this->_ssl); @@ -255,6 +257,8 @@ QUICTLS::update_key_materials() Debug("vv_quic_crypto", "server key 0x%s", print_buf); to_hex(print_buf, km->iv, km->iv_len); Debug("vv_quic_crypto", "server iv 0x%s", print_buf); + to_hex(print_buf, km->pn, km->pn_len); + Debug("vv_quic_crypto", "server pn 0x%s", print_buf); } this->_server_pp->set_key(std::move(km), next_key_phase); From 32d43b09212e1de4f2b4f699bf6f0f2c02bb00e6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Jun 2018 11:04:09 +0900 Subject: [PATCH 0646/1313] Change payload length field to length field (apart of draft 13) --- iocore/net/quic/QUICPacket.cc | 37 ++++++++++++++--------- iocore/net/quic/QUICPacket.h | 2 +- iocore/net/quic/QUICPacketReceiveQueue.cc | 19 ++++++------ 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index ca3bc45c590..d9cb9d066b1 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -53,8 +53,8 @@ QUICPacketHeader::buf() return this->_buf.get(); } else { // TODO Reuse serialzied data if nothing has changed - size_t dummy; - this->store(this->_serialized, &dummy); + this->store(this->_serialized, &this->_buf_len); + this->_buf_len += this->_payload_length; return this->_serialized; } } @@ -148,15 +148,14 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf if (this->type() == QUICPacketType::VERSION_NEGOTIATION) { this->_payload_offset = offset; - this->_payload_length = len - offset; } else { - this->_payload_length = QUICIntUtil::read_QUICVariableInt(raw_buf + offset); offset += QUICVariableInt::size(raw_buf + offset); int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf + offset); QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset), pn_len, this->_base_packet_number); this->_payload_offset = offset + pn_len; } + this->_payload_length = len - this->_payload_offset; } QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICConnectionId destination_cid, QUICConnectionId source_cid, @@ -177,8 +176,7 @@ QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICConnectionId this->_buf_len = LONG_HDR_OFFSET_CONNECTION_ID + this->_destination_cid.length() + this->_source_cid.length() + this->_payload_length; } else { - this->_buf_len = LONG_HDR_OFFSET_CONNECTION_ID + this->_destination_cid.length() + this->_source_cid.length() + - QUICVariableInt::size(this->_payload_length + aead_tag_len) + 4 + this->_payload_length; + // this->_buf_len will be updated when buf() is called } } @@ -245,17 +243,17 @@ QUICPacketLongHeader::scil(uint8_t &scil, const uint8_t *packet, size_t packet_l } bool -QUICPacketLongHeader::payload_length(size_t &length, uint8_t *field_len, const uint8_t *packet, size_t packet_len) +QUICPacketLongHeader::length(size_t &length, uint8_t *field_len, const uint8_t *packet, size_t packet_len) { uint8_t dcil, scil; QUICPacketLongHeader::dcil(dcil, packet, packet_len); QUICPacketLongHeader::scil(scil, packet, packet_len); - size_t payload_len_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; - length = QUICIntUtil::read_QUICVariableInt(packet + payload_len_offset); + size_t length_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; + length = QUICIntUtil::read_QUICVariableInt(packet + length_offset); if (field_len) { - *field_len = QUICVariableInt::size(packet + payload_len_offset); + *field_len = QUICVariableInt::size(packet + length_offset); } return true; } @@ -373,13 +371,22 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const *len += n; if (this->_type != QUICPacketType::VERSION_NEGOTIATION) { - QUICIntUtil::write_QUICVariableInt(this->_payload_length + aead_tag_len, buf + *len, &n); + QUICPacketNumber pn = 0; + size_t pn_len = 4; + QUICPacket::encode_packet_number(pn, this->_packet_number, pn_len); + + if (pn < 0x100) { + pn_len = 1; + } else if (pn < 0x4000) { + pn_len = 2; + } else { + pn_len = 4; + } + + QUICIntUtil::write_QUICVariableInt(QUICVariableInt::size(pn_len) + this->_payload_length + aead_tag_len, buf + *len, &n); *len += n; - QUICPacketNumber dst = 0; - size_t dst_len = 4; - QUICPacket::encode_packet_number(dst, this->_packet_number, dst_len); - QUICTypeUtil::write_QUICPacketNumber(dst, dst_len, buf + *len, &n); + QUICTypeUtil::write_QUICPacketNumber(pn, pn_len, buf + *len, &n); *len += n; } } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index bf6cfb7f55c..3ce9bc8776b 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -200,7 +200,7 @@ class QUICPacketLongHeader : public QUICPacketHeader * Unlike QUICInvariants::scil(), this returns actual connection id length */ static bool scil(uint8_t &scil, const uint8_t *packet, size_t packet_len); - static bool payload_length(size_t &payload_length, uint8_t *field_len, const uint8_t *packet, size_t packet_len); + static bool length(size_t &length, uint8_t *field_len, const uint8_t *packet, size_t packet_len); private: QUICPacketNumber _packet_number; diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 4fd2ad3348f..bfd6c5fb324 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -36,18 +36,19 @@ is_vn(QUICVersion v) } static size_t -long_hdr_pkt_len(uint8_t *buf) +long_hdr_pkt_len(uint8_t *buf, size_t len) { uint8_t dcil, scil; - QUICPacketLongHeader::dcil(dcil, buf, 6); - QUICPacketLongHeader::scil(scil, buf, 6); + QUICPacketLongHeader::dcil(dcil, buf, len); + QUICPacketLongHeader::scil(scil, buf, len); - size_t payload_len_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; + size_t length_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; - size_t payload_len; - uint8_t payload_len_field_len; - QUICPacketLongHeader::payload_length(payload_len, &payload_len_field_len, buf, payload_len_offset + 4); - return payload_len_offset + payload_len_field_len + QUICTypeUtil::read_QUICPacketNumberLen(buf) + payload_len; + size_t length; + uint8_t length_field_len; + QUICPacketLongHeader::length(length, &length_field_len, buf, len); + + return length_offset + length_field_len + length; } QUICPacketReceiveQueue::QUICPacketReceiveQueue(QUICPacketFactory &packet_factory, QUICPacketNumberProtector &pn_protector) @@ -105,7 +106,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) result = QUICPacketCreationResult::UNSUPPORTED; pkt_len = remaining_len; } else { - pkt_len = long_hdr_pkt_len(this->_payload.get() + this->_offset); + pkt_len = long_hdr_pkt_len(this->_payload.get() + this->_offset, remaining_len); } } else { pkt_len = remaining_len; From 6751e97d47d4bef227c35ba206ae4466292b1cdc Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Jun 2018 11:07:08 +0900 Subject: [PATCH 0647/1313] Protect sending packet numbers --- iocore/net/P_QUICPacketHandler.h | 10 ++- iocore/net/QUICNetVConnection.cc | 6 +- iocore/net/QUICPacketHandler.cc | 20 +++-- iocore/net/quic/QUICPacket.cc | 100 ++++++++++++++++++++++ iocore/net/quic/QUICPacket.h | 5 ++ iocore/net/quic/QUICPacketReceiveQueue.cc | 51 +---------- iocore/net/quic/QUICPacketReceiveQueue.h | 2 - 7 files changed, 128 insertions(+), 66 deletions(-) diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 3e982bc891f..77fe3641b27 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -32,6 +32,7 @@ class QUICClosedConCollector; class QUICNetVConnection; class QUICPacket; +class QUICPacketNumberProtector; class QUICPacketHandler { @@ -39,11 +40,12 @@ class QUICPacketHandler QUICPacketHandler(); ~QUICPacketHandler(); - virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc) = 0; + virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) = 0; virtual void close_conenction(QUICNetVConnection *conn); protected: - static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu); + static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu, + QUICPacketNumberProtector *pn_protector); Event *_collector_event = nullptr; QUICClosedConCollector *_closed_con_collector = nullptr; @@ -68,7 +70,7 @@ class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler void init_accept(EThread *t) override; // QUICPacketHandler - virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc) override; + virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) override; private: void _recv_packet(int event, UDPPacket *udp_packet) override; @@ -90,7 +92,7 @@ class QUICPacketHandlerOut : public Continuation, public QUICPacketHandler int event_handler(int event, Event *data); // QUICPacketHandler - virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc) override; + virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) override; private: void _recv_packet(int event, UDPPacket *udp_packet) override; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e4727565864..a9c9d201f1b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1077,7 +1077,7 @@ QUICNetVConnection::_state_common_send_packet() break; } - this->_packet_handler->send_packet(*packet, this); + this->_packet_handler->send_packet(*packet, this, this->_pn_protector); if (packet->type() == QUICPacketType::HANDSHAKE) { ++this->_handshake_packets_sent; } @@ -1116,7 +1116,7 @@ QUICNetVConnection::_state_handshake_send_retry_packet() } QUICPacketUPtr packet = this->_build_packet(std::move(buf), len, retransmittable, QUICPacketType::RETRY); - this->_packet_handler->send_packet(*packet, this); + this->_packet_handler->send_packet(*packet, this, this->_pn_protector); this->_loss_detector->on_packet_sent(std::move(packet)); QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, 1); @@ -1137,7 +1137,7 @@ QUICNetVConnection::_state_closing_send_packet() // that an endpoint maintains for a closing connection, endpoints MAY // send the exact same packet. if (this->_the_final_packet) { - this->_packet_handler->send_packet(*this->_the_final_packet, this); + this->_packet_handler->send_packet(*this->_the_final_packet, this, this->_pn_protector); } return QUICErrorUPtr(new QUICNoError()); } diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index ab2a5732290..7e6a58e964b 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -70,7 +70,8 @@ QUICPacketHandler::close_conenction(QUICNetVConnection *conn) } void -QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu) +QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu, + QUICPacketNumberProtector *pn_protector) { size_t udp_len; Ptr udp_payload(new_IOBufferBlock()); @@ -78,6 +79,10 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo packet.store(reinterpret_cast(udp_payload->end()), &udp_len); udp_payload->fill(udp_len); + if (pn_protector) { + QUICPacket::protect_packet_number(reinterpret_cast(udp_payload->start()), udp_len, pn_protector); + } + UDPPacket *udp_packet = new_UDPPacket(addr, 0, udp_payload); if (is_debug_tag_set(tag)) { @@ -216,7 +221,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) QUICDebugDS(scid, dcid, "Unsupported version: 0x%x", v); QUICPacketUPtr vn = QUICPacketFactory::create_version_negotiation_packet(scid, dcid); - this->_send_packet(this, *vn, udp_packet->getConnection(), udp_packet->from, 1200); + this->_send_packet(this, *vn, udp_packet->getConnection(), udp_packet->from, 1200, nullptr); udp_packet->free(); return; } @@ -247,7 +252,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) token.generate(dcid, params->server_id()); } auto packet = QUICPacketFactory::create_stateless_reset_packet(dcid, token); - this->_send_packet(this, *packet, udp_packet->getConnection(), udp_packet->from, 1200); + this->_send_packet(this, *packet, udp_packet->getConnection(), udp_packet->from, 1200, nullptr); udp_packet->free(); return; } @@ -297,9 +302,9 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // TODO: Should be called via eventProcessor? void -QUICPacketHandlerIn::send_packet(const QUICPacket &packet, QUICNetVConnection *vc) +QUICPacketHandlerIn::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) { - this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu()); + this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &pn_protector); } // @@ -342,9 +347,10 @@ QUICPacketHandlerOut::event_handler(int event, Event *data) } void -QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection *vc) +QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) { - this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu()); + // TODO Pass QUICPacketNumberProtector + this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), nullptr); } void diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index d9cb9d066b1..a28a3f511ca 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -258,6 +258,20 @@ QUICPacketLongHeader::length(size_t &length, uint8_t *field_len, const uint8_t * return true; } +bool +QUICPacketLongHeader::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len) +{ + uint8_t dcil, scil; + size_t length; + uint8_t length_field_len; + if (!QUICPacketLongHeader::dcil(dcil, packet, packet_len) || !QUICPacketLongHeader::scil(scil, packet, packet_len) || + !QUICPacketLongHeader::length(length, &length_field_len, packet, packet_len)) { + return false; + } + pn_offset = 6 + dcil + scil + length_field_len; + return true; +} + QUICConnectionId QUICPacketLongHeader::destination_cid() const { @@ -530,6 +544,14 @@ QUICPacketShortHeader::key_phase(QUICKeyPhase &phase, const uint8_t *packet, siz return true; } +bool +QUICPacketShortHeader::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len) +{ + int connection_id_len = QUICConfigParams::scid_len(); + pn_offset = 1 + connection_id_len; + return true; +} + /** * Header Length (doesn't include payload length) */ @@ -733,6 +755,84 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si return true; } +bool +QUICPacket::protect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector) +{ + size_t pn_offset = 0; + uint8_t pn_len = 4; + size_t sample_offset = 0; + uint8_t sample_len = 0; + constexpr int aead_expansion = 16; // Currently, AEAD expansion (which is probably AEAD tag) length is always 16 + QUICKeyPhase phase; + + if (QUICInvariants::is_long_header(packet)) { + QUICPacketType type; + QUICPacketLongHeader::type(type, packet, packet_len); + switch (type) { + case QUICPacketType::ZERO_RTT_PROTECTED: + phase = QUICKeyPhase::ZERORTT; + break; + default: + phase = QUICKeyPhase::CLEARTEXT; + break; + } + QUICPacketLongHeader::packet_number_offset(pn_offset, packet, packet_len); + } else { + QUICPacketShortHeader::key_phase(phase, packet, packet_len); + QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len); + } + sample_offset = std::min(pn_offset + 4, packet_len - aead_expansion); + sample_len = 16; // On draft-12, the length is always 16 (See 5.6.1 and 5.6.2) + + uint8_t protected_pn[4] = {0}; + uint8_t protected_pn_len = 0; + pn_len = QUICTypeUtil::read_QUICPacketNumberLen(packet + pn_offset); + if (!pn_protector->protect(protected_pn, protected_pn_len, packet + pn_offset, pn_len, packet + sample_offset, phase)) { + return false; + } + memcpy(packet + pn_offset, protected_pn, pn_len); + return true; +} + +bool +QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector) +{ + size_t pn_offset = 0; + uint8_t pn_len = 4; + size_t sample_offset = 0; + uint8_t sample_len = 0; + constexpr int aead_expansion = 16; // Currently, AEAD expansion (which is probably AEAD tag) length is always 16 + QUICKeyPhase phase; + + if (QUICInvariants::is_long_header(packet)) { + QUICPacketType type; + QUICPacketLongHeader::type(type, packet, packet_len); + switch (type) { + case QUICPacketType::ZERO_RTT_PROTECTED: + phase = QUICKeyPhase::ZERORTT; + break; + default: + phase = QUICKeyPhase::CLEARTEXT; + break; + } + QUICPacketLongHeader::packet_number_offset(pn_offset, packet, packet_len); + } else { + QUICPacketShortHeader::key_phase(phase, packet, packet_len); + QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len); + } + sample_offset = std::min(pn_offset + 4, packet_len - aead_expansion); + sample_len = 16; // On draft-12, the length is always 16 (See 5.6.1 and 5.6.2) + + uint8_t unprotected_pn[4] = {0}; + uint8_t unprotected_pn_len = 0; + if (!pn_protector->unprotect(unprotected_pn, unprotected_pn_len, packet + pn_offset, pn_len, packet + sample_offset, phase)) { + return false; + } + unprotected_pn_len = QUICTypeUtil::read_QUICPacketNumberLen(unprotected_pn); + memcpy(packet + pn_offset, unprotected_pn, unprotected_pn_len); + return true; +} + // // QUICPacketFactory // diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 3ce9bc8776b..4067fdabbd4 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -201,6 +201,7 @@ class QUICPacketLongHeader : public QUICPacketHeader */ static bool scil(uint8_t &scil, const uint8_t *packet, size_t packet_len); static bool length(size_t &length, uint8_t *field_len, 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); private: QUICPacketNumber _packet_number; @@ -237,6 +238,7 @@ class QUICPacketShortHeader : public QUICPacketHeader void store(uint8_t *buf, size_t *len) const; 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); private: int _packet_number_len; @@ -328,6 +330,9 @@ class QUICPacket 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); + static bool protect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector); + static bool unprotect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector); + LINK(QUICPacket, link); private: diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index bfd6c5fb324..fcb318421ef 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -138,7 +138,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) this->_offset = 0; } - if (this->_unprotect_packet_number(pkt.get(), pkt_len)) { + if (QUICPacket::unprotect_packet_number(pkt.get(), pkt_len, &this->_pn_protector)) { quic_packet = this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->_largest_received_packet_number, result); } else { result = QUICPacketCreationResult::FAILED; @@ -179,52 +179,3 @@ QUICPacketReceiveQueue::reset() { this->_largest_received_packet_number = 0; } - -bool -QUICPacketReceiveQueue::_unprotect_packet_number(uint8_t *packet, size_t packet_len) -{ - size_t pn_offset = 0; - uint8_t pn_len = 4; - size_t sample_offset = 0; - uint8_t sample_len = 0; - constexpr int aead_expansion = 16; // Currently, AEAD expansion (which is probably AEAD tag) length is always 16 - int connection_id_len = QUICConfigParams::scid_len(); - QUICKeyPhase phase; - - if (QUICInvariants::is_long_header(packet)) { - QUICPacketType type; - QUICPacketLongHeader::type(type, packet, packet_len); - switch (type) { - case QUICPacketType::ZERO_RTT_PROTECTED: - phase = QUICKeyPhase::ZERORTT; - break; - default: - phase = QUICKeyPhase::CLEARTEXT; - break; - } - - uint8_t dcil, scil; - size_t payload_length; - uint8_t payload_length_field_len; - if (!QUICPacketLongHeader::dcil(dcil, packet, packet_len) || !QUICPacketLongHeader::scil(scil, packet, packet_len) || - !QUICPacketLongHeader::payload_length(payload_length, &payload_length_field_len, packet, packet_len)) { - return false; - } - pn_offset = 6 + dcil + scil + payload_length_field_len; - } else { - QUICPacketShortHeader::key_phase(phase, packet, packet_len); - pn_offset = 1 + connection_id_len; - } - sample_offset = std::min(pn_offset + 4, packet_len - aead_expansion); - sample_len = 16; // On draft-12, the length is always 16 (See 5.6.1 and 5.6.2) - - uint8_t unprotected_pn[4] = {0}; - uint8_t unprotected_pn_len = 0; - if (!this->_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, packet + pn_offset, pn_len, packet + sample_offset, - phase)) { - return false; - } - unprotected_pn_len = QUICTypeUtil::read_QUICPacketNumberLen(unprotected_pn); - memcpy(packet + pn_offset, unprotected_pn, unprotected_pn_len); - return true; -} diff --git a/iocore/net/quic/QUICPacketReceiveQueue.h b/iocore/net/quic/QUICPacketReceiveQueue.h index 230fc8a3352..9f9a3b8bd94 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.h +++ b/iocore/net/quic/QUICPacketReceiveQueue.h @@ -48,6 +48,4 @@ class QUICPacketReceiveQueue size_t _payload_len = 0; size_t _offset = 0; IpEndpoint _from; - - bool _unprotect_packet_number(uint8_t *packet, size_t packet_len); }; From 609e3e7a416e0f38689363afe05b42ba3e85f29f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Jun 2018 11:07:36 +0900 Subject: [PATCH 0648/1313] Length of keys for PNE is not a fixed length --- iocore/net/quic/QUICKeyGenerator.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index cf2b9979d3c..908dec0b09a 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -121,7 +121,7 @@ QUICKeyGenerator::_generate(KeyMaterial &km, QUICHKDF &hkdf, const uint8_t *secr // pn_key = QHKDF-Expand(S, "pn", pn_key_length) this->_generate_key(km.key, &km.key_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); this->_generate_iv(km.iv, &km.iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher)); - this->_generate_pn(km.pn, &km.pn_len, hkdf, secret, secret_len, 12); + this->_generate_pn(km.pn, &km.pn_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); return 0; } From 0e2934c7b9f7219e4462eb4e6490130371b3a8b3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Jun 2018 12:22:21 +0900 Subject: [PATCH 0649/1313] Fix a bug in unprotecting PN in short header Incorrect PN offset was used due to CID length difference. --- iocore/net/P_QUICPacketHandler.h | 2 +- iocore/net/QUICPacketHandler.cc | 12 ++++++------ iocore/net/quic/QUICPacket.cc | 11 +++++------ iocore/net/quic/QUICPacket.h | 4 ++-- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 77fe3641b27..b85fc0233dd 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -45,7 +45,7 @@ class QUICPacketHandler protected: static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu, - QUICPacketNumberProtector *pn_protector); + QUICPacketNumberProtector *pn_protector, int dcil); Event *_collector_event = nullptr; QUICClosedConCollector *_closed_con_collector = nullptr; diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 7e6a58e964b..8d66d5a6ebd 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -71,7 +71,7 @@ QUICPacketHandler::close_conenction(QUICNetVConnection *conn) void QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu, - QUICPacketNumberProtector *pn_protector) + QUICPacketNumberProtector *pn_protector, int dcil) { size_t udp_len; Ptr udp_payload(new_IOBufferBlock()); @@ -80,7 +80,7 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo udp_payload->fill(udp_len); if (pn_protector) { - QUICPacket::protect_packet_number(reinterpret_cast(udp_payload->start()), udp_len, pn_protector); + QUICPacket::protect_packet_number(reinterpret_cast(udp_payload->start()), udp_len, pn_protector, dcil); } UDPPacket *udp_packet = new_UDPPacket(addr, 0, udp_payload); @@ -221,7 +221,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) QUICDebugDS(scid, dcid, "Unsupported version: 0x%x", v); QUICPacketUPtr vn = QUICPacketFactory::create_version_negotiation_packet(scid, dcid); - this->_send_packet(this, *vn, udp_packet->getConnection(), udp_packet->from, 1200, nullptr); + this->_send_packet(this, *vn, udp_packet->getConnection(), udp_packet->from, 1200, nullptr, 0); udp_packet->free(); return; } @@ -252,7 +252,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) token.generate(dcid, params->server_id()); } auto packet = QUICPacketFactory::create_stateless_reset_packet(dcid, token); - this->_send_packet(this, *packet, udp_packet->getConnection(), udp_packet->from, 1200, nullptr); + this->_send_packet(this, *packet, udp_packet->getConnection(), udp_packet->from, 1200, nullptr, 0); udp_packet->free(); return; } @@ -304,7 +304,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) void QUICPacketHandlerIn::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) { - this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &pn_protector); + this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &pn_protector, vc->peer_connection_id().length()); } // @@ -350,7 +350,7 @@ void QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) { // TODO Pass QUICPacketNumberProtector - this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), nullptr); + this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), nullptr, 0); } void diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index a28a3f511ca..9ac10d5a666 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -545,10 +545,9 @@ QUICPacketShortHeader::key_phase(QUICKeyPhase &phase, const uint8_t *packet, siz } bool -QUICPacketShortHeader::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len) +QUICPacketShortHeader::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len, int dcil) { - int connection_id_len = QUICConfigParams::scid_len(); - pn_offset = 1 + connection_id_len; + pn_offset = 1 + dcil; return true; } @@ -756,7 +755,7 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si } bool -QUICPacket::protect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector) +QUICPacket::protect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector, int dcil) { size_t pn_offset = 0; uint8_t pn_len = 4; @@ -779,7 +778,7 @@ QUICPacket::protect_packet_number(uint8_t *packet, size_t packet_len, QUICPacket QUICPacketLongHeader::packet_number_offset(pn_offset, packet, packet_len); } else { QUICPacketShortHeader::key_phase(phase, packet, packet_len); - QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len); + QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, dcil); } sample_offset = std::min(pn_offset + 4, packet_len - aead_expansion); sample_len = 16; // On draft-12, the length is always 16 (See 5.6.1 and 5.6.2) @@ -818,7 +817,7 @@ QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, QUICPack QUICPacketLongHeader::packet_number_offset(pn_offset, packet, packet_len); } else { QUICPacketShortHeader::key_phase(phase, packet, packet_len); - QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len); + QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, QUICConfigParams::scid_len()); } sample_offset = std::min(pn_offset + 4, packet_len - aead_expansion); sample_len = 16; // On draft-12, the length is always 16 (See 5.6.1 and 5.6.2) diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 4067fdabbd4..8156a16f9a5 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -238,7 +238,7 @@ class QUICPacketShortHeader : public QUICPacketHeader void store(uint8_t *buf, size_t *len) const; 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); + static bool packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len, int dcil); private: int _packet_number_len; @@ -330,7 +330,7 @@ class QUICPacket 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); - static bool protect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector); + static bool protect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector, int dcil); static bool unprotect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector); LINK(QUICPacket, link); From 75dc251e0bff94b44eb131221c35d85b171c0125 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Jun 2018 14:56:20 +0900 Subject: [PATCH 0650/1313] clang-format --- iocore/net/quic/QUICCongestionController.cc | 7 ++++--- iocore/net/quic/QUICLossDetector.cc | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index cd01979bd60..0d03be2eb5f 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -138,8 +138,9 @@ QUICCongestionController::current_ssthresh() const void QUICCongestionController::reset() { - this->_bytes_in_flight = 0; - this->_congestion_window = this->_k_initial_window;; + this->_bytes_in_flight = 0; + this->_congestion_window = this->_k_initial_window; + ; this->_end_of_recovery = 0; - this->_ssthresh = UINT32_MAX; + this->_ssthresh = UINT32_MAX; } diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index bc16613306f..42269aa4578 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -388,7 +388,8 @@ QUICLossDetector::_on_loss_detection_alarm() if (is_debug_tag_set("v_quic_loss_detector")) { for (auto &unacked : this->_sent_packets) { - QUICLDVDebug("#%" PRIu64 " is_handshake=%i is_ack_only=%i size=%zu", unacked.first, unacked.second->handshake, unacked.second->ack_only, unacked.second->bytes); + QUICLDVDebug("#%" PRIu64 " is_handshake=%i is_ack_only=%i size=%zu", unacked.first, unacked.second->handshake, + unacked.second->ack_only, unacked.second->bytes); } } @@ -424,7 +425,8 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num unacked.first, time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, this->_smoothed_rtt); } else { - QUICLDDebug("Lost: packet delta is too large (PN=%" PRId64 " largest=%" PRId64 " unacked=%" PRId64 " threshold=%" PRId32 ")", + QUICLDDebug("Lost: packet delta is too large (PN=%" PRId64 " largest=%" PRId64 " unacked=%" PRId64 " threshold=%" PRId32 + ")", unacked.first, largest_acked_packet_number, unacked.second->packet_number, this->_reordering_threshold); } From 1d1384a03a937274172a1d11794dffd099691ba4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Jun 2018 15:58:01 +0900 Subject: [PATCH 0651/1313] Fix QUICPacketLongHeader::size() and store() --- iocore/net/quic/QUICPacket.cc | 4 ++-- iocore/net/quic/test/test_QUICPacket.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 9ac10d5a666..bf738bb3a4a 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -176,7 +176,7 @@ QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICConnectionId this->_buf_len = LONG_HDR_OFFSET_CONNECTION_ID + this->_destination_cid.length() + this->_source_cid.length() + this->_payload_length; } else { - // this->_buf_len will be updated when buf() is called + this->buf(); } } @@ -397,7 +397,7 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const pn_len = 4; } - QUICIntUtil::write_QUICVariableInt(QUICVariableInt::size(pn_len) + this->_payload_length + aead_tag_len, buf + *len, &n); + QUICIntUtil::write_QUICVariableInt(pn_len + this->_payload_length + aead_tag_len, buf + *len, &n); *len += n; QUICTypeUtil::write_QUICPacketNumber(pn, pn_len, buf + *len, &n); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index abf53669143..e1be5de3b28 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -79,7 +79,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") SECTION("Long Header (store)") { - uint8_t buf[32] = {0}; + uint8_t buf[64] = {0}; size_t len = 0; const uint8_t expected[] = { @@ -88,7 +88,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0x55, // DCIL/SCIL 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID - 0x15, // Payload length (Not 0x05 because it will have 16 bytes of AEAD tag) + 0x19, // Length (Not 0x09 because it will have 16 bytes of AEAD tag) 0xC1, 0x23, 0x45, 0x67, // Packet number 0x11, 0x22, 0x33, 0x44, 0x55, // Payload (dummy) }; From ec666b4f8572af73fbc8f0a3fd9c9739bd85a8d9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 22 Jun 2018 09:08:31 +0900 Subject: [PATCH 0652/1313] Ignore traffic_quic --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8301874277a..7e7997791d5 100644 --- a/.gitignore +++ b/.gitignore @@ -57,7 +57,7 @@ src/traffic_layout/traffic_layout src/traffic_logcat/traffic_logcat src/traffic_logstats/traffic_logstats src/traffic_manager/traffic_manager -cmd/traffic_quic/traffic_quic +src/traffic_quic/traffic_quic src/traffic_server/traffic_server src/traffic_top/traffic_top src/traffic_via/traffic_via From f57ac7ce13f259f3231b75e0452ce543ec6a4258 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 22 Jun 2018 09:32:13 +0900 Subject: [PATCH 0653/1313] Fix Version Negotiation Packet handling --- iocore/net/quic/QUICPacket.cc | 6 ++++++ iocore/net/quic/QUICPacketReceiveQueue.cc | 11 +++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index bf738bb3a4a..67f9fa3ec8f 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -804,6 +804,12 @@ QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, QUICPack QUICKeyPhase phase; if (QUICInvariants::is_long_header(packet)) { +#ifdef DEBUG + QUICVersion version; + QUICPacketLongHeader::version(version, packet, packet_len); + ink_assert(version != 0x0); +#endif + QUICPacketType type; QUICPacketLongHeader::type(type, packet, packet_len); switch (type) { diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index fcb318421ef..e7b2e01013d 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -90,8 +90,9 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) } } - ats_unique_buf pkt = {nullptr, [](void *p) { ats_free(p); }}; - size_t pkt_len = 0; + ats_unique_buf pkt = {nullptr, [](void *p) { ats_free(p); }}; + size_t pkt_len = 0; + bool has_packet_number = true; if (QUICInvariants::is_long_header(this->_payload.get())) { uint8_t *buf = this->_payload.get() + this->_offset; @@ -101,7 +102,8 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) QUICVersion version; QUICPacketLongHeader::version(version, buf, remaining_len); if (is_vn(version)) { - pkt_len = remaining_len; + has_packet_number = false; + pkt_len = remaining_len; } else if (!QUICTypeUtil::is_supported_version(version)) { result = QUICPacketCreationResult::UNSUPPORTED; pkt_len = remaining_len; @@ -138,7 +140,8 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) this->_offset = 0; } - if (QUICPacket::unprotect_packet_number(pkt.get(), pkt_len, &this->_pn_protector)) { + // VN doesn't have Packet Number field + if (!has_packet_number || QUICPacket::unprotect_packet_number(pkt.get(), pkt_len, &this->_pn_protector)) { quic_packet = this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->_largest_received_packet_number, result); } else { result = QUICPacketCreationResult::FAILED; From 64db8f9505b55757726536bd185fa396b55040f6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 22 Jun 2018 09:43:28 +0900 Subject: [PATCH 0654/1313] Add PNE support to QUICPacketHandlerOut --- iocore/net/QUICPacketHandler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 8d66d5a6ebd..1a92cf76981 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -350,7 +350,7 @@ void QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) { // TODO Pass QUICPacketNumberProtector - this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), nullptr, 0); + this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &pn_protector, vc->peer_connection_id().length()); } void From 8fc244e8e30cb4f9ea27865bd571f6f75dd64175 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 22 Jun 2018 10:05:23 +0900 Subject: [PATCH 0655/1313] Make pn_protector const reference --- iocore/net/P_QUICPacketHandler.h | 10 ++++++---- iocore/net/QUICPacketHandler.cc | 7 +++---- iocore/net/quic/QUICPacket.cc | 4 ++-- iocore/net/quic/QUICPacket.h | 4 ++-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index b85fc0233dd..3380f6b058b 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -40,12 +40,12 @@ class QUICPacketHandler QUICPacketHandler(); ~QUICPacketHandler(); - virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) = 0; + virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketNumberProtector &pn_protector) = 0; virtual void close_conenction(QUICNetVConnection *conn); protected: static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu, - QUICPacketNumberProtector *pn_protector, int dcil); + const QUICPacketNumberProtector *pn_protector, int dcil); Event *_collector_event = nullptr; QUICClosedConCollector *_closed_con_collector = nullptr; @@ -70,7 +70,8 @@ class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler void init_accept(EThread *t) override; // QUICPacketHandler - virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) override; + virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, + const QUICPacketNumberProtector &pn_protector) override; private: void _recv_packet(int event, UDPPacket *udp_packet) override; @@ -92,7 +93,8 @@ class QUICPacketHandlerOut : public Continuation, public QUICPacketHandler int event_handler(int event, Event *data); // QUICPacketHandler - virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) override; + virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, + const QUICPacketNumberProtector &pn_protector) override; private: void _recv_packet(int event, UDPPacket *udp_packet) override; diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 1a92cf76981..602db26d691 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -71,7 +71,7 @@ QUICPacketHandler::close_conenction(QUICNetVConnection *conn) void QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu, - QUICPacketNumberProtector *pn_protector, int dcil) + const QUICPacketNumberProtector *pn_protector, int dcil) { size_t udp_len; Ptr udp_payload(new_IOBufferBlock()); @@ -302,7 +302,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // TODO: Should be called via eventProcessor? void -QUICPacketHandlerIn::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) +QUICPacketHandlerIn::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketNumberProtector &pn_protector) { this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &pn_protector, vc->peer_connection_id().length()); } @@ -347,9 +347,8 @@ QUICPacketHandlerOut::event_handler(int event, Event *data) } void -QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, QUICPacketNumberProtector &pn_protector) +QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketNumberProtector &pn_protector) { - // TODO Pass QUICPacketNumberProtector this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &pn_protector, vc->peer_connection_id().length()); } diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 67f9fa3ec8f..7a4b076059a 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -755,7 +755,7 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si } bool -QUICPacket::protect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector, int dcil) +QUICPacket::protect_packet_number(uint8_t *packet, size_t packet_len, const QUICPacketNumberProtector *pn_protector, int dcil) { size_t pn_offset = 0; uint8_t pn_len = 4; @@ -794,7 +794,7 @@ QUICPacket::protect_packet_number(uint8_t *packet, size_t packet_len, QUICPacket } bool -QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector) +QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, const QUICPacketNumberProtector *pn_protector) { size_t pn_offset = 0; uint8_t pn_len = 4; diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 8156a16f9a5..fd9f12d9ca2 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -330,8 +330,8 @@ class QUICPacket 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); - static bool protect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector, int dcil); - static bool unprotect_packet_number(uint8_t *packet, size_t packet_len, QUICPacketNumberProtector *pn_protector); + static bool protect_packet_number(uint8_t *packet, size_t packet_len, const QUICPacketNumberProtector *pn_protector, int dcil); + static bool unprotect_packet_number(uint8_t *packet, size_t packet_len, const QUICPacketNumberProtector *pn_protector); LINK(QUICPacket, link); From b6e885823118ee95abfaf58c56247ba591ffbe1d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 22 Jun 2018 10:17:32 +0900 Subject: [PATCH 0656/1313] [draft-11] Relax restrictions of QUICTransportParameterId::STATELESS_RESET_TOKEN --- iocore/net/quic/QUICTransportParameters.cc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index fbf402b4b80..53b2c0be76d 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -457,16 +457,13 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const decltype(this->_parameters)::const_iterator ite; - // MUSTs + // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) { if (ite->second->len() != QUICStatelessResetToken::LEN) { return -1; } - } else { - return -2; } - // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::PREFERRED_ADDRESS)) != this->_parameters.end()) { if (ite->second->len() < QUICPreferredAddress::MIN_LEN || QUICPreferredAddress::MAX_LEN < ite->second->len()) { return -3; @@ -509,16 +506,13 @@ QUICTransportParametersInNewSessionTicket::_validate_parameters() const decltype(this->_parameters)::const_iterator ite; - // MUSTs + // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) { if (ite->second->len() != QUICStatelessResetToken::LEN) { return -1; } - } else { - return -2; } - // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS)) != this->_parameters.end()) { if (ite->second->len() != 4) { return -3; From 30b4edd4c43a2dfdd47455b5f0ea8dd8e1f4c2a0 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 22 Jun 2018 10:43:52 +0900 Subject: [PATCH 0657/1313] Remove unused variables --- iocore/net/quic/QUICPacket.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 7a4b076059a..7010acd38b4 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -760,7 +760,6 @@ QUICPacket::protect_packet_number(uint8_t *packet, size_t packet_len, const QUIC size_t pn_offset = 0; uint8_t pn_len = 4; size_t sample_offset = 0; - uint8_t sample_len = 0; constexpr int aead_expansion = 16; // Currently, AEAD expansion (which is probably AEAD tag) length is always 16 QUICKeyPhase phase; @@ -781,7 +780,6 @@ QUICPacket::protect_packet_number(uint8_t *packet, size_t packet_len, const QUIC QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, dcil); } sample_offset = std::min(pn_offset + 4, packet_len - aead_expansion); - sample_len = 16; // On draft-12, the length is always 16 (See 5.6.1 and 5.6.2) uint8_t protected_pn[4] = {0}; uint8_t protected_pn_len = 0; @@ -799,7 +797,6 @@ QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, const QU size_t pn_offset = 0; uint8_t pn_len = 4; size_t sample_offset = 0; - uint8_t sample_len = 0; constexpr int aead_expansion = 16; // Currently, AEAD expansion (which is probably AEAD tag) length is always 16 QUICKeyPhase phase; @@ -826,7 +823,6 @@ QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, const QU QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, QUICConfigParams::scid_len()); } sample_offset = std::min(pn_offset + 4, packet_len - aead_expansion); - sample_len = 16; // On draft-12, the length is always 16 (See 5.6.1 and 5.6.2) uint8_t unprotected_pn[4] = {0}; uint8_t unprotected_pn_len = 0; From 7034f0d6d35fb72c3eccea6a8d1d2deb560da2e6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 22 Jun 2018 12:06:57 +0900 Subject: [PATCH 0658/1313] Fix a build issue on gcc environment --- src/traffic_server/Makefile.inc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/traffic_server/Makefile.inc b/src/traffic_server/Makefile.inc index c31ca65c135..a759d3ebea3 100644 --- a/src/traffic_server/Makefile.inc +++ b/src/traffic_server/Makefile.inc @@ -75,12 +75,6 @@ traffic_server_traffic_server_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/proxy/libproxy.a -if ENABLE_QUIC -traffic_server_traffic_server_LDADD += \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/proxy/hq/libhq.a -endif - # ToDo: When we remove this, we hould merge the two _LDADD rules here traffic_server_traffic_server_LDADD += \ $(top_builddir)/iocore/net/libinknet.a \ @@ -98,3 +92,9 @@ traffic_server_traffic_server_LDADD += \ @OPENSSL_LIBS@ \ @LIB_YAMLCPP@ \ -lm + +if ENABLE_QUIC +traffic_server_traffic_server_LDADD += \ + $(top_builddir)/proxy/hq/libhq.a \ + $(top_builddir)/iocore/net/quic/libquic.a +endif From c6db432e5f2a6e5fe003028d1f5325f9974a6f85 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 22 Jun 2018 14:41:23 +0900 Subject: [PATCH 0659/1313] Small refactoring --- iocore/net/quic/QUICPacket.cc | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 7010acd38b4..777a5609868 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -132,14 +132,11 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf { uint8_t *raw_buf = this->_buf.get(); - uint8_t dcil = (raw_buf[5] >> 4); - if (dcil) { - dcil += 3; - } - uint8_t scil = (raw_buf[5] & 0x0F); - if (scil) { - scil += 3; - } + uint8_t dcil = 0; + uint8_t scil = 0; + QUICPacketLongHeader::dcil(dcil, raw_buf, len); + QUICPacketLongHeader::dcil(scil, raw_buf, len); + size_t offset = LONG_HDR_OFFSET_CONNECTION_ID; this->_destination_cid = {raw_buf + offset, dcil}; offset += dcil; From 6e85c9c8518526f158484f99e34c671a4e1afaa8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 22 Jun 2018 16:10:28 +0900 Subject: [PATCH 0660/1313] Fix a bug in the previous commit --- iocore/net/quic/QUICPacket.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 777a5609868..6706cee7a6c 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -135,7 +135,7 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf uint8_t dcil = 0; uint8_t scil = 0; QUICPacketLongHeader::dcil(dcil, raw_buf, len); - QUICPacketLongHeader::dcil(scil, raw_buf, len); + QUICPacketLongHeader::scil(scil, raw_buf, len); size_t offset = LONG_HDR_OFFSET_CONNECTION_ID; this->_destination_cid = {raw_buf + offset, dcil}; From ef3334b73486bf7409ac73dadd2d465c2a7999c6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 25 Jun 2018 12:16:38 +0900 Subject: [PATCH 0661/1313] Cleanup: simplify check program of QUIC Before this change, `make distclean` didn't work. Because many files in upper directories are specified in *_SOURCES. --- .gitignore | 24 +- configure.ac | 2 - iocore/net/quic/Makefile.am | 53 +- iocore/net/quic/Mock.h | 10 +- iocore/net/quic/test/Makefile.am | 579 ------------------ .../quic/test/{stub_QUICConfig.cc => stub.cc} | 8 + .../quic/test/test_QUICHandshakeProtocol.cc | 2 +- iocore/net/quic/test/test_QUICKeyGenerator.cc | 16 - proxy/hq/Makefile.am | 34 +- proxy/hq/test/Makefile.am | 81 --- 10 files changed, 96 insertions(+), 713 deletions(-) delete mode 100644 iocore/net/quic/test/Makefile.am rename iocore/net/quic/test/{stub_QUICConfig.cc => stub.cc} (88%) delete mode 100644 proxy/hq/test/Makefile.am diff --git a/.gitignore b/.gitignore index 7e7997791d5..70bd6846f33 100644 --- a/.gitignore +++ b/.gitignore @@ -94,25 +94,8 @@ lib/perl/lib/Apache/TS.pm iocore/net/test_certlookup iocore/net/test_UDPNet -iocore/net/quic/test/test_QUICAckFrameCreator -iocore/net/quic/test/test_QUICHandshakeProtocol -iocore/net/quic/test/test_QUICFlowController -iocore/net/quic/test/test_QUICFrame -iocore/net/quic/test/test_QUICFrameDispatcher -iocore/net/quic/test/test_QUICLossDetector -iocore/net/quic/test/test_QUICHandshake -iocore/net/quic/test/test_QUICIncomingFrameBuffer -iocore/net/quic/test/test_QUICInvariants -iocore/net/quic/test/test_QUICKeyGenerator -iocore/net/quic/test/test_QUICPacket -iocore/net/quic/test/test_QUICPacketFactory -iocore/net/quic/test/test_QUICStream -iocore/net/quic/test/test_QUICStreamManager -iocore/net/quic/test/test_QUICStreamState -iocore/net/quic/test/test_QUICTransportParameters -iocore/net/quic/test/test_QUICTypeUtil -iocore/net/quic/test/test_QUICVersionNegotiator -iocore/net/quic/ts_quic_client +iocore/net/quic/test_libquic +iocore/net/quic/test_libquic_w_ep iocore/aio/test_AIO iocore/eventsystem/test_Buffer iocore/eventsystem/test_Event @@ -127,8 +110,7 @@ proxy/http2/test_Huffmancode proxy/http2/test_Http2DependencyTree proxy/http2/test_HPACK proxy/http2/hpack-tests/results -proxy/hq/test/test_HQFrame -proxy/hq/test/test_HQFrameDispatcher +proxy/hq/test_libhq proxy/logging/test_LogUtils plugins/header_rewrite/header_rewrite_test diff --git a/configure.ac b/configure.ac index f12211219f8..ef8a4dd34d2 100644 --- a/configure.ac +++ b/configure.ac @@ -2065,7 +2065,6 @@ AC_CONFIG_FILES([ iocore/hostdb/Makefile iocore/net/Makefile iocore/net/quic/Makefile - iocore/net/quic/test/Makefile iocore/utils/Makefile lib/Makefile lib/cppapi/Makefile @@ -2095,7 +2094,6 @@ AC_CONFIG_FILES([ proxy/http/remap/Makefile proxy/http2/Makefile proxy/hq/Makefile - proxy/hq/test/Makefile proxy/logging/Makefile proxy/shared/Makefile rc/Makefile diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index d9787f5aec0..d70093f7772 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -16,8 +16,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -SUBDIRS = test - AM_CPPFLAGS += \ $(iocore_include_dirs) \ -I$(abs_top_srcdir)/lib \ @@ -79,6 +77,57 @@ libquic_a_SOURCES = \ QUICPathValidator.cc \ QUICStatelessRetry.cc +# +# Check Programs +# + +check_PROGRAMS = \ + test_libquic + +test_libquic_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(abs_top_srcdir)/tests/include + +test_libquic_LDFLAGS = \ + @AM_LDFLAGS@ + +test_libquic_LDADD = \ + libquic.a \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + @LIBTCL@ @OPENSSL_LIBS@ \ + @HWLOC_LIBS@ + +test_libquic_SOURCES = \ + ./test/event_processor_main.cc \ + ./test/stub.cc \ + ./test/test_QUICAckFrameCreator.cc \ + ./test/test_QUICFlowController.cc \ + ./test/test_QUICFrame.cc \ + ./test/test_QUICFrameDispatcher.cc \ + ./test/test_QUICLossDetector.cc \ + ./test/test_QUICHandshake.cc \ + ./test/test_QUICHandshakeProtocol.cc \ + ./test/test_QUICIncomingFrameBuffer.cc \ + ./test/test_QUICInvariants.cc \ + ./test/test_QUICKeyGenerator.cc \ + ./test/test_QUICPacket.cc \ + ./test/test_QUICPacketFactory.cc \ + ./test/test_QUICStream.cc \ + ./test/test_QUICStreamManager.cc \ + ./test/test_QUICStreamState.cc \ + ./test/test_QUICTransportParameters.cc \ + ./test/test_QUICTypeUtil.cc \ + ./test/test_QUICVersionNegotiator.cc + +TESTS = $(check_PROGRAMS) + +# +# clang-tidy +# include $(top_srcdir)/build/tidy.mk tidy-local: $(DIST_SOURCES) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 9c578deffd6..b2e26245e1d 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -20,6 +20,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +#pragma once + #include "P_Net.h" #include "QUICApplication.h" @@ -592,13 +595,6 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol } }; -void NetVConnection::cancel_OOB(){}; -Action * -NetVConnection::send_OOB(Continuation *, char *, int) -{ - return nullptr; -} - class MockContinuation : public Continuation { public: diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am deleted file mode 100644 index b80c094d129..00000000000 --- a/iocore/net/quic/test/Makefile.am +++ /dev/null @@ -1,579 +0,0 @@ -# Makefile.am for the traffic/iocore/net hierarchy -# -# 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. - -TESTS = $(check_PROGRAMS) -check_PROGRAMS = \ - test_QUICInvariants \ - test_QUICPacket \ - test_QUICPacketFactory \ - test_QUICFrame \ - test_QUICFrameDispatcher \ - test_QUICStreamState \ - test_QUICStream \ - test_QUICStreamManager \ - test_QUICTransportParameters \ - test_QUICKeyGenerator \ - test_QUICHandshakeProtocol \ - test_QUICLossDetector \ - test_QUICTypeUtil \ - test_QUICAckFrameCreator \ - test_QUICVersionNegotiator \ - test_QUICFlowController \ - test_QUICIncomingFrameBuffer \ - test_QUICHandshake - -AM_CPPFLAGS += \ - $(iocore_include_dirs) \ - -I$(abs_top_srcdir)/lib \ - -I$(abs_top_srcdir)/lib/records \ - -I$(abs_top_srcdir)/mgmt \ - -I$(abs_top_srcdir)/mgmt/utils \ - -I$(abs_top_srcdir)/proxy \ - -I$(abs_top_srcdir)/proxy/hdrs \ - -I$(abs_top_srcdir)/proxy/http \ - -I$(abs_top_srcdir)/proxy/logging \ - -I$(abs_top_srcdir)/proxy/shared \ - -I$(abs_top_srcdir)/tests/include \ - $(TS_INCLUDES) \ - @OPENSSL_INCLUDES@ - -if OPENSSL_IS_BORINGSSL -QUICKeyGenerator_impl = ../QUICKeyGenerator_boringssl.cc -QUICTLS_impl = ../QUICTLS_boringssl.cc -else -QUICKeyGenerator_impl = ../QUICKeyGenerator_openssl.cc -QUICTLS_impl = ../QUICTLS_openssl.cc -endif - -catch_main = \ - main.cc \ - stub_QUICConfig.cc \ - ../../SSLNextProtocolSet.cc - -catch_event_processor_main = \ - event_processor_main.cc \ - stub_QUICConfig.cc \ - ../../SSLNextProtocolSet.cc - -test_LDADD = \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/lib/ts/libtsutil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ @OPENSSL_LIBS@ \ - @HWLOC_LIBS@ - -# -# test_QUICInvariants -# -test_QUICInvariants_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICInvariants_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICInvariants_SOURCES = \ - $(catch_main) \ - test_QUICInvariants.cc - -test_QUICInvariants_LDADD = \ - $(test_LDADD) - -# -# test_QUICPacket -# -test_QUICPacket_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICPacket_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICPacket_SOURCES = \ - $(catch_main) \ - test_QUICPacket.cc \ - ../QUICPacket.cc \ - ../QUICHandshakeProtocol.cc \ - ../QUICTLS.cc \ - $(QUICTLS_impl) \ - ../QUICTypes.cc - -test_QUICPacket_LDADD = \ - $(test_LDADD) - -# -# test_QUICPacketFactory -# -test_QUICPacketFactory_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICPacketFactory_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICPacketFactory_SOURCES = \ - $(catch_main) \ - test_QUICPacketFactory.cc \ - ../QUICPacket.cc \ - ../QUICHandshakeProtocol.cc \ - ../QUICTLS.cc \ - $(QUICTLS_impl) \ - ../QUICTypes.cc - -test_QUICPacketFactory_LDADD = \ - $(test_LDADD) - -# -# test_QUICFrame -# -test_QUICFrame_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICFrame_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICFrame_SOURCES = \ - $(catch_main) \ - test_QUICFrame.cc \ - ../QUICGlobals.cc \ - ../QUICFrame.cc \ - ../QUICPacket.cc \ - ../QUICKeyGenerator.cc \ - $(QUICKeyGenerator_impl) \ - ../QUICHKDF.cc \ - ../QUICHandshakeProtocol.cc \ - ../QUICTLS.cc \ - $(QUICTLS_impl) \ - ../QUICTypes.cc \ - ../QUICIntUtil.cc \ - ../QUICStream.cc \ - ../QUICStreamState.cc \ - ../QUICIncomingFrameBuffer.cc \ - ../QUICDebugNames.cc \ - ../QUICFlowController.cc - -test_QUICFrame_LDADD = \ - $(test_LDADD) - -# -# test_QUICFrameDispatcher -# -test_QUICFrameDispatcher_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICFrameDispatcher_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICFrameDispatcher_SOURCES = \ - $(catch_event_processor_main) \ - test_QUICFrameDispatcher.cc \ - ../QUICGlobals.cc \ - ../QUICConfig.cc \ - ../QUICVersionNegotiator.cc \ - ../QUICFrameDispatcher.cc \ - ../QUICTransportParameters.cc \ - ../QUICStreamManager.cc \ - ../QUICApplicationMap.cc \ - ../QUICCongestionController.cc \ - ../QUICFlowController.cc \ - ../QUICLossDetector.cc \ - ../QUICFrame.cc \ - ../QUICPacket.cc \ - ../QUICStream.cc \ - ../QUICStreamState.cc \ - ../QUICIncomingFrameBuffer.cc \ - ../QUICApplication.cc \ - ../QUICHandshake.cc \ - ../QUICTypes.cc \ - ../QUICIntUtil.cc \ - ../QUICEchoApp.cc \ - ../QUICDebugNames.cc \ - ../QUICHandshakeProtocol.cc \ - ../QUICTLS.cc \ - $(QUICTLS_impl) \ - ../QUICKeyGenerator.cc \ - $(QUICKeyGenerator_impl) \ - ../QUICHKDF.cc - -test_QUICFrameDispatcher_LDADD = \ - $(test_LDADD) - -# -# test_QUICStreamState -# -test_QUICStreamState_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICStreamState_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICStreamState_SOURCES = \ - $(catch_main) \ - test_QUICStreamState.cc \ - ../QUICStreamState.cc - -test_QUICStreamState_LDADD = \ - $(test_LDADD) - -# -# test_QUICStream -# -test_QUICStream_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICStream_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICStream_SOURCES = \ - $(catch_event_processor_main) \ - test_QUICStream.cc \ - ../QUICStream.cc \ - ../QUICIncomingFrameBuffer.cc \ - ../QUICFrameDispatcher.cc \ - ../QUICStreamManager.cc \ - ../QUICApplicationMap.cc \ - ../QUICCongestionController.cc - -test_QUICStream_LDADD = \ - $(test_LDADD) - -# -# test_QUICStreamManager -# -test_QUICStreamManager_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICStreamManager_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICStreamManager_SOURCES = \ - $(catch_event_processor_main) \ - test_QUICStreamManager.cc \ - ../QUICStream.cc \ - ../QUICIncomingFrameBuffer.cc \ - ../QUICFrameDispatcher.cc \ - ../QUICStreamManager.cc \ - ../QUICApplicationMap.cc \ - ../QUICCongestionController.cc \ - ../QUICConfig.cc - -test_QUICStreamManager_LDADD = \ - $(test_LDADD) - -# -# test_QUICTransportParameters -# -test_QUICTransportParameters_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICTransportParameters_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICTransportParameters_SOURCES = \ - $(catch_main) \ - test_QUICTransportParameters.cc \ - ../QUICGlobals.cc \ - ../QUICConfig.cc \ - ../QUICApplication.cc \ - ../QUICApplicationMap.cc \ - ../QUICHandshake.cc \ - ../QUICVersionNegotiator.cc \ - ../QUICHandshakeProtocol.cc \ - ../QUICTLS.cc \ - $(QUICTLS_impl) \ - ../QUICKeyGenerator.cc \ - $(QUICKeyGenerator_impl) \ - ../QUICHKDF.cc \ - ../QUICStream.cc \ - ../QUICIncomingFrameBuffer.cc \ - ../QUICStreamState.cc \ - ../QUICStreamManager.cc \ - ../QUICFlowController.cc \ - ../QUICPacket.cc \ - ../QUICFrame.cc \ - ../QUICDebugNames.cc \ - ../QUICTransportParameters.cc \ - ../QUICTypes.cc \ - ../QUICIntUtil.cc - -test_QUICTransportParameters_LDADD = \ - $(test_LDADD) - -# -# test_QUICKeyGenerator -# -test_QUICKeyGenerator_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICKeyGenerator_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICKeyGenerator_LDADD = \ - $(test_LDADD) - -test_QUICKeyGenerator_SOURCES = \ - $(catch_main) \ - test_QUICKeyGenerator.cc \ - ../QUICKeyGenerator.cc \ - $(QUICKeyGenerator_impl) \ - ../QUICDebugNames.cc \ - ../QUICIncomingFrameBuffer.cc \ - ../QUICFlowController.cc \ - ../QUICPacket.cc \ - ../QUICStreamState.cc \ - ../QUICFrame.cc \ - ../QUICStream.cc \ - ../QUICHKDF.cc \ - ../QUICIntUtil.cc \ - ../QUICTypes.cc - -# -# test_QUICHandshakeProtocol -# -test_QUICHandshakeProtocol_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICHandshakeProtocol_LDFLAGS = \ - @AM_LDFLAGS@ \ - @OPENSSL_LDFLAGS@ - -test_QUICHandshakeProtocol_LDADD = \ - $(test_LDADD) - -test_QUICHandshakeProtocol_SOURCES = \ - $(catch_main) \ - test_QUICHandshakeProtocol.cc \ - ../QUICKeyGenerator.cc \ - $(QUICKeyGenerator_impl) \ - ../QUICHKDF.cc \ - ../QUICHandshakeProtocol.cc \ - ../QUICTLS.cc \ - $(QUICTLS_impl) \ - ../QUICHandshakeProtocol.h \ - ../QUICTypes.cc \ - ../QUICIntUtil.cc \ - ../QUICDebugNames.cc \ - ../QUICStreamState.cc \ - ../QUICFrame.cc \ - ../QUICStream.cc \ - ../QUICPacket.cc \ - ../QUICIncomingFrameBuffer.cc \ - ../QUICFlowController.cc \ - ../QUICGlobals.cc - -# -# test_QUICLossDetector -# -test_QUICLossDetector_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICLossDetector_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICLossDetector_LDADD = \ - $(test_LDADD) - -test_QUICLossDetector_SOURCES = \ - $(catch_event_processor_main) \ - test_QUICLossDetector.cc \ - ../QUICLossDetector.cc \ - ../QUICTypes.cc \ - ../QUICPacket.cc \ - ../QUICHandshakeProtocol.cc \ - ../QUICTLS.cc \ - $(QUICTLS_impl) \ - ../QUICFrame.cc - -# -# test_QUICTypeUtil -# -test_QUICTypeUtil_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICTypeUtil_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICTypeUtil_LDADD = \ - $(test_LDADD) - -test_QUICTypeUtil_SOURCES = \ - $(catch_main) \ - test_QUICTypeUtil.cc \ - ../QUICStream.cc \ - ../QUICIncomingFrameBuffer.cc \ - ../QUICStreamState.cc \ - ../QUICFlowController.cc \ - ../QUICDebugNames.cc \ - ../QUICFrame.cc \ - ../QUICPacket.cc \ - ../QUICKeyGenerator.cc \ - $(QUICKeyGenerator_impl) \ - ../QUICHKDF.cc \ - ../QUICHandshakeProtocol.cc \ - ../QUICTLS.cc \ - $(QUICTLS_impl) \ - ../QUICIntUtil.cc \ - ../QUICTypes.cc - -# -# test_QUICAckFrameCreator -# -test_QUICAckFrameCreator_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICAckFrameCreator_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICAckFrameCreator_LDADD = \ - $(test_LDADD) - -test_QUICAckFrameCreator_SOURCES = \ - $(catch_main) \ - test_QUICAckFrameCreator.cc \ - ../QUICAckFrameCreator.cc \ - ../QUICGlobals.cc \ - ../QUICTypes.cc \ - ../QUICIntUtil.cc \ - ../QUICFrame.cc \ - ../QUICPacket.cc \ - ../QUICStream.cc \ - ../QUICIncomingFrameBuffer.cc \ - ../QUICStreamState.cc \ - ../QUICFlowController.cc \ - ../QUICDebugNames.cc \ - ../QUICKeyGenerator.cc \ - $(QUICKeyGenerator_impl) \ - ../QUICHKDF.cc \ - ../QUICHandshakeProtocol.cc \ - ../QUICTLS.cc \ - $(QUICTLS_impl) - -# -# test_QUICTypeUtil -# -test_QUICVersionNegotiator_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICVersionNegotiator_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICVersionNegotiator_LDADD = \ - $(test_LDADD) - -test_QUICVersionNegotiator_SOURCES = \ - $(catch_main) \ - test_QUICVersionNegotiator.cc \ - ../QUICGlobals.cc \ - ../QUICTypes.cc \ - ../QUICIntUtil.cc \ - ../QUICPacket.cc \ - ../QUICKeyGenerator.cc \ - $(QUICKeyGenerator_impl) \ - ../QUICHKDF.cc \ - ../QUICHandshakeProtocol.cc \ - ../QUICTLS.cc \ - $(QUICTLS_impl) \ - ../QUICApplication.cc \ - ../QUICApplicationMap.cc \ - ../QUICHandshake.cc \ - ../QUICStream.cc \ - ../QUICIncomingFrameBuffer.cc \ - ../QUICStreamState.cc \ - ../QUICStreamManager.cc \ - ../QUICFlowController.cc \ - ../QUICFrame.cc \ - ../QUICDebugNames.cc \ - ../QUICVersionNegotiator.cc \ - ../QUICTransportParameters.cc \ - ../QUICConfig.cc - -# -# test_QUICFlowController -# -test_QUICFlowController_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICFlowController_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICFlowController_LDADD = \ - $(test_LDADD) - -test_QUICFlowController_SOURCES = \ - $(catch_main) \ - test_QUICFlowController.cc \ - ../QUICFlowController.cc \ - ../QUICStream.cc \ - ../QUICIncomingFrameBuffer.cc \ - ../QUICStreamState.cc \ - ../QUICDebugNames.cc \ - ../QUICTypes.cc \ - ../QUICIntUtil.cc \ - ../QUICPacket.cc \ - ../QUICKeyGenerator.cc \ - $(QUICKeyGenerator_impl) \ - ../QUICHKDF.cc \ - ../QUICHandshakeProtocol.cc \ - ../QUICTLS.cc \ - $(QUICTLS_impl) \ - ../QUICFrame.cc \ - ../QUICLossDetector.cc - -# -# test_QUICIncomingFrameBuffer -# -test_QUICIncomingFrameBuffer_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICIncomingFrameBuffer_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICIncomingFrameBuffer_SOURCES = \ - $(catch_event_processor_main) \ - ../QUICStream.cc \ - ../QUICFrameDispatcher.cc \ - ../QUICStreamManager.cc \ - ../QUICApplicationMap.cc \ - ../QUICCongestionController.cc \ - ../QUICIncomingFrameBuffer.cc \ - test_QUICIncomingFrameBuffer.cc - -test_QUICIncomingFrameBuffer_LDADD = \ - $(test_LDADD) - -# -# test_QUICHandshake -# -test_QUICHandshake_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_QUICHandshake_LDFLAGS = \ - @AM_LDFLAGS@ - -test_QUICHandshake_SOURCES = \ - $(catch_event_processor_main) \ - test_QUICHandshake.cc \ - ../QUICHandshake.cc - -test_QUICHandshake_LDADD = \ - $(test_LDADD) - -include $(top_srcdir)/build/tidy.mk - -tidy-local: $(DIST_SOURCES) - $(CXX_Clang_Tidy) diff --git a/iocore/net/quic/test/stub_QUICConfig.cc b/iocore/net/quic/test/stub.cc similarity index 88% rename from iocore/net/quic/test/stub_QUICConfig.cc rename to iocore/net/quic/test/stub.cc index aa817abcea3..958661a5c53 100644 --- a/iocore/net/quic/test/stub_QUICConfig.cc +++ b/iocore/net/quic/test/stub.cc @@ -41,3 +41,11 @@ SSLConfig::release(SSLConfigParams *) { return; } + +#include "P_SSLNextProtocolSet.h" + +bool +SSLNextProtocolSet::advertiseProtocols(const unsigned char **out, unsigned *len) const +{ + return true; +} diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index f24c6577a5b..1e5e2273103 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -40,7 +40,7 @@ static constexpr uint32_t MAX_HANDSHAKE_MSG_LEN = 2048; #include "./server_cert.h" -void +static void print_hex(const uint8_t *v, size_t len) { for (size_t i = 0; i < len; i++) { diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index 71123908f1e..ffb8c37102b 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -35,22 +35,6 @@ #include "Mock.h" #include "QUICKeyGenerator.h" -void -print_hex(const uint8_t *v, size_t len) -{ - for (size_t i = 0; i < len; i++) { - std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast(v[i]) << " "; - - if (i != 0 && (i + 1) % 32 == 0 && i != len - 1) { - std::cout << std::endl; - } - } - - std::cout << std::endl; - - return; -} - TEST_CASE("QUICKeyGenerator", "[quic]") { SECTION("CLIENT Cleartext") diff --git a/proxy/hq/Makefile.am b/proxy/hq/Makefile.am index 17b99b6a83f..32765309f0c 100644 --- a/proxy/hq/Makefile.am +++ b/proxy/hq/Makefile.am @@ -17,10 +17,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -include $(top_srcdir)/build/tidy.mk - -SUBDIRS = test - AM_CPPFLAGS += \ $(iocore_include_dirs) \ -I$(abs_top_srcdir)/proxy/api/ts \ @@ -51,5 +47,35 @@ libhq_a_SOURCES = \ HQStreamDataVIOAdaptor.cc \ QUICSimpleApp.cc +# +# Check Programs +# +check_PROGRAMS = \ + test_libhq + +TESTS = $(check_PROGRAMS) + +test_libhq_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(abs_top_srcdir)/tests/include + +test_libhq_LDFLAGS = \ + @AM_LDFLAGS@ + +test_libhq_SOURCES = \ + ./test/main.cc \ + ./test/test_HQFrame.cc \ + ./test/test_HQFrameDispatcher.cc + +test_libhq_LDADD = \ + libhq.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/lib/ts/libtsutil.la + +# +# clang-tidy +# +include $(top_srcdir)/build/tidy.mk + tidy-local: $(libhq_a_SOURCES) \ $(CXX_Clang_Tidy) diff --git a/proxy/hq/test/Makefile.am b/proxy/hq/test/Makefile.am deleted file mode 100644 index 10536c9a1ed..00000000000 --- a/proxy/hq/test/Makefile.am +++ /dev/null @@ -1,81 +0,0 @@ -# Makefile.am for the traffic/iocore/net hierarchy -# -# 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. - -TESTS = $(check_PROGRAMS) -check_PROGRAMS = \ - test_HQFrame \ - test_HQFrameDispatcher - - -AM_CPPFLAGS += \ - $(iocore_include_dirs) \ - -I$(abs_top_srcdir)/lib \ - -I$(abs_top_srcdir)/lib/records \ - -I$(abs_top_srcdir)/mgmt \ - -I$(abs_top_srcdir)/mgmt/utils \ - -I$(abs_top_srcdir)/proxy \ - -I$(abs_top_srcdir)/proxy/hdrs \ - -I$(abs_top_srcdir)/proxy/http \ - -I$(abs_top_srcdir)/proxy/hq \ - -I$(abs_top_srcdir)/proxy/logging \ - -I$(abs_top_srcdir)/proxy/shared \ - -I$(abs_top_srcdir)/tests/include \ - @OPENSSL_INCLUDES@ - -# -# test_HQFrame -# -test_HQFrame_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_HQFrame_LDFLAGS = \ - @AM_LDFLAGS@ - -test_HQFrame_SOURCES = \ - main.cc \ - test_HQFrame.cc \ - ../HQFrame.cc - -test_HQFrame_LDADD = \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/ts/libtsutil.la - -# -# test_HQFrameDispatcher -# -test_HQFrameDispatcher_CPPFLAGS = \ - $(AM_CPPFLAGS) - -test_HQFrameDispatcher_LDFLAGS = \ - @AM_LDFLAGS@ - -test_HQFrameDispatcher_SOURCES = \ - main.cc \ - test_HQFrameDispatcher.cc \ - ../HQFrameDispatcher.cc \ - ../HQFrame.cc - -test_HQFrameDispatcher_LDADD = \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/lib/ts/libtsutil.la - - -include $(top_srcdir)/build/tidy.mk - -tidy-local: $(DIST_SOURCES) - $(CXX_Clang_Tidy) From d7f1602163b748295cb33af917ab90d2bd4b1e47 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 25 Jun 2018 15:20:50 +0900 Subject: [PATCH 0662/1313] Fix bugs around PN encoding --- iocore/net/quic/QUICPacket.cc | 30 ++++++++++++++++++++++-------- iocore/net/quic/QUICTypes.cc | 4 ++-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 6706cee7a6c..2aa5dee5ccc 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -386,12 +386,12 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const size_t pn_len = 4; QUICPacket::encode_packet_number(pn, this->_packet_number, pn_len); - if (pn < 0x100) { - pn_len = 1; - } else if (pn < 0x4000) { + if (pn > 0x3FFF) { + pn_len = 4; + } else if (pn > 0x7F) { pn_len = 2; } else { - pn_len = 4; + pn_len = 1; } QUICIntUtil::write_QUICVariableInt(pn_len + this->_payload_length + aead_tag_len, buf + *len, &n); @@ -710,9 +710,9 @@ QUICPacket::calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base) uint64_t d = (num - base) * 2; uint8_t len = 0; - if (d > 0xFFFF) { + if (d > 0x3FFF) { len = 4; - } else if (d > 0xFF) { + } else if (d > 0x7F) { len = 2; } else { len = 1; @@ -726,8 +726,22 @@ QUICPacket::encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si { ink_assert(len == 1 || len == 2 || len == 4); - uint64_t mask = (1ULL << (len * 8)) - 1; - dst = src & mask; + uint64_t mask = 0; + switch (len) { + case 1: + mask = 0x7F; + break; + case 2: + mask = 0x3FFF; + break; + case 4: + mask = 0x3FFFFFFF; + break; + default: + ink_assert(!"len must be 1, 2, or 4"); + return false; + } + dst = src & mask; return true; } diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 5fd6336d5b5..812220243b2 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -77,9 +77,9 @@ QUICTypeUtil::read_QUICConnectionId(const uint8_t *buf, uint8_t len) int QUICTypeUtil::read_QUICPacketNumberLen(const uint8_t *buf) { - if (buf[0] & 0xC0) { + if ((buf[0] & 0xC0) == 0xC0) { return 4; - } else if (buf[0] & 0x10) { + } else if ((buf[0] & 0x80) == 0x80) { return 2; } else { return 1; From a114d463a69f664868bc0171e26994ddf9f394d9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 26 Jun 2018 10:39:43 +0900 Subject: [PATCH 0663/1313] Fix another bug around PN calculation --- iocore/net/quic/QUICPacket.cc | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 2aa5dee5ccc..19a86d54579 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -750,13 +750,27 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si { ink_assert(len == 1 || len == 2 || len == 4); - uint64_t maximum_diff = 1ULL << (len * 8); + uint64_t maximum_diff = 0; + switch (len) { + case 1: + maximum_diff = 0x80; + break; + case 2: + maximum_diff = 0x4000; + break; + case 4: + maximum_diff = 0x40000000; + break; + default: + ink_assert(!"len must be 1, 2 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 > largest_acked) ? (candidate1 - largest_acked) : (largest_acked - candidate1)) < - ((candidate2 > largest_acked) ? (candidate2 - largest_acked) : (largest_acked - candidate2))) { + if (((candidate1 > expected) ? (candidate1 - expected) : (expected - candidate1)) < + ((candidate2 > expected) ? (candidate2 - expected) : (expected - candidate2))) { dst = candidate1; } else { dst = candidate2; From 28970d79c990dc7c0274ff35269ce1fec412cc45 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 26 Jun 2018 10:59:41 +0900 Subject: [PATCH 0664/1313] Add a option to enable connection close excercise --- src/traffic_quic/quic_client.cc | 16 +++++++--------- src/traffic_quic/quic_client.h | 7 +++++-- src/traffic_quic/traffic_quic.cc | 1 + 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc index 119b9c33bb9..b5237ac4cbe 100644 --- a/src/traffic_quic/quic_client.cc +++ b/src/traffic_quic/quic_client.cc @@ -83,13 +83,7 @@ QUICClient::state_http_server_open(int event, void *data) Debug("quic_client", "start proxy server ssn/txn"); QUICNetVConnection *conn = static_cast(data); - - const char *filename = nullptr; - if (this->_config->output[0] != 0x0) { - filename = this->_config->output; - } - - QUICClientApp *app = new QUICClientApp(conn, filename); + QUICClientApp *app = new QUICClientApp(conn, this->_config); app->start(this->_config->path); break; @@ -115,7 +109,7 @@ QUICClient::state_http_server_open(int event, void *data) #define QUICClientAppDebug(fmt, ...) Debug("quic_client_app", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) #define QUICClientAppVDebug(fmt, ...) Debug("v_quic_client_app", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) -QUICClientApp::QUICClientApp(QUICNetVConnection *qvc, const char *filename) : QUICApplication(qvc), _filename(filename) +QUICClientApp::QUICClientApp(QUICNetVConnection *qvc, const QUICClientConfig *config) : QUICApplication(qvc), _config(config) { this->_qc->stream_manager()->set_default_application(this); @@ -125,6 +119,10 @@ QUICClientApp::QUICClientApp(QUICNetVConnection *qvc, const char *filename) : QU void QUICClientApp::start(const char *path) { + if (this->_config->output[0] != 0x0) { + this->_filename = this->_config->output; + } + if (this->_filename) { // Destroy contents if file already exists std::ofstream f_stream(this->_filename, std::ios::binary | std::ios::trunc); @@ -191,7 +189,7 @@ QUICClientApp::main_event_handler(int event, Event *data) std::cout.rdbuf(default_stream); } - if (stream_io->is_read_done()) { + if (stream_io->is_read_done() && this->_config->close) { // Connection Close Exercise this->_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::NO_ERROR, "Close Exercise"))); } diff --git a/src/traffic_quic/quic_client.h b/src/traffic_quic/quic_client.h index 0e3e534c857..9cd7573c688 100644 --- a/src/traffic_quic/quic_client.h +++ b/src/traffic_quic/quic_client.h @@ -30,12 +30,14 @@ #include "QUICApplication.h" +// TODO: add quic version option struct QUICClientConfig { char addr[1024] = "127.0.0.1"; char output[1024] = {0}; char port[16] = "4433"; char path[1018] = "/"; char debug_tags[1024] = "quic"; + int close = false; }; class QUICClient : public Continuation @@ -55,11 +57,12 @@ class QUICClient : public Continuation class QUICClientApp : public QUICApplication { public: - QUICClientApp(QUICNetVConnection *qvc, const char *filename); + QUICClientApp(QUICNetVConnection *qvc, const QUICClientConfig *config); void start(const char *path); int main_event_handler(int event, Event *data); private: - const char *_filename = nullptr; + const QUICClientConfig *_config = nullptr; + const char *_filename = nullptr; }; diff --git a/src/traffic_quic/traffic_quic.cc b/src/traffic_quic/traffic_quic.cc index ec81a4582e7..67802af879e 100644 --- a/src/traffic_quic/traffic_quic.cc +++ b/src/traffic_quic/traffic_quic.cc @@ -57,6 +57,7 @@ main(int argc, const char **argv) {"port", 'p', "Port", "S15", config.port, nullptr, nullptr}, {"path", 'P', "Path", "S1017", config.path, nullptr, nullptr}, {"debug", 'T', "Vertical-bar-separated Debug Tags", "S1023", config.debug_tags, nullptr, nullptr}, + {"close", 'c', "Enable connection close excercise", "F", &config.close, nullptr, nullptr}, HELP_ARGUMENT_DESCRIPTION(), VERSION_ARGUMENT_DESCRIPTION(), RUNROOT_ARGUMENT_DESCRIPTION(), From 4e2b166c4ae3e20f704d214567017798cf6e5c0d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 26 Jun 2018 11:37:34 +0900 Subject: [PATCH 0665/1313] Cleanup: break down test_libquic into small check programs --- .gitignore | 20 +++- iocore/net/quic/Makefile.am | 180 ++++++++++++++++++++++++++++++------ 2 files changed, 171 insertions(+), 29 deletions(-) diff --git a/.gitignore b/.gitignore index 70bd6846f33..cdccef75e69 100644 --- a/.gitignore +++ b/.gitignore @@ -94,8 +94,24 @@ lib/perl/lib/Apache/TS.pm iocore/net/test_certlookup iocore/net/test_UDPNet -iocore/net/quic/test_libquic -iocore/net/quic/test_libquic_w_ep +iocore/net/quic/test_QUICAckFrameCreator +iocore/net/quic/test_QUICFlowController +iocore/net/quic/test_QUICFrame +iocore/net/quic/test_QUICFrameDispatcher +iocore/net/quic/test_QUICHandshake +iocore/net/quic/test_QUICHandshakeProtocol +iocore/net/quic/test_QUICIncomingFrameBuffer +iocore/net/quic/test_QUICInvariants +iocore/net/quic/test_QUICKeyGenerator +iocore/net/quic/test_QUICLossDetector +iocore/net/quic/test_QUICPacket +iocore/net/quic/test_QUICPacketFactory +iocore/net/quic/test_QUICStream +iocore/net/quic/test_QUICStreamManager +iocore/net/quic/test_QUICStreamState +iocore/net/quic/test_QUICTransportParameters +iocore/net/quic/test_QUICTypeUtil +iocore/net/quic/test_QUICVersionNegotiator iocore/aio/test_AIO iocore/eventsystem/test_Buffer iocore/eventsystem/test_Event diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index d70093f7772..7411ef2c337 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -82,16 +82,32 @@ libquic_a_SOURCES = \ # check_PROGRAMS = \ - test_libquic + test_QUICAckFrameCreator \ + test_QUICFlowController \ + test_QUICFrame \ + test_QUICFrameDispatcher \ + test_QUICLossDetector \ + test_QUICHandshake \ + test_QUICHandshakeProtocol \ + test_QUICIncomingFrameBuffer \ + test_QUICInvariants \ + test_QUICKeyGenerator \ + test_QUICPacket \ + test_QUICPacketFactory \ + test_QUICStream \ + test_QUICStreamManager \ + test_QUICStreamState \ + test_QUICTransportParameters \ + test_QUICTypeUtil \ + test_QUICVersionNegotiator -test_libquic_CPPFLAGS = \ +TESTS = $(check_PROGRAMS) + +test_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(abs_top_srcdir)/tests/include -test_libquic_LDFLAGS = \ - @AM_LDFLAGS@ - -test_libquic_LDADD = \ +test_LDADD = \ libquic.a \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -101,29 +117,139 @@ test_libquic_LDADD = \ @LIBTCL@ @OPENSSL_LIBS@ \ @HWLOC_LIBS@ -test_libquic_SOURCES = \ +test_event_main_SOURCES = \ ./test/event_processor_main.cc \ - ./test/stub.cc \ - ./test/test_QUICAckFrameCreator.cc \ - ./test/test_QUICFlowController.cc \ - ./test/test_QUICFrame.cc \ - ./test/test_QUICFrameDispatcher.cc \ - ./test/test_QUICLossDetector.cc \ - ./test/test_QUICHandshake.cc \ - ./test/test_QUICHandshakeProtocol.cc \ - ./test/test_QUICIncomingFrameBuffer.cc \ - ./test/test_QUICInvariants.cc \ - ./test/test_QUICKeyGenerator.cc \ - ./test/test_QUICPacket.cc \ - ./test/test_QUICPacketFactory.cc \ - ./test/test_QUICStream.cc \ - ./test/test_QUICStreamManager.cc \ - ./test/test_QUICStreamState.cc \ - ./test/test_QUICTransportParameters.cc \ - ./test/test_QUICTypeUtil.cc \ - ./test/test_QUICVersionNegotiator.cc + ./test/stub.cc -TESTS = $(check_PROGRAMS) +test_main_SOURCES = \ + ./test/main.cc \ + ./test/stub.cc + +test_QUICAckFrameCreator_CPPFLAGS = $(test_CPPFLAGS) +test_QUICAckFrameCreator_LDFLAGS = @AM_LDFLAGS@ +test_QUICAckFrameCreator_LDADD = $(test_LDADD) +test_QUICAckFrameCreator_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICAckFrameCreator.cc + +test_QUICFlowController_CPPFLAGS = $(test_CPPFLAGS) +test_QUICFlowController_LDFLAGS = @AM_LDFLAGS@ +test_QUICFlowController_LDADD = $(test_LDADD) +test_QUICFlowController_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICFlowController.cc + +test_QUICFrame_CPPFLAGS = $(test_CPPFLAGS) +test_QUICFrame_LDFLAGS = @AM_LDFLAGS@ +test_QUICFrame_LDADD = $(test_LDADD) +test_QUICFrame_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICFrame.cc + +test_QUICFrameDispatcher_CPPFLAGS = $(test_CPPFLAGS) +test_QUICFrameDispatcher_LDFLAGS = @AM_LDFLAGS@ +test_QUICFrameDispatcher_LDADD = $(test_LDADD) +test_QUICFrameDispatcher_SOURCES = \ + $(test_event_main_SOURCES) \ + ./test/test_QUICFrameDispatcher.cc + +test_QUICLossDetector_CPPFLAGS = $(test_CPPFLAGS) +test_QUICLossDetector_LDFLAGS = @AM_LDFLAGS@ +test_QUICLossDetector_LDADD = $(test_LDADD) +test_QUICLossDetector_SOURCES = \ + $(test_event_main_SOURCES) \ + ./test/test_QUICLossDetector.cc + +test_QUICHandshake_CPPFLAGS = $(test_CPPFLAGS) +test_QUICHandshake_LDFLAGS = @AM_LDFLAGS@ +test_QUICHandshake_LDADD = $(test_LDADD) +test_QUICHandshake_SOURCES = \ + $(test_event_main_SOURCES) \ + ./test/test_QUICHandshake.cc + +test_QUICHandshakeProtocol_CPPFLAGS = $(test_CPPFLAGS) +test_QUICHandshakeProtocol_LDFLAGS = @AM_LDFLAGS@ +test_QUICHandshakeProtocol_LDADD = $(test_LDADD) +test_QUICHandshakeProtocol_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICHandshakeProtocol.cc + +test_QUICIncomingFrameBuffer_CPPFLAGS = $(test_CPPFLAGS) +test_QUICIncomingFrameBuffer_LDFLAGS = @AM_LDFLAGS@ +test_QUICIncomingFrameBuffer_LDADD = $(test_LDADD) +test_QUICIncomingFrameBuffer_SOURCES = \ + $(test_event_main_SOURCES) \ + ./test/test_QUICIncomingFrameBuffer.cc + +test_QUICInvariants_CPPFLAGS = $(test_CPPFLAGS) +test_QUICInvariants_LDFLAGS = @AM_LDFLAGS@ +test_QUICInvariants_LDADD = $(test_LDADD) +test_QUICInvariants_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICInvariants.cc + +test_QUICKeyGenerator_CPPFLAGS = $(test_CPPFLAGS) +test_QUICKeyGenerator_LDFLAGS = @AM_LDFLAGS@ +test_QUICKeyGenerator_LDADD = $(test_LDADD) +test_QUICKeyGenerator_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICKeyGenerator.cc + +test_QUICPacket_CPPFLAGS = $(test_CPPFLAGS) +test_QUICPacket_LDFLAGS = @AM_LDFLAGS@ +test_QUICPacket_LDADD = $(test_LDADD) +test_QUICPacket_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICPacket.cc + +test_QUICPacketFactory_CPPFLAGS = $(test_CPPFLAGS) +test_QUICPacketFactory_LDFLAGS = @AM_LDFLAGS@ +test_QUICPacketFactory_LDADD = $(test_LDADD) +test_QUICPacketFactory_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICPacketFactory.cc + +test_QUICStream_CPPFLAGS = $(test_CPPFLAGS) +test_QUICStream_LDFLAGS = @AM_LDFLAGS@ +test_QUICStream_LDADD = $(test_LDADD) +test_QUICStream_SOURCES = \ + $(test_event_main_SOURCES) \ + ./test/test_QUICStream.cc + +test_QUICStreamManager_CPPFLAGS = $(test_CPPFLAGS) +test_QUICStreamManager_LDFLAGS = @AM_LDFLAGS@ +test_QUICStreamManager_LDADD = $(test_LDADD) +test_QUICStreamManager_SOURCES = \ + $(test_event_main_SOURCES) \ + ./test/test_QUICStreamManager.cc + +test_QUICStreamState_CPPFLAGS = $(test_CPPFLAGS) +test_QUICStreamState_LDFLAGS = @AM_LDFLAGS@ +test_QUICStreamState_LDADD = $(test_LDADD) +test_QUICStreamState_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICStreamState.cc + +test_QUICTransportParameters_CPPFLAGS = $(test_CPPFLAGS) +test_QUICTransportParameters_LDFLAGS = @AM_LDFLAGS@ +test_QUICTransportParameters_LDADD = $(test_LDADD) +test_QUICTransportParameters_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICTransportParameters.cc + +test_QUICTypeUtil_CPPFLAGS = $(test_CPPFLAGS) +test_QUICTypeUtil_LDFLAGS = @AM_LDFLAGS@ +test_QUICTypeUtil_LDADD = $(test_LDADD) +test_QUICTypeUtil_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICTypeUtil.cc + +test_QUICVersionNegotiator_CPPFLAGS = $(test_CPPFLAGS) +test_QUICVersionNegotiator_LDFLAGS = @AM_LDFLAGS@ +test_QUICVersionNegotiator_LDADD = $(test_LDADD) +test_QUICVersionNegotiator_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICVersionNegotiator.cc # # clang-tidy From c11c12e3020e2bf4328c6a6df9a58c93ae7f6390 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 26 Jun 2018 15:14:53 +0900 Subject: [PATCH 0666/1313] Ignore empty stream frames except pure fin stream frame --- iocore/net/quic/QUICIncomingFrameBuffer.cc | 5 +++++ .../quic/test/test_QUICIncomingFrameBuffer.cc | 22 ++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index 66eca10ff53..b945ef84acc 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -64,6 +64,11 @@ QUICIncomingFrameBuffer::insert(const std::shared_ptr fra return err; } + // Ignore empty stream frame except pure fin stream frame + if (len == 0 && !frame->has_fin_flag()) { + return QUICErrorUPtr(new QUICNoError()); + } + if (this->_recv_offset > offset) { // dup frame; return QUICErrorUPtr(new QUICNoError()); diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 1f6c337cd4e..24a069ad30d 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -74,13 +74,17 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") SECTION("Pure FIN") { - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); - std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 0, 1, 1024, true); + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); + std::shared_ptr stream1_frame_empty = QUICFrameFactory::create_stream_frame(data, 0, 1, 1024); + std::shared_ptr stream1_frame_pure_fin = QUICFrameFactory::create_stream_frame(data, 0, 1, 1024, true); err = buffer.insert(stream1_frame_0_r); CHECK(err->cls == QUICErrorClass::NONE); - err = buffer.insert(stream1_frame_1_r); + err = buffer.insert(stream1_frame_empty); + CHECK(err->cls == QUICErrorClass::NONE); + + err = buffer.insert(stream1_frame_pure_fin); CHECK(err->cls == QUICErrorClass::NONE); } @@ -95,14 +99,16 @@ TEST_CASE("QUICIncomingFrameBuffer_pop", "[quic]") uint8_t data[1024] = {0}; - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); - std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); - std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048); - std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 3072); - std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 4096, true); + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); + std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); + std::shared_ptr stream1_frame_empty = QUICFrameFactory::create_stream_frame(data, 0, 1, 2048); + std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048); + std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 3072); + std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 4096, true); buffer.insert(stream1_frame_0_r); buffer.insert(stream1_frame_1_r); + buffer.insert(stream1_frame_empty); buffer.insert(stream1_frame_2_r); buffer.insert(stream1_frame_3_r); buffer.insert(stream1_frame_4_r); From 75db12328189875c861eb1f4f54eca265a485f7a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 28 Jun 2018 16:56:29 +0900 Subject: [PATCH 0667/1313] Add debug prints and assertions --- iocore/net/QUICNetVConnection.cc | 13 ++++++++++--- iocore/net/quic/QUICPacket.cc | 4 ++++ iocore/net/quic/QUICTLS.cc | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a9c9d201f1b..e2049a792f0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -988,14 +988,21 @@ QUICNetVConnection::_state_common_receive_packet() if (this->_handshake_handler->is_completed() && p->destination_cid() != this->_quic_connection_id) { if (this->_alt_con_manager->migrate_to(p->destination_cid(), this->_reset_token)) { // Migrate connection - // TODO Address Validation - this->_quic_connection_id = p->destination_cid(); + this->_update_local_cid(p->destination_cid()); Connection con; con.setRemote(&p->from().sa); this->con.move(con); + 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); + p->destination_cid().hex(new_cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH); + QUICConDebug("Connection migrated from %s to %s", old_cid_str, new_cid_str); + } this->_validate_new_path(); } else { - // TODO Send some error? + QUICConDebug("Connection migration failed"); + ink_assert(!"Connection migration failed"); } } error = this->_state_connection_established_process_packet(std::move(p)); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 19a86d54579..2d892e22487 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -843,6 +843,10 @@ QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, const QU break; } QUICPacketLongHeader::packet_number_offset(pn_offset, packet, packet_len); + + Debug("quic", "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), + QUICDebugNames::key_phase(phase)); + } else { QUICPacketShortHeader::key_phase(phase, packet, packet_len); QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, QUICConfigParams::scid_len()); diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index dad654237fa..7b36b48ca44 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -434,6 +434,7 @@ QUICTLS::_get_km(QUICKeyPhase phase, bool for_encryption) const } break; default: + ink_assert(!"It should not happen"); return nullptr; } From a1ecf66e6bd971ddf9861a654145cdd05883952f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 28 Jun 2018 16:56:59 +0900 Subject: [PATCH 0668/1313] Make 0-RTT available again --- iocore/net/quic/QUICPacket.cc | 8 ++++++-- iocore/net/quic/QUICTLS.cc | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 2d892e22487..5a18b33687c 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -347,8 +347,12 @@ QUICPacketLongHeader::has_key_phase() const QUICKeyPhase QUICPacketLongHeader::key_phase() const { - // TODO LongHeader will also be used for 0-RTT packets - return QUICKeyPhase::CLEARTEXT; + switch (this->type()) { + case QUICPacketType::ZERO_RTT_PROTECTED: + return QUICKeyPhase::ZERORTT; + default: + return QUICKeyPhase::CLEARTEXT; + } } uint16_t diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 7b36b48ca44..7d145ab9014 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -216,6 +216,10 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) int QUICTLS::update_key_materials() { + if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT)) { + this->_generate_0rtt_key(); + } + // Switch key phase QUICKeyPhase next_key_phase; switch (this->_client_pp->key_phase()) { From 79a5e0708b3b326c5f1cf671b84eaf598c216a2f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 2 Jul 2018 13:44:48 +0900 Subject: [PATCH 0669/1313] Remove redundant(and wrong) CID output on connection migration --- iocore/net/QUICNetVConnection.cc | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e2049a792f0..60daf02315f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -992,13 +992,7 @@ QUICNetVConnection::_state_common_receive_packet() Connection con; con.setRemote(&p->from().sa); this->con.move(con); - 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); - p->destination_cid().hex(new_cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH); - QUICConDebug("Connection migrated from %s to %s", old_cid_str, new_cid_str); - } + QUICConDebug("Connection migrated"); this->_validate_new_path(); } else { QUICConDebug("Connection migration failed"); From 747c7419f1f5a8b704ef904297f5f1c7532bb18b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 12 Jul 2018 10:31:34 +0900 Subject: [PATCH 0670/1313] Check buffer length before reading packet length --- iocore/net/quic/QUICPacket.cc | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 5a18b33687c..6678eb78790 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -248,7 +248,10 @@ QUICPacketLongHeader::length(size_t &length, uint8_t *field_len, const uint8_t * QUICPacketLongHeader::scil(scil, packet, packet_len); size_t length_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; - length = QUICIntUtil::read_QUICVariableInt(packet + length_offset); + if (length_offset >= packet_len) { + return false; + } + length = QUICIntUtil::read_QUICVariableInt(packet + length_offset); if (field_len) { *field_len = QUICVariableInt::size(packet + length_offset); } @@ -846,14 +849,20 @@ QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, const QU phase = QUICKeyPhase::CLEARTEXT; break; } - QUICPacketLongHeader::packet_number_offset(pn_offset, packet, packet_len); + if (!QUICPacketLongHeader::packet_number_offset(pn_offset, packet, packet_len)) { + Debug("quic", "Failed to calculate packet number offset"); + return false; + } Debug("quic", "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), QUICDebugNames::key_phase(phase)); } else { QUICPacketShortHeader::key_phase(phase, packet, packet_len); - QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, QUICConfigParams::scid_len()); + if (!QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, QUICConfigParams::scid_len())) { + Debug("quic", "Failed to calculate packet number offset"); + return false; + } } sample_offset = std::min(pn_offset + 4, packet_len - aead_expansion); From 9e23ea5a69bd00ab136ac31a12667c5b219b9a61 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 13 Jul 2018 16:21:14 +0900 Subject: [PATCH 0671/1313] Fix build issues --- iocore/net/QUICNetVConnection.cc | 1 + iocore/net/quic/QUICConfig.cc | 6 ++++++ iocore/net/quic/QUICPacket.cc | 1 + iocore/net/quic/QUICTypes.h | 5 ----- src/traffic_quic/Makefile.inc | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 60daf02315f..f1cca34115d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -42,6 +42,7 @@ #define STATE_FROM_VIO(_x) ((NetState *)(((char *)(_x)) - STATE_VIO_OFFSET)) #define STATE_VIO_OFFSET ((uintptr_t) & ((NetState *)0)->vio) +using namespace std::literals; static constexpr std::string_view QUIC_DEBUG_TAG = "quic_net"sv; #define QUICConDebug(fmt, ...) Debug(QUIC_DEBUG_TAG.data(), "[%s] " fmt, this->cids().data(), ##__VA_ARGS__) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index b03d1bbc584..0e941c6c03d 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -33,6 +33,12 @@ #include "QUICTransportParameters.h" #include "QUICStatelessRetry.h" +// OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings) +// https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html +// Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? +using namespace std::literals; +static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-12"sv); + int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 6678eb78790..e1431810fa7 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -30,6 +30,7 @@ #include "QUICDebugNames.h" #include "QUICConfig.h" +using namespace std::literals; static constexpr std::string_view tag = "quic_packet"sv; static constexpr uint64_t aead_tag_len = 16; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index c7b3f42f112..bc88d1aedc0 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -53,11 +53,6 @@ constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; constexpr QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; -// OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings) -// https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html -// Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? -constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-12"sv); - enum class QUICHandshakeMsgType { NONE = 0, INITIAL, diff --git a/src/traffic_quic/Makefile.inc b/src/traffic_quic/Makefile.inc index be83416c9f0..8a6e9f6251b 100644 --- a/src/traffic_quic/Makefile.inc +++ b/src/traffic_quic/Makefile.inc @@ -52,5 +52,5 @@ traffic_quic_traffic_quic_LDADD = \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ @LIBTCL@ \ @HWLOC_LIBS@ \ - @LIB_YAMLCPP@ \ + @YAMLCPP_LIBS@ \ @OPENSSL_LIBS@ From 4503964ea557ffb9e9a9b7d24a070d1abcb76ff8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sun, 15 Jul 2018 11:12:25 +0900 Subject: [PATCH 0672/1313] Check the buffer size before reading a packet number --- iocore/net/quic/QUICPacket.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index e1431810fa7..fd9a1db40fc 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -873,6 +873,10 @@ QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, const QU return false; } unprotected_pn_len = QUICTypeUtil::read_QUICPacketNumberLen(unprotected_pn); + if (pn_offset + unprotected_pn_len > packet_len) { + Debug(tag.data(), "Malformed header: pn_offset=%zu, pn_len=%d", pn_offset, unprotected_pn_len); + return false; + } memcpy(packet + pn_offset, unprotected_pn, unprotected_pn_len); return true; } From 97737e6b183ad1f97abdb3e7adb2766c31dbad1d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sun, 15 Jul 2018 11:13:42 +0900 Subject: [PATCH 0673/1313] Add debug prints --- iocore/net/quic/QUICPacket.cc | 6 +++--- iocore/net/quic/QUICTLS_openssl.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index fd9a1db40fc..cffe2c92a9b 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -851,17 +851,17 @@ QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, const QU break; } if (!QUICPacketLongHeader::packet_number_offset(pn_offset, packet, packet_len)) { - Debug("quic", "Failed to calculate packet number offset"); + Debug(tag.data(), "Failed to calculate packet number offset"); return false; } - Debug("quic", "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), + Debug(tag.data(), "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), QUICDebugNames::key_phase(phase)); } else { QUICPacketShortHeader::key_phase(phase, packet, packet_len); if (!QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, QUICConfigParams::scid_len())) { - Debug("quic", "Failed to calculate packet number offset"); + Debug(tag.data(), "Failed to calculate packet number offset"); return false; } } diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index a1030b03956..f616a9f1e5c 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -216,7 +216,7 @@ QUICTLS::_decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const plain_len += len; return true; } else { - Debug(tag, "Failed to decrypt"); + 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; } } From 2e68c1b21d28e0608321ed8ba6bbfdd1f8f0c191 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 27 Jul 2018 12:00:17 +0900 Subject: [PATCH 0674/1313] fix unit tests --- iocore/net/quic/Mock.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index b2e26245e1d..964ee32f413 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -175,6 +175,7 @@ class MockQUICConnection : public QUICConnection std::string_view cids() const override { + using namespace std::literals; return std::string_view("00000000-00000000"sv); } @@ -316,6 +317,7 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider std::string_view cids() const override { + using namespace std::literals; return std::string_view("00000000-00000000"sv); } From 73c14aa10e29d6161de021c526d6dfd1ef76d00e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 27 Jul 2018 12:16:36 +0900 Subject: [PATCH 0675/1313] Use refernce instead of shared_ptr while passing around stream frames --- iocore/net/quic/QUICIncomingFrameBuffer.cc | 14 ++-- iocore/net/quic/QUICIncomingFrameBuffer.h | 2 +- iocore/net/quic/QUICStream.cc | 40 +++++------ iocore/net/quic/QUICStream.h | 12 ++-- iocore/net/quic/QUICStreamManager.cc | 8 +-- .../quic/test/test_QUICIncomingFrameBuffer.cc | 66 ++++++++--------- iocore/net/quic/test/test_QUICStream.cc | 72 +++++++++---------- 7 files changed, 106 insertions(+), 108 deletions(-) diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index b945ef84acc..964163a88b1 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -54,18 +54,18 @@ QUICIncomingFrameBuffer::pop() } QUICErrorUPtr -QUICIncomingFrameBuffer::insert(const std::shared_ptr frame) +QUICIncomingFrameBuffer::insert(const QUICStreamFrame &frame) { - QUICOffset offset = frame->offset(); - size_t len = frame->data_length(); + QUICOffset offset = frame.offset(); + size_t len = frame.data_length(); - QUICErrorUPtr err = this->_check_and_set_fin_flag(offset, len, frame->has_fin_flag()); + QUICErrorUPtr err = this->_check_and_set_fin_flag(offset, len, frame.has_fin_flag()); if (err->cls != QUICErrorClass::NONE) { return err; } // Ignore empty stream frame except pure fin stream frame - if (len == 0 && !frame->has_fin_flag()) { + if (len == 0 && !frame.has_fin_flag()) { return QUICErrorUPtr(new QUICNoError()); } @@ -74,10 +74,10 @@ QUICIncomingFrameBuffer::insert(const std::shared_ptr fra return QUICErrorUPtr(new QUICNoError()); } else if (this->_recv_offset == offset) { this->_recv_offset = offset + len; - std::shared_ptr cloned = frame->clone(); + std::shared_ptr cloned = frame.clone(); this->_recv_buffer.push(std::static_pointer_cast(cloned)); } else { - std::shared_ptr cloned = frame->clone(); + std::shared_ptr cloned = frame.clone(); this->_out_of_order_queue.insert(std::make_pair(offset, std::static_pointer_cast(cloned))); } diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index 66143017afb..d08a56f69bd 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -41,7 +41,7 @@ class QUICIncomingFrameBuffer : public QUICTransferProgressProvider /* * Becasue frames passed by FrameDispatcher is temporal, this clones a passed frame to ensure that we can use it later. */ - QUICErrorUPtr insert(const std::shared_ptr); + QUICErrorUPtr insert(const QUICStreamFrame &frame); void clear(); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index c7f6e13be16..3edd456b872 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -280,22 +280,16 @@ QUICStream::reenable(VIO *vio) } void -QUICStream::_write_to_read_vio(const std::shared_ptr &frame) +QUICStream::_write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin) { SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); - uint64_t bytes_added = this->_read_vio.buffer.writer()->write(frame->data(), frame->data_length()); + uint64_t bytes_added = this->_read_vio.buffer.writer()->write(data, data_length); // Until receive FIN flag, keep nbytes INT64_MAX - if (frame->has_fin_flag() && bytes_added == frame->data_length()) { - this->_read_vio.nbytes = frame->offset() + frame->data_length(); + if (fin && bytes_added == data_length) { + this->_read_vio.nbytes = offset + data_length; } - - this->_local_flow_controller.forward_limit(frame->offset() + frame->data_length() + this->_flow_control_buffer_size); - QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), - this->_local_flow_controller.current_limit()); - - this->_state.update_with_receiving_frame(*frame); } /** @@ -305,19 +299,19 @@ QUICStream::_write_to_read_vio(const std::shared_ptr &fra * which is called by application via do_io_read() or reenable(). */ QUICErrorUPtr -QUICStream::recv(const std::shared_ptr frame) +QUICStream::recv(const QUICStreamFrame &frame) { - ink_assert(_id == frame->stream_id()); + ink_assert(_id == frame.stream_id()); ink_assert(this->_read_vio.op == VIO::READ); // Check stream state - Do this first before accept the frame - if (!this->_state.is_allowed_to_receive(*frame)) { - QUICStreamDebug("Canceled receiving %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); + if (!this->_state.is_allowed_to_receive(frame)) { + QUICStreamDebug("Canceled receiving %s frame due to the stream state", QUICDebugNames::frame_type(frame.type())); return QUICErrorUPtr(new QUICStreamError(this, QUICTransErrorCode::STREAM_STATE_ERROR)); } // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit - int ret = this->_local_flow_controller.update(frame->offset() + frame->data_length()); + int ret = this->_local_flow_controller.update(frame.offset() + frame.data_length()); QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), this->_local_flow_controller.current_limit()); if (ret != 0) { @@ -332,7 +326,11 @@ QUICStream::recv(const std::shared_ptr frame) auto new_frame = this->_received_stream_frame_buffer.pop(); while (new_frame != nullptr) { - this->_write_to_read_vio(new_frame); + this->_write_to_read_vio(new_frame->offset(), new_frame->data(), new_frame->data_length(), new_frame->has_fin_flag()); + this->_local_flow_controller.forward_limit(new_frame->offset() + new_frame->data_length() + this->_flow_control_buffer_size); + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), + this->_local_flow_controller.current_limit()); + this->_state.update_with_receiving_frame(*new_frame); new_frame = this->_received_stream_frame_buffer.pop(); } @@ -342,9 +340,9 @@ QUICStream::recv(const std::shared_ptr frame) } QUICErrorUPtr -QUICStream::recv(const std::shared_ptr frame) +QUICStream::recv(const QUICMaxStreamDataFrame &frame) { - this->_remote_flow_controller.forward_limit(frame->maximum_stream_data()); + this->_remote_flow_controller.forward_limit(frame.maximum_stream_data()); QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), this->_remote_flow_controller.current_limit()); @@ -358,16 +356,16 @@ QUICStream::recv(const std::shared_ptr frame) } QUICErrorUPtr -QUICStream::recv(const std::shared_ptr frame) +QUICStream::recv(const QUICStreamBlockedFrame &frame) { // STREAM_BLOCKED frames are for debugging. Nothing to do here. return QUICErrorUPtr(new QUICNoError()); } QUICErrorUPtr -QUICStream::recv(const std::shared_ptr frame) +QUICStream::recv(const QUICStopSendingFrame &frame) { - this->_state.update_with_receiving_frame(*frame); + this->_state.update_with_receiving_frame(frame); this->_reset_reason = QUICStreamErrorUPtr(new QUICStreamError(this, QUIC_APP_ERROR_CODE_STOPPING)); // We received and processed STOP_SENDING frame, so return NO_ERROR here return QUICErrorUPtr(new QUICNoError()); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 1d880091881..9f217aad46b 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -78,10 +78,10 @@ class QUICStream : public VConnection, public QUICFrameGenerator void do_io_shutdown(ShutdownHowTo_t howto) override; void reenable(VIO *vio) override; - QUICErrorUPtr recv(const std::shared_ptr frame); - QUICErrorUPtr recv(const std::shared_ptr frame); - QUICErrorUPtr recv(const std::shared_ptr frame); - QUICErrorUPtr recv(const std::shared_ptr frame); + QUICErrorUPtr recv(const QUICStreamFrame &frame); + QUICErrorUPtr recv(const QUICMaxStreamDataFrame &frame); + QUICErrorUPtr recv(const QUICStreamBlockedFrame &frame); + QUICErrorUPtr recv(const QUICStopSendingFrame &frame); void reset(QUICStreamErrorUPtr error); @@ -94,14 +94,14 @@ class QUICStream : public VConnection, public QUICFrameGenerator QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) override; bool will_generate_frame() override; -private: +protected: virtual int64_t _process_read_vio(); virtual int64_t _process_write_vio(); void _signal_read_event(); void _signal_write_event(); Event *_send_tracked_event(Event *, int, VIO *); - void _write_to_read_vio(const std::shared_ptr &); + void _write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin); QUICStreamErrorUPtr _reset_reason = nullptr; QUICConnectionInfoProvider *_info = nullptr; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 24cd4923652..70914269793 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -180,7 +180,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr_find_or_create_stream(frame->stream_id()); if (stream) { - return stream->recv(frame); + return stream->recv(*frame); } else { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); } @@ -191,7 +191,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr_find_or_create_stream(frame->stream_id()); if (stream) { - return stream->recv(frame); + return stream->recv(*frame); } else { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); } @@ -210,7 +210,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr &f if (!application->is_stream_set(stream)) { application->set_stream(stream); } - QUICErrorUPtr error = stream->recv(frame); + QUICErrorUPtr error = stream->recv(*frame); return error; } @@ -232,7 +232,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr_find_or_create_stream(frame->stream_id()); if (stream) { - return stream->recv(frame); + return stream->recv(*frame); } else { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); } diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 24a069ad30d..34978ba82b1 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -39,7 +39,7 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") { std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0, true); - err = buffer.insert(stream1_frame_0_r); + err = buffer.insert(*stream1_frame_0_r); CHECK(err->trans_error_code != QUICTransErrorCode::FINAL_OFFSET_ERROR); } @@ -51,24 +51,24 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 3072, true); std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 4096); - buffer.insert(stream1_frame_0_r); - buffer.insert(stream1_frame_1_r); - buffer.insert(stream1_frame_2_r); - err = buffer.insert(stream1_frame_3_r); + buffer.insert(*stream1_frame_0_r); + buffer.insert(*stream1_frame_1_r); + buffer.insert(*stream1_frame_2_r); + err = buffer.insert(*stream1_frame_3_r); CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); QUICIncomingFrameBuffer buffer2(stream); - buffer2.insert(stream1_frame_3_r); - buffer2.insert(stream1_frame_0_r); - buffer2.insert(stream1_frame_1_r); - err = buffer2.insert(stream1_frame_2_r); + buffer2.insert(*stream1_frame_3_r); + buffer2.insert(*stream1_frame_0_r); + buffer2.insert(*stream1_frame_1_r); + err = buffer2.insert(*stream1_frame_2_r); CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); QUICIncomingFrameBuffer buffer3(stream); - buffer3.insert(stream1_frame_4_r); - err = buffer3.insert(stream1_frame_3_r); + buffer3.insert(*stream1_frame_4_r); + err = buffer3.insert(*stream1_frame_3_r); CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); } @@ -78,13 +78,13 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") std::shared_ptr stream1_frame_empty = QUICFrameFactory::create_stream_frame(data, 0, 1, 1024); std::shared_ptr stream1_frame_pure_fin = QUICFrameFactory::create_stream_frame(data, 0, 1, 1024, true); - err = buffer.insert(stream1_frame_0_r); + err = buffer.insert(*stream1_frame_0_r); CHECK(err->cls == QUICErrorClass::NONE); - err = buffer.insert(stream1_frame_empty); + err = buffer.insert(*stream1_frame_empty); CHECK(err->cls == QUICErrorClass::NONE); - err = buffer.insert(stream1_frame_pure_fin); + err = buffer.insert(*stream1_frame_pure_fin); CHECK(err->cls == QUICErrorClass::NONE); } @@ -106,12 +106,12 @@ TEST_CASE("QUICIncomingFrameBuffer_pop", "[quic]") std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 3072); std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 4096, true); - buffer.insert(stream1_frame_0_r); - buffer.insert(stream1_frame_1_r); - buffer.insert(stream1_frame_empty); - buffer.insert(stream1_frame_2_r); - buffer.insert(stream1_frame_3_r); - buffer.insert(stream1_frame_4_r); + buffer.insert(*stream1_frame_0_r); + buffer.insert(*stream1_frame_1_r); + buffer.insert(*stream1_frame_empty); + buffer.insert(*stream1_frame_2_r); + buffer.insert(*stream1_frame_3_r); + buffer.insert(*stream1_frame_4_r); CHECK(!buffer.empty()); auto frame = buffer.pop(); @@ -128,11 +128,11 @@ TEST_CASE("QUICIncomingFrameBuffer_pop", "[quic]") buffer.clear(); - buffer.insert(stream1_frame_4_r); - buffer.insert(stream1_frame_3_r); - buffer.insert(stream1_frame_2_r); - buffer.insert(stream1_frame_1_r); - buffer.insert(stream1_frame_0_r); + buffer.insert(*stream1_frame_4_r); + buffer.insert(*stream1_frame_3_r); + buffer.insert(*stream1_frame_2_r); + buffer.insert(*stream1_frame_1_r); + buffer.insert(*stream1_frame_0_r); CHECK(!buffer.empty()); frame = buffer.pop(); @@ -163,10 +163,10 @@ TEST_CASE("QUICIncomingFrameBuffer_dup_frame", "[quic]") std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); - buffer.insert(stream1_frame_0_r); - buffer.insert(stream1_frame_1_r); - buffer.insert(stream1_frame_2_r); - err = buffer.insert(stream1_frame_3_r); + buffer.insert(*stream1_frame_0_r); + buffer.insert(*stream1_frame_1_r); + buffer.insert(*stream1_frame_2_r); + err = buffer.insert(*stream1_frame_3_r); CHECK(err->cls == QUICErrorClass::NONE); auto frame = buffer.pop(); @@ -186,10 +186,10 @@ TEST_CASE("QUICIncomingFrameBuffer_dup_frame", "[quic]") std::shared_ptr stream2_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); std::shared_ptr stream2_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); - buffer.insert(stream2_frame_0_r); - buffer.insert(stream2_frame_1_r); - buffer.insert(stream2_frame_2_r); - err = buffer.insert(stream2_frame_3_r); + buffer.insert(*stream2_frame_0_r); + buffer.insert(*stream2_frame_1_r); + buffer.insert(*stream2_frame_2_r); + err = buffer.insert(*stream2_frame_3_r); CHECK(err->cls == QUICErrorClass::NONE); frame = buffer.pop(); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 28d61662e40..020e9f49924 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -73,14 +73,14 @@ TEST_CASE("QUICStream", "[quic]") new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, 1024, 1024)); stream->do_io_read(nullptr, 0, read_buffer); - stream->recv(frame_1); - stream->recv(frame_2); - stream->recv(frame_3); - stream->recv(frame_4); - stream->recv(frame_5); - stream->recv(frame_6); - stream->recv(frame_7); - stream->recv(frame_8); + stream->recv(*frame_1); + stream->recv(*frame_2); + stream->recv(*frame_3); + stream->recv(*frame_4); + stream->recv(*frame_5); + stream->recv(*frame_6); + stream->recv(*frame_7); + stream->recv(*frame_8); uint8_t buf[32]; int64_t len = reader->read_avail(); @@ -99,14 +99,14 @@ TEST_CASE("QUICStream", "[quic]") new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, 0, read_buffer); - stream->recv(frame_8); - stream->recv(frame_7); - stream->recv(frame_6); - stream->recv(frame_5); - stream->recv(frame_4); - stream->recv(frame_3); - stream->recv(frame_2); - stream->recv(frame_1); + stream->recv(*frame_8); + stream->recv(*frame_7); + stream->recv(*frame_6); + stream->recv(*frame_5); + stream->recv(*frame_4); + stream->recv(*frame_3); + stream->recv(*frame_2); + stream->recv(*frame_1); uint8_t buf[32]; int64_t len = reader->read_avail(); @@ -125,16 +125,16 @@ TEST_CASE("QUICStream", "[quic]") new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, 0, read_buffer); - stream->recv(frame_8); - stream->recv(frame_7); - stream->recv(frame_6); - stream->recv(frame_7); // duplicated frame - stream->recv(frame_5); - stream->recv(frame_3); - stream->recv(frame_1); - stream->recv(frame_2); - stream->recv(frame_4); - stream->recv(frame_5); // duplicated frame + stream->recv(*frame_8); + stream->recv(*frame_7); + stream->recv(*frame_6); + stream->recv(*frame_7); // duplicated frame + stream->recv(*frame_5); + stream->recv(*frame_3); + stream->recv(*frame_1); + stream->recv(*frame_2); + stream->recv(*frame_4); + stream->recv(*frame_5); // duplicated frame uint8_t buf[32]; int64_t len = reader->read_avail(); @@ -156,24 +156,24 @@ TEST_CASE("QUICStream", "[quic]") stream->do_io_read(nullptr, 0, read_buffer); // Start with 1024 but not 0 so received frames won't be processed - error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 1024)); + error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 1024)); CHECK(error->cls == QUICErrorClass::NONE); // duplicate - error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 1024)); + error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 1024)); CHECK(error->cls == QUICErrorClass::NONE); - error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 3072)); + error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 3072)); CHECK(error->cls == QUICErrorClass::NONE); // delay - error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 2048)); + error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 2048)); CHECK(error->cls == QUICErrorClass::NONE); // all frames should be processed - error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 0)); + error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 0)); CHECK(error->cls == QUICErrorClass::NONE); // start again without the first block - error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 5120)); + error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 5120)); CHECK(error->cls == QUICErrorClass::NONE); // this should exceed the limit - error = stream->recv(std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 8192)); + error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 8192)); CHECK(error->cls == QUICErrorClass::TRANSPORT); CHECK(error->trans_error_code == QUICTransErrorCode::FLOW_CONTROL_ERROR); } @@ -233,7 +233,7 @@ TEST_CASE("QUICStream", "[quic]") CHECK(stream->will_generate_frame() == true); // Update window - stream->recv(std::make_shared(stream_id, 5120)); + stream->recv(*std::make_shared(stream_id, 5120)); // This should send a frame stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); @@ -243,7 +243,7 @@ TEST_CASE("QUICStream", "[quic]") CHECK(stream->will_generate_frame() == false); // Update window - stream->recv(std::make_shared(stream_id, 5632)); + stream->recv(*std::make_shared(stream_id, 5632)); // This should send a frame write_buffer->write(data, 1024); @@ -259,7 +259,7 @@ TEST_CASE("QUICStream", "[quic]") CHECK(frame->type() == QUICFrameType::STREAM_BLOCKED); // Update window - stream->recv(std::make_shared(stream_id, 6144)); + stream->recv(*std::make_shared(stream_id, 6144)); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame() == true); From 45a351251275357365c67fc4bf6c3bf390e03738 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 27 Jul 2018 17:26:23 +0900 Subject: [PATCH 0676/1313] Add be32toh and htobe32 --- lib/ts/ink_endian.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/ts/ink_endian.h b/lib/ts/ink_endian.h index 30b3132598f..db8dad2bb3a 100644 --- a/lib/ts/ink_endian.h +++ b/lib/ts/ink_endian.h @@ -48,4 +48,14 @@ htobe64(uint64_t x) { return OSSwapHostToBigInt64(x); } +inline uint32_t +be32toh(uint32_t x) +{ + return OSSwapBigToHostInt32(x); +} +inline uint32_t +htobe32(uint32_t x) +{ + return OSSwapHostToBigInt32(x); +} #endif From 636548084557512da0a7bff9e0f59d85ece9a9a7 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 1 Aug 2018 09:51:57 +0900 Subject: [PATCH 0677/1313] Fix unit test of QUICPakcet --- iocore/net/quic/test/test_QUICPacket.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index e1be5de3b28..a8bcc4b2be5 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -187,7 +187,9 @@ TEST_CASE("Encoded Packet Number Length", "[quic]") { QUICPacketNumber base = 0x6afa2f; - CHECK(QUICPacket::calc_packet_number_len(0x6b4264, base) == 2); + // To be clarify: Is "As a result..." sentence missing "twice" ? + // + // CHECK(QUICPacket::calc_packet_number_len(0x6b2d79, base) == 2); CHECK(QUICPacket::calc_packet_number_len(0x6bc107, base) == 4); } @@ -203,12 +205,12 @@ TEST_CASE("Encoding Packet Number", "[quic]") TEST_CASE("Decoding Packet Number 1", "[quic]") { QUICPacketNumber dst = 0; - QUICPacketNumber src = 0x1f94; + QUICPacketNumber src = 0x9b3; size_t len = 2; QUICPacketNumber base = 0xaa82f30e; QUICPacket::decode_packet_number(dst, src, len, base); - CHECK(dst == 0xaa831f94); + CHECK(dst == 0xaa8309b3); } TEST_CASE("Decoding Packet Number 2", "[quic]") @@ -219,7 +221,7 @@ TEST_CASE("Decoding Packet Number 2", "[quic]") QUICPacketNumber base = 0x18bf54f0; QUICPacket::decode_packet_number(dst, src, len, base); - CHECK(dst == 0x18bf54f1); + CHECK(dst == 0x18bf5571); } TEST_CASE("Decoding Packet Number 3", "[quic]") @@ -228,6 +230,7 @@ TEST_CASE("Decoding Packet Number 3", "[quic]") QUICPacketNumber src = 0x5694; size_t len = 2; QUICPacketNumber base = 0x44D35695; + QUICPacket::decode_packet_number(dst, src, len, base); - CHECK(dst == 0x44D35694); + CHECK(dst == 0x44d39694); } From 50b85989c9c94cfc1292f86b00846af601f88884 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 3 Jul 2018 15:49:54 +0900 Subject: [PATCH 0678/1313] [draft-13] Add CRYPTO frame --- iocore/net/quic/QUICFrame.cc | 185 ++++++++++++++++++++++++- iocore/net/quic/QUICFrame.h | 60 +++++++- iocore/net/quic/QUICTypes.h | 5 +- iocore/net/quic/test/test_QUICFrame.cc | 66 ++++++++- 4 files changed, 309 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 45db0d5a5bf..053f5af21dc 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -27,6 +27,7 @@ #include "QUICDebugNames.h" ClassAllocator quicStreamFrameAllocator("quicStreamFrameAllocator"); +ClassAllocator quicCryptoFrameAllocator("quicCryptoFrameAllocator"); ClassAllocator quicAckFrameAllocator("quicAckFrameAllocator"); ClassAllocator quicPaddingFrameAllocator("quicPaddingFrameAllocator"); ClassAllocator quicRstStreamFrameAllocator("quicRstStreamFrameAllocator"); @@ -56,7 +57,7 @@ QUICFrame::type(const uint8_t *buf) { if (buf[0] >= static_cast(QUICFrameType::UNKNOWN)) { return QUICFrameType::UNKNOWN; - } else if (buf[0] >= static_cast(QUICFrameType::STREAM)) { + } else if (static_cast(QUICFrameType::STREAM) <= buf[0] && buf[0] < static_cast(QUICFrameType::CRYPTO)) { return QUICFrameType::STREAM; } else { return static_cast(buf[0]); @@ -383,6 +384,173 @@ QUICStreamFrame::_get_length_field_len() const } } +// +// CRYPTO frame +// + +QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffset offset, bool protection) : QUICFrame(protection) +{ + this->_data = std::move(data); + this->_data_len = data_len; + this->_offset = offset; +} + +QUICFrame * +QUICCryptoFrame::split(size_t size) +{ + if (size <= this->_get_data_field_offset()) { + return nullptr; + } + + ink_assert(size < this->size()); + + size_t data_len = size - this->_get_data_field_offset(); + size_t buf2_len = this->data_length() - data_len; + + ats_unique_buf buf = ats_unique_malloc(data_len); + ats_unique_buf buf2 = ats_unique_malloc(buf2_len); + memcpy(buf.get(), this->data(), data_len); + memcpy(buf2.get(), this->data() + data_len, buf2_len); + + this->_offset = this->offset(); + this->_data_len = data_len; + this->_data = std::move(buf); + + this->reset(nullptr, 0); + + QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); + new (frame) QUICCryptoFrame(std::move(buf2), buf2_len, this->offset() + this->data_length(), this->is_protected()); + return frame; +} + +QUICFrameUPtr +QUICCryptoFrame::clone() const +{ + return QUICFrameFactory::create_crypto_frame(this->data(), this->data_length(), this->offset(), this->is_protected()); +} + +QUICFrameType +QUICCryptoFrame::type() const +{ + return QUICFrameType::CRYPTO; +} + +size_t +QUICCryptoFrame::size() const +{ + return this->_get_data_field_offset() + this->data_length(); +} + +int +QUICCryptoFrame::debug_msg(char *msg, size_t msg_len) const +{ + return snprintf(msg, msg_len, "type=CRYPTO size=%zu offset=%" PRIu64 " data_len=%" PRIu64, this->size(), this->offset(), + this->data_length()); +} + +size_t +QUICCryptoFrame::store(uint8_t *buf, size_t *len, size_t limit) const +{ + if (limit < this->size()) { + return 0; + } + + // Frame Type + buf[0] = static_cast(QUICFrameType::CRYPTO); + *len = 1; + + size_t n; + + // Offset (i) + QUICTypeUtil::write_QUICOffset(this->offset(), buf + *len, &n); + *len += n; + + // Length (i) + QUICIntUtil::write_QUICVariableInt(this->data_length(), buf + *len, &n); + *len += n; + + // Crypto Data (*) + memcpy(buf + *len, this->data(), this->data_length()); + *len += this->data_length(); + + return *len; +} + +QUICOffset +QUICCryptoFrame::offset() const +{ + if (this->_buf) { + return QUICTypeUtil::read_QUICOffset(this->_buf + this->_get_offset_field_offset()); + } else { + return this->_offset; + } +} + +uint64_t +QUICCryptoFrame::data_length() const +{ + if (this->_buf) { + return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_length_field_offset()); + } else { + return this->_data_len; + } +} + +const uint8_t * +QUICCryptoFrame::data() const +{ + if (this->_buf) { + return this->_buf + this->_get_data_field_offset(); + } else { + return this->_data.get(); + } +} + +size_t +QUICCryptoFrame::_get_offset_field_offset() const +{ + return sizeof(QUICFrameType); +} + +size_t +QUICCryptoFrame::_get_length_field_offset() const +{ + size_t length_field_offset = this->_get_offset_field_offset(); + length_field_offset += this->_get_offset_field_len(); + + return length_field_offset; +} + +size_t +QUICCryptoFrame::_get_data_field_offset() const +{ + size_t data_field_offset = this->_get_offset_field_offset(); + data_field_offset += this->_get_offset_field_len(); + data_field_offset += this->_get_length_field_len(); + + return data_field_offset; +} + +size_t +QUICCryptoFrame::_get_offset_field_len() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_offset_field_offset()); + } else { + return QUICVariableInt::size(this->_offset); + } +} + +size_t +QUICCryptoFrame::_get_length_field_len() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + this->_get_length_field_offset()); + } else { + return QUICVariableInt::size(this->_data_len); + } +} + // // ACK frame // @@ -2125,6 +2293,10 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicStreamFrameAllocator.alloc(); new (frame) QUICStreamFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); + case QUICFrameType::CRYPTO: + frame = quicCryptoFrameAllocator.alloc(); + new (frame) QUICCryptoFrame(buf, len); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_crypto_frame); case QUICFrameType::ACK: frame = quicAckFrameAllocator.alloc(); new (frame) QUICAckFrame(buf, len); @@ -2229,6 +2401,17 @@ QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUIC return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); } +QUICCryptoFrameUPtr +QUICFrameFactory::create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, bool protection) +{ + ats_unique_buf buf = ats_unique_malloc(data_len); + memcpy(buf.get(), data, data_len); + + QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); + new (frame) QUICCryptoFrame(std::move(buf), data_len, offset, protection); + return QUICCryptoFrameUPtr(frame, &QUICFrameDeleter::delete_crypto_frame); +} + QUICFrameUPtr QUICFrameFactory::split_frame(QUICFrame *frame, size_t size) { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 1cb32af0a97..0ca5b1502f1 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -32,9 +32,13 @@ #include "QUICPacket.h" class QUICFrame; +class QUICStreamFrame; +class QUICCryptoFrame; using QUICFrameDeleterFunc = void (*)(QUICFrame *p); using QUICFrameUPtr = std::unique_ptr; +using QUICStreamFrameUPtr = std::unique_ptr; +using QUICCryptoFrameUPtr = std::unique_ptr; class QUICFrame { @@ -107,6 +111,43 @@ class QUICStreamFrame : public QUICFrame size_t _get_length_field_len() const; }; +// +// CRYPTO Frame +// + +class QUICCryptoFrame : public QUICFrame +{ +public: + QUICCryptoFrame() : QUICFrame() {} + QUICCryptoFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICCryptoFrame(ats_unique_buf buf, size_t len, QUICOffset offset, bool protection = true); + + QUICFrame *split(size_t size) override; + QUICFrameUPtr clone() const override; + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual int debug_msg(char *msg, size_t msg_len) const override; + + QUICOffset offset() const; + uint64_t data_length() const; + const uint8_t *data() const; + + LINK(QUICCryptoFrame, link); + +private: + QUICOffset _offset = 0; + uint64_t _data_len = 0; + ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; + + size_t _get_offset_field_offset() const; + size_t _get_length_field_offset() const; + size_t _get_data_field_offset() const; + + size_t _get_offset_field_len() const; + size_t _get_length_field_len() const; +}; + // // ACK Frame // @@ -602,8 +643,6 @@ class QUICPathResponseFrame : public QUICFrame ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; }; -using QUICStreamFrameUPtr = std::unique_ptr; - // // Retransmission Frame // @@ -628,6 +667,7 @@ class QUICRetransmissionFrame : public QUICFrame }; extern ClassAllocator quicStreamFrameAllocator; +extern ClassAllocator quicCryptoFrameAllocator; extern ClassAllocator quicAckFrameAllocator; extern ClassAllocator quicPaddingFrameAllocator; extern ClassAllocator quicRstStreamFrameAllocator; @@ -663,6 +703,13 @@ class QUICFrameDeleter quicStreamFrameAllocator.free(static_cast(frame)); } + static void + delete_crypto_frame(QUICFrame *frame) + { + frame->~QUICFrame(); + quicCryptoFrameAllocator.free(static_cast(frame)); + } + static void delete_ack_frame(QUICFrame *frame) { @@ -819,6 +866,13 @@ class QUICFrameFactory */ static QUICStreamFrameUPtr create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last = false, bool protection = true); + + /* + * Creates a CRYPTO frame. + * You have to make sure that the data size won't exceed the maximum size of QUIC packet. + */ + static QUICCryptoFrameUPtr create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, bool protection = true); + /* * Creates a ACK frame. * You shouldn't call this directly but through QUICAckFrameCreator because QUICAckFrameCreator manages packet numbers that we @@ -849,7 +903,7 @@ class QUICFrameFactory static std::unique_ptr create_max_data_frame(uint64_t maximum_data); /* - * Creates a MAX_STREAM_DATA frame. + / * Creates a MAX_STREAM_DATA frame. */ static std::unique_ptr create_max_stream_data_frame(QUICStreamId stream_id, uint64_t maximum_stream_data); diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index bc88d1aedc0..e071494eda7 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -90,8 +90,9 @@ enum class QUICFrameType : uint8_t { ACK, PATH_CHALLENGE, PATH_RESPONSE, - STREAM = 0x10, // 0x10 - 0x17 - UNKNOWN = 0x18, + STREAM = 0x10, // 0x10 - 0x17 + CRYPTO = 0x18, + UNKNOWN, }; enum class QUICVersionNegotiationStatus { diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index c455be45eb1..6a32a469849 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -48,8 +48,9 @@ TEST_CASE("QUICFrame Type", "[quic]") // Range of STREAM CHECK(QUICFrame::type(reinterpret_cast("\x10")) == QUICFrameType::STREAM); CHECK(QUICFrame::type(reinterpret_cast("\x17")) == QUICFrameType::STREAM); + CHECK(QUICFrame::type(reinterpret_cast("\x18")) == QUICFrameType::CRYPTO); // Undefined ragne - CHECK(QUICFrame::type(reinterpret_cast("\x18")) == QUICFrameType::UNKNOWN); + CHECK(QUICFrame::type(reinterpret_cast("\x21")) == QUICFrameType::UNKNOWN); CHECK(QUICFrame::type(reinterpret_cast("\xff")) == QUICFrameType::UNKNOWN); } @@ -353,6 +354,49 @@ TEST_CASE("Store STREAM Frame", "[quic]") } } +TEST_CASE("CRYPTO Frame", "[quic]") +{ + SECTION("Loading") + { + uint8_t buf[] = { + 0x18, // Type + 0x80, 0x01, 0x00, 0x00, // Offset + 0x05, // Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Crypto Data + }; + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::CRYPTO); + CHECK(frame->size() == sizeof(buf)); + + std::shared_ptr crypto_frame = std::dynamic_pointer_cast(frame); + CHECK(crypto_frame->offset() == 0x010000); + CHECK(crypto_frame->data_length() == 5); + CHECK(memcmp(crypto_frame->data(), "\x01\x02\x03\x04\x05", 5) == 0); + } + + SECTION("Storing") + { + uint8_t buf[32] = {0}; + size_t len; + uint8_t expected[] = { + 0x18, // Typr + 0x80, 0x01, 0x00, 0x00, // Offset + 0x05, // Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Crypto Data + }; + uint8_t raw_data[] = "\x01\x02\x03\x04\x05"; + ats_unique_buf payload = ats_unique_malloc(5); + memcpy(payload.get(), raw_data, 5); + + QUICCryptoFrame crypto_frame(std::move(payload), 5, 0x010000); + CHECK(crypto_frame.size() == sizeof(expected)); + + crypto_frame.store(buf, &len, 32); + CHECK(len == sizeof(expected)); + CHECK(memcmp(buf, expected, sizeof(expected)) == 0); + } +} + TEST_CASE("Load Ack Frame 1", "[quic]") { SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") @@ -1236,6 +1280,26 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") CHECK(memcmp(buf, frame_buf, len) == 0); } + SECTION("CRYPTO frame") + { + uint8_t frame_buf[] = { + 0x18, // Type + 0x01, // Offset + 0x05, // Length + 0x01, 0x02, 0x03, 0x04, 0x05, // Crypto Data + }; + + QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); + frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); + + uint8_t buf[32] = {0}; + size_t len; + frame->store(buf, &len, 32); + + CHECK(len == 8); + CHECK(memcmp(buf, frame_buf, len) == 0); + } + SECTION("RST_STREAM frame") { uint8_t frame_buf[] = { From 3c6e8bf67556d14bda7158686d7da7fca630be19 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Jul 2018 10:17:39 +0900 Subject: [PATCH 0679/1313] [draft-13] Handshake with raw TLS messages This requires quick hacked custom OpenSSL. When OpenSSL add new APIs to support QUIC (draft-13+), move it. --- iocore/net/quic/QUICHandshakeProtocol.h | 7 + iocore/net/quic/QUICTLS.h | 3 + iocore/net/quic/QUICTLS_openssl.cc | 102 ++ .../quic/test/test_QUICHandshakeProtocol.cc | 885 +++++++----------- 4 files changed, 439 insertions(+), 558 deletions(-) diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index aec814c4288..373b84d7ef8 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -60,6 +60,12 @@ class QUICPacketNumberProtector QUICHandshakeProtocol *_hs_protocol = nullptr; }; +struct QUICHandshakeMsgs { + uint8_t *buf = nullptr; //< pointer to the buffer + size_t max_buf_len = 0; //< size of buffer + size_t offsets[5] = {0}; //< offset to the each encryption level - {initial, zero_rtt, handshake, one_rtt, total length} +}; + class QUICHandshakeProtocol { public: @@ -67,6 +73,7 @@ class QUICHandshakeProtocol virtual ~QUICHandshakeProtocol(){}; virtual int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) = 0; + virtual int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) = 0; virtual bool is_handshake_finished() const = 0; virtual bool is_ready_to_derive() const = 0; virtual bool is_key_derived(QUICKeyPhase key_phase) const = 0; diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index ec2c9dffdb0..a9ae0b98b04 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -43,7 +43,10 @@ class QUICTLS : public QUICHandshakeProtocol QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless); ~QUICTLS(); + static QUICEncryptionLevel get_encryption_level(int msg_type); + int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override; + int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) override; bool is_handshake_finished() const override; bool is_ready_to_derive() const override; bool is_key_derived(QUICKeyPhase key_phase) const override; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index f616a9f1e5c..218a4975941 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -30,6 +30,108 @@ static constexpr char tag[] = "quic_tls"; +static void +msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg) +{ + if (!write_p || !arg || version != TLS1_3_VERSION || (content_type != SSL3_RT_HANDSHAKE && content_type != SSL3_RT_ALERT)) { + return; + } + + const uint8_t *tmp = reinterpret_cast(buf); + int msg_type = tmp[0]; + QUICEncryptionLevel level = QUICTLS::get_encryption_level(msg_type); + int index = static_cast(level); + int next_index = index + 1; + + QUICHandshakeMsgs *msg = reinterpret_cast(arg); + if (msg == nullptr) { + return; + } + + size_t offset = msg->offsets[next_index]; + size_t next_level_offset = offset + len; + + memcpy(msg->buf + offset, buf, len); + + for (int i = next_index; i < 5; ++i) { + msg->offsets[i] = next_level_offset; + } + + return; +} + +QUICEncryptionLevel +QUICTLS::get_encryption_level(int msg_type) +{ + switch (msg_type) { + case SSL3_MT_CLIENT_HELLO: + case SSL3_MT_SERVER_HELLO: + return QUICEncryptionLevel::INITIAL; + case SSL3_MT_END_OF_EARLY_DATA: + return QUICEncryptionLevel::ZERO_RTT; + case SSL3_MT_ENCRYPTED_EXTENSIONS: + case SSL3_MT_CERTIFICATE_REQUEST: + case SSL3_MT_CERTIFICATE: + case SSL3_MT_CERTIFICATE_VERIFY: + case SSL3_MT_FINISHED: + return QUICEncryptionLevel::HANDSHAKE; + case SSL3_MT_KEY_UPDATE: + case SSL3_MT_NEWSESSION_TICKET: + return QUICEncryptionLevel::ONE_RTT; + default: + return QUICEncryptionLevel::NONE; + } +} + +int +QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) +{ + ink_assert(this->_ssl != nullptr); + if (SSL_is_init_finished(this->_ssl)) { + return 0; + } + + int err = SSL_ERROR_NONE; + ERR_clear_error(); + int ret = 0; + + SSL_set_msg_callback(this->_ssl, msg_cb); + SSL_set_msg_callback_arg(this->_ssl, out); + + // TODO: set BIO_METHOD which read from QUICHandshakeMsgs directly + BIO *rbio = BIO_new(BIO_s_mem()); + // TODO: set dummy BIO_METHOD which do nothing + BIO *wbio = BIO_new(BIO_s_mem()); + if (in != nullptr && in->offsets[4] != 0) { + BIO_write(rbio, in->buf, in->offsets[4]); + } + SSL_set_bio(this->_ssl, rbio, wbio); + + if (this->_netvc_context == NET_VCONNECTION_IN) { + // TODO: early data + ret = SSL_accept(this->_ssl); + } else { + 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; + } + } + + return 1; +} + const EVP_CIPHER * QUICTLS::_get_evp_aead(QUICKeyPhase phase) const { diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 1e5e2273103..9066f47cac0 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -33,10 +33,11 @@ #include -#include "Mock.h" +// #include "Mock.h" #include "QUICTLS.h" -static constexpr uint32_t MAX_HANDSHAKE_MSG_LEN = 2048; +// depends on size of cert +static constexpr uint32_t MAX_HANDSHAKE_MSG_LEN = 8192; #include "./server_cert.h" @@ -65,44 +66,95 @@ static const uint8_t original[] = { static const uint64_t pkt_num = 0x123456789; static const uint8_t ad[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; -/* Fixed value used in the ServerHello random field to identify an HRR */ -const unsigned char hrr_random[] = { - 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91, - 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c, -}; - -static const bool -is_hrr(uint8_t *msg, size_t msg_len) -{ - return memmem(msg, msg_len, hrr_random, sizeof(hrr_random)) != nullptr; -} - -// dummy token to simplify test -static uint8_t token[] = {0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, - 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, - 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, - 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef}; - -static int -generate_cookie_callback(SSL * /* ssl */, unsigned char *cookie, size_t *cookie_len) -{ - memcpy(cookie, token, sizeof(token)); - *cookie_len = sizeof(token); - - return 1; -} - -static int -verify_cookie_callback(SSL *ssl, const unsigned char *cookie, size_t cookie_len) -{ - if (memcmp(token, cookie, sizeof(token)) == 0) { - return 1; - } else { - return 0; - } -} - -TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]") +// /* Fixed value used in the ServerHello random field to identify an HRR */ +// const unsigned char hrr_random[] = { +// 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91, +// 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c, +// }; + +// static const bool +// is_hrr(uint8_t *msg, size_t msg_len) +// { +// return memmem(msg, msg_len, hrr_random, sizeof(hrr_random)) != nullptr; +// } + +// // dummy token to simplify test +// static uint8_t token[] = {0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, +// 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, +// 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, +// 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef}; + +// static int +// generate_cookie_callback(SSL * /* ssl */, unsigned char *cookie, size_t *cookie_len) +// { +// memcpy(cookie, token, sizeof(token)); +// *cookie_len = sizeof(token); + +// return 1; +// } + +// static int +// verify_cookie_callback(SSL *ssl, const unsigned char *cookie, size_t cookie_len) +// { +// if (memcmp(token, cookie, sizeof(token)) == 0) { +// return 1; +// } else { +// return 0; +// } +// } + +// TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]") +// { +// // Client +// SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); +// SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); +// SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); +// SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +// QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + +// // Server +// SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); +// SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); +// SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); +// SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +// BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); +// SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); +// BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); +// SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); +// QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + +// CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); +// CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + +// // encrypt - decrypt +// // client (encrypt) - server (decrypt) +// std::cout << "### Original Text" << std::endl; +// print_hex(original, sizeof(original)); + +// uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead +// size_t cipher_len = 0; +// CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), +// QUICKeyPhase::CLEARTEXT)); + +// std::cout << "### Encrypted Text" << std::endl; +// print_hex(cipher, cipher_len); + +// uint8_t plain[128] = {0}; +// size_t plain_len = 0; +// CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::CLEARTEXT)); + +// std::cout << "### Decrypted Text" << std::endl; +// print_hex(plain, plain_len); + +// CHECK(sizeof(original) == (plain_len)); +// CHECK(memcmp(original, plain, plain_len) == 0); + +// // Teardown +// delete client; +// delete server; +// } + +TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") { // Client SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); @@ -125,447 +177,47 @@ TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]") CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - // encrypt - decrypt - // client (encrypt) - server (decrypt) - std::cout << "### Original Text" << std::endl; - print_hex(original, sizeof(original)); - - uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead - size_t cipher_len = 0; - CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), - QUICKeyPhase::CLEARTEXT)); - - std::cout << "### Encrypted Text" << std::endl; - print_hex(cipher, cipher_len); - - uint8_t plain[128] = {0}; - size_t plain_len = 0; - CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::CLEARTEXT)); - - std::cout << "### Decrypted Text" << std::endl; - print_hex(plain, plain_len); - - CHECK(sizeof(original) == (plain_len)); - CHECK(memcmp(original, plain, plain_len) == 0); - - // Teardown - delete client; - delete server; -} - -TEST_CASE("QUICHandshakeProtocol 1-RTT", "[quic]") -{ - // Client - SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); - - // Server - SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); - SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); - BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); - SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); - - CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - - // Client Hello - uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t client_hello_len = 0; - CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); - std::cout << "### Client Hello" << std::endl; - print_hex(client_hello, client_hello_len); - - // Server Hello - uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t server_hello_len = 0; - CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == - SSL_ERROR_WANT_READ); - std::cout << "### Server Hello" << std::endl; - print_hex(server_hello, server_hello_len); - - // Client Fnished - uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t client_finished_len = 0; - CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == - SSL_ERROR_NONE); - std::cout << "### Client Finished" << std::endl; - print_hex(client_finished, client_finished_len); - - CHECK(client->update_key_materials()); - - // Post Handshake Msg - uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t post_handshake_msg_len = 0; - CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, - client_finished_len) == SSL_ERROR_NONE); - std::cout << "### Post Handshake Message" << std::endl; - print_hex(post_handshake_msg, post_handshake_msg_len); - - CHECK(server->update_key_materials()); - - // encrypt - decrypt - // client (encrypt) - server (decrypt) - std::cout << "### Original Text" << std::endl; - print_hex(original, sizeof(original)); - - uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead - size_t cipher_len = 0; - CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), - QUICKeyPhase::PHASE_0)); - - std::cout << "### Encrypted Text" << std::endl; - print_hex(cipher, cipher_len); - - uint8_t plain[128] = {0}; - size_t plain_len = 0; - CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); - - std::cout << "### Decrypted Text" << std::endl; - print_hex(plain, plain_len); - - CHECK(sizeof(original) == (plain_len)); - CHECK(memcmp(original, plain, plain_len) == 0); - - // Teardown - delete client; - delete server; -} - -// HRR - Incorrect DHE Share -// NOTE: This is *NOT* client address validation. -// https://tools.ietf.org/html/draft-ietf-tls-tls13-26 - 2.1. Incorrect DHE Share -TEST_CASE("QUICHandshakeProtocol 1-RTT HRR key_share mismatch", "[quic]") -{ - // Client - SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - - QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); - - // Server - SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); - SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); - BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); - SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - - // client key_share will be X25519 (default of OpenSSL) - if (SSL_CTX_set1_groups_list(server_ssl_ctx, "P-521:P-384:P-256") != 1) { - REQUIRE(false); - } - - QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); - - CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - - // Client Hello - uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t client_hello_len = 0; - REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); - REQUIRE(client_hello_len > 0); - std::cout << "### Client Hello" << std::endl; - print_hex(client_hello, client_hello_len); - - // Hello Retry Request w/o cookie - uint8_t retry[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t retry_len = 0; - REQUIRE(server->handshake(retry, retry_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == SSL_ERROR_WANT_READ); - REQUIRE(retry_len > 0); - REQUIRE(is_hrr(retry, retry_len)); - std::cout << "### HRR" << std::endl; - print_hex(retry, retry_len); - - // Client Hello w/ cookie - memset(client_hello, 0, MAX_HANDSHAKE_MSG_LEN); - client_hello_len = 0; - REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, retry, retry_len) == SSL_ERROR_WANT_READ); - REQUIRE(client_hello_len > 0); - std::cout << "### Client Hello" << std::endl; - print_hex(client_hello, client_hello_len); - - // Server Hello - uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t server_hello_len = 0; - REQUIRE(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == - SSL_ERROR_WANT_READ); - REQUIRE(server_hello_len > 0); - std::cout << "### Server Hello" << std::endl; - print_hex(server_hello, server_hello_len); - - // Client Fnished - uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t client_finished_len = 0; - REQUIRE(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == - SSL_ERROR_NONE); - REQUIRE(client_finished_len > 0); - std::cout << "### Client Finished" << std::endl; - print_hex(client_finished, client_finished_len); - - CHECK(client->update_key_materials()); - - // Post Handshake Msg - uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t post_handshake_msg_len = 0; - REQUIRE(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, - client_finished_len) == SSL_ERROR_NONE); - std::cout << "### Post Handshake Message" << std::endl; - print_hex(post_handshake_msg, post_handshake_msg_len); - - CHECK(server->update_key_materials()); - - // encrypt - decrypt - // client (encrypt) - server (decrypt) - std::cout << "### Original Text" << std::endl; - print_hex(original, sizeof(original)); - - uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead - size_t cipher_len = 0; - CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), - QUICKeyPhase::PHASE_0)); + // CH + QUICHandshakeMsgs msg1; + uint8_t msg1_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg1.buf = msg1_buf; + msg1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - std::cout << "### Encrypted Text" << std::endl; - print_hex(cipher, cipher_len); + CHECK(client->handshake(&msg1, nullptr) == 1); + std::cout << "### Messages from client" << std::endl; + print_hex(msg1.buf, msg1.offsets[4]); - uint8_t plain[128] = {0}; - size_t plain_len = 0; - CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); + // SH, EE, CERT, CV, FIN + QUICHandshakeMsgs msg2; + uint8_t msg2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2.buf = msg2_buf; + msg2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - std::cout << "### Decrypted Text" << std::endl; - print_hex(plain, plain_len); - - CHECK(sizeof(original) == (plain_len)); - CHECK(memcmp(original, plain, plain_len) == 0); - - // Teardown - delete client; - delete server; -} + CHECK(server->handshake(&msg2, &msg1) == 1); + std::cout << "### Messages from server" << std::endl; + print_hex(msg2.buf, msg2.offsets[4]); -// HRR for client address varidation -TEST_CASE("QUICHandshakeProtocol 1-RTT HRR statless", "[quic]") -{ - // Client - SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + // FIN + QUICHandshakeMsgs msg3; + uint8_t msg3_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg3.buf = msg3_buf; + msg3.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); - - // Server - SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); - SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); - BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); - SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - - // callbacks for cookie ext - // Requires OpenSSL-1.1.1-rc3+ : https://github.com/openssl/openssl/pull/5463 - SSL_CTX_set_stateless_cookie_generate_cb(server_ssl_ctx, generate_cookie_callback); - SSL_CTX_set_stateless_cookie_verify_cb(server_ssl_ctx, verify_cookie_callback); - - bool stateless = true; - QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN, stateless); - - CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - - // Client Hello - uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t client_hello_len = 0; - REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); - REQUIRE(client_hello_len > 0); - std::cout << "### Client Hello" << std::endl; - print_hex(client_hello, client_hello_len); - - // Hello Retry Request - uint8_t retry[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t retry_len = 0; - CHECK(server->handshake(retry, retry_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == SSL_ERROR_NONE); - REQUIRE(retry_len > 0); - CHECK(is_hrr(retry, retry_len)); - std::cout << "### HRR" << std::endl; - print_hex(retry, retry_len); - - // Make sure "stateless" - delete server; - server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN, stateless); - - // Client Hello w/ cookie - memset(client_hello, 0, MAX_HANDSHAKE_MSG_LEN); - client_hello_len = 0; - CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, retry, retry_len) == SSL_ERROR_WANT_READ); - REQUIRE(client_hello_len > 0); - std::cout << "### Client Hello" << std::endl; - print_hex(client_hello, client_hello_len); - - // Server Hello - uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t server_hello_len = 0; - REQUIRE(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == - SSL_ERROR_NONE); - REQUIRE(server_hello_len > 0); - std::cout << "### Server Hello" << std::endl; - print_hex(server_hello, server_hello_len); - - // Client Fnished - uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t client_finished_len = 0; - REQUIRE(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == - SSL_ERROR_NONE); - REQUIRE(client_finished_len > 0); - std::cout << "### Client Finished" << std::endl; - print_hex(client_finished, client_finished_len); + CHECK(client->handshake(&msg3, &msg2) == 1); + std::cout << "### Messages from client" << std::endl; + print_hex(msg3.buf, msg3.offsets[4]); CHECK(client->update_key_materials()); - // Post Handshake Msg - uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t post_handshake_msg_len = 0; - REQUIRE(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, - client_finished_len) == SSL_ERROR_NONE); - std::cout << "### Post Handshake Message" << std::endl; - print_hex(post_handshake_msg, post_handshake_msg_len); + // NS + QUICHandshakeMsgs msg4; + uint8_t msg4_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg4.buf = msg4_buf; + msg4.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - CHECK(server->update_key_materials()); - - // encrypt - decrypt - // client (encrypt) - server (decrypt) - std::cout << "### Original Text" << std::endl; - print_hex(original, sizeof(original)); - - uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead - size_t cipher_len = 0; - CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), - QUICKeyPhase::PHASE_0)); - - std::cout << "### Encrypted Text" << std::endl; - print_hex(cipher, cipher_len); - - uint8_t plain[128] = {0}; - size_t plain_len = 0; - CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); - - std::cout << "### Decrypted Text" << std::endl; - print_hex(plain, plain_len); - - CHECK(sizeof(original) == (plain_len)); - CHECK(memcmp(original, plain, plain_len) == 0); - - // Teardown - delete client; - delete server; -} - -// HRR for client address varidation & Incorrect DHE Share -TEST_CASE("QUICHandshakeProtocol 1-RTT HRR statless & key_share mismatch", "[quic]") -{ - // Client - SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - - QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); - - // Server - SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); - SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); - BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); - SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - - // client key_share will be X25519 (default of OpenSSL) - if (SSL_CTX_set1_groups_list(server_ssl_ctx, "P-521:P-384:P-256") != 1) { - REQUIRE(false); - } - - // callbacks for cookie ext - SSL_CTX_set_stateless_cookie_generate_cb(server_ssl_ctx, generate_cookie_callback); - SSL_CTX_set_stateless_cookie_verify_cb(server_ssl_ctx, verify_cookie_callback); - - bool stateless = true; - QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN, stateless); - - CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - - // Client Hello - uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t client_hello_len = 0; - REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); - REQUIRE(client_hello_len > 0); - std::cout << "### Client Hello" << std::endl; - print_hex(client_hello, client_hello_len); - - // Hello Retry Request - uint8_t retry[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t retry_len = 0; - CHECK(server->handshake(retry, retry_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == SSL_ERROR_NONE); - REQUIRE(retry_len > 0); - REQUIRE(is_hrr(retry, retry_len)); - std::cout << "### HRR" << std::endl; - print_hex(retry, retry_len); - - // Make sure "stateless" - delete server; - server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN, stateless); - - // Client Hello w/ cookie - memset(client_hello, 0, MAX_HANDSHAKE_MSG_LEN); - client_hello_len = 0; - REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, retry, retry_len) == SSL_ERROR_WANT_READ); - REQUIRE(client_hello_len > 0); - std::cout << "### Client Hello" << std::endl; - print_hex(client_hello, client_hello_len); - - // Server Hello - uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t server_hello_len = 0; - REQUIRE(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == - SSL_ERROR_NONE); - REQUIRE(server_hello_len > 0); - std::cout << "### Server Hello" << std::endl; - print_hex(server_hello, server_hello_len); - - // Client Fnished - uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t client_finished_len = 0; - CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == - SSL_ERROR_NONE); - REQUIRE(client_finished_len > 0); - std::cout << "### Client Finished" << std::endl; - print_hex(client_finished, client_finished_len); - - CHECK(client->update_key_materials()); - - // Post Handshake Msg - uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t post_handshake_msg_len = 0; - REQUIRE(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, - client_finished_len) == SSL_ERROR_NONE); - std::cout << "### Post Handshake Message" << std::endl; - print_hex(post_handshake_msg, post_handshake_msg_len); + CHECK(server->handshake(&msg4, &msg3) == 1); + std::cout << "### Messages from server" << std::endl; + print_hex(msg4.buf, msg4.offsets[4]); CHECK(server->update_key_materials()); @@ -597,89 +249,206 @@ TEST_CASE("QUICHandshakeProtocol 1-RTT HRR statless & key_share mismatch", "[qui delete server; } -TEST_CASE("QUICHandshakeProtocol PNE", "[quic]") -{ - // Client - SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); - - // Server - SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); - SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); - BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); - SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); - - uint8_t expected[] = {0x01, 0x02, 0x03, 0x04, 0x05}; - uint8_t sample[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; - uint8_t protected_pn[18], unprotected_pn[18]; - uint8_t protected_pn_len = 0, unprotected_pn_len = 0; - - // # Before handshake - CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - - // ## Client -> Server - client->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::CLEARTEXT); - server->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::CLEARTEXT); - CHECK(unprotected_pn_len == sizeof(expected)); - CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); - // ## Server -> Client - server->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::CLEARTEXT); - client->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::CLEARTEXT); - CHECK(unprotected_pn_len == sizeof(expected)); - CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); - - // # After handshake - uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t client_hello_len = 0; - CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); - std::cout << "### Client Hello" << std::endl; - print_hex(client_hello, client_hello_len); - - // Server Hello - uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t server_hello_len = 0; - CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == - SSL_ERROR_WANT_READ); - std::cout << "### Server Hello" << std::endl; - print_hex(server_hello, server_hello_len); - - // Client Fnished - uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t client_finished_len = 0; - CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == - SSL_ERROR_NONE); - std::cout << "### Client Finished" << std::endl; - print_hex(client_finished, client_finished_len); - - CHECK(client->update_key_materials()); - - // Post Handshake Msg - uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; - size_t post_handshake_msg_len = 0; - CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, - client_finished_len) == SSL_ERROR_NONE); - std::cout << "### Post Handshake Message" << std::endl; - print_hex(post_handshake_msg, post_handshake_msg_len); - - CHECK(server->update_key_materials()); - - // ## Client -> Server - client->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); - server->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); - CHECK(unprotected_pn_len == sizeof(expected)); - CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); - // ## Server -> Client - server->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); - client->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); - CHECK(unprotected_pn_len == sizeof(expected)); - CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); -} +// // HRR - Incorrect DHE Share +// // NOTE: This is *NOT* client address validation. +// // https://tools.ietf.org/html/draft-ietf-tls-tls13-26 - 2.1. Incorrect DHE Share +// TEST_CASE("QUICHandshakeProtocol 1-RTT HRR key_share mismatch", "[quic]") +// { +// // Client +// SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); +// SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); +// SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); +// SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +// +// QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); +// +// // Server +// SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); +// SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); +// SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); +// SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +// BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); +// SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); +// BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); +// SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); +// +// // client key_share will be X25519 (default of OpenSSL) +// if (SSL_CTX_set1_groups_list(server_ssl_ctx, "P-521:P-384:P-256") != 1) { +// REQUIRE(false); +// } +// +// QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); +// +// CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); +// CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); +// +// // Client Hello +// uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; +// size_t client_hello_len = 0; +// REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); +// REQUIRE(client_hello_len > 0); +// std::cout << "### Client Hello" << std::endl; +// print_hex(client_hello, client_hello_len); +// +// // Hello Retry Request w/o cookie +// uint8_t retry[MAX_HANDSHAKE_MSG_LEN] = {0}; +// size_t retry_len = 0; +// REQUIRE(server->handshake(retry, retry_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == SSL_ERROR_WANT_READ); +// REQUIRE(retry_len > 0); +// REQUIRE(is_hrr(retry, retry_len)); +// std::cout << "### HRR" << std::endl; +// print_hex(retry, retry_len); +// +// // Client Hello w/ cookie +// memset(client_hello, 0, MAX_HANDSHAKE_MSG_LEN); +// client_hello_len = 0; +// REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, retry, retry_len) == SSL_ERROR_WANT_READ); +// REQUIRE(client_hello_len > 0); +// std::cout << "### Client Hello" << std::endl; +// print_hex(client_hello, client_hello_len); +// +// // Server Hello +// uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; +// size_t server_hello_len = 0; +// REQUIRE(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == +// SSL_ERROR_WANT_READ); +// REQUIRE(server_hello_len > 0); +// std::cout << "### Server Hello" << std::endl; +// print_hex(server_hello, server_hello_len); +// +// // Client Fnished +// uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; +// size_t client_finished_len = 0; +// REQUIRE(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == +// SSL_ERROR_NONE); +// REQUIRE(client_finished_len > 0); +// std::cout << "### Client Finished" << std::endl; +// print_hex(client_finished, client_finished_len); +// +// CHECK(client->update_key_materials()); +// +// // Post Handshake Msg +// uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; +// size_t post_handshake_msg_len = 0; +// REQUIRE(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, +// client_finished_len) == SSL_ERROR_NONE); +// std::cout << "### Post Handshake Message" << std::endl; +// print_hex(post_handshake_msg, post_handshake_msg_len); +// +// CHECK(server->update_key_materials()); +// +// // encrypt - decrypt +// // client (encrypt) - server (decrypt) +// std::cout << "### Original Text" << std::endl; +// print_hex(original, sizeof(original)); +// +// uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead +// size_t cipher_len = 0; +// CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), +// QUICKeyPhase::PHASE_0)); +// +// std::cout << "### Encrypted Text" << std::endl; +// print_hex(cipher, cipher_len); +// +// uint8_t plain[128] = {0}; +// size_t plain_len = 0; +// CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); +// +// std::cout << "### Decrypted Text" << std::endl; +// print_hex(plain, plain_len); +// +// CHECK(sizeof(original) == (plain_len)); +// CHECK(memcmp(original, plain, plain_len) == 0); +// +// // Teardown +// delete client; +// delete server; +// } +// +// +// TEST_CASE("QUICHandshakeProtocol PNE", "[quic]") +// { +// // Client +// SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); +// SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); +// SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); +// SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +// QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); +// +// // Server +// SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); +// SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); +// SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); +// SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +// BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); +// SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); +// BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); +// SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); +// QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); +// +// uint8_t expected[] = {0x01, 0x02, 0x03, 0x04, 0x05}; +// uint8_t sample[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; +// uint8_t protected_pn[18], unprotected_pn[18]; +// uint8_t protected_pn_len = 0, unprotected_pn_len = 0; +// +// // # Before handshake +// CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); +// CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); +// +// // ## Client -> Server +// client->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::CLEARTEXT); +// server->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::CLEARTEXT); +// CHECK(unprotected_pn_len == sizeof(expected)); +// CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); +// // ## Server -> Client +// server->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::CLEARTEXT); +// client->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::CLEARTEXT); +// CHECK(unprotected_pn_len == sizeof(expected)); +// CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); +// +// // # After handshake +// uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; +// size_t client_hello_len = 0; +// CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); +// std::cout << "### Client Hello" << std::endl; +// print_hex(client_hello, client_hello_len); +// +// // Server Hello +// uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; +// size_t server_hello_len = 0; +// CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == +// SSL_ERROR_WANT_READ); +// std::cout << "### Server Hello" << std::endl; +// print_hex(server_hello, server_hello_len); +// +// // Client Fnished +// uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; +// size_t client_finished_len = 0; +// CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == +// SSL_ERROR_NONE); +// std::cout << "### Client Finished" << std::endl; +// print_hex(client_finished, client_finished_len); +// +// CHECK(client->update_key_materials()); +// +// // Post Handshake Msg +// uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; +// size_t post_handshake_msg_len = 0; +// CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, +// client_finished_len) == SSL_ERROR_NONE); +// std::cout << "### Post Handshake Message" << std::endl; +// print_hex(post_handshake_msg, post_handshake_msg_len); +// +// CHECK(server->update_key_materials()); +// +// // ## Client -> Server +// client->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); +// server->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); +// CHECK(unprotected_pn_len == sizeof(expected)); +// CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); +// // ## Server -> Client +// server->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); +// client->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); +// CHECK(unprotected_pn_len == sizeof(expected)); +// CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); +// } From 6710bec5e67459e17f8f3b97aa3b3662a6bf0eb1 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Jul 2018 10:25:20 +0900 Subject: [PATCH 0680/1313] [draft-13] Add QUICEncryptionLevel --- iocore/net/quic/QUICDebugNames.cc | 17 +++++++++++++++ iocore/net/quic/QUICDebugNames.h | 1 + iocore/net/quic/QUICTypes.cc | 36 +++++++++++++++++++++++++++++++ iocore/net/quic/QUICTypes.h | 22 ++++++++++++++++++- 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 2eeb2943b2b..9c0a76d2fa6 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -253,3 +253,20 @@ QUICDebugNames::key_phase(QUICKeyPhase phase) return "UNKNOWN"; } } + +const char * +QUICDebugNames::encryption_level(QUICEncryptionLevel level) +{ + switch (level) { + case QUICEncryptionLevel::INITIAL: + return "INITIAL"; + case QUICEncryptionLevel::ZERO_RTT: + return "ZERO_RTT"; + case QUICEncryptionLevel::HANDSHAKE: + return "HANDSHAKE"; + case QUICEncryptionLevel::ONE_RTT: + return "ONE_RTT"; + default: + return "UNKNOWN"; + } +} diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index 7e813b64e05..a01cf521adf 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -39,4 +39,5 @@ class QUICDebugNames static const char *stream_state(const QUICStreamState &state); static const char *quic_event(int event); static const char *key_phase(QUICKeyPhase phase); + static const char *encryption_level(QUICEncryptionLevel level); }; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 812220243b2..33a159fed0f 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -68,6 +68,42 @@ QUICTypeUtil::detect_stream_type(QUICStreamId id) } } +QUICEncryptionLevel +QUICTypeUtil::encryption_level(QUICPacketType type) +{ + switch (type) { + case QUICPacketType::INITIAL: + return QUICEncryptionLevel::INITIAL; + case QUICPacketType::ZERO_RTT_PROTECTED: + return QUICEncryptionLevel::ZERO_RTT; + case QUICPacketType::HANDSHAKE: + return QUICEncryptionLevel::HANDSHAKE; + case QUICPacketType::PROTECTED: + return QUICEncryptionLevel::ONE_RTT; + default: + ink_assert(false); + return QUICEncryptionLevel::NONE; + } +} + +QUICPacketType +QUICTypeUtil::packet_type(QUICEncryptionLevel level) +{ + switch (level) { + case QUICEncryptionLevel::INITIAL: + return QUICPacketType::INITIAL; + case QUICEncryptionLevel::ZERO_RTT: + return QUICPacketType::ZERO_RTT_PROTECTED; + case QUICEncryptionLevel::HANDSHAKE: + return QUICPacketType::HANDSHAKE; + case QUICEncryptionLevel::ONE_RTT: + return QUICPacketType::PROTECTED; + default: + ink_assert(false); + return QUICPacketType::UNINITIALIZED; + } +} + QUICConnectionId QUICTypeUtil::read_QUICConnectionId(const uint8_t *buf, uint8_t len) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index e071494eda7..33a3874dafe 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -53,6 +53,7 @@ constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; constexpr QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; +// [[deprecated]] enum class QUICHandshakeMsgType { NONE = 0, INITIAL, @@ -60,6 +61,23 @@ enum class QUICHandshakeMsgType { HANDSHAKE, }; +enum class QUICEncryptionLevel { + NONE = -1, + INITIAL = 0, + ZERO_RTT = 1, + HANDSHAKE = 2, + ONE_RTT = 3, +}; + +// For range-based for loop. This starts from INITIAL to ONE_RTT. It doesn't include NONE nor ZERO_RTT. +// Defining begin, end, operator*, operator++ doen't work for duplicate symbol issue with libmgmt_p.a :( +// TODO: support ZERO_RTT +constexpr QUICEncryptionLevel QUIC_ENCRYPTION_LEVELS[] = { + QUICEncryptionLevel::INITIAL, + QUICEncryptionLevel::HANDSHAKE, + QUICEncryptionLevel::ONE_RTT, +}; + // Devide to QUICPacketType and QUICPacketLongHeaderType ? enum class QUICPacketType : uint8_t { VERSION_NEGOTIATION = 0, @@ -313,7 +331,9 @@ class QUICTypeUtil { public: static bool is_supported_version(QUICVersion version); - static QUICStreamType detect_stream_type(QUICStreamId id); + [[deprecated]] static QUICStreamType detect_stream_type(QUICStreamId id); + static QUICEncryptionLevel encryption_level(QUICPacketType type); + static QUICPacketType packet_type(QUICEncryptionLevel level); static QUICConnectionId read_QUICConnectionId(const uint8_t *buf, uint8_t n); static int read_QUICPacketNumberLen(const uint8_t *buf); From c9d2f5936b0f3df129257152953fff9fe391e4fd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Jul 2018 11:34:35 +0900 Subject: [PATCH 0681/1313] [draft-13] Add QUICIncomingStreamFrameBuffer and QUICIncomingCryptoFrameBuffer QUICIncomingFrameBuffer is parent class of QUICIncomingStreamFrameBuffer and QUICIncomingCryptoFrameBuffer now. --- iocore/net/quic/QUICFrame.h | 4 + iocore/net/quic/QUICIncomingFrameBuffer.cc | 154 +++++++++++++----- iocore/net/quic/QUICIncomingFrameBuffer.h | 54 ++++-- iocore/net/quic/QUICStream.cc | 9 +- iocore/net/quic/QUICStream.h | 2 +- .../quic/test/test_QUICIncomingFrameBuffer.cc | 52 +++--- 6 files changed, 188 insertions(+), 87 deletions(-) diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 0ca5b1502f1..05f65cb911c 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -40,6 +40,10 @@ using QUICFrameUPtr = std::unique_ptr; using QUICStreamFrameUPtr = std::unique_ptr; using QUICCryptoFrameUPtr = std::unique_ptr; +using QUICFrameSPtr = std::shared_ptr; +using QUICStreamFrameSPtr = std::shared_ptr; +using QUICCryptoFrameSPtr = std::shared_ptr; + class QUICFrame { public: diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index 964163a88b1..afb735bbad3 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -23,25 +23,47 @@ #include "QUICIncomingFrameBuffer.h" -QUICIncomingFrameBuffer::~QUICIncomingFrameBuffer() +// +// QUICIncomingFrameBuffer +// +void +QUICIncomingFrameBuffer::clear() { this->_out_of_order_queue.clear(); while (!this->_recv_buffer.empty()) { this->_recv_buffer.pop(); } + + this->_recv_offset = 0; +} + +bool +QUICIncomingFrameBuffer::empty() +{ + return this->_out_of_order_queue.empty() && this->_recv_buffer.empty(); +} + +// +// QUICIncomingStreamFrameBuffer +// +QUICIncomingStreamFrameBuffer::~QUICIncomingStreamFrameBuffer() +{ + this->clear(); } -std::shared_ptr -QUICIncomingFrameBuffer::pop() +QUICFrameSPtr +QUICIncomingStreamFrameBuffer::pop() { if (this->_recv_buffer.empty()) { - auto frame = this->_out_of_order_queue.find(this->_recv_offset); - while (frame != this->_out_of_order_queue.end()) { - this->_recv_buffer.push(frame->second); - this->_recv_offset += frame->second->data_length(); - this->_out_of_order_queue.erase(frame); - frame = this->_out_of_order_queue.find(this->_recv_offset); + auto elem = this->_out_of_order_queue.find(this->_recv_offset); + while (elem != this->_out_of_order_queue.end()) { + QUICStreamFrameSPtr frame = std::static_pointer_cast(elem->second); + + this->_recv_buffer.push(frame); + this->_recv_offset += frame->data_length(); + this->_out_of_order_queue.erase(elem); + elem = this->_out_of_order_queue.find(this->_recv_offset); } } @@ -54,18 +76,20 @@ QUICIncomingFrameBuffer::pop() } QUICErrorUPtr -QUICIncomingFrameBuffer::insert(const QUICStreamFrame &frame) +QUICIncomingStreamFrameBuffer::insert(const QUICFrame &frame) { - QUICOffset offset = frame.offset(); - size_t len = frame.data_length(); + const QUICStreamFrame *stream_frame = static_cast(&frame); + + QUICOffset offset = stream_frame->offset(); + size_t len = stream_frame->data_length(); - QUICErrorUPtr err = this->_check_and_set_fin_flag(offset, len, frame.has_fin_flag()); + QUICErrorUPtr err = this->_check_and_set_fin_flag(offset, len, stream_frame->has_fin_flag()); if (err->cls != QUICErrorClass::NONE) { return err; } // Ignore empty stream frame except pure fin stream frame - if (len == 0 && !frame.has_fin_flag()) { + if (len == 0 && !stream_frame->has_fin_flag()) { return QUICErrorUPtr(new QUICNoError()); } @@ -73,39 +97,28 @@ QUICIncomingFrameBuffer::insert(const QUICStreamFrame &frame) // dup frame; return QUICErrorUPtr(new QUICNoError()); } else if (this->_recv_offset == offset) { - this->_recv_offset = offset + len; - std::shared_ptr cloned = frame.clone(); - this->_recv_buffer.push(std::static_pointer_cast(cloned)); + this->_recv_offset = offset + len; + QUICFrameSPtr cloned = frame.clone(); + this->_recv_buffer.push(cloned); } else { - std::shared_ptr cloned = frame.clone(); - this->_out_of_order_queue.insert(std::make_pair(offset, std::static_pointer_cast(cloned))); + QUICFrameSPtr cloned = frame.clone(); + this->_out_of_order_queue.insert(std::make_pair(offset, cloned)); } return QUICErrorUPtr(new QUICNoError()); } void -QUICIncomingFrameBuffer::clear() +QUICIncomingStreamFrameBuffer::clear() { - this->_out_of_order_queue.clear(); + this->_fin_offset = UINT64_MAX; + this->_max_offset = 0; - while (!this->_recv_buffer.empty()) { - this->_recv_buffer.pop(); - } - - this->_fin_offset = UINT64_MAX; - this->_max_offset = 0; - this->_recv_offset = 0; -} - -bool -QUICIncomingFrameBuffer::empty() -{ - return this->_out_of_order_queue.empty() && this->_recv_buffer.empty(); + super::clear(); } QUICErrorUPtr -QUICIncomingFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, bool fin_flag) +QUICIncomingStreamFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, bool fin_flag) { // stream with fin flag {11.3. Stream Final Offset} // Once a final offset for a stream is known, it cannot change. @@ -140,29 +153,86 @@ QUICIncomingFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, return QUICErrorUPtr(new QUICNoError()); } -/* - *QUICTransferProgressProvider - */ bool -QUICIncomingFrameBuffer::is_transfer_goal_set() const +QUICIncomingStreamFrameBuffer::is_transfer_goal_set() const { return this->_fin_offset != UINT64_MAX; } bool -QUICIncomingFrameBuffer::is_transfer_complete() const +QUICIncomingStreamFrameBuffer::is_transfer_complete() const { return this->is_transfer_goal_set() && this->transfer_progress() == this->transfer_goal(); } uint64_t -QUICIncomingFrameBuffer::transfer_progress() const +QUICIncomingStreamFrameBuffer::transfer_progress() const { return this->_max_offset; } uint64_t -QUICIncomingFrameBuffer::transfer_goal() const +QUICIncomingStreamFrameBuffer::transfer_goal() const { return this->_fin_offset; } + +// +// QUICIncomingCryptoFrameBuffer +// +QUICIncomingCryptoFrameBuffer::~QUICIncomingCryptoFrameBuffer() +{ + super::clear(); +} + +QUICFrameSPtr +QUICIncomingCryptoFrameBuffer::pop() +{ + if (this->_recv_buffer.empty()) { + auto elem = this->_out_of_order_queue.find(this->_recv_offset); + while (elem != this->_out_of_order_queue.end()) { + QUICCryptoFrameSPtr frame = std::static_pointer_cast(elem->second); + + this->_recv_buffer.push(frame); + this->_recv_offset += frame->data_length(); + this->_out_of_order_queue.erase(elem); + elem = this->_out_of_order_queue.find(this->_recv_offset); + } + } + + if (!this->_recv_buffer.empty()) { + auto frame = this->_recv_buffer.front(); + this->_recv_buffer.pop(); + return frame; + } + + return nullptr; +} + +QUICErrorUPtr +QUICIncomingCryptoFrameBuffer::insert(const QUICFrame &frame) +{ + const QUICCryptoFrame *crypto_frame = static_cast(&frame); + + QUICOffset offset = crypto_frame->offset(); + size_t len = crypto_frame->data_length(); + + // Ignore empty stream frame + if (len == 0) { + return QUICErrorUPtr(new QUICNoError()); + } + + if (this->_recv_offset > offset) { + // dup frame; + return QUICErrorUPtr(new QUICNoError()); + } else if (this->_recv_offset == offset) { + this->_recv_offset = offset + len; + QUICFrameSPtr cloned = frame.clone(); + this->_recv_buffer.push(cloned); + } else { + QUICFrameSPtr cloned = frame.clone(); + this->_out_of_order_queue.insert(std::make_pair(offset, cloned)); + } + + return QUICErrorUPtr(new QUICNoError()); +} diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index d08a56f69bd..904b0bce3c4 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -30,22 +30,35 @@ #include "QUICFrame.h" #include "QUICTransferProgressProvider.h" -class QUICIncomingFrameBuffer : public QUICTransferProgressProvider +class QUICIncomingFrameBuffer { public: - QUICIncomingFrameBuffer(const QUICStream *stream) : _stream(stream) {} - ~QUICIncomingFrameBuffer(); - - std::shared_ptr pop(); - + virtual QUICFrameSPtr pop() = 0; /* * Becasue frames passed by FrameDispatcher is temporal, this clones a passed frame to ensure that we can use it later. */ - QUICErrorUPtr insert(const QUICStreamFrame &frame); + virtual QUICErrorUPtr insert(const QUICFrame &frame) = 0; + virtual void clear(); + virtual bool empty(); + +protected: + QUICOffset _recv_offset = 0; + + std::queue _recv_buffer; + std::map _out_of_order_queue; +}; - void clear(); +class QUICIncomingStreamFrameBuffer : public QUICIncomingFrameBuffer, public QUICTransferProgressProvider +{ +public: + using super = QUICIncomingFrameBuffer; ///< Parent type. - bool empty(); + QUICIncomingStreamFrameBuffer(const QUICStream *stream) : _stream(stream) {} + ~QUICIncomingStreamFrameBuffer(); + + QUICFrameSPtr pop() override; + QUICErrorUPtr insert(const QUICFrame &frame) override; + void clear() override; // QUICTransferProgressProvider bool is_transfer_goal_set() const override; @@ -54,14 +67,23 @@ class QUICIncomingFrameBuffer : public QUICTransferProgressProvider uint64_t transfer_goal() const override; private: - QUICOffset _recv_offset = 0; - QUICOffset _max_offset = 0; - QUICOffset _fin_offset = UINT64_MAX; - QUICErrorUPtr _check_and_set_fin_flag(QUICOffset offset, size_t len = 0, bool fin_flag = false); - std::queue> _recv_buffer; - std::map> _out_of_order_queue; - const QUICStream *_stream = nullptr; + QUICOffset _max_offset = 0; + QUICOffset _fin_offset = UINT64_MAX; +}; + +class QUICIncomingCryptoFrameBuffer : public QUICIncomingFrameBuffer +{ +public: + using super = QUICIncomingFrameBuffer; ///< Parent type. + + QUICIncomingCryptoFrameBuffer() {} + ~QUICIncomingCryptoFrameBuffer(); + + QUICFrameSPtr pop() override; + QUICErrorUPtr insert(const QUICFrame &frame) override; + +private: }; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 3edd456b872..7079df9a004 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -326,11 +326,16 @@ QUICStream::recv(const QUICStreamFrame &frame) auto new_frame = this->_received_stream_frame_buffer.pop(); while (new_frame != nullptr) { - this->_write_to_read_vio(new_frame->offset(), new_frame->data(), new_frame->data_length(), new_frame->has_fin_flag()); - this->_local_flow_controller.forward_limit(new_frame->offset() + new_frame->data_length() + this->_flow_control_buffer_size); + QUICStreamFrameSPtr stream_frame = std::static_pointer_cast(new_frame); + + this->_write_to_read_vio(stream_frame->offset(), stream_frame->data(), stream_frame->data_length(), + stream_frame->has_fin_flag()); + this->_local_flow_controller.forward_limit(stream_frame->offset() + stream_frame->data_length() + + this->_flow_control_buffer_size); QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), this->_local_flow_controller.current_limit()); this->_state.update_with_receiving_frame(*new_frame); + new_frame = this->_received_stream_frame_buffer.pop(); } diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 9f217aad46b..99d152ba88f 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -120,7 +120,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator // Fragments of received STREAM frame (offset is unmatched) // TODO: Consider to replace with ts/RbTree.h or other data structure - QUICIncomingFrameBuffer _received_stream_frame_buffer; + QUICIncomingStreamFrameBuffer _received_stream_frame_buffer; // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState QUICBidirectionalStreamState _state; diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 34978ba82b1..e8c104938fd 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -27,10 +27,10 @@ #include "quic/QUICStream.h" #include -TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") +TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") { QUICStream *stream = new QUICStream(); - QUICIncomingFrameBuffer buffer(stream); + QUICIncomingStreamFrameBuffer buffer(stream); QUICErrorUPtr err = nullptr; uint8_t data[1024] = {0}; @@ -57,7 +57,7 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") err = buffer.insert(*stream1_frame_3_r); CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); - QUICIncomingFrameBuffer buffer2(stream); + QUICIncomingStreamFrameBuffer buffer2(stream); buffer2.insert(*stream1_frame_3_r); buffer2.insert(*stream1_frame_0_r); @@ -65,7 +65,7 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") err = buffer2.insert(*stream1_frame_2_r); CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); - QUICIncomingFrameBuffer buffer3(stream); + QUICIncomingStreamFrameBuffer buffer3(stream); buffer3.insert(*stream1_frame_4_r); err = buffer3.insert(*stream1_frame_3_r); @@ -91,10 +91,10 @@ TEST_CASE("QUICIncomingFrameBuffer_fin_offset", "[quic]") delete stream; } -TEST_CASE("QUICIncomingFrameBuffer_pop", "[quic]") +TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") { QUICStream *stream = new QUICStream(); - QUICIncomingFrameBuffer buffer(stream); + QUICIncomingStreamFrameBuffer buffer(stream); QUICErrorUPtr err = nullptr; uint8_t data[1024] = {0}; @@ -114,15 +114,15 @@ TEST_CASE("QUICIncomingFrameBuffer_pop", "[quic]") buffer.insert(*stream1_frame_4_r); CHECK(!buffer.empty()); - auto frame = buffer.pop(); + auto frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 0); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 1024); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 2048); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 3072); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 4096); CHECK(buffer.empty()); @@ -135,25 +135,25 @@ TEST_CASE("QUICIncomingFrameBuffer_pop", "[quic]") buffer.insert(*stream1_frame_0_r); CHECK(!buffer.empty()); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 0); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 1024); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 2048); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 3072); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 4096); CHECK(buffer.empty()); delete stream; } -TEST_CASE("QUICIncomingFrameBuffer_dup_frame", "[quic]") +TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") { QUICStream *stream = new QUICStream(); - QUICIncomingFrameBuffer buffer(stream); + QUICIncomingStreamFrameBuffer buffer(stream); QUICErrorUPtr err = nullptr; uint8_t data[1024] = {0}; @@ -169,13 +169,13 @@ TEST_CASE("QUICIncomingFrameBuffer_dup_frame", "[quic]") err = buffer.insert(*stream1_frame_3_r); CHECK(err->cls == QUICErrorClass::NONE); - auto frame = buffer.pop(); + auto frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 0); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 1024); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 2048); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame == nullptr); CHECK(buffer.empty()); @@ -192,13 +192,13 @@ TEST_CASE("QUICIncomingFrameBuffer_dup_frame", "[quic]") err = buffer.insert(*stream2_frame_3_r); CHECK(err->cls == QUICErrorClass::NONE); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 0); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 1024); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 2048); - frame = buffer.pop(); + frame = std::static_pointer_cast(buffer.pop()); CHECK(frame == nullptr); CHECK(buffer.empty()); From 0712fe5f5b2e845aea7baad8e4a25b2573028374 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Jul 2018 12:26:58 +0900 Subject: [PATCH 0682/1313] [draft-13] Add encryption level to QUICFrameDispatcher/Generator/Handler interfaces --- iocore/net/quic/QUICAltConnectionManager.cc | 14 ++++++++++--- iocore/net/quic/QUICAltConnectionManager.h | 4 ++-- iocore/net/quic/QUICFrameDispatcher.cc | 4 ++-- iocore/net/quic/QUICFrameDispatcher.h | 2 +- iocore/net/quic/QUICFrameGenerator.h | 23 +++++++++++++++++++-- iocore/net/quic/QUICFrameHandler.h | 4 ++-- iocore/net/quic/QUICLossDetector.cc | 2 +- iocore/net/quic/QUICLossDetector.h | 2 +- iocore/net/quic/QUICPacketRetransmitter.cc | 4 ++-- iocore/net/quic/QUICPacketRetransmitter.h | 4 ++-- iocore/net/quic/QUICPathValidator.cc | 14 ++++++++++--- iocore/net/quic/QUICPathValidator.h | 6 +++--- iocore/net/quic/QUICStream.cc | 4 ++-- iocore/net/quic/QUICStream.h | 4 ++-- iocore/net/quic/QUICStreamManager.cc | 20 ++++++++++++------ iocore/net/quic/QUICStreamManager.h | 14 ++++++++++--- 16 files changed, 88 insertions(+), 37 deletions(-) diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index b24e6a04c15..4ad73f737f7 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -96,16 +96,24 @@ QUICAltConnectionManager::invalidate_alt_connections() } bool -QUICAltConnectionManager::will_generate_frame() +QUICAltConnectionManager::will_generate_frame(QUICEncryptionLevel level) { + if (!this->_is_level_matched(level)) { + return false; + } + return this->_need_advertise; } QUICFrameUPtr -QUICAltConnectionManager::generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) +QUICAltConnectionManager::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - int count = this->_nids; + if (!this->_is_level_matched(level)) { + return frame; + } + + int count = this->_nids; for (int i = 0; i < count; ++i) { if (!this->_alt_quic_connection_ids[i].advertised) { this->_alt_quic_connection_ids[i].advertised = true; diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index 79f27efd69a..1727a322db7 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -39,8 +39,8 @@ class QUICAltConnectionManager : public QUICFrameGenerator void invalidate_alt_connections(); // QUICFrameGenerator - bool will_generate_frame(); - QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size); + bool will_generate_frame(QUICEncryptionLevel level); + QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size); private: class AltConnectionInfo diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 2419526c3f5..afb90dd2743 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -42,7 +42,7 @@ QUICFrameDispatcher::add_handler(QUICFrameHandler *handler) } QUICErrorUPtr -QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size, bool &should_send_ack) +QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, bool &should_send_ack) { std::shared_ptr frame(nullptr); uint16_t cursor = 0; @@ -69,7 +69,7 @@ QUICFrameDispatcher::receive_frames(const uint8_t *payload, uint16_t size, bool std::vector handlers = this->_handlers[static_cast(type)]; for (auto h : handlers) { - error = h->handle_frame(frame); + error = h->handle_frame(level, frame); // TODO: is there any case to continue this loop even if error? if (error->cls != QUICErrorClass::NONE) { return error; diff --git a/iocore/net/quic/QUICFrameDispatcher.h b/iocore/net/quic/QUICFrameDispatcher.h index e9e3a0149ad..6db357d5785 100644 --- a/iocore/net/quic/QUICFrameDispatcher.h +++ b/iocore/net/quic/QUICFrameDispatcher.h @@ -37,7 +37,7 @@ class QUICFrameDispatcher /* * Returns true if ACK frame should be sent */ - QUICErrorUPtr receive_frames(const uint8_t *payload, uint16_t size, bool &should_send_ack); + QUICErrorUPtr receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, bool &should_send_ack); void add_handler(QUICFrameHandler *handler); diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index 0e4d2655b32..218b1572b38 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -29,6 +29,25 @@ class QUICFrameGenerator { public: virtual ~QUICFrameGenerator(){}; - virtual bool will_generate_frame() = 0; - virtual QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) = 0; + virtual bool will_generate_frame(QUICEncryptionLevel level) = 0; + virtual QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) = 0; + +protected: + virtual std::vector + _encryption_level_filter() + { + return {QUICEncryptionLevel::ONE_RTT}; + } + + virtual bool + _is_level_matched(QUICEncryptionLevel level) + { + for (auto l : this->_encryption_level_filter()) { + if (l == level) { + return true; + } + } + + return false; + } }; diff --git a/iocore/net/quic/QUICFrameHandler.h b/iocore/net/quic/QUICFrameHandler.h index e857513e435..2384d609312 100644 --- a/iocore/net/quic/QUICFrameHandler.h +++ b/iocore/net/quic/QUICFrameHandler.h @@ -30,6 +30,6 @@ class QUICFrameHandler { public: virtual ~QUICFrameHandler(){}; - virtual std::vector interests() = 0; - virtual QUICErrorUPtr handle_frame(std::shared_ptr frame) = 0; + virtual std::vector interests() = 0; + virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) = 0; }; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 42269aa4578..124156d66b4 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -100,7 +100,7 @@ QUICLossDetector::interests() } QUICErrorUPtr -QUICLossDetector::handle_frame(std::shared_ptr frame) +QUICLossDetector::handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 2f2e3c889b5..b84883d3c50 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -102,7 +102,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU int event_handler(int event, Event *edata); std::vector interests() override; - virtual QUICErrorUPtr handle_frame(std::shared_ptr) override; + virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, std::shared_ptr) override; void on_packet_sent(QUICPacketUPtr packet); QUICPacketNumber largest_acked_packet_number(); void reset(); diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 2186540a27f..57e2be03f50 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -62,13 +62,13 @@ QUICPacketRetransmitter::reset() } bool -QUICPacketRetransmitter::will_generate_frame() +QUICPacketRetransmitter::will_generate_frame(QUICEncryptionLevel level) { return !this->_retransmission_frames.empty(); } QUICFrameUPtr -QUICPacketRetransmitter::generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) +QUICPacketRetransmitter::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); if (!this->_retransmission_frames.empty()) { diff --git a/iocore/net/quic/QUICPacketRetransmitter.h b/iocore/net/quic/QUICPacketRetransmitter.h index c468b850400..d488fa2f6f0 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.h +++ b/iocore/net/quic/QUICPacketRetransmitter.h @@ -35,8 +35,8 @@ class QUICPacketRetransmitter : public QUICFrameGenerator void reset(); // QUICFrameGenerator - bool will_generate_frame() override; - QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) override; + bool will_generate_frame(QUICEncryptionLevel level) override; + QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; private: std::queue _retransmission_frames; diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index a210be2a102..53db58d599d 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -85,7 +85,7 @@ QUICPathValidator::interests() } QUICErrorUPtr -QUICPathValidator::handle_frame(std::shared_ptr frame) +QUICPathValidator::handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); @@ -107,16 +107,24 @@ QUICPathValidator::handle_frame(std::shared_ptr frame) // QUICFrameGenerator // bool -QUICPathValidator::will_generate_frame() +QUICPathValidator::will_generate_frame(QUICEncryptionLevel level) { + if (!this->_is_level_matched(level)) { + return false; + } + return (this->_has_outgoing_challenge || this->_has_outgoing_response); } QUICFrameUPtr -QUICPathValidator::generate_frame(uint64_t connection_credit, uint16_t maximum_quic_packet_size) +QUICPathValidator::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_quic_packet_size) { QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + if (!this->_is_level_matched(level)) { + return frame; + } + if (this->_has_outgoing_response) { frame = QUICFrameFactory::create_path_response_frame(this->_incoming_challenge); this->_has_outgoing_response = false; diff --git a/iocore/net/quic/QUICPathValidator.h b/iocore/net/quic/QUICPathValidator.h index 93343dec380..30d10fb587c 100644 --- a/iocore/net/quic/QUICPathValidator.h +++ b/iocore/net/quic/QUICPathValidator.h @@ -37,11 +37,11 @@ class QUICPathValidator : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameHandler std::vector interests() override; - QUICErrorUPtr handle_frame(std::shared_ptr frame) override; + QUICErrorUPtr handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) override; // QUICFrameGeneratro - bool will_generate_frame() override; - QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) override; + bool will_generate_frame(QUICEncryptionLevel level) override; + QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; private: enum class ValidationState : int { diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 7079df9a004..bd25c5db570 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -377,13 +377,13 @@ QUICStream::recv(const QUICStopSendingFrame &frame) } bool -QUICStream::will_generate_frame() +QUICStream::will_generate_frame(QUICEncryptionLevel level) { return this->_write_vio.get_reader()->read_avail() > 0; } QUICFrameUPtr -QUICStream::generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) +QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 99d152ba88f..747165e9f47 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -91,8 +91,8 @@ class QUICStream : public VConnection, public QUICFrameGenerator LINK(QUICStream, link); // QUICFrameGenerator - QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) override; - bool will_generate_frame() override; + bool will_generate_frame(QUICEncryptionLevel level) override; + QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; protected: virtual int64_t _process_read_vio(); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 70914269793..08333167adb 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -142,7 +142,7 @@ QUICStreamManager::reset_stream(QUICStreamId stream_id, QUICStreamErrorUPtr erro } QUICErrorUPtr -QUICStreamManager::handle_frame(std::shared_ptr frame) +QUICStreamManager::handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); @@ -364,10 +364,14 @@ QUICStreamManager::reset_recv_offset() } bool -QUICStreamManager::will_generate_frame() +QUICStreamManager::will_generate_frame(QUICEncryptionLevel level) { + if (!this->_is_level_matched(level)) { + return false; + } + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { - if (s->will_generate_frame()) { + if (s->will_generate_frame(level)) { return true; } } @@ -376,15 +380,19 @@ QUICStreamManager::will_generate_frame() } QUICFrameUPtr -QUICStreamManager::generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) +QUICStreamManager::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { // FIXME We should pick a stream based on priority QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + if (!this->_is_level_matched(level)) { + return frame; + } + // Stream 0 must be prioritized over other streams QUICStream *stream = this->_find_stream(STREAM_ID_FOR_HANDSHAKE); if (stream) { - frame = stream->generate_frame(connection_credit, maximum_frame_size); + frame = stream->generate_frame(level, connection_credit, maximum_frame_size); } if (frame == nullptr) { @@ -392,7 +400,7 @@ QUICStreamManager::generate_frame(uint64_t connection_credit, uint16_t maximum_f if (s->id() == STREAM_ID_FOR_HANDSHAKE) { continue; } - frame = s->generate_frame(connection_credit, maximum_frame_size); + frame = s->generate_frame(level, connection_credit, maximum_frame_size); if (frame) { break; } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 51d38dc4622..ad63209d913 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -61,11 +61,11 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameHandler virtual std::vector interests() override; - virtual QUICErrorUPtr handle_frame(std::shared_ptr) override; + virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, std::shared_ptr) override; // QUICFrameGenerator - bool will_generate_frame() override; - QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) override; + bool will_generate_frame(QUICEncryptionLevel level) override; + QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; private: QUICStream *_find_stream(QUICStreamId id); @@ -76,6 +76,14 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICErrorUPtr _handle_frame(const std::shared_ptr &); QUICErrorUPtr _handle_frame(const std::shared_ptr &); + std::vector + _encryption_level_filter() override + { + return { + QUICEncryptionLevel::ZERO_RTT, + QUICEncryptionLevel::ONE_RTT, + }; + } QUICConnectionInfoProvider *_info = nullptr; QUICRTTProvider *_rtt_provider = nullptr; From 2f0757d582b2dd723b74a35ad6ba5bfb1eb84fd6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Jul 2018 14:17:12 +0900 Subject: [PATCH 0683/1313] [draft-13] Generate ACK frame for each encryption level --- iocore/net/quic/QUICAckFrameCreator.cc | 104 ++++++++++-------- iocore/net/quic/QUICAckFrameCreator.h | 31 +++--- .../net/quic/test/test_QUICAckFrameCreator.cc | 50 +++++---- 3 files changed, 104 insertions(+), 81 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index f6f894964d6..84e1b282e3b 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -26,91 +26,99 @@ #include int -QUICAckFrameCreator::update(QUICPacketNumber packet_number, bool protection, bool should_send) +QUICAckFrameCreator::update(QUICEncryptionLevel level, QUICPacketNumber packet_number, bool should_send) { - if (this->_packet_numbers.size() == MAXIMUM_PACKET_COUNT) { - return -1; + if (!this->_is_level_matched(level)) { + return 0; } - this->_packet_numbers.push_back(packet_number); + int index = static_cast(level); + QUICAckPacketNumbers *packet_numbers = &this->_packet_numbers[index]; + packet_numbers->push_back(packet_number); - if (!protection) { - this->_unprotected_packets.insert(packet_number); + if (packet_numbers->size() == MAXIMUM_PACKET_COUNT) { + return -1; } - if (!this->_can_send) { - this->_can_send = true; + if (!this->_can_send[index]) { + this->_can_send[index] = true; } + if (should_send) { - this->_should_send = true; + this->_should_send[index] = true; } return 0; } QUICFrameUPtr -QUICAckFrameCreator::_create_frame() +QUICAckFrameCreator::_create_frame(QUICEncryptionLevel level) { QUICFrameUPtr ack_frame = QUICFrameFactory::create_null_frame(); - if (this->_can_send) { - ack_frame = this->_create_ack_frame(); - this->_can_send = false; - this->_should_send = false; - this->_packet_count = 0; - this->_packet_numbers.clear(); - this->_unprotected_packets.clear(); + + if (!this->_is_level_matched(level)) { + return ack_frame; } - return ack_frame; -} -void -QUICAckFrameCreator::_sort_packet_numbers() -{ - // TODO Find more smart way + int index = static_cast(level); + + if (this->_can_send[index]) { + QUICAckPacketNumbers *packet_numbers = &this->_packet_numbers[index]; + + ack_frame = this->_create_ack_frame(level); + this->_can_send[index] = false; + this->_should_send[index] = false; + packet_numbers->clear(); + } + + return ack_frame; } QUICFrameUPtr -QUICAckFrameCreator::_create_ack_frame() +QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) { + int index = static_cast(level); + QUICAckPacketNumbers *packet_numbers = &this->_packet_numbers[index]; + this->_should_send[index] = false; + std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); - this->_packet_numbers.sort(); - QUICPacketNumber largest_ack_number = this->_packet_numbers.largest_ack_number(); + packet_numbers->sort(); + QUICPacketNumber largest_ack_number = packet_numbers->largest_ack_number(); QUICPacketNumber last_ack_number = largest_ack_number; size_t i = 0; uint8_t gap = 0; uint64_t length = 0; + // TODO: remove protection bool protection = false; - while (i < this->_packet_numbers.size()) { - if (!protection) { - if (this->_unprotected_packets.find(last_ack_number) == this->_unprotected_packets.end()) { - protection = true; - } - } - if (this->_packet_numbers[i] == last_ack_number) { + while (i < packet_numbers->size()) { + QUICPacketNumber pn = (*packet_numbers)[i]; + if (pn == last_ack_number) { last_ack_number--; length++; i++; continue; } + ink_assert(length > 0); + if (ack_frame) { ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}, protection); } else { - uint64_t delay = this->_calculate_delay(); + uint64_t delay = this->_calculate_delay(level); ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, protection); } - gap = last_ack_number - this->_packet_numbers[i]; - last_ack_number = this->_packet_numbers[i]; + gap = last_ack_number - pn; + last_ack_number = pn; length = 0; } if (ack_frame) { ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}, protection); } else { - uint64_t delay = this->_calculate_delay(); + uint64_t delay = this->_calculate_delay(level); ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, protection); } @@ -118,32 +126,40 @@ QUICAckFrameCreator::_create_ack_frame() } bool -QUICAckFrameCreator::will_generate_frame() +QUICAckFrameCreator::will_generate_frame(QUICEncryptionLevel level) { - return this->_should_send; + if (!this->_is_level_matched(level)) { + return false; + } + + return this->_should_send[static_cast(level)]; } QUICFrameUPtr -QUICAckFrameCreator::generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) +QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { // FIXME fix size - return this->_create_frame(); + return this->_create_frame(level); } uint64_t -QUICAckFrameCreator::_calculate_delay() +QUICAckFrameCreator::_calculate_delay(QUICEncryptionLevel level) { // Ack delay is in microseconds and scaled - uint64_t delay = (Thread::get_hrtime() - this->_packet_numbers.largest_ack_received_time()) / 1000; + ink_hrtime now = Thread::get_hrtime(); + uint64_t delay = (now - this->_packet_numbers[static_cast(level)].largest_ack_received_time()) / 1000; // FXIME ack delay exponent has to be read from transport parameters uint8_t ack_delay_exponent = 3; return delay >> ack_delay_exponent; } +// +// QUICAckPacketNumbers +// void QUICAckPacketNumbers::push_back(QUICPacketNumber packet_number) { - if (packet_number > this->_largest_ack_number) { + if (packet_number == 0 || packet_number > this->_largest_ack_number) { this->_largest_ack_received_time = Thread::get_hrtime(); this->_largest_ack_number = packet_number; } diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index acf53ca8195..c78a46302a1 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -62,33 +62,38 @@ class QUICAckFrameCreator : public QUICFrameGenerator * All packet numbers ATS received need to be passed to this method. * Returns 0 if updated successfully. */ - int update(QUICPacketNumber packet_number, bool protection, bool should_send); + int update(QUICEncryptionLevel level, QUICPacketNumber packet_number, bool should_send); /* * Returns true only if should send ack. */ - bool will_generate_frame() override; + bool will_generate_frame(QUICEncryptionLevel level) override; /* * Calls create directly. */ - QUICFrameUPtr generate_frame(uint64_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; private: /* * Returns QUICAckFrame only if ACK frame is able to be sent. * Caller must send the ACK frame to the peer if it was returned. */ - QUICFrameUPtr _create_frame(); + QUICFrameUPtr _create_frame(QUICEncryptionLevel level); + QUICFrameUPtr _create_ack_frame(QUICEncryptionLevel level); + uint64_t _calculate_delay(QUICEncryptionLevel level); + std::vector + _encryption_level_filter() override + { + return { + QUICEncryptionLevel::INITIAL, + QUICEncryptionLevel::HANDSHAKE, + QUICEncryptionLevel::ONE_RTT, + }; + } - bool _can_send = false; - bool _should_send = false; + bool _can_send[4] = {false}; + bool _should_send[4] = {false}; - QUICAckPacketNumbers _packet_numbers; - uint16_t _packet_count = 0; - std::set _unprotected_packets; - - void _sort_packet_numbers(); - QUICFrameUPtr _create_ack_frame(); - uint64_t _calculate_delay(); + QUICAckPacketNumbers _packet_numbers[4]; }; diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index b044c5ac8bc..194c34047a8 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -29,31 +29,32 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") { QUICAckFrameCreator creator; + QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; // Initial state - std::shared_ptr ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + std::shared_ptr ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); std::shared_ptr frame = std::static_pointer_cast(ack_frame); CHECK(frame == nullptr); // One packet - creator.update(1, false, true); - ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + creator.update(level, 1, true); + ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 1); CHECK(frame->ack_block_section()->first_ack_block() == 0); - ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame == nullptr); // Not sequential - creator.update(2, false, true); - creator.update(5, false, true); - creator.update(3, false, true); - creator.update(4, false, true); - ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + creator.update(level, 2, true); + creator.update(level, 5, true); + creator.update(level, 3, true); + creator.update(level, 4, true); + ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -61,10 +62,10 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 3); // Loss - creator.update(6, false, true); - creator.update(7, false, true); - creator.update(10, false, true); - ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + creator.update(level, 6, true); + creator.update(level, 7, true); + creator.update(level, 10, true); + ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); @@ -76,19 +77,20 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") { QUICAckFrameCreator creator; + QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; // Initial state - std::shared_ptr ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + std::shared_ptr ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); std::shared_ptr frame = std::static_pointer_cast(ack_frame); CHECK(frame == nullptr); - creator.update(2, false, true); - creator.update(5, false, true); - creator.update(6, false, true); - creator.update(8, false, true); - creator.update(9, false, true); + creator.update(level, 2, true); + creator.update(level, 5, true); + creator.update(level, 6, true); + creator.update(level, 8, true); + creator.update(level, 9, true); - ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 2); @@ -96,13 +98,13 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 1); CHECK(frame->ack_block_section()->begin()->gap() == 0); - ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame == nullptr); - creator.update(7, false, true); - creator.update(4, false, true); - ack_frame = creator.generate_frame(UINT16_MAX, UINT16_MAX); + creator.update(level, 7, true); + creator.update(level, 4, true); + ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); From 1b99a5fbd3c6f938707ee2f4924331206ed4f7b3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Jul 2018 14:19:36 +0900 Subject: [PATCH 0684/1313] [draft-13] Add QUICCryptoStream --- iocore/net/quic/QUICStream.cc | 100 ++++++++++++++++++++++++++++++++++ iocore/net/quic/QUICStream.h | 52 ++++++++++++++++++ 2 files changed, 152 insertions(+) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index bd25c5db570..4c368023ff0 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -575,3 +575,103 @@ QUICStream::largest_offset_sent() { return this->_remote_flow_controller.current_offset(); } + +// +// QUICCryptoStream +// +QUICCryptoStream::QUICCryptoStream() : _received_stream_frame_buffer() +{ + this->_read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); + this->_write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); + + this->_read_buffer_reader = this->_read_buffer->alloc_reader(); + this->_write_buffer_reader = this->_write_buffer->alloc_reader(); +} + +QUICCryptoStream::~QUICCryptoStream() +{ + // All readers will be deallocated + free_MIOBuffer(this->_read_buffer); + free_MIOBuffer(this->_write_buffer); +} + +/** + * Reset send/recv offset of stream + */ +void +QUICCryptoStream::reset_send_offset() +{ + this->_send_offset = 0; +} + +void +QUICCryptoStream::reset_recv_offset() +{ + this->_received_stream_frame_buffer.clear(); +} + +QUICErrorUPtr +QUICCryptoStream::recv(const std::shared_ptr frame) +{ + QUICErrorUPtr error = this->_received_stream_frame_buffer.insert(frame); + if (error->cls != QUICErrorClass::NONE) { + this->_received_stream_frame_buffer.clear(); + return error; + } + + auto new_frame = this->_received_stream_frame_buffer.pop(); + while (new_frame != nullptr) { + QUICCryptoFrameSPtr crypto_frame = std::static_pointer_cast(new_frame); + + this->_read_buffer->write(crypto_frame->data(), crypto_frame->data_length()); + new_frame = this->_received_stream_frame_buffer.pop(); + } + + return QUICErrorUPtr(new QUICNoError()); +} + +int64_t +QUICCryptoStream::read_avail() +{ + return this->_read_buffer_reader->read_avail(); +} + +int64_t +QUICCryptoStream::read(uint8_t *buf, int64_t len) +{ + return this->_read_buffer_reader->read(buf, len); +} + +int64_t +QUICCryptoStream::write(const uint8_t *buf, int64_t len) +{ + return this->_write_buffer->write(buf, len); +} + +bool +QUICCryptoStream::will_generate_frame(QUICEncryptionLevel level) +{ + return this->_write_buffer_reader->is_read_avail_more_than(0); +} + +QUICFrameUPtr +QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +{ + QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); + + if (this->_reset_reason) { + return QUICFrameFactory::create_rst_stream_frame(std::move(this->_reset_reason)); + } + + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + + // TODO: check len + uint64_t bytes_avail = this->_write_buffer_reader->read_avail(); + uint64_t frame_size = std::min(bytes_avail, (uint64_t)maximum_frame_size); + frame = QUICFrameFactory::create_crypto_frame(reinterpret_cast(this->_write_buffer_reader->start()), frame_size, + this->_send_offset, true); + this->_send_offset += frame_size; + this->_write_buffer_reader->consume(frame_size); + + return frame; +} diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 747165e9f47..2a9b32d4f4f 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -125,3 +125,55 @@ class QUICStream : public VConnection, public QUICFrameGenerator // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState QUICBidirectionalStreamState _state; }; + +/** + * @brief QUIC Crypto stream + * Differences from QUICStream are below + * - this doesn't have VConnection interface + * - no stream id + * - no flow control + * - no state (never closed) + */ +class QUICCryptoStream : public QUICFrameGenerator +{ +public: + QUICCryptoStream(); + ~QUICCryptoStream(); + + int state_stream_open(int event, void *data); + + const QUICConnectionInfoProvider *info() const; + QUICOffset final_offset() const; + void reset_send_offset(); + void reset_recv_offset(); + + QUICErrorUPtr recv(const std::shared_ptr frame); + int64_t read_avail(); + int64_t read(uint8_t *buf, int64_t len); + int64_t write(const uint8_t *buf, int64_t len); + + void reset(QUICStreamErrorUPtr error); + + QUICOffset largest_offset_received(); + QUICOffset largest_offset_sent(); + + LINK(QUICStream, link); + + // QUICFrameGenerator + bool will_generate_frame(QUICEncryptionLevel level) override; + QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + +private: + QUICStreamErrorUPtr _reset_reason = nullptr; + QUICOffset _send_offset = 0; + + // Fragments of received STREAM frame (offset is unmatched) + // TODO: Consider to replace with ts/RbTree.h or other data structure + QUICIncomingCryptoFrameBuffer _received_stream_frame_buffer; + + MIOBuffer *_read_buffer = nullptr; + MIOBuffer *_write_buffer = nullptr; + + IOBufferReader *_read_buffer_reader = nullptr; + IOBufferReader *_write_buffer_reader = nullptr; +}; From 0f6c8e235cfea8c2f7eedc3702271cc51e4b3016 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Jul 2018 14:28:13 +0900 Subject: [PATCH 0685/1313] Make QUICHandshake QUICFrameHandler/Generator instead of QUICApplication --- iocore/net/quic/QUICHandshake.cc | 227 ++++++++++++------------------- iocore/net/quic/QUICHandshake.h | 52 +++---- 2 files changed, 118 insertions(+), 161 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 7ef84aecfa6..44fd91b3b6c 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -33,8 +33,7 @@ #include "QUICGlobals.h" #include "QUICVersionNegotiator.h" #include "QUICConfig.h" - -static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; +#include "QUICStream.h" #define QUICHSDebug(fmt, ...) Debug("quic_handshake", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) @@ -42,6 +41,7 @@ static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; #define I_WANNA_DUMP_THIS_BUF(buf, len) \ { \ + static constexpr char dump_tag[] = "v_quic_handshake_dump_pkt"; \ int i; \ Debug(dump_tag, "len=%" PRId64 "\n", len); \ for (i = 0; i < len / 8; i++) { \ @@ -90,7 +90,7 @@ static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527; QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandshake(qc, ssl_ctx, {}, false) {} QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token, bool stateless_retry) - : QUICApplication(qc), + : _qc(qc), _ssl(SSL_new(ssl_ctx)), _hs_protocol(new QUICTLS(this->_ssl, qc->direction(), stateless_retry)), _version_negotiator(new QUICVersionNegotiator()), @@ -102,10 +102,8 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless this->_hs_protocol->initialize_key_materials(this->_qc->original_connection_id()); if (this->_qc->direction() == NET_VCONNECTION_OUT) { - this->_initial = true; + this->_client_initial = true; } - - SET_HANDLER(&QUICHandshake::state_handshake); } QUICHandshake::~QUICHandshake() @@ -124,6 +122,8 @@ QUICHandshake::start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled this->_load_local_client_transport_parameters(initital_version); packet_factory->set_version(initital_version); + this->do_handshake(); + return QUICErrorUPtr(new QUICNoError()); } @@ -190,7 +190,8 @@ QUICHandshake::is_version_negotiated() const bool QUICHandshake::is_completed() const { - return this->handler == &QUICHandshake::state_complete; + // TODO: check state with other way + return SSL_is_init_finished(this->_ssl); } bool @@ -307,79 +308,73 @@ QUICHandshake::remote_transport_parameters() return this->_remote_transport_parameters; } -int -QUICHandshake::state_handshake(int event, Event *data) +/** + * reset states for starting over + */ +void +QUICHandshake::reset() { - QUICVHSDebug("%s (%d)", get_vc_event_name(event), event); + this->_client_initial = true; + SSL_clear(this->_ssl); - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - switch (event) { - case QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE: { - if (this->_hs_protocol->is_handshake_finished()) { - int res = this->_complete_handshake(); - if (!res) { - this->_abort_handshake(QUICTransErrorCode::TLS_HANDSHAKE_FAILED); - } - } - break; + for (auto level : QUIC_ENCRYPTION_LEVELS) { + int index = static_cast(level); + QUICCryptoStream *stream = &this->_crypto_streams[index]; + stream->reset_send_offset(); + stream->reset_recv_offset(); } - case VC_EVENT_READ_READY: - case VC_EVENT_READ_COMPLETE: - case VC_EVENT_WRITE_READY: - case VC_EVENT_WRITE_COMPLETE: { - error = this->_process_handshake_msg(); +} + +std::vector +QUICHandshake::interests() +{ + return { + QUICFrameType::CRYPTO, + }; +} + +QUICErrorUPtr +QUICHandshake::handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) +{ + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + + switch (frame->type()) { + case QUICFrameType::CRYPTO: + error = this->_crypto_streams[static_cast(level)].recv(std::static_pointer_cast(frame)); break; - } default: + QUICHSDebug("Unexpected frame type: %02x", static_cast(frame->type())); + ink_assert(false); break; } - if (error->cls != QUICErrorClass::NONE) { - QUICTransErrorCode code; - if (dynamic_cast(error.get()) != nullptr) { - code = error->trans_error_code; - } else { - code = QUICTransErrorCode::PROTOCOL_VIOLATION; - } - this->_abort_handshake(code); - } + this->do_handshake(); - return EVENT_DONE; + return error; } -int -QUICHandshake::state_complete(int event, void *data) +bool +QUICHandshake::will_generate_frame(QUICEncryptionLevel level) { - QUICVHSDebug("%s (%d)", get_vc_event_name(event), event); - QUICVHSDebug("Got an event on complete state. Ignoring it for now."); + if (!this->_is_level_matched(level)) { + return false; + } - return EVENT_DONE; + return this->_crypto_streams[static_cast(level)].will_generate_frame(level); } -int -QUICHandshake::state_closed(int event, void *data) +QUICFrameUPtr +QUICHandshake::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { - return EVENT_DONE; -} + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); -QUICHandshakeMsgType -QUICHandshake::msg_type() const -{ - if (this->_hs_protocol) { - return this->_hs_protocol->msg_type(); - } else { - return QUICHandshakeMsgType::NONE; + if (!this->_is_level_matched(level)) { + return frame; } -} -/** - * reset states for starting over - */ -void -QUICHandshake::reset() -{ - this->_initial = true; - SSL_clear(this->_ssl); + frame = this->_crypto_streams[static_cast(level)].generate_frame(level, connection_credit, maximum_frame_size); + + return frame; } void @@ -423,34 +418,44 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi } int -QUICHandshake::_do_handshake(size_t &out_len) +QUICHandshake::do_handshake() { - // TODO: pass stream_io - QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); + QUICHandshakeMsgs in; + uint8_t in_buf[UDP_MAXIMUM_PAYLOAD_SIZE] = {0}; + in.buf = in_buf; + in.max_buf_len = UDP_MAXIMUM_PAYLOAD_SIZE; - uint8_t in[UDP_MAXIMUM_PAYLOAD_SIZE] = {0}; - int64_t in_len = 0; - - if (this->_initial) { - this->_initial = false; + if (this->_client_initial) { + this->_client_initial = false; } else { - // Complete message should fit in a packet and be able to read - in_len = stream_io->read_avail(); - stream_io->read(in, in_len); - - if (in_len <= 0) { - QUICVHSDebug("No message"); - return SSL_ERROR_NONE; + for (auto level : QUIC_ENCRYPTION_LEVELS) { + int index = static_cast(level); + QUICCryptoStream *stream = &this->_crypto_streams[index]; + int64_t bytes_avail = stream->read_avail(); + // 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; + } } - I_WANNA_DUMP_THIS_BUF(in, in_len); } - uint8_t out[MAX_HANDSHAKE_MSG_LEN] = {0}; - int result = this->_hs_protocol->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, in, in_len); + QUICHandshakeMsgs out; + uint8_t out_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + out.buf = out_buf; + out.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - if (out_len > 0) { - I_WANNA_DUMP_THIS_BUF(out, static_cast(out_len)); - stream_io->write(out, out_len); + int result = this->_hs_protocol->handshake(&out, &in); + + for (auto level : QUIC_ENCRYPTION_LEVELS) { + int index = static_cast(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 (!this->_hs_protocol->is_key_derived(QUICKeyPhase::PHASE_0) && this->_hs_protocol->is_ready_to_derive()) { @@ -465,64 +470,10 @@ QUICHandshake::_do_handshake(size_t &out_len) return result; } -QUICErrorUPtr -QUICHandshake::_process_handshake_msg() -{ - QUICStreamIO *stream_io = this->_find_stream_io(STREAM_ID_FOR_HANDSHAKE); - size_t out_len = 0; - int result = this->_do_handshake(out_len); - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - - switch (result) { - case SSL_ERROR_NONE: - if (this->_hs_protocol->is_handshake_finished()) { - int res = this->_complete_handshake(); - if (!res) { - error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); - } - } - // Fall-through - case SSL_ERROR_WANT_READ: { - if (out_len > 0) { - stream_io->write_reenable(); - } - stream_io->read_reenable(); - - break; - } - default: - QUICHSDebug("Handshake failed: %d", result); - error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_HANDSHAKE_FAILED)); - } - - return error; -} - -int -QUICHandshake::_complete_handshake() -{ - QUICHSDebug("Enter state_complete"); - SET_HANDLER(&QUICHandshake::state_complete); - QUICHSDebug("%s", this->negotiated_cipher_suite()); - - int res = 1; - if (!this->_hs_protocol->is_key_derived(QUICKeyPhase::PHASE_0)) { - res = this->_hs_protocol->update_key_materials(); - if (res) { - QUICHSDebug("Keying Materials are exported"); - } else { - QUICHSDebug("Failed to export Keying Materials"); - } - } - - return res; -} - void QUICHandshake::_abort_handshake(QUICTransErrorCode code) { - this->_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(code))); + QUICHSDebug("Abort Handshake"); - QUICHSDebug("Enter state_closed"); - SET_HANDLER(&QUICHandshake::state_closed); + this->_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(code))); } diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 95820c24f2d..d18c0d0ca4b 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -24,25 +24,19 @@ #pragma once #include "QUICConnection.h" -#include "QUICApplication.h" #include "QUICTransportParameters.h" +#include "QUICFrameHandler.h" +#include "QUICFrameGenerator.h" +#include "QUICStream.h" /** * @class QUICHandshake - * @brief Do handshake as a QUIC application - * @detail - * - * state_handshake() - * | - * v - * state_complete() on success - * or - * state_closed() on error + * @brief Send/Receive CRYPTO frame and do Cryptographic Handshake */ class QUICVersionNegotiator; class SSLNextProtocolSet; -class QUICHandshake : public QUICApplication +class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator { public: // Constructor for client side @@ -51,6 +45,14 @@ class QUICHandshake : public QUICApplication QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token, bool stateless_retry); ~QUICHandshake(); + // QUICFrameHandler + virtual std::vector interests() override; + virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) override; + + // QUICFrameGenerator + bool will_generate_frame(QUICEncryptionLevel level) override; + QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + // for client side QUICErrorUPtr start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled); QUICErrorUPtr negotiate_version(const QUICPacket *packet, QUICPacketFactory *packet_factory); @@ -59,10 +61,7 @@ class QUICHandshake : public QUICApplication // for server side QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); - // States - int state_handshake(int event, Event *data); - int state_complete(int event, void *data); - int state_closed(int event, void *data); + int do_handshake(); // Getters QUICHandshakeProtocol *protocol(); @@ -81,9 +80,10 @@ class QUICHandshake : public QUICApplication void set_transport_parameters(std::shared_ptr tp); // A workaround API to indicate handshake msg type to QUICNetVConnection - QUICHandshakeMsgType msg_type() const; + [[deprecated]] QUICHandshakeMsgType msg_type() const; private: + QUICConnection *_qc = nullptr; SSL *_ssl = nullptr; QUICHandshakeProtocol *_hs_protocol = nullptr; std::shared_ptr _local_transport_parameters = nullptr; @@ -91,16 +91,22 @@ class QUICHandshake : public QUICApplication QUICVersionNegotiator *_version_negotiator = nullptr; QUICStatelessResetToken _reset_token; - bool _initial = false; + bool _client_initial = false; bool _stateless_retry = false; + QUICCryptoStream _crypto_streams[4]; + + std::vector + _encryption_level_filter() override + { + return { + QUICEncryptionLevel::INITIAL, + QUICEncryptionLevel::ZERO_RTT, + QUICEncryptionLevel::HANDSHAKE, + QUICEncryptionLevel::ONE_RTT, + }; + } void _load_local_server_transport_parameters(QUICVersion negotiated_version); void _load_local_client_transport_parameters(QUICVersion initial_version); - - int _do_handshake(size_t &out_len); - - QUICErrorUPtr _process_handshake_msg(); - - int _complete_handshake(); void _abort_handshake(QUICTransErrorCode code); }; From a80d8f0ae005318a35e5abeb90344aee3abe5483 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Jul 2018 14:37:03 +0900 Subject: [PATCH 0686/1313] Cleanup: remove STREAM_ID_FOR_HANDSHAKE --- iocore/net/QUICNetVConnection.cc | 10 ----- iocore/net/quic/QUICStream.cc | 25 ++---------- iocore/net/quic/QUICStream.h | 2 - iocore/net/quic/QUICStreamManager.cc | 46 +++------------------- iocore/net/quic/QUICTypes.h | 2 - iocore/net/quic/test/test_QUICHandshake.cc | 2 +- 6 files changed, 9 insertions(+), 78 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index f1cca34115d..7be0e5e52b1 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -207,7 +207,6 @@ QUICNetVConnection::start() } this->_application_map = new QUICApplicationMap(); - this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); this->_hs_protocol = this->_handshake_handler->protocol(); this->_frame_dispatcher = new QUICFrameDispatcher(this); @@ -313,21 +312,12 @@ QUICNetVConnection::connectUp(EThread *t, int fd) // FIXME: startIO only return 0 now! what should we do if it failed ? } - // create stream for handshake - QUICErrorUPtr error = this->_stream_manager->create_stream(STREAM_ID_FOR_HANDSHAKE); - if (error->cls != QUICErrorClass::NONE) { - QUICConDebug("Couldn't create stream for handshake"); - - return CONNECT_FAILURE; - } - nh->startCop(this); // FIXME: complete do_io_xxxx instead this->read.enabled = 1; // start QUIC handshake - this->_handshake_handler->handleEvent(VC_EVENT_WRITE_READY, nullptr); this->_schedule_packet_write_ready(); return CONNECT_SUCCESS; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 4c368023ff0..d345eea6292 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -325,6 +325,7 @@ QUICStream::recv(const QUICStreamFrame &frame) } auto new_frame = this->_received_stream_frame_buffer.pop(); + while (new_frame != nullptr) { QUICStreamFrameSPtr stream_frame = std::static_pointer_cast(new_frame); @@ -418,9 +419,8 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit } if (len > 0) { - bool protection = this->_id != STREAM_ID_FOR_HANDSHAKE; - frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, this->_id, - this->_send_offset, fin, protection); + frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, this->_id, + this->_send_offset, fin, true); if (!this->_state.is_allowed_to_send(*frame)) { QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); return frame; @@ -447,25 +447,6 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit return frame; } -/** - * Reset send/recv offset of stream. This is only for stream 0. - */ -void -QUICStream::reset_send_offset() -{ - if (this->_id == STREAM_ID_FOR_HANDSHAKE) { - this->_send_offset = 0; - } -} - -void -QUICStream::reset_recv_offset() -{ - if (this->_id == STREAM_ID_FOR_HANDSHAKE) { - this->_received_stream_frame_buffer.clear(); - } -} - /** * Replace existing event only if the new event is different than the inprogress event */ diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 2a9b32d4f4f..bc2bfaffffc 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -67,8 +67,6 @@ class QUICStream : public VConnection, public QUICFrameGenerator QUICStreamId id() const; const QUICConnectionInfoProvider *info() const; QUICOffset final_offset() const; - void reset_send_offset(); - void reset_recv_offset(); QUICStreamFrameUPtr generete_frame(uint16_t flow_control_credit, uint16_t maximum_frame_size); // Implement VConnection Interface. diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 08333167adb..c42abb5184c 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -61,12 +61,6 @@ QUICStreamManager::init_flow_control_params(const std::shared_ptr_local_tp = local_tp; this->_remote_tp = remote_tp; - // Setup a stream for Handshake - QUICStream *stream = this->_find_stream(STREAM_ID_FOR_HANDSHAKE); - if (stream) { - stream->init_flow_control_params(UINT64_MAX, UINT64_MAX); - } - if (this->_local_tp) { this->_local_maximum_stream_id_bidi = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS); this->_local_maximum_stream_id_uni = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS); @@ -283,10 +277,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) uint64_t local_max_stream_data = 0; uint64_t remote_max_stream_data = 0; - if (stream_id == STREAM_ID_FOR_HANDSHAKE) { - local_max_stream_data = UINT64_MAX; - remote_max_stream_data = UINT64_MAX; - } else if (this->_local_tp) { + if (this->_local_tp) { local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA), remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); } else { @@ -347,22 +338,6 @@ QUICStreamManager::set_default_application(QUICApplication *app) this->_app_map->set_default(app); } -void -QUICStreamManager::reset_send_offset() -{ - QUICStream *stream = this->_find_stream(STREAM_ID_FOR_HANDSHAKE); - - stream->reset_send_offset(); -} - -void -QUICStreamManager::reset_recv_offset() -{ - QUICStream *stream = this->_find_stream(STREAM_ID_FOR_HANDSHAKE); - - stream->reset_recv_offset(); -} - bool QUICStreamManager::will_generate_frame(QUICEncryptionLevel level) { @@ -389,21 +364,10 @@ QUICStreamManager::generate_frame(QUICEncryptionLevel level, uint64_t connection return frame; } - // Stream 0 must be prioritized over other streams - QUICStream *stream = this->_find_stream(STREAM_ID_FOR_HANDSHAKE); - if (stream) { - frame = stream->generate_frame(level, connection_credit, maximum_frame_size); - } - - if (frame == nullptr) { - for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { - if (s->id() == STREAM_ID_FOR_HANDSHAKE) { - continue; - } - frame = s->generate_frame(level, connection_credit, maximum_frame_size); - if (frame) { - break; - } + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + frame = s->generate_frame(level, connection_credit, maximum_frame_size); + if (frame) { + break; } } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 33a3874dafe..cb8dbd27085 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -51,8 +51,6 @@ constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { }; constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; -constexpr QUICStreamId STREAM_ID_FOR_HANDSHAKE = 0; - // [[deprecated]] enum class QUICHandshakeMsgType { NONE = 0, diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc index f55cdb95b9a..2043ce2b01a 100644 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ b/iocore/net/quic/test/test_QUICHandshake.cc @@ -63,7 +63,7 @@ TEST_CASE("1-RTT handshake ", "[quic]") // setup stream 0 MockQUICRTTProvider rtt; MockQUICConnectionInfoProvider info; - QUICStream *stream = new MockQUICStream(&rtt, &info, STREAM_ID_FOR_HANDSHAKE, UINT64_MAX, UINT64_MAX); + QUICStream *stream = new MockQUICStream(&rtt, &info, 0, UINT64_MAX, UINT64_MAX); MockQUICStreamIO *stream_io = new MockQUICStreamIO(nullptr, stream); client->set_stream(stream, stream_io); From cee6ef4c883af35b286b0f1a170f047dadeef4f0 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Jul 2018 14:37:32 +0900 Subject: [PATCH 0687/1313] Add null check of application --- iocore/net/quic/QUICStreamManager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index c42abb5184c..214449cbfab 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -201,7 +201,7 @@ QUICStreamManager::_handle_frame(const std::shared_ptr &f QUICApplication *application = this->_app_map->get(frame->stream_id()); - if (!application->is_stream_set(stream)) { + if (application && !application->is_stream_set(stream)) { application->set_stream(stream); } QUICErrorUPtr error = stream->recv(*frame); From f90658d97cfb47ca3421a8987a1bd41b222bf92f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 10 Jul 2018 16:20:54 +0900 Subject: [PATCH 0688/1313] Coalescing Packets on sending --- iocore/net/P_QUICNetVConnection.h | 11 +- iocore/net/P_QUICPacketHandler.h | 5 + iocore/net/QUICNetVConnection.cc | 281 ++++++++++---------- iocore/net/QUICPacketHandler.cc | 22 ++ iocore/net/quic/QUICCongestionController.cc | 10 + iocore/net/quic/QUICLossDetector.h | 1 + 6 files changed, 191 insertions(+), 139 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 543b3304ffd..615862151a9 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -215,11 +215,11 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub // QUICConnection (QUICFrameHandler) std::vector interests() override; - QUICErrorUPtr handle_frame(std::shared_ptr frame) override; + QUICErrorUPtr handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) override; // QUICConnection (QUICFrameGenerator) - bool will_generate_frame(); - QUICFrameUPtr generate_frame(uint16_t connection_credit, uint16_t maximum_frame_size); + // bool will_generate_frame(QUICEncryptionLevel level); + // QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint16_t connection_credit, uint16_t maximum_frame_size); int in_closed_queue = 0; @@ -294,14 +294,15 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _close_path_validation_timeout(Event *data); Event *_path_validation_timeout = nullptr; - uint32_t _maximum_stream_frame_data_size(); + uint64_t _maximum_stream_frame_data_size(); uint32_t _transmit_packet(QUICPacketUPtr packet); void _store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, QUICFrameUPtr frame); - void _packetize_frames(); + QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size); void _packetize_closing_frame(); QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type = QUICPacketType::UNINITIALIZED); + QUICPacketUPtr _build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable); QUICErrorUPtr _recv_and_ack(QUICPacketUPtr packet); diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 3380f6b058b..007627015d3 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -41,11 +41,14 @@ class QUICPacketHandler ~QUICPacketHandler(); virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketNumberProtector &pn_protector) = 0; + virtual void send_packet(QUICNetVConnection *vc, Ptr udp_payload) = 0; + virtual void close_conenction(QUICNetVConnection *conn); protected: static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu, const QUICPacketNumberProtector *pn_protector, int dcil); + static void _send_packet(Continuation *c, QUICNetVConnection *vc, Ptr udp_payload); Event *_collector_event = nullptr; QUICClosedConCollector *_closed_con_collector = nullptr; @@ -72,6 +75,7 @@ class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler // QUICPacketHandler virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketNumberProtector &pn_protector) override; + virtual void send_packet(QUICNetVConnection *vc, Ptr udp_payload) override; private: void _recv_packet(int event, UDPPacket *udp_packet) override; @@ -95,6 +99,7 @@ class QUICPacketHandlerOut : public Continuation, public QUICPacketHandler // QUICPacketHandler virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketNumberProtector &pn_protector) override; + virtual void send_packet(QUICNetVConnection *vc, Ptr udp_payload) override; private: void _recv_packet(int event, UDPPacket *udp_packet) override; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 7be0e5e52b1..e86cdf1d7e9 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -62,7 +62,6 @@ static constexpr uint32_t MAX_PACKET_OVERHEAD = 54; // Max long header l static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(20); -static constexpr int FRAME_PER_EVENT = 64; static constexpr uint32_t STATE_CLOSING_MAX_SEND_PKT_NUM = 8; // Max number of sending packets which contain a closing frame. static constexpr uint32_t STATE_CLOSING_MAX_RECV_PKT_WIND = 1 << STATE_CLOSING_MAX_SEND_PKT_NUM; @@ -394,7 +393,7 @@ QUICNetVConnection::maximum_quic_packet_size() const } } -uint32_t +uint64_t QUICNetVConnection::_maximum_stream_frame_data_size() { return this->maximum_quic_packet_size() - MAX_STREAM_FRAME_OVERHEAD - MAX_PACKET_OVERHEAD; @@ -466,7 +465,7 @@ QUICNetVConnection::interests() } QUICErrorUPtr -QUICNetVConnection::handle_frame(std::shared_ptr frame) +QUICNetVConnection::handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); @@ -870,8 +869,6 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack error = this->_handshake_handler->negotiate_version(packet.get(), &this->_packet_factory); // discard all transport state except packet number - this->_stream_manager->reset_send_offset(); - this->_stream_manager->reset_recv_offset(); this->_loss_detector->reset(); this->_congestion_controller->reset(); SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); @@ -879,7 +876,6 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack // start handshake over this->_handshake_handler->reset(); - this->_handshake_handler->handleEvent(VC_EVENT_WRITE_READY, nullptr); this->_schedule_packet_write_ready(); } @@ -911,7 +907,7 @@ QUICErrorUPtr QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) { // discard all transport state - this->_stream_manager->reset_send_offset(); + this->_handshake_handler->reset(); this->_loss_detector->reset(); this->_congestion_controller->reset(); SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); @@ -921,7 +917,6 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) // Packet number of RETRY packet is echo of INITIAL packet this->_packet_recv_queue.reset(); - this->_stream_manager->reset_recv_offset(); // Generate new Connection ID this->_rerandomize_original_cid(); @@ -1049,36 +1044,65 @@ QUICNetVConnection::_state_draining_receive_packet() return QUICErrorUPtr(new QUICNoError()); } +/** + * 1. Check congestion window + * 2. Allocate buffer for UDP Payload + * 3. Generate QUIC Packet + * 4. Store data to the paylaod + * 5. Send UDP Packet + */ QUICErrorUPtr QUICNetVConnection::_state_common_send_packet() { - this->_packetize_frames(); - - QUICPacket *packet; - - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); uint32_t packet_count = 0; - while ((packet = this->_packet_send_queue.dequeue()) != nullptr) { - if (packet->type() == QUICPacketType::HANDSHAKE && !this->_path_validator->is_validated() && - this->_handshake_packets_sent >= 3) { - this->_packet_send_queue.push(packet); + + while (true) { + // TODO: add safeguard like FRAME_PER_EVENT + uint32_t window = this->_congestion_controller->open_window(); + if (window == 0) { break; } - if (!this->_congestion_controller->check_credit()) { - this->_packet_send_queue.push(packet); - break; + + Ptr udp_payload(new_IOBufferBlock()); + uint32_t udp_payload_len = std::min(window, this->_pmtu); + udp_payload->alloc(iobuffer_size_to_index(udp_payload_len)); + + uint32_t written = 0; + for (auto level : QUIC_ENCRYPTION_LEVELS) { + uint32_t max_packet_size = udp_payload_len - written; + QUICPacketUPtr packet = this->_packetize_frames(level, max_packet_size); + + if (packet) { + if (this->netvc_context == NET_VCONNECTION_IN && + (packet->type() == QUICPacketType::INITIAL || packet->type() == QUICPacketType::HANDSHAKE)) { + ++this->_handshake_packets_sent; + // TODO: do path validation before sending over 3 Initial/Handshake packets + } + + // TODO: do not write two QUIC Short Header Packets + uint8_t *buf = reinterpret_cast(udp_payload->end()); + size_t len = 0; + packet->store(buf, &len); + udp_payload->fill(len); + written += len; + + QUICPacket::protect_packet_number(buf, len, &this->_pn_protector, this->_peer_quic_connection_id.length()); + + this->_loss_detector->on_packet_sent(std::move(packet)); + packet_count++; + } } - this->_packet_handler->send_packet(*packet, this, this->_pn_protector); - if (packet->type() == QUICPacketType::HANDSHAKE) { - ++this->_handshake_packets_sent; + if (written) { + this->_packet_handler->send_packet(this, udp_payload); + } else { + udp_payload->dealloc(); + break; } - this->_loss_detector->on_packet_sent(QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet)); - packet_count++; } - QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, packet_count); if (packet_count) { + QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, packet_count); net_activity(this, this_ethread()); } @@ -1089,29 +1113,28 @@ QUICNetVConnection::_state_common_send_packet() QUICErrorUPtr QUICNetVConnection::_state_handshake_send_retry_packet() { - size_t len = 0; - ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); - QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; + // size_t len = 0; + // ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); + // QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; - QUICFrameUPtr frame(nullptr, nullptr); - bool retransmittable = this->_handshake_handler->is_stateless_retry_enabled() ? false : true; + // QUICFrameUPtr frame(nullptr, nullptr); + // bool retransmittable = this->_handshake_handler->is_stateless_retry_enabled() ? false : true; - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); - SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); + // SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); + // SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); - frame = this->_stream_manager->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); - ink_assert(frame); - ink_assert(frame->type() == QUICFrameType::STREAM); - this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - if (len == 0) { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); - } + // frame = this->_stream_manager->generate_frame(this->_remote_flow_controller->credit(), + // this->_maximum_stream_frame_data_size()); ink_assert(frame); ink_assert(frame->type() == QUICFrameType::STREAM); + // this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + // if (len == 0) { + // return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); + // } - QUICPacketUPtr packet = this->_build_packet(std::move(buf), len, retransmittable, QUICPacketType::RETRY); - this->_packet_handler->send_packet(*packet, this, this->_pn_protector); - this->_loss_detector->on_packet_sent(std::move(packet)); + // QUICPacketUPtr packet = this->_build_packet(std::move(buf), len, retransmittable, QUICPacketType::RETRY); + // this->_packet_handler->send_packet(*packet, this, this->_pn_protector); + // this->_loss_detector->on_packet_sent(std::move(packet)); - QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, 1); + // QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, 1); return QUICErrorUPtr(new QUICNoError()); } @@ -1199,106 +1222,117 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans return; } -void -QUICNetVConnection::_packetize_frames() +QUICPacketUPtr +QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size) { - int frame_count = 0; - size_t len = 0; + QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); + int frame_count = 0; + size_t len = 0; ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); - QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; - QUICFrameUPtr frame(nullptr, nullptr); bool retransmittable = false; + uint64_t max_frame_size = max_packet_size - MAX_PACKET_OVERHEAD; + max_frame_size = std::min(max_frame_size, this->_maximum_stream_frame_data_size()); + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); bool will_be_ack_only = true; - if (this->_connection_error || this->_packet_retransmitter.will_generate_frame() || - this->_stream_manager->will_generate_frame() || this->_path_validator->will_generate_frame()) { + if (this->_connection_error || this->_packet_retransmitter.will_generate_frame(level) || + this->_handshake_handler->will_generate_frame(level) || this->_stream_manager->will_generate_frame(level) || + this->_path_validator->will_generate_frame(level)) { will_be_ack_only = false; } - // ACK - if (will_be_ack_only) { - if (this->_ack_frame_creator.will_generate_frame()) { - frame = this->_ack_frame_creator.generate_frame(UINT16_MAX, this->_maximum_stream_frame_data_size()); + // CRYPTO + if (this->_handshake_handler->will_generate_frame(level)) { + frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); + while (frame) { + ++frame_count; + frame->store(buf.get(), &len, max_frame_size); + max_frame_size -= len; + + frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); } - } else { - frame = this->_ack_frame_creator.generate_frame(UINT16_MAX, this->_maximum_stream_frame_data_size()); } - if (frame != nullptr) { - ++frame_count; - this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + // ACK + if (this->_ack_frame_creator.will_generate_frame(level)) { + frame = this->_ack_frame_creator.generate_frame(level, UINT16_MAX, max_frame_size); + if (frame != nullptr) { + ++frame_count; + frame->store(buf.get(), &len, max_frame_size); + max_frame_size -= len; + } } // PATH_CHALLENGE, PATH_RESPOSNE - if (this->_stream_manager->will_generate_frame()) { - frame = this->_path_validator->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); + if (this->_path_validator->will_generate_frame(level)) { + frame = this->_path_validator->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); if (frame) { ++frame_count; - this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + frame->store(buf.get(), &len, max_frame_size); + max_frame_size -= len; } } // NEW_CONNECTION_ID - if (this->_alt_con_manager && this->_alt_con_manager->will_generate_frame()) { - frame = - this->_alt_con_manager->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); + if (this->_alt_con_manager && this->_alt_con_manager->will_generate_frame(level)) { + frame = this->_alt_con_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); while (frame) { ++frame_count; - this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - if (frame_count >= FRAME_PER_EVENT) { - break; - } - frame = - this->_alt_con_manager->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); + frame->store(buf.get(), &len, max_frame_size); + max_frame_size -= len; + frame = this->_alt_con_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); } } // Lost frames - frame = - this->_packet_retransmitter.generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); - while (frame) { - ++frame_count; - this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - if (frame_count >= FRAME_PER_EVENT) { - break; + if (this->_packet_retransmitter.will_generate_frame(level)) { + frame = this->_packet_retransmitter.generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + while (frame) { + ++frame_count; + frame->store(buf.get(), &len, max_frame_size); + max_frame_size -= len; + frame = this->_packet_retransmitter.generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); } - frame = - this->_packet_retransmitter.generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); } // STREAM, MAX_STREAM_DATA, STREAM_BLOCKED - frame = this->_stream_manager->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); - while (frame) { - ++frame_count; - if (frame->type() == QUICFrameType::STREAM) { - int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); - QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); - ink_assert(ret == 0); - } - this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + if (this->_stream_manager->will_generate_frame(level)) { + frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + while (frame) { + ++frame_count; + if (frame->type() == QUICFrameType::STREAM) { + int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); + QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); + ink_assert(ret == 0); + } + frame->store(buf.get(), &len, max_frame_size); + max_frame_size -= len; - if (frame_count >= FRAME_PER_EVENT) { - break; + frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); } - frame = this->_stream_manager->generate_frame(this->_remote_flow_controller->credit(), this->_maximum_stream_frame_data_size()); } // Schedule a packet if (len != 0) { - // Pad with PADDING frames - uint32_t min_size = this->minimum_quic_packet_size(); - if (min_size > len) { - // FIXME QUICNetVConnection should not know the actual type value of PADDING frame - memset(buf.get() + len, 0, min_size - len); - len += min_size - len; + if (level == QUICEncryptionLevel::INITIAL) { + // Pad with PADDING frames + uint32_t min_size = this->minimum_quic_packet_size(); + if (min_size > len) { + // FIXME QUICNetVConnection should not know the actual type value of PADDING frame + memset(buf.get() + len, 0, min_size - len); + len += min_size - len; + } } - this->_transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, current_packet_type)); + + packet = this->_build_packet(level, std::move(buf), len, retransmittable); } + + return packet; } void @@ -1333,12 +1367,13 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) const uint8_t *payload = packet->payload(); uint16_t size = packet->payload_length(); QUICPacketNumber packet_num = packet->packet_number(); + QUICEncryptionLevel level = QUICTypeUtil::encryption_level(packet->type()); bool should_send_ack; QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - error = this->_frame_dispatcher->receive_frames(payload, size, should_send_ack); + error = this->_frame_dispatcher->receive_frames(level, payload, size, should_send_ack); if (error->cls != QUICErrorClass::NONE) { return error; } @@ -1354,39 +1389,27 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } - bool protection = packet->type() == QUICPacketType::PROTECTED || packet->type() == QUICPacketType::ZERO_RTT_PROTECTED; - this->_ack_frame_creator.update(packet_num, protection, should_send_ack); + this->_ack_frame_creator.update(level, packet_num, should_send_ack); return error; } +QUICPacketUPtr +QUICNetVConnection::_build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable) +{ + return this->_build_packet(std::move(buf), len, retransmittable, QUICTypeUtil::packet_type(level)); +} + QUICPacketUPtr QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type) { QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); - // TODO: support NET_VCONNECTION_IN - if (this->get_context() == NET_VCONNECTION_OUT && type == QUICPacketType::UNINITIALIZED) { - if (this->_last_received_packet_type == QUICPacketType::UNINITIALIZED || - this->_last_received_packet_type == QUICPacketType::VERSION_NEGOTIATION || - this->_last_received_packet_type == QUICPacketType::RETRY) { - type = QUICPacketType::INITIAL; - } else if (_last_received_packet_type == QUICPacketType::HANDSHAKE) { - type = QUICPacketType::HANDSHAKE; - } else if (this->_handshake_handler && this->_handshake_handler->is_completed()) { - type = QUICPacketType::PROTECTED; - } else { - Error("Unsupported case"); - } - } - switch (type) { case QUICPacketType::INITIAL: ink_assert(this->get_context() == NET_VCONNECTION_OUT); packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len); - this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); - break; case QUICPacketType::RETRY: // Echo "_largest_received_packet_number" as packet number. Probably this is the packet number from triggering client packet. @@ -1397,24 +1420,14 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi packet = this->_packet_factory.create_handshake_packet(this->_peer_quic_connection_id, this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); - this->_handshake_handler->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); - break; case QUICPacketType::PROTECTED: packet = this->_packet_factory.create_server_protected_packet( this->_peer_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); break; default: - if (this->get_context() == NET_VCONNECTION_IN) { - if (this->_handshake_handler && this->_handshake_handler->is_completed()) { - packet = this->_packet_factory.create_server_protected_packet( - this->_peer_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); - } else { - packet = - this->_packet_factory.create_handshake_packet(this->_peer_quic_connection_id, this->_quic_connection_id, - this->largest_acked_packet_number(), std::move(buf), len, retransmittable); - } - } + // should not be here except zero_rtt + ink_assert(false); break; } diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 602db26d691..e1b58daf5cb 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -100,6 +100,16 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo udp_con->send(c, udp_packet); } +void +QUICPacketHandler::_send_packet(Continuation *c, QUICNetVConnection *vc, Ptr udp_payload) +{ + UDPConnection *udp_con = vc->get_udp_con(); + IpEndpoint addr = vc->con.addr; + UDPPacket *udp_packet = new_UDPPacket(addr, 0, udp_payload); + + udp_con->send(c, udp_packet); +} + // // QUICPacketHandlerIn // @@ -307,6 +317,12 @@ QUICPacketHandlerIn::send_packet(const QUICPacket &packet, QUICNetVConnection *v this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &pn_protector, vc->peer_connection_id().length()); } +void +QUICPacketHandlerIn::send_packet(QUICNetVConnection *vc, Ptr udp_payload) +{ + this->_send_packet(this, vc, udp_payload); +} + // // QUICPacketHandlerOut // @@ -352,6 +368,12 @@ QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection * this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &pn_protector, vc->peer_connection_id().length()); } +void +QUICPacketHandlerOut::send_packet(QUICNetVConnection *vc, Ptr udp_payload) +{ + this->_send_packet(this, vc, udp_payload); +} + void QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet) { diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 0d03be2eb5f..eed302feaba 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -116,6 +116,16 @@ QUICCongestionController::check_credit() const return this->_bytes_in_flight < this->_congestion_window; } +uint32_t +QUICCongestionController::open_window() const +{ + if (this->check_credit()) { + return this->_congestion_window - this->_bytes_in_flight; + } else { + return 0; + } +} + uint32_t QUICCongestionController::bytes_in_flight() const { diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index b84883d3c50..0bcd4161f83 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -67,6 +67,7 @@ class QUICCongestionController virtual void on_packets_lost(const std::map &packets); void on_retransmission_timeout_verified(); bool check_credit() const; + uint32_t open_window() const; void reset(); // Debug From c243e8c00a75c44673f0e4bff27abf01b224391b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 17 Jul 2018 10:27:11 +0900 Subject: [PATCH 0689/1313] Cleanup: remove QUICHandshakeMsgType --- iocore/net/QUICNetVConnection.cc | 11 +-- iocore/net/quic/QUICHandshake.h | 3 - iocore/net/quic/QUICHandshakeProtocol.cc | 9 --- iocore/net/quic/QUICHandshakeProtocol.h | 25 +++--- iocore/net/quic/QUICStreamManager.h | 2 - iocore/net/quic/QUICTLS.cc | 96 ------------------------ iocore/net/quic/QUICTLS.h | 1 - iocore/net/quic/QUICTLS_boringssl.cc | 7 ++ iocore/net/quic/QUICTLS_openssl.cc | 13 ++++ 9 files changed, 33 insertions(+), 134 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e86cdf1d7e9..6fa44e0f899 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -575,14 +575,9 @@ QUICNetVConnection::state_handshake(int event, Event *data) case QUIC_EVENT_PACKET_WRITE_READY: { this->_close_packet_write_ready(data); - if (this->_handshake_handler && this->_handshake_handler->msg_type() == QUICHandshakeMsgType::RETRY) { - error = this->_state_handshake_send_retry_packet(); - if (this->_handshake_handler->is_stateless_retry_enabled()) { - this->_switch_to_close_state(); - } - } else { - error = this->_state_common_send_packet(); - } + // TODO: support RETRY packet + error = this->_state_common_send_packet(); + // Reschedule WRITE_READY this->_schedule_packet_write_ready(true); diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index d18c0d0ca4b..09bd39cce93 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -79,9 +79,6 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator void set_transport_parameters(std::shared_ptr tp); void set_transport_parameters(std::shared_ptr tp); - // A workaround API to indicate handshake msg type to QUICNetVConnection - [[deprecated]] QUICHandshakeMsgType msg_type() const; - private: QUICConnection *_qc = nullptr; SSL *_ssl = nullptr; diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index 94bf852a245..4a408b983c5 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -102,12 +102,3 @@ QUICPacketNumberProtector::set_hs_protocol(QUICHandshakeProtocol *hs_protocol) { this->_hs_protocol = hs_protocol; } - -// -// QUICHandshakeProtocol -// -QUICHandshakeMsgType -QUICHandshakeProtocol::msg_type() const -{ - return this->_msg_type; -} diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 373b84d7ef8..224732350c7 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -72,23 +72,18 @@ class QUICHandshakeProtocol QUICHandshakeProtocol(){}; virtual ~QUICHandshakeProtocol(){}; - virtual int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) = 0; - virtual int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) = 0; - virtual bool is_handshake_finished() const = 0; - virtual bool is_ready_to_derive() const = 0; - virtual bool is_key_derived(QUICKeyPhase key_phase) const = 0; - virtual int initialize_key_materials(QUICConnectionId cid) = 0; - virtual int update_key_materials() = 0; + virtual int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) = 0; + virtual bool is_handshake_finished() const = 0; + virtual bool is_ready_to_derive() const = 0; + virtual bool is_key_derived(QUICKeyPhase key_phase) const = 0; + virtual int initialize_key_materials(QUICConnectionId cid) = 0; + virtual int update_key_materials() = 0; virtual bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; virtual bool decrypt(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, QUICKeyPhase phase) const = 0; + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; virtual bool encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, - uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const = 0; + uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const = 0; virtual bool decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, - uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const = 0; - virtual QUICHandshakeMsgType msg_type() const; - -protected: - QUICHandshakeMsgType _msg_type = QUICHandshakeMsgType::NONE; + uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const = 0; }; diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index ad63209d913..49bf9b31f84 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -54,8 +54,6 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator void reset_stream(QUICStreamId stream_id, QUICStreamErrorUPtr error); void set_default_application(QUICApplication *app); - void reset_send_offset(); - void reset_recv_offset(); DLL stream_list; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 7d145ab9014..797adbe5c51 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -59,102 +59,6 @@ QUICTLS::~QUICTLS() delete this->_server_pp; } -int -QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) -{ - ink_assert(this->_ssl != nullptr); - - // TODO: directly read/write from VIO - BIO *rbio = BIO_new(BIO_s_mem()); - BIO *wbio = BIO_new(BIO_s_mem()); - if (in != nullptr || in_len != 0) { - BIO_write(rbio, in, in_len); - } - SSL_set_bio(this->_ssl, rbio, wbio); - - int err = SSL_ERROR_NONE; - if (!SSL_is_init_finished(this->_ssl)) { - ERR_clear_error(); - int ret = 0; - if (this->_netvc_context == NET_VCONNECTION_IN) { - // If stateless is enabled, TS should not allow early data, these are incompatible. - // Details in https://github.com/openssl/openssl/issues/5235 - if (this->_stateless) { - // process stateless retry -#ifndef OPENSSL_IS_BORINGSSL - ret = SSL_stateless(this->_ssl); -#else - ink_assert(!"stateless retry is not available with boringssl"); -#endif - if (ret > 0) { - this->_stateless = false; - this->_msg_type = QUICHandshakeMsgType::HANDSHAKE; - } else if (ret == 0) { - this->_msg_type = QUICHandshakeMsgType::RETRY; - } - } else { - // process early data - if (!this->_early_data_processed) { - if (this->_read_early_data()) { - this->_early_data_processed = true; - } - -#ifndef OPENSSL_IS_BORINGSSL - if (SSL_get_early_data_status(this->_ssl) == SSL_EARLY_DATA_ACCEPTED) { -#else - if (SSL_early_data_accepted(this->_ssl)) { -#endif - Debug(tag, "Early data processed"); - - if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT)) { - this->_generate_0rtt_key(); - } - } - } - - ret = SSL_accept(this->_ssl); - this->_msg_type = QUICHandshakeMsgType::HANDSHAKE; - } - } else { - ret = SSL_connect(this->_ssl); - -#ifndef OPENSSL_IS_BORINGSSL - // FIXME: if SSL_get_state work well on server side, use this for distinction of HANDSHAKE and RERTY - if (SSL_get_state(this->_ssl) == TLS_ST_CW_CLNT_HELLO) { - this->_msg_type = QUICHandshakeMsgType::INITIAL; - } else { - this->_msg_type = QUICHandshakeMsgType::HANDSHAKE; - } -#else - // No stateless retry support - this->_msg_type = QUICHandshakeMsgType::INITIAL; -#endif - } - - 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 err; - } - } - - out_len = BIO_ctrl_pending(wbio); - if (out_len > 0) { - BIO_read(wbio, out, max_out_len); - } - } - - return err; -} - bool QUICTLS::is_handshake_finished() const { diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index a9ae0b98b04..4ed55144bef 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -45,7 +45,6 @@ class QUICTLS : public QUICHandshakeProtocol static QUICEncryptionLevel get_encryption_level(int msg_type); - int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override; int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) override; bool is_handshake_finished() const override; bool is_ready_to_derive() const override; diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc index 2e14f6ba6f3..5335ffa6664 100644 --- a/iocore/net/quic/QUICTLS_boringssl.cc +++ b/iocore/net/quic/QUICTLS_boringssl.cc @@ -31,6 +31,13 @@ static constexpr char tag[] = "quic_tls"; +int +QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) +{ + ink_assert(false); + return 0; +} + const EVP_AEAD * QUICTLS::_get_evp_aead(QUICKeyPhase phase) const { diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 218a4975941..4b0dd556cc0 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -109,6 +109,19 @@ QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) if (this->_netvc_context == NET_VCONNECTION_IN) { // TODO: early data + // if (!this->_early_data_processed) { + // if (this->_read_early_data()) { + // this->_early_data_processed = true; + // } + // if (SSL_early_data_accepted(this->_ssl)) { + // Debug(tag, "Early data processed"); + + // if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT)) { + // this->_generate_0rtt_key(); + // } + // } + // } + ret = SSL_accept(this->_ssl); } else { ret = SSL_connect(this->_ssl); From 0f2bf0089e67a5c9391a131f72ed71e6ba936f4b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 17 Jul 2018 11:16:19 +0900 Subject: [PATCH 0690/1313] Return empty frame if no bytes to sent --- iocore/net/quic/QUICStream.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index d345eea6292..1db7d0628f8 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -649,6 +649,10 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ // TODO: check len uint64_t bytes_avail = this->_write_buffer_reader->read_avail(); uint64_t frame_size = std::min(bytes_avail, (uint64_t)maximum_frame_size); + if (frame_size == 0) { + return frame; + } + frame = QUICFrameFactory::create_crypto_frame(reinterpret_cast(this->_write_buffer_reader->start()), frame_size, this->_send_offset, true); this->_send_offset += frame_size; From ca9b7ffbe561219805861c5cdb5199e64f8cffcd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 17 Jul 2018 11:17:32 +0900 Subject: [PATCH 0691/1313] Call do_handshake() on client side --- iocore/net/QUICNetVConnection.cc | 2 ++ iocore/net/quic/QUICHandshake.cc | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6fa44e0f899..e10d321b70d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -203,6 +203,7 @@ QUICNetVConnection::start() } else { this->_handshake_handler = new QUICHandshake(this, params->client_ssl_ctx()); this->_handshake_handler->start(&this->_packet_factory, params->vn_exercise_enabled()); + this->_handshake_handler->do_handshake(); } this->_application_map = new QUICApplicationMap(); @@ -871,6 +872,7 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack // start handshake over this->_handshake_handler->reset(); + this->_handshake_handler->do_handshake(); this->_schedule_packet_write_ready(); } diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 44fd91b3b6c..d7f03afa867 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -122,8 +122,6 @@ QUICHandshake::start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled this->_load_local_client_transport_parameters(initital_version); packet_factory->set_version(initital_version); - this->do_handshake(); - return QUICErrorUPtr(new QUICNoError()); } From 7c7223eabdc0e915ac2d54e87180530ad05ea971 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 17 Jul 2018 11:19:36 +0900 Subject: [PATCH 0692/1313] Fix allocating buffer for packet --- iocore/net/QUICNetVConnection.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e10d321b70d..e8820aed0d8 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1225,7 +1225,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); int frame_count = 0; size_t len = 0; - ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); + ats_unique_buf buf = ats_unique_malloc(max_packet_size); QUICFrameUPtr frame(nullptr, nullptr); bool retransmittable = false; @@ -1318,7 +1318,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa if (len != 0) { if (level == QUICEncryptionLevel::INITIAL) { // Pad with PADDING frames - uint32_t min_size = this->minimum_quic_packet_size(); + uint64_t min_size = this->minimum_quic_packet_size(); + min_size = std::min(min_size, max_packet_size); if (min_size > len) { // FIXME QUICNetVConnection should not know the actual type value of PADDING frame memset(buf.get() + len, 0, min_size - len); @@ -1404,7 +1405,6 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi switch (type) { case QUICPacketType::INITIAL: - ink_assert(this->get_context() == NET_VCONNECTION_OUT); packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len); break; From 7ad40959cc37959dd939c4d52c17715157d6ee33 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 17 Jul 2018 12:04:30 +0900 Subject: [PATCH 0693/1313] Add CRYPTO frame in QUICDebugNames --- iocore/net/quic/QUICDebugNames.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 9c0a76d2fa6..72fa363a040 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -86,6 +86,8 @@ QUICDebugNames::frame_type(QUICFrameType type) return "PATH_RESPONSE"; case QUICFrameType::STREAM: return "STREAM"; + case QUICFrameType::CRYPTO: + return "CRYPTO"; case QUICFrameType::UNKNOWN: default: return "UNKNOWN"; From 4229faf002966b631785bf085544656d26309747 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 17 Jul 2018 12:05:37 +0900 Subject: [PATCH 0694/1313] Fix storing frame --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 43 +++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 615862151a9..8142b6f3301 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -298,6 +298,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub uint32_t _transmit_packet(QUICPacketUPtr packet); void _store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, QUICFrameUPtr frame); + void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr frame); QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size); void _packetize_closing_frame(); QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e8820aed0d8..741f1bd1345 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -225,6 +225,7 @@ QUICNetVConnection::start() this->_frame_dispatcher->add_handler(this->_stream_manager); this->_frame_dispatcher->add_handler(this->_loss_detector); this->_frame_dispatcher->add_handler(this->_path_validator); + this->_frame_dispatcher->add_handler(this->_handshake_handler); if (this->direction() == NET_VCONNECTION_IN) { this->_validate_new_path(); @@ -889,8 +890,12 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe // return QUICErrorUPtr(new QUICNoError()); // } + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + // Start handshake - QUICErrorUPtr error = this->_handshake_handler->start(packet.get(), &this->_packet_factory); + if (this->netvc_context == NET_VCONNECTION_IN) { + error = this->_handshake_handler->start(packet.get(), &this->_packet_factory); + } // If version negotiation was failed and VERSION NEGOTIATION packet was sent, nothing to do. if (this->_handshake_handler->is_version_negotiated()) { @@ -1219,6 +1224,22 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retrans return; } +void +QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr frame) +{ + size_t l = 0; + frame->store(buf.get() + offset, &l, max_frame_size); + + offset += l; + max_frame_size -= l; + + if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) { + char msg[1024]; + frame->debug_msg(msg, sizeof(msg)); + QUICConDebug("[TX] %s", msg); + } +} + QUICPacketUPtr QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size) { @@ -1247,8 +1268,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); while (frame) { ++frame_count; - frame->store(buf.get(), &len, max_frame_size); - max_frame_size -= len; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); } @@ -1259,8 +1279,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_ack_frame_creator.generate_frame(level, UINT16_MAX, max_frame_size); if (frame != nullptr) { ++frame_count; - frame->store(buf.get(), &len, max_frame_size); - max_frame_size -= len; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); } } @@ -1269,8 +1288,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_path_validator->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); if (frame) { ++frame_count; - frame->store(buf.get(), &len, max_frame_size); - max_frame_size -= len; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); } } @@ -1279,8 +1297,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_alt_con_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); while (frame) { ++frame_count; - frame->store(buf.get(), &len, max_frame_size); - max_frame_size -= len; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); + frame = this->_alt_con_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); } } @@ -1290,8 +1308,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_packet_retransmitter.generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); while (frame) { ++frame_count; - frame->store(buf.get(), &len, max_frame_size); - max_frame_size -= len; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); + frame = this->_packet_retransmitter.generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); } } @@ -1307,8 +1325,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa this->_remote_flow_controller->current_limit()); ink_assert(ret == 0); } - frame->store(buf.get(), &len, max_frame_size); - max_frame_size -= len; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); } From 0ba665bf4cdb5dc36aa108e68f80425fe999d843 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 17 Jul 2018 12:11:09 +0900 Subject: [PATCH 0695/1313] Separate packet number space --- iocore/net/quic/QUICPacket.cc | 18 +++++++++--------- iocore/net/quic/QUICPacket.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index cffe2c92a9b..7618e354929 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -1035,9 +1035,9 @@ QUICPacketUPtr QUICPacketFactory::create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len) { - QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::INITIAL, destination_cid, source_cid, this->_packet_number_generator.next(), - base_packet_number, this->_version, std::move(payload), len); + QUICPacketNumber pn = this->_packet_number_generator[static_cast(QUICEncryptionLevel::INITIAL)].next(); + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::INITIAL, destination_cid, source_cid, pn, + base_packet_number, this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), true); } @@ -1055,9 +1055,9 @@ QUICPacketFactory::create_handshake_packet(QUICConnectionId destination_cid, QUI QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::HANDSHAKE, destination_cid, source_cid, this->_packet_number_generator.next(), - base_packet_number, this->_version, std::move(payload), len); + QUICPacketNumber pn = this->_packet_number_generator[static_cast(QUICEncryptionLevel::HANDSHAKE)].next(); + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, destination_cid, source_cid, pn, + base_packet_number, this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), retransmittable); } @@ -1065,10 +1065,10 @@ QUICPacketUPtr QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { + QUICPacketNumber pn = this->_packet_number_generator[static_cast(QUICEncryptionLevel::ONE_RTT)].next(); // TODO Key phase should be picked up from QUICHandshakeProtocol, probably - QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::PROTECTED, QUICKeyPhase::PHASE_0, connection_id, this->_packet_number_generator.next(), - base_packet_number, std::move(payload), len); + 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); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index fd9f12d9ca2..91721cbfea9 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -398,7 +398,7 @@ class QUICPacketFactory private: QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; QUICHandshakeProtocol *_hs_protocol = nullptr; - QUICPacketNumberGenerator _packet_number_generator; + QUICPacketNumberGenerator _packet_number_generator[4]; static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeaderUPtr header); QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable); From 40a36c5711cdc84bff9c771a5ce98317dedd2a4b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 18 Jul 2018 11:07:50 +0900 Subject: [PATCH 0696/1313] Check frame size restrictively on frame generation --- iocore/net/QUICNetVConnection.cc | 29 ++++++++++++++++++----------- iocore/net/quic/QUICStream.cc | 29 ++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 741f1bd1345..e8ea6e965e5 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -55,11 +55,12 @@ static constexpr std::string_view QUIC_DEBUG_TAG = "quic_net"sv; Debug("quic_net", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__); \ Error("quic_net [%s] " fmt, this->cids().data(), ##__VA_ARGS__) -static constexpr uint32_t IPV4_HEADER_SIZE = 20; -static constexpr uint32_t IPV6_HEADER_SIZE = 40; -static constexpr uint32_t UDP_HEADER_SIZE = 8; -static constexpr uint32_t MAX_PACKET_OVERHEAD = 54; // Max long header len -static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; +static constexpr uint32_t IPV4_HEADER_SIZE = 20; +static constexpr uint32_t IPV6_HEADER_SIZE = 40; +static constexpr uint32_t UDP_HEADER_SIZE = 8; +static constexpr uint32_t MAX_PACKET_OVERHEAD = 54; // Max long header len +static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; +// static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(20); @@ -1230,6 +1231,9 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t & size_t l = 0; frame->store(buf.get() + offset, &l, max_frame_size); + // frame should be stored because it's created with max_frame_size + ink_assert(l != 0); + offset += l; max_frame_size -= l; @@ -1244,15 +1248,19 @@ QUICPacketUPtr QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size) { QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); - int frame_count = 0; - size_t len = 0; - ats_unique_buf buf = ats_unique_malloc(max_packet_size); - QUICFrameUPtr frame(nullptr, nullptr); - bool retransmittable = false; + if (max_packet_size <= MAX_PACKET_OVERHEAD) { + return packet; + } uint64_t max_frame_size = max_packet_size - MAX_PACKET_OVERHEAD; max_frame_size = std::min(max_frame_size, this->_maximum_stream_frame_data_size()); + int frame_count = 0; + size_t len = 0; + ats_unique_buf buf = ats_unique_malloc(max_packet_size); + QUICFrameUPtr frame(nullptr, nullptr); + bool retransmittable = false; + SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); @@ -1269,7 +1277,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa while (frame) { ++frame_count; this->_store_frame(buf, len, max_frame_size, std::move(frame)); - frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); } } diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 1db7d0628f8..a22390d4cf5 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -40,6 +40,9 @@ Debug("quic_flow_ctrl", "[%s] [%" PRIx64 "] [%s] " fmt, this->_info->cids().data(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) +static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; +static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; + QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data) : VConnection(nullptr), @@ -400,6 +403,10 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit return frame; } + if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) { + return frame; + } + IOBufferReader *reader = this->_write_vio.get_reader(); int64_t bytes_avail = reader->read_avail(); if (bytes_avail == 0) { @@ -411,7 +418,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit bool fin = false; len = std::min(data_len, static_cast( - std::min(static_cast(maximum_frame_size), + std::min(static_cast(maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD), std::min(this->_remote_flow_controller.credit(), static_cast(connection_credit))))); if (this->_write_vio.nbytes == static_cast(this->_send_offset + len)) { @@ -646,17 +653,21 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - // TODO: check len - uint64_t bytes_avail = this->_write_buffer_reader->read_avail(); - uint64_t frame_size = std::min(bytes_avail, (uint64_t)maximum_frame_size); - if (frame_size == 0) { + if (maximum_frame_size <= MAX_CRYPTO_FRAME_OVERHEAD) { + return frame; + } + + uint64_t frame_payload_size = maximum_frame_size - MAX_CRYPTO_FRAME_OVERHEAD; + uint64_t bytes_avail = this->_write_buffer_reader->read_avail(); + frame_payload_size = std::min(bytes_avail, frame_payload_size); + if (frame_payload_size == 0) { return frame; } - frame = QUICFrameFactory::create_crypto_frame(reinterpret_cast(this->_write_buffer_reader->start()), frame_size, - this->_send_offset, true); - this->_send_offset += frame_size; - this->_write_buffer_reader->consume(frame_size); + frame = QUICFrameFactory::create_crypto_frame(reinterpret_cast(this->_write_buffer_reader->start()), + frame_payload_size, this->_send_offset, true); + this->_send_offset += frame_payload_size; + this->_write_buffer_reader->consume(frame_payload_size); return frame; } From 451f4ed174c2f3003c99ef0bdcce007864f49fcd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 18 Jul 2018 11:08:48 +0900 Subject: [PATCH 0697/1313] Process INITIAL packet on client side --- iocore/net/QUICNetVConnection.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e8ea6e965e5..cc75f6b8ecb 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -896,10 +896,13 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe // Start handshake if (this->netvc_context == NET_VCONNECTION_IN) { error = this->_handshake_handler->start(packet.get(), &this->_packet_factory); - } - // If version negotiation was failed and VERSION NEGOTIATION packet was sent, nothing to do. - if (this->_handshake_handler->is_version_negotiated()) { + // 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(std::move(packet)); + } + } else { + // on client side, _handshake_handler is already started. Just process packet like _state_handshake_process_handshake_packet() error = this->_recv_and_ack(std::move(packet)); } From 812e0b2b392a252d8a6fc6ce5a511003440d9d35 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 18 Jul 2018 11:10:10 +0900 Subject: [PATCH 0698/1313] Add empty check in on_packets_lost to avoid crash --- iocore/net/quic/QUICCongestionController.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index eed302feaba..52f20b72761 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -84,6 +84,9 @@ QUICCongestionController::on_packet_acked(const PacketInfo &acked_packet) void QUICCongestionController::on_packets_lost(const std::map &lost_packets) { + if (lost_packets.empty()) { + return; + } // Remove lost packets from bytes_in_flight. for (auto &lost_packet : lost_packets) { this->_bytes_in_flight -= lost_packet.second->bytes; From 9c30ce7adb2afff33ec20de846a632fdf3844a55 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 18 Jul 2018 11:13:17 +0900 Subject: [PATCH 0699/1313] [draft-13] Bump version --- iocore/net/quic/QUICTypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index cb8dbd27085..b73a31c0600 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -47,7 +47,7 @@ using QUICOffset = uint64_t; // Note: You also need to update tests for VersionNegotiationPacket creation, if you change the number of versions // Prefix for drafts (0xff000000) + draft number constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff00000c, + 0xff00000d, }; constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; From c3d9bf142af23d1d2b28719afe397e0b0366f6f7 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 19 Jul 2018 10:52:30 +0900 Subject: [PATCH 0700/1313] Derive traffic keying material from TLS stack This change requires a API to derive traffic keying material on TLS stack. --- iocore/net/quic/QUICHKDF.cc | 13 ++- iocore/net/quic/QUICHandshake.cc | 16 +-- iocore/net/quic/QUICHandshakeProtocol.cc | 5 + iocore/net/quic/QUICHandshakeProtocol.h | 3 +- iocore/net/quic/QUICKeyGenerator.cc | 11 +- iocore/net/quic/QUICKeyGenerator.h | 6 ++ iocore/net/quic/QUICKeyGenerator_openssl.cc | 17 ++++ iocore/net/quic/QUICPacket.cc | 35 ++++--- iocore/net/quic/QUICPacket.h | 8 +- iocore/net/quic/QUICTLS.cc | 11 -- iocore/net/quic/QUICTLS.h | 1 + iocore/net/quic/QUICTLS_boringssl.cc | 11 ++ iocore/net/quic/QUICTLS_openssl.cc | 105 ++++++++++++++++++++ iocore/net/quic/QUICTypes.h | 1 + 14 files changed, 198 insertions(+), 45 deletions(-) diff --git a/iocore/net/quic/QUICHKDF.cc b/iocore/net/quic/QUICHKDF.cc index fd0bd9dc0fa..d01b3953c13 100644 --- a/iocore/net/quic/QUICHKDF.cc +++ b/iocore/net/quic/QUICHKDF.cc @@ -21,9 +21,16 @@ * limitations under the License. */ #include "QUICHKDF.h" + #include #include +#include + +using namespace std::literals; + +constexpr static std::string_view QUIC_HKDF_EXPAND_LABEL_PREFIX("quic "sv); + int QUICHKDF::expand(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, uint16_t length) @@ -35,9 +42,9 @@ QUICHKDF::expand(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t se hkdf_label[0] = (length >> 8) & 0xFF; hkdf_label[1] = length & 0xFF; hkdf_label_len += 2; - // "QUIC " + Label - hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%cQUIC %.*s", static_cast(5 + label_len), - static_cast(label_len), label); + // prefix + Label + hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%c%s%.*s", static_cast(5 + label_len), + QUIC_HKDF_EXPAND_LABEL_PREFIX.data(), static_cast(label_len), label); HKDF::expand(dst, dst_len, secret, secret_len, hkdf_label, hkdf_label_len, length); return 1; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index d7f03afa867..7fe089aa3e8 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -456,14 +456,14 @@ QUICHandshake::do_handshake() } } - if (!this->_hs_protocol->is_key_derived(QUICKeyPhase::PHASE_0) && this->_hs_protocol->is_ready_to_derive()) { - int res = this->_hs_protocol->update_key_materials(); - if (res) { - QUICHSDebug("Keying Materials are exported"); - } else { - QUICHSDebug("Failed to export Keying Materials"); - } - } + // if (!this->_hs_protocol->is_key_derived(QUICKeyPhase::PHASE_0) && this->_hs_protocol->is_ready_to_derive()) { + // int res = this->_hs_protocol->update_key_materials(); + // if (res) { + // QUICHSDebug("Keying Materials are exported"); + // } else { + // QUICHSDebug("Failed to export Keying Materials"); + // } + // } return result; } diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index 4a408b983c5..87c73dd476e 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -50,6 +50,9 @@ QUICPacketProtection::set_key(std::unique_ptr km, QUICKeyPhase phas case QUICKeyPhase::ZERORTT: this->_zerortt_key = std::move(km); break; + case QUICKeyPhase::HANDSHAKE: + this->_handshake_key = std::move(km); + break; } } @@ -65,6 +68,8 @@ QUICPacketProtection::get_key(QUICKeyPhase phase) const return this->_cleartext_key.get(); case QUICKeyPhase::ZERORTT: return this->_zerortt_key.get(); + case QUICKeyPhase::HANDSHAKE: + return this->_handshake_key.get(); } ink_release_assert(!"Bad phase"); diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 224732350c7..06f0acec82d 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -38,8 +38,9 @@ class QUICPacketProtection QUICKeyPhase key_phase() const; private: + std::unique_ptr _cleartext_key = nullptr; // _initial_key std::unique_ptr _zerortt_key = nullptr; - std::unique_ptr _cleartext_key = nullptr; + std::unique_ptr _handshake_key = nullptr; std::unique_ptr _phase_0_key = nullptr; std::unique_ptr _phase_1_key = nullptr; QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 908dec0b09a..6ea8889f6a8 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -31,8 +31,8 @@ using namespace std::literals; constexpr static uint8_t QUIC_VERSION_1_SALT[] = { 0x9c, 0x10, 0x8f, 0x98, 0x52, 0x0a, 0x5c, 0x5c, 0x32, 0x96, 0x8e, 0x95, 0x0e, 0x8a, 0x2c, 0x5f, 0xe0, 0x6d, 0x6c, 0x38, }; -constexpr static std::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("client hs"sv); -constexpr static std::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("server hs"sv); +constexpr static std::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("client in"sv); +constexpr static std::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("server in"sv); constexpr static std::string_view LABEL_FOR_CLIENT_0RTT_SECRET("EXPORTER-QUIC 0rtt"sv); constexpr static std::string_view LABEL_FOR_CLIENT_PP_SECRET("EXPORTER-QUIC client 1rtt"sv); constexpr static std::string_view LABEL_FOR_SERVER_PP_SECRET("EXPORTER-QUIC server 1rtt"sv); @@ -197,3 +197,10 @@ QUICKeyGenerator::_generate_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, co { return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_PN.data(), LABEL_FOR_PN.length(), pn_length); } + +int +QUICKeyGenerator::generate_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, + size_t pn_length) +{ + return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_PN.data(), LABEL_FOR_PN.length(), pn_length); +} diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index 235eab4f474..5dcf1f81f84 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -44,12 +44,18 @@ struct KeyMaterial { size_t pn_len = 512; }; +// TODO: rename "cleartext" to "initial" +// TODO: cleanup pp/0rtt stuff which is removed in draft-13 class QUICKeyGenerator { public: enum class Context { SERVER, CLIENT }; QUICKeyGenerator(Context ctx) : _ctx(ctx) {} + + static int generate_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t pn_length); + static const EVP_MD *get_handshake_digest(const SSL *ssl); + /* * Gnerate a key and an IV for Cleartext */ diff --git a/iocore/net/quic/QUICKeyGenerator_openssl.cc b/iocore/net/quic/QUICKeyGenerator_openssl.cc index a70b996e24c..bdcae8d0d5e 100644 --- a/iocore/net/quic/QUICKeyGenerator_openssl.cc +++ b/iocore/net/quic/QUICKeyGenerator_openssl.cc @@ -78,3 +78,20 @@ QUICKeyGenerator::_get_handshake_digest(const SSL *ssl) const return nullptr; } } + +const EVP_MD * +QUICKeyGenerator::get_handshake_digest(const SSL *ssl) +{ + switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { + case TLS1_3_CK_AES_128_GCM_SHA256: + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + case TLS1_3_CK_AES_128_CCM_SHA256: + case TLS1_3_CK_AES_128_CCM_8_SHA256: + return EVP_sha256(); + case TLS1_3_CK_AES_256_GCM_SHA384: + return EVP_sha384(); + default: + ink_assert(false); + return nullptr; + } +} diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 7618e354929..c9e7c368604 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -89,13 +89,13 @@ QUICPacketHeader::load(const IpEndpoint from, ats_unique_buf buf, size_t len, QU } QUICPacketHeaderUPtr -QUICPacketHeader::build(QUICPacketType type, QUICConnectionId destination_cid, QUICConnectionId source_cid, +QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len) { QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); - new (long_header) - QUICPacketLongHeader(type, destination_cid, source_cid, packet_number, base_packet_number, version, std::move(payload), len); + new (long_header) QUICPacketLongHeader(type, key_phase, destination_cid, source_cid, packet_number, base_packet_number, version, + std::move(payload), len); return QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); } @@ -156,9 +156,9 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf this->_payload_length = len - this->_payload_offset; } -QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICConnectionId destination_cid, QUICConnectionId source_cid, - QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, - ats_unique_buf buf, size_t len) +QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, + QUICConnectionId source_cid, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len) { this->_type = type; this->_destination_cid = destination_cid; @@ -169,6 +169,7 @@ QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICConnectionId this->_version = version; this->_payload = std::move(buf); this->_payload_length = len; + this->_key_phase = key_phase; if (this->_type == QUICPacketType::VERSION_NEGOTIATION) { this->_buf_len = @@ -1025,8 +1026,8 @@ QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUIC } // VN packet dosen't have packet number field and version field is always 0x00000000 - QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, dcid, scid, 0x00, 0x00, 0x00, std::move(versions), len); + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, QUICKeyPhase::CLEARTEXT, dcid, scid, + 0x00, 0x00, 0x00, std::move(versions), len); return QUICPacketFactory::_create_unprotected_packet(std::move(header)); } @@ -1035,9 +1036,10 @@ QUICPacketUPtr QUICPacketFactory::create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len) { - QUICPacketNumber pn = this->_packet_number_generator[static_cast(QUICEncryptionLevel::INITIAL)].next(); - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::INITIAL, destination_cid, source_cid, pn, - base_packet_number, this->_version, std::move(payload), len); + QUICPacketNumber pn = this->_packet_number_generator[static_cast(QUICEncryptionLevel::INITIAL)].next(); + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::CLEARTEXT, destination_cid, source_cid, pn, base_packet_number, + this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), true); } @@ -1045,8 +1047,8 @@ QUICPacketUPtr QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, ats_unique_buf payload, size_t len, bool retransmittable) { - QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::RETRY, destination_cid, source_cid, 0, 0, this->_version, std::move(payload), len); + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, QUICKeyPhase::CLEARTEXT, destination_cid, source_cid, + 0, 0, this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), retransmittable); } @@ -1055,9 +1057,10 @@ QUICPacketFactory::create_handshake_packet(QUICConnectionId destination_cid, QUI QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - QUICPacketNumber pn = this->_packet_number_generator[static_cast(QUICEncryptionLevel::HANDSHAKE)].next(); - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, destination_cid, source_cid, pn, - base_packet_number, this->_version, std::move(payload), len); + QUICPacketNumber pn = this->_packet_number_generator[static_cast(QUICEncryptionLevel::HANDSHAKE)].next(); + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::HANDSHAKE, QUICKeyPhase::HANDSHAKE, destination_cid, source_cid, pn, base_packet_number, + this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), retransmittable); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 91721cbfea9..41dae0bb81b 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -124,9 +124,9 @@ class QUICPacketHeader * * This creates a QUICPacketLongHeader. */ - static QUICPacketHeaderUPtr build(QUICPacketType type, QUICConnectionId destination_cid, QUICConnectionId source_cid, - QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, - ats_unique_buf payload, size_t len); + static QUICPacketHeaderUPtr build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, + QUICConnectionId source_cid, QUICPacketNumber packet_number, + QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); /* * Build a QUICPacketHeader @@ -174,7 +174,7 @@ class QUICPacketLongHeader : public QUICPacketHeader QUICPacketLongHeader() : QUICPacketHeader(){}; virtual ~QUICPacketLongHeader(){}; QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base); - QUICPacketLongHeader(QUICPacketType type, QUICConnectionId destination_cid, QUICConnectionId source_cid, + QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len); QUICPacketType type() const; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 797adbe5c51..a2093eb9ccd 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -42,17 +42,6 @@ to_hex(uint8_t *out, uint8_t *in, int in_len) out[in_len * 2] = 0; } -QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless) - : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx), _stateless(stateless) -{ - ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); - - this->_client_pp = new QUICPacketProtection(); - this->_server_pp = new QUICPacketProtection(); -} - -QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICTLS(ssl, nvc_ctx, false) {} - QUICTLS::~QUICTLS() { delete this->_client_pp; diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 4ed55144bef..0d6944e9afa 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -51,6 +51,7 @@ class QUICTLS : public QUICHandshakeProtocol bool is_key_derived(QUICKeyPhase key_phase) const override; int initialize_key_materials(QUICConnectionId cid) override; int update_key_materials() override; + void update_key_materials_on_key_cb(std::unique_ptr km, int name); bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override; bool decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher, size_t cipher_len, uint64_t pkt_num, diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc index 5335ffa6664..dc4e34b4878 100644 --- a/iocore/net/quic/QUICTLS_boringssl.cc +++ b/iocore/net/quic/QUICTLS_boringssl.cc @@ -31,6 +31,17 @@ static constexpr char tag[] = "quic_tls"; +QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICTLS(ssl, nvc_ctx, false) {} + +QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless) + : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx), _stateless(stateless) +{ + ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); + + this->_client_pp = new QUICPacketProtection(); + this->_server_pp = new QUICPacketProtection(); +} + int QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) { diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 4b0dd556cc0..2aee2b954d9 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -30,6 +30,18 @@ static constexpr char tag[] = "quic_tls"; +static void +to_hex(uint8_t *out, uint8_t *in, int in_len) +{ + for (int i = 0; i < in_len; ++i) { + int u4 = in[i] / 16; + int l4 = in[i] % 16; + out[i * 2] = (u4 < 10) ? ('0' + u4) : ('A' + u4 - 10); + out[i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('A' + l4 - 10); + } + out[in_len * 2] = 0; +} + static void msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg) { @@ -60,6 +72,99 @@ msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, return; } +static void +key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, const unsigned char *key, size_t key_len, + const unsigned char *iv, size_t iv_len, void *arg) +{ + QUICTLS *qtls = reinterpret_cast(arg); + if (qtls == nullptr) { + return; + } + + std::unique_ptr km = std::make_unique(); + memcpy(km->key, key, key_len); + km->key_len = key_len; + memcpy(km->iv, iv, iv_len); + km->iv_len = iv_len; + + const EVP_MD *md = QUICKeyGenerator::get_handshake_digest(ssl); + QUICHKDF hkdf(md); + QUICKeyGenerator::generate_pn(km->pn, &km->pn_len, hkdf, secret, secret_len, key_len); + + if (is_debug_tag_set("vv_quic_crypto")) { + switch (name) { + case SSL_KEY_CLIENT_EARLY_TRAFFIC: + Debug("vv_quic_crypto", "client_early_traffic"); + break; + case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: + Debug("vv_quic_crypto", "client_handshake_traffic"); + break; + case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: + Debug("vv_quic_crypto", "client_application_traffic"); + break; + case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC: + Debug("vv_quic_crypto", "server_handshake_traffic"); + break; + case SSL_KEY_SERVER_APPLICATION_TRAFFIC: + Debug("vv_quic_crypto", "server_application_traffic"); + break; + default: + break; + } + + uint8_t print_buf[512]; + to_hex(print_buf, km->key, km->key_len); + Debug("vv_quic_crypto", "key 0x%s", print_buf); + to_hex(print_buf, km->iv, km->iv_len); + Debug("vv_quic_crypto", "iv 0x%s", print_buf); + to_hex(print_buf, km->pn, km->pn_len); + Debug("vv_quic_crypto", "pn 0x%s", print_buf); + } + + qtls->update_key_materials_on_key_cb(std::move(km), name); + + return; +} + +void +QUICTLS::update_key_materials_on_key_cb(std::unique_ptr km, int name) +{ + switch (name) { + case SSL_KEY_CLIENT_EARLY_TRAFFIC: + this->_client_pp->set_key(std::move(km), QUICKeyPhase::ZERORTT); + break; + case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: + this->_client_pp->set_key(std::move(km), QUICKeyPhase::HANDSHAKE); + break; + case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: + this->_client_pp->set_key(std::move(km), QUICKeyPhase::PHASE_0); + break; + case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC: + this->_server_pp->set_key(std::move(km), QUICKeyPhase::HANDSHAKE); + break; + case SSL_KEY_SERVER_APPLICATION_TRAFFIC: + this->_server_pp->set_key(std::move(km), QUICKeyPhase::PHASE_0); + break; + default: + break; + } + + return; +} + +QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICTLS(ssl, nvc_ctx, false) {} + +QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless) + : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx), _stateless(stateless) +{ + ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); + + this->_client_pp = new QUICPacketProtection(); + this->_server_pp = new QUICPacketProtection(); + + SSL_set_key_callback(this->_ssl, key_cb, this); +} + QUICEncryptionLevel QUICTLS::get_encryption_level(int msg_type) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index b73a31c0600..c61abc46582 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -123,6 +123,7 @@ enum class QUICKeyPhase : int { PHASE_1, CLEARTEXT, ZERORTT, + HANDSHAKE, }; enum class QUICPacketCreationResult { From 70fcaaed4807ed06a393e2bf4b44c404c5c19874 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 19 Jul 2018 15:25:54 +0900 Subject: [PATCH 0701/1313] [draft-13] Add Token Length and Token fields in INITIAL packet This change follows draft-13 + PR1498. --- iocore/net/quic/QUICPacket.cc | 109 ++++++++++++++++++++-- iocore/net/quic/QUICPacket.h | 9 +- iocore/net/quic/QUICPacketReceiveQueue.cc | 9 +- 3 files changed, 116 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index c9e7c368604..52a1f082339 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -144,21 +144,33 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf this->_source_cid = {raw_buf + offset, scil}; offset += scil; - if (this->type() == QUICPacketType::VERSION_NEGOTIATION) { - this->_payload_offset = offset; - } else { + if (this->type() != QUICPacketType::VERSION_NEGOTIATION) { + 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; + } + + // Length Field offset += QUICVariableInt::size(raw_buf + offset); + // PN Field int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf + offset); QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset), pn_len, this->_base_packet_number); - this->_payload_offset = offset + pn_len; + offset += pn_len; } + + this->_payload_offset = offset; this->_payload_length = len - this->_payload_offset; } QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len) + QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len, + ats_unique_buf token, size_t token_len) { this->_type = type; this->_destination_cid = destination_cid; @@ -167,6 +179,8 @@ QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key this->_base_packet_number = base_packet_number; this->_has_version = true; this->_version = version; + this->_token = std::move(token); + this->_token_len = token_len; this->_payload = std::move(buf); this->_payload_length = len; this->_key_phase = key_phase; @@ -242,18 +256,57 @@ QUICPacketLongHeader::scil(uint8_t &scil, const uint8_t *packet, size_t packet_l } bool -QUICPacketLongHeader::length(size_t &length, uint8_t *field_len, const uint8_t *packet, size_t packet_len) +QUICPacketLongHeader::token_length(size_t &token_length, uint8_t *field_len, const uint8_t *packet, size_t packet_len) { + QUICPacketType type; + QUICPacketLongHeader::type(type, packet, packet_len); + + if (type != QUICPacketType::INITIAL) { + token_length = 0; + if (field_len) { + *field_len = 0; + } + return true; + } + uint8_t dcil, scil; + QUICPacketLongHeader::dcil(dcil, packet, packet_len); + QUICPacketLongHeader::scil(scil, packet, packet_len); + size_t offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; + if (offset >= packet_len) { + return false; + } + + token_length = QUICIntUtil::read_QUICVariableInt(packet + offset); + if (field_len) { + *field_len = QUICVariableInt::size(packet + offset); + } + + return true; +} + +bool +QUICPacketLongHeader::length(size_t &length, uint8_t *field_len, const uint8_t *packet, size_t packet_len) +{ + uint8_t dcil, scil; QUICPacketLongHeader::dcil(dcil, packet, packet_len); QUICPacketLongHeader::scil(scil, packet, packet_len); - size_t length_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; + // Token Length (i) + Token (*) (for INITIAL packet) + size_t token_length = 0; + uint8_t token_length_field_len = 0; + if (!QUICPacketLongHeader::token_length(token_length, &token_length_field_len, packet, packet_len)) { + return false; + } + + // Length (i) + size_t length_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil + token_length_field_len + token_length; if (length_offset >= packet_len) { return false; } length = QUICIntUtil::read_QUICVariableInt(packet + length_offset); + if (field_len) { *field_len = QUICVariableInt::size(packet + length_offset); } @@ -263,14 +316,21 @@ QUICPacketLongHeader::length(size_t &length, uint8_t *field_len, const uint8_t * bool QUICPacketLongHeader::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len) { + QUICPacketType type; + QUICPacketLongHeader::type(type, packet, packet_len); + uint8_t dcil, scil; + size_t token_length; + uint8_t token_length_field_len; size_t length; uint8_t length_field_len; if (!QUICPacketLongHeader::dcil(dcil, packet, packet_len) || !QUICPacketLongHeader::scil(scil, packet, packet_len) || + !QUICPacketLongHeader::token_length(token_length, &token_length_field_len, packet, packet_len) || !QUICPacketLongHeader::length(length, &length_field_len, packet, packet_len)) { return false; } - pn_offset = 6 + dcil + scil + length_field_len; + pn_offset = 6 + dcil + scil + token_length_field_len + token_length + length_field_len; + return true; } @@ -343,6 +403,23 @@ QUICPacketHeader::payload_size() const return this->_payload_length; } +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(); + } +} + +size_t +QUICPacketLongHeader::token_len() const +{ + return this->_token_len; +} + bool QUICPacketLongHeader::has_key_phase() const { @@ -391,6 +468,16 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const *len += n; if (this->_type != QUICPacketType::VERSION_NEGOTIATION) { + 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); @@ -403,11 +490,15 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const pn_len = 1; } + // Length Field QUICIntUtil::write_QUICVariableInt(pn_len + this->_payload_length + aead_tag_len, buf + *len, &n); *len += n; + // PN Field QUICTypeUtil::write_QUICPacketNumber(pn, pn_len, buf + *len, &n); *len += n; + + // Payload will be stored } } @@ -874,10 +965,12 @@ QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, const QU return false; } unprotected_pn_len = QUICTypeUtil::read_QUICPacketNumberLen(unprotected_pn); + if (pn_offset + unprotected_pn_len > packet_len) { Debug(tag.data(), "Malformed header: pn_offset=%zu, pn_len=%d", pn_offset, unprotected_pn_len); return false; } + memcpy(packet + pn_offset, unprotected_pn, unprotected_pn_len); return true; } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 41dae0bb81b..c7788d8f931 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -176,7 +176,8 @@ class QUICPacketLongHeader : public QUICPacketHeader QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base); QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, - size_t len); + size_t len, ats_unique_buf token = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }), + size_t token_len = 0); QUICPacketType type() const; QUICConnectionId destination_cid() const; QUICConnectionId source_cid() const; @@ -185,6 +186,8 @@ class QUICPacketLongHeader : public QUICPacketHeader bool is_valid() const; QUICVersion version() const; const uint8_t *payload() const; + const uint8_t *token() const; + size_t token_len() const; QUICKeyPhase key_phase() const; bool has_key_phase() const; uint16_t size() const; @@ -200,6 +203,7 @@ class QUICPacketLongHeader : public QUICPacketHeader * Unlike QUICInvariants::scil(), this returns actual connection id length */ 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, const uint8_t *packet, size_t packet_len); static bool length(size_t &length, uint8_t *field_len, 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); @@ -207,6 +211,9 @@ class QUICPacketLongHeader : public QUICPacketHeader QUICPacketNumber _packet_number; QUICConnectionId _destination_cid = QUICConnectionId::ZERO(); QUICConnectionId _source_cid = QUICConnectionId::ZERO(); + size_t _token_len = 0; //< only INITIAL packet + size_t _token_offset = 0; //< only INITIAL packet + ats_unique_buf _token = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); //< only INITIAL packet size_t _payload_offset = 0; }; diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index e7b2e01013d..62204f4e3c1 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -42,13 +42,18 @@ long_hdr_pkt_len(uint8_t *buf, size_t len) QUICPacketLongHeader::dcil(dcil, buf, len); QUICPacketLongHeader::scil(scil, buf, len); - size_t length_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; + size_t offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; + + // token_length and token_length_field_len should be 0 except INITIAL packet + size_t token_length; + uint8_t token_length_field_len; + QUICPacketLongHeader::token_length(token_length, &token_length_field_len, buf, len); size_t length; uint8_t length_field_len; QUICPacketLongHeader::length(length, &length_field_len, buf, len); - return length_offset + length_field_len + length; + return offset + token_length + token_length_field_len + length_field_len + length; } QUICPacketReceiveQueue::QUICPacketReceiveQueue(QUICPacketFactory &packet_factory, QUICPacketNumberProtector &pn_protector) From 5cb3191e4fb30e32c5b4445e63b4f97a032ed252 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 20 Jul 2018 11:17:49 +0900 Subject: [PATCH 0702/1313] [draft-13] adjust QUICHKDF::expand to use HkdfLabel structure of TLS 1.3 --- iocore/net/quic/QUICHKDF.cc | 27 +++++++++----- iocore/net/quic/test/test_QUICKeyGenerator.cc | 36 +++++++++++++------ 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/iocore/net/quic/QUICHKDF.cc b/iocore/net/quic/QUICHKDF.cc index d01b3953c13..08cc8cd9428 100644 --- a/iocore/net/quic/QUICHKDF.cc +++ b/iocore/net/quic/QUICHKDF.cc @@ -27,25 +27,34 @@ #include -using namespace std::literals; - -constexpr static std::string_view QUIC_HKDF_EXPAND_LABEL_PREFIX("quic "sv); - +/** + * HKDF-Expand-Label function of QUIC + * The HKDF-Expand-Label function and HkdfLabel structure is defined in TLS 1.3 Section 7.1. + */ int QUICHKDF::expand(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, uint16_t length) { - // Create HKDF label + // Create HkdfLabel uint8_t hkdf_label[512]; // 2 + 255 + 255 int hkdf_label_len = 0; - // Length + + // length field hkdf_label[0] = (length >> 8) & 0xFF; hkdf_label[1] = length & 0xFF; hkdf_label_len += 2; - // prefix + Label - hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%c%s%.*s", static_cast(5 + label_len), - QUIC_HKDF_EXPAND_LABEL_PREFIX.data(), static_cast(label_len), label); + + // label (prefix + Label) field + hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%cquic %.*s", static_cast(5 + label_len), + static_cast(label_len), label); + + // context field + // XXX: Assuming Context is zero-length character (indicated by "") + // HkdfLabel requires "0" (length) in context field, because `context<0..255>` is valiable-integer. + hkdf_label[hkdf_label_len] = 0; + ++hkdf_label_len; HKDF::expand(dst, dst_len, secret, secret_len, hkdf_label, hkdf_label_len, length); + return 1; } diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index ffb8c37102b..1c19a2c003a 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -32,19 +32,26 @@ #include -#include "Mock.h" +// #include "Mock.h" #include "QUICKeyGenerator.h" TEST_CASE("QUICKeyGenerator", "[quic]") { - SECTION("CLIENT Cleartext") + SECTION("CLIENT Initial") { QUICKeyGenerator keygen(QUICKeyGenerator::Context::CLIENT); - QUICConnectionId cid = {reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x08"), 8}; - uint8_t expected_client_key[] = {0x3a, 0xd0, 0x54, 0x2c, 0x4a, 0x85, 0x84, 0x74, - 0x00, 0x63, 0x04, 0x9e, 0x3b, 0x3c, 0xaa, 0xb2}; - uint8_t expected_client_iv[] = {0xd1, 0xfd, 0x26, 0x05, 0x42, 0x75, 0x3a, 0xba, 0x38, 0x58, 0x9b, 0xad}; + QUICConnectionId cid = {reinterpret_cast("\x06\xb8\x58\xec\x6f\x80\x45\x2b"), 8}; + + uint8_t expected_client_key[] = { + 0xa7, 0x99, 0x43, 0x56, 0x6c, 0x41, 0x34, 0x2f, 0x2b, 0xc3, 0xde, 0x6b, 0x7c, 0x15, 0x39, 0xdf, + }; + uint8_t expected_client_iv[] = { + 0x84, 0xeb, 0x95, 0x4f, 0xfe, 0x16, 0x1c, 0x38, 0x75, 0x91, 0x9f, 0x5f, + }; + uint8_t expected_client_pn[] = { + 0x5c, 0x0f, 0x64, 0x72, 0xa1, 0x56, 0x58, 0x04, 0x7a, 0x3c, 0xc1, 0xf1, 0x54, 0x78, 0xdc, 0xf4, + }; std::unique_ptr actual_km = keygen.generate(cid); @@ -54,14 +61,21 @@ TEST_CASE("QUICKeyGenerator", "[quic]") CHECK(memcmp(actual_km->iv, expected_client_iv, sizeof(expected_client_iv)) == 0); } - SECTION("SERVER Cleartext") + SECTION("SERVER Initial") { QUICKeyGenerator keygen(QUICKeyGenerator::Context::SERVER); - QUICConnectionId cid = {reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x08"), 8}; - uint8_t expected_server_key[] = {0xbe, 0xe4, 0xc2, 0x4d, 0x2a, 0xf1, 0x33, 0x80, - 0xa9, 0xfa, 0x24, 0xa5, 0xe2, 0xba, 0x2c, 0xff}; - uint8_t expected_server_iv[] = {0x25, 0xb5, 0x8e, 0x24, 0x6d, 0x9e, 0x7d, 0x5f, 0xfe, 0x43, 0x23, 0xfe}; + QUICConnectionId cid = {reinterpret_cast("\x06\xb8\x58\xec\x6f\x80\x45\x2b"), 8}; + + uint8_t expected_server_key[] = { + 0x26, 0x08, 0x0e, 0x60, 0xd2, 0x88, 0xdb, 0x7d, 0xf8, 0x16, 0xa1, 0xcb, 0x0b, 0xc6, 0xc7, 0xf4, + }; + uint8_t expected_server_iv[] = { + 0xb9, 0xfd, 0xc5, 0xb4, 0x48, 0xaf, 0x3e, 0x02, 0x34, 0x22, 0x44, 0x3b, + }; + uint8_t expected_server_pn[] = { + 0x00, 0xba, 0xbb, 0xe1, 0xbe, 0x0f, 0x0c, 0x66, 0x18, 0x18, 0x8b, 0x4f, 0xcc, 0xa5, 0x7a, 0x96, + }; std::unique_ptr actual_km = keygen.generate(cid); From 0b9031939d973ab397560af3dc69dec37aa9508e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 20 Jul 2018 11:45:45 +0900 Subject: [PATCH 0703/1313] Add debug prints of secrets with vv_quic_crypto tag --- iocore/net/quic/QUICDebugNames.h | 16 ++++++++++ iocore/net/quic/QUICKeyGenerator.cc | 26 ++++++++++++++- iocore/net/quic/QUICTLS.cc | 49 +++++++++++++---------------- iocore/net/quic/QUICTLS_openssl.cc | 20 +++--------- 4 files changed, 67 insertions(+), 44 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index a01cf521adf..a117805e7a2 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -41,3 +41,19 @@ class QUICDebugNames static const char *key_phase(QUICKeyPhase phase); static const char *encryption_level(QUICEncryptionLevel level); }; + +class QUICDebug +{ +public: + static void + to_hex(uint8_t *out, uint8_t *in, int in_len) + { + for (int i = 0; i < in_len; ++i) { + int u4 = in[i] / 16; + int l4 = in[i] % 16; + out[i * 2] = (u4 < 10) ? ('0' + u4) : ('A' + u4 - 10); + out[i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('A' + l4 - 10); + } + out[in_len * 2] = 0; + } +}; diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 6ea8889f6a8..228633ab01c 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -21,10 +21,15 @@ * limitations under the License. */ -#include #include "QUICKeyGenerator.h" + +#include + #include "ts/ink_assert.h" +#include "ts/Diags.h" + #include "QUICHKDF.h" +#include "QUICDebugNames.h" using namespace std::literals; @@ -55,10 +60,22 @@ QUICKeyGenerator::generate(QUICConnectionId cid) case Context::CLIENT: this->_generate_cleartext_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_CLIENT_CLEARTEXT_SECRET.data(), LABEL_FOR_CLIENT_CLEARTEXT_SECRET.length(), EVP_MD_size(md)); + if (is_debug_tag_set("vv_quic_crypto")) { + uint8_t print_buf[512]; + QUICDebug::to_hex(print_buf, secret, secret_len); + Debug("vv_quic_crypto", "client in secret 0x%s", print_buf); + } + break; case Context::SERVER: this->_generate_cleartext_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_SERVER_CLEARTEXT_SECRET.data(), LABEL_FOR_SERVER_CLEARTEXT_SECRET.length(), EVP_MD_size(md)); + if (is_debug_tag_set("vv_quic_crypto")) { + uint8_t print_buf[512]; + QUICDebug::to_hex(print_buf, secret, secret_len); + Debug("vv_quic_crypto", "server in secret 0x%s", print_buf); + } + break; } @@ -135,12 +152,19 @@ QUICKeyGenerator::_generate_cleartext_secret(uint8_t *out, size_t *out_len, QUIC uint8_t cleartext_secret[512]; size_t cleartext_secret_len = sizeof(cleartext_secret); + // TODO: do not extract initial secret twice QUICTypeUtil::write_QUICConnectionId(cid, client_connection_id, &cid_len); if (hkdf.extract(cleartext_secret, &cleartext_secret_len, QUIC_VERSION_1_SALT, sizeof(QUIC_VERSION_1_SALT), client_connection_id, cid.length()) != 1) { return -1; } + if (is_debug_tag_set("vv_quic_crypto")) { + uint8_t print_buf[512]; + QUICDebug::to_hex(print_buf, cleartext_secret, cleartext_secret_len); + Debug("vv_quic_crypto", "initial secret 0x%s", print_buf); + } + hkdf.expand(out, out_len, cleartext_secret, cleartext_secret_len, reinterpret_cast(label), label_len, length); return 0; } diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index a2093eb9ccd..207458b18b7 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -22,25 +22,14 @@ */ #include "QUICTLS.h" -#include "QUICDebugNames.h" #include #include #include -constexpr static char tag[] = "quic_tls"; +#include "QUICDebugNames.h" -static void -to_hex(uint8_t *out, uint8_t *in, int in_len) -{ - for (int i = 0; i < in_len; ++i) { - int u4 = in[i] / 16; - int l4 = in[i] % 16; - out[i * 2] = (u4 < 10) ? ('0' + u4) : ('A' + u4 - 10); - out[i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('A' + l4 - 10); - } - out[in_len * 2] = 0; -} +constexpr static char tag[] = "quic_tls"; QUICTLS::~QUICTLS() { @@ -79,26 +68,30 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) { // Generate keys Debug(tag, "Generating %s keys", QUICDebugNames::key_phase(QUICKeyPhase::CLEARTEXT)); - uint8_t print_buf[512]; std::unique_ptr km; + km = this->_keygen_for_client.generate(cid); + if (is_debug_tag_set("vv_quic_crypto")) { - to_hex(print_buf, km->key, km->key_len); + uint8_t print_buf[512]; + QUICDebug::to_hex(print_buf, km->key, km->key_len); Debug("vv_quic_crypto", "client key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); + QUICDebug::to_hex(print_buf, km->iv, km->iv_len); Debug("vv_quic_crypto", "client iv 0x%s", print_buf); - to_hex(print_buf, km->pn, km->pn_len); + QUICDebug::to_hex(print_buf, km->pn, km->pn_len); Debug("vv_quic_crypto", "client pn 0x%s", print_buf); } this->_client_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); km = this->_keygen_for_server.generate(cid); + if (is_debug_tag_set("vv_quic_crypto")) { - to_hex(print_buf, km->key, km->key_len); + uint8_t print_buf[512]; + QUICDebug::to_hex(print_buf, km->key, km->key_len); Debug("vv_quic_crypto", "server key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); + QUICDebug::to_hex(print_buf, km->iv, km->iv_len); Debug("vv_quic_crypto", "server iv 0x%s", print_buf); - to_hex(print_buf, km->pn, km->pn_len); + QUICDebug::to_hex(print_buf, km->pn, km->pn_len); Debug("vv_quic_crypto", "server pn 0x%s", print_buf); } this->_server_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); @@ -140,21 +133,21 @@ QUICTLS::update_key_materials() std::unique_ptr km; km = this->_keygen_for_client.generate(this->_ssl); if (is_debug_tag_set("vv_quic_crypto")) { - to_hex(print_buf, km->key, km->key_len); + QUICDebug::to_hex(print_buf, km->key, km->key_len); Debug("vv_quic_crypto", "client key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); + QUICDebug::to_hex(print_buf, km->iv, km->iv_len); Debug("vv_quic_crypto", "client iv 0x%s", print_buf); - to_hex(print_buf, km->pn, km->pn_len); + QUICDebug::to_hex(print_buf, km->pn, km->pn_len); Debug("vv_quic_crypto", "client pn 0x%s", print_buf); } this->_client_pp->set_key(std::move(km), next_key_phase); km = this->_keygen_for_server.generate(this->_ssl); if (is_debug_tag_set("vv_quic_crypto")) { - to_hex(print_buf, km->key, km->key_len); + QUICDebug::to_hex(print_buf, km->key, km->key_len); Debug("vv_quic_crypto", "server key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); + QUICDebug::to_hex(print_buf, km->iv, km->iv_len); Debug("vv_quic_crypto", "server iv 0x%s", print_buf); - to_hex(print_buf, km->pn, km->pn_len); + QUICDebug::to_hex(print_buf, km->pn, km->pn_len); Debug("vv_quic_crypto", "server pn 0x%s", print_buf); } this->_server_pp->set_key(std::move(km), next_key_phase); @@ -195,9 +188,9 @@ QUICTLS::_generate_0rtt_key() km = this->_keygen_for_client.generate_0rtt(this->_ssl); if (is_debug_tag_set("vv_quic_crypto")) { uint8_t print_buf[512]; - to_hex(print_buf, km->key, km->key_len); + QUICDebug::to_hex(print_buf, km->key, km->key_len); Debug("vv_quic_crypto", "0rtt key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); + QUICDebug::to_hex(print_buf, km->iv, km->iv_len); Debug("vv_quic_crypto", "0rtt iv 0x%s", print_buf); } this->_client_pp->set_key(std::move(km), QUICKeyPhase::ZERORTT); diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 2aee2b954d9..6da115c0bf0 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -28,19 +28,9 @@ #include #include -static constexpr char tag[] = "quic_tls"; +#include "QUICDebugNames.h" -static void -to_hex(uint8_t *out, uint8_t *in, int in_len) -{ - for (int i = 0; i < in_len; ++i) { - int u4 = in[i] / 16; - int l4 = in[i] % 16; - out[i * 2] = (u4 < 10) ? ('0' + u4) : ('A' + u4 - 10); - out[i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('A' + l4 - 10); - } - out[in_len * 2] = 0; -} +static constexpr char tag[] = "quic_tls"; static void msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg) @@ -113,11 +103,11 @@ key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, const } uint8_t print_buf[512]; - to_hex(print_buf, km->key, km->key_len); + QUICDebug::to_hex(print_buf, km->key, km->key_len); Debug("vv_quic_crypto", "key 0x%s", print_buf); - to_hex(print_buf, km->iv, km->iv_len); + QUICDebug::to_hex(print_buf, km->iv, km->iv_len); Debug("vv_quic_crypto", "iv 0x%s", print_buf); - to_hex(print_buf, km->pn, km->pn_len); + QUICDebug::to_hex(print_buf, km->pn, km->pn_len); Debug("vv_quic_crypto", "pn 0x%s", print_buf); } From 553c45945e627853ff5bbfdf6137b6d82709470e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 20 Jul 2018 15:10:44 +0900 Subject: [PATCH 0704/1313] Change Encryption Level on key callback --- iocore/net/QUICNetVConnection.cc | 4 +++- iocore/net/quic/QUICHandshakeProtocol.h | 1 + iocore/net/quic/QUICTLS.cc | 16 ++++++++++++++++ iocore/net/quic/QUICTLS.h | 8 ++++++-- iocore/net/quic/QUICTLS_openssl.cc | 5 +++++ 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index cc75f6b8ecb..9a1c3827007 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1383,7 +1383,9 @@ QUICNetVConnection::_packetize_closing_frame() QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - this->_the_final_packet = this->_build_packet(std::move(buf), len, false); + QUICEncryptionLevel level = this->_hs_protocol->current_encryption_level(); + ink_assert(level != QUICEncryptionLevel::ZERO_RTT); + this->_the_final_packet = this->_build_packet(level, std::move(buf), len, false); } QUICErrorUPtr diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 06f0acec82d..5285025eceb 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -87,4 +87,5 @@ class QUICHandshakeProtocol uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const = 0; virtual bool decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const = 0; + virtual QUICEncryptionLevel current_encryption_level() const = 0; }; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 207458b18b7..b5b58b96e7f 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -155,6 +155,22 @@ QUICTLS::update_key_materials() return 1; } +QUICEncryptionLevel +QUICTLS::current_encryption_level() const +{ + return this->_current_level; +} + +void +QUICTLS::_update_encryption_level(QUICEncryptionLevel level) +{ + if (this->_current_level < level) { + this->_current_level = level; + } + + return; +} + int QUICTLS::_read_early_data() { diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 0d6944e9afa..3ae8caa3986 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -60,6 +60,7 @@ class QUICTLS : public QUICHandshakeProtocol const uint8_t *sample, QUICKeyPhase phase) const override; bool decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const override; + QUICEncryptionLevel current_encryption_level() const override; // FIXME SSL handle should not be exported SSL *ssl_handle(); @@ -82,6 +83,10 @@ class QUICTLS : public QUICHandshakeProtocol const uint8_t *sample, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead) const; bool _decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, const uint8_t *sample, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead) const; + int _read_early_data(); + void _generate_0rtt_key(); + void _update_encryption_level(QUICEncryptionLevel level); + SSL *_ssl = nullptr; QUICPacketProtection *_client_pp = nullptr; QUICPacketProtection *_server_pp = nullptr; @@ -89,6 +94,5 @@ class QUICTLS : public QUICHandshakeProtocol bool _stateless = false; bool _early_data_processed = false; bool _early_data = true; - int _read_early_data(); - void _generate_0rtt_key(); + QUICEncryptionLevel _current_level = QUICEncryptionLevel::INITIAL; }; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 6da115c0bf0..4cc31066dd9 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -121,18 +121,23 @@ QUICTLS::update_key_materials_on_key_cb(std::unique_ptr km, int nam { switch (name) { case SSL_KEY_CLIENT_EARLY_TRAFFIC: + // this->_update_encryption_level(QUICEncryptionLevel::ZERO_RTT); this->_client_pp->set_key(std::move(km), QUICKeyPhase::ZERORTT); break; case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: + this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); this->_client_pp->set_key(std::move(km), QUICKeyPhase::HANDSHAKE); break; case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: + this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); this->_client_pp->set_key(std::move(km), QUICKeyPhase::PHASE_0); break; case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC: + this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); this->_server_pp->set_key(std::move(km), QUICKeyPhase::HANDSHAKE); break; case SSL_KEY_SERVER_APPLICATION_TRAFFIC: + this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); this->_server_pp->set_key(std::move(km), QUICKeyPhase::PHASE_0); break; default: From 5e4e2340ceb056b6eabbb92f538c89ffca9c874f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 23 Jul 2018 08:44:19 +0900 Subject: [PATCH 0705/1313] Set key phase depends on packet type --- iocore/net/quic/QUICDebugNames.cc | 2 ++ iocore/net/quic/QUICHandshakeProtocol.h | 2 +- iocore/net/quic/QUICPacket.cc | 40 ++++++++----------------- iocore/net/quic/QUICTLS.cc | 4 +-- iocore/net/quic/QUICTLS.h | 2 +- iocore/net/quic/QUICTypes.cc | 19 ++++++++++++ iocore/net/quic/QUICTypes.h | 1 + 7 files changed, 38 insertions(+), 32 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 72fa363a040..75c422e17b3 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -251,6 +251,8 @@ QUICDebugNames::key_phase(QUICKeyPhase phase) return "CLEARTEXT"; case QUICKeyPhase::ZERORTT: return "ZERORTT"; + case QUICKeyPhase::HANDSHAKE: + return "HANDSHAKE"; default: return "UNKNOWN"; } diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 5285025eceb..a9374859899 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -76,7 +76,7 @@ class QUICHandshakeProtocol virtual int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) = 0; virtual bool is_handshake_finished() const = 0; virtual bool is_ready_to_derive() const = 0; - virtual bool is_key_derived(QUICKeyPhase key_phase) const = 0; + virtual bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const = 0; virtual int initialize_key_materials(QUICConnectionId cid) = 0; virtual int update_key_materials() = 0; virtual bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 52a1f082339..b54d8b634b4 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -131,6 +131,7 @@ QUICPacketHeader::clone() const QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base) : QUICPacketHeader(from, std::move(buf), len, base) { + this->_key_phase = QUICTypeUtil::key_phase(this->type()); uint8_t *raw_buf = this->_buf.get(); uint8_t dcil = 0; @@ -156,6 +157,7 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf // Length Field offset += QUICVariableInt::size(raw_buf + offset); + // PN Field int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf + offset); QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset), pn_len, @@ -429,12 +431,7 @@ QUICPacketLongHeader::has_key_phase() const QUICKeyPhase QUICPacketLongHeader::key_phase() const { - switch (this->type()) { - case QUICPacketType::ZERO_RTT_PROTECTED: - return QUICKeyPhase::ZERORTT; - default: - return QUICKeyPhase::CLEARTEXT; - } + return this->_key_phase; } uint16_t @@ -891,14 +888,7 @@ QUICPacket::protect_packet_number(uint8_t *packet, size_t packet_len, const QUIC if (QUICInvariants::is_long_header(packet)) { QUICPacketType type; QUICPacketLongHeader::type(type, packet, packet_len); - switch (type) { - case QUICPacketType::ZERO_RTT_PROTECTED: - phase = QUICKeyPhase::ZERORTT; - break; - default: - phase = QUICKeyPhase::CLEARTEXT; - break; - } + phase = QUICTypeUtil::key_phase(type); QUICPacketLongHeader::packet_number_offset(pn_offset, packet, packet_len); } else { QUICPacketShortHeader::key_phase(phase, packet, packet_len); @@ -934,14 +924,8 @@ QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, const QU QUICPacketType type; QUICPacketLongHeader::type(type, packet, packet_len); - switch (type) { - case QUICPacketType::ZERO_RTT_PROTECTED: - phase = QUICKeyPhase::ZERORTT; - break; - default: - phase = QUICKeyPhase::CLEARTEXT; - break; - } + phase = QUICTypeUtil::key_phase(type); + if (!QUICPacketLongHeader::packet_number_offset(pn_offset, packet, packet_len)) { Debug(tag.data(), "Failed to calculate packet number offset"); return false; @@ -1020,7 +1004,7 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP result = QUICPacketCreationResult::SUCCESS; break; case QUICPacketType::PROTECTED: - if (this->_hs_protocol->is_key_derived(header->key_phase())) { + if (this->_hs_protocol->is_key_derived(header->key_phase(), false)) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { @@ -1033,7 +1017,7 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } break; case QUICPacketType::INITIAL: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::CLEARTEXT)) { + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::CLEARTEXT, false)) { if (QUICTypeUtil::is_supported_version(header->version())) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), @@ -1050,7 +1034,7 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } break; case QUICPacketType::RETRY: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::CLEARTEXT)) { + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::CLEARTEXT, false)) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), QUICKeyPhase::CLEARTEXT)) { @@ -1065,10 +1049,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } break; case QUICPacketType::HANDSHAKE: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::CLEARTEXT)) { + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::HANDSHAKE, false)) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::CLEARTEXT)) { + QUICKeyPhase::HANDSHAKE)) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -1078,7 +1062,7 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } break; case QUICPacketType::ZERO_RTT_PROTECTED: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::ZERORTT)) { + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::ZERORTT, false)) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), QUICKeyPhase::ZERORTT)) { diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index b5b58b96e7f..47db795b747 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -54,12 +54,12 @@ QUICTLS::is_ready_to_derive() const } bool -QUICTLS::is_key_derived(QUICKeyPhase key_phase) const +QUICTLS::is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const { if (key_phase == QUICKeyPhase::ZERORTT) { return this->_client_pp->get_key(QUICKeyPhase::ZERORTT); } else { - return this->_client_pp->get_key(key_phase) && this->_server_pp->get_key(key_phase); + return this->_get_km(key_phase, for_encryption); } } diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 3ae8caa3986..c070cbbd7c0 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -48,7 +48,7 @@ class QUICTLS : public QUICHandshakeProtocol int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) override; bool is_handshake_finished() const override; bool is_ready_to_derive() const override; - bool is_key_derived(QUICKeyPhase key_phase) const override; + bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const override; int initialize_key_materials(QUICConnectionId cid) override; int update_key_materials() override; void update_key_materials_on_key_cb(std::unique_ptr km, int name); diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 33a159fed0f..cc707b919f0 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -104,6 +104,25 @@ QUICTypeUtil::packet_type(QUICEncryptionLevel level) } } +// TODO: clarify QUICKeyPhase and QUICEncryptionlevel mapping +QUICKeyPhase +QUICTypeUtil::key_phase(QUICPacketType type) +{ + switch (type) { + case QUICPacketType::INITIAL: + return QUICKeyPhase::CLEARTEXT; + case QUICPacketType::ZERO_RTT_PROTECTED: + return QUICKeyPhase::ZERORTT; + case QUICPacketType::HANDSHAKE: + return QUICKeyPhase::HANDSHAKE; + case QUICPacketType::PROTECTED: + // XXX assuming Long Header Packet + return QUICKeyPhase::PHASE_0; + default: + return QUICKeyPhase::CLEARTEXT; + } +} + QUICConnectionId QUICTypeUtil::read_QUICConnectionId(const uint8_t *buf, uint8_t len) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index c61abc46582..006e1e936ad 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -333,6 +333,7 @@ class QUICTypeUtil [[deprecated]] static QUICStreamType detect_stream_type(QUICStreamId id); static QUICEncryptionLevel encryption_level(QUICPacketType type); static QUICPacketType packet_type(QUICEncryptionLevel level); + static QUICKeyPhase key_phase(QUICPacketType type); static QUICConnectionId read_QUICConnectionId(const uint8_t *buf, uint8_t n); static int read_QUICPacketNumberLen(const uint8_t *buf); From 6f52da485ef6eb995f41035d89848a8ef807d64b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 23 Jul 2018 10:38:28 +0900 Subject: [PATCH 0706/1313] [draft-13] Update QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID --- iocore/net/quic/QUICTransportParameters.h | 2 +- iocore/net/quic/QUICTypes.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 3c5aa65718c..cc2839aeb3c 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -163,7 +163,7 @@ class QUICTransportParametersInNewSessionTicket : public QUICTransportParameters class QUICTransportParametersHandler { public: - static constexpr int TRANSPORT_PARAMETER_ID = 26; + static constexpr int TRANSPORT_PARAMETER_ID = 0xffa5; static int add(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char **out, size_t *outlen, X509 *x, size_t chainidx, int *al, void *add_arg); diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 006e1e936ad..762b276ef5e 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -44,8 +44,8 @@ using QUICStreamId = uint64_t; using QUICOffset = uint64_t; // TODO: Update version number -// Note: You also need to update tests for VersionNegotiationPacket creation, if you change the number of versions -// Prefix for drafts (0xff000000) + draft number +// Note: Prefix for drafts (0xff000000) + draft number +// Note: Change ExtensionType (QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID) if it's changed constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { 0xff00000d, }; From 3247788fe7a34f15f4f45c3842fd71c0d5bcde1a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 23 Jul 2018 10:49:41 +0900 Subject: [PATCH 0707/1313] Cleanup debug logs around quic_crypto --- iocore/net/quic/QUICDebugNames.h | 4 +- iocore/net/quic/QUICKeyGenerator.cc | 6 +-- iocore/net/quic/QUICTLS.cc | 12 ++--- iocore/net/quic/QUICTLS_openssl.cc | 74 +++++++++++++++++++++++++++-- src/traffic_quic/quic_client.h | 2 +- 5 files changed, 81 insertions(+), 17 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index a117805e7a2..23222998ad7 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -51,8 +51,8 @@ class QUICDebug for (int i = 0; i < in_len; ++i) { int u4 = in[i] / 16; int l4 = in[i] % 16; - out[i * 2] = (u4 < 10) ? ('0' + u4) : ('A' + u4 - 10); - out[i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('A' + l4 - 10); + out[i * 2] = (u4 < 10) ? ('0' + u4) : ('a' + u4 - 10); + out[i * 2 + 1] = (l4 < 10) ? ('0' + l4) : ('a' + l4 - 10); } out[in_len * 2] = 0; } diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 228633ab01c..32f526723ac 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -63,7 +63,7 @@ QUICKeyGenerator::generate(QUICConnectionId cid) if (is_debug_tag_set("vv_quic_crypto")) { uint8_t print_buf[512]; QUICDebug::to_hex(print_buf, secret, secret_len); - Debug("vv_quic_crypto", "client in secret 0x%s", print_buf); + Debug("vv_quic_crypto", "client_in_secret=%s", print_buf); } break; @@ -73,7 +73,7 @@ QUICKeyGenerator::generate(QUICConnectionId cid) if (is_debug_tag_set("vv_quic_crypto")) { uint8_t print_buf[512]; QUICDebug::to_hex(print_buf, secret, secret_len); - Debug("vv_quic_crypto", "server in secret 0x%s", print_buf); + Debug("vv_quic_crypto", "server_in_secret=%s", print_buf); } break; @@ -162,7 +162,7 @@ QUICKeyGenerator::_generate_cleartext_secret(uint8_t *out, size_t *out_len, QUIC if (is_debug_tag_set("vv_quic_crypto")) { uint8_t print_buf[512]; QUICDebug::to_hex(print_buf, cleartext_secret, cleartext_secret_len); - Debug("vv_quic_crypto", "initial secret 0x%s", print_buf); + Debug("vv_quic_crypto", "initial_secret=%s", print_buf); } hkdf.expand(out, out_len, cleartext_secret, cleartext_secret_len, reinterpret_cast(label), label_len, length); diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 47db795b747..24a14fc2195 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -75,11 +75,11 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) if (is_debug_tag_set("vv_quic_crypto")) { uint8_t print_buf[512]; QUICDebug::to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "client key 0x%s", print_buf); + Debug("vv_quic_crypto", "key=%s", print_buf); QUICDebug::to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "client iv 0x%s", print_buf); + Debug("vv_quic_crypto", "iv=%s", print_buf); QUICDebug::to_hex(print_buf, km->pn, km->pn_len); - Debug("vv_quic_crypto", "client pn 0x%s", print_buf); + Debug("vv_quic_crypto", "pn=%s", print_buf); } this->_client_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); @@ -88,11 +88,11 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) if (is_debug_tag_set("vv_quic_crypto")) { uint8_t print_buf[512]; QUICDebug::to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "server key 0x%s", print_buf); + Debug("vv_quic_crypto", "key=%s", print_buf); QUICDebug::to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "server iv 0x%s", print_buf); + Debug("vv_quic_crypto", "iv=%s", print_buf); QUICDebug::to_hex(print_buf, km->pn, km->pn_len); - Debug("vv_quic_crypto", "server pn 0x%s", print_buf); + Debug("vv_quic_crypto", "pn=%s", print_buf); } this->_server_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 4cc31066dd9..e5780e5de5a 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -32,15 +32,79 @@ static constexpr char tag[] = "quic_tls"; +static const char * +content_type_str(int type) +{ + switch (type) { + case SSL3_RT_CHANGE_CIPHER_SPEC: + return "SSL3_RT_CHANGE_CIPHER_SPEC"; + case SSL3_RT_ALERT: + return "SSL3_RT_ALERT 21"; + case SSL3_RT_HANDSHAKE: + return "SSL3_RT_HANDSHAKE"; + case SSL3_RT_APPLICATION_DATA: + return "SSL3_RT_APPLICATION_DATA"; + case SSL3_RT_HEADER: + // The buf contains the record header bytes only + return "SSL3_RT_HEADER"; + case SSL3_RT_INNER_CONTENT_TYPE: + // Used when an encrypted TLSv1.3 record is sent or received. In encrypted TLSv1.3 records the content type in the record header + // is always SSL3_RT_APPLICATION_DATA. The real content type for the record is contained in an "inner" content type. buf + // contains the encoded "inner" content type byte. + return "SSL3_RT_INNER_CONTENT_TYPE"; + default: + return "UNKNOWN"; + } +} + +static const char * +hs_type_str(int type) +{ + switch (type) { + case SSL3_MT_CLIENT_HELLO: + return "SSL3_MT_CLIENT_HELLO"; + case SSL3_MT_SERVER_HELLO: + return "SSL3_MT_SERVER_HELLO"; + case SSL3_MT_NEWSESSION_TICKET: + return "SSL3_MT_NEWSESSION_TICKET"; + case SSL3_MT_END_OF_EARLY_DATA: + return "SSL3_MT_END_OF_EARLY_DATA"; + case SSL3_MT_ENCRYPTED_EXTENSIONS: + return "SSL3_MT_ENCRYPTED_EXTENSIONS"; + case SSL3_MT_CERTIFICATE: + return "SSL3_MT_CERTIFICATE"; + case SSL3_MT_CERTIFICATE_VERIFY: + return "SSL3_MT_CERTIFICATE_VERIFY"; + case SSL3_MT_FINISHED: + return "SSL3_MT_FINISHED"; + case SSL3_MT_KEY_UPDATE: + return "SSL3_MT_KEY_UPDATE"; + case SSL3_MT_MESSAGE_HASH: + return "SSL3_MT_MESSAGE_HASH"; + default: + return "UNKNOWN"; + } +} + static void msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg) { + // Debug for reading + if (write_p == 0 && (content_type == SSL3_RT_HANDSHAKE || content_type == SSL3_RT_ALERT)) { + const uint8_t *tmp = reinterpret_cast(buf); + int msg_type = tmp[0]; + + Debug("v_quic_crypto", "%s (%d), %s (%d)", content_type_str(content_type), content_type, hs_type_str(msg_type), msg_type); + return; + } + if (!write_p || !arg || version != TLS1_3_VERSION || (content_type != SSL3_RT_HANDSHAKE && content_type != SSL3_RT_ALERT)) { return; } - const uint8_t *tmp = reinterpret_cast(buf); - int msg_type = tmp[0]; + const uint8_t *tmp = reinterpret_cast(buf); + int msg_type = tmp[0]; + QUICEncryptionLevel level = QUICTLS::get_encryption_level(msg_type); int index = static_cast(level); int next_index = index + 1; @@ -104,11 +168,11 @@ key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, const uint8_t print_buf[512]; QUICDebug::to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "key 0x%s", print_buf); + Debug("vv_quic_crypto", "key=%s", print_buf); QUICDebug::to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "iv 0x%s", print_buf); + Debug("vv_quic_crypto", "iv=%s", print_buf); QUICDebug::to_hex(print_buf, km->pn, km->pn_len); - Debug("vv_quic_crypto", "pn 0x%s", print_buf); + Debug("vv_quic_crypto", "pn=%s", print_buf); } qtls->update_key_materials_on_key_cb(std::move(km), name); diff --git a/src/traffic_quic/quic_client.h b/src/traffic_quic/quic_client.h index 9cd7573c688..384acac658d 100644 --- a/src/traffic_quic/quic_client.h +++ b/src/traffic_quic/quic_client.h @@ -36,7 +36,7 @@ struct QUICClientConfig { char output[1024] = {0}; char port[16] = "4433"; char path[1018] = "/"; - char debug_tags[1024] = "quic"; + char debug_tags[1024] = "quic|vv_quic_crypto"; int close = false; }; From a75c3eb59feff87f9f70d0fa43fa970484f11ec0 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 23 Jul 2018 11:01:31 +0900 Subject: [PATCH 0708/1313] Check remot transport parameters existence --- iocore/net/QUICNetVConnection.cc | 8 ++++++++ iocore/net/quic/QUICHandshake.cc | 6 ++++++ iocore/net/quic/QUICHandshake.h | 1 + 3 files changed, 15 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 9a1c3827007..6584b9d6bd5 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -900,6 +900,10 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe // 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(std::move(packet)); + + if (!this->_handshake_handler->has_remote_tp()) { + error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR)); + } } } else { // on client side, _handshake_handler is already started. Just process packet like _state_handshake_process_handshake_packet() @@ -1648,6 +1652,10 @@ QUICNetVConnection::_complete_handshake_if_possible() return -1; } + if (this->netvc_context == NET_VCONNECTION_OUT && !this->_handshake_handler->has_remote_tp()) { + return -1; + } + this->_init_flow_control_params(this->_handshake_handler->local_transport_parameters(), this->_handshake_handler->remote_transport_parameters()); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 7fe089aa3e8..53862fd993d 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -198,6 +198,12 @@ QUICHandshake::is_stateless_retry_enabled() const return this->_stateless_retry; } +bool +QUICHandshake::has_remote_tp() const +{ + return this->_remote_transport_parameters != nullptr; +} + QUICHandshakeProtocol * QUICHandshake::protocol() { diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 09bd39cce93..4d1ea43a087 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -74,6 +74,7 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator bool is_version_negotiated() const; bool is_completed() const; bool is_stateless_retry_enabled() const; + bool has_remote_tp() const; void set_transport_parameters(std::shared_ptr tp); void set_transport_parameters(std::shared_ptr tp); From 6c17894c9db2e1882e1a9cfc9d12e024bc0d0085 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 23 Jul 2018 12:19:08 +0900 Subject: [PATCH 0709/1313] Check buffer length before reading QUICVariableInt --- iocore/net/quic/QUICPacket.cc | 5 +++- iocore/net/quic/QUICPacketReceiveQueue.cc | 35 ++++++++++++++++------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index b54d8b634b4..9c3da981bd1 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -280,6 +280,10 @@ QUICPacketLongHeader::token_length(size_t &token_length, uint8_t *field_len, con return false; } + if (offset > packet_len) { + return false; + } + token_length = QUICIntUtil::read_QUICVariableInt(packet + offset); if (field_len) { *field_len = QUICVariableInt::size(packet + offset); @@ -308,7 +312,6 @@ QUICPacketLongHeader::length(size_t &length, uint8_t *field_len, const uint8_t * return false; } length = QUICIntUtil::read_QUICVariableInt(packet + length_offset); - if (field_len) { *field_len = QUICVariableInt::size(packet + length_offset); } diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 62204f4e3c1..5dfa346e61b 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -35,8 +35,8 @@ is_vn(QUICVersion v) return v == 0x0; } -static size_t -long_hdr_pkt_len(uint8_t *buf, size_t len) +static bool +long_hdr_pkt_len(size_t &pkt_len, uint8_t *buf, size_t len) { uint8_t dcil, scil; QUICPacketLongHeader::dcil(dcil, buf, len); @@ -45,15 +45,21 @@ long_hdr_pkt_len(uint8_t *buf, size_t len) size_t offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil; // token_length and token_length_field_len should be 0 except INITIAL packet - size_t token_length; - uint8_t token_length_field_len; - QUICPacketLongHeader::token_length(token_length, &token_length_field_len, buf, len); + size_t token_length = 0; + uint8_t token_length_field_len = 0; + if (!QUICPacketLongHeader::token_length(token_length, &token_length_field_len, buf, len)) { + return false; + } + + size_t length = 0; + uint8_t length_field_len = 0; + if (!QUICPacketLongHeader::length(length, &length_field_len, buf, len)) { + return false; + } - size_t length; - uint8_t length_field_len; - QUICPacketLongHeader::length(length, &length_field_len, buf, len); + pkt_len = offset + token_length + token_length_field_len + length_field_len + length; - return offset + token_length + token_length_field_len + length_field_len + length; + return true; } QUICPacketReceiveQueue::QUICPacketReceiveQueue(QUICPacketFactory &packet_factory, QUICPacketNumberProtector &pn_protector) @@ -113,7 +119,16 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) result = QUICPacketCreationResult::UNSUPPORTED; pkt_len = remaining_len; } else { - pkt_len = long_hdr_pkt_len(this->_payload.get() + this->_offset, remaining_len); + if (!long_hdr_pkt_len(pkt_len, this->_payload.get() + this->_offset, remaining_len)) { + this->_payload.release(); + this->_payload = nullptr; + this->_payload_len = 0; + this->_offset = 0; + + result = QUICPacketCreationResult::IGNORED; + + return quic_packet; + } } } else { pkt_len = remaining_len; From e523c076588e7632869f6493dbde37e8467d8194 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 23 Jul 2018 15:25:54 +0900 Subject: [PATCH 0710/1313] Fix dcid of INITIAL packet from server --- iocore/net/QUICNetVConnection.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6584b9d6bd5..a65fa2056a1 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1437,24 +1437,30 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); switch (type) { - case QUICPacketType::INITIAL: - packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->_quic_connection_id, - this->largest_acked_packet_number(), std::move(buf), len); + case QUICPacketType::INITIAL: { + QUICConnectionId dcid = + (this->netvc_context == NET_VCONNECTION_OUT) ? this->_original_quic_connection_id : this->_peer_quic_connection_id; + packet = this->_packet_factory.create_initial_packet(dcid, this->_quic_connection_id, this->largest_acked_packet_number(), + std::move(buf), len); break; - case QUICPacketType::RETRY: + } + case QUICPacketType::RETRY: { // Echo "_largest_received_packet_number" as packet number. Probably this is the packet number from triggering client packet. packet = this->_packet_factory.create_retry_packet(this->_peer_quic_connection_id, this->_quic_connection_id, std::move(buf), len, retransmittable); break; - case QUICPacketType::HANDSHAKE: + } + case QUICPacketType::HANDSHAKE: { packet = this->_packet_factory.create_handshake_packet(this->_peer_quic_connection_id, this->_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); break; - case QUICPacketType::PROTECTED: + } + case QUICPacketType::PROTECTED: { packet = this->_packet_factory.create_server_protected_packet( this->_peer_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); break; + } default: // should not be here except zero_rtt ink_assert(false); From 85924fdc2d21a1a9569e8995357b951c5b5262bd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 23 Jul 2018 15:46:05 +0900 Subject: [PATCH 0711/1313] Cleanup: remove QUICStreamType::HANDSHAKE --- iocore/net/quic/QUICTypes.cc | 8 ++------ iocore/net/quic/QUICTypes.h | 3 +-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index cc707b919f0..8ff98c16ea8 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -60,12 +60,8 @@ QUICTypeUtil::is_supported_version(QUICVersion version) QUICStreamType QUICTypeUtil::detect_stream_type(QUICStreamId id) { - if (id == 0) { - return QUICStreamType::HANDSHAKE; - } else { - uint8_t type = (id & 0x03); - return static_cast(type); - } + uint8_t type = (id & 0x03); + return static_cast(type); } QUICEncryptionLevel diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 762b276ef5e..936069c37a6 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -305,7 +305,6 @@ enum class QUICStreamType : uint8_t { SERVER_BIDI, CLIENT_UNI, SERVER_UNI, - HANDSHAKE, }; class QUICFiveTuple @@ -330,7 +329,7 @@ class QUICTypeUtil { public: static bool is_supported_version(QUICVersion version); - [[deprecated]] static QUICStreamType detect_stream_type(QUICStreamId id); + static QUICStreamType detect_stream_type(QUICStreamId id); static QUICEncryptionLevel encryption_level(QUICPacketType type); static QUICPacketType packet_type(QUICEncryptionLevel level); static QUICKeyPhase key_phase(QUICPacketType type); From 120216a41ab37b21f891d8cc64cece75435bf190 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 23 Jul 2018 15:46:26 +0900 Subject: [PATCH 0712/1313] Cleanup: remove QUICHandshakeMsgType --- iocore/net/quic/QUICTypes.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 936069c37a6..46eff4799f8 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -51,14 +51,6 @@ constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { }; constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; -// [[deprecated]] -enum class QUICHandshakeMsgType { - NONE = 0, - INITIAL, - RETRY, - HANDSHAKE, -}; - enum class QUICEncryptionLevel { NONE = -1, INITIAL = 0, From 930a6393c71121ae2e923e6dad1720b8455a6e4d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 23 Jul 2018 15:50:26 +0900 Subject: [PATCH 0713/1313] Add debug prints on receiving and transmiting packets --- iocore/net/QUICNetVConnection.cc | 8 ++++++-- iocore/net/quic/QUICPacket.cc | 15 +++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a65fa2056a1..c2296774454 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1096,8 +1096,12 @@ QUICNetVConnection::_state_common_send_packet() udp_payload->fill(len); written += len; + // TODO: Avoid static function. We don't need to parse buffer again. Get packet number offset from packet. QUICPacket::protect_packet_number(buf, len, &this->_pn_protector, this->_peer_quic_connection_id.length()); + QUICConDebug("[TX] %s packet #%" PRIu64 " size=%zu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), + len); + this->_loss_detector->on_packet_sent(std::move(packet)); packet_count++; } @@ -1551,9 +1555,9 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) break; case QUICPacketCreationResult::SUCCESS: if (packet->type() == QUICPacketType::VERSION_NEGOTIATION) { - QUICConDebug("Dequeue %s size=%u", QUICDebugNames::packet_type(packet->type()), packet->size()); + QUICConDebug("[RX] %s packet size=%u", QUICDebugNames::packet_type(packet->type()), packet->size()); } else { - QUICConDebug("Dequeue %s packet #%" PRIu64 " size=%u", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), + QUICConDebug("[RX] %s packet #%" PRIu64 " size=%u", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), packet->size()); } break; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 9c3da981bd1..972beb795bf 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -31,11 +31,14 @@ #include "QUICConfig.h" using namespace std::literals; -static constexpr std::string_view tag = "quic_packet"sv; -static constexpr uint64_t aead_tag_len = 16; +static constexpr std::string_view tag = "quic_packet"sv; +static constexpr std::string_view tag_v = "v_quic_crypto"sv; +static constexpr uint64_t aead_tag_len = 16; #define QUICDebug(dcid, scid, fmt, ...) \ Debug(tag.data(), "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__); +#define QUICVDebug(dcid, scid, fmt, ...) \ + Debug(tag_v.data(), "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__); ClassAllocator quicPacketAllocator("quicPacketAllocator"); ClassAllocator quicPacketLongHeaderAllocator("quicPacketLongHeaderAllocator"); @@ -983,8 +986,8 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP QUICConnectionId dcid = header->destination_cid(); QUICConnectionId scid = header->source_cid(); - QUICDebug(scid, dcid, "Decrypting %s packet #%" PRIu64 " using %s", QUICDebugNames::packet_type(header->type()), - header->packet_number(), QUICDebugNames::key_phase(header->key_phase())); + 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) { @@ -1201,8 +1204,8 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool re QUICConnectionId dcid = header->destination_cid(); QUICConnectionId scid = header->source_cid(); - QUICDebug(dcid, scid, "Encrypting %s packet #%" PRIu64 " using %s", QUICDebugNames::packet_type(header->type()), - header->packet_number(), QUICDebugNames::key_phase(header->key_phase())); + 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; if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), From 82d3d6b44d9f63fdec3315ecbe02e39fb021c83d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 24 Jul 2018 14:19:06 +0900 Subject: [PATCH 0714/1313] Support 0-RTT with draft-13 --- iocore/net/quic/QUICAckFrameCreator.cc | 18 ++++++++++-------- iocore/net/quic/QUICAckFrameCreator.h | 4 +++- iocore/net/quic/QUICPacket.cc | 11 +++++++---- iocore/net/quic/QUICPacket.h | 3 ++- iocore/net/quic/QUICStreamManager.cc | 10 ++++++++++ iocore/net/quic/QUICTLS_openssl.cc | 18 +++++------------- iocore/net/quic/QUICTypes.cc | 11 +++++++++++ iocore/net/quic/QUICTypes.h | 4 +++- 8 files changed, 51 insertions(+), 28 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 84e1b282e3b..77be5628343 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -32,7 +32,7 @@ QUICAckFrameCreator::update(QUICEncryptionLevel level, QUICPacketNumber packet_n return 0; } - int index = static_cast(level); + int index = QUICTypeUtil::pn_space_index(level); QUICAckPacketNumbers *packet_numbers = &this->_packet_numbers[index]; packet_numbers->push_back(packet_number); @@ -56,12 +56,11 @@ QUICAckFrameCreator::_create_frame(QUICEncryptionLevel level) { QUICFrameUPtr ack_frame = QUICFrameFactory::create_null_frame(); - if (!this->_is_level_matched(level)) { + if (!this->_is_level_matched(level) || level == QUICEncryptionLevel::ZERO_RTT) { return ack_frame; } - int index = static_cast(level); - + int index = QUICTypeUtil::pn_space_index(level); if (this->_can_send[index]) { QUICAckPacketNumbers *packet_numbers = &this->_packet_numbers[index]; @@ -77,7 +76,7 @@ QUICAckFrameCreator::_create_frame(QUICEncryptionLevel level) QUICFrameUPtr QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) { - int index = static_cast(level); + int index = QUICTypeUtil::pn_space_index(level); QUICAckPacketNumbers *packet_numbers = &this->_packet_numbers[index]; this->_should_send[index] = false; @@ -128,11 +127,13 @@ QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) bool QUICAckFrameCreator::will_generate_frame(QUICEncryptionLevel level) { - if (!this->_is_level_matched(level)) { + // No ACK frame on ZERO_RTT level + if (!this->_is_level_matched(level) || level == QUICEncryptionLevel::ZERO_RTT) { return false; } - return this->_should_send[static_cast(level)]; + int index = QUICTypeUtil::pn_space_index(level); + return this->_should_send[index]; } QUICFrameUPtr @@ -147,7 +148,8 @@ QUICAckFrameCreator::_calculate_delay(QUICEncryptionLevel level) { // Ack delay is in microseconds and scaled ink_hrtime now = Thread::get_hrtime(); - uint64_t delay = (now - this->_packet_numbers[static_cast(level)].largest_ack_received_time()) / 1000; + int index = QUICTypeUtil::pn_space_index(level); + uint64_t delay = (now - this->_packet_numbers[index].largest_ack_received_time()) / 1000; // FXIME ack delay exponent has to be read from transport parameters uint8_t ack_delay_exponent = 3; return delay >> ack_delay_exponent; diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index c78a46302a1..4b69fcbc4b4 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -87,6 +87,7 @@ class QUICAckFrameCreator : public QUICFrameGenerator { return { QUICEncryptionLevel::INITIAL, + QUICEncryptionLevel::ZERO_RTT, QUICEncryptionLevel::HANDSHAKE, QUICEncryptionLevel::ONE_RTT, }; @@ -95,5 +96,6 @@ class QUICAckFrameCreator : public QUICFrameGenerator bool _can_send[4] = {false}; bool _should_send[4] = {false}; - QUICAckPacketNumbers _packet_numbers[4]; + // Initial, 0/1-RTT, and Handshake + QUICAckPacketNumbers _packet_numbers[3]; }; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 972beb795bf..85ab28b33ac 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -937,7 +937,7 @@ QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, const QU return false; } - Debug(tag.data(), "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), + Debug("v_quic_crypto", "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), QUICDebugNames::key_phase(phase)); } else { @@ -1119,7 +1119,8 @@ QUICPacketUPtr QUICPacketFactory::create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len) { - QUICPacketNumber pn = this->_packet_number_generator[static_cast(QUICEncryptionLevel::INITIAL)].next(); + int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); + QUICPacketNumber pn = this->_packet_number_generator[index].next(); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::CLEARTEXT, destination_cid, source_cid, pn, base_packet_number, this->_version, std::move(payload), len); @@ -1140,7 +1141,8 @@ QUICPacketFactory::create_handshake_packet(QUICConnectionId destination_cid, QUI QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - QUICPacketNumber pn = this->_packet_number_generator[static_cast(QUICEncryptionLevel::HANDSHAKE)].next(); + int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::HANDSHAKE); + QUICPacketNumber pn = this->_packet_number_generator[index].next(); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, QUICKeyPhase::HANDSHAKE, destination_cid, source_cid, pn, base_packet_number, this->_version, std::move(payload), len); @@ -1151,7 +1153,8 @@ QUICPacketUPtr QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable) { - QUICPacketNumber pn = this->_packet_number_generator[static_cast(QUICEncryptionLevel::ONE_RTT)].next(); + int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ONE_RTT); + QUICPacketNumber pn = this->_packet_number_generator[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); diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index c7788d8f931..ddb6a5720dd 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -405,7 +405,8 @@ class QUICPacketFactory private: QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; QUICHandshakeProtocol *_hs_protocol = nullptr; - QUICPacketNumberGenerator _packet_number_generator[4]; + // 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 retransmittable); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 214449cbfab..fa8f63734b8 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -345,6 +345,11 @@ QUICStreamManager::will_generate_frame(QUICEncryptionLevel level) return false; } + // workaround fix until support 0-RTT on client + if (level == QUICEncryptionLevel::ZERO_RTT) { + return false; + } + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { if (s->will_generate_frame(level)) { return true; @@ -364,6 +369,11 @@ QUICStreamManager::generate_frame(QUICEncryptionLevel level, uint64_t connection return frame; } + // workaround fix until support 0-RTT on client + if (level == QUICEncryptionLevel::ZERO_RTT) { + return frame; + } + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { frame = s->generate_frame(level, connection_credit, maximum_frame_size); if (frame) { diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index e5780e5de5a..ff65f4f5c39 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -272,19 +272,11 @@ QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) SSL_set_bio(this->_ssl, rbio, wbio); if (this->_netvc_context == NET_VCONNECTION_IN) { - // TODO: early data - // if (!this->_early_data_processed) { - // if (this->_read_early_data()) { - // this->_early_data_processed = true; - // } - // if (SSL_early_data_accepted(this->_ssl)) { - // Debug(tag, "Early data processed"); - - // if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT)) { - // this->_generate_0rtt_key(); - // } - // } - // } + if (!this->_early_data_processed) { + if (this->_read_early_data()) { + this->_early_data_processed = true; + } + } ret = SSL_accept(this->_ssl); } else { diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 8ff98c16ea8..48c5f352c9d 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -119,6 +119,17 @@ QUICTypeUtil::key_phase(QUICPacketType type) } } +// 0-RTT and 1-RTT use same PN Space +int +QUICTypeUtil::pn_space_index(QUICEncryptionLevel level) +{ + if (level == QUICEncryptionLevel::ONE_RTT) { + level = QUICEncryptionLevel::ZERO_RTT; + } + + return static_cast(level); +} + QUICConnectionId QUICTypeUtil::read_QUICConnectionId(const uint8_t *buf, uint8_t len) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 46eff4799f8..183b5d8a214 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -59,11 +59,12 @@ enum class QUICEncryptionLevel { ONE_RTT = 3, }; -// For range-based for loop. This starts from INITIAL to ONE_RTT. It doesn't include NONE nor ZERO_RTT. +// For range-based for loop. This starts from INITIAL to ONE_RTT. It doesn't include NONE. // Defining begin, end, operator*, operator++ doen't work for duplicate symbol issue with libmgmt_p.a :( // TODO: support ZERO_RTT constexpr QUICEncryptionLevel QUIC_ENCRYPTION_LEVELS[] = { QUICEncryptionLevel::INITIAL, + QUICEncryptionLevel::ZERO_RTT, QUICEncryptionLevel::HANDSHAKE, QUICEncryptionLevel::ONE_RTT, }; @@ -325,6 +326,7 @@ class QUICTypeUtil static QUICEncryptionLevel encryption_level(QUICPacketType type); static QUICPacketType packet_type(QUICEncryptionLevel level); static QUICKeyPhase key_phase(QUICPacketType type); + static int pn_space_index(QUICEncryptionLevel level); static QUICConnectionId read_QUICConnectionId(const uint8_t *buf, uint8_t n); static int read_QUICPacketNumberLen(const uint8_t *buf); From e252c749ae263fef6f2dfa650c08b19dae9b6e0f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 24 Jul 2018 14:25:30 +0900 Subject: [PATCH 0715/1313] Divide _retransmission_frames for each encryption level --- iocore/net/quic/QUICPacketRetransmitter.cc | 25 +++++++++++++--------- iocore/net/quic/QUICPacketRetransmitter.h | 2 +- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 57e2be03f50..be5f8df164c 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -46,8 +46,9 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) case QUICFrameType::PATH_CHALLENGE: break; default: - frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); - this->_retransmission_frames.push(std::move(frame)); + frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); + int index = static_cast(QUICTypeUtil::encryption_level(packet.type())); + this->_retransmission_frames[index].push(std::move(frame)); break; } } @@ -56,24 +57,28 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) void QUICPacketRetransmitter::reset() { - while (!this->_retransmission_frames.empty()) { - this->_retransmission_frames.pop(); + for (auto level : QUIC_ENCRYPTION_LEVELS) { + int index = static_cast(level); + while (!this->_retransmission_frames[index].empty()) { + this->_retransmission_frames[index].pop(); + } } } bool QUICPacketRetransmitter::will_generate_frame(QUICEncryptionLevel level) { - return !this->_retransmission_frames.empty(); + return !this->_retransmission_frames[static_cast(level)].empty(); } QUICFrameUPtr QUICPacketRetransmitter::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - if (!this->_retransmission_frames.empty()) { - frame = std::move(this->_retransmission_frames.front()); - this->_retransmission_frames.pop(); + int index = static_cast(level); + if (!this->_retransmission_frames[index].empty()) { + frame = std::move(this->_retransmission_frames[index].front()); + this->_retransmission_frames[index].pop(); // maximum_frame_size is actually for payload size. So we should compare it // with data_length(). Howeever, because data_length() is STREAM frame @@ -90,10 +95,10 @@ QUICPacketRetransmitter::generate_frame(QUICEncryptionLevel level, uint64_t conn if (split) { auto new_frame = QUICFrameFactory::split_frame(frame.get(), maximum_frame_size); if (new_frame) { - this->_retransmission_frames.push(std::move(new_frame)); + this->_retransmission_frames[index].push(std::move(new_frame)); } else { // failed to split frame return nullptr - this->_retransmission_frames.push(std::move(frame)); + this->_retransmission_frames[index].push(std::move(frame)); frame = QUICFrameFactory::create_null_frame(); } } diff --git a/iocore/net/quic/QUICPacketRetransmitter.h b/iocore/net/quic/QUICPacketRetransmitter.h index d488fa2f6f0..93de7cf0f24 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.h +++ b/iocore/net/quic/QUICPacketRetransmitter.h @@ -39,5 +39,5 @@ class QUICPacketRetransmitter : public QUICFrameGenerator QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; private: - std::queue _retransmission_frames; + std::queue _retransmission_frames[4]; }; From 321380994940d513252b918f74a6f5dbb72e82e5 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 24 Jul 2018 14:26:55 +0900 Subject: [PATCH 0716/1313] Continue handshake when server reject 0-RTT --- iocore/net/quic/QUICPacketReceiveQueue.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 5dfa346e61b..fb09a870254 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -104,6 +104,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) ats_unique_buf pkt = {nullptr, [](void *p) { ats_free(p); }}; size_t pkt_len = 0; bool has_packet_number = true; + QUICPacketType type = QUICPacketType::UNINITIALIZED; if (QUICInvariants::is_long_header(this->_payload.get())) { uint8_t *buf = this->_payload.get() + this->_offset; @@ -115,10 +116,12 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) if (is_vn(version)) { has_packet_number = false; pkt_len = remaining_len; + type = QUICPacketType::VERSION_NEGOTIATION; } else if (!QUICTypeUtil::is_supported_version(version)) { result = QUICPacketCreationResult::UNSUPPORTED; pkt_len = remaining_len; } else { + QUICPacketLongHeader::type(type, this->_payload.get() + this->_offset, remaining_len); if (!long_hdr_pkt_len(pkt_len, this->_payload.get() + this->_offset, remaining_len)) { this->_payload.release(); this->_payload = nullptr; @@ -158,13 +161,19 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) this->_payload = nullptr; this->_payload_len = 0; this->_offset = 0; + type = QUICPacketType::PROTECTED; } // VN doesn't have Packet Number field if (!has_packet_number || QUICPacket::unprotect_packet_number(pkt.get(), pkt_len, &this->_pn_protector)) { quic_packet = this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->_largest_received_packet_number, result); } else { - result = QUICPacketCreationResult::FAILED; + // ZERO_RTT might be rejected + if (type == QUICPacketType::ZERO_RTT_PROTECTED) { + result = QUICPacketCreationResult::IGNORED; + } else { + result = QUICPacketCreationResult::FAILED; + } } if (udp_packet) { From 52024bae302d7e52f138908a86ab03e4630905cd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 24 Jul 2018 14:28:04 +0900 Subject: [PATCH 0717/1313] Fix key_callback for custom OpenSSL --- iocore/net/quic/QUICTLS_openssl.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index ff65f4f5c39..3d48123803e 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -126,13 +126,13 @@ msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, return; } -static void +static int key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, const unsigned char *key, size_t key_len, const unsigned char *iv, size_t iv_len, void *arg) { QUICTLS *qtls = reinterpret_cast(arg); if (qtls == nullptr) { - return; + return 0; } std::unique_ptr km = std::make_unique(); @@ -177,7 +177,7 @@ key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, const qtls->update_key_materials_on_key_cb(std::move(km), name); - return; + return 1; } void From 8e7a9c13470f1462ae073d317862cf4c7e1196a7 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 24 Jul 2018 14:41:50 +0900 Subject: [PATCH 0718/1313] Cleanup: fix debug messages --- iocore/net/quic/QUICFrame.cc | 12 ++++++------ iocore/net/quic/QUICTLS.cc | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 053f5af21dc..25ef619f5e9 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -80,7 +80,7 @@ QUICFrame::is_protected() const int QUICFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "type=%s size=%zu", QUICDebugNames::frame_type(this->type()), this->size()); + return snprintf(msg, msg_len, "| %s size=%zu", QUICDebugNames::frame_type(this->type()), this->size()); } QUICFrame * @@ -170,7 +170,7 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, size_t limit) const int QUICStreamFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "type=STREAM size=%zu id=%" PRIu64 " offset=%" PRIu64 " data_len=%" PRIu64 " fin=%d", this->size(), + return snprintf(msg, msg_len, "| STREAM size=%zu id=%" PRIu64 " offset=%" PRIu64 " data_len=%" PRIu64 " fin=%d", this->size(), this->stream_id(), this->offset(), this->data_length(), this->has_fin_flag()); } @@ -444,7 +444,7 @@ QUICCryptoFrame::size() const int QUICCryptoFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "type=CRYPTO size=%zu offset=%" PRIu64 " data_len=%" PRIu64, this->size(), this->offset(), + return snprintf(msg, msg_len, "| CRYPTO size=%zu offset=%" PRIu64 " data_len=%" PRIu64, this->size(), this->offset(), this->data_length()); } @@ -639,8 +639,8 @@ QUICAckFrame::store(uint8_t *buf, size_t *len, size_t limit) const int QUICAckFrame::debug_msg(char *msg, size_t msg_len) const { - int len = snprintf(msg, msg_len, "type=ACK size=%zu largest_acked=%" PRIu64 " delay=%" PRIu64 " block_count=%" PRIu64, - this->size(), this->largest_acknowledged(), this->ack_delay(), this->ack_block_count()); + int len = snprintf(msg, msg_len, "| ACK size=%zu largest_acked=%" PRIu64 " delay=%" PRIu64 " block_count=%" PRIu64, this->size(), + this->largest_acknowledged(), this->ack_delay(), this->ack_block_count()); msg_len -= len; if (this->ack_block_section()) { @@ -2248,7 +2248,7 @@ QUICRetransmissionFrame::store(uint8_t *buf, size_t *len, size_t limit) const int QUICRetransmissionFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "type=%s size=%zu (retransmission)", QUICDebugNames::frame_type(this->type()), this->size()); + return snprintf(msg, msg_len, "| %s size=%zu (retransmission)", QUICDebugNames::frame_type(this->type()), this->size()); } QUICPacketType diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 24a14fc2195..4be979bbbfa 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -261,7 +261,7 @@ QUICTLS::encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint { const KeyMaterial *km = this->_get_km(phase, true); if (!km) { - Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); + Debug(tag, "Failed to encrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } @@ -279,7 +279,7 @@ QUICTLS::decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const { const KeyMaterial *km = this->_get_km(phase, false); if (!km) { - Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); + Debug(tag, "Failed to decrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } From 9a3606851ed1a66d1506c9ef40ca87416d82301b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 24 Jul 2018 15:28:35 +0900 Subject: [PATCH 0719/1313] Cleanup: remove dead code around key generation --- iocore/net/quic/QUICHandshake.cc | 9 -- iocore/net/quic/QUICKeyGenerator.cc | 96 +------------------ iocore/net/quic/QUICKeyGenerator.h | 21 +--- iocore/net/quic/QUICKeyGenerator_boringssl.cc | 2 +- iocore/net/quic/QUICKeyGenerator_openssl.cc | 17 ---- iocore/net/quic/QUICTLS.cc | 76 --------------- iocore/net/quic/QUICTLS_boringssl.cc | 13 +++ iocore/net/quic/QUICTLS_openssl.cc | 15 +++ 8 files changed, 37 insertions(+), 212 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 53862fd993d..a039226d50b 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -462,15 +462,6 @@ QUICHandshake::do_handshake() } } - // if (!this->_hs_protocol->is_key_derived(QUICKeyPhase::PHASE_0) && this->_hs_protocol->is_ready_to_derive()) { - // int res = this->_hs_protocol->update_key_materials(); - // if (res) { - // QUICHSDebug("Keying Materials are exported"); - // } else { - // QUICHSDebug("Failed to export Keying Materials"); - // } - // } - return result; } diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 32f526723ac..4ec4cba8ab9 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -38,9 +38,6 @@ constexpr static uint8_t QUIC_VERSION_1_SALT[] = { }; constexpr static std::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("client in"sv); constexpr static std::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("server in"sv); -constexpr static std::string_view LABEL_FOR_CLIENT_0RTT_SECRET("EXPORTER-QUIC 0rtt"sv); -constexpr static std::string_view LABEL_FOR_CLIENT_PP_SECRET("EXPORTER-QUIC client 1rtt"sv); -constexpr static std::string_view LABEL_FOR_SERVER_PP_SECRET("EXPORTER-QUIC server 1rtt"sv); constexpr static std::string_view LABEL_FOR_KEY("key"sv); constexpr static std::string_view LABEL_FOR_IV("iv"sv); constexpr static std::string_view LABEL_FOR_PN("pn"sv); @@ -84,61 +81,17 @@ QUICKeyGenerator::generate(QUICConnectionId cid) return km; } -std::unique_ptr -QUICKeyGenerator::generate_0rtt(SSL *ssl) -{ - std::unique_ptr km = std::make_unique(); - - const QUIC_EVP_CIPHER *cipher = this->_get_cipher_for_protected_packet(ssl); - const EVP_MD *md = _get_handshake_digest(ssl); - uint8_t secret[512]; - size_t secret_len = sizeof(secret); - QUICHKDF hkdf(md); - - this->_generate_0rtt_secret(secret, &secret_len, hkdf, ssl, EVP_MD_size(md)); - this->_generate(*km, hkdf, secret, secret_len, cipher); - - return km; -} - -std::unique_ptr -QUICKeyGenerator::generate(SSL *ssl) -{ - std::unique_ptr km = std::make_unique(); - - const QUIC_EVP_CIPHER *cipher = this->_get_cipher_for_protected_packet(ssl); - const EVP_MD *md = _get_handshake_digest(ssl); - uint8_t secret[512]; - size_t secret_len = sizeof(secret); - QUICHKDF hkdf(md); - - switch (this->_ctx) { - case Context::CLIENT: - this->_generate_pp_secret(secret, &secret_len, hkdf, ssl, LABEL_FOR_CLIENT_PP_SECRET.data(), - LABEL_FOR_CLIENT_PP_SECRET.length(), EVP_MD_size(md)); - break; - case Context::SERVER: - this->_generate_pp_secret(secret, &secret_len, hkdf, ssl, LABEL_FOR_SERVER_PP_SECRET.data(), - LABEL_FOR_SERVER_PP_SECRET.length(), EVP_MD_size(md)); - break; - } - - this->_generate(*km, hkdf, secret, secret_len, cipher); - - return km; -} - int QUICKeyGenerator::_generate(KeyMaterial &km, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher) { - // Generate a key and a IV - // key = QHKDF-Expand(S, "key", "", key_length) - // iv = QHKDF-Expand(S, "iv", "", iv_length) - // pn_key = QHKDF-Expand(S, "pn", pn_key_length) + // Generate key, iv, and pn_key + // key = HKDF-Expand-Label(S, "key", "", key_length) + // iv = HKDF-Expand-Label(S, "iv", "", iv_length) + // pn_key = HKDF-Expand-Label(S, "pn", "", pn_key_length) this->_generate_key(km.key, &km.key_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); this->_generate_iv(km.iv, &km.iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher)); - this->_generate_pn(km.pn, &km.pn_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); + QUICKeyGenerator::generate_pn(km.pn, &km.pn_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); return 0; } @@ -169,38 +122,6 @@ QUICKeyGenerator::_generate_cleartext_secret(uint8_t *out, size_t *out_len, QUIC return 0; } -int -QUICKeyGenerator::_generate_pp_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, SSL *ssl, const char *label, size_t label_len, - size_t length) -{ - *out_len = length; - if (this->_last_secret_len == 0) { - SSL_export_keying_material(ssl, out, *out_len, label, label_len, reinterpret_cast(""), 0, 1); - } else { - ink_assert(!"not implemented"); - } - - memcpy(this->_last_secret, out, *out_len); - this->_last_secret_len = *out_len; - - return 0; -} - -int -QUICKeyGenerator::_generate_0rtt_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, SSL *ssl, size_t length) -{ - *out_len = length; -#ifndef OPENSSL_IS_BORINGSSL - SSL_export_keying_material_early(ssl, out, *out_len, LABEL_FOR_CLIENT_0RTT_SECRET.data(), LABEL_FOR_CLIENT_0RTT_SECRET.length(), - reinterpret_cast(""), 0); -#else - SSL_export_early_keying_material(ssl, out, *out_len, LABEL_FOR_CLIENT_0RTT_SECRET.data(), LABEL_FOR_CLIENT_0RTT_SECRET.length(), - reinterpret_cast(""), 0); -#endif - - return 0; -} - int QUICKeyGenerator::_generate_key(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t key_length) const @@ -215,13 +136,6 @@ QUICKeyGenerator::_generate_iv(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, co return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_IV.data(), LABEL_FOR_IV.length(), iv_length); } -int -QUICKeyGenerator::_generate_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, - size_t pn_length) const -{ - return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_PN.data(), LABEL_FOR_PN.length(), pn_length); -} - int QUICKeyGenerator::generate_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t pn_length) diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index 5dcf1f81f84..4c6071cf376 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -56,22 +56,12 @@ class QUICKeyGenerator static int generate_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t pn_length); static const EVP_MD *get_handshake_digest(const SSL *ssl); - /* - * Gnerate a key and an IV for Cleartext + /** + * Generate keys for Initial encryption level + * The keys for the remaining encryption level are derived by TLS stack with "quic " prefix */ std::unique_ptr generate(QUICConnectionId cid); - /* - * Generate a key and an IV for Packet Protection - * - * On the first call, this generates a secret with the constatnt label and generate a key material with the secret. - * On the following call, this regenerates a new secret based on the last secret and genereate a new key material with the new - * secret. - */ - std::unique_ptr generate(SSL *ssl); - - std::unique_ptr generate_0rtt(SSL *ssl); - private: Context _ctx = Context::SERVER; @@ -81,16 +71,11 @@ class QUICKeyGenerator int _generate(KeyMaterial &km, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher); int _generate_cleartext_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid, const char *label, size_t label_len, size_t length); - int _generate_pp_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, SSL *ssl, const char *label, size_t label_len, - size_t length); - int _generate_0rtt_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, SSL *ssl, 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_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t pn_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_cleartext() const; const QUIC_EVP_CIPHER *_get_cipher_for_protected_packet(const SSL *ssl) const; - const EVP_MD *_get_handshake_digest(const SSL *ssl) const; }; diff --git a/iocore/net/quic/QUICKeyGenerator_boringssl.cc b/iocore/net/quic/QUICKeyGenerator_boringssl.cc index 22473281eb5..8df2ccb251f 100644 --- a/iocore/net/quic/QUICKeyGenerator_boringssl.cc +++ b/iocore/net/quic/QUICKeyGenerator_boringssl.cc @@ -60,7 +60,7 @@ QUICKeyGenerator::_get_cipher_for_protected_packet(const SSL *ssl) const // 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) const +QUICKeyGenerator::get_handshake_digest(const SSL *ssl) { switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { case TLS1_CK_AES_128_GCM_SHA256: diff --git a/iocore/net/quic/QUICKeyGenerator_openssl.cc b/iocore/net/quic/QUICKeyGenerator_openssl.cc index bdcae8d0d5e..ad3e5e76d6a 100644 --- a/iocore/net/quic/QUICKeyGenerator_openssl.cc +++ b/iocore/net/quic/QUICKeyGenerator_openssl.cc @@ -62,23 +62,6 @@ QUICKeyGenerator::_get_cipher_for_protected_packet(const SSL *ssl) const } } -const EVP_MD * -QUICKeyGenerator::_get_handshake_digest(const SSL *ssl) const -{ - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { - case TLS1_3_CK_AES_128_GCM_SHA256: - case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - case TLS1_3_CK_AES_128_CCM_SHA256: - case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_sha256(); - case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_sha384(); - default: - ink_assert(false); - return nullptr; - } -} - const EVP_MD * QUICKeyGenerator::get_handshake_digest(const SSL *ssl) { diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 4be979bbbfa..b4e6e3d0789 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -102,10 +102,6 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) int QUICTLS::update_key_materials() { - if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT)) { - this->_generate_0rtt_key(); - } - // Switch key phase QUICKeyPhase next_key_phase; switch (this->_client_pp->key_phase()) { @@ -115,43 +111,12 @@ QUICTLS::update_key_materials() case QUICKeyPhase::PHASE_1: next_key_phase = QUICKeyPhase::PHASE_0; break; - case QUICKeyPhase::CLEARTEXT: - next_key_phase = QUICKeyPhase::PHASE_0; - break; - case QUICKeyPhase::ZERORTT: - next_key_phase = QUICKeyPhase::PHASE_0; - break; default: Error("QUICKeyPhase value is undefined"); ink_assert(false); next_key_phase = QUICKeyPhase::PHASE_0; } - // Generate keys - Debug(tag, "Generating %s keys", QUICDebugNames::key_phase(next_key_phase)); - uint8_t print_buf[512]; - std::unique_ptr km; - km = this->_keygen_for_client.generate(this->_ssl); - if (is_debug_tag_set("vv_quic_crypto")) { - QUICDebug::to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "client key 0x%s", print_buf); - QUICDebug::to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "client iv 0x%s", print_buf); - QUICDebug::to_hex(print_buf, km->pn, km->pn_len); - Debug("vv_quic_crypto", "client pn 0x%s", print_buf); - } - this->_client_pp->set_key(std::move(km), next_key_phase); - km = this->_keygen_for_server.generate(this->_ssl); - if (is_debug_tag_set("vv_quic_crypto")) { - QUICDebug::to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "server key 0x%s", print_buf); - QUICDebug::to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "server iv 0x%s", print_buf); - QUICDebug::to_hex(print_buf, km->pn, km->pn_len); - Debug("vv_quic_crypto", "server pn 0x%s", print_buf); - } - this->_server_pp->set_key(std::move(km), next_key_phase); - return 1; } @@ -171,47 +136,6 @@ QUICTLS::_update_encryption_level(QUICEncryptionLevel level) return; } -int -QUICTLS::_read_early_data() -{ - uint8_t early_data[8]; - size_t early_data_len = 0; -#ifndef OPENSSL_IS_BORINGSSL - int ret = 0; - - do { - ERR_clear_error(); - ret = SSL_read_early_data(this->_ssl, early_data, sizeof(early_data), &early_data_len); - } while (ret == SSL_READ_EARLY_DATA_SUCCESS); - - return ret == SSL_READ_EARLY_DATA_FINISH ? 1 : 0; -#else - do { - ERR_clear_error(); - early_data_len = SSL_read(this->_ssl, early_data, sizeof(early_data)); - } while (SSL_in_early_data(this->_ssl)); - - return 1; -#endif -} - -void -QUICTLS::_generate_0rtt_key() -{ - // Generate key material for 0-RTT - Debug(tag, "Generating %s keys", QUICDebugNames::key_phase(QUICKeyPhase::ZERORTT)); - std::unique_ptr km; - km = this->_keygen_for_client.generate_0rtt(this->_ssl); - if (is_debug_tag_set("vv_quic_crypto")) { - uint8_t print_buf[512]; - QUICDebug::to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "0rtt key 0x%s", print_buf); - QUICDebug::to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "0rtt iv 0x%s", print_buf); - } - this->_client_pp->set_key(std::move(km), QUICKeyPhase::ZERORTT); -} - SSL * QUICTLS::ssl_handle() { diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc index dc4e34b4878..00416d45c90 100644 --- a/iocore/net/quic/QUICTLS_boringssl.cc +++ b/iocore/net/quic/QUICTLS_boringssl.cc @@ -49,6 +49,19 @@ QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) return 0; } +int +QUICTLS::_read_early_data() +{ + uint8_t early_data[8]; + size_t early_data_len = 0; + do { + ERR_clear_error(); + early_data_len = SSL_read(this->_ssl, early_data, sizeof(early_data)); + } while (SSL_in_early_data(this->_ssl)); + + return 1; +} + const EVP_AEAD * QUICTLS::_get_evp_aead(QUICKeyPhase phase) const { diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 3d48123803e..cf3e81b626b 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -301,6 +301,21 @@ QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) return 1; } +int +QUICTLS::_read_early_data() +{ + uint8_t early_data[8]; + size_t early_data_len = 0; + int ret = 0; + + do { + ERR_clear_error(); + ret = SSL_read_early_data(this->_ssl, early_data, sizeof(early_data), &early_data_len); + } while (ret == SSL_READ_EARLY_DATA_SUCCESS); + + return ret == SSL_READ_EARLY_DATA_FINISH ? 1 : 0; +} + const EVP_CIPHER * QUICTLS::_get_evp_aead(QUICKeyPhase phase) const { From f9923621031c9a8fa30082982b62f7719c5cf206 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 24 Jul 2018 15:56:33 +0900 Subject: [PATCH 0720/1313] Cleanup: rename "cleartext" to "initial" No logical changes - QUICKeyPhase::CLEARTEXT -> QUICKeyPhase::INITIAL - QUICKeyPhase::ZERORTT -> QUICKeyPhase::ZERO_RTT - _cleartext_key -> _initial_key - cleartext_secret -> initial_secret --- iocore/net/quic/QUICDebugNames.cc | 4 +-- iocore/net/quic/QUICHandshakeProtocol.cc | 12 ++++---- iocore/net/quic/QUICHandshakeProtocol.h | 4 +-- iocore/net/quic/QUICKeyGenerator.cc | 28 +++++++++---------- iocore/net/quic/QUICKeyGenerator.h | 8 ++---- iocore/net/quic/QUICKeyGenerator_boringssl.cc | 2 +- iocore/net/quic/QUICKeyGenerator_openssl.cc | 2 +- iocore/net/quic/QUICPacket.cc | 27 +++++++++--------- iocore/net/quic/QUICPacket.h | 2 +- iocore/net/quic/QUICTLS.cc | 10 +++---- iocore/net/quic/QUICTLS_boringssl.cc | 4 +-- iocore/net/quic/QUICTLS_openssl.cc | 8 +++--- iocore/net/quic/QUICTypes.cc | 6 ++-- iocore/net/quic/QUICTypes.h | 4 +-- .../quic/test/test_QUICHandshakeProtocol.cc | 12 ++++---- 15 files changed, 65 insertions(+), 68 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 75c422e17b3..01aecf32981 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -247,9 +247,9 @@ QUICDebugNames::key_phase(QUICKeyPhase phase) return "PHASE_0"; case QUICKeyPhase::PHASE_1: return "PHASE_1"; - case QUICKeyPhase::CLEARTEXT: + case QUICKeyPhase::INITIAL: return "CLEARTEXT"; - case QUICKeyPhase::ZERORTT: + case QUICKeyPhase::ZERO_RTT: return "ZERORTT"; case QUICKeyPhase::HANDSHAKE: return "HANDSHAKE"; diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index 87c73dd476e..dbb04d47f6d 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -44,10 +44,10 @@ QUICPacketProtection::set_key(std::unique_ptr km, QUICKeyPhase phas case QUICKeyPhase::PHASE_1: this->_phase_1_key = std::move(km); break; - case QUICKeyPhase::CLEARTEXT: - this->_cleartext_key = std::move(km); + case QUICKeyPhase::INITIAL: + this->_initial_key = std::move(km); break; - case QUICKeyPhase::ZERORTT: + case QUICKeyPhase::ZERO_RTT: this->_zerortt_key = std::move(km); break; case QUICKeyPhase::HANDSHAKE: @@ -64,9 +64,9 @@ QUICPacketProtection::get_key(QUICKeyPhase phase) const return this->_phase_0_key.get(); case QUICKeyPhase::PHASE_1: return this->_phase_1_key.get(); - case QUICKeyPhase::CLEARTEXT: - return this->_cleartext_key.get(); - case QUICKeyPhase::ZERORTT: + case QUICKeyPhase::INITIAL: + return this->_initial_key.get(); + case QUICKeyPhase::ZERO_RTT: return this->_zerortt_key.get(); case QUICKeyPhase::HANDSHAKE: return this->_handshake_key.get(); diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index a9374859899..53943890a30 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -38,12 +38,12 @@ class QUICPacketProtection QUICKeyPhase key_phase() const; private: - std::unique_ptr _cleartext_key = nullptr; // _initial_key + std::unique_ptr _initial_key = nullptr; std::unique_ptr _zerortt_key = nullptr; std::unique_ptr _handshake_key = nullptr; std::unique_ptr _phase_0_key = nullptr; std::unique_ptr _phase_1_key = nullptr; - QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; + QUICKeyPhase _key_phase = QUICKeyPhase::INITIAL; }; class QUICPacketNumberProtector diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 4ec4cba8ab9..3864e576499 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -36,8 +36,8 @@ using namespace std::literals; constexpr static uint8_t QUIC_VERSION_1_SALT[] = { 0x9c, 0x10, 0x8f, 0x98, 0x52, 0x0a, 0x5c, 0x5c, 0x32, 0x96, 0x8e, 0x95, 0x0e, 0x8a, 0x2c, 0x5f, 0xe0, 0x6d, 0x6c, 0x38, }; -constexpr static std::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("client in"sv); -constexpr static std::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("server in"sv); +constexpr static std::string_view LABEL_FOR_CLIENT_INITIAL_SECRET("client in"sv); +constexpr static std::string_view LABEL_FOR_SERVER_INITIAL_SECRET("server in"sv); constexpr static std::string_view LABEL_FOR_KEY("key"sv); constexpr static std::string_view LABEL_FOR_IV("iv"sv); constexpr static std::string_view LABEL_FOR_PN("pn"sv); @@ -47,7 +47,7 @@ QUICKeyGenerator::generate(QUICConnectionId cid) { std::unique_ptr km = std::make_unique(); - const QUIC_EVP_CIPHER *cipher = this->_get_cipher_for_cleartext(); + const QUIC_EVP_CIPHER *cipher = this->_get_cipher_for_initial(); const EVP_MD *md = EVP_sha256(); uint8_t secret[512]; size_t secret_len = sizeof(secret); @@ -55,8 +55,8 @@ QUICKeyGenerator::generate(QUICConnectionId cid) switch (this->_ctx) { case Context::CLIENT: - this->_generate_cleartext_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_CLIENT_CLEARTEXT_SECRET.data(), - LABEL_FOR_CLIENT_CLEARTEXT_SECRET.length(), EVP_MD_size(md)); + this->_generate_initial_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_CLIENT_INITIAL_SECRET.data(), + LABEL_FOR_CLIENT_INITIAL_SECRET.length(), EVP_MD_size(md)); if (is_debug_tag_set("vv_quic_crypto")) { uint8_t print_buf[512]; QUICDebug::to_hex(print_buf, secret, secret_len); @@ -65,8 +65,8 @@ QUICKeyGenerator::generate(QUICConnectionId cid) break; case Context::SERVER: - this->_generate_cleartext_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_SERVER_CLEARTEXT_SECRET.data(), - LABEL_FOR_SERVER_CLEARTEXT_SECRET.length(), EVP_MD_size(md)); + this->_generate_initial_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_SERVER_INITIAL_SECRET.data(), + LABEL_FOR_SERVER_INITIAL_SECRET.length(), EVP_MD_size(md)); if (is_debug_tag_set("vv_quic_crypto")) { uint8_t print_buf[512]; QUICDebug::to_hex(print_buf, secret, secret_len); @@ -97,28 +97,28 @@ QUICKeyGenerator::_generate(KeyMaterial &km, QUICHKDF &hkdf, const uint8_t *secr } int -QUICKeyGenerator::_generate_cleartext_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid, const char *label, - size_t label_len, size_t length) +QUICKeyGenerator::_generate_initial_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid, const char *label, + size_t label_len, size_t length) { uint8_t client_connection_id[QUICConnectionId::MAX_LENGTH]; size_t cid_len = 0; - uint8_t cleartext_secret[512]; - size_t cleartext_secret_len = sizeof(cleartext_secret); + uint8_t initial_secret[512]; + size_t initial_secret_len = sizeof(initial_secret); // TODO: do not extract initial secret twice QUICTypeUtil::write_QUICConnectionId(cid, client_connection_id, &cid_len); - if (hkdf.extract(cleartext_secret, &cleartext_secret_len, QUIC_VERSION_1_SALT, sizeof(QUIC_VERSION_1_SALT), client_connection_id, + if (hkdf.extract(initial_secret, &initial_secret_len, QUIC_VERSION_1_SALT, sizeof(QUIC_VERSION_1_SALT), client_connection_id, cid.length()) != 1) { return -1; } if (is_debug_tag_set("vv_quic_crypto")) { uint8_t print_buf[512]; - QUICDebug::to_hex(print_buf, cleartext_secret, cleartext_secret_len); + QUICDebug::to_hex(print_buf, initial_secret, initial_secret_len); Debug("vv_quic_crypto", "initial_secret=%s", print_buf); } - hkdf.expand(out, out_len, cleartext_secret, cleartext_secret_len, reinterpret_cast(label), label_len, length); + hkdf.expand(out, out_len, initial_secret, initial_secret_len, reinterpret_cast(label), label_len, length); return 0; } diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index 4c6071cf376..fdc5765f2c2 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -44,8 +44,6 @@ struct KeyMaterial { size_t pn_len = 512; }; -// TODO: rename "cleartext" to "initial" -// TODO: cleanup pp/0rtt stuff which is removed in draft-13 class QUICKeyGenerator { public: @@ -69,13 +67,13 @@ class QUICKeyGenerator size_t _last_secret_len = 0; int _generate(KeyMaterial &km, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher); - int _generate_cleartext_secret(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, QUICConnectionId cid, const char *label, - size_t label_len, size_t length); + int _generate_initial_secret(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; 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_cleartext() const; + const QUIC_EVP_CIPHER *_get_cipher_for_initial() const; const QUIC_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 8df2ccb251f..fe94a1c83de 100644 --- a/iocore/net/quic/QUICKeyGenerator_boringssl.cc +++ b/iocore/net/quic/QUICKeyGenerator_boringssl.cc @@ -37,7 +37,7 @@ QUICKeyGenerator::_get_iv_len(const QUIC_EVP_CIPHER *cipher) const } const QUIC_EVP_CIPHER * -QUICKeyGenerator::_get_cipher_for_cleartext() const +QUICKeyGenerator::_get_cipher_for_initial() const { return EVP_aead_aes_128_gcm(); } diff --git a/iocore/net/quic/QUICKeyGenerator_openssl.cc b/iocore/net/quic/QUICKeyGenerator_openssl.cc index ad3e5e76d6a..4fccdbbd8a4 100644 --- a/iocore/net/quic/QUICKeyGenerator_openssl.cc +++ b/iocore/net/quic/QUICKeyGenerator_openssl.cc @@ -38,7 +38,7 @@ QUICKeyGenerator::_get_iv_len(const QUIC_EVP_CIPHER *cipher) const } const QUIC_EVP_CIPHER * -QUICKeyGenerator::_get_cipher_for_cleartext() const +QUICKeyGenerator::_get_cipher_for_initial() const { return EVP_aes_128_gcm(); } diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 85ab28b33ac..4731b7e2505 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -1023,11 +1023,11 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } break; case QUICPacketType::INITIAL: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::CLEARTEXT, false)) { + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::INITIAL, false)) { if (QUICTypeUtil::is_supported_version(header->version())) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::CLEARTEXT)) { + QUICKeyPhase::INITIAL)) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -1040,10 +1040,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } break; case QUICPacketType::RETRY: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::CLEARTEXT, false)) { + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::INITIAL, false)) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::CLEARTEXT)) { + QUICKeyPhase::INITIAL)) { result = QUICPacketCreationResult::SUCCESS; } else { // ignore failure - probably clear text key is already updated @@ -1068,10 +1068,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } break; case QUICPacketType::ZERO_RTT_PROTECTED: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::ZERORTT, false)) { + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::ZERO_RTT, false)) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::ZERORTT)) { + QUICKeyPhase::ZERO_RTT)) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::IGNORED; @@ -1109,7 +1109,7 @@ QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUIC } // VN packet dosen't have packet number field and version field is always 0x00000000 - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, QUICKeyPhase::CLEARTEXT, dcid, scid, + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::VERSION_NEGOTIATION, QUICKeyPhase::INITIAL, dcid, scid, 0x00, 0x00, 0x00, std::move(versions), len); return QUICPacketFactory::_create_unprotected_packet(std::move(header)); @@ -1119,11 +1119,10 @@ QUICPacketUPtr QUICPacketFactory::create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len) { - int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); - QUICPacketNumber pn = this->_packet_number_generator[index].next(); - QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::CLEARTEXT, destination_cid, source_cid, pn, base_packet_number, - this->_version, std::move(payload), len); + int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); + QUICPacketNumber pn = this->_packet_number_generator[index].next(); + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, destination_cid, source_cid, + pn, base_packet_number, this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), true); } @@ -1131,7 +1130,7 @@ QUICPacketUPtr QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, ats_unique_buf payload, size_t len, bool retransmittable) { - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, QUICKeyPhase::CLEARTEXT, destination_cid, source_cid, + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, QUICKeyPhase::INITIAL, destination_cid, source_cid, 0, 0, this->_version, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), retransmittable); } @@ -1179,7 +1178,7 @@ QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, memcpy(naked_payload + payload_len - 16, stateless_reset_token.buf(), 16); // KeyPhase won't be used - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::STATELESS_RESET, QUICKeyPhase::CLEARTEXT, connection_id, + 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)); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index ddb6a5720dd..1aadc805871 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -158,7 +158,7 @@ class QUICPacketHeader uint8_t _serialized[64]; ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); QUICPacketType _type = QUICPacketType::UNINITIALIZED; - QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT; + QUICKeyPhase _key_phase = QUICKeyPhase::INITIAL; QUICConnectionId _connection_id = QUICConnectionId::ZERO(); QUICPacketNumber _packet_number = 0; QUICPacketNumber _base_packet_number = 0; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index b4e6e3d0789..1923e0176e0 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -56,8 +56,8 @@ QUICTLS::is_ready_to_derive() const bool QUICTLS::is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const { - if (key_phase == QUICKeyPhase::ZERORTT) { - return this->_client_pp->get_key(QUICKeyPhase::ZERORTT); + if (key_phase == QUICKeyPhase::ZERO_RTT) { + return this->_client_pp->get_key(QUICKeyPhase::ZERO_RTT); } else { return this->_get_km(key_phase, for_encryption); } @@ -67,7 +67,7 @@ int QUICTLS::initialize_key_materials(QUICConnectionId cid) { // Generate keys - Debug(tag, "Generating %s keys", QUICDebugNames::key_phase(QUICKeyPhase::CLEARTEXT)); + Debug(tag, "Generating %s keys", QUICDebugNames::key_phase(QUICKeyPhase::INITIAL)); std::unique_ptr km; km = this->_keygen_for_client.generate(cid); @@ -81,7 +81,7 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) QUICDebug::to_hex(print_buf, km->pn, km->pn_len); Debug("vv_quic_crypto", "pn=%s", print_buf); } - this->_client_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); + this->_client_pp->set_key(std::move(km), QUICKeyPhase::INITIAL); km = this->_keygen_for_server.generate(cid); @@ -94,7 +94,7 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) QUICDebug::to_hex(print_buf, km->pn, km->pn_len); Debug("vv_quic_crypto", "pn=%s", print_buf); } - this->_server_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT); + this->_server_pp->set_key(std::move(km), QUICKeyPhase::INITIAL); return 1; } diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc index 00416d45c90..a2e9f70952b 100644 --- a/iocore/net/quic/QUICTLS_boringssl.cc +++ b/iocore/net/quic/QUICTLS_boringssl.cc @@ -65,7 +65,7 @@ QUICTLS::_read_early_data() const EVP_AEAD * QUICTLS::_get_evp_aead(QUICKeyPhase phase) const { - if (phase == QUICKeyPhase::CLEARTEXT) { + if (phase == QUICKeyPhase::INITIAL) { return EVP_aead_aes_128_gcm(); } else { const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); @@ -91,7 +91,7 @@ QUICTLS::_get_evp_aead(QUICKeyPhase phase) const size_t QUICTLS::_get_aead_tag_len(QUICKeyPhase phase) const { - if (phase == QUICKeyPhase::CLEARTEXT) { + if (phase == QUICKeyPhase::INITIAL) { return EVP_GCM_TLS_TAG_LEN; } else { const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index cf3e81b626b..7cb1a7a002d 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -186,7 +186,7 @@ QUICTLS::update_key_materials_on_key_cb(std::unique_ptr km, int nam switch (name) { case SSL_KEY_CLIENT_EARLY_TRAFFIC: // this->_update_encryption_level(QUICEncryptionLevel::ZERO_RTT); - this->_client_pp->set_key(std::move(km), QUICKeyPhase::ZERORTT); + this->_client_pp->set_key(std::move(km), QUICKeyPhase::ZERO_RTT); break; case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); @@ -319,7 +319,7 @@ QUICTLS::_read_early_data() const EVP_CIPHER * QUICTLS::_get_evp_aead(QUICKeyPhase phase) const { - if (phase == QUICKeyPhase::CLEARTEXT) { + if (phase == QUICKeyPhase::INITIAL) { return EVP_aes_128_gcm(); } else { const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); @@ -348,7 +348,7 @@ QUICTLS::_get_evp_aead(QUICKeyPhase phase) const const EVP_CIPHER * QUICTLS::_get_evp_aead_for_pne(QUICKeyPhase phase) const { - if (phase == QUICKeyPhase::CLEARTEXT) { + if (phase == QUICKeyPhase::INITIAL) { return EVP_aes_128_ctr(); } else { const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); @@ -377,7 +377,7 @@ QUICTLS::_get_evp_aead_for_pne(QUICKeyPhase phase) const size_t QUICTLS::_get_aead_tag_len(QUICKeyPhase phase) const { - if (phase == QUICKeyPhase::CLEARTEXT) { + if (phase == QUICKeyPhase::INITIAL) { return EVP_GCM_TLS_TAG_LEN; } else { const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 48c5f352c9d..82e980b2b68 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -106,16 +106,16 @@ QUICTypeUtil::key_phase(QUICPacketType type) { switch (type) { case QUICPacketType::INITIAL: - return QUICKeyPhase::CLEARTEXT; + return QUICKeyPhase::INITIAL; case QUICPacketType::ZERO_RTT_PROTECTED: - return QUICKeyPhase::ZERORTT; + return QUICKeyPhase::ZERO_RTT; case QUICPacketType::HANDSHAKE: return QUICKeyPhase::HANDSHAKE; case QUICPacketType::PROTECTED: // XXX assuming Long Header Packet return QUICKeyPhase::PHASE_0; default: - return QUICKeyPhase::CLEARTEXT; + return QUICKeyPhase::INITIAL; } } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 183b5d8a214..df24da3f1a9 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -114,8 +114,8 @@ enum class QUICVersionNegotiationStatus { enum class QUICKeyPhase : int { PHASE_0 = 0, PHASE_1, - CLEARTEXT, - ZERORTT, + INITIAL, + ZERO_RTT, HANDSHAKE, }; diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 9066f47cac0..1aa21728157 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -134,14 +134,14 @@ static const uint8_t ad[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead // size_t cipher_len = 0; // CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), -// QUICKeyPhase::CLEARTEXT)); +// QUICKeyPhase::INITIAL)); // std::cout << "### Encrypted Text" << std::endl; // print_hex(cipher, cipher_len); // uint8_t plain[128] = {0}; // size_t plain_len = 0; -// CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::CLEARTEXT)); +// CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::INITIAL)); // std::cout << "### Decrypted Text" << std::endl; // print_hex(plain, plain_len); @@ -396,13 +396,13 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") // CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); // // // ## Client -> Server -// client->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::CLEARTEXT); -// server->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::CLEARTEXT); +// client->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); +// server->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::INITIAL); // CHECK(unprotected_pn_len == sizeof(expected)); // CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); // // ## Server -> Client -// server->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::CLEARTEXT); -// client->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::CLEARTEXT); +// server->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); +// client->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::INITIAL); // CHECK(unprotected_pn_len == sizeof(expected)); // CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); // From 9cc24dbfe7fcf8c7b98ee3a2b79447eb3edb3572 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 24 Jul 2018 16:18:28 +0900 Subject: [PATCH 0721/1313] Simplify KeyMaterials in QUICPacketProtection --- iocore/net/quic/QUICHandshakeProtocol.cc | 35 ++---------------------- iocore/net/quic/QUICHandshakeProtocol.h | 9 ++---- 2 files changed, 5 insertions(+), 39 deletions(-) diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index dbb04d47f6d..84028eaaca9 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -36,44 +36,13 @@ QUICPacketProtection::~QUICPacketProtection() {} void QUICPacketProtection::set_key(std::unique_ptr km, QUICKeyPhase phase) { - this->_key_phase = phase; - switch (phase) { - case QUICKeyPhase::PHASE_0: - this->_phase_0_key = std::move(km); - break; - case QUICKeyPhase::PHASE_1: - this->_phase_1_key = std::move(km); - break; - case QUICKeyPhase::INITIAL: - this->_initial_key = std::move(km); - break; - case QUICKeyPhase::ZERO_RTT: - this->_zerortt_key = std::move(km); - break; - case QUICKeyPhase::HANDSHAKE: - this->_handshake_key = std::move(km); - break; - } + this->_key_chain[static_cast(phase)] = std::move(km); } const KeyMaterial * QUICPacketProtection::get_key(QUICKeyPhase phase) const { - switch (phase) { - case QUICKeyPhase::PHASE_0: - return this->_phase_0_key.get(); - case QUICKeyPhase::PHASE_1: - return this->_phase_1_key.get(); - case QUICKeyPhase::INITIAL: - return this->_initial_key.get(); - case QUICKeyPhase::ZERO_RTT: - return this->_zerortt_key.get(); - case QUICKeyPhase::HANDSHAKE: - return this->_handshake_key.get(); - } - - ink_release_assert(!"Bad phase"); - return nullptr; + return this->_key_chain[static_cast(phase)].get(); } QUICKeyPhase diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 53943890a30..9556155d854 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -38,12 +38,9 @@ class QUICPacketProtection QUICKeyPhase key_phase() const; private: - std::unique_ptr _initial_key = nullptr; - std::unique_ptr _zerortt_key = nullptr; - std::unique_ptr _handshake_key = nullptr; - std::unique_ptr _phase_0_key = nullptr; - std::unique_ptr _phase_1_key = nullptr; - QUICKeyPhase _key_phase = QUICKeyPhase::INITIAL; + // TODO: discard keys + std::unique_ptr _key_chain[5] = {nullptr}; + QUICKeyPhase _key_phase = QUICKeyPhase::INITIAL; }; class QUICPacketNumberProtector From 303879530e324125c6bcb27899953d4e2dac59de Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 25 Jul 2018 11:29:11 +0900 Subject: [PATCH 0722/1313] Print negotiated cipher suite on complete handshake --- iocore/net/quic/QUICHandshake.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index a039226d50b..e08d7b21305 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -188,7 +188,6 @@ QUICHandshake::is_version_negotiated() const bool QUICHandshake::is_completed() const { - // TODO: check state with other way return SSL_is_init_finished(this->_ssl); } @@ -462,6 +461,10 @@ QUICHandshake::do_handshake() } } + if (SSL_is_init_finished(this->_ssl)) { + QUICHSDebug("%s", this->negotiated_cipher_suite()); + } + return result; } From 800e03be68c4016c6dea25c648a6cbe2326ac0da Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 25 Jul 2018 13:32:16 +0900 Subject: [PATCH 0723/1313] Fix maximum_frame_size check The maximum_frame_size is maximum size of whole frame include header from draft-13 changes. --- iocore/net/quic/QUICPacketRetransmitter.cc | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index be5f8df164c..1b92ea37b85 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -80,19 +80,7 @@ QUICPacketRetransmitter::generate_frame(QUICEncryptionLevel level, uint64_t conn frame = std::move(this->_retransmission_frames[index].front()); this->_retransmission_frames[index].pop(); - // maximum_frame_size is actually for payload size. So we should compare it - // with data_length(). Howeever, because data_length() is STREAM frame - // specific, we need a branch here. - // See also where maximum_frame_size come from. - bool split = false; - if (frame->type() == QUICFrameType::STREAM) { - QUICStreamFrame *stream_frame = static_cast(frame.get()); - split = stream_frame->data_length() > maximum_frame_size; - } else { - split = frame->size() > maximum_frame_size; - } - - if (split) { + if (frame->size() > maximum_frame_size) { auto new_frame = QUICFrameFactory::split_frame(frame.get(), maximum_frame_size); if (new_frame) { this->_retransmission_frames[index].push(std::move(new_frame)); From 0a1c183e649ecf7b398067c68b8fbdd3815748e9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 26 Jul 2018 10:10:07 +0900 Subject: [PATCH 0724/1313] Do padding only client INITIAL --- iocore/net/QUICNetVConnection.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index c2296774454..b9b983b034d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1351,7 +1351,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa // Schedule a packet if (len != 0) { - if (level == QUICEncryptionLevel::INITIAL) { + if (level == QUICEncryptionLevel::INITIAL && this->netvc_context == NET_VCONNECTION_OUT) { // Pad with PADDING frames uint64_t min_size = this->minimum_quic_packet_size(); min_size = std::min(min_size, max_packet_size); From 45bcdb711391256d8ebafb3801a67ef0c9ca82fc Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 27 Jul 2018 12:32:38 +0900 Subject: [PATCH 0725/1313] [draft-13] Add Loss Detections for each Packet Number Space --- iocore/net/P_QUICNetVConnection.h | 5 +- iocore/net/QUICNetVConnection.cc | 59 +++++++++++++-------- iocore/net/quic/QUICCongestionController.cc | 13 +++-- iocore/net/quic/QUICConnection.h | 10 ++-- iocore/net/quic/QUICLossDetector.cc | 54 +++++++++++++------ iocore/net/quic/QUICLossDetector.h | 22 ++++++-- iocore/net/quic/QUICTypes.cc | 2 +- iocore/net/quic/QUICTypes.h | 7 +++ 8 files changed, 120 insertions(+), 52 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 8142b6f3301..377ff38b3f3 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -205,7 +205,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub uint32_t pmtu() const override; NetVConnectionContext_t direction() const override; SSLNextProtocolSet *next_protocol_set() const override; - QUICPacketNumber largest_acked_packet_number() const override; + QUICPacketNumber largest_acked_packet_number(QUICEncryptionLevel level) const override; bool is_closed() const override; // QUICConnection (QUICPacketTransmitter) @@ -247,6 +247,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICAckFrameCreator _ack_frame_creator; QUICPacketRetransmitter _packet_retransmitter; QUICPacketNumberProtector _pn_protector; + QUICRTTMeasure _rtt_measure; QUICApplicationMap *_application_map = nullptr; uint32_t _pmtu = 1280; @@ -257,7 +258,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub // or make them just member variables. QUICHandshake *_handshake_handler = nullptr; QUICHandshakeProtocol *_hs_protocol = nullptr; - QUICLossDetector *_loss_detector = nullptr; + QUICLossDetector *_loss_detector[3] = {nullptr}; QUICFrameDispatcher *_frame_dispatcher = nullptr; QUICStreamManager *_stream_manager = nullptr; QUICCongestionController *_congestion_controller = nullptr; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b9b983b034d..e72e1f7bd73 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -215,16 +215,20 @@ QUICNetVConnection::start() this->_pn_protector.set_hs_protocol(this->_hs_protocol); // Create frame handlers - this->_congestion_controller = new QUICCongestionController(this); - this->_loss_detector = new QUICLossDetector(this, this, this->_congestion_controller); + this->_congestion_controller = new QUICCongestionController(this); + for (auto s : QUIC_PN_SPACES) { + int index = static_cast(s); + QUICLossDetector *ld = new QUICLossDetector(this, this, this->_congestion_controller, &this->_rtt_measure, index); + this->_frame_dispatcher->add_handler(ld); + this->_loss_detector[index] = ld; + } this->_remote_flow_controller = new QUICRemoteConnectionFlowController(UINT64_MAX); - this->_local_flow_controller = new QUICLocalConnectionFlowController(this->_loss_detector, UINT64_MAX); + this->_local_flow_controller = new QUICLocalConnectionFlowController(&this->_rtt_measure, UINT64_MAX); this->_path_validator = new QUICPathValidator(); - this->_stream_manager = new QUICStreamManager(this, this->_loss_detector, this->_application_map); + this->_stream_manager = new QUICStreamManager(this, &this->_rtt_measure, this->_application_map); this->_frame_dispatcher->add_handler(this); this->_frame_dispatcher->add_handler(this->_stream_manager); - this->_frame_dispatcher->add_handler(this->_loss_detector); this->_frame_dispatcher->add_handler(this->_path_validator); this->_frame_dispatcher->add_handler(this->_handshake_handler); @@ -730,7 +734,9 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) // TODO: Drop record from Connection-ID - QUICNetVConnection table in QUICPacketHandler // Shutdown loss detector - this->_loss_detector->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); + for (auto s : QUIC_PN_SPACES) { + this->_loss_detector[static_cast(s)]->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); + } if (this->nh) { this->nh->free_netvc(this); @@ -816,9 +822,11 @@ QUICNetVConnection::next_protocol_set() const } QUICPacketNumber -QUICNetVConnection::largest_acked_packet_number() const +QUICNetVConnection::largest_acked_packet_number(QUICEncryptionLevel level) const { - return this->_loss_detector->largest_acked_packet_number(); + int index = QUICTypeUtil::pn_space_index(level); + + return this->_loss_detector[index]->largest_acked_packet_number(); } QUICErrorUPtr @@ -867,7 +875,9 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack error = this->_handshake_handler->negotiate_version(packet.get(), &this->_packet_factory); // discard all transport state except packet number - this->_loss_detector->reset(); + for (auto s : QUIC_PN_SPACES) { + this->_loss_detector[static_cast(s)]->reset(); + } this->_congestion_controller->reset(); SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); this->_packet_retransmitter.reset(); @@ -918,7 +928,9 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) { // discard all transport state this->_handshake_handler->reset(); - this->_loss_detector->reset(); + for (auto s : QUIC_PN_SPACES) { + this->_loss_detector[static_cast(s)]->reset(); + } this->_congestion_controller->reset(); SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); this->_packet_retransmitter.reset(); @@ -1102,7 +1114,8 @@ QUICNetVConnection::_state_common_send_packet() QUICConDebug("[TX] %s packet #%" PRIu64 " size=%zu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), len); - this->_loss_detector->on_packet_sent(std::move(packet)); + int index = QUICTypeUtil::pn_space_index(level); + this->_loss_detector[index]->on_packet_sent(std::move(packet)); packet_count++; } } @@ -1444,8 +1457,8 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi case QUICPacketType::INITIAL: { QUICConnectionId dcid = (this->netvc_context == NET_VCONNECTION_OUT) ? this->_original_quic_connection_id : this->_peer_quic_connection_id; - packet = this->_packet_factory.create_initial_packet(dcid, this->_quic_connection_id, this->largest_acked_packet_number(), - std::move(buf), len); + packet = this->_packet_factory.create_initial_packet( + dcid, this->_quic_connection_id, this->largest_acked_packet_number(QUICEncryptionLevel::INITIAL), std::move(buf), len); break; } case QUICPacketType::RETRY: { @@ -1455,14 +1468,15 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi break; } case QUICPacketType::HANDSHAKE: { - packet = - this->_packet_factory.create_handshake_packet(this->_peer_quic_connection_id, this->_quic_connection_id, - this->largest_acked_packet_number(), std::move(buf), len, retransmittable); + packet = this->_packet_factory.create_handshake_packet(this->_peer_quic_connection_id, this->_quic_connection_id, + this->largest_acked_packet_number(QUICEncryptionLevel::HANDSHAKE), + std::move(buf), len, retransmittable); break; } case QUICPacketType::PROTECTED: { - packet = this->_packet_factory.create_server_protected_packet( - this->_peer_quic_connection_id, this->largest_acked_packet_number(), std::move(buf), len, retransmittable); + packet = this->_packet_factory.create_server_protected_packet(this->_peer_quic_connection_id, + this->largest_acked_packet_number(QUICEncryptionLevel::ONE_RTT), + std::move(buf), len, retransmittable); break; } default: @@ -1766,7 +1780,8 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) this->remove_from_active_queue(); this->set_inactivity_timeout(0); - ink_hrtime rto = this->_loss_detector->current_rto_period(); + int index = QUICTypeUtil::pn_space_index(this->_hs_protocol->current_encryption_level()); + ink_hrtime rto = this->_loss_detector[index]->current_rto_period(); QUICConDebug("Enter state_connection_closing %" PRIu64 "ms", 3 * rto / HRTIME_MSECOND); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); @@ -1792,7 +1807,8 @@ QUICNetVConnection::_switch_to_draining_state(QUICConnectionErrorUPtr error) this->remove_from_active_queue(); this->set_inactivity_timeout(0); - ink_hrtime rto = this->_loss_detector->current_rto_period(); + int index = QUICTypeUtil::pn_space_index(this->_hs_protocol->current_encryption_level()); + ink_hrtime rto = this->_loss_detector[index]->current_rto_period(); QUICConDebug("Enter state_connection_draining %" PRIu64 "ms", 3 * rto / HRTIME_MSECOND); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_draining); @@ -1833,7 +1849,8 @@ QUICNetVConnection::_validate_new_path() this->_path_validator->validate(); // Not sure how long we should wait. The spec says just "enough time". // Use the same time amount as the closing timeout. - ink_hrtime rto = this->_loss_detector->current_rto_period(); + int index = QUICTypeUtil::pn_space_index(this->_hs_protocol->current_encryption_level()); + ink_hrtime rto = this->_loss_detector[index]->current_rto_period(); this->_schedule_path_validation_timeout(3 * rto); } diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 52f20b72761..a6ced6234c7 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -40,6 +40,8 @@ QUICCongestionController::QUICCongestionController(QUICConnectionInfoProvider *info) : _info(info) { + this->_cc_mutex = new_ProxyMutex(); + QUICConfig::scoped_config params; this->_k_default_mss = params->cc_default_mss(); this->_k_initial_window = params->cc_initial_window(); @@ -52,6 +54,7 @@ QUICCongestionController::QUICCongestionController(QUICConnectionInfoProvider *i void QUICCongestionController::on_packet_sent(size_t bytes_sent) { + SCOPED_MUTEX_LOCK(lock, this->_cc_mutex, this_ethread()); this->_bytes_in_flight += bytes_sent; } @@ -65,6 +68,7 @@ void QUICCongestionController::on_packet_acked(const PacketInfo &acked_packet) { // Remove from bytes_in_flight. + SCOPED_MUTEX_LOCK(lock, this->_cc_mutex, this_ethread()); this->_bytes_in_flight -= acked_packet.bytes; if (this->_in_recovery(acked_packet.packet_number)) { // Do not increase congestion window in recovery period. @@ -87,6 +91,8 @@ QUICCongestionController::on_packets_lost(const std::map_cc_mutex, this_ethread()); // Remove lost packets from bytes_in_flight. for (auto &lost_packet : lost_packets) { this->_bytes_in_flight -= lost_packet.second->bytes; @@ -151,9 +157,10 @@ QUICCongestionController::current_ssthresh() const void QUICCongestionController::reset() { + SCOPED_MUTEX_LOCK(lock, this->_cc_mutex, this_ethread()); + this->_bytes_in_flight = 0; this->_congestion_window = this->_k_initial_window; - ; - this->_end_of_recovery = 0; - this->_ssthresh = UINT32_MAX; + this->_end_of_recovery = 0; + this->_ssthresh = UINT32_MAX; } diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 2b4b5e16f6e..7e4ae8b33ca 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -57,11 +57,11 @@ class QUICConnectionInfoProvider */ virtual uint32_t minimum_quic_packet_size() = 0; - virtual uint32_t pmtu() const = 0; - virtual NetVConnectionContext_t direction() const = 0; - virtual SSLNextProtocolSet *next_protocol_set() const = 0; - virtual bool is_closed() const = 0; - virtual QUICPacketNumber largest_acked_packet_number() const = 0; + virtual uint32_t pmtu() const = 0; + virtual NetVConnectionContext_t direction() const = 0; + virtual SSLNextProtocolSet *next_protocol_set() const = 0; + virtual bool is_closed() const = 0; + virtual QUICPacketNumber largest_acked_packet_number(QUICEncryptionLevel level) const = 0; }; class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler, public QUICConnectionInfoProvider diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 124156d66b4..c6a50145d11 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -28,12 +28,14 @@ #include "QUICConfig.h" #include "QUICEvents.h" -#define QUICLDDebug(fmt, ...) Debug("quic_loss_detector", "[%s] " fmt, this->_info->cids().data(), ##__VA_ARGS__) -#define QUICLDVDebug(fmt, ...) Debug("v_quic_loss_detector", "[%s] " fmt, this->_info->cids().data(), ##__VA_ARGS__) +#define QUICLDDebug(fmt, ...) \ + Debug("quic_loss_detector", "[%s] [PNS-%d] " fmt, this->_info->cids().data(), this->_pn_space_index, ##__VA_ARGS__) +#define QUICLDVDebug(fmt, ...) \ + Debug("v_quic_loss_detector", "[%s] [PNS-%d] " fmt, this->_info->cids().data(), this->_pn_space_index, ##__VA_ARGS__) QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, - QUICCongestionController *cc) - : _transmitter(transmitter), _info(info), _cc(cc) + QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, int index) + : _transmitter(transmitter), _info(info), _cc(cc), _rtt_measure(rtt_measure), _pn_space_index(index) { this->mutex = new_ProxyMutex(); this->_loss_detection_mutex = new_ProxyMutex(); @@ -73,6 +75,7 @@ QUICLossDetector::event_handler(int event, Event *edata) case EVENT_INTERVAL: { if (this->_loss_detection_alarm_at <= Thread::get_hrtime()) { this->_loss_detection_alarm_at = 0; + this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); this->_on_loss_detection_alarm(); } break; @@ -104,8 +107,13 @@ QUICLossDetector::handle_frame(QUICEncryptionLevel level, std::shared_ptr_pn_space_index != QUICTypeUtil::pn_space_index(level)) { + return error; + } + switch (frame->type()) { case QUICFrameType::ACK: + this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); this->_on_ack_received(std::dynamic_pointer_cast(frame)); break; default: @@ -133,6 +141,7 @@ QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) return; } + // Is CRYPTO[EOED] on 0-RTT handshake? if (type == QUICPacketType::INITIAL || type == QUICPacketType::HANDSHAKE) { is_handshake = true; } @@ -140,6 +149,7 @@ QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) QUICPacketNumber packet_number = packet->packet_number(); bool is_ack_only = !packet->is_retransmittable(); size_t sent_bytes = is_ack_only ? 0 : packet->size(); + this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); this->_on_packet_sent(packet_number, is_ack_only, is_handshake, sent_bytes, std::move(packet)); } @@ -262,6 +272,8 @@ QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICP this->_rttvar = 3.0 / 4.0 * this->_rttvar + 1.0 / 4.0 * rttvar_sample; this->_smoothed_rtt = 7.0 / 8.0 * this->_smoothed_rtt + 1.0 / 8.0 * latest_rtt; } + + this->_rtt_measure->update_smoothed_rtt(this->_smoothed_rtt); } void @@ -290,18 +302,21 @@ void QUICLossDetector::_set_loss_detection_alarm() { ink_hrtime alarm_duration; - // Don't arm the alarm if there are no packets with - // retransmittable data in flight. - if (this->_cc->bytes_in_flight() == 0 && this->_loss_detection_alarm) { - this->_loss_detection_alarm_at = 0; - this->_loss_detection_alarm->cancel(); - this->_loss_detection_alarm = nullptr; - QUICLDDebug("Loss detection alarm has been unset"); + + // Don't arm the alarm if there are no packets with retransmittable data in flight. + // -- MODIFIED CODE -- + // In psuedocode, `bytes_in_flight` is used, but we're tracking "retransmittable data in flight" by `_retransmittable_outstanding` + if (this->_retransmittable_outstanding == 0) { + if (this->_loss_detection_alarm) { + this->_loss_detection_alarm_at = 0; + this->_loss_detection_alarm->cancel(); + this->_loss_detection_alarm = nullptr; + QUICLDDebug("Loss detection alarm has been unset"); + } return; - } else { - QUICLDDebug("bytes_in_flight=%" PRIu32, this->_cc->bytes_in_flight()); } + // -- END OF MODIFIED CODE -- if (this->_handshake_outstanding) { // Handshake retransmission alarm. @@ -594,8 +609,17 @@ QUICLossDetector::current_rto_period() return alarm_duration; } +// +// QUICRTTMeasure +// ink_hrtime -QUICLossDetector::smoothed_rtt() const +QUICRTTMeasure::smoothed_rtt() const +{ + return this->_smoothed_rtt.load(); +} + +void +QUICRTTMeasure::update_smoothed_rtt(ink_hrtime rtt) { - return this->_smoothed_rtt; + this->_smoothed_rtt.store(rtt); } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 0bcd4161f83..48249a11330 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -57,6 +57,16 @@ class QUICRTTProvider virtual ink_hrtime smoothed_rtt() const = 0; }; +class QUICRTTMeasure : public QUICRTTProvider +{ +public: + ink_hrtime smoothed_rtt() const override; + void update_smoothed_rtt(ink_hrtime rtt); + +private: + std::atomic _smoothed_rtt = 0; +}; + class QUICCongestionController { public: @@ -76,6 +86,8 @@ class QUICCongestionController uint32_t current_ssthresh() const; private: + Ptr _cc_mutex; + // [draft-11 recovery] 4.7.1. Constants of interest // Values will be loaded from records.config via QUICConfig at constructor uint32_t _k_default_mss = 0; @@ -94,10 +106,11 @@ class QUICCongestionController bool _in_recovery(QUICPacketNumber packet_number); }; -class QUICLossDetector : public Continuation, public QUICFrameHandler, public QUICRTTProvider +class QUICLossDetector : public Continuation, public QUICFrameHandler { public: - QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, QUICCongestionController *cc); + QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, QUICCongestionController *cc, + QUICRTTMeasure *rtt_measure, int index); ~QUICLossDetector(); int event_handler(int event, Event *edata); @@ -108,13 +121,10 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU QUICPacketNumber largest_acked_packet_number(); void reset(); ink_hrtime current_rto_period(); - ink_hrtime smoothed_rtt() const override; private: Ptr _loss_detection_mutex; - // TODO QUICCongestionController *cc = nullptr; - // [draft-11 recovery] 3.5.1. Constants of interest // Values will be loaded from records.config via QUICConfig at constructor uint32_t _k_max_tlps = 0; @@ -179,4 +189,6 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler, public QU QUICPacketTransmitter *_transmitter = nullptr; QUICConnectionInfoProvider *_info = nullptr; QUICCongestionController *_cc = nullptr; + QUICRTTMeasure *_rtt_measure = nullptr; + int _pn_space_index = -1; }; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 82e980b2b68..0577d45cce9 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -119,7 +119,7 @@ QUICTypeUtil::key_phase(QUICPacketType type) } } -// 0-RTT and 1-RTT use same PN Space +// 0-RTT and 1-RTT use same Packet Number Space int QUICTypeUtil::pn_space_index(QUICEncryptionLevel level) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index df24da3f1a9..4775e58cdf3 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -69,6 +69,13 @@ constexpr QUICEncryptionLevel QUIC_ENCRYPTION_LEVELS[] = { QUICEncryptionLevel::ONE_RTT, }; +// 0-RTT and 1-RTT use same Packet Number Space +constexpr QUICEncryptionLevel QUIC_PN_SPACES[] = { + QUICEncryptionLevel::INITIAL, + QUICEncryptionLevel::ZERO_RTT, + QUICEncryptionLevel::HANDSHAKE, +}; + // Devide to QUICPacketType and QUICPacketLongHeaderType ? enum class QUICPacketType : uint8_t { VERSION_NEGOTIATION = 0, From 48129f0443e0db9289bfe06dc57d994adb4f1d60 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 27 Jul 2018 12:33:27 +0900 Subject: [PATCH 0726/1313] Print negotiated cipher suite on complete handshake (take 2) --- iocore/net/QUICNetVConnection.cc | 2 ++ iocore/net/quic/QUICHandshake.cc | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e72e1f7bd73..a04a3246a97 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1752,6 +1752,8 @@ QUICNetVConnection::_switch_to_established_state() { if (this->_complete_handshake_if_possible() == 0) { QUICConDebug("Enter state_connection_established"); + QUICConDebug("Negotiated cipher suite: %s", this->_handshake_handler->negotiated_cipher_suite()); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); if (netvc_context == NET_VCONNECTION_IN) { diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index e08d7b21305..0d1f18a3e78 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -461,10 +461,6 @@ QUICHandshake::do_handshake() } } - if (SSL_is_init_finished(this->_ssl)) { - QUICHSDebug("%s", this->negotiated_cipher_suite()); - } - return result; } From 35cfdca9cf41419aac45e8beeb0de359059222cd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 27 Jul 2018 16:11:08 +0900 Subject: [PATCH 0727/1313] Source addresses verification by receiving messages in HANDSHAKE packet --- iocore/net/P_QUICNetVConnection.h | 4 ++++ iocore/net/QUICNetVConnection.cc | 29 ++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 377ff38b3f3..18bff6033e8 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -347,12 +347,16 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _update_peer_cid(const QUICConnectionId &new_cid); void _update_local_cid(const QUICConnectionId &new_cid); void _rerandomize_original_cid(); + bool _is_src_addr_verified(); QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet(); QUICStatelessResetToken _reset_token; // This is for limiting number of packets that a server can send without path validation unsigned int _handshake_packets_sent = 0; + + // TODO: Source addresses verification through an address validation token + bool _src_addr_verified = false; }; typedef int (QUICNetVConnection::*QUICNetVConnHandler)(int, void *); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a04a3246a97..93e8143d906 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -64,6 +64,8 @@ static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(20); +static constexpr uint32_t MAX_PACKETS_WITHOUT_SRC_ADDR_VARIDATION = 3; + static constexpr uint32_t STATE_CLOSING_MAX_SEND_PKT_NUM = 8; // Max number of sending packets which contain a closing frame. static constexpr uint32_t STATE_CLOSING_MAX_RECV_PKT_WIND = 1 << STATE_CLOSING_MAX_SEND_PKT_NUM; @@ -231,10 +233,6 @@ 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); - - if (this->direction() == NET_VCONNECTION_IN) { - this->_validate_new_path(); - } } void @@ -951,6 +949,11 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) QUICErrorUPtr QUICNetVConnection::_state_handshake_process_handshake_packet(QUICPacketUPtr 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->_src_addr_verified) { + this->_src_addr_verified = true; + } return this->_recv_and_ack(std::move(packet)); } @@ -1077,10 +1080,11 @@ QUICErrorUPtr QUICNetVConnection::_state_common_send_packet() { uint32_t packet_count = 0; - - while (true) { + uint32_t error = 0; + while (error == 0) { // TODO: add safeguard like FRAME_PER_EVENT uint32_t window = this->_congestion_controller->open_window(); + if (window == 0) { break; } @@ -1091,6 +1095,12 @@ QUICNetVConnection::_state_common_send_packet() uint32_t written = 0; for (auto level : QUIC_ENCRYPTION_LEVELS) { + if (this->netvc_context == NET_VCONNECTION_IN && !this->_is_src_addr_verified() && + this->_handshake_packets_sent >= MAX_PACKETS_WITHOUT_SRC_ADDR_VARIDATION) { + error = 1; + break; + } + uint32_t max_packet_size = udp_payload_len - written; QUICPacketUPtr packet = this->_packetize_frames(level, max_packet_size); @@ -1098,7 +1108,6 @@ QUICNetVConnection::_state_common_send_packet() if (this->netvc_context == NET_VCONNECTION_IN && (packet->type() == QUICPacketType::INITIAL || packet->type() == QUICPacketType::HANDSHAKE)) { ++this->_handshake_packets_sent; - // TODO: do path validation before sending over 3 Initial/Handshake packets } // TODO: do not write two QUIC Short Header Packets @@ -1912,3 +1921,9 @@ QUICNetVConnection::_rerandomize_original_cid() QUICConDebug("original cid: %s -> %s", old_cid_str, new_cid_str); } } + +bool +QUICNetVConnection::_is_src_addr_verified() +{ + return this->_src_addr_verified; +} From ad51d3c286a67cff5a39986e10a5428e6de36f61 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 1 Aug 2018 11:24:20 +0900 Subject: [PATCH 0728/1313] Fix errors caused by rebase quic-d13 branch --- iocore/net/quic/QUICHandshake.cc | 6 ++++-- iocore/net/quic/QUICStream.cc | 2 +- iocore/net/quic/QUICStream.h | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 0d1f18a3e78..f6ea128eb68 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -342,9 +342,11 @@ QUICHandshake::handle_frame(QUICEncryptionLevel level, std::shared_ptrtype()) { - case QUICFrameType::CRYPTO: - error = this->_crypto_streams[static_cast(level)].recv(std::static_pointer_cast(frame)); + case QUICFrameType::CRYPTO: { + QUICCryptoFrameSPtr crypto_frame = std::static_pointer_cast(frame); + error = this->_crypto_streams[static_cast(level)].recv(*crypto_frame); break; + } default: QUICHSDebug("Unexpected frame type: %02x", static_cast(frame->type())); ink_assert(false); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index a22390d4cf5..1965760b72d 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -599,7 +599,7 @@ QUICCryptoStream::reset_recv_offset() } QUICErrorUPtr -QUICCryptoStream::recv(const std::shared_ptr frame) +QUICCryptoStream::recv(const QUICCryptoFrame &frame) { QUICErrorUPtr error = this->_received_stream_frame_buffer.insert(frame); if (error->cls != QUICErrorClass::NONE) { diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index bc2bfaffffc..e70cbd9060e 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -145,7 +145,7 @@ class QUICCryptoStream : public QUICFrameGenerator void reset_send_offset(); void reset_recv_offset(); - QUICErrorUPtr recv(const std::shared_ptr frame); + QUICErrorUPtr recv(const QUICCryptoFrame &frame); int64_t read_avail(); int64_t read(uint8_t *buf, int64_t len); int64_t write(const uint8_t *buf, int64_t len); From a1a942be2d650f9d4b5ada00b51dafcf9fd92be9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 1 Aug 2018 11:29:11 +0900 Subject: [PATCH 0729/1313] Set SSL_MODE_QUIC_HACK To use tatsuhiro-t's custom OpenSSL for QUIC draft-13. https://github.com/tatsuhiro-t/openssl/tree/quic-draft-13 --- iocore/net/quic/QUICConfig.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 0e941c6c03d..949a2841812 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -61,6 +61,13 @@ quic_new_ssl_ctx() SSL_EXT_TLS_ONLY | SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS, &QUICTransportParametersHandler::add, &QUICTransportParametersHandler::free, nullptr, &QUICTransportParametersHandler::parse, nullptr); + +#ifdef SSL_MODE_QUIC_HACK + // 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); +#endif + return ssl_ctx; } From 3692c63376d3997a41cb2240a330b0fac413868e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 1 Aug 2018 15:44:13 +0900 Subject: [PATCH 0730/1313] Fix build errors of unit tests --- iocore/net/quic/Makefile.am | 15 +++--- iocore/net/quic/Mock.h | 30 +++++++---- .../net/quic/test/test_QUICFrameDispatcher.cc | 6 +-- iocore/net/quic/test/test_QUICLossDetector.cc | 27 +++++----- iocore/net/quic/test/test_QUICPacket.cc | 2 +- iocore/net/quic/test/test_QUICStream.cc | 54 ++++++++++--------- .../net/quic/test/test_QUICStreamManager.cc | 30 ++++++----- 7 files changed, 91 insertions(+), 73 deletions(-) diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 7411ef2c337..4b53388bd59 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -80,14 +80,12 @@ libquic_a_SOURCES = \ # # Check Programs # - check_PROGRAMS = \ test_QUICAckFrameCreator \ test_QUICFlowController \ test_QUICFrame \ test_QUICFrameDispatcher \ test_QUICLossDetector \ - test_QUICHandshake \ test_QUICHandshakeProtocol \ test_QUICIncomingFrameBuffer \ test_QUICInvariants \ @@ -160,12 +158,13 @@ test_QUICLossDetector_SOURCES = \ $(test_event_main_SOURCES) \ ./test/test_QUICLossDetector.cc -test_QUICHandshake_CPPFLAGS = $(test_CPPFLAGS) -test_QUICHandshake_LDFLAGS = @AM_LDFLAGS@ -test_QUICHandshake_LDADD = $(test_LDADD) -test_QUICHandshake_SOURCES = \ - $(test_event_main_SOURCES) \ - ./test/test_QUICHandshake.cc +# TODO: fix unit test using QUICCryptoStream +# test_QUICHandshake_CPPFLAGS = $(test_CPPFLAGS) +# test_QUICHandshake_LDFLAGS = @AM_LDFLAGS@ +# test_QUICHandshake_LDADD = $(test_LDADD) +# test_QUICHandshake_SOURCES = \ +# $(test_event_main_SOURCES) \ +# ./test/test_QUICHandshake.cc test_QUICHandshakeProtocol_CPPFLAGS = $(test_CPPFLAGS) test_QUICHandshakeProtocol_LDFLAGS = @AM_LDFLAGS@ diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 964ee32f413..05789321342 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -37,7 +37,7 @@ class MockQUICStreamManager : public QUICStreamManager MockQUICStreamManager() : QUICStreamManager() {} // Override virtual QUICErrorUPtr - handle_frame(std::shared_ptr f) override + handle_frame(QUICEncryptionLevel level, std::shared_ptr f) override { ++_frameCount[static_cast(f->type())]; ++_totalFrameCount; @@ -205,7 +205,7 @@ class MockQUICConnection : public QUICConnection } QUICErrorUPtr - handle_frame(std::shared_ptr f) override + handle_frame(QUICEncryptionLevel level, std::shared_ptr f) override { ++_frameCount[static_cast(f->type())]; ++_totalFrameCount; @@ -232,7 +232,7 @@ class MockQUICConnection : public QUICConnection } QUICPacketNumber - largest_acked_packet_number() const override + largest_acked_packet_number(QUICEncryptionLevel level) const override { return 0; } @@ -340,7 +340,7 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider } QUICPacketNumber - largest_acked_packet_number() const override + largest_acked_packet_number(QUICEncryptionLevel level) const override { return 0; } @@ -444,8 +444,9 @@ class MockQUICCongestionController : public QUICCongestionController class MockQUICLossDetector : public QUICLossDetector { public: - MockQUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, QUICCongestionController *cc) - : QUICLossDetector(transmitter, info, cc) + MockQUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, QUICCongestionController *cc, + QUICRTTMeasure *rtt_measure, int index) + : QUICLossDetector(transmitter, info, cc, rtt_measure, index) { } void @@ -536,7 +537,7 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol public: MockQUICHandshakeProtocol() : QUICHandshakeProtocol() {} int - handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len) override + handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) override { return true; } @@ -551,9 +552,14 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol is_ready_to_derive() const override { return true; - }; + } + + bool + is_key_derived(QUICKeyPhase /* key_phase */, bool /* for_encryption */) const override + { + return true; + } - bool is_key_derived(QUICKeyPhase /* key_phase */) const override { return true; } int initialize_key_materials(QUICConnectionId cid) override { @@ -595,6 +601,12 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol { return true; } + + QUICEncryptionLevel + current_encryption_level() const override + { + return QUICEncryptionLevel::INITIAL; + } }; class MockContinuation : public Continuation diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 8be50c29666..eca9aa3ce47 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -40,7 +40,7 @@ TEST_CASE("QUICFrameHandler", "[quic]") auto tx = new MockQUICPacketTransmitter(); auto info = new MockQUICConnectionInfoProvider(); auto cc = new MockQUICCongestionController(info); - auto lossDetector = new MockQUICLossDetector(tx, info, cc); + auto lossDetector = new MockQUICLossDetector(tx, info, cc, nullptr, 0); QUICFrameDispatcher quicFrameDispatcher(info); quicFrameDispatcher.add_handler(connection); @@ -56,14 +56,14 @@ TEST_CASE("QUICFrameHandler", "[quic]") size_t len = 0; streamFrame.store(buf, &len, 4096); bool should_send_ack; - quicFrameDispatcher.receive_frames(buf, len, should_send_ack); + quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack); CHECK(connection->getTotalFrameCount() == 0); CHECK(streamManager->getTotalFrameCount() == 1); // CONNECTION_CLOSE frame QUICConnectionCloseFrame connectionCloseFrame({}); connectionCloseFrame.store(buf, &len, 4096); - quicFrameDispatcher.receive_frames(buf, len, should_send_ack); + quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack); CHECK(connection->getTotalFrameCount() == 1); CHECK(streamManager->getTotalFrameCount() == 1); } diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 26d0f561798..cebe4dca56b 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -39,7 +39,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); MockQUICConnectionInfoProvider *info = new MockQUICConnectionInfoProvider(); MockQUICCongestionController *cc = new MockQUICCongestionController(info); - QUICLossDetector detector(tx, info, cc); + QUICLossDetector detector(tx, info, cc, nullptr, 0); ats_unique_buf payload = ats_unique_malloc(16); size_t payload_len = 16; QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); @@ -57,7 +57,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") memcpy(payload.get(), raw, sizeof(raw)); QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::HANDSHAKE, {reinterpret_cast("\xff\xdd\xbb\x99\x77\x55\x33\x11"), 8}, + QUICPacketHeader::build(QUICPacketType::HANDSHAKE, QUICKeyPhase::HANDSHAKE, + {reinterpret_cast("\xff\xdd\xbb\x99\x77\x55\x33\x11"), 8}, {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x00000001, 0, 0x00112233, std::move(payload), sizeof(raw)); QUICPacketUPtr packet = @@ -69,7 +70,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") // Receive ACK std::shared_ptr frame = std::make_shared(0x01, 20, 0); frame->ack_block_section()->add_ack_block({0, 1ULL}); - detector.handle_frame(frame); + detector.handle_frame(QUICEncryptionLevel::INITIAL, frame); ink_hrtime_sleep(HRTIME_MSECONDS(1500)); int retransmit_count = tx->retransmitted.size(); ink_hrtime_sleep(HRTIME_MSECONDS(1500)); @@ -133,16 +134,16 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") ink_hrtime_sleep(HRTIME_MSECONDS(1000)); // Receive an ACK for (1) (4) (5) (7) (8) (9) - afc->update(pn1, false, true); - afc->update(pn4, false, true); - afc->update(pn5, false, true); - afc->update(pn7, false, true); - afc->update(pn8, false, true); - afc->update(pn9, false, true); + afc->update(QUICEncryptionLevel::INITIAL, pn1, true); + afc->update(QUICEncryptionLevel::INITIAL, pn4, true); + afc->update(QUICEncryptionLevel::INITIAL, pn5, true); + afc->update(QUICEncryptionLevel::INITIAL, pn7, true); + afc->update(QUICEncryptionLevel::INITIAL, pn8, true); + afc->update(QUICEncryptionLevel::INITIAL, pn9, true); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); - std::shared_ptr x = afc->generate_frame(2048, 2048); + std::shared_ptr x = afc->generate_frame(QUICEncryptionLevel::INITIAL, 2048, 2048); frame = std::dynamic_pointer_cast(x); - detector.handle_frame(frame); + detector.handle_frame(QUICEncryptionLevel::INITIAL, frame); ink_hrtime_sleep(HRTIME_MSECONDS(5000)); CHECK(cc->lost_packets.size() == 3); @@ -164,7 +165,7 @@ TEST_CASE("QUICLossDetector_HugeGap", "[quic]") MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); MockQUICConnectionInfoProvider *info = new MockQUICConnectionInfoProvider(); MockQUICCongestionController *cc = new MockQUICCongestionController(info); - QUICLossDetector detector(tx, info, cc); + QUICLossDetector detector(tx, info, cc, nullptr, 0); // Check initial state CHECK(tx->retransmitted.size() == 0); @@ -172,7 +173,7 @@ TEST_CASE("QUICLossDetector_HugeGap", "[quic]") auto t1 = Thread::get_hrtime(); std::shared_ptr ack = QUICFrameFactory::create_ack_frame(100000000, 100, 10000000); ack->ack_block_section()->add_ack_block({20000000, 30000000}); - detector.handle_frame(ack); + detector.handle_frame(QUICEncryptionLevel::INITIAL, ack); auto t2 = Thread::get_hrtime(); CHECK(t2 - t1 < HRTIME_MSECONDS(100)); } diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index a8bcc4b2be5..c62c18c1dba 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -96,7 +96,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") memcpy(payload.get(), expected + 17, 5); QUICPacketHeaderUPtr header = QUICPacketHeader::build( - QUICPacketType::INITIAL, {reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, + QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, {reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x01234567, 0, 0x11223344, std::move(payload), 5); CHECK(header->size() == 27); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 020e9f49924..a5a0eec3ea0 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -193,54 +193,56 @@ TEST_CASE("QUICStream", "[quic]") stream->do_io_read(nullptr, 0, read_buffer); stream->do_io_write(&mock_cont, 0, write_buffer_reader); + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + const char data[1024] = {0}; QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame() == true); - frame = stream->generate_frame(4096, 4096); + CHECK(stream->will_generate_frame(level) == true); + frame = stream->generate_frame(level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame() == false); + CHECK(stream->will_generate_frame(level) == false); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame() == true); - frame = stream->generate_frame(4096, 4096); + CHECK(stream->will_generate_frame(level) == true); + frame = stream->generate_frame(level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame() == false); + CHECK(stream->will_generate_frame(level) == false); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame() == true); - frame = stream->generate_frame(4096, 4096); + CHECK(stream->will_generate_frame(level) == true); + frame = stream->generate_frame(level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame() == false); + CHECK(stream->will_generate_frame(level) == false); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame() == true); - frame = stream->generate_frame(4096, 4096); + CHECK(stream->will_generate_frame(level) == true); + frame = stream->generate_frame(level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame() == false); + CHECK(stream->will_generate_frame(level) == false); // This should not send a frame because of flow control write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame() == true); - frame = stream->generate_frame(4096, 4096); + CHECK(stream->will_generate_frame(level) == true); + frame = stream->generate_frame(level, 4096, 4096); CHECK(frame); CHECK(frame->type() == QUICFrameType::STREAM_BLOCKED); - CHECK(stream->will_generate_frame() == true); + CHECK(stream->will_generate_frame(level) == true); // Update window stream->recv(*std::make_shared(stream_id, 5120)); // This should send a frame stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame() == true); - frame = stream->generate_frame(4096, 4096); + CHECK(stream->will_generate_frame(level) == true); + frame = stream->generate_frame(level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame() == false); + CHECK(stream->will_generate_frame(level) == false); // Update window stream->recv(*std::make_shared(stream_id, 5632)); @@ -248,23 +250,23 @@ TEST_CASE("QUICStream", "[quic]") // This should send a frame write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame() == true); - frame = stream->generate_frame(4096, 4096); + CHECK(stream->will_generate_frame(level) == true); + frame = stream->generate_frame(level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame() == true); + CHECK(stream->will_generate_frame(level) == true); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame() == true); - frame = stream->generate_frame(4096, 4096); + CHECK(stream->will_generate_frame(level) == true); + frame = stream->generate_frame(level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM_BLOCKED); // Update window stream->recv(*std::make_shared(stream_id, 6144)); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame() == true); - frame = stream->generate_frame(4096, 4096); + CHECK(stream->will_generate_frame(level) == true); + frame = stream->generate_frame(level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame() == false); + CHECK(stream->will_generate_frame(level) == false); } } diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 269cd3696e9..9f017169685 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -31,6 +31,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") { + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); @@ -47,36 +48,37 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 1, 0); CHECK(sm.stream_count() == 0); - sm.handle_frame(stream_frame_0); + sm.handle_frame(level, stream_frame_0); CHECK(sm.stream_count() == 1); - sm.handle_frame(stream_frame_1); + sm.handle_frame(level, stream_frame_1); CHECK(sm.stream_count() == 2); // RST_STREAM frames create new streams std::shared_ptr rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(2, static_cast(0x01), 0); - sm.handle_frame(rst_stream_frame); + sm.handle_frame(level, rst_stream_frame); CHECK(sm.stream_count() == 3); // MAX_STREAM_DATA frames create new streams std::shared_ptr max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(3, 0); - sm.handle_frame(max_stream_data_frame); + sm.handle_frame(level, max_stream_data_frame); CHECK(sm.stream_count() == 4); // STREAM_BLOCKED frames create new streams std::shared_ptr stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(4, 0); - sm.handle_frame(stream_blocked_frame); + sm.handle_frame(level, stream_blocked_frame); CHECK(sm.stream_count() == 5); // Set local maximum stream id sm.set_max_stream_id(5); std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_blocked_frame(8, 0); - sm.handle_frame(stream_blocked_frame_x); + sm.handle_frame(level, stream_blocked_frame_x); CHECK(sm.stream_count() == 5); } TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") { + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); @@ -91,12 +93,13 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") std::shared_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 7); - sm.handle_frame(stream_frame_0); + sm.handle_frame(level, stream_frame_0); CHECK("succeed"); } TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") { + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); @@ -112,24 +115,25 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") // Create a stream with STREAM_BLOCKED (== noop) std::shared_ptr stream_blocked_frame_0 = QUICFrameFactory::create_stream_blocked_frame(0, 0); std::shared_ptr stream_blocked_frame_1 = QUICFrameFactory::create_stream_blocked_frame(1, 0); - sm.handle_frame(stream_blocked_frame_0); - sm.handle_frame(stream_blocked_frame_1); + sm.handle_frame(level, stream_blocked_frame_0); + sm.handle_frame(level, stream_blocked_frame_1); CHECK(sm.stream_count() == 2); CHECK(sm.total_offset_received() == 0); // Stream 0 shoud be out of flow control std::shared_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(data, 1024, 0, 0); - sm.handle_frame(stream_frame_0); + sm.handle_frame(level, stream_frame_0); CHECK(sm.total_offset_received() == 0); // total_offset should be a integer in unit of 1024 octets std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); - sm.handle_frame(stream_frame_1); + sm.handle_frame(level, stream_frame_1); CHECK(sm.total_offset_received() == 1024); } TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") { + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; QUICApplicationMap app_map; MockQUICApplication mock_app; app_map.set_default(&mock_app); @@ -147,8 +151,8 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 0); std::shared_ptr stream_frame_1_r = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 1, 0); - sm.handle_frame(stream_frame_0_r); - sm.handle_frame(stream_frame_1_r); + sm.handle_frame(level, stream_frame_0_r); + sm.handle_frame(level, stream_frame_1_r); CHECK(sm.stream_count() == 2); CHECK(sm.total_offset_sent() == 0); From 8dcf5b193c3841e75dcf567f685843f1cea1af52 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 1 Aug 2018 15:59:44 +0900 Subject: [PATCH 0731/1313] Fix unit tests except handshake --- iocore/net/quic/QUICTypes.h | 1 + iocore/net/quic/test/test_QUICFrameDispatcher.cc | 3 ++- iocore/net/quic/test/test_QUICLossDetector.cc | 6 ++++-- iocore/net/quic/test/test_QUICPacket.cc | 12 +++++++----- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 4775e58cdf3..8b4df08bb6d 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -45,6 +45,7 @@ using QUICOffset = uint64_t; // TODO: Update version number // Note: Prefix for drafts (0xff000000) + draft number +// Note: Fix "Supported Version" field in test case of QUICPacketFactory_Create_VersionNegotiationPacket // Note: Change ExtensionType (QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID) if it's changed constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { 0xff00000d, diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index eca9aa3ce47..30b38ceb2e0 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -40,7 +40,8 @@ TEST_CASE("QUICFrameHandler", "[quic]") auto tx = new MockQUICPacketTransmitter(); auto info = new MockQUICConnectionInfoProvider(); auto cc = new MockQUICCongestionController(info); - auto lossDetector = new MockQUICLossDetector(tx, info, cc, nullptr, 0); + QUICRTTMeasure rtt_measure; + auto lossDetector = new MockQUICLossDetector(tx, info, cc, &rtt_measure, 0); QUICFrameDispatcher quicFrameDispatcher(info); quicFrameDispatcher.add_handler(connection); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index cebe4dca56b..628a96d1409 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -33,13 +33,14 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") MockQUICHandshakeProtocol hs_protocol; QUICPacketFactory pf; pf.set_hs_protocol(&hs_protocol); + QUICRTTMeasure rtt_measure; QUICAckFrameCreator *afc = new QUICAckFrameCreator(); QUICConnectionId connection_id = {reinterpret_cast("\x01"), 1}; MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); MockQUICConnectionInfoProvider *info = new MockQUICConnectionInfoProvider(); MockQUICCongestionController *cc = new MockQUICCongestionController(info); - QUICLossDetector detector(tx, info, cc, nullptr, 0); + QUICLossDetector detector(tx, info, cc, &rtt_measure, 0); ats_unique_buf payload = ats_unique_malloc(16); size_t payload_len = 16; QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); @@ -165,7 +166,8 @@ TEST_CASE("QUICLossDetector_HugeGap", "[quic]") MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); MockQUICConnectionInfoProvider *info = new MockQUICConnectionInfoProvider(); MockQUICCongestionController *cc = new MockQUICCongestionController(info); - QUICLossDetector detector(tx, info, cc, nullptr, 0); + QUICRTTMeasure rtt_measure; + QUICLossDetector detector(tx, info, cc, &rtt_measure, 0); // Check initial state CHECK(tx->retransmitted.size() == 0); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index c62c18c1dba..67cc2959a67 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -59,14 +59,15 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0x55, // DCIL/SCIL 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID + 0x00, // Token Length (i), Token (*) 0x02, // Payload length 0xC1, 0x23, 0x45, 0x67, // Packet number 0xff, 0xff, // Payload (dummy) }; QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); - CHECK(header->size() == 27); - CHECK(header->packet_size() == 29); + CHECK(header->size() == sizeof(input) - 2); // Packet Length - Payload Length + CHECK(header->packet_size() == sizeof(input)); CHECK(header->type() == QUICPacketType::INITIAL); CHECK( (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); @@ -88,6 +89,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0x55, // DCIL/SCIL 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID + 0x00, // Token Length (i), Token (*) 0x19, // Length (Not 0x09 because it will have 16 bytes of AEAD tag) 0xC1, 0x23, 0x45, 0x67, // Packet number 0x11, 0x22, 0x33, 0x44, 0x55, // Payload (dummy) @@ -99,9 +101,9 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, {reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x01234567, 0, 0x11223344, std::move(payload), 5); - CHECK(header->size() == 27); + CHECK(header->size() == sizeof(expected) - 5); CHECK(header->has_key_phase() == false); - CHECK(header->packet_size() == 32); + CHECK(header->packet_size() == sizeof(expected)); CHECK(header->type() == QUICPacketType::INITIAL); CHECK( (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); @@ -111,7 +113,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") CHECK(header->version() == 0x11223344); header->store(buf, &len); - CHECK(len == 27); + CHECK(len == header->size()); CHECK(memcmp(buf, expected, len) == 0); } } diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index cd3bb507b82..d56bc146c93 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -53,7 +53,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x55, // DCIL/SCIL 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Destination Connection ID 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection ID - 0xff, 0x00, 0x00, 0x0c, // Supported Version + 0xff, 0x00, 0x00, 0x0d, // Supported Version }; uint8_t buf[1024] = {0}; size_t buf_len; From 87526c0d9889f7660a2a416078f7b902607bd568 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 1 Aug 2018 10:19:03 +0900 Subject: [PATCH 0732/1313] [draft-13] Add NEW_TOKEN frame --- iocore/net/quic/QUICFrame.cc | 108 +++++++++++++++++++++++++ iocore/net/quic/QUICFrame.h | 47 ++++++++++- iocore/net/quic/QUICTypes.h | 1 + iocore/net/quic/test/test_QUICFrame.cc | 42 ++++++++++ 4 files changed, 197 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 25ef619f5e9..f0c47bfdbf3 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -44,6 +44,7 @@ ClassAllocator quicNewConnectionIdFrameAllocator("quic ClassAllocator quicStopSendingFrameAllocator("quicStopSendingFrameAllocator"); ClassAllocator quicPathChallengeFrameAllocator("quicPathChallengeFrameAllocator"); ClassAllocator quicPathResponseFrameAllocator("quicPathResponseFrameAllocator"); +ClassAllocator quicNewTokenFrameAllocator("quicNewTokenFrameAllocator"); ClassAllocator quicRetransmissionFrameAllocator("quicRetransmissionFrameAllocator"); QUICFrameType @@ -2211,6 +2212,101 @@ QUICPathResponseFrame::_data_offset() const return sizeof(QUICFrameType); } +// +// QUICNewTokenFrame +// +QUICFrameUPtr +QUICNewTokenFrame::clone() const +{ + return QUICFrameFactory::create_new_token_frame(this->token(), this->token_length()); +} + +QUICFrameType +QUICNewTokenFrame::type() const +{ + return QUICFrameType::NEW_TOKEN; +} + +size_t +QUICNewTokenFrame::size() const +{ + return this->_get_token_field_offset() + this->token_length(); +} + +size_t +QUICNewTokenFrame::store(uint8_t *buf, size_t *len, size_t limit) const +{ + if (limit < this->size()) { + return 0; + } + + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + uint8_t *p = buf; + + // Type (i) + *p = static_cast(QUICFrameType::NEW_TOKEN); + ++p; + + // Token Length (i) + size_t n; + QUICIntUtil::write_QUICVariableInt(this->_token_length, p, &n); + p += n; + + // Token (*) + memcpy(p, this->token(), this->token_length()); + p += this->token_length(); + + *len = p - buf; + } + + return *len; +} + +uint64_t +QUICNewTokenFrame::token_length() const +{ + if (this->_buf) { + return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_token_length_field_offset()); + } else { + return this->_token_length; + } +} + +const uint8_t * +QUICNewTokenFrame::token() const +{ + if (this->_buf) { + return this->_buf + this->_get_token_field_offset(); + } else { + return this->_token.get(); + } +} + +size_t +QUICNewTokenFrame::_get_token_length_field_offset() const +{ + return sizeof(QUICFrameType); +} + +size_t +QUICNewTokenFrame::_get_token_length_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); + } else { + return QUICVariableInt::size(this->_token_length); + } +} + +size_t +QUICNewTokenFrame::_get_token_field_offset() const +{ + return sizeof(QUICFrameType) + this->_get_token_length_field_length(); +} + // // QUICRetransmissionFrame // @@ -2361,6 +2457,10 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicPathResponseFrameAllocator.alloc(); new (frame) QUICPathResponseFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_path_response_frame); + case QUICFrameType::NEW_TOKEN: + frame = quicNewTokenFrameAllocator.alloc(); + new (frame) QUICNewTokenFrame(buf, len); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_new_token_frame); default: // Unknown frame Debug("quic_frame_factory", "Unknown frame type %x", buf[0]); @@ -2581,6 +2681,14 @@ QUICFrameFactory::create_new_connection_id_frame(uint32_t sequence, QUICConnecti return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_connection_id_frame); } +std::unique_ptr +QUICFrameFactory::create_new_token_frame(const uint8_t *token, uint64_t token_len) +{ + QUICNewTokenFrame *frame = quicNewTokenFrameAllocator.alloc(); + new (frame) QUICNewTokenFrame(token, token_len); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_token_frame); +} + std::unique_ptr QUICFrameFactory::create_retransmission_frame(QUICFrameUPtr original_frame, const QUICPacket &original_packet) { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 05f65cb911c..1d5598f9c5e 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -326,7 +326,9 @@ class QUICPingFrame : public QUICFrame private: }; +// // PADDING +// class QUICPaddingFrame : public QUICFrame { @@ -648,7 +650,37 @@ class QUICPathResponseFrame : public QUICFrame }; // -// Retransmission Frame +// NEW_TOKEN +// + +class QUICNewTokenFrame : public QUICFrame +{ +public: + QUICNewTokenFrame() : QUICFrame() {} + QUICNewTokenFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICNewTokenFrame(ats_unique_buf token, size_t token_length, bool protection = true) + : QUICFrame(protection), _token_length(token_length), _token(std::move(token)) + { + } + QUICFrameUPtr clone() const override; + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + + uint64_t token_length() const; + const uint8_t *token() const; + +private: + size_t _get_token_length_field_offset() const; + size_t _get_token_length_field_length() const; + size_t _get_token_field_offset() const; + + uint64_t _token_length = 0; + ats_unique_buf _token = {nullptr, [](void *p) { ats_free(p); }}; +}; + +// +// Retransmission Frame - Not on the spec // class QUICRetransmissionFrame : public QUICFrame @@ -688,6 +720,7 @@ extern ClassAllocator quicNewConnectionIdFrameAllocato extern ClassAllocator quicStopSendingFrameAllocator; extern ClassAllocator quicPathChallengeFrameAllocator; extern ClassAllocator quicPathResponseFrameAllocator; +extern ClassAllocator quicNewTokenFrameAllocator; extern ClassAllocator quicRetransmissionFrameAllocator; class QUICFrameDeleter @@ -826,6 +859,13 @@ class QUICFrameDeleter quicPathResponseFrameAllocator.free(static_cast(frame)); } + static void + delete_new_token_frame(QUICFrame *frame) + { + frame->~QUICFrame(); + quicNewTokenFrameAllocator.free(static_cast(frame)); + } + static void delete_retransmission_frame(QUICFrame *frame) { @@ -967,6 +1007,11 @@ class QUICFrameFactory static std::unique_ptr create_new_connection_id_frame( uint32_t sequence, QUICConnectionId connectoin_id, QUICStatelessResetToken stateless_reset_token); + /* + * Creates a NEW_TOKEN frame + */ + static std::unique_ptr create_new_token_frame(const uint8_t *token, uint64_t token_len); + /* * Creates a retransmission frame, which is very special. * This retransmission frame will be used only for retransmission and it's not a standard frame type. diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 8b4df08bb6d..b58b0070f7b 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -109,6 +109,7 @@ enum class QUICFrameType : uint8_t { PATH_RESPONSE, STREAM = 0x10, // 0x10 - 0x17 CRYPTO = 0x18, + NEW_TOKEN, UNKNOWN, }; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 6a32a469849..ad67a6f3583 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -49,6 +49,7 @@ TEST_CASE("QUICFrame Type", "[quic]") CHECK(QUICFrame::type(reinterpret_cast("\x10")) == QUICFrameType::STREAM); CHECK(QUICFrame::type(reinterpret_cast("\x17")) == QUICFrameType::STREAM); CHECK(QUICFrame::type(reinterpret_cast("\x18")) == QUICFrameType::CRYPTO); + CHECK(QUICFrame::type(reinterpret_cast("\x19")) == QUICFrameType::NEW_TOKEN); // Undefined ragne CHECK(QUICFrame::type(reinterpret_cast("\x21")) == QUICFrameType::UNKNOWN); CHECK(QUICFrame::type(reinterpret_cast("\xff")) == QUICFrameType::UNKNOWN); @@ -1133,6 +1134,47 @@ TEST_CASE("Store PATH_RESPONSE Frame", "[quic]") CHECK(memcmp(buf, expected, len) == 0); } +TEST_CASE("NEW_TOKEN Frame", "[quic]") +{ + uint8_t raw_new_token_frame[] = { + 0x19, // Type + 0x08, // Token Length (i) + 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, // Token (*) + }; + size_t raw_new_token_frame_len = sizeof(raw_new_token_frame); + + uint8_t raw_token[] = {0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef}; + size_t raw_token_len = sizeof(raw_token); + + SECTION("load") + { + std::shared_ptr frame = QUICFrameFactory::create(raw_new_token_frame, raw_new_token_frame_len); + CHECK(frame->type() == QUICFrameType::NEW_TOKEN); + CHECK(frame->size() == raw_new_token_frame_len); + + std::shared_ptr new_token_frame = std::dynamic_pointer_cast(frame); + CHECK(new_token_frame != nullptr); + CHECK(new_token_frame->token_length() == raw_token_len); + CHECK(memcmp(new_token_frame->token(), raw_token, raw_token_len) == 0); + } + + SECTION("store") + { + uint8_t buf[32]; + size_t len; + + ats_unique_buf token = ats_unique_malloc(raw_token_len); + memcpy(token.get(), raw_token, raw_token_len); + + QUICNewTokenFrame frame(std::move(token), raw_token_len); + CHECK(frame.size() == raw_new_token_frame_len); + + frame.store(buf, &len, 16); + CHECK(len == raw_new_token_frame_len); + CHECK(memcmp(buf, raw_new_token_frame, len) == 0); + } +} + TEST_CASE("QUICFrameFactory Create Unknown Frame", "[quic]") { uint8_t buf1[] = { From 34545229747c748d2b79d44353f1ced3e2a7a769 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 3 Aug 2018 09:34:15 +0900 Subject: [PATCH 0733/1313] [draft-13] Add Frame Type field in CONNECTION_CLOSE frame --- iocore/net/quic/QUICFrame.cc | 107 +++++++++++++++++++++---- iocore/net/quic/QUICFrame.h | 13 ++- iocore/net/quic/QUICTypes.cc | 7 ++ iocore/net/quic/QUICTypes.h | 9 ++- iocore/net/quic/test/test_QUICFrame.cc | 68 +++++++++------- 5 files changed, 154 insertions(+), 50 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index f0c47bfdbf3..2b3f66917c1 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -22,6 +22,9 @@ */ #include "QUICFrame.h" + +#include + #include "QUICStream.h" #include "QUICIntUtil.h" #include "QUICDebugNames.h" @@ -1211,19 +1214,21 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len, size_t limit) const // // CONNECTION_CLOSE frame // -QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint64_t reason_phrase_length, - const char *reason_phrase, bool protection) - : QUICFrame(protection) +QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode error_code, QUICFrameType frame_type, + uint64_t reason_phrase_length, const char *reason_phrase, bool protection) + : QUICFrame(protection), + _error_code(error_code), + _frame_type(frame_type), + _reason_phrase_length(reason_phrase_length), + _reason_phrase(reason_phrase) { - this->_error_code = error_code; - this->_reason_phrase_length = reason_phrase_length; - this->_reason_phrase = reason_phrase; } QUICFrameUPtr QUICConnectionCloseFrame::clone() const { - return QUICFrameFactory::create_connection_close_frame(this->error_code(), this->reason_phrase_length(), this->reason_phrase()); + return QUICFrameFactory::create_connection_close_frame(this->error_code(), this->frame_type(), this->reason_phrase_length(), + this->reason_phrase()); } QUICFrameType @@ -1235,10 +1240,16 @@ QUICConnectionCloseFrame::type() const size_t QUICConnectionCloseFrame::size() const { - return sizeof(QUICFrameType) + sizeof(QUICTransErrorCode) + this->_get_reason_phrase_length_field_length() + + return this->_get_reason_phrase_length_field_offset() + this->_get_reason_phrase_length_field_length() + this->reason_phrase_length(); } +/** + Store CONNECTION_CLOSE frame in buffer. + + PADDING frame in Frame Type field means frame type that triggered the error is unknown. + When `_frame_type` is QUICFrameType::UNKNOWN, it's converted to QUICFrameType::PADDING (0x0). + */ size_t QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const { @@ -1254,10 +1265,24 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const uint8_t *p = buf; *p = static_cast(QUICFrameType::CONNECTION_CLOSE); ++p; + + // Error Code (16) QUICTypeUtil::write_QUICTransErrorCode(this->_error_code, p, &n); p += n; + + // Frame Type (i) + QUICFrameType frame_type = this->_frame_type; + if (frame_type == QUICFrameType::UNKNOWN) { + frame_type = QUICFrameType::PADDING; + } + *p = static_cast(frame_type); + ++p; + + // Reason Phrase Length (i) QUICIntUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); p += n; + + // Reason Phrase (*) if (this->_reason_phrase_length > 0) { memcpy(p, this->_reason_phrase, this->_reason_phrase_length); p += this->_reason_phrase_length; @@ -1269,16 +1294,54 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const return *len; } +int +QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const +{ + int len = snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=%s frame=%s", this->size(), + QUICDebugNames::error_code(this->error_code()), QUICDebugNames::frame_type(this->frame_type())); + + if (this->reason_phrase_length() != 0) { + memcpy(msg + len, " reason=", 8); + len += 8; + + int phrase_len = std::min(msg_len - len, static_cast(this->reason_phrase_length())); + memcpy(msg + len, this->reason_phrase(), phrase_len); + len += phrase_len; + } + + return len; +} + QUICTransErrorCode QUICConnectionCloseFrame::error_code() const { if (this->_buf) { - return QUICTypeUtil::read_QUICTransErrorCode(this->_buf + 1); + return QUICTypeUtil::read_QUICTransErrorCode(this->_buf + sizeof(QUICFrameType)); } else { return this->_error_code; } } +/** + Frame Type Field Accessor + + PADDING frame in Frame Type field means frame type that triggered the error is unknown. + Return QUICFrameType::UNKNOWN when Frame Type field is PADDING (0x0). + */ +QUICFrameType +QUICConnectionCloseFrame::frame_type() const +{ + if (this->_buf) { + QUICFrameType frame = QUICFrame::type(this->_buf + this->_get_frame_type_field_offset()); + if (frame == QUICFrameType::PADDING) { + frame = QUICFrameType::UNKNOWN; + } + return frame; + } else { + return this->_frame_type; + } +} + uint64_t QUICConnectionCloseFrame::reason_phrase_length() const { @@ -1293,18 +1356,29 @@ const char * QUICConnectionCloseFrame::reason_phrase() const { if (this->_buf) { - return reinterpret_cast(this->_buf + this->_get_reason_phrase_field_offset()); + size_t offset = this->_get_reason_phrase_field_offset(); + if (offset > this->_len) { + return nullptr; + } else { + return reinterpret_cast(this->_buf + offset); + } } else { return this->_reason_phrase; } } size_t -QUICConnectionCloseFrame::_get_reason_phrase_length_field_offset() const +QUICConnectionCloseFrame::_get_frame_type_field_offset() const { return sizeof(QUICFrameType) + sizeof(QUICTransErrorCode); } +size_t +QUICConnectionCloseFrame::_get_reason_phrase_length_field_offset() const +{ + return this->_get_frame_type_field_offset() + sizeof(QUICFrameType); +} + size_t QUICConnectionCloseFrame::_get_reason_phrase_length_field_length() const { @@ -2533,11 +2607,11 @@ QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64 } std::unique_ptr -QUICFrameFactory::create_connection_close_frame(QUICTransErrorCode error_code, uint16_t reason_phrase_length, - const char *reason_phrase) +QUICFrameFactory::create_connection_close_frame(QUICTransErrorCode error_code, QUICFrameType frame_type, + uint16_t reason_phrase_length, const char *reason_phrase) { QUICConnectionCloseFrame *frame = quicConnectionCloseFrameAllocator.alloc(); - new (frame) QUICConnectionCloseFrame(error_code, reason_phrase_length, reason_phrase); + new (frame) QUICConnectionCloseFrame(error_code, frame_type, reason_phrase_length, reason_phrase); return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); } @@ -2546,9 +2620,10 @@ QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error) { ink_assert(error->cls == QUICErrorClass::TRANSPORT); if (error->msg) { - return QUICFrameFactory::create_connection_close_frame(error->trans_error_code, strlen(error->msg), error->msg); + return QUICFrameFactory::create_connection_close_frame(error->trans_error_code, error->frame_type(), strlen(error->msg), + error->msg); } else { - return QUICFrameFactory::create_connection_close_frame(error->trans_error_code); + return QUICFrameFactory::create_connection_close_frame(error->trans_error_code, error->frame_type()); } } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 1d5598f9c5e..d4feb26719d 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -350,22 +350,27 @@ class QUICConnectionCloseFrame : public QUICFrame public: QUICConnectionCloseFrame() : QUICFrame() {} QUICConnectionCloseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICConnectionCloseFrame(QUICTransErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase, - bool protection = true); + QUICConnectionCloseFrame(QUICTransErrorCode error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, + const char *reason_phrase, bool protection = true); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual int debug_msg(char *msg, size_t msg_len) const override; + QUICTransErrorCode error_code() const; + QUICFrameType frame_type() const; uint64_t reason_phrase_length() const; const char *reason_phrase() const; private: + size_t _get_frame_type_field_offset() const; size_t _get_reason_phrase_length_field_offset() const; size_t _get_reason_phrase_length_field_length() const; size_t _get_reason_phrase_field_offset() const; QUICTransErrorCode _error_code; + QUICFrameType _frame_type = QUICFrameType::UNKNOWN; uint64_t _reason_phrase_length = 0; const char *_reason_phrase = nullptr; }; @@ -929,7 +934,9 @@ class QUICFrameFactory * Creates a CONNECTION_CLOSE frame. */ static std::unique_ptr create_connection_close_frame( - QUICTransErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr); + QUICTransErrorCode error_code, QUICFrameType frame_type, uint16_t reason_phrase_length = 0, + const char *reason_phrase = nullptr); + static std::unique_ptr create_connection_close_frame( QUICConnectionErrorUPtr error); diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 0577d45cce9..46988230136 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -280,6 +280,13 @@ QUICError::code() return static_cast(this->trans_error_code); } +QUICFrameType +QUICConnectionError::frame_type() const +{ + ink_assert(this->cls != QUICErrorClass::APPLICATION); + return _frame_type; +} + // // QUICFiveTuple // diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index b58b0070f7b..c3f53f00255 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -197,8 +197,15 @@ class QUICConnectionError : public QUICError { public: QUICConnectionError() : QUICError() {} - QUICConnectionError(const QUICTransErrorCode error_code, const char *error_msg = nullptr) : QUICError(error_code, error_msg){}; + QUICConnectionError(const QUICTransErrorCode error_code, const char *error_msg = nullptr, + QUICFrameType frame_type = QUICFrameType::UNKNOWN) + : QUICError(error_code, error_msg), _frame_type(frame_type){}; QUICConnectionError(const QUICAppErrorCode error_code, const char *error_msg = nullptr) : QUICError(error_code, error_msg){}; + + QUICFrameType frame_type() const; + +private: + QUICFrameType _frame_type = QUICFrameType::UNKNOWN; }; class QUICStream; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index ad67a6f3583..1a8843a2e44 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -624,82 +624,89 @@ TEST_CASE("Store Padding Frame", "[quic]") CHECK(memcmp(buf, expected, len) == 0); } -TEST_CASE("Load ConnectionClose Frame", "[quic]") +TEST_CASE("ConnectionClose Frame", "[quic]") { - SECTION("w/ reason phrase") + uint8_t reason_phrase[] = {0x41, 0x42, 0x43, 0x44, 0x45}; + size_t reason_phrase_len = sizeof(reason_phrase); + + SECTION("loading w/ reason phrase") { - uint8_t buf1[] = { + uint8_t buf[] = { 0x02, // Type 0x00, 0x0A, // Error Code + 0x00, // Frame Type 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::CONNECTION_CLOSE); - CHECK(frame1->size() == 9); + + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::CONNECTION_CLOSE); + CHECK(frame->size() == sizeof(buf)); std::shared_ptr conn_close_frame = - std::dynamic_pointer_cast(frame1); + std::dynamic_pointer_cast(frame); CHECK(conn_close_frame != nullptr); CHECK(conn_close_frame->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION); - CHECK(conn_close_frame->reason_phrase_length() == 5); - CHECK(memcmp(conn_close_frame->reason_phrase(), buf1 + 4, 5) == 0); + CHECK(conn_close_frame->frame_type() == QUICFrameType::UNKNOWN); + CHECK(conn_close_frame->reason_phrase_length() == reason_phrase_len); + CHECK(memcmp(conn_close_frame->reason_phrase(), reason_phrase, reason_phrase_len) == 0); } - SECTION("w/o reason phrase") + SECTION("loading w/o reason phrase") { - uint8_t buf2[] = { + uint8_t buf[] = { 0x02, // Type 0x00, 0x0A, // Error Code + 0x01, // Frame Type 0x00, // Reason Phrase Length }; - std::shared_ptr frame2 = QUICFrameFactory::create(buf2, sizeof(buf2)); - CHECK(frame2->type() == QUICFrameType::CONNECTION_CLOSE); - CHECK(frame2->size() == 4); + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::CONNECTION_CLOSE); + CHECK(frame->size() == sizeof(buf)); std::shared_ptr conn_close_frame = - std::dynamic_pointer_cast(frame2); + std::dynamic_pointer_cast(frame); CHECK(conn_close_frame != nullptr); CHECK(conn_close_frame->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION); + CHECK(conn_close_frame->frame_type() == QUICFrameType::RST_STREAM); CHECK(conn_close_frame->reason_phrase_length() == 0); } -} -TEST_CASE("Store ConnectionClose Frame", "[quic]") -{ - SECTION("w/ reason phrase") + SECTION("storing w/ reason phrase") { uint8_t buf[32]; size_t len; - uint8_t expected1[] = { + uint8_t expected[] = { 0x02, // Type 0x00, 0x0A, // Error Code + 0x10, // Frame Type 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; - QUICConnectionCloseFrame connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, 5, "ABCDE"); - CHECK(connection_close_frame.size() == 9); + QUICConnectionCloseFrame connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, QUICFrameType::STREAM, 5, "ABCDE"); + CHECK(connection_close_frame.size() == sizeof(expected)); connection_close_frame.store(buf, &len, 32); - CHECK(len == 9); - CHECK(memcmp(buf, expected1, len) == 0); + CHECK(len == sizeof(expected)); + CHECK(memcmp(buf, expected, len) == 0); } - SECTION("w/o reason phrase") + SECTION("storing w/o reason phrase") { uint8_t buf[32]; size_t len; - uint8_t expected2[] = { + uint8_t expected[] = { 0x02, // Type 0x00, 0x0A, // Error Code + 0x00, // Frame Type 0x00, // Reason Phrase Length }; - QUICConnectionCloseFrame connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, 0, nullptr); + QUICConnectionCloseFrame connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, QUICFrameType::UNKNOWN, 0, nullptr); connection_close_frame.store(buf, &len, 32); - CHECK(len == 4); - CHECK(memcmp(buf, expected2, len) == 0); + CHECK(len == sizeof(expected)); + CHECK(memcmp(buf, expected, len) == 0); } } @@ -1367,6 +1374,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") uint8_t frame_buf[] = { 0x02, // Type 0x00, 0x0A, // Error Code + 0x00, // Frame Type 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; @@ -1378,7 +1386,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") size_t len; frame->store(buf, &len, 32); - CHECK(len == 9); + CHECK(len == sizeof(frame_buf)); CHECK(memcmp(buf, frame_buf, len) == 0); } From 17e6ab5be1704105eef4a8a721b81cec00d326e0 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 3 Aug 2018 10:33:18 +0900 Subject: [PATCH 0734/1313] Check value of Reason Phrase Length of CONNECTION_CLOSE frame --- iocore/net/quic/QUICFrame.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 2b3f66917c1..7aca81b87dc 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1300,7 +1300,7 @@ QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const int len = snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=%s frame=%s", this->size(), QUICDebugNames::error_code(this->error_code()), QUICDebugNames::frame_type(this->frame_type())); - if (this->reason_phrase_length() != 0) { + if (this->reason_phrase_length() != 0 && this->reason_phrase() != nullptr) { memcpy(msg + len, " reason=", 8); len += 8; @@ -1346,7 +1346,13 @@ uint64_t QUICConnectionCloseFrame::reason_phrase_length() const { if (this->_buf) { - return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_reason_phrase_length_field_offset()); + size_t offset = this->_get_reason_phrase_length_field_offset(); + uint64_t reason_phrase_len = QUICIntUtil::read_QUICVariableInt(this->_buf + offset); + if (reason_phrase_len > this->_len - offset) { + reason_phrase_len = this->_len - offset; + } + + return reason_phrase_len; } else { return this->_reason_phrase_length; } From 795ba9b89e788858e470138dfc9958a4f4c37205 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 3 Aug 2018 14:00:09 +0900 Subject: [PATCH 0735/1313] Print maximum_(stream)_data on debug log --- iocore/net/quic/QUICFrame.cc | 12 ++++++++++++ iocore/net/quic/QUICFrame.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 7aca81b87dc..71ae8963f28 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1564,6 +1564,12 @@ QUICMaxDataFrame::store(uint8_t *buf, size_t *len, size_t limit) const return *len; } +int +QUICMaxDataFrame::debug_msg(char *msg, size_t msg_len) const +{ + return snprintf(msg, msg_len, "| MAX_DATA size=%zu maximum=%" PRIu64, this->size(), this->maximum_data()); +} + uint64_t QUICMaxDataFrame::maximum_data() const { @@ -1636,6 +1642,12 @@ QUICMaxStreamDataFrame::store(uint8_t *buf, size_t *len, size_t limit) const return *len; } +int +QUICMaxStreamDataFrame::debug_msg(char *msg, size_t msg_len) const +{ + return snprintf(msg, msg_len, "| MAX_STREAM_DATA size=%zu maximum=%" PRIu64, this->size(), this->maximum_stream_data()); +} + QUICStreamId QUICMaxStreamDataFrame::stream_id() const { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index d4feb26719d..a82ac077587 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -418,6 +418,8 @@ class QUICMaxDataFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual int debug_msg(char *msg, size_t msg_len) const override; + uint64_t maximum_data() const; private: @@ -440,6 +442,8 @@ class QUICMaxStreamDataFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual int debug_msg(char *msg, size_t msg_len) const override; + QUICStreamId stream_id() const; uint64_t maximum_stream_data() const; From c0f4400280d8ac033c497ab1f598a7526f1aefec Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 3 Aug 2018 16:23:48 +0900 Subject: [PATCH 0736/1313] Remove unnecessary checks before generate_frame() calls --- iocore/net/QUICNetVConnection.cc | 73 +++++++++++++++----------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 93e8143d906..f9f48f15536 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1305,35 +1305,36 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } // CRYPTO - if (this->_handshake_handler->will_generate_frame(level)) { + frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); + while (frame) { + ++frame_count; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); - while (frame) { - ++frame_count; - this->_store_frame(buf, len, max_frame_size, std::move(frame)); - frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); - } } // ACK - if (this->_ack_frame_creator.will_generate_frame(level)) { - frame = this->_ack_frame_creator.generate_frame(level, UINT16_MAX, max_frame_size); - if (frame != nullptr) { - ++frame_count; - this->_store_frame(buf, len, max_frame_size, std::move(frame)); + if (will_be_ack_only) { + if (this->_ack_frame_creator.will_generate_frame(level)) { + frame = this->_ack_frame_creator.generate_frame(level, UINT16_MAX, max_frame_size); } + } else { + frame = this->_ack_frame_creator.generate_frame(level, UINT16_MAX, max_frame_size); + } + + if (frame != nullptr) { + ++frame_count; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); } // PATH_CHALLENGE, PATH_RESPOSNE - if (this->_path_validator->will_generate_frame(level)) { - frame = this->_path_validator->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); - if (frame) { - ++frame_count; - this->_store_frame(buf, len, max_frame_size, std::move(frame)); - } + frame = this->_path_validator->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + if (frame) { + ++frame_count; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); } // NEW_CONNECTION_ID - if (this->_alt_con_manager && this->_alt_con_manager->will_generate_frame(level)) { + if (this->_alt_con_manager) { frame = this->_alt_con_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); while (frame) { ++frame_count; @@ -1344,31 +1345,27 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } // Lost frames - if (this->_packet_retransmitter.will_generate_frame(level)) { - frame = this->_packet_retransmitter.generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); - while (frame) { - ++frame_count; - this->_store_frame(buf, len, max_frame_size, std::move(frame)); + frame = this->_packet_retransmitter.generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + while (frame) { + ++frame_count; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); - frame = this->_packet_retransmitter.generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); - } + frame = this->_packet_retransmitter.generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); } // STREAM, MAX_STREAM_DATA, STREAM_BLOCKED - if (this->_stream_manager->will_generate_frame(level)) { - frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); - while (frame) { - ++frame_count; - if (frame->type() == QUICFrameType::STREAM) { - int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); - QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); - ink_assert(ret == 0); - } - this->_store_frame(buf, len, max_frame_size, std::move(frame)); - - frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + while (frame) { + ++frame_count; + if (frame->type() == QUICFrameType::STREAM) { + int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); + QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); + ink_assert(ret == 0); } + this->_store_frame(buf, len, max_frame_size, std::move(frame)); + + frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); } // Schedule a packet From d924cd877b731fcfd5fa283b3efa9f627ce7d35a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 7 Aug 2018 10:50:19 +0900 Subject: [PATCH 0737/1313] Fix test_QUICHandshakeProtocol --- iocore/net/quic/test/test_QUICHandshakeProtocol.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 1aa21728157..a1b567eda05 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -161,6 +161,9 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +#ifdef SSL_MODE_QUIC_HACK + SSL_CTX_set_mode(client_ssl_ctx, SSL_MODE_QUIC_HACK); +#endif QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); // Server @@ -168,6 +171,9 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +#ifdef SSL_MODE_QUIC_HACK + SSL_CTX_set_mode(server_ssl_ctx, SSL_MODE_QUIC_HACK); +#endif BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); @@ -207,8 +213,6 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") std::cout << "### Messages from client" << std::endl; print_hex(msg3.buf, msg3.offsets[4]); - CHECK(client->update_key_materials()); - // NS QUICHandshakeMsgs msg4; uint8_t msg4_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; @@ -219,8 +223,6 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") std::cout << "### Messages from server" << std::endl; print_hex(msg4.buf, msg4.offsets[4]); - CHECK(server->update_key_materials()); - // encrypt - decrypt // client (encrypt) - server (decrypt) std::cout << "### Original Text" << std::endl; From bc126992c7d95d7a28b34e32e9a47f8a87d33984 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 7 Aug 2018 15:25:00 +0900 Subject: [PATCH 0738/1313] Fix test_QUICHandshakeProtocol for OpenSSL with SSL_MODE_QUIC_HACK It looks like OpenSSL with SSL_MODE_QUIC_HACK process only one encryption level on one SSL_do_handshake call. This behaivior might be different for each TLS stack. --- .../quic/test/test_QUICHandshakeProtocol.cc | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index a1b567eda05..4e46c3e04a7 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -189,7 +189,7 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") msg1.buf = msg1_buf; msg1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - CHECK(client->handshake(&msg1, nullptr) == 1); + REQUIRE(client->handshake(&msg1, nullptr) == 1); std::cout << "### Messages from client" << std::endl; print_hex(msg1.buf, msg1.offsets[4]); @@ -199,7 +199,7 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") msg2.buf = msg2_buf; msg2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - CHECK(server->handshake(&msg2, &msg1) == 1); + REQUIRE(server->handshake(&msg2, &msg1) == 1); std::cout << "### Messages from server" << std::endl; print_hex(msg2.buf, msg2.offsets[4]); @@ -209,7 +209,40 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") msg3.buf = msg3_buf; msg3.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - CHECK(client->handshake(&msg3, &msg2) == 1); +#ifdef SSL_MODE_QUIC_HACK + // -- Hacks for OpenSSL with SSL_MODE_QUIC_HACK -- + // SH + QUICHandshakeMsgs msg2_1; + uint8_t msg2_1_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2_1.buf = msg2_1_buf; + msg2_1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + memcpy(msg2_1.buf, msg2.buf, msg2.offsets[1]); + msg2_1.offsets[0] = 0; + msg2_1.offsets[1] = msg2.offsets[1]; + msg2_1.offsets[2] = msg2.offsets[1]; + msg2_1.offsets[3] = msg2.offsets[1]; + msg2_1.offsets[4] = msg2.offsets[1]; + + // EE - FIN + QUICHandshakeMsgs msg2_2; + uint8_t msg2_2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2_2.buf = msg2_2_buf; + msg2_2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + size_t len = msg2.offsets[3] - msg2.offsets[2]; + memcpy(msg2_2.buf, msg2.buf + msg2.offsets[1], len); + msg2_2.offsets[0] = 0; + msg2_2.offsets[1] = 0; + msg2_2.offsets[2] = 0; + msg2_2.offsets[3] = len; + msg2_2.offsets[4] = len; + + REQUIRE(client->handshake(&msg3, &msg2_1) == 1); + REQUIRE(client->handshake(&msg3, &msg2_2) == 1); +#else + REQUIRE(client->handshake(&msg3, &msg2) == 1); +#endif std::cout << "### Messages from client" << std::endl; print_hex(msg3.buf, msg3.offsets[4]); @@ -219,7 +252,7 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") msg4.buf = msg4_buf; msg4.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - CHECK(server->handshake(&msg4, &msg3) == 1); + REQUIRE(server->handshake(&msg4, &msg3) == 1); std::cout << "### Messages from server" << std::endl; print_hex(msg4.buf, msg4.offsets[4]); From da7f40841303b9b36617f0f8cc2decd0a2eefee9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 7 Aug 2018 15:50:43 +0900 Subject: [PATCH 0739/1313] Ignore ZERO_RTT_PROTECTED packet on state_connection_established --- iocore/net/QUICNetVConnection.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index f9f48f15536..6cc1c756223 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1017,6 +1017,12 @@ QUICNetVConnection::_state_common_receive_packet() // 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(std::move(p)); break; + case QUICPacketType::ZERO_RTT_PROTECTED: + // Probably retransmitted unintentionally. Do nothing. + QUICConDebug("Ignore %s(%" PRIu8 ")", QUICDebugNames::packet_type(p->type()), static_cast(p->type())); + + error = QUICErrorUPtr(new QUICNoError()); + break; default: QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(p->type()), static_cast(p->type())); From 1fdeea385abbe66f2e2ed051a46a54716e08e038 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 8 Aug 2018 11:53:36 +0900 Subject: [PATCH 0740/1313] Process 0-RTT packet on state_connection_established Some client send STREAM frame on 0-RTT packet after handshake is completed. Need to clarify, but it looks not prohibited in draft-13. --- iocore/net/QUICNetVConnection.cc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6cc1c756223..6b92aed0389 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1014,15 +1014,10 @@ QUICNetVConnection::_state_common_receive_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(std::move(p)); break; - case QUICPacketType::ZERO_RTT_PROTECTED: - // Probably retransmitted unintentionally. Do nothing. - QUICConDebug("Ignore %s(%" PRIu8 ")", QUICDebugNames::packet_type(p->type()), static_cast(p->type())); - - error = QUICErrorUPtr(new QUICNoError()); - break; default: QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(p->type()), static_cast(p->type())); From fad804a84d1a45f7ac4f24baea0d5838e15476db Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 8 Aug 2018 16:48:51 +0900 Subject: [PATCH 0741/1313] Erase "ack_only" lost packet correctly To avoid heap-use-after-free caused by erasing elements in the loop --- iocore/net/quic/QUICLossDetector.cc | 48 +++++++++++++++++++---------- iocore/net/quic/QUICLossDetector.h | 3 ++ 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index c6a50145d11..2773d80ed88 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -427,36 +427,39 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num delay_until_lost = 5.0 / 4.0 * std::max(this->_latest_rtt, this->_smoothed_rtt); } - for (auto &unacked : this->_sent_packets) { - if (unacked.first >= largest_acked_packet_number) { + for (auto it = this->_sent_packets.begin(); it != this->_sent_packets.end();) { + if (it->first >= largest_acked_packet_number) { break; } - ink_hrtime time_since_sent = Thread::get_hrtime() - unacked.second->time; - uint64_t delta = largest_acked_packet_number - unacked.second->packet_number; + ink_hrtime time_since_sent = Thread::get_hrtime() - it->second->time; + uint64_t delta = largest_acked_packet_number - it->second->packet_number; if (time_since_sent > delay_until_lost || delta > this->_reordering_threshold) { if (time_since_sent > delay_until_lost) { QUICLDDebug("Lost: time since sent is too long (PN=%" PRId64 " sent=%" PRId64 ", delay=%lf, fraction=%lf, lrtt=%" PRId64 ", srtt=%" PRId64 ")", - unacked.first, time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, + it->first, time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, this->_smoothed_rtt); } else { QUICLDDebug("Lost: packet delta is too large (PN=%" PRId64 " largest=%" PRId64 " unacked=%" PRId64 " threshold=%" PRId32 ")", - unacked.first, largest_acked_packet_number, unacked.second->packet_number, this->_reordering_threshold); + it->first, largest_acked_packet_number, it->second->packet_number, this->_reordering_threshold); } - if (!unacked.second->ack_only) { - lost_packets.insert({unacked.first, unacked.second.get()}); + if (!it->second->ack_only) { + lost_packets.insert({it->first, it->second.get()}); } else { // -- ADDITIONAL CODE -- // We remove only "ack-only" packets for life time management of packets. // Packets in lost_packets will be removed from sent_packet later. - this->_remove_from_sent_packet_list(unacked.first); + it = this->_remove_from_sent_packet_list(it); + continue; // -- END OF ADDITIONAL CODE -- } } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) { this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent; } + + ++it; } // Inform the congestion controller of lost packets and @@ -582,21 +585,34 @@ QUICLossDetector::_remove_from_sent_packet_list(QUICPacketNumber packet_number) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - // Decrement counters auto ite = this->_sent_packets.find(packet_number); - if (ite != this->_sent_packets.end()) { - if (ite->second->handshake) { + this->_decrement_outstanding_counters(ite); + this->_sent_packets.erase(packet_number); +} + +std::map::iterator +QUICLossDetector::_remove_from_sent_packet_list(std::map::iterator it) +{ + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); + + this->_decrement_outstanding_counters(it); + return this->_sent_packets.erase(it); +} + +void +QUICLossDetector::_decrement_outstanding_counters(std::map::iterator it) +{ + if (it != this->_sent_packets.end()) { + // Decrement counters + if (it->second->handshake) { ink_assert(this->_handshake_outstanding.load() > 0); --this->_handshake_outstanding; } - if (!ite->second->ack_only) { + if (!it->second->ack_only) { ink_assert(this->_retransmittable_outstanding.load() > 0); --this->_retransmittable_outstanding; } } - - // Remove from the list - this->_sent_packets.erase(packet_number); } ink_hrtime diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 48249a11330..4bb26ec396f 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -163,6 +163,9 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler std::atomic _retransmittable_outstanding; void _add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr packet_info); void _remove_from_sent_packet_list(QUICPacketNumber packet_number); + std::map::iterator _remove_from_sent_packet_list( + std::map::iterator it); + void _decrement_outstanding_counters(std::map::iterator it); /* * Because this alarm will be reset on every packet transmission, to reduce number of events, From cbc81bcc4aae47bd4c37a28bb4ec74b39c0648e7 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 9 Aug 2018 08:45:14 +0800 Subject: [PATCH 0742/1313] Release ssl in QUICTLS destructor --- iocore/net/quic/QUICTLS.cc | 2 ++ .../net/quic/test/test_QUICHandshakeProtocol.cc | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 1923e0176e0..862c25d9ce4 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -33,6 +33,8 @@ constexpr static char tag[] = "quic_tls"; QUICTLS::~QUICTLS() { + SSL_free(this->_ssl); + delete this->_client_pp; delete this->_server_pp; } diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 4e46c3e04a7..22bbfe803db 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -175,11 +175,19 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") SSL_CTX_set_mode(server_ssl_ctx, SSL_MODE_QUIC_HACK); #endif BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); - SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); + X509 *x509 = PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr); + SSL_CTX_use_certificate(server_ssl_ctx, x509); BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); - SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); + EVP_PKEY *pkey = PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr); + SSL_CTX_use_PrivateKey(server_ssl_ctx, pkey); QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + BIO_free(crt_bio); + BIO_free(key_bio); + + X509_free(x509); + EVP_PKEY_free(pkey); + CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); @@ -282,6 +290,9 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") // Teardown delete client; delete server; + + SSL_CTX_free(server_ssl_ctx); + SSL_CTX_free(client_ssl_ctx); } // // HRR - Incorrect DHE Share From a9a689061d75b1024bba6eff25170aa1705b8a0e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 14 Aug 2018 14:47:09 +0900 Subject: [PATCH 0743/1313] Check state of handshake before change encryption level To avoid sending CONNECTION_CLOSE (TRANSPORT_PARAMETER_ERROR) on 1-RTT packet when handshake is aborted by TP validation. --- iocore/net/quic/QUICHandshake.cc | 2 ++ iocore/net/quic/QUICHandshakeProtocol.h | 1 + iocore/net/quic/QUICTLS.cc | 8 ++++++++ iocore/net/quic/QUICTLS.h | 8 ++++++++ iocore/net/quic/QUICTLS_openssl.cc | 6 +++++- 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index f6ea128eb68..637b8cc2125 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -471,5 +471,7 @@ QUICHandshake::_abort_handshake(QUICTransErrorCode code) { QUICHSDebug("Abort Handshake"); + this->_hs_protocol->abort_handshake(); + this->_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(code))); } diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 9556155d854..88dc369d3b9 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -85,4 +85,5 @@ class QUICHandshakeProtocol virtual bool decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const = 0; virtual QUICEncryptionLevel current_encryption_level() const = 0; + virtual void abort_handshake() = 0; }; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 862c25d9ce4..fb8803e8dc7 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -128,6 +128,14 @@ QUICTLS::current_encryption_level() const return this->_current_level; } +void +QUICTLS::abort_handshake() +{ + this->_state = HandshakeState::ABORTED; + + return; +} + void QUICTLS::_update_encryption_level(QUICEncryptionLevel level) { diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index c070cbbd7c0..81fd96deed6 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -43,6 +43,12 @@ class QUICTLS : public QUICHandshakeProtocol QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless); ~QUICTLS(); + // TODO: integrate with _early_data_processed + enum class HandshakeState { + PROCESSING, + ABORTED, + }; + static QUICEncryptionLevel get_encryption_level(int msg_type); int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) override; @@ -61,6 +67,7 @@ class QUICTLS : public QUICHandshakeProtocol bool decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const override; QUICEncryptionLevel current_encryption_level() const override; + void abort_handshake() override; // FIXME SSL handle should not be exported SSL *ssl_handle(); @@ -95,4 +102,5 @@ class QUICTLS : public QUICHandshakeProtocol bool _early_data_processed = false; bool _early_data = true; QUICEncryptionLevel _current_level = QUICEncryptionLevel::INITIAL; + HandshakeState _state = HandshakeState::PROCESSING; }; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 7cb1a7a002d..9c1be675b66 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -183,6 +183,10 @@ key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, const void QUICTLS::update_key_materials_on_key_cb(std::unique_ptr km, int name) { + if (this->_state == HandshakeState::ABORTED) { + return; + } + switch (name) { case SSL_KEY_CLIENT_EARLY_TRAFFIC: // this->_update_encryption_level(QUICEncryptionLevel::ZERO_RTT); @@ -251,7 +255,7 @@ int QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) { ink_assert(this->_ssl != nullptr); - if (SSL_is_init_finished(this->_ssl)) { + if (SSL_is_init_finished(this->_ssl) || this->_state == HandshakeState::ABORTED) { return 0; } From 969ac3dc255b463dd79bd75f3a0eade7b099418f Mon Sep 17 00:00:00 2001 From: sunwei Date: Sat, 4 Aug 2018 16:42:26 +0800 Subject: [PATCH 0744/1313] process early protected data during handshake --- iocore/net/quic/QUICPacket.cc | 5 +++++ iocore/net/quic/QUICPacket.h | 1 + iocore/net/quic/QUICPacketReceiveQueue.cc | 9 +++++++++ 3 files changed, 15 insertions(+) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 4731b7e2505..82e0f788a22 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -1233,6 +1233,11 @@ QUICPacketFactory::set_hs_protocol(QUICHandshakeProtocol *hs_protocol) this->_hs_protocol = hs_protocol; } +bool +QUICPacketFactory::is_ready_to_create_protected_packet() +{ + return this->_hs_protocol->is_handshake_finished(); +} // // QUICPacketNumberGenerator // diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 1aadc805871..b43b4e4c83a 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -401,6 +401,7 @@ class QUICPacketFactory ats_unique_buf payload, size_t len, bool retransmittable); void set_version(QUICVersion negotiated_version); void set_hs_protocol(QUICHandshakeProtocol *hs_protocol); + bool is_ready_to_create_protected_packet(); private: QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index fb09a870254..9b0a837b56f 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -156,6 +156,15 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) this->_offset = 0; } } else { + if (!this->_packet_factory.is_ready_to_create_protected_packet() && udp_packet) { + this->enqueue(udp_packet); + this->_payload.release(); + this->_payload = nullptr; + this->_payload_len = 0; + this->_offset = 0; + result = QUICPacketCreationResult::NOT_READY; + return quic_packet; + } pkt = std::move(this->_payload); pkt_len = this->_payload_len; this->_payload = nullptr; From 90e21a372a1a1620b1e53f82be3719662a56916a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 20 Aug 2018 14:32:19 +0900 Subject: [PATCH 0745/1313] Add sageguard on sending packet --- iocore/net/QUICNetVConnection.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6b92aed0389..87b5ed19884 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -63,6 +63,7 @@ static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; // static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(20); +static constexpr uint32_t PACKET_PRE_EVENT = 32; static constexpr uint32_t MAX_PACKETS_WITHOUT_SRC_ADDR_VARIDATION = 3; @@ -1082,8 +1083,7 @@ QUICNetVConnection::_state_common_send_packet() { uint32_t packet_count = 0; uint32_t error = 0; - while (error == 0) { - // TODO: add safeguard like FRAME_PER_EVENT + while (error == 0 && packet_count < PACKET_PRE_EVENT) { uint32_t window = this->_congestion_controller->open_window(); if (window == 0) { From 4b13b8c5d2f7d60b44522d43476fe4e77970f54a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 21 Aug 2018 16:24:29 +0900 Subject: [PATCH 0746/1313] Fix retransmittable flag on packetizing frames --- iocore/net/QUICNetVConnection.cc | 16 +++++++++------- iocore/net/quic/QUICPacket.cc | 5 +++-- iocore/net/quic/QUICPacket.h | 3 ++- .../net/quic/test/test_QUICVersionNegotiator.cc | 8 ++++---- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 87b5ed19884..e43d9c4cdd3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1293,16 +1293,15 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa size_t len = 0; ats_unique_buf buf = ats_unique_malloc(max_packet_size); QUICFrameUPtr frame(nullptr, nullptr); - bool retransmittable = false; SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); - bool will_be_ack_only = true; + bool ack_only = true; if (this->_connection_error || this->_packet_retransmitter.will_generate_frame(level) || this->_handshake_handler->will_generate_frame(level) || this->_stream_manager->will_generate_frame(level) || this->_path_validator->will_generate_frame(level)) { - will_be_ack_only = false; + ack_only = false; } // CRYPTO @@ -1314,7 +1313,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } // ACK - if (will_be_ack_only) { + if (ack_only) { if (this->_ack_frame_creator.will_generate_frame(level)) { frame = this->_ack_frame_creator.generate_frame(level, UINT16_MAX, max_frame_size); } @@ -1382,7 +1381,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } } - packet = this->_build_packet(level, std::move(buf), len, retransmittable); + // Packet is retransmittable if it's not ack only packet + packet = this->_build_packet(level, std::move(buf), len, !ack_only); } return packet; @@ -1440,6 +1440,7 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) int ret = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); QUICFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), this->_local_flow_controller->current_limit()); + if (ret != 0) { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } @@ -1464,8 +1465,9 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi case QUICPacketType::INITIAL: { QUICConnectionId dcid = (this->netvc_context == NET_VCONNECTION_OUT) ? this->_original_quic_connection_id : this->_peer_quic_connection_id; - packet = this->_packet_factory.create_initial_packet( - dcid, this->_quic_connection_id, this->largest_acked_packet_number(QUICEncryptionLevel::INITIAL), std::move(buf), len); + packet = this->_packet_factory.create_initial_packet(dcid, this->_quic_connection_id, + this->largest_acked_packet_number(QUICEncryptionLevel::INITIAL), + std::move(buf), len, retransmittable); break; } case QUICPacketType::RETRY: { diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 82e0f788a22..ebd9f68d87a 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -1117,13 +1117,14 @@ QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUIC QUICPacketUPtr QUICPacketFactory::create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, - QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len) + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, + bool retransmittable) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); QUICPacketNumber pn = this->_packet_number_generator[index].next(); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, destination_cid, source_cid, pn, base_packet_number, this->_version, std::move(payload), len); - return this->_create_encrypted_packet(std::move(header), true); + return this->_create_encrypted_packet(std::move(header), retransmittable); } QUICPacketUPtr diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index b43b4e4c83a..4760bf274cd 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -391,7 +391,8 @@ class QUICPacketFactory QUICPacketUPtr create(IpEndpoint from, 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); + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, + bool retransmittable); QUICPacketUPtr create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, ats_unique_buf payload, size_t len, bool retransmittable); QUICPacketUPtr create_handshake_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 78142b62bda..a4e6842e90b 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -40,7 +40,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -58,7 +58,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -76,7 +76,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); @@ -118,7 +118,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true); // Server send VN packet based on Initial packet QUICPacketUPtr vn_packet = From 516db1abea0671c6ce18437dd48e1c6016d7c7a8 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 22 Aug 2018 10:37:24 +0900 Subject: [PATCH 0747/1313] Fix unit tests --- iocore/net/quic/Mock.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 05789321342..1bc08a48625 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -607,6 +607,12 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol { return QUICEncryptionLevel::INITIAL; } + + void + abort_handshake() override + { + return; + } }; class MockContinuation : public Continuation From 45a5cdc92d4733141eeaf258df46c1c362890bb0 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 22 Aug 2018 12:16:13 +0900 Subject: [PATCH 0748/1313] Cleanup: Remove QUICAckFrameCreator::_create_frame() --- iocore/net/quic/QUICAckFrameCreator.cc | 9 +-------- iocore/net/quic/QUICAckFrameCreator.h | 1 - 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 77be5628343..cdfda9467e0 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -52,7 +52,7 @@ QUICAckFrameCreator::update(QUICEncryptionLevel level, QUICPacketNumber packet_n } QUICFrameUPtr -QUICAckFrameCreator::_create_frame(QUICEncryptionLevel level) +QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { QUICFrameUPtr ack_frame = QUICFrameFactory::create_null_frame(); @@ -136,13 +136,6 @@ QUICAckFrameCreator::will_generate_frame(QUICEncryptionLevel level) return this->_should_send[index]; } -QUICFrameUPtr -QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) -{ - // FIXME fix size - return this->_create_frame(level); -} - uint64_t QUICAckFrameCreator::_calculate_delay(QUICEncryptionLevel level) { diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 4b69fcbc4b4..63c18f6abdc 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -79,7 +79,6 @@ class QUICAckFrameCreator : public QUICFrameGenerator * Returns QUICAckFrame only if ACK frame is able to be sent. * Caller must send the ACK frame to the peer if it was returned. */ - QUICFrameUPtr _create_frame(QUICEncryptionLevel level); QUICFrameUPtr _create_ack_frame(QUICEncryptionLevel level); uint64_t _calculate_delay(QUICEncryptionLevel level); std::vector From cfecee8a4e42b3b7d3d8afaf31970791dd0523cc Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 22 Aug 2018 16:00:23 +0900 Subject: [PATCH 0749/1313] Fix MAX_PACKET_OVERHEAD (INITIAL packet has token field from draft-13) --- iocore/net/QUICNetVConnection.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e43d9c4cdd3..8562d5cb668 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -58,7 +58,7 @@ static constexpr std::string_view QUIC_DEBUG_TAG = "quic_net"sv; static constexpr uint32_t IPV4_HEADER_SIZE = 20; static constexpr uint32_t IPV6_HEADER_SIZE = 40; static constexpr uint32_t UDP_HEADER_SIZE = 8; -static constexpr uint32_t MAX_PACKET_OVERHEAD = 54; // Max long header len +static constexpr uint32_t MAX_PACKET_OVERHEAD = 62; // Max long header len without length of token field of Initial packet static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; // static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; @@ -1286,6 +1286,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa return packet; } + // TODO: adjust MAX_PACKET_OVERHEAD for each encryption level uint64_t max_frame_size = max_packet_size - MAX_PACKET_OVERHEAD; max_frame_size = std::min(max_frame_size, this->_maximum_stream_frame_data_size()); From 49f8be8763e60c2ee4c13c5d10956e2059cc712c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 22 Aug 2018 16:02:20 +0900 Subject: [PATCH 0750/1313] Check frame size when AckFrameCreator/AltConnectionManager/PathValidator generate frame --- iocore/net/quic/QUICAckFrameCreator.cc | 13 +++++++++---- iocore/net/quic/QUICAltConnectionManager.cc | 10 ++++++++-- iocore/net/quic/QUICPathValidator.cc | 19 +++++++++++++++---- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index cdfda9467e0..239aff0e53a 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -64,10 +64,15 @@ QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connecti if (this->_can_send[index]) { QUICAckPacketNumbers *packet_numbers = &this->_packet_numbers[index]; - ack_frame = this->_create_ack_frame(level); - this->_can_send[index] = false; - this->_should_send[index] = false; - packet_numbers->clear(); + ack_frame = this->_create_ack_frame(level); + if (ack_frame && ack_frame->size() > maximum_frame_size) { + // Cancel generating frame + ack_frame = QUICFrameFactory::create_null_frame(); + } else { + this->_can_send[index] = false; + this->_should_send[index] = false; + packet_numbers->clear(); + } } return ack_frame; diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 4ad73f737f7..feb1aa8646a 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -116,9 +116,15 @@ QUICAltConnectionManager::generate_frame(QUICEncryptionLevel level, uint64_t con int count = this->_nids; for (int i = 0; i < count; ++i) { if (!this->_alt_quic_connection_ids[i].advertised) { - this->_alt_quic_connection_ids[i].advertised = true; - return QUICFrameFactory::create_new_connection_id_frame( + frame = QUICFrameFactory::create_new_connection_id_frame( this->_alt_quic_connection_ids[i].seq_num, this->_alt_quic_connection_ids[i].id, this->_alt_quic_connection_ids[i].token); + + if (frame && frame->size() > maximum_frame_size) { + // Cancel generating frame + frame = QUICFrameFactory::create_null_frame(); + } else { + this->_alt_quic_connection_ids[i].advertised = true; + } } } this->_need_advertise = false; diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index 53db58d599d..bdc6cc6696b 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -126,13 +126,24 @@ QUICPathValidator::generate_frame(QUICEncryptionLevel level, uint64_t connection } if (this->_has_outgoing_response) { - frame = QUICFrameFactory::create_path_response_frame(this->_incoming_challenge); - this->_has_outgoing_response = false; + frame = QUICFrameFactory::create_path_response_frame(this->_incoming_challenge); + if (frame && frame->size() > maximum_quic_packet_size) { + // Cancel generating frame + frame = QUICFrameFactory::create_null_frame(); + } else { + this->_has_outgoing_response = false; + } } else if (this->_has_outgoing_challenge) { frame = QUICFrameFactory::create_path_challenge_frame(this->_outgoing_challenge + (QUICPathChallengeFrame::DATA_LEN * (this->_has_outgoing_challenge - 1))); - --this->_has_outgoing_challenge; - ink_assert(this->_has_outgoing_challenge >= 0); + if (frame && frame->size() > maximum_quic_packet_size) { + // Cancel generating frame + frame = QUICFrameFactory::create_null_frame(); + } else { + --this->_has_outgoing_challenge; + ink_assert(this->_has_outgoing_challenge >= 0); + } } + return frame; } From 7dadd68544e117f80ea09ab98c15179011880528 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 23 Aug 2018 11:01:56 +0900 Subject: [PATCH 0751/1313] Make QUICFlowController derived class from QUICFrameGenerator --- iocore/net/quic/QUICFlowController.cc | 20 +++++++++++++++++-- iocore/net/quic/QUICFlowController.h | 7 +++++-- iocore/net/quic/QUICStream.cc | 4 ++-- .../net/quic/test/test_QUICFlowController.cc | 6 +++--- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index c833aa663cd..57357f1385c 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -100,14 +100,30 @@ QUICFlowController::set_limit(QUICOffset limit) this->_limit = limit; } +bool +QUICFlowController::will_generate_frame(QUICEncryptionLevel level) +{ + if (!this->_is_level_matched(level)) { + return false; + } + + return this->_frame != nullptr; +} + QUICFrameUPtr -QUICFlowController::generate_frame() +QUICFlowController::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - if (this->_frame) { + + if (!this->_is_level_matched(level)) { + return frame; + } + + if (this->_frame && this->_frame->size() <= maximum_frame_size) { frame = std::move(this->_frame); this->_frame = nullptr; } + return frame; } diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index bc4a91ab9e4..8f9e3873f40 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -26,6 +26,7 @@ #include "../../eventsystem/I_EventSystem.h" #include "QUICTypes.h" #include "QUICFrame.h" +#include "QUICFrameGenerator.h" #include "QUICLossDetector.h" class QUICRateAnalyzer @@ -39,7 +40,7 @@ class QUICRateAnalyzer ink_hrtime _start_time = Thread::get_hrtime(); }; -class QUICFlowController +class QUICFlowController : public QUICFrameGenerator { public: uint64_t credit(); @@ -60,7 +61,9 @@ class QUICFlowController */ void set_limit(QUICOffset limit); - QUICFrameUPtr generate_frame(); + // QUICFrameGenerator + bool will_generate_frame(QUICEncryptionLevel level) override; + QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; protected: QUICFlowController(uint64_t initial_limit) : _limit(initial_limit) {} diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 1965760b72d..ff381473db7 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -398,7 +398,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit } QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - frame = this->_local_flow_controller.generate_frame(); + frame = this->_local_flow_controller.generate_frame(level, connection_credit, maximum_frame_size); if (frame) { return frame; } @@ -449,7 +449,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit this->_state.update_with_sending_frame(*frame); } else if (ret != 0) { QUICStreamDebug("Flow Controller blocked sending a STREAM frame"); - frame = this->_remote_flow_controller.generate_frame(); + frame = this->_remote_flow_controller.generate_frame(level, connection_credit, maximum_frame_size); } return frame; } diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index c52b8b202a2..0d8749c302c 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -97,7 +97,7 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") fc.forward_limit(2048); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 2048); - QUICFrameUPtr frame = fc.generate_frame(); + QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024); CHECK(frame); CHECK(frame->type() == QUICFrameType::MAX_DATA); @@ -148,7 +148,7 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 1024); CHECK(ret != 0); - QUICFrameUPtr frame = fc.generate_frame(); + QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024); CHECK(frame); CHECK(frame->type() == QUICFrameType::BLOCKED); @@ -211,7 +211,7 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]") fc.forward_limit(2048); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 2048); - QUICFrameUPtr frame = fc.generate_frame(); + QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024); CHECK(frame); CHECK(frame->type() == QUICFrameType::MAX_STREAM_DATA); From f422468a9b4288c8264803f0327c096e06ca6994 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 23 Aug 2018 11:02:17 +0900 Subject: [PATCH 0752/1313] Fix typo --- iocore/net/QUICNetVConnection.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 8562d5cb668..3b9884c0283 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -63,7 +63,7 @@ static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; // static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(20); -static constexpr uint32_t PACKET_PRE_EVENT = 32; +static constexpr uint32_t PACKET_PER_EVENT = 32; static constexpr uint32_t MAX_PACKETS_WITHOUT_SRC_ADDR_VARIDATION = 3; @@ -1083,7 +1083,7 @@ QUICNetVConnection::_state_common_send_packet() { uint32_t packet_count = 0; uint32_t error = 0; - while (error == 0 && packet_count < PACKET_PRE_EVENT) { + while (error == 0 && packet_count < PACKET_PER_EVENT) { uint32_t window = this->_congestion_controller->open_window(); if (window == 0) { From 33772c879267bab570eb89d183d24f23028b80ee Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 23 Aug 2018 11:28:02 +0900 Subject: [PATCH 0753/1313] Cleanup: Remove tricky QUICNetVConnection::_store_frame() Which is used before draft-13. --- iocore/net/P_QUICNetVConnection.h | 2 - iocore/net/QUICNetVConnection.cc | 76 +++---------------------------- 2 files changed, 6 insertions(+), 72 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 18bff6033e8..27a341048c1 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -297,8 +297,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub uint64_t _maximum_stream_frame_data_size(); uint32_t _transmit_packet(QUICPacketUPtr packet); - void _store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, - QUICFrameUPtr frame); void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr frame); QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size); void _packetize_closing_frame(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3b9884c0283..750fa09c6c0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1194,71 +1194,6 @@ QUICNetVConnection::_state_closing_send_packet() return QUICErrorUPtr(new QUICNoError()); } -// Store frame data to buffer for packet. When remaining buffer is too small to store frame data or packet type is different from -// previous one, build packet and transmit it. After that, allocate new buffer. -void -QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &len, bool &retransmittable, QUICPacketType ¤t_packet_type, - QUICFrameUPtr frame) -{ - uint32_t max_size = this->maximum_quic_packet_size(); - - QUICPacketType previous_packet_type = current_packet_type; - QUICRetransmissionFrame *rf = dynamic_cast(frame.get()); - if (rf) { - current_packet_type = rf->packet_type(); - } else if (frame->is_protected()) { - current_packet_type = QUICPacketType::PROTECTED; - } else { - current_packet_type = QUICPacketType::UNINITIALIZED; - } - - if (len + frame->size() + MAX_PACKET_OVERHEAD > max_size || (previous_packet_type != current_packet_type && len > 0)) { - this->_transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, previous_packet_type)); - retransmittable = false; - len = 0; - buf = nullptr; - } - - retransmittable = retransmittable || (frame->type() != QUICFrameType::ACK && frame->type() != QUICFrameType::PADDING); - - if (buf == nullptr) { - buf = ats_unique_malloc(max_size); - } - - ink_assert(max_size > len); - - size_t l = 0; - size_t n = frame->store(buf.get() + len, &l, max_size - len); - if (n > 0) { - if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) { - char msg[1024]; - frame->debug_msg(msg, sizeof(msg)); - QUICConDebug("[TX] %s", msg); - } - - len += l; - return; - } - - // split frame - auto new_frame = QUICFrameFactory::split_frame(frame.get(), max_size - len); - - if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) { - char msg[1024]; - frame->debug_msg(msg, sizeof(msg)); - QUICConDebug("[TX] %s", msg); - } - - ink_assert(frame->store(buf.get() + len, &l, max_size - len) > 0); - ink_assert(new_frame != nullptr); - - this->_transmit_packet(this->_build_packet(std::move(buf), len, retransmittable, current_packet_type)); - len = 0; - buf = ats_unique_malloc(max_size); - this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(new_frame)); - return; -} - void QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr frame) { @@ -1406,11 +1341,12 @@ QUICNetVConnection::_packetize_closing_frame() frame = QUICFrameFactory::create_connection_close_frame(std::move(this->_connection_error)); } - ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); - size_t len = 0; - bool retransmittable = false; - QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; - this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); + uint32_t max_size = this->maximum_quic_packet_size(); + ats_unique_buf buf = ats_unique_malloc(max_size); + + size_t len = 0; + uint64_t max_frame_size = static_cast(max_size); + this->_store_frame(buf, len, max_frame_size, std::move(frame)); QUICEncryptionLevel level = this->_hs_protocol->current_encryption_level(); ink_assert(level != QUICEncryptionLevel::ZERO_RTT); From 486bdb507ac801666534e382e4a2eeebea5188d3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 23 Aug 2018 12:13:45 +0900 Subject: [PATCH 0754/1313] Do not change state of QUICAckFrameCreator::_should_send flag in QUICAckFrameCreator::_create_ack_frame() It's changed outside of QUICAckFrameCreator::_create_ack_frame() --- iocore/net/quic/QUICAckFrameCreator.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 239aff0e53a..3b0422a63a7 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -62,8 +62,6 @@ QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connecti int index = QUICTypeUtil::pn_space_index(level); if (this->_can_send[index]) { - QUICAckPacketNumbers *packet_numbers = &this->_packet_numbers[index]; - ack_frame = this->_create_ack_frame(level); if (ack_frame && ack_frame->size() > maximum_frame_size) { // Cancel generating frame @@ -71,7 +69,7 @@ QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connecti } else { this->_can_send[index] = false; this->_should_send[index] = false; - packet_numbers->clear(); + this->_packet_numbers[index].clear(); } } @@ -83,7 +81,6 @@ QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) { int index = QUICTypeUtil::pn_space_index(level); QUICAckPacketNumbers *packet_numbers = &this->_packet_numbers[index]; - this->_should_send[index] = false; std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); packet_numbers->sort(); From 0a2fd364d8e3826fa5530760a8eaf03e1008e478 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 23 Aug 2018 14:58:09 +0900 Subject: [PATCH 0755/1313] Cleanup: Remove QUICPacketTransmitter::transmit_packet() --- iocore/net/P_QUICNetVConnection.h | 3 --- iocore/net/QUICNetVConnection.cc | 22 ---------------------- iocore/net/quic/Mock.h | 16 ---------------- iocore/net/quic/QUICLossDetector.cc | 11 ++++------- iocore/net/quic/QUICPacketTransmitter.h | 9 --------- 5 files changed, 4 insertions(+), 57 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 27a341048c1..5e6e0d3d656 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -209,7 +209,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub bool is_closed() const override; // QUICConnection (QUICPacketTransmitter) - virtual uint32_t transmit_packet(QUICPacketUPtr packet) override; virtual void retransmit_packet(const QUICPacket &packet) override; virtual Ptr get_packet_transmitter_mutex() override; @@ -269,7 +268,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPathValidator *_path_validator = nullptr; QUICPacketReceiveQueue _packet_recv_queue = {this->_packet_factory, this->_pn_protector}; - CountQueue _packet_send_queue; QUICConnectionErrorUPtr _connection_error = nullptr; uint32_t _state_closing_recv_packet_count = 0; @@ -296,7 +294,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub Event *_path_validation_timeout = nullptr; uint64_t _maximum_stream_frame_data_size(); - uint32_t _transmit_packet(QUICPacketUPtr packet); void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr frame); QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size); void _packetize_closing_frame(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 750fa09c6c0..03fde79c495 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -411,28 +411,6 @@ QUICNetVConnection::stream_manager() return this->_stream_manager; } -uint32_t -QUICNetVConnection::_transmit_packet(QUICPacketUPtr packet) -{ - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); - - if (packet) { - QUICConDebug("Enqueue %s packet #%" PRIu64 " size=%hu %s", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), - packet->size(), (!packet->is_retransmittable()) ? "ack_only" : ""); - // TODO Remove const_cast - this->_packet_send_queue.enqueue(const_cast(packet.release())); - } - return this->_packet_send_queue.size; -} - -uint32_t -QUICNetVConnection::transmit_packet(QUICPacketUPtr packet) -{ - uint32_t npackets = this->_transmit_packet(std::move(packet)); - this->_schedule_packet_write_ready(); - return npackets; -} - void QUICNetVConnection::retransmit_packet(const QUICPacket &packet) { diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 1bc08a48625..df68c420b86 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -179,13 +179,6 @@ class MockQUICConnection : public QUICConnection return std::string_view("00000000-00000000"sv); } - uint32_t - transmit_packet(QUICPacketUPtr packet) override - { - ++_transmit_count; - return 1; - } - void retransmit_packet(const QUICPacket &packet) override { @@ -368,15 +361,6 @@ class MockQUICPacketTransmitter : public QUICPacketTransmitter { public: MockQUICPacketTransmitter() : QUICPacketTransmitter() { this->_mutex = new_ProxyMutex(); }; - uint32_t - transmit_packet(QUICPacketUPtr packet) override - { - if (packet) { - this->transmitted.insert(packet->packet_number()); - return 1; - } - return 0; - } void retransmit_packet(const QUICPacket &packet) override diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 2773d80ed88..de3c8648146 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -507,11 +507,10 @@ QUICLossDetector::_send_one_packet() { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - if (this->_transmitter->transmit_packet() < 1) { - auto ite = this->_sent_packets.rbegin(); - if (ite != this->_sent_packets.rend()) { - this->_transmitter->retransmit_packet(*ite->second->packet); - } + + auto ite = this->_sent_packets.rbegin(); + if (ite != this->_sent_packets.rend()) { + this->_transmitter->retransmit_packet(*ite->second->packet); } } @@ -527,8 +526,6 @@ QUICLossDetector::_send_two_packets() if (ite != this->_sent_packets.rend()) { this->_transmitter->retransmit_packet(*ite->second->packet); } - } else { - this->_transmitter->transmit_packet(); } } diff --git a/iocore/net/quic/QUICPacketTransmitter.h b/iocore/net/quic/QUICPacketTransmitter.h index d5622575fee..c60e55ca8d2 100644 --- a/iocore/net/quic/QUICPacketTransmitter.h +++ b/iocore/net/quic/QUICPacketTransmitter.h @@ -29,15 +29,6 @@ class QUICPacketTransmitter { public: - /* - * Enqueue a packet for transmission - * - * If packet parameter is not passed, it just sends an event without queuing a new packet. - * This sends QUIC_PACKET_WRITE_READY event. - * This return number of packets currently in queue - */ - virtual uint32_t transmit_packet(QUICPacketUPtr packet = QUICPacketUPtr(nullptr, &QUICPacketDeleter::delete_packet)) = 0; - /* * Enqueue a packet for retransmission * All frames except ACK and PADDING frames in the original packet will be retransmitted on a new packet. From 253ee352ede1edd115d59fd1bdd433a94273e1c9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 23 Aug 2018 15:47:39 +0900 Subject: [PATCH 0756/1313] Cleanup debug logs of Loss Detector --- iocore/net/quic/QUICDebugNames.cc | 15 +++++++++++++++ iocore/net/quic/QUICDebugNames.h | 1 + iocore/net/quic/QUICLossDetector.cc | 30 +++++++++++++++-------------- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 01aecf32981..de86f8e7cd6 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -274,3 +274,18 @@ QUICDebugNames::encryption_level(QUICEncryptionLevel level) return "UNKNOWN"; } } + +const char * +QUICDebugNames::pn_space(int index) +{ + switch (index) { + case 0: + return "INITIAL"; + case 1: + return "PROTECTED"; + case 2: + return "HANDSHAKE"; + default: + return "UNKNOWN"; + } +} diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index 23222998ad7..b2ce4ecaab7 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -40,6 +40,7 @@ class QUICDebugNames static const char *quic_event(int event); static const char *key_phase(QUICKeyPhase phase); static const char *encryption_level(QUICEncryptionLevel level); + static const char *pn_space(int index); }; class QUICDebug diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index de3c8648146..548ee9b67db 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -27,11 +27,14 @@ #include "QUICConfig.h" #include "QUICEvents.h" +#include "QUICDebugNames.h" -#define QUICLDDebug(fmt, ...) \ - Debug("quic_loss_detector", "[%s] [PNS-%d] " fmt, this->_info->cids().data(), this->_pn_space_index, ##__VA_ARGS__) -#define QUICLDVDebug(fmt, ...) \ - Debug("v_quic_loss_detector", "[%s] [PNS-%d] " fmt, this->_info->cids().data(), this->_pn_space_index, ##__VA_ARGS__) +#define QUICLDDebug(fmt, ...) \ + Debug("quic_loss_detector", "[%s] [%s] " fmt, this->_info->cids().data(), QUICDebugNames::pn_space(this->_pn_space_index), \ + ##__VA_ARGS__) +#define QUICLDVDebug(fmt, ...) \ + Debug("v_quic_loss_detector", "[%s] [%s] " fmt, this->_info->cids().data(), QUICDebugNames::pn_space(this->_pn_space_index), \ + ##__VA_ARGS__) QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, int index) @@ -223,8 +226,8 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac this->_update_rtt(this->_latest_rtt, delay, ack_frame->largest_acknowledged()); } - QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), - this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); + QUICLDVDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), + this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); // Find all newly acked packets. for (auto &&range : this->_determine_newly_acked_packets(*ack_frame)) { @@ -238,8 +241,8 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac } } - QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), - this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); + QUICLDVDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), + this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); this->_detect_lost_packets(ack_frame->largest_acknowledged()); @@ -384,7 +387,7 @@ QUICLossDetector::_on_loss_detection_alarm() this->_detect_lost_packets(this->_largest_acked_packet); } else if (this->_tlp_count < this->_k_max_tlps) { // Tail Loss Probe. - QUICLDDebug("TLP"); + QUICLDVDebug("TLP"); // FIXME TLP causes inifinite loop somehow // this->_send_one_packet(); this->_tlp_count++; @@ -393,7 +396,7 @@ QUICLossDetector::_on_loss_detection_alarm() if (this->_rto_count == 0) { this->_largest_sent_before_rto = this->_largest_sent_packet; } - QUICLDDebug("RTO"); + QUICLDVDebug("RTO"); this->_send_two_packets(); this->_rto_count++; } @@ -435,14 +438,13 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num uint64_t delta = largest_acked_packet_number - it->second->packet_number; if (time_since_sent > delay_until_lost || delta > this->_reordering_threshold) { if (time_since_sent > delay_until_lost) { - QUICLDDebug("Lost: time since sent is too long (PN=%" PRId64 " sent=%" PRId64 ", delay=%lf, fraction=%lf, lrtt=%" PRId64 + QUICLDDebug("Lost: time since sent is too long (#%" PRId64 " sent=%" PRId64 ", delay=%lf, fraction=%lf, lrtt=%" PRId64 ", srtt=%" PRId64 ")", it->first, time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, this->_smoothed_rtt); } else { - QUICLDDebug("Lost: packet delta is too large (PN=%" PRId64 " largest=%" PRId64 " unacked=%" PRId64 " threshold=%" PRId32 - ")", - it->first, largest_acked_packet_number, it->second->packet_number, this->_reordering_threshold); + QUICLDDebug("Lost: packet delta is too large (#%" PRId64 " largest=%" PRId64 " threshold=%" PRId32 ")", it->first, + largest_acked_packet_number, this->_reordering_threshold); } if (!it->second->ack_only) { From 7a195464eca6c51c491dfb14d6343e06f863ac46 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 23 Aug 2018 16:05:16 +0900 Subject: [PATCH 0757/1313] Send BLOCKED frame QUICRemoteFlowController::update() create BLOCKED(_STREAM) frame. It will be sent when STREAMs have anything to send. --- iocore/net/QUICNetVConnection.cc | 22 +++++++--- iocore/net/quic/QUICFlowController.cc | 6 ++- iocore/net/quic/QUICStream.cc | 17 ++++++-- .../net/quic/test/test_QUICFlowController.cc | 43 +++++++++++++++++-- 4 files changed, 73 insertions(+), 15 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 03fde79c495..a019f9b07fd 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1214,7 +1214,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa bool ack_only = true; if (this->_connection_error || this->_packet_retransmitter.will_generate_frame(level) || this->_handshake_handler->will_generate_frame(level) || this->_stream_manager->will_generate_frame(level) || - this->_path_validator->will_generate_frame(level)) { + this->_path_validator->will_generate_frame(level) || this->_local_flow_controller->will_generate_frame(level) || + (this->_stream_manager->will_generate_frame(level) && this->_remote_flow_controller->will_generate_frame(level))) { ack_only = false; } @@ -1241,7 +1242,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } // PATH_CHALLENGE, PATH_RESPOSNE - frame = this->_path_validator->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + frame = this->_path_validator->generate_frame(level, UINT16_MAX, max_frame_size); if (frame) { ++frame_count; this->_store_frame(buf, len, max_frame_size, std::move(frame)); @@ -1249,22 +1250,31 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa // NEW_CONNECTION_ID if (this->_alt_con_manager) { - frame = this->_alt_con_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + frame = this->_alt_con_manager->generate_frame(level, UINT16_MAX, max_frame_size); while (frame) { ++frame_count; this->_store_frame(buf, len, max_frame_size, std::move(frame)); - frame = this->_alt_con_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + frame = this->_alt_con_manager->generate_frame(level, UINT16_MAX, max_frame_size); } } // Lost frames - frame = this->_packet_retransmitter.generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + frame = this->_packet_retransmitter.generate_frame(level, UINT16_MAX, max_frame_size); while (frame) { ++frame_count; this->_store_frame(buf, len, max_frame_size, std::move(frame)); - frame = this->_packet_retransmitter.generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + frame = this->_packet_retransmitter.generate_frame(level, UINT16_MAX, max_frame_size); + } + + // BLOCKED + if (this->_remote_flow_controller->credit() == 0 && this->_stream_manager->will_generate_frame(level)) { + frame = this->_remote_flow_controller->generate_frame(level, UINT16_MAX, max_frame_size); + if (frame) { + ++frame_count; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); + } } // STREAM, MAX_STREAM_DATA, STREAM_BLOCKED diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 57357f1385c..70ff1817522 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -100,6 +100,7 @@ QUICFlowController::set_limit(QUICOffset limit) this->_limit = limit; } +// For RemoteFlowController, caller of this function should also check QUICStreamManager::will_generate_frame() bool QUICFlowController::will_generate_frame(QUICEncryptionLevel level) { @@ -142,8 +143,9 @@ QUICRemoteFlowController::update(QUICOffset offset) { int ret = QUICFlowController::update(offset); - // Send BLOCKED(_STREAM) frame - if (!this->_blocked && offset > this->_limit) { + // Create BLOCKED(_STREAM) frame + // The frame will be sent if stream has something to send. + if (!this->_blocked && offset >= this->_limit) { this->_frame = this->_create_frame(); this->_blocked = true; } diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index ff381473db7..d2a5a3f4819 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -403,6 +403,10 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit return frame; } + if (connection_credit == 0) { + return frame; + } + if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) { return frame; } @@ -413,13 +417,20 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit return frame; } + // STREAM_BLOCKED + uint64_t stream_credit = this->_remote_flow_controller.credit(); + // The `bytes_avail` should be also checked before calling QUICRemoteFlowController::generate_frame(), but we don't need it. + // Because it's already checked in above. + if (stream_credit == 0) { + frame = this->_remote_flow_controller.generate_frame(level, connection_credit, maximum_frame_size); + } + int64_t data_len = reader->block_read_avail(); int64_t len = 0; bool fin = false; - len = std::min(data_len, static_cast( - std::min(static_cast(maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD), - std::min(this->_remote_flow_controller.credit(), static_cast(connection_credit))))); + len = std::min(data_len, static_cast(std::min(static_cast(maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD), + std::min(stream_credit, static_cast(connection_credit))))); if (this->_write_vio.nbytes == static_cast(this->_send_offset + len)) { fin = true; diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index 0d8749c302c..951a0e57712 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -132,26 +132,58 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") CHECK(fc.current_limit() == 1024); CHECK(ret == 0); - ret = fc.update(1024); - CHECK(fc.current_offset() == 1024); + ret = fc.update(1000); + CHECK(fc.current_offset() == 1000); CHECK(fc.current_limit() == 1024); CHECK(ret == 0); // Delay ret = fc.update(512); - CHECK(fc.current_offset() == 1024); + CHECK(fc.current_offset() == 1000); CHECK(fc.current_limit() == 1024); CHECK(ret == 0); // Exceed limit ret = fc.update(1280); - CHECK(fc.current_offset() == 1024); + CHECK(fc.current_offset() == 1000); CHECK(fc.current_limit() == 1024); CHECK(ret != 0); QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024); CHECK(frame); CHECK(frame->type() == QUICFrameType::BLOCKED); + // MAX_STREAM_DATA + fc.forward_limit(2048); + CHECK(fc.current_offset() == 1000); + CHECK(fc.current_limit() == 2048); + + ret = fc.update(1280); + CHECK(fc.current_offset() == 1280); + CHECK(fc.current_limit() == 2048); + CHECK(ret == 0); +} + +TEST_CASE("QUICFlowController_Remote_Connection_ZERO_Credit", "[quic]") +{ + int ret = 0; + QUICRemoteConnectionFlowController fc(1024); + + // Check initial state + CHECK(fc.current_offset() == 0); + CHECK(fc.current_limit() == 1024); + + // Zero credit + ret = fc.update(1024); + CHECK(fc.current_offset() == 1024); + CHECK(fc.current_limit() == 1024); + CHECK(ret == 0); + + CHECK(fc.will_generate_frame(QUICEncryptionLevel::ONE_RTT)); + // if there're anything to send + QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024); + CHECK(frame); + CHECK(frame->type() == QUICFrameType::BLOCKED); + // MAX_STREAM_DATA fc.forward_limit(2048); CHECK(fc.current_offset() == 1024); @@ -251,6 +283,9 @@ TEST_CASE("QUICFlowController_Remote_Stream", "[quic]") CHECK(fc.current_limit() == 1024); CHECK(ret == 0); + CHECK(fc.credit() == 0); + CHECK(fc.will_generate_frame(QUICEncryptionLevel::ONE_RTT)); + // Delay ret = fc.update(512); CHECK(fc.current_offset() == 1024); From 9e7e83fbd9c1456e780042113aeb5f85c001d0e6 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 23 Aug 2018 15:16:54 +0800 Subject: [PATCH 0758/1313] QUIC: fix memleaking in test_QUICFrame --- iocore/net/quic/QUICPacketReceiveQueue.cc | 2 +- iocore/net/quic/test/test_QUICFrame.cc | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 9b0a837b56f..309e3b37f41 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -162,7 +162,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) this->_payload = nullptr; this->_payload_len = 0; this->_offset = 0; - result = QUICPacketCreationResult::NOT_READY; + result = QUICPacketCreationResult::NOT_READY; return quic_packet; } pkt = std::move(this->_payload); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 1a8843a2e44..711d30fcbb2 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -325,7 +325,6 @@ TEST_CASE("Store STREAM Frame", "[quic]") SECTION("split stream frame") { - size_t len; uint8_t buf1[] = { 0x16, // 0b00010OLF (OLF=110) 0x01, // Stream ID @@ -352,6 +351,8 @@ TEST_CASE("Store STREAM Frame", "[quic]") CHECK(memcmp(stream_frame2->data(), "\x11\x22\x33\x44\x55", stream_frame2->data_length()) == 0); CHECK(stream_frame2->offset() == 0x100000000 + 5); CHECK(stream_frame2->stream_id() == 0x01); + + QUICFrameDeleter::delete_stream_frame(stream_frame2); } } @@ -1251,7 +1252,9 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") { - QUICStream stream(new MockQUICRTTProvider(), new MockQUICConnection(), 0x1234, 0, 0); + MockQUICRTTProvider mock_rtt; + MockQUICConnection mock_connection; + QUICStream stream(&mock_rtt, &mock_connection, 0x1234, 0, 0); std::unique_ptr error = std::unique_ptr(new QUICStreamError(&stream, static_cast(0x01))); std::unique_ptr rst_stream_frame1 = @@ -1303,10 +1306,13 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") auto frame = QUICFrameFactory::create_retransmission_frame(std::move(frame1), *packet); auto frame2 = frame->split(16); + CHECK(frame2->type() == QUICFrameType::STREAM); CHECK(frame2->store(buffer, &len, 128)); CHECK(memcmp(buffer, expected, sizeof(expected)) == 0); CHECK(frame->store(buffer, &len, 128)); CHECK(memcmp(buffer, expected2, sizeof(expected2)) == 0); + + QUICFrameDeleter::delete_stream_frame(frame2); } SECTION("STREAM frame") From 0d5f86e310dcb8cb983dada02d9848b2de78a231 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 24 Aug 2018 15:19:25 +0800 Subject: [PATCH 0759/1313] Fixes memleaking in handshake --- iocore/net/quic/QUICHandshake.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 637b8cc2125..4eaef4c98ab 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -400,7 +400,7 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_in()); // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); - this->_local_transport_parameters = std::unique_ptr(tp); + this->_local_transport_parameters = std::unique_ptr(tp); } void @@ -419,7 +419,7 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_out()); tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_out()); - this->_local_transport_parameters = std::unique_ptr(tp); + this->_local_transport_parameters = std::unique_ptr(tp); } int From 05417b553944fd5b66f87d709a4a85acb4cae28b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 27 Aug 2018 11:56:34 +0900 Subject: [PATCH 0760/1313] Revert "Fixes memleaking in handshake" This reverts commit 0d5f86e310dcb8cb983dada02d9848b2de78a231. --- iocore/net/quic/QUICHandshake.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 4eaef4c98ab..637b8cc2125 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -400,7 +400,7 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_in()); // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); - this->_local_transport_parameters = std::unique_ptr(tp); + this->_local_transport_parameters = std::unique_ptr(tp); } void @@ -419,7 +419,7 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_out()); tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_out()); - this->_local_transport_parameters = std::unique_ptr(tp); + this->_local_transport_parameters = std::unique_ptr(tp); } int From 96c19776113aed9b9017ea4ee228912243087a76 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 27 Aug 2018 12:05:58 +0900 Subject: [PATCH 0761/1313] Make destructor of QUICTransportParameters virtual --- iocore/net/quic/QUICTransportParameters.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index cc2839aeb3c..1214001b98c 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -70,7 +70,7 @@ class QUICTransportParameters { public: QUICTransportParameters(const uint8_t *buf, size_t len); - ~QUICTransportParameters(); + virtual ~QUICTransportParameters(); bool is_valid() const; From 125fc326423d1275b1d975cf4484ca22c89968b9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 24 Aug 2018 16:29:22 +0900 Subject: [PATCH 0762/1313] Generate ACK frame in the end of packetizing frames To set "ack_only" flag correctly. Because any generate_frame() could fail. Also add a counter to interrupt sending STREAM frames to send ACK frame periodically. --- iocore/net/P_QUICNetVConnection.h | 3 ++- iocore/net/QUICNetVConnection.cc | 44 +++++++++++++++---------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 5e6e0d3d656..b2efbdf8680 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -348,7 +348,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICStatelessResetToken _reset_token; // This is for limiting number of packets that a server can send without path validation - unsigned int _handshake_packets_sent = 0; + uint32_t _handshake_packets_sent = 0; + uint64_t _stream_frames_sent = 0; // TODO: Source addresses verification through an address validation token bool _src_addr_verified = false; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a019f9b07fd..af40685aac0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -64,6 +64,7 @@ static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(20); static constexpr uint32_t PACKET_PER_EVENT = 32; +static constexpr uint32_t MAX_CONSECUTIVE_STREAMS = 8; //< Interrupt sending STREAM frames to send ACK frame static constexpr uint32_t MAX_PACKETS_WITHOUT_SRC_ADDR_VARIDATION = 3; @@ -1211,14 +1212,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); - bool ack_only = true; - if (this->_connection_error || this->_packet_retransmitter.will_generate_frame(level) || - this->_handshake_handler->will_generate_frame(level) || this->_stream_manager->will_generate_frame(level) || - this->_path_validator->will_generate_frame(level) || this->_local_flow_controller->will_generate_frame(level) || - (this->_stream_manager->will_generate_frame(level) && this->_remote_flow_controller->will_generate_frame(level))) { - ack_only = false; - } - // CRYPTO frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); while (frame) { @@ -1227,20 +1220,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); } - // ACK - if (ack_only) { - if (this->_ack_frame_creator.will_generate_frame(level)) { - frame = this->_ack_frame_creator.generate_frame(level, UINT16_MAX, max_frame_size); - } - } else { - frame = this->_ack_frame_creator.generate_frame(level, UINT16_MAX, max_frame_size); - } - - if (frame != nullptr) { - ++frame_count; - this->_store_frame(buf, len, max_frame_size, std::move(frame)); - } - // PATH_CHALLENGE, PATH_RESPOSNE frame = this->_path_validator->generate_frame(level, UINT16_MAX, max_frame_size); if (frame) { @@ -1281,6 +1260,9 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); while (frame) { ++frame_count; + if (++this->_stream_frames_sent % MAX_CONSECUTIVE_STREAMS == 0) { + break; + } if (frame->type() == QUICFrameType::STREAM) { int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), @@ -1292,6 +1274,24 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); } + // ACK + if (frame_count == 0) { + if (this->_ack_frame_creator.will_generate_frame(level)) { + frame = this->_ack_frame_creator.generate_frame(level, UINT16_MAX, max_frame_size); + } + } else { + frame = this->_ack_frame_creator.generate_frame(level, UINT16_MAX, max_frame_size); + } + + bool ack_only = false; + if (frame != nullptr) { + if (frame_count == 0) { + ack_only = true; + } + ++frame_count; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); + } + // Schedule a packet if (len != 0) { if (level == QUICEncryptionLevel::INITIAL && this->netvc_context == NET_VCONNECTION_OUT) { From ea32638a1a0e2f8d52dc0876cace1c929ba67597 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 27 Aug 2018 12:18:11 +0900 Subject: [PATCH 0763/1313] Return STREAM_BLOCKED frame when it is generated --- iocore/net/quic/QUICStream.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index d2a5a3f4819..37f1130d745 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -423,6 +423,9 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit // Because it's already checked in above. if (stream_credit == 0) { frame = this->_remote_flow_controller.generate_frame(level, connection_credit, maximum_frame_size); + if (frame) { + return frame; + } } int64_t data_len = reader->block_read_avail(); From 8b8d9a043c651d0e5bcd97658b007e6dc02ccb74 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 20 Jul 2018 17:20:45 +0900 Subject: [PATCH 0764/1313] Add QUICStreamIO::peek --- iocore/net/quic/QUICApplication.cc | 14 +++++++++++++- iocore/net/quic/QUICApplication.h | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 46863985719..54bf199ead8 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -66,7 +66,7 @@ QUICStreamIO::read(uint8_t *buf, int64_t len) this->_read_vio->ndone, this->_read_buffer_reader->read_avail(), len); } - int64_t nread = this->_read_buffer_reader->read(const_cast(buf), len); + int64_t nread = this->_read_buffer_reader->read(buf, len); if (nread > 0) { this->_read_vio->ndone += nread; } @@ -74,6 +74,18 @@ QUICStreamIO::read(uint8_t *buf, int64_t len) return nread; } +int64_t +QUICStreamIO::peek(uint8_t *buf, int64_t len) +{ + return this->_read_buffer_reader->memcpy(buf, len) - reinterpret_cast(buf); +} + +void +QUICStreamIO::consume(int64_t len) +{ + this->_read_buffer_reader->consume(len); +} + bool QUICStreamIO::is_read_done() { diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index e9b8e4c8f92..87d84ebd1b9 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -43,6 +43,8 @@ class QUICStreamIO uint32_t stream_id() const; int64_t read(uint8_t *buf, int64_t len); + int64_t peek(uint8_t *buf, int64_t len); + void consume(int64_t len); bool is_read_done(); virtual void read_reenable(); From 062b8f481c5fe176f3fc73f986a275da7e3a4318 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 23 Jul 2018 10:17:58 +0900 Subject: [PATCH 0765/1313] Separate out some of HPACK logic into hdrs/ Primitive representations and Huffman encoding can be shared with HPACK and QPACK. --- .gitignore | 2 +- proxy/{http2 => hdrs}/HuffmanCodec.cc | 0 proxy/{http2 => hdrs}/HuffmanCodec.h | 0 proxy/hdrs/Makefile.am | 23 ++- proxy/hdrs/XPACK.cc | 193 ++++++++++++++++++++ proxy/hdrs/XPACK.h | 36 ++++ proxy/{http2 => hdrs}/test_Huffmancode.cc | 0 proxy/http2/HPACK.cc | 212 +++------------------- proxy/http2/HPACK.h | 5 +- proxy/http2/HTTP2.cc | 1 - proxy/http2/Makefile.am | 16 +- proxy/http2/RegressionHPACK.cc | 18 +- 12 files changed, 285 insertions(+), 221 deletions(-) rename proxy/{http2 => hdrs}/HuffmanCodec.cc (100%) rename proxy/{http2 => hdrs}/HuffmanCodec.h (100%) create mode 100644 proxy/hdrs/XPACK.cc create mode 100644 proxy/hdrs/XPACK.h rename proxy/{http2 => hdrs}/test_Huffmancode.cc (100%) diff --git a/.gitignore b/.gitignore index 33e0c164da9..a97b1128c8a 100644 --- a/.gitignore +++ b/.gitignore @@ -122,8 +122,8 @@ iocore/eventsystem/test_MIOBufferWriter iocore/hostdb/test_RefCountCache proxy/hdrs/test_mime +proxy/hdrs/test_Huffmancode proxy/http/test_ForwardedConfig -proxy/http2/test_Huffmancode proxy/http2/test_Http2DependencyTree proxy/http2/test_HPACK proxy/http2/hpack-tests/results diff --git a/proxy/http2/HuffmanCodec.cc b/proxy/hdrs/HuffmanCodec.cc similarity index 100% rename from proxy/http2/HuffmanCodec.cc rename to proxy/hdrs/HuffmanCodec.cc diff --git a/proxy/http2/HuffmanCodec.h b/proxy/hdrs/HuffmanCodec.h similarity index 100% rename from proxy/http2/HuffmanCodec.h rename to proxy/hdrs/HuffmanCodec.h diff --git a/proxy/hdrs/Makefile.am b/proxy/hdrs/Makefile.am index f2e5c27e77e..930962b7a09 100644 --- a/proxy/hdrs/Makefile.am +++ b/proxy/hdrs/Makefile.am @@ -43,7 +43,11 @@ libhdrs_a_SOURCES = \ MIME.cc \ MIME.h \ URL.cc \ - URL.h + URL.h \ + HuffmanCodec.cc \ + HuffmanCodec.h \ + XPACK.cc \ + XPACK.h if BUILD_TESTS libhdrs_a_SOURCES += \ @@ -61,9 +65,13 @@ load_http_hdr_LDADD = -L. -lhdrs \ $(top_builddir)/lib/ts/libtsutil.la \ @LIBTCL@ -check_PROGRAMS = test_mime +check_PROGRAMS = \ + test_mime \ + test_Huffmancode -TESTS = test_mime +TESTS = \ + test_mime \ + test_Huffmancode test_mime_LDADD = -L. -lhdrs \ $(top_builddir)/lib/ts/libtsutil.la \ @@ -76,6 +84,15 @@ test_mime_LDADD = -L. -lhdrs \ test_mime_SOURCES = test_mime.cc +test_Huffmancode_LDADD = \ + $(top_builddir)/lib/ts/libtsutil.la + +test_Huffmancode_SOURCES = \ + test_Huffmancode.cc \ + HuffmanCodec.cc \ + HuffmanCodec.h + + #test_UNUSED_SOURCES = \ # test_urlhash.cc diff --git a/proxy/hdrs/XPACK.cc b/proxy/hdrs/XPACK.cc new file mode 100644 index 00000000000..c5378729a0d --- /dev/null +++ b/proxy/hdrs/XPACK.cc @@ -0,0 +1,193 @@ +/** @file + + Common functions for HPACK and QPACK + + @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 "ts/Arena.h" +#include "ts/ink_memory.h" +#include "XPACK.h" +#include "HuffmanCodec.h" + +// +// [RFC 7541] 5.1. Integer representation +// +int64_t +xpack_decode_integer(uint64_t &dst, const uint8_t *buf_start, const uint8_t *buf_end, uint8_t n) +{ + if (buf_start >= buf_end) { + return XPACK_ERROR_COMPRESSION_ERROR; + } + + const uint8_t *p = buf_start; + + dst = (*p & ((1 << n) - 1)); + if (dst == static_cast(1 << n) - 1) { + int m = 0; + do { + if (++p >= buf_end) { + return XPACK_ERROR_COMPRESSION_ERROR; + } + + uint64_t added_value = *p & 0x7f; + if ((UINT64_MAX >> m) < added_value) { + // Excessively large integer encodings - in value or octet + // length - MUST be treated as a decoding error. + return XPACK_ERROR_COMPRESSION_ERROR; + } + dst += added_value << m; + m += 7; + } while (*p & 0x80); + } + + return p - buf_start + 1; +} + +// +// [RFC 7541] 5.2. String Literal Representation +// return content from String Data (Length octets) with huffman decoding if it is encoded +// +int64_t +xpack_decode_string(Arena &arena, char **str, uint64_t &str_length, const uint8_t *buf_start, const uint8_t *buf_end, uint8_t n) +{ + if (buf_start >= buf_end) { + return XPACK_ERROR_COMPRESSION_ERROR; + } + + const uint8_t *p = buf_start; + bool isHuffman = *p & (0x01 << n); + uint64_t encoded_string_len = 0; + int64_t len = 0; + + len = xpack_decode_integer(encoded_string_len, p, buf_end, n); + if (len == XPACK_ERROR_COMPRESSION_ERROR) { + return XPACK_ERROR_COMPRESSION_ERROR; + } + p += len; + + if ((p + encoded_string_len) > buf_end) { + return XPACK_ERROR_COMPRESSION_ERROR; + } + + if (isHuffman) { + // Allocate temporary area twice the size of before decoded data + *str = arena.str_alloc(encoded_string_len * 2); + + len = huffman_decode(*str, p, encoded_string_len); + if (len < 0) { + return XPACK_ERROR_COMPRESSION_ERROR; + } + str_length = len; + } else { + *str = arena.str_alloc(encoded_string_len); + + memcpy(*str, reinterpret_cast(p), encoded_string_len); + + str_length = encoded_string_len; + } + + return p + encoded_string_len - buf_start; +} + +// +// [RFC 7541] 5.1. Integer representation +// +int64_t +xpack_encode_integer(uint8_t *buf_start, const uint8_t *buf_end, uint64_t value, uint8_t n) +{ + if (buf_start >= buf_end) { + return -1; + } + + uint8_t *p = buf_start; + + if (value < (static_cast(1 << n) - 1)) { + *(p++) = value; + } else { + *(p++) = (1 << n) - 1; + value -= (1 << n) - 1; + while (value >= 128) { + if (p >= buf_end) { + return -1; + } + *(p++) = (value & 0x7F) | 0x80; + value = value >> 7; + } + if (p + 1 >= buf_end) { + return -1; + } + *(p++) = value; + } + return p - buf_start; +} + +int64_t +xpack_encode_string(uint8_t *buf_start, const uint8_t *buf_end, const char *value, uint64_t value_len, uint8_t n) +{ + uint8_t *p = buf_start; + bool use_huffman = true; + char *data = nullptr; + int64_t data_len = 0; + + // TODO Choose whether to use Huffman encoding wisely + + if (use_huffman && value_len) { + data = static_cast(ats_malloc(value_len * 4)); + if (data == nullptr) { + return -1; + } + data_len = huffman_encode(reinterpret_cast(data), reinterpret_cast(value), value_len); + } + + // Length + const int64_t len = xpack_encode_integer(p, buf_end, data_len, n); + if (len == -1) { + if (use_huffman) { + ats_free(data); + } + + return -1; + } + + if (use_huffman) { + *p |= 0x01 << n; + } + p += len; + + if (buf_end < p || buf_end - p < data_len) { + if (use_huffman) { + ats_free(data); + } + + return -1; + } + + // Value + if (data_len) { + memcpy(p, data, data_len); + p += data_len; + } + + if (use_huffman) { + ats_free(data); + } + + return p - buf_start; +} diff --git a/proxy/hdrs/XPACK.h b/proxy/hdrs/XPACK.h new file mode 100644 index 00000000000..5e8eca35e44 --- /dev/null +++ b/proxy/hdrs/XPACK.h @@ -0,0 +1,36 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +const static int XPACK_ERROR_COMPRESSION_ERROR = -1; +const static int XPACK_ERROR_SIZE_EXCEEDED_ERROR = -2; + +// These primitives are shared with HPACK and QPACK. +int64_t xpack_encode_integer(uint8_t *buf_start, const uint8_t *buf_end, uint64_t value, uint8_t n); +int64_t xpack_decode_integer(uint64_t &dst, const uint8_t *buf_start, const uint8_t *buf_end, uint8_t n); +int64_t xpack_encode_string(uint8_t *buf_start, const uint8_t *buf_end, const char *value, uint64_t value_len, uint8_t n = 7); +int64_t xpack_decode_string(Arena &arena, char **str, uint64_t &str_length, const uint8_t *buf_start, const uint8_t *buf_end, + uint8_t n = 7); diff --git a/proxy/http2/test_Huffmancode.cc b/proxy/hdrs/test_Huffmancode.cc similarity index 100% rename from proxy/http2/test_Huffmancode.cc rename to proxy/hdrs/test_Huffmancode.cc diff --git a/proxy/http2/HPACK.cc b/proxy/http2/HPACK.cc index 1c45d1e178e..fd16460e05a 100644 --- a/proxy/http2/HPACK.cc +++ b/proxy/http2/HPACK.cc @@ -409,92 +409,6 @@ HpackDynamicTable::length() const return _headers.size(); } -// -// [RFC 7541] 5.1. Integer representation -// -int64_t -encode_integer(uint8_t *buf_start, const uint8_t *buf_end, uint32_t value, uint8_t n) -{ - if (buf_start >= buf_end) { - return -1; - } - - uint8_t *p = buf_start; - - if (value < (static_cast(1 << n) - 1)) { - *(p++) = value; - } else { - *(p++) = (1 << n) - 1; - value -= (1 << n) - 1; - while (value >= 128) { - if (p >= buf_end) { - return -1; - } - *(p++) = (value & 0x7F) | 0x80; - value = value >> 7; - } - if (p + 1 >= buf_end) { - return -1; - } - *(p++) = value; - } - return p - buf_start; -} - -int64_t -encode_string(uint8_t *buf_start, const uint8_t *buf_end, const char *value, size_t value_len) -{ - uint8_t *p = buf_start; - bool use_huffman = true; - char *data = nullptr; - int64_t data_len = 0; - - // TODO Choose whether to use Huffman encoding wisely - - if (use_huffman && value_len) { - data = static_cast(ats_malloc(value_len * 4)); - if (data == nullptr) { - return -1; - } - data_len = huffman_encode(reinterpret_cast(data), reinterpret_cast(value), value_len); - } - - // Length - const int64_t len = encode_integer(p, buf_end, data_len, 7); - if (len == -1) { - if (use_huffman) { - ats_free(data); - } - - return -1; - } - - if (use_huffman) { - *p |= 0x80; - } - p += len; - - if (buf_end < p || buf_end - p < data_len) { - if (use_huffman) { - ats_free(data); - } - - return -1; - } - - // Value - if (data_len) { - memcpy(p, data, data_len); - p += data_len; - } - - if (use_huffman) { - ats_free(data); - } - - return p - buf_start; -} - int64_t encode_indexed_header_field(uint8_t *buf_start, const uint8_t *buf_end, uint32_t index) { @@ -505,7 +419,7 @@ encode_indexed_header_field(uint8_t *buf_start, const uint8_t *buf_end, uint32_t uint8_t *p = buf_start; // Index - const int64_t len = encode_integer(p, buf_end, index, 7); + const int64_t len = xpack_encode_integer(p, buf_end, index, 7); if (len == -1) { return -1; } @@ -551,7 +465,7 @@ encode_literal_header_field_with_indexed_name(uint8_t *buf_start, const uint8_t } // Index - len = encode_integer(p, buf_end, index, prefix); + len = xpack_encode_integer(p, buf_end, index, prefix); if (len == -1) { return -1; } @@ -566,7 +480,7 @@ encode_literal_header_field_with_indexed_name(uint8_t *buf_start, const uint8_t // Value String int value_len; const char *value = header.value_get(&value_len); - len = encode_string(p, buf_end, value, value_len); + len = xpack_encode_string(p, buf_end, value, value_len); if (len == -1) { return -1; } @@ -616,7 +530,7 @@ encode_literal_header_field_with_new_name(uint8_t *buf_start, const uint8_t *buf } // Name String - len = encode_string(p, buf_end, lower_name, name_len); + len = xpack_encode_string(p, buf_end, lower_name, name_len); if (len == -1) { return -1; } @@ -625,7 +539,7 @@ encode_literal_header_field_with_new_name(uint8_t *buf_start, const uint8_t *buf // Value String int value_len; const char *value = header.value_get(&value_len); - len = encode_string(p, buf_end, value, value_len); + len = xpack_encode_string(p, buf_end, value, value_len); if (len == -1) { return -1; } @@ -639,7 +553,7 @@ encode_literal_header_field_with_new_name(uint8_t *buf_start, const uint8_t *buf int64_t encode_dynamic_table_size_update(uint8_t *buf_start, const uint8_t *buf_end, uint32_t size) { - const int64_t len = encode_integer(buf_start, buf_end, size, 5); + const int64_t len = xpack_encode_integer(buf_start, buf_end, size, 5); if (len == -1) { return -1; } @@ -648,86 +562,6 @@ encode_dynamic_table_size_update(uint8_t *buf_start, const uint8_t *buf_end, uin return len; } -// -// [RFC 7541] 5.1. Integer representation -// -int64_t -decode_integer(uint32_t &dst, const uint8_t *buf_start, const uint8_t *buf_end, uint8_t n) -{ - if (buf_start >= buf_end) { - return HPACK_ERROR_COMPRESSION_ERROR; - } - - const uint8_t *p = buf_start; - - dst = (*p & ((1 << n) - 1)); - if (dst == static_cast(1 << n) - 1) { - int m = 0; - do { - if (++p >= buf_end) { - return HPACK_ERROR_COMPRESSION_ERROR; - } - - uint32_t added_value = *p & 0x7f; - if ((UINT32_MAX >> m) < added_value) { - // Excessively large integer encodings - in value or octet - // length - MUST be treated as a decoding error. - return HPACK_ERROR_COMPRESSION_ERROR; - } - dst += added_value << m; - m += 7; - } while (*p & 0x80); - } - - return p - buf_start + 1; -} - -// -// [RFC 7541] 5.2. String Literal Representation -// return content from String Data (Length octets) with huffman decoding if it is encoded -// -int64_t -decode_string(Arena &arena, char **str, uint32_t &str_length, const uint8_t *buf_start, const uint8_t *buf_end) -{ - if (buf_start >= buf_end) { - return HPACK_ERROR_COMPRESSION_ERROR; - } - - const uint8_t *p = buf_start; - bool isHuffman = *p & 0x80; - uint32_t encoded_string_len = 0; - int64_t len = 0; - - len = decode_integer(encoded_string_len, p, buf_end, 7); - if (len == HPACK_ERROR_COMPRESSION_ERROR) { - return HPACK_ERROR_COMPRESSION_ERROR; - } - p += len; - - if ((p + encoded_string_len) > buf_end) { - return HPACK_ERROR_COMPRESSION_ERROR; - } - - if (isHuffman) { - // Allocate temporary area twice the size of before decoded data - *str = arena.str_alloc(encoded_string_len * 2); - - len = huffman_decode(*str, p, encoded_string_len); - if (len < 0) { - return HPACK_ERROR_COMPRESSION_ERROR; - } - str_length = len; - } else { - *str = arena.str_alloc(encoded_string_len); - - memcpy(*str, reinterpret_cast(p), encoded_string_len); - - str_length = encoded_string_len; - } - - return p + encoded_string_len - buf_start; -} - // // [RFC 7541] 6.1. Indexed Header Field Representation // @@ -735,11 +569,11 @@ int64_t decode_indexed_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start, const uint8_t *buf_end, HpackIndexingTable &indexing_table) { - uint32_t index = 0; + uint64_t index = 0; int64_t len = 0; - len = decode_integer(index, buf_start, buf_end, 7); - if (len == HPACK_ERROR_COMPRESSION_ERROR) { + len = xpack_decode_integer(index, buf_start, buf_end, 7); + if (len == XPACK_ERROR_COMPRESSION_ERROR) { return HPACK_ERROR_COMPRESSION_ERROR; } @@ -771,22 +605,22 @@ decode_literal_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start, { const uint8_t *p = buf_start; bool isIncremental = false; - uint32_t index = 0; + uint64_t index = 0; int64_t len = 0; HpackField ftype = hpack_parse_field_type(*p); bool has_http2_violation = false; if (ftype == HpackField::INDEXED_LITERAL) { - len = decode_integer(index, p, buf_end, 6); + len = xpack_decode_integer(index, p, buf_end, 6); isIncremental = true; } else if (ftype == HpackField::NEVERINDEX_LITERAL) { - len = decode_integer(index, p, buf_end, 4); + len = xpack_decode_integer(index, p, buf_end, 4); } else { ink_assert(ftype == HpackField::NOINDEX_LITERAL); - len = decode_integer(index, p, buf_end, 4); + len = xpack_decode_integer(index, p, buf_end, 4); } - if (len == HPACK_ERROR_COMPRESSION_ERROR) { + if (len == XPACK_ERROR_COMPRESSION_ERROR) { return HPACK_ERROR_COMPRESSION_ERROR; } @@ -799,10 +633,10 @@ decode_literal_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start, indexing_table.get_header_field(index, header); } else { char *name_str = nullptr; - uint32_t name_str_len = 0; + uint64_t name_str_len = 0; - len = decode_string(arena, &name_str, name_str_len, p, buf_end); - if (len == HPACK_ERROR_COMPRESSION_ERROR) { + len = xpack_decode_string(arena, &name_str, name_str_len, p, buf_end); + if (len == XPACK_ERROR_COMPRESSION_ERROR) { return HPACK_ERROR_COMPRESSION_ERROR; } @@ -821,10 +655,10 @@ decode_literal_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start, // Decode header field value char *value_str = nullptr; - uint32_t value_str_len = 0; + uint64_t value_str_len = 0; - len = decode_string(arena, &value_str, value_str_len, p, buf_end); - if (len == HPACK_ERROR_COMPRESSION_ERROR) { + len = xpack_decode_string(arena, &value_str, value_str_len, p, buf_end); + if (len == XPACK_ERROR_COMPRESSION_ERROR) { return HPACK_ERROR_COMPRESSION_ERROR; } @@ -867,9 +701,9 @@ update_dynamic_table_size(const uint8_t *buf_start, const uint8_t *buf_end, Hpac } // Update header table size if its required. - uint32_t size = 0; - int64_t len = decode_integer(size, buf_start, buf_end, 5); - if (len == HPACK_ERROR_COMPRESSION_ERROR) { + uint64_t size = 0; + int64_t len = xpack_decode_integer(size, buf_start, buf_end, 5); + if (len == XPACK_ERROR_COMPRESSION_ERROR) { return HPACK_ERROR_COMPRESSION_ERROR; } diff --git a/proxy/http2/HPACK.h b/proxy/http2/HPACK.h index c20f40f6d47..d581749235a 100644 --- a/proxy/http2/HPACK.h +++ b/proxy/http2/HPACK.h @@ -26,6 +26,7 @@ #include "ts/ink_platform.h" #include "ts/Diags.h" #include "HTTP.h" +#include "../hdrs/XPACK.h" #include @@ -156,10 +157,6 @@ class HpackIndexingTable }; // Low level interfaces -int64_t encode_integer(uint8_t *buf_start, const uint8_t *buf_end, uint32_t value, uint8_t n); -int64_t decode_integer(uint32_t &dst, const uint8_t *buf_start, const uint8_t *buf_end, uint8_t n); -int64_t encode_string(uint8_t *buf_start, const uint8_t *buf_end, const char *value, size_t value_len); -int64_t decode_string(Arena &arena, char **str, uint32_t &str_length, const uint8_t *buf_start, const uint8_t *buf_end); int64_t encode_indexed_header_field(uint8_t *buf_start, const uint8_t *buf_end, uint32_t index); int64_t encode_literal_header_field_with_indexed_name(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper &header, uint32_t index, HpackIndexingTable &indexing_table, HpackField type); diff --git a/proxy/http2/HTTP2.cc b/proxy/http2/HTTP2.cc index 4327e71fb95..5aa80d2cfa2 100644 --- a/proxy/http2/HTTP2.cc +++ b/proxy/http2/HTTP2.cc @@ -23,7 +23,6 @@ #include "HTTP2.h" #include "HPACK.h" -#include "HuffmanCodec.h" #include "ts/ink_assert.h" #include "P_RecCore.h" #include "P_RecProcess.h" diff --git a/proxy/http2/Makefile.am b/proxy/http2/Makefile.am index 67e2f5b6bb1..747aee8d089 100644 --- a/proxy/http2/Makefile.am +++ b/proxy/http2/Makefile.am @@ -48,9 +48,7 @@ libhttp2_a_SOURCES = \ Http2Stream.cc \ Http2Stream.h \ Http2SessionAccept.cc \ - Http2SessionAccept.h \ - HuffmanCodec.cc \ - HuffmanCodec.h + Http2SessionAccept.h if BUILD_TESTS libhttp2_a_SOURCES += \ @@ -58,23 +56,13 @@ libhttp2_a_SOURCES += \ endif check_PROGRAMS = \ - test_Huffmancode \ test_Http2DependencyTree \ test_HPACK TESTS = \ - test_Huffmancode \ test_Http2DependencyTree \ test_HPACK -test_Huffmancode_LDADD = \ - $(top_builddir)/lib/ts/libtsutil.la - -test_Huffmancode_SOURCES = \ - test_Huffmancode.cc \ - HuffmanCodec.cc \ - HuffmanCodec.h - test_Http2DependencyTree_LDADD = \ $(top_builddir)/lib/ts/libtsutil.la @@ -94,8 +82,6 @@ test_HPACK_LDADD = \ test_HPACK_SOURCES = \ test_HPACK.cc \ - HuffmanCodec.cc \ - HuffmanCodec.h \ HPACK.cc \ HPACK.h diff --git a/proxy/http2/RegressionHPACK.cc b/proxy/http2/RegressionHPACK.cc index 399df34e03d..d0745618b41 100644 --- a/proxy/http2/RegressionHPACK.cc +++ b/proxy/http2/RegressionHPACK.cc @@ -326,7 +326,7 @@ REGRESSION_TEST(HPACK_EncodeInteger)(RegressionTest *t, int, int *pstatus) for (const auto &i : integer_test_case) { memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST); - int len = encode_integer(buf, buf + BUFSIZE_FOR_REGRESSION_TEST, i.raw_integer, i.prefix); + int len = xpack_encode_integer(buf, buf + BUFSIZE_FOR_REGRESSION_TEST, i.raw_integer, i.prefix); box.check(len == i.encoded_field_len, "encoded length was %d, expecting %d", len, i.encoded_field_len); box.check(len > 0 && memcmp(buf, i.encoded_field, len) == 0, "encoded value was invalid"); @@ -345,7 +345,8 @@ REGRESSION_TEST(HPACK_EncodeString)(RegressionTest *t, int, int *pstatus) for (unsigned int i = 2; i < sizeof(string_test_case) / sizeof(string_test_case[0]); i++) { memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST); - len = encode_string(buf, buf + BUFSIZE_FOR_REGRESSION_TEST, string_test_case[i].raw_string, string_test_case[i].raw_string_len); + len = xpack_encode_string(buf, buf + BUFSIZE_FOR_REGRESSION_TEST, string_test_case[i].raw_string, + string_test_case[i].raw_string_len); box.check(len == string_test_case[i].encoded_field_len, "encoded length was %d, expecting %d", len, string_test_case[i].encoded_field_len); @@ -471,13 +472,13 @@ REGRESSION_TEST(HPACK_DecodeInteger)(RegressionTest *t, int, int *pstatus) TestBox box(t, pstatus); box = REGRESSION_TEST_PASSED; - uint32_t actual; + uint64_t actual; for (const auto &i : integer_test_case) { - int len = decode_integer(actual, i.encoded_field, i.encoded_field + i.encoded_field_len, i.prefix); + int len = xpack_decode_integer(actual, i.encoded_field, i.encoded_field + i.encoded_field_len, i.prefix); box.check(len == i.encoded_field_len, "decoded length was %d, expecting %d", len, i.encoded_field_len); - box.check(actual == i.raw_integer, "decoded value was %d, expected %d", actual, i.raw_integer); + box.check(actual == i.raw_integer, "decoded value was %" PRIu64 ", expected %d", actual, i.raw_integer); } } @@ -488,15 +489,16 @@ REGRESSION_TEST(HPACK_DecodeString)(RegressionTest *t, int, int *pstatus) Arena arena; char *actual = nullptr; - uint32_t actual_len = 0; + uint64_t actual_len = 0; hpack_huffman_init(); for (const auto &i : string_test_case) { - int len = decode_string(arena, &actual, actual_len, i.encoded_field, i.encoded_field + i.encoded_field_len); + int len = xpack_decode_string(arena, &actual, actual_len, i.encoded_field, i.encoded_field + i.encoded_field_len); box.check(len == i.encoded_field_len, "decoded length was %d, expecting %d", len, i.encoded_field_len); - box.check(actual_len == i.raw_string_len, "length of decoded string was %d, expecting %d", actual_len, i.raw_string_len); + box.check(actual_len == i.raw_string_len, "length of decoded string was %" PRIu64 ", expecting %d", actual_len, + i.raw_string_len); box.check(memcmp(actual, i.raw_string, actual_len) == 0, "decoded string was invalid"); } } From e755cc8500624689612ceccc49ee7ff228b6f834 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 27 Jul 2018 12:19:32 +0900 Subject: [PATCH 0766/1313] Preserve the prefix bits when encoding integer with XPACK --- proxy/hdrs/XPACK.cc | 9 +++++++++ proxy/hdrs/XPACK.h | 1 + proxy/http2/HPACK.cc | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/proxy/hdrs/XPACK.cc b/proxy/hdrs/XPACK.cc index c5378729a0d..73d6e807af7 100644 --- a/proxy/hdrs/XPACK.cc +++ b/proxy/hdrs/XPACK.cc @@ -118,6 +118,9 @@ xpack_encode_integer(uint8_t *buf_start, const uint8_t *buf_end, uint64_t value, uint8_t *p = buf_start; + // Preserve the first n bits + uint8_t prefix = *buf_start & (0xFF << n); + if (value < (static_cast(1 << n) - 1)) { *(p++) = value; } else { @@ -135,6 +138,10 @@ xpack_encode_integer(uint8_t *buf_start, const uint8_t *buf_end, uint64_t value, } *(p++) = value; } + + // Restore the prefix + *buf_start |= prefix; + return p - buf_start; } @@ -168,6 +175,8 @@ xpack_encode_string(uint8_t *buf_start, const uint8_t *buf_end, const char *valu if (use_huffman) { *p |= 0x01 << n; + } else { + *p &= ~(0x01 << n); } p += len; diff --git a/proxy/hdrs/XPACK.h b/proxy/hdrs/XPACK.h index 5e8eca35e44..bb3bc71d079 100644 --- a/proxy/hdrs/XPACK.h +++ b/proxy/hdrs/XPACK.h @@ -24,6 +24,7 @@ #pragma once #include +#include "ts/Arena.h" const static int XPACK_ERROR_COMPRESSION_ERROR = -1; const static int XPACK_ERROR_SIZE_EXCEEDED_ERROR = -2; diff --git a/proxy/http2/HPACK.cc b/proxy/http2/HPACK.cc index fd16460e05a..f51f94727ed 100644 --- a/proxy/http2/HPACK.cc +++ b/proxy/http2/HPACK.cc @@ -465,6 +465,7 @@ encode_literal_header_field_with_indexed_name(uint8_t *buf_start, const uint8_t } // Index + *p = 0; len = xpack_encode_integer(p, buf_end, index, prefix); if (len == -1) { return -1; @@ -553,11 +554,11 @@ encode_literal_header_field_with_new_name(uint8_t *buf_start, const uint8_t *buf int64_t encode_dynamic_table_size_update(uint8_t *buf_start, const uint8_t *buf_end, uint32_t size) { + buf_start[0] = 0x20; const int64_t len = xpack_encode_integer(buf_start, buf_end, size, 5); if (len == -1) { return -1; } - buf_start[0] |= 0x20; return len; } From e4cbf6b1a984fdd1dfdd1ef3fcf0f90166209bd2 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 24 Jul 2018 11:39:36 +0900 Subject: [PATCH 0767/1313] ADD QPACK module --- iocore/eventsystem/I_Event.h | 1 + proxy/hq/Makefile.am | 1 + proxy/hq/QPACK.cc | 1608 ++++++++++++++++++++++++++++++++++ proxy/hq/QPACK.h | 322 +++++++ 4 files changed, 1932 insertions(+) create mode 100644 proxy/hq/QPACK.cc create mode 100644 proxy/hq/QPACK.h diff --git a/iocore/eventsystem/I_Event.h b/iocore/eventsystem/I_Event.h index 4e1938f3166..36239d3d780 100644 --- a/iocore/eventsystem/I_Event.h +++ b/iocore/eventsystem/I_Event.h @@ -75,6 +75,7 @@ #define HTTP_SCH_UPDATE_EVENTS_START 2400 #define QUIC_EVENT_EVENTS_START 2500 #define HQ_SESSION_EVENTS_START 2600 +#define QPACK_EVENT_EVENTS_START 2700 #define NT_ASYNC_CONNECT_EVENT_EVENTS_START 3000 #define NT_ASYNC_IO_EVENT_EVENTS_START 3100 #define RAFT_EVENT_EVENTS_START 3200 diff --git a/proxy/hq/Makefile.am b/proxy/hq/Makefile.am index 32765309f0c..c8dac9ac3f4 100644 --- a/proxy/hq/Makefile.am +++ b/proxy/hq/Makefile.am @@ -45,6 +45,7 @@ libhq_a_SOURCES = \ HQDataFramer.cc \ HQHeaderVIOAdaptor.cc \ HQStreamDataVIOAdaptor.cc \ + QPACK.cc \ QUICSimpleApp.cc # diff --git a/proxy/hq/QPACK.cc b/proxy/hq/QPACK.cc new file mode 100644 index 00000000000..127e3051f17 --- /dev/null +++ b/proxy/hq/QPACK.cc @@ -0,0 +1,1608 @@ +/** @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 "HTTP.h" +#include "XPACK.h" +#include "QPACK.h" +#include "ts/ink_defs.h" +#include "ts/ink_memory.h" + +#define QPACKDebug(fmt, ...) Debug("qpack", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) + +const QPACK::Header QPACK::StaticTable::STATIC_HEADER_FIELDS[] = { + {"", ""}, // Index 0 is invalid + {"static_1", "svalue1"}, + {"static_2", ""}, +}; + +QPACK::QPACK(QUICConnection *qc, size_t maximum_size) : QUICApplication(qc), _dynamic_table(SETTINGS_HEADER_TABLE_SIZE) +{ + SET_HANDLER(&QPACK::event_handler); + + this->_encoder_stream_sending_instructions = new_MIOBuffer(BUFFER_SIZE_INDEX_1K); + this->_decoder_stream_sending_instructions = new_MIOBuffer(BUFFER_SIZE_INDEX_1K); + this->_encoder_stream_sending_instructions_reader = this->_encoder_stream_sending_instructions->alloc_reader(); + this->_decoder_stream_sending_instructions_reader = this->_decoder_stream_sending_instructions->alloc_reader(); +} + +QPACK::~QPACK() {} + +int +QPACK::event_handler(int event, Event *data) +{ + VIO *vio = reinterpret_cast(data); + QUICStreamIO *stream_io = this->_find_stream_io(vio); + int ret; + + switch (event) { + case VC_EVENT_READ_READY: + ret = this->_on_read_ready(*stream_io); + break; + case VC_EVENT_READ_COMPLETE: + ret = EVENT_DONE; + break; + case VC_EVENT_WRITE_READY: + ret = this->_on_write_ready(*stream_io); + case VC_EVENT_WRITE_COMPLETE: + ret = EVENT_DONE; + break; + default: + ret = EVENT_DONE; + } + return ret; +} + +int +QPACK::encode(uint64_t stream_id, HTTPHdr &header_set, MIOBuffer *header_block) +{ + if (!header_block) { + return -1; + } + + uint16_t base_index = this->_largest_known_received_index; + + // Compress headers and record the largest reference + uint16_t referred_index = 0; + uint16_t largest_reference = 0; + uint16_t smallest_reference = 0; + IOBufferBlock *compressed_headers = new_IOBufferBlock(); + compressed_headers->alloc(BUFFER_SIZE_INDEX_2K); + + MIMEFieldIter field_iter; + for (MIMEField *field = header_set.iter_get_first(&field_iter); field != nullptr; field = header_set.iter_get_next(&field_iter)) { + int ret = this->_encode_header(*field, base_index, compressed_headers, referred_index); + largest_reference = std::max(largest_reference, referred_index); + smallest_reference = std::min(smallest_reference, referred_index); + if (ret < 0) { + compressed_headers->free(); + return ret; + } + } + struct EntryReference eref = {smallest_reference, largest_reference}; + this->_references.emplace(stream_id, eref); + + // Make an IOBufferBlock for Header Data Prefix + IOBufferBlock *header_data_prefix = new_IOBufferBlock(); + header_data_prefix->alloc(BUFFER_SIZE_INDEX_128); + this->_encode_prefix(largest_reference, base_index, header_data_prefix); + + header_block->append_block(header_data_prefix); + header_block->append_block(compressed_headers); + + return 0; +} + +int +QPACK::decode(uint64_t stream_id, const uint8_t *header_block, size_t header_block_len, HTTPHdr &hdr, Continuation *cont, + EThread *thread) +{ + if (!cont || !header_block) { + return -1; + } + + if (this->_invalid) { + thread->schedule_imm(cont, QPACK_EVENT_DECODE_FAILED, nullptr); + return 0; + } + + uint64_t tmp = 0; + int64_t ret = xpack_decode_integer(tmp, header_block, header_block + header_block_len, 8); + if (ret < 0 && tmp > 0xFFFF) { + return -1; + } + uint16_t largest_reference = tmp; + + if (this->_dynamic_table.largest_index() < largest_reference) { + // Blocked + if (this->_add_to_blocked_list( + new DecodeRequest(largest_reference, thread, cont, stream_id, header_block, header_block_len, hdr))) { + return 1; + } else { + // Number of blocked streams exceed the limit + return -2; + } + } + + this->_decode(thread, cont, stream_id, header_block, header_block_len, hdr); + + return 0; +} + +int +QPACK::_encode_prefix(uint16_t largest_reference, uint16_t base_index, IOBufferBlock *prefix) +{ + int ret; + if ((ret = xpack_encode_integer(reinterpret_cast(prefix->end()), + reinterpret_cast(prefix->end() + prefix->write_avail()), largest_reference, 8)) < 0) { + return -1; + } + prefix->fill(ret); + + uint16_t delta; + if (base_index < largest_reference) { + prefix->end()[0] |= 0x80; + delta = largest_reference - base_index; + } else { + delta = base_index - largest_reference; + } + if ((ret = xpack_encode_integer(reinterpret_cast(prefix->end()), + reinterpret_cast(prefix->end() + prefix->write_avail()), delta, 7)) < 0) { + return -1; + } + prefix->fill(ret); + + QPACKDebug("Encoded Header Data Prefix: largest_ref=%d, base_index=%d, delta=%d", largest_reference, base_index, delta); + + return 0; +} + +int +QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock *compressed_header, uint16_t &referred_index) +{ + int name_len; + const char *name = field.name_get(&name_len); + int value_len; + const char *value = field.value_get(&value_len); + + // TODO Set never_index flag on/off according to encoding headers + bool never_index = false; + + // Find from tables, and insert / duplicate a entry prior to encode it + LookupResult lookup_result_static; + LookupResult lookup_result_dynamic; + lookup_result_static = StaticTable::lookup(name, name_len, value, value_len); + if (lookup_result_static.match_type != LookupResult::MatchType::EXACT) { + lookup_result_dynamic = this->_dynamic_table.lookup(name, name_len, value, value_len); + if (lookup_result_dynamic.match_type == LookupResult::MatchType::EXACT) { + if (this->_dynamic_table.should_duplicate(lookup_result_dynamic.index)) { + // Duplicate an entry and use the new entry + uint16_t current_index = lookup_result_dynamic.index; + lookup_result_dynamic = this->_dynamic_table.duplicate_entry(current_index); + if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { + this->_write_duplicate(current_index); + QPACKDebug("Wrote Duplicate: current_index=%d", current_index); + } + } + } else if (lookup_result_static.match_type == LookupResult::MatchType::NAME) { + if (never_index) { + // Name in static table is always available. Do nothing. + } else { + // Insert both the name and the value + lookup_result_dynamic = this->_dynamic_table.insert_entry(name, name_len, value, value_len); + if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { + this->_write_insert_without_name_ref(name, name_len, value, value_len); + QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, name, value_len, value); + } + } + } else if (lookup_result_dynamic.match_type == LookupResult::MatchType::NAME) { + if (never_index) { + if (this->_dynamic_table.should_duplicate(lookup_result_dynamic.index)) { + // Duplicate an entry and use the new entry + uint16_t current_index = lookup_result_dynamic.index; + lookup_result_dynamic = this->_dynamic_table.duplicate_entry(current_index); + if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { + this->_write_duplicate(current_index); + QPACKDebug("Wrote Duplicate: current_index=%d", current_index); + } + } + } else { + if (this->_dynamic_table.should_duplicate(lookup_result_dynamic.index)) { + // Duplicate an entry and use the new entry + uint16_t current_index = lookup_result_dynamic.index; + lookup_result_dynamic = this->_dynamic_table.duplicate_entry(current_index); + if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { + this->_write_duplicate(current_index); + QPACKDebug("Wrote Duplicate: current_index=%d", current_index); + } + } else { + // Insert both the name and the value + lookup_result_dynamic = this->_dynamic_table.insert_entry(name, name_len, value, value_len); + if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { + this->_write_insert_without_name_ref(name, name_len, value, value_len); + QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, name, value_len, value); + } + } + } + } else { + if (never_index) { + // Insert only the name + lookup_result_dynamic = this->_dynamic_table.insert_entry(name, name_len, "", 0); + if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { + this->_write_insert_without_name_ref(name, name_len, "", 0); + QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, name, 0, ""); + } + } else { + // Insert both the name and the value + lookup_result_dynamic = this->_dynamic_table.insert_entry(name, name_len, value, value_len); + if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { + this->_write_insert_without_name_ref(name, name_len, value, value_len); + QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, name, value_len, value); + } + } + } + } + + // Encode + if (lookup_result_static.match_type == LookupResult::MatchType::EXACT) { + this->_encode_indexed_header_field(lookup_result_static.index, base_index, false, compressed_header); + QPACKDebug("Encoded Indexed Header Field: abs_index=%d, base_index=%d, dynamic_table=%d", lookup_result_static.index, + base_index, false); + referred_index = lookup_result_static.index; + } else if (lookup_result_dynamic.match_type == LookupResult::MatchType::EXACT) { + if (lookup_result_dynamic.index < this->_largest_known_received_index) { + this->_encode_indexed_header_field(lookup_result_dynamic.index, base_index, true, compressed_header); + QPACKDebug("Encoded Indexed Header Field: abs_index=%d, base_index=%d, dynamic_table=%d", lookup_result_dynamic.index, + base_index, true); + } else { + this->_encode_indexed_header_field_with_postbase_index(lookup_result_dynamic.index, base_index, never_index, + compressed_header); + QPACKDebug("Encoded Indexed Header With Postbase Index: abs_index=%d, base_index=%d, never_index=%d", + lookup_result_dynamic.index, base_index, never_index); + } + this->_dynamic_table.ref_entry(lookup_result_dynamic.index); + referred_index = lookup_result_dynamic.index; + } else if (lookup_result_static.match_type == LookupResult::MatchType::NAME) { + this->_encode_literal_header_field_with_name_ref(lookup_result_static.index, false, base_index, value, value_len, never_index, + compressed_header); + QPACKDebug( + "Encoded Literal Header Field With Name Ref: abs_index=%d, base_index=%d, dynamic_table=%d, value=%.*s, never_index=%d", + lookup_result_static.index, base_index, false, value_len, value, never_index); + referred_index = lookup_result_static.index; + } else if (lookup_result_dynamic.match_type == LookupResult::MatchType::NAME) { + if (lookup_result_dynamic.index <= this->_largest_known_received_index) { + this->_encode_literal_header_field_with_name_ref(lookup_result_dynamic.index, true, base_index, value, value_len, never_index, + compressed_header); + QPACKDebug( + "Encoded Literal Header Field With Name Ref: abs_index=%d, base_index=%d, dynamic_table=%d, value=%.*s, never_index=%d", + lookup_result_dynamic.index, base_index, true, value_len, value, never_index); + } else { + this->_encode_literal_header_field_with_postbase_name_ref(lookup_result_dynamic.index, base_index, value, value_len, + never_index, compressed_header); + QPACKDebug("Encoded Literal Header Field With Postbase Name Ref: abs_index=%d, base_index=%d, value=%.*s, never_index=%d", + lookup_result_dynamic.index, base_index, value_len, value, never_index); + } + this->_dynamic_table.ref_entry(lookup_result_dynamic.index); + referred_index = lookup_result_dynamic.index; + } else { + this->_encode_literal_header_field_without_name_ref(name, name_len, value, value_len, never_index, compressed_header); + QPACKDebug("Encoded Literal Header Field Without Name Ref: name=%.*s, value=%.*s, never_index=%d", name_len, name, value_len, + value, never_index); + } + + return 0; +} + +int +QPACK::_encode_indexed_header_field(uint16_t index, uint16_t base_index, bool dynamic_table, IOBufferBlock *compressed_header) +{ + char *buf = compressed_header->end(); + char *buf_end = buf + compressed_header->write_avail(); + int written = 0; + + // Indexed Header Field + buf[0] = 0x80; + + // References static table or not + if (dynamic_table) { + // Use relative index if we refer Dynamic Table + index = this->_calc_relative_index_from_absolute_index(base_index, index); + } else { + buf[0] |= 0x40; + } + + // Index + int ret; + if ((ret = xpack_encode_integer(reinterpret_cast(buf + written), reinterpret_cast(buf_end), index, 6)) < + 0) { + return ret; + } + written += ret; + + // Finalize and Schedule to send + compressed_header->fill(written); + + return 0; +} + +int +QPACK::_encode_indexed_header_field_with_postbase_index(uint16_t index, uint16_t base_index, bool never_index, + IOBufferBlock *compressed_header) +{ + char *buf = compressed_header->end(); + char *buf_end = buf + compressed_header->write_avail(); + int written = 0; + + // Indexed Header Field with Post-Base Index + buf[0] = 0x10; + + // Index + int ret; + if ((ret = xpack_encode_integer(reinterpret_cast(buf + written), reinterpret_cast(buf_end), + this->_calc_postbase_index_from_absolute_index(base_index, index), 4)) < 0) { + return ret; + } + written += ret; + + // Finalize and Schedule to send + compressed_header->fill(written); + + return 0; +} + +int +QPACK::_encode_literal_header_field_with_name_ref(uint16_t index, bool dynamic_table, uint16_t base_index, const char *value, + int value_len, bool never_index, IOBufferBlock *compressed_header) +{ + char *buf = compressed_header->end(); + char *buf_end = buf + compressed_header->write_avail(); + int written = 0; + + // Literal Header Field With Name Reference + buf[0] = 0x40; + + if (never_index) { + buf[0] |= 0x20; + } + + // References static table or not + if (dynamic_table) { + // Use relative index if we refer Dynamic Table + index = this->_calc_relative_index_from_absolute_index(base_index, index); + } else { + buf[0] |= 0x10; + } + + // Index + int ret; + if ((ret = xpack_encode_integer(reinterpret_cast(buf + written), reinterpret_cast(buf_end), index, 4)) < + 0) { + return ret; + } + written += ret; + + // Value + if ((ret = xpack_encode_string(reinterpret_cast(buf + written), reinterpret_cast(buf_end), value, + value_len)) < 0) { + return ret; + } + written += ret; + + // Finalize and Schedule to send + compressed_header->fill(written); + + return 0; +} + +int +QPACK::_encode_literal_header_field_without_name_ref(const char *name, int name_len, const char *value, int value_len, + bool never_index, IOBufferBlock *compressed_header) +{ + char *buf = compressed_header->end(); + char *buf_end = buf + compressed_header->write_avail(); + int written = 0; + + // Literal Header Field Without Name Reference + buf[0] = 0x20; + + if (never_index) { + buf[0] |= 0x10; + } + + // Name + int ret; + if ((ret = xpack_encode_string(reinterpret_cast(buf + written), reinterpret_cast(buf_end), name, name_len, + 3)) < 0) { + return ret; + } + written += ret; + + // Value + if ((ret = xpack_encode_string(reinterpret_cast(buf + written), reinterpret_cast(buf_end), value, value_len, + 7)) < 0) { + return ret; + } + written += ret; + + // Finalize and Schedule to send + compressed_header->fill(written); + + return 0; +} + +int +QPACK::_encode_literal_header_field_with_postbase_name_ref(uint16_t index, uint16_t base_index, const char *value, int value_len, + bool never_index, IOBufferBlock *compressed_header) +{ + char *buf = compressed_header->end(); + char *buf_end = buf + compressed_header->write_avail(); + int written = 0; + + // Literal Header Field With Post-Base Name Reference + buf[0] = 0x00; + + if (never_index) { + buf[0] |= 0x08; + } + + // Index + int ret; + if ((ret = xpack_encode_integer(reinterpret_cast(buf + written), reinterpret_cast(buf_end), + this->_calc_postbase_index_from_absolute_index(base_index, index), 3)) < 0) { + return ret; + } + written += ret; + + // Value + if ((ret = xpack_encode_string(reinterpret_cast(buf + written), reinterpret_cast(buf_end), value, value_len, + 7)) < 0) { + return ret; + } + written += ret; + + // Finalize and Schedule to send + compressed_header->fill(written); + + return 0; +} + +int +QPACK::_decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr) +{ + // Read index field + int len = 0; + uint64_t index; + int ret = xpack_decode_integer(index, buf, buf + buf_len, 6); + if (ret < 0) { + return -1; + } + len += ret; + + // Lookup a table + const char *name = nullptr; + int name_len = 0; + const char *value = nullptr; + int value_len = 0; + QPACK::LookupResult result; + + if (buf[0] & 0x40) { // Static table + result = StaticTable::lookup(index, &name, &name_len, &value, &value_len); + } else { // Dynamic table + result = this->_dynamic_table.lookup(this->_calc_absolute_index_from_relative_index(base_index, index), &name, &name_len, + &value, &value_len); + } + if (result.match_type != QPACK::LookupResult::MatchType::EXACT) { + return -1; + } + + // Create and attach a header + MIMEField *new_field = hdr.field_create(name, name_len); + new_field->value_set(hdr.m_heap, hdr.m_mime, value, value_len); + hdr.field_attach(new_field); + + QPACKDebug("Decoded Indexed Header Field: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index, result.index, name_len, + name, value_len, value); + + return len; +} + +int +QPACK::_decode_literal_header_field_with_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr) +{ + int read_len = 0; + + // Never index field + bool never_index = false; + if (buf[0] & 0x40) { + never_index = true; + } + + // Read name index field + uint64_t index; + int ret = xpack_decode_integer(index, buf, buf + buf_len, 4); + if (ret < 0) { + return -1; + } + read_len += ret; + + // Lookup the name + const char *name = nullptr; + int name_len = 0; + const char *dummy = nullptr; + int dummy_len = 0; + QPACK::LookupResult result; + + if (buf[0] & 0x10) { // Static table + result = StaticTable::lookup(index, &name, &name_len, &dummy, &dummy_len); + } else { // Dynamic table + result = this->_dynamic_table.lookup(this->_calc_absolute_index_from_relative_index(base_index, index), &name, &name_len, + &dummy, &dummy_len); + } + if (result.match_type != QPACK::LookupResult::MatchType::EXACT) { + return -1; + } + + // Read value + Arena arena; + char *value; + uint64_t value_len; + if ((ret = xpack_decode_string(arena, &value, value_len, buf + read_len, buf + buf_len - read_len, 7)) < 0) { + return -1; + } + read_len += ret; + + // Create and attach a header + this->_attach_header(hdr, name, name_len, value, value_len); + + QPACKDebug("Decoded Literal Header Field With Name Ref: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index, + result.index, name_len, name, static_cast(value_len), value); + + return read_len; +} + +int +QPACK::_decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t buf_len, HTTPHdr &hdr) +{ + int read_len = 0; + + // Never index field + bool never_index = false; + if (buf[0] & 0x10) { + never_index = true; + } + + // Read name and value + Arena arena; + int64_t ret; + char *name; + uint64_t name_len; + if ((ret = xpack_decode_string(arena, &name, name_len, buf, buf + buf_len, 3)) < 0) { + return -1; + } + read_len += ret; + + char *value; + uint64_t value_len; + if ((ret = xpack_decode_string(arena, &value, value_len, buf + read_len, buf + buf_len - read_len, 7)) < 0) { + return -1; + } + read_len += ret; + + // Create and attach a header + this->_attach_header(hdr, name, name_len, value, value_len); + + QPACKDebug("Decoded Literal Header Field Without Name Ref: name=%.*s, value=%.*s", static_cast(name_len), name, + static_cast(value_len), value); + + return read_len; +} + +int +QPACK::_decode_indexed_header_field_with_postbase_index(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr) +{ + // Read index field + int len = 0; + uint64_t index; + int ret = xpack_decode_integer(index, buf, buf + buf_len, 4); + if (ret < 0) { + return -1; + } + len += ret; + + // Lookup a table + const char *name = nullptr; + int name_len = 0; + const char *value = nullptr; + int value_len = 0; + QPACK::LookupResult result; + + result = this->_dynamic_table.lookup(this->_calc_absolute_index_from_postbase_index(base_index, index), &name, &name_len, &value, + &value_len); + if (result.match_type != QPACK::LookupResult::MatchType::EXACT) { + return -1; + } + + // Create and attach a header + this->_attach_header(hdr, name, name_len, value, value_len); + + QPACKDebug("Decoded Indexed Header Field With Postbase Index: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index, + result.index, name_len, name, value_len, value); + + return len; +} + +int +QPACK::_decode_literal_header_field_with_postbase_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr) +{ + int read_len = 0; + + // Never index field + bool never_index = false; + if (buf[0] & 0x08) { + never_index = true; + } + + // Read name index field + uint64_t index; + int ret = xpack_decode_integer(index, buf, buf + buf_len, 3); + if (ret < 0) { + return -1; + } + read_len += ret; + + // Lookup the name + const char *name = nullptr; + int name_len = 0; + const char *dummy = nullptr; + int dummy_len = 0; + QPACK::LookupResult result; + + result = this->_dynamic_table.lookup(this->_calc_absolute_index_from_postbase_index(base_index, index), &name, &name_len, &dummy, + &dummy_len); + if (result.match_type != QPACK::LookupResult::MatchType::EXACT) { + return -1; + } + + // Read value + Arena arena; + char *value; + uint64_t value_len; + if ((ret = xpack_decode_string(arena, &value, value_len, buf + read_len, buf + buf_len - read_len, 7)) < 0) { + return -1; + } + read_len += ret; + + // Create and attach a header + this->_attach_header(hdr, name, name_len, value, value_len); + + QPACKDebug("Decoded Literal Header Field With Postbase Name Ref: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index, + static_cast(index), name_len, name, static_cast(value_len), value); + + return read_len; +} + +int +QPACK::_decode_header(const uint8_t *header_block, size_t header_block_len, HTTPHdr &hdr) +{ + const uint8_t *pos = header_block; + size_t remain_len = header_block_len; + int64_t ret; + + // Decode Header Data Prefix + uint64_t tmp; + if ((ret = xpack_decode_integer(tmp, pos, pos + remain_len, 8)) < 0 && tmp > 0xFFFF) { + return -1; + } + pos += ret; + uint16_t largest_reference = tmp; + + uint64_t delta_base_index; + uint16_t base_index; + if ((ret = xpack_decode_integer(delta_base_index, pos, pos + remain_len, 7)) < 0 && delta_base_index < 0xFFFF) { + return -1; + } + if (pos[0] & 0x80) { + if (delta_base_index == 0) { + return -1; + } + base_index = largest_reference - delta_base_index; + } else { + base_index = largest_reference + delta_base_index; + } + pos += ret; + + // Decode Instructions + while (pos < header_block + header_block_len) { + if (pos[0] & 0x80) { // Index Header Field + ret = this->_decode_indexed_header_field(base_index, pos, remain_len, hdr); + } else if (pos[0] & 0x40) { // Literal Header Field With Name Reference + ret = this->_decode_literal_header_field_with_name_ref(base_index, pos, remain_len, hdr); + } else if (pos[0] & 0x20) { // Literal Header Field Without Name Reference + ret = this->_decode_literal_header_field_without_name_ref(pos, remain_len, hdr); + } else if (pos[0] & 0x10) { // Indexed Header Field With Post-Base Index + ret = this->_decode_indexed_header_field_with_postbase_index(base_index, pos, remain_len, hdr); + } else { // Literal Header Field With Post-Base Name Reference + ret = this->_decode_literal_header_field_with_postbase_name_ref(base_index, pos, remain_len, hdr); + } + if (ret < 0) { + break; + } + pos += ret; + } + + return ret; +} + +void +QPACK::_decode(EThread *ethread, Continuation *cont, uint64_t stream_id, const uint8_t *header_block, size_t header_block_len, + HTTPHdr &hdr) +{ + int event; + if (this->_decode_header(header_block, header_block_len, hdr) < 0) { + event = QPACK_EVENT_DECODE_FAILED; + } else { + event = QPACK_EVENT_DECODE_COMPLETE; + this->_write_header_acknowledgement(stream_id); + } + ethread->schedule_imm(cont, event, &hdr); +} + +bool +QPACK::_add_to_blocked_list(DecodeRequest *decode_request) +{ + if (this->_blocked_list.count() >= SETTINGS_QPACK_BLOCKED_STREAMS) { + return false; + } + + this->_blocked_list.append(decode_request); + return true; +} + +void +QPACK::_update_largest_known_received_index_by_insert_count(uint16_t insert_count) +{ + this->_largest_known_received_index += insert_count; +} + +void +QPACK::_update_largest_known_received_index_by_stream_id(uint64_t stream_id) +{ + uint16_t largest_ref_index = this->_references[stream_id].largest; + if (largest_ref_index > this->_largest_known_received_index) { + this->_largest_known_received_index = largest_ref_index; + } +} + +void +QPACK::_update_reference_counts(uint64_t stream_id) +{ + uint16_t smallest_ref_index = this->_references[stream_id].smallest; + this->_dynamic_table.unref_entry(smallest_ref_index); +} + +void +QPACK::_resume_decode() +{ + DecodeRequest *r = this->_blocked_list.head(); + while (r) { + if (this->_largest_known_received_index >= r->largest_reference()) { + this->_decode(r->thread(), r->continuation(), r->stream_id(), r->header_block(), r->header_block_len(), r->hdr()); + DecodeRequest *tmp = r; + r = DecodeRequest::Linkage::next_ptr(r); + this->_blocked_list.erase(tmp); + delete tmp; + } else { + r = DecodeRequest::Linkage::next_ptr(r); + } + } +} + +void +QPACK::_abort_decode() +{ + this->_invalid = true; + + DecodeRequest *r = this->_blocked_list.head(); + while (r) { + if (this->_largest_known_received_index >= r->largest_reference()) { + r->thread()->schedule_imm(r->continuation(), QPACK_EVENT_DECODE_FAILED, nullptr); + DecodeRequest *tmp = r; + r = DecodeRequest::Linkage::next_ptr(r); + this->_blocked_list.erase(tmp); + delete tmp; + } else { + r = DecodeRequest::Linkage::next_ptr(r); + } + } +} + +int +QPACK::_on_read_ready(QUICStreamIO &stream_io) +{ + QUICStreamId stream_id = stream_io.stream_id(); + if (stream_id == this->_decoder_stream_id) { + return this->_on_decoder_stream_read_ready(stream_io); + } else if (stream_id == this->_encoder_stream_id) { + return this->_on_encoder_stream_read_ready(stream_io); + } else { + ink_assert(!"The stream ID must match either encoder stream id or decoder stream id"); + return EVENT_DONE; + } +} + +int +QPACK::_on_write_ready(QUICStreamIO &stream_io) +{ + QUICStreamId stream_id = stream_io.stream_id(); + if (stream_id == this->_decoder_stream_id) { + return this->_on_decoder_write_ready(stream_io); + } else if (stream_id == this->_encoder_stream_id) { + return this->_on_encoder_write_ready(stream_io); + } else { + ink_assert(!"The stream ID must match either decoder stream id or decoder stream id"); + return EVENT_DONE; + } +} + +int +QPACK::_on_decoder_stream_read_ready(QUICStreamIO &stream_io) +{ + uint8_t buf; + if (stream_io.peek(&buf, 1) > 0) { + if (buf & 0x80) { // Header Acknowledgement + uint64_t stream_id; + if (this->_read_header_acknowledgement(stream_io, stream_id) >= 0) { + QPACKDebug("Received Header Acknowledgement: stream_id=%" PRIu64, stream_id); + this->_update_largest_known_received_index_by_stream_id(stream_id); + this->_update_reference_counts(stream_id); + this->_references.erase(stream_id); + } + } else if (buf & 0x40) { // Stream Cancellation + uint64_t stream_id; + if (this->_read_stream_cancellation(stream_io, stream_id) >= 0) { + QPACKDebug("Received Stream Cancellation: stream_id=%" PRIu64, stream_id); + this->_update_reference_counts(stream_id); + this->_references.erase(stream_id); + } + } else { // Table State Synchronize + uint16_t insert_count; + if (this->_read_table_state_synchronize(stream_io, insert_count) >= 0) { + QPACKDebug("Received Table State Synchronize: inserted_count=%d", insert_count); + this->_update_largest_known_received_index_by_insert_count(insert_count); + } + } + } + + return EVENT_DONE; +} + +int +QPACK::_on_encoder_stream_read_ready(QUICStreamIO &stream_io) +{ + uint8_t buf; + + while (stream_io.peek(&buf, 1) > 0) { + if (buf & 0x80) { // Insert With Name Reference + bool is_static; + uint16_t index; + Arena arena; + char *value; + uint16_t value_len; + if (this->_read_insert_with_name_ref(stream_io, is_static, index, arena, &value, value_len) < 0) { + this->_abort_decode(); + return EVENT_DONE; + } + QPACKDebug("Received Insert With Name Ref: is_static=%d, index=%d, value=%.*s", is_static, index, value_len, value); + this->_dynamic_table.insert_entry(is_static, index, value, value_len); + } else if (buf & 0x40) { // Insert Without Name Reference + Arena arena; + char *name; + uint16_t name_len; + char *value; + uint16_t value_len; + if (this->_read_insert_without_name_ref(stream_io, arena, &name, name_len, &value, value_len) < 0) { + this->_abort_decode(); + return EVENT_DONE; + } + QPACKDebug("Received Insert Without Name Ref: name=%.*s, value=%.*s", name_len, name, value_len, value); + this->_dynamic_table.insert_entry(name, name_len, value, value_len); + } else if (buf & 0x20) { // Dynamic Table Size Update + uint16_t max_size; + if (this->_read_dynamic_table_size_update(stream_io, max_size) < 0) { + this->_abort_decode(); + return EVENT_DONE; + } + QPACKDebug("Received Dynamic Table Size Update: max_size=%d", max_size); + this->_dynamic_table.update_size(max_size); + } else { // Duplicatex + uint16_t index; + if (this->_read_duplicate(stream_io, index) < 0) { + this->_abort_decode(); + return EVENT_DONE; + } + QPACKDebug("Received Duplicate: index=%d", index); + this->_dynamic_table.duplicate_entry(index); + } + + this->_resume_decode(); + } + + return EVENT_DONE; +} + +int +QPACK::_on_decoder_write_ready(QUICStreamIO &stream_io) +{ + int64_t written_len = stream_io.write(this->_decoder_stream_sending_instructions_reader, INT64_MAX); + this->_decoder_stream_sending_instructions_reader->consume(written_len); + return written_len; +} + +int +QPACK::_on_encoder_write_ready(QUICStreamIO &stream_io) +{ + int64_t written_len = stream_io.write(this->_encoder_stream_sending_instructions_reader, INT64_MAX); + this->_encoder_stream_sending_instructions_reader->consume(written_len); + return written_len; +} + +size_t +QPACK::estimate_header_block_size(const HTTPHdr &hdr) +{ + // FIXME Estimate it + return 128 * 1024 * 1024; +} + +const QPACK::LookupResult +QPACK::StaticTable::lookup(uint16_t index, const char **name, int *name_len, const char **value, int *value_len) +{ + const Header &header = STATIC_HEADER_FIELDS[index]; + *name = header.name; + *name_len = header.name_len; + *value = header.value; + *value_len = header.value_len; + return {index, QPACK::LookupResult::MatchType::EXACT}; +} + +const QPACK::LookupResult +QPACK::StaticTable::lookup(const char *name, int name_len, const char *value, int value_len) +{ + QPACK::LookupResult::MatchType match_type = QPACK::LookupResult::MatchType::NONE; + uint16_t i = 0; + int candidate_index = 0; + int n = countof(STATIC_HEADER_FIELDS); + + for (; i < n; ++i) { + const Header &h = STATIC_HEADER_FIELDS[i]; + if (h.name_len == name_len) { + if (memcmp(name, h.name, name_len) == 0) { + if (value_len == h.value_len && memcmp(value, h.value, value_len) == 0) { + // Exact match + match_type = QPACK::LookupResult::MatchType::EXACT; + break; + } else { + // Name match -- Keep it for no exact matchs + match_type = QPACK::LookupResult::MatchType::NAME; + } + candidate_index = i; + } + } + } + return {i, match_type}; +} + +uint16_t +QPACK::_calc_absolute_index_from_relative_index(uint16_t base_index, uint16_t relative_index) +{ + return base_index - relative_index; +} + +uint16_t +QPACK::_calc_absolute_index_from_postbase_index(uint16_t base_index, uint16_t postbase_index) +{ + return base_index + postbase_index + 1; +} + +uint16_t +QPACK::_calc_relative_index_from_absolute_index(uint16_t base_index, uint16_t absolute_index) +{ + return base_index - absolute_index; +} + +uint16_t +QPACK::_calc_postbase_index_from_absolute_index(uint16_t base_index, uint16_t absolute_index) +{ + return absolute_index - base_index - 1; +} + +void +QPACK::_attach_header(HTTPHdr &hdr, const char *name, int name_len, const char *value, int value_len) +{ + MIMEField *new_field = hdr.field_create(name, name_len); + new_field->value_set(hdr.m_heap, hdr.m_mime, value, value_len); + hdr.field_attach(new_field); +} + +// +// DynamicTable +// +QPACK::DynamicTable::DynamicTable(uint16_t size) : _available(size), _storage(new DynamicTableStorage(size)) {} + +QPACK::DynamicTable::~DynamicTable() +{ + if (this->_storage) { + delete this->_storage; + this->_storage = nullptr; + } +} + +const QPACK::LookupResult +QPACK::DynamicTable::lookup(uint16_t index, const char **name, int *name_len, const char **value, int *value_len) +{ + uint16_t pos = (this->_entries_head + (index - this->_entries[this->_entries_head].index)) % countof(this->_entries); + *name_len = this->_entries[pos].name_len; + *value_len = this->_entries[pos].value_len; + this->_storage->read(this->_entries[pos].offset, name, *name_len, value, *value_len); + return {index, QPACK::LookupResult::MatchType::EXACT}; +} + +const QPACK::LookupResult +QPACK::DynamicTable::lookup(const char *name, int name_len, const char *value, int value_len) +{ + QPACK::LookupResult::MatchType match_type = QPACK::LookupResult::MatchType::NONE; + uint16_t i = 0; + uint16_t candidate_index = 0; + const char *tmp_name = nullptr; + const char *tmp_value = nullptr; + int n = countof(this->_entries); + + // TODO Use a tree for better perfomance + for (; i < n; ++i) { + if (name_len != 0 && this->_entries[i].name_len == name_len) { + this->_storage->read(this->_entries[i].offset, &tmp_name, this->_entries[i].name_len, &tmp_value, + this->_entries[i].value_len); + if (memcmp(name, tmp_name, name_len) == 0) { + candidate_index = this->_entries[i].index; + if (value_len == this->_entries[i].value_len && memcmp(value, tmp_value, value_len) == 0) { + // Exact match + match_type = QPACK::LookupResult::MatchType::EXACT; + break; + } else { + // Name match -- Keep it for no exact matchs + match_type = QPACK::LookupResult::MatchType::NAME; + } + } + } + } + return {candidate_index, match_type}; +} + +const QPACK::LookupResult +QPACK::DynamicTable::insert_entry(bool is_static, uint16_t index, const char *value, uint16_t value_len) +{ + // TODO Implement it. + ink_assert(!"not implemented"); + return {}; +} + +const QPACK::LookupResult +QPACK::DynamicTable::insert_entry(const char *name, uint16_t name_len, const char *value, uint16_t value_len) +{ + // Check if we can make enough space to insert a new entry + uint16_t required_len = name_len + value_len; + uint16_t available = this->_available; + uint16_t tail = this->_entries_tail; + while (available < required_len) { + if (this->_entries[tail].ref_count) { + break; + } + available += this->_entries[tail].name_len + this->_entries[tail].value_len; + tail = (tail + 1) % countof(this->_entries); + } + if (available < required_len) { + // We can't insert a new entry because some stream(s) refer an entry that need to be evicted + return {UINT16_C(0), QPACK::LookupResult::MatchType::NONE}; + } + + // Evict + this->_available = available; + this->_entries_tail = tail; + + // Insert + this->_entries_head = (this->_entries_head + 1) % countof(this->_entries); + this->_entries[this->_entries_head] = {++this->_entries_inserted, this->_storage->write(name, name_len, value, value_len), + name_len, value_len, 0}; + this->_available -= required_len; + + return {this->_entries_inserted, value_len ? LookupResult::MatchType::EXACT : LookupResult::MatchType::NAME}; +} + +const QPACK::LookupResult +QPACK::DynamicTable::duplicate_entry(uint16_t current_index) +{ + const char *name; + int name_len; + const char *value; + int value_len; + + this->lookup(current_index, &name, &name_len, &value, &value_len); + return this->insert_entry(name, name_len, value, value_len); +} + +bool +QPACK::DynamicTable::should_duplicate(uint16_t index) +{ + // TODO: Check whether a specified entry should be duplicated + // Just return false for now + return false; +} + +void +QPACK::DynamicTable::update_size(uint16_t max_size) +{ + // TODO Implement it +} + +void +QPACK::DynamicTable::ref_entry(uint16_t index) +{ + ++this->_entries[index].ref_count; +} + +void +QPACK::DynamicTable::unref_entry(uint16_t index) +{ + --this->_entries[index].ref_count; +} + +uint16_t +QPACK::DynamicTable::largest_index() +{ + return this->_entries_inserted; +} + +int +QPACK::_write_insert_with_name_ref(uint16_t index, bool dynamic, const char *value, uint16_t value_len) +{ + IOBufferBlock *instruction = new_IOBufferBlock(); + instruction->alloc(TS_IOBUFFER_SIZE_INDEX_2K); + + char *buf = instruction->end(); + char *buf_end = buf + instruction->write_avail(); + int written = 0; + + // Insert With Name Reference + buf[0] = 0x80; + + // References static table or not + if (!dynamic) { + buf[0] |= 0x40; + } + + // Name Index + int ret; + if ((ret = xpack_encode_integer(reinterpret_cast(buf + written), reinterpret_cast(buf_end), index, 6)) < + 0) { + return ret; + } + written += ret; + + // Value + if ((ret = xpack_encode_string(reinterpret_cast(buf + written), reinterpret_cast(buf_end), value, value_len, + 7)) < 0) { + return ret; + } + written += ret; + + // Finalize and Schedule to send + instruction->fill(written); + this->_encoder_stream_sending_instructions->append_block(instruction); + + return 0; +} + +int +QPACK::_write_insert_without_name_ref(const char *name, int name_len, const char *value, uint16_t value_len) +{ + IOBufferBlock *instruction = new_IOBufferBlock(); + instruction->alloc(TS_IOBUFFER_SIZE_INDEX_2K); + + char *buf = instruction->end(); + char *buf_end = buf + instruction->write_avail(); + int written = 0; + + // Insert Without Name Reference + buf[0] = 0x40; + + // Name + int ret; + if ((ret = xpack_encode_string(reinterpret_cast(buf + written), reinterpret_cast(buf_end), name, name_len, + 5)) < 0) { + return ret; + } + written += ret; + + // Value + if ((ret = xpack_encode_string(reinterpret_cast(buf + written), reinterpret_cast(buf_end), value, value_len, + 7)) < 0) { + return ret; + } + written += ret; + + // Finalize and Schedule to send + instruction->fill(written); + this->_encoder_stream_sending_instructions->append_block(instruction); + + return 0; +} + +int +QPACK::_write_duplicate(uint16_t index) +{ + IOBufferBlock *instruction = new_IOBufferBlock(); + instruction->alloc(TS_IOBUFFER_SIZE_INDEX_2K); + + char *buf = instruction->end(); + char *buf_end = buf + instruction->write_avail(); + int written = 0; + + // Index + int ret; + if ((ret = xpack_encode_integer(reinterpret_cast(buf + written), reinterpret_cast(buf_end), index, 5)) < + 0) { + return ret; + } + written += ret; + + // Finalize and Schedule to send + instruction->fill(written); + this->_encoder_stream_sending_instructions->append_block(instruction); + + return 0; +} + +int +QPACK::_write_dynamic_table_size_update(uint16_t max_size) +{ + IOBufferBlock *instruction = new_IOBufferBlock(); + instruction->alloc(TS_IOBUFFER_SIZE_INDEX_128); + + char *buf = instruction->end(); + char *buf_end = buf + instruction->write_avail(); + int written = 0; + + // Dynamic Table Size Update + buf[0] = 0x20; + + // Max Size + int ret; + if ((ret = xpack_encode_integer(reinterpret_cast(buf + written), reinterpret_cast(buf_end), max_size, 5)) < + 0) { + return ret; + } + written += ret; + + // Finalize and Schedule to send + instruction->fill(written); + this->_encoder_stream_sending_instructions->append_block(instruction); + + return 0; +} + +int +QPACK::_write_table_state_syncrhonize(uint16_t insert_count) +{ + IOBufferBlock *instruction = new_IOBufferBlock(); + instruction->alloc(TS_IOBUFFER_SIZE_INDEX_128); + + char *buf = instruction->end(); + char *buf_end = buf + instruction->write_avail(); + int written = 0; + + // Insert Count + int ret; + if ((ret = xpack_encode_integer(reinterpret_cast(buf + written), reinterpret_cast(buf_end), insert_count, + 6)) < 0) { + return ret; + } + written += ret; + + // Finalize and Schedule to send + instruction->fill(written); + this->_encoder_stream_sending_instructions->append_block(instruction); + + return 0; +} + +int +QPACK::_write_header_acknowledgement(uint64_t stream_id) +{ + IOBufferBlock *instruction = new_IOBufferBlock(); + instruction->alloc(TS_IOBUFFER_SIZE_INDEX_128); + + char *buf = instruction->end(); + char *buf_end = buf + instruction->write_avail(); + int written = 0; + + // Header Acknowledgement + buf[0] = 0x80; + + // Stream ID + int ret; + if ((ret = xpack_encode_integer(reinterpret_cast(buf + written), reinterpret_cast(buf_end), stream_id, 7)) < + 0) { + return ret; + } + written += ret; + + // Finalize and Schedule to send + instruction->fill(written); + this->_encoder_stream_sending_instructions->append_block(instruction); + + return 0; +} + +int +QPACK::_write_stream_cancellation(uint64_t stream_id) +{ + IOBufferBlock *instruction = new_IOBufferBlock(); + instruction->alloc(TS_IOBUFFER_SIZE_INDEX_128); + + char *buf = instruction->end(); + char *buf_end = buf + instruction->write_avail(); + int written = 0; + + // Stream Cancellation + buf[0] = 0x40; + + // Stream ID + int ret; + if ((ret = xpack_encode_integer(reinterpret_cast(buf + written), reinterpret_cast(buf_end), stream_id, 7)) < + 0) { + return ret; + } + written += ret; + + // Finalize and Schedule to send + instruction->fill(written); + this->_encoder_stream_sending_instructions->append_block(instruction); + + return 0; +} + +int +QPACK::_read_insert_with_name_ref(QUICStreamIO &stream_io, bool &is_static, uint16_t &index, Arena &arena, char **value, + uint16_t &value_len) +{ + size_t read_len = 0; + int ret; + uint8_t input[16384]; + int input_len; + input_len = stream_io.peek(input, sizeof(input)); + + // S flag + is_static = input[0] & 0x40; + + // Name Index + uint64_t tmp; + if ((ret = xpack_decode_integer(tmp, input, input + input_len, 6)) < 0 && tmp > 0xFFFF) { + return -1; + } + index = tmp; + read_len += ret; + + // Value + if ((ret = xpack_decode_string(arena, value, tmp, input + read_len, input + input_len, 7)) < 0 && tmp > 0xFF) { + return -1; + } + value_len = tmp; + read_len += ret; + + stream_io.consume(read_len); + + return 0; +} + +int +QPACK::_read_insert_without_name_ref(QUICStreamIO &stream_io, Arena &arena, char **name, uint16_t &name_len, char **value, + uint16_t &value_len) +{ + size_t read_len = 0; + int ret; + uint8_t input[16384]; + int input_len; + input_len = stream_io.peek(input, sizeof(input)); + + // Name + uint64_t tmp; + if ((ret = xpack_decode_string(arena, name, tmp, input, input + input_len, 5)) < 0 && tmp > 0xFFFF) { + return -1; + } + name_len = tmp; + read_len += ret; + + // Value + if ((ret = xpack_decode_string(arena, value, tmp, input + read_len, input + input_len, 7)) < 0 && tmp > 0xFFFF) { + return -1; + } + value_len = tmp; + read_len += ret; + + stream_io.consume(read_len); + + return 0; +} + +int +QPACK::_read_duplicate(QUICStreamIO &stream_io, uint16_t &index) +{ + size_t read_len = 0; + int ret; + uint8_t input[16]; + int input_len; + input_len = stream_io.peek(input, sizeof(input)); + + // Index + uint64_t tmp; + if ((ret = xpack_decode_integer(tmp, input, input + input_len, 5)) < 0 && tmp > 0xFFFF) { + return -1; + } + index = tmp; + read_len += ret; + + stream_io.consume(read_len); + + return 0; +} + +int +QPACK::_read_dynamic_table_size_update(QUICStreamIO &stream_io, uint16_t &max_size) +{ + size_t read_len = 0; + int ret; + uint8_t input[16]; + int input_len; + input_len = stream_io.peek(input, sizeof(input)); + uint64_t tmp; + + // Max Size + if ((ret = xpack_decode_integer(tmp, input, input + input_len, 5)) < 0 && tmp > 0xFFFF) { + return -1; + } + max_size = tmp; + read_len += ret; + + stream_io.consume(read_len); + + return 0; +} + +int +QPACK::_read_table_state_synchronize(QUICStreamIO &stream_io, uint16_t &insert_count) +{ + size_t read_len = 0; + int ret; + uint8_t input[16]; + int input_len; + input_len = stream_io.peek(input, sizeof(input)); + uint64_t tmp; + + // Insert Count + if ((ret = xpack_decode_integer(tmp, input, input + input_len, 6)) < 0 && tmp > 0xFFFF) { + return -1; + } + insert_count = tmp; + read_len += ret; + + stream_io.consume(read_len); + + return 0; +} + +int +QPACK::_read_header_acknowledgement(QUICStreamIO &stream_io, uint64_t &stream_id) +{ + size_t read_len = 0; + int ret; + uint8_t input[16]; + int input_len; + input_len = stream_io.peek(input, sizeof(input)); + + // Stream ID + // FIXME xpack_decode_integer does not support uint64_t + if ((ret = xpack_decode_integer(stream_id, input, input + input_len, 7)) < 0) { + return -1; + } + read_len += ret; + + stream_io.consume(read_len); + + return 0; +} + +int +QPACK::_read_stream_cancellation(QUICStreamIO &stream_io, uint64_t &stream_id) +{ + size_t read_len = 0; + int ret; + uint8_t input[16]; + int input_len; + input_len = stream_io.peek(input, sizeof(input)); + + // Stream ID + // FIXME xpack_decode_integer does not support uint64_t + if ((ret = xpack_decode_integer(stream_id, input, input + input_len, 6)) < 0) { + return -1; + } + read_len += ret; + + stream_io.consume(read_len); + + return 0; +} + +// +// DynamicTableStorage +// + +QPACK::DynamicTableStorage::DynamicTableStorage(uint16_t size) : _head(size * 2 - 1), _tail(size * 2 - 1) +{ + this->_data_size = size * 2; + this->_data = reinterpret_cast(ats_malloc(this->_data_size)); + this->_overwrite_threshold = size; +} + +QPACK::DynamicTableStorage::~DynamicTableStorage() +{ + if (this->_data) { + ats_free(this->_data); + this->_data = nullptr; + } +} + +void +QPACK::DynamicTableStorage::read(uint16_t offset, const char **name, uint16_t name_len, const char **value, uint16_t value_len) +{ + *name = reinterpret_cast(this->_data + offset); + *value = reinterpret_cast(this->_data + offset + name_len); +} + +uint16_t +QPACK::DynamicTableStorage::write(const char *name, uint16_t name_len, const char *value, uint16_t value_len) +{ + uint16_t offset = (this->_head + 1) % this->_data_size; + memcpy(this->_data + offset, name, name_len); + memcpy(this->_data + offset + name_len, value, value_len); + + this->_head = (this->_head + (name_len + value_len)) % this->_data_size; + if (this->_head > this->_overwrite_threshold) { + this->_head = 0; + } + + return offset; +} + +void +QPACK::DynamicTableStorage::erase(uint16_t name_len, uint16_t value_len) +{ + this->_tail = (this->_tail + (name_len + value_len)) % this->_data_size; +} diff --git a/proxy/hq/QPACK.h b/proxy/hq/QPACK.h new file mode 100644 index 00000000000..53845efdd12 --- /dev/null +++ b/proxy/hq/QPACK.h @@ -0,0 +1,322 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "I_EventSystem.h" +#include "I_Event.h" +#include "ts/IntrusiveDList.h" +#include "MIME.h" +#include "QUICApplication.h" + +class HTTPHdr; + +enum { + QPACK_EVENT_DECODE_COMPLETE = QPACK_EVENT_EVENTS_START, + QPACK_EVENT_DECODE_FAILED, +}; + +// FIXME This setting should be passed by HQ +constexpr int SETTINGS_HEADER_TABLE_SIZE = 4096; +constexpr int SETTINGS_QPACK_BLOCKED_STREAMS = 100; + +class QPACK : public QUICApplication +{ +public: + QPACK(QUICConnection *qc, size_t maximum_size); + virtual ~QPACK(); + + int event_handler(int event, Event *data); + + /* + * header_block must have enough size to store all headers in header_set. + * The maximum size can be estimated with QPACK::estimate_header_block_size(). + */ + int encode(uint64_t stream_id, HTTPHdr &header_set, MIOBuffer *header_block); + + /* + * This will emit either of two events below: + * - QPACK_EVENT_DECODE_COMPLETE (Data: *HTTPHdr) + * - QPACK_EVENT_DECODE_FAILED (Data: nullptr) + */ + int decode(uint64_t stream_id, const uint8_t *header_block, size_t header_block_len, HTTPHdr &hdr, Continuation *cont, + EThread *thread = this_ethread()); + + int cancel(uint64_t stream_id); + + static size_t estimate_header_block_size(const HTTPHdr &header_set); + +private: + struct LookupResult { + uint16_t index = 0; + enum MatchType { NONE, NAME, EXACT } match_type = MatchType::NONE; + }; + + struct Header { + Header(const char *n, const char *v) : name(n), value(v), name_len(strlen(name)), value_len(strlen(value)) {} + const char *name; + const char *value; + const int name_len; + const int value_len; + }; + + class StaticTable + { + public: + static const LookupResult lookup(uint16_t index, const char **name, int *name_len, const char **value, int *value_len); + static const LookupResult lookup(const char *name, int name_len, const char *value, int value_len); + + private: + static const Header STATIC_HEADER_FIELDS[]; + }; + + struct DynamicTableEntry { + uint16_t index = 0; + uint16_t offset = 0; + uint16_t name_len = 0; + uint16_t value_len = 0; + uint16_t ref_count = 0; + }; + + class DynamicTableStorage + { + public: + DynamicTableStorage(uint16_t size); + ~DynamicTableStorage(); + void read(uint16_t offset, const char **name, uint16_t name_len, const char **value, uint16_t value_len); + uint16_t write(const char *name, uint16_t name_len, const char *value, uint16_t value_len); + void erase(uint16_t name_len, uint16_t value_len); + + private: + uint16_t _overwrite_threshold = 0; + uint8_t *_data = nullptr; + uint16_t _data_size = 0; + uint16_t _head = 0; + uint16_t _tail = 0; + }; + + class DynamicTable + { + public: + DynamicTable(uint16_t size); + ~DynamicTable(); + + const LookupResult lookup(uint16_t index, const char **name, int *name_len, const char **value, int *value_len); + const LookupResult lookup(const char *name, int name_len, const char *value, int value_len); + const LookupResult insert_entry(bool is_static, uint16_t index, const char *value, uint16_t value_len); + const LookupResult insert_entry(const char *name, uint16_t name_len, const char *value, uint16_t value_len); + const LookupResult duplicate_entry(uint16_t current_index); + bool should_duplicate(uint16_t index); + void update_size(uint16_t max_size); + void ref_entry(uint16_t index); + void unref_entry(uint16_t index); + uint16_t largest_index(); + + private: + uint16_t _available = 0; + uint16_t _entries_inserted = 0; + + // FIXME It may be better to split this array into small arrays to reduce memory footprint + struct DynamicTableEntry _entries[SETTINGS_HEADER_TABLE_SIZE] = {{}}; + uint16_t _entries_head = sizeof(_entries) - 1; + uint16_t _entries_tail = sizeof(_entries) - 1; + DynamicTableStorage *_storage = nullptr; + }; + + class DecodeRequest + { + public: + DecodeRequest(uint16_t largest_reference, EThread *thread, Continuation *continuation, uint64_t stream_id, + const uint8_t *header_blcok, size_t header_block_len, HTTPHdr &hdr) + : _largest_reference(largest_reference), + _thread(thread), + _continuation(continuation), + _stream_id(stream_id), + _header_block(header_blcok), + _header_block_len(header_block_len), + _hdr(hdr) + { + } + + uint16_t + largest_reference() + { + return this->_largest_reference; + } + + EThread * + thread() + { + return this->_thread; + } + + Continuation * + continuation() + { + return this->_continuation; + } + + uint64_t + stream_id() + { + return this->_stream_id; + } + + const uint8_t * + header_block() + { + return this->_header_block; + } + + size_t + header_block_len() + { + return this->_header_block_len; + } + + HTTPHdr & + hdr() + { + return this->_hdr; + } + + class Linkage + { + public: + static DecodeRequest *& + next_ptr(DecodeRequest *t) + { + return *reinterpret_cast(&t->_next); + } + static DecodeRequest *& + prev_ptr(DecodeRequest *t) + { + return *reinterpret_cast(&t->_prev); + } + }; + + private: + uint16_t _largest_reference; + EThread *_thread; + Continuation *_continuation; + uint64_t _stream_id; + const uint8_t *_header_block; + size_t _header_block_len; + HTTPHdr &_hdr; + + // For IntrusiveDList support + DecodeRequest *_next = nullptr; + DecodeRequest *_prev = nullptr; + }; + + struct EntryReference { + uint16_t smallest; + uint16_t largest; + }; + + DynamicTable _dynamic_table; + std::map _references; + + Continuation *_event_handler = nullptr; + void _resume_decode(); + void _abort_decode(); + + bool _invalid = false; + + IntrusiveDList _blocked_list; + bool _add_to_blocked_list(DecodeRequest *decode_request); + + uint16_t _largest_known_received_index = 0; + void _update_largest_known_received_index_by_insert_count(uint16_t insert_count); + void _update_largest_known_received_index_by_stream_id(uint64_t stream_id); + + void _update_reference_counts(uint64_t stream_id); + + // Encoder Stream + int _read_insert_with_name_ref(QUICStreamIO &stream_io, bool &is_static, uint16_t &index, Arena &arena, char **value, + uint16_t &value_len); + int _read_insert_without_name_ref(QUICStreamIO &stream_io, Arena &arena, char **name, uint16_t &name_len, char **value, + uint16_t &value_len); + int _read_duplicate(QUICStreamIO &stream_io, uint16_t &index); + int _read_dynamic_table_size_update(QUICStreamIO &stream_io, uint16_t &max_size); + int _write_insert_with_name_ref(uint16_t index, bool dynamic, const char *value, uint16_t value_len); + int _write_insert_without_name_ref(const char *name, int name_len, const char *value, uint16_t value_len); + int _write_duplicate(uint16_t index); + int _write_dynamic_table_size_update(uint16_t max_size); + + // Decoder Stream + int _read_table_state_synchronize(QUICStreamIO &stream_io, uint16_t &insert_count); + int _read_header_acknowledgement(QUICStreamIO &stream_io, uint64_t &stream_id); + int _read_stream_cancellation(QUICStreamIO &stream_io, uint64_t &stream_id); + int _write_table_state_syncrhonize(uint16_t insert_count); + int _write_header_acknowledgement(uint64_t stream_id); + int _write_stream_cancellation(uint64_t stream_id); + + // Request and Push Streams + int _encode_prefix(uint16_t largest_reference, uint16_t base_index, IOBufferBlock *prefix); + int _encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock *compressed_header, uint16_t &referred_index); + int _encode_indexed_header_field(uint16_t index, uint16_t base_index, bool dynamic_table, IOBufferBlock *compressed_header); + int _encode_indexed_header_field_with_postbase_index(uint16_t index, uint16_t base_index, bool never_index, + IOBufferBlock *compressed_header); + int _encode_literal_header_field_with_name_ref(uint16_t index, bool dynamic_table, uint16_t base_index, const char *value, + int value_len, bool never_index, IOBufferBlock *compressed_header); + int _encode_literal_header_field_without_name_ref(const char *name, int name_len, const char *value, int value_len, + bool never_index, IOBufferBlock *compressed_header); + int _encode_literal_header_field_with_postbase_name_ref(uint16_t index, uint16_t base_index, const char *value, int value_len, + bool never_index, IOBufferBlock *compressed_header); + + void _decode(EThread *ethread, Continuation *cont, uint64_t stream_id, const uint8_t *header_block, size_t header_block_len, + HTTPHdr &hdr); + int _decode_header(const uint8_t *header_block, size_t header_block_len, HTTPHdr &hdr); + int _decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr); + int _decode_indexed_header_field_with_postbase_index(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr); + int _decode_literal_header_field_with_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr); + int _decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t buf_len, HTTPHdr &hdr); + int _decode_literal_header_field_with_postbase_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr); + + // Utilities + uint16_t _calc_absolute_index_from_relative_index(uint16_t base_index, uint16_t relative_index); + uint16_t _calc_absolute_index_from_postbase_index(uint16_t base_index, uint16_t postbase_index); + uint16_t _calc_relative_index_from_absolute_index(uint16_t base_index, uint16_t absolute_index); + uint16_t _calc_postbase_index_from_absolute_index(uint16_t base_index, uint16_t absolute_index); + void _attach_header(HTTPHdr &hdr, const char *name, int name_len, const char *value, int value_len); + + int _on_read_ready(QUICStreamIO &stream_io); + int _on_decoder_stream_read_ready(QUICStreamIO &stream_io); + int _on_encoder_stream_read_ready(QUICStreamIO &stream_io); + + int _on_write_ready(QUICStreamIO &stream_io); + int _on_decoder_write_ready(QUICStreamIO &stream_io); + int _on_encoder_write_ready(QUICStreamIO &stream_io); + + // Stream numbers + // FIXME How are these stream ids negotiated? In interop, encoder stream id have to be 0 and decoder stream id must not be used. + uint64_t _encoder_stream_id = 0; + uint64_t _decoder_stream_id = 9999; + + // Chain of sending instructions + MIOBuffer *_encoder_stream_sending_instructions; + MIOBuffer *_decoder_stream_sending_instructions; + IOBufferReader *_encoder_stream_sending_instructions_reader; + IOBufferReader *_decoder_stream_sending_instructions_reader; +}; From 4c0dc178fa412e48dc0a043d0e97df88986a0e4a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 27 Jul 2018 12:23:49 +0900 Subject: [PATCH 0768/1313] Add tests for QPACK --- proxy/hq/Makefile.am | 31 ++- proxy/hq/test/main_qpack.cc | 100 +++++++++ proxy/hq/test/stub.cc | 88 ++++++++ proxy/hq/test/test_QPACK.cc | 433 ++++++++++++++++++++++++++++++++++++ 4 files changed, 651 insertions(+), 1 deletion(-) create mode 100644 proxy/hq/test/main_qpack.cc create mode 100644 proxy/hq/test/stub.cc create mode 100644 proxy/hq/test/test_QPACK.cc diff --git a/proxy/hq/Makefile.am b/proxy/hq/Makefile.am index c8dac9ac3f4..0afc84faebd 100644 --- a/proxy/hq/Makefile.am +++ b/proxy/hq/Makefile.am @@ -52,7 +52,8 @@ libhq_a_SOURCES = \ # Check Programs # check_PROGRAMS = \ - test_libhq + test_libhq \ + test_qpack TESTS = $(check_PROGRAMS) @@ -73,6 +74,34 @@ test_libhq_LDADD = \ $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/lib/ts/libtsutil.la +test_qpack_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(abs_top_srcdir)/tests/include + +test_qpack_LDFLAGS = \ + @AM_LDFLAGS@ + +test_qpack_SOURCES = \ + ./test/main_qpack.cc \ + ./test/test_HQFrame.cc \ + ./test/test_HQFrameDispatcher.cc \ + ./test/test_QPACK.cc \ + $(top_builddir)/proxy/http/HttpConfig.cc \ + $(top_builddir)/proxy/http/HttpConnectionCount.cc \ + $(top_builddir)/proxy/http/ForwardedConfig.cc \ + ./test/stub.cc + +test_qpack_LDADD = \ + libhq.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/proxy/libproxy.a \ + $(top_builddir)/proxy/hdrs/libhdrs.a \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a + # # clang-tidy # diff --git a/proxy/hq/test/main_qpack.cc b/proxy/hq/test/main_qpack.cc new file mode 100644 index 00000000000..b5c7380887a --- /dev/null +++ b/proxy/hq/test/main_qpack.cc @@ -0,0 +1,100 @@ +/** @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. + */ + +// To make compile faster +// https://github.com/philsquared/Catch/blob/master/docs/slow-compiles.md +// #define CATCH_CONFIG_MAIN +#define CATCH_CONFIG_RUNNER +#include "catch.hpp" + +#include "ts/I_Layout.h" +#include "ts/Diags.h" + +#include "I_EventSystem.h" +#include "RecordsConfig.h" + +#include "QUICConfig.h" +#include "HuffmanCodec.h" +#include "QPACK.h" +#include "HTTP.h" + +#define TEST_THREADS 1 + +char qifdir[256] = "test/qif/"; +int tablesize = 4096; +int streams = 100; +int ackmode = 0; +char appname[256] = "ats"; + +struct EventProcessorListener : Catch::TestEventListenerBase { + using TestEventListenerBase::TestEventListenerBase; // inherit constructor + + virtual void + testRunStarting(Catch::TestRunInfo const &testRunInfo) override + { + BaseLogFile *base_log_file = new BaseLogFile("stderr"); + diags = new Diags(testRunInfo.name.c_str(), "" /* tags */, "" /* actions */, base_log_file); + diags->activate_taglist("qpack", DiagsTagType_Debug); + diags->config.enabled[DiagsTagType_Debug] = true; + diags->show_location = SHOW_LOCATION_DEBUG; + + Layout::create(); + RecProcessInit(RECM_STAND_ALONE); + LibRecordsConfigInit(); + + QUICConfig::startup(); + + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + eventProcessor.start(TEST_THREADS); + + Thread *main_thread = new EThread; + main_thread->set_specific(); + + url_init(); + mime_init(); + http_init(); + hpack_huffman_init(); + } +}; +CATCH_REGISTER_LISTENER(EventProcessorListener); + +int +main(int argc, char *argv[]) +{ + Catch::Session session; + using namespace Catch::clara; + auto cli = session.cli() | Opt(qifdir, "dir")["--q-qif-dir"]("path for a directory that contains QIF files (default:test/qif/") | + Opt(tablesize, "size")["--q-dynamic-table-size"]("dynamic table size: 0-65535 (default:4096)") | + Opt(streams, "n")["--q-max-blocked-streams"]("max blocked streams: 0-65535 (default:100)") | + Opt(ackmode, "mode")["--q-ack-mode"]("acknowledgement mode: none(default:0) or immediate(1)") | + Opt(appname, "app")["--q-app"]("app name: app name (default:ats)"); + + session.cli(cli); + + int returnCode = session.applyCommandLine(argc, argv); + if (returnCode != 0) { + return returnCode; + } + + return session.run(); +} diff --git a/proxy/hq/test/stub.cc b/proxy/hq/test/stub.cc new file mode 100644 index 00000000000..59491783f51 --- /dev/null +++ b/proxy/hq/test/stub.cc @@ -0,0 +1,88 @@ +/** @file + * + * Stubs for QUICConfig + * + * @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 "ts/ink_assert.h" + +#include "P_SSLConfig.h" + +bool +SSLParseCertificateConfiguration(const SSLConfigParams *, SSL_CTX *) +{ + return false; +} + +SSLConfigParams * +SSLConfig::acquire() +{ + return nullptr; +} + +void +SSLConfig::release(SSLConfigParams *) +{ + return; +} + +#include "P_SSLNextProtocolSet.h" + +bool +SSLNextProtocolSet::advertiseProtocols(const unsigned char **out, unsigned *len) const +{ + return true; +} + +#include "InkAPIInternal.h" +int +APIHook::invoke(int, void *) +{ + ink_assert(false); + return 0; +} + +APIHook * +APIHook::next() const +{ + ink_assert(false); + return nullptr; +} + +APIHook * +APIHooks::get() const +{ + ink_assert(false); + return nullptr; +} + +void +APIHooks::clear() +{ +} + +void +APIHooks::prepend(INKContInternal *cont) +{ +} + +void +APIHooks::append(INKContInternal *cont) +{ +} diff --git a/proxy/hq/test/test_QPACK.cc b/proxy/hq/test/test_QPACK.cc new file mode 100644 index 00000000000..2e1e91c1865 --- /dev/null +++ b/proxy/hq/test/test_QPACK.cc @@ -0,0 +1,433 @@ +/** @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 "catch.hpp" +#include +#include +#include +#include "XPACK.h" +#include "QPACK.h" +#include "HTTP.h" +#include "../../iocore/net/quic/Mock.h" + +// Declared in main_qpack.cc +extern char qifdir[256]; +extern int tablesize; +extern int streams; +extern int ackmode; +extern char appname[256]; + +constexpr int ACK_MODE_IMMEDIATE = 1; +constexpr int ACK_MODE_NONE = 0; + +class TestQUICConnection : public MockQUICConnection +{ +}; + +class QUICApplicationDriver +{ +public: + QUICApplicationDriver() {} + + QUICConnection * + get_connection() + { + return &this->_connection; + } + +private: + TestQUICConnection _connection; +}; + +class TestQUICStream : public QUICStream +{ +public: + TestQUICStream(QUICStreamId sid) : QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), sid) {} + + void + write(const uint8_t *buf, size_t buf_len, QUICOffset offset, bool last) + { + this->_write_to_read_vio(offset, buf, buf_len, last); + this->_signal_read_event(); + } + + size_t + read(uint8_t *buf, size_t buf_len) + { + this->_signal_write_event(); + IOBufferReader *reader = this->_write_vio.get_reader(); + return reader->read(buf, buf_len); + } +}; + +class TestQPACKEventHandler : public Continuation +{ +public: + TestQPACKEventHandler() : Continuation() { SET_HANDLER(&TestQPACKEventHandler::event_handler); } + + int + event_handler(int event, Event *data) + { + this->_event = event; + return 0; + } + + int + last_event() + { + return this->_event; + } + +private: + int _event = 0; +}; + +static int +load_qif_file(const char *filename, HTTPHdr **headers) +{ + HTTPHdr *hdr = nullptr; + int n = 0; + std::ifstream ifs(filename); + std::string line; + + while (std::getline(ifs, line)) { + if (line.empty()) { + if (hdr) { + headers[n++] = hdr; + hdr = nullptr; + } else { + continue; + } + } else if (line.at(0) == '#') { + continue; + } else { + if (!hdr) { + hdr = new HTTPHdr(); + hdr->create(HTTP_TYPE_REQUEST); + } + auto tab = line.find_first_of('\t'); + auto name = line.substr(0, tab); + auto value = line.substr(tab + 1); + hdr->value_set(name.c_str(), tab, value.c_str(), line.length() - tab - 1); + } + } + if (hdr) { + headers[n++] = hdr; + } + + return n; +} + +void +output_encoder_stream_data(FILE *fd, TestQUICStream *stream) +{ + uint8_t buf[1024]; + + // Write StreamId (0) + uint64_t stream_id = 0; + fwrite(reinterpret_cast(&stream_id), 8, 1, fd); + + // Skip 32 bits for Legnth + fseek(fd, 4, SEEK_CUR); + + // Write QPACKData + uint64_t total, nread; + total = 0; + while ((nread = stream->read(buf, sizeof(buf))) > 0) { + fwrite(buf, nread, 1, fd); + total += nread; + } + + // Back to the posistion for Length + fseek(fd, -(total + 4), SEEK_CUR); + + // Write Length + uint32_t len = htobe32(total); + fwrite(reinterpret_cast(&len), 4, 1, fd); + + // Back to the tail + fseek(fd, 0, SEEK_END); +} + +void +output_encoded_data(FILE *fd, uint64_t stream_id, IOBufferReader *header_block_reader) +{ + uint8_t buf[1024]; + + // Write StreamId + stream_id = htobe64(stream_id); + fwrite(reinterpret_cast(&stream_id), 8, 1, fd); + + // Skip 32 bits for Legnth + fseek(fd, 4, SEEK_CUR); + + // Write QPACKData + int64_t total, nread; + total = 0; + while ((nread = header_block_reader->read(buf, sizeof(buf))) > 0) { + fwrite(buf, nread, 1, fd); + total += nread; + } + + // Back to the posistion for Length + fseek(fd, -(total + 4), SEEK_CUR); + + // Write Length + uint32_t len = htobe32(total); + fwrite(reinterpret_cast(&len), 4, 1, fd); + + // Back to the tail + fseek(fd, 0, SEEK_END); +} + +void +output_decoded_headers(FILE *fd, HTTPHdr **headers, uint64_t n) +{ + for (uint64_t i = 0; i < n; ++i) { + HTTPHdr *header_set = headers[i]; + if (!header_set) { + continue; + } + fprintf(fd, "# stream %llu\n", i + 1); + MIMEFieldIter field_iter; + for (MIMEField *field = header_set->iter_get_first(&field_iter); field != nullptr; + field = header_set->iter_get_next(&field_iter)) { + int name_len; + int value_len; + const char *name = field->name_get(&name_len); + const char *value = field->value_get(&value_len); + fprintf(fd, "%.*s\t%.*s\n", name_len, name, value_len, value); + } + fprintf(fd, "\n"); + } +} + +static int +read_block(FILE *fd, uint64_t &stream_id, uint8_t **head, uint32_t &block_len) +{ + size_t len; + + // Read Stream ID + len = fread(&stream_id, 1, 8, fd); + if (len != 8) { + return -1; + } + stream_id = be64toh(stream_id); + + // Read Length + len = fread(&block_len, 1, 4, fd); + if (len != 4) { + return -1; + } + block_len = be32toh(block_len); + + // Set the head of block + *head = reinterpret_cast(ats_malloc(block_len)); + len = fread(*head, 1, block_len, fd); + if (len != block_len) { + ats_free(*head); + return -1; + } + + return 0; +} + +void +acknowledge_header_block(TestQUICStream *stream, uint64_t stream_id) +{ + uint8_t buf[128]; + int buf_len = 0; + + buf[0] = 0x80; + int ret = xpack_encode_integer(buf, buf + sizeof(buf), stream_id, 7); + stream->write(buf, ret, 0, stream_id); +} + +static int +test_encode(const char *qif_file, int dts, int mbs, int am) +{ + int ret = 0; + + char output_filename[256]; + sprintf(output_filename, "%s.ats.%d.%d.%d", qif_file, dts, mbs, am); + FILE *fd = fopen(output_filename, "w"); + + HTTPHdr *requests[256] = {nullptr}; + int n_requests = load_qif_file(qif_file, requests); + + QUICApplicationDriver driver; + QPACK *qpack = new QPACK(driver.get_connection(), dts); + TestQUICStream *encoder_stream = new TestQUICStream(0); + TestQUICStream *decoder_stream = new TestQUICStream(9999); + qpack->set_stream(encoder_stream); + qpack->set_stream(decoder_stream); + + uint64_t stream_id = 1; + MIOBuffer *header_block = new_MIOBuffer(); + IOBufferReader *header_block_reader = header_block->alloc_reader(); + for (int i = 0; i < n_requests; ++i) { + HTTPHdr *hdr = requests[i]; + ret = qpack->encode(stream_id, *hdr, header_block); + if (ret < 0) { + break; + } + + output_encoder_stream_data(fd, encoder_stream); + output_encoded_data(fd, stream_id, header_block_reader); + + if (am == ACK_MODE_IMMEDIATE) { + acknowledge_header_block(decoder_stream, stream_id); + } + + ++stream_id; + } + + fflush(fd); + fclose(fd); + + return ret; +} + +static int +test_decode(const char *qif_file, int dts, int mbs, int am, const char *app_name) +{ + int ret = 0; + + char data_filename[256]; + sprintf(data_filename, "%s.%s.%d.%d.%d", qif_file, app_name, dts, mbs, am); + FILE *fd_in = fopen(data_filename, "r"); + + char output_filename[256]; + sprintf(output_filename, "%s.decoded", data_filename); + FILE *fd_out = fopen(output_filename, "w"); + + HTTPHdr *requests[256]; + int n_requests = load_qif_file(qif_file, requests); + + TestQPACKEventHandler *event_handler = new TestQPACKEventHandler(); + + QUICApplicationDriver driver; + QPACK *qpack = new QPACK(driver.get_connection(), dts); + TestQUICStream *encoder_stream = new TestQUICStream(0); + qpack->set_stream(encoder_stream); + + int offset = 0; + uint8_t *block = nullptr; + uint32_t block_len; + int read_len = 0; + + uint64_t stream_id = 1; + HTTPHdr *header_sets[256] = {nullptr}; + int n_headers = 0; + while ((read_len = read_block(fd_in, stream_id, &block, block_len)) >= 0) { + if (stream_id == encoder_stream->id()) { + encoder_stream->write(block, block_len, offset, false); + offset += block_len; + } else { + if (!header_sets[stream_id - 1]) { + header_sets[stream_id - 1] = new HTTPHdr(); + header_sets[stream_id - 1]->create(HTTP_TYPE_REQUEST); + ++n_headers; + } + qpack->decode(stream_id, block, block_len, *header_sets[stream_id - 1], event_handler, eventProcessor.all_ethreads[0]); + } + ats_free(block); + } + + if (!feof(fd_in)) { + return -1; + } + + sleep(3); + + CHECK(event_handler->last_event() == QPACK_EVENT_DECODE_COMPLETE); + + output_decoded_headers(fd_out, header_sets, n_headers); + + for (unsigned int i = 0; i < countof(header_sets); ++i) { + if (header_sets[i]) { + header_sets[i]->destroy(); + delete header_sets[i]; + } + } + + return ret; +} + +TEST_CASE("Encoding", "[qpack]") +{ + struct dirent *d; + DIR *dir = opendir(qifdir); + + if (dir == nullptr) { + return; + } + + struct stat st; + char qif_file[PATH_MAX + 1] = ""; + strcat(qif_file, qifdir); + + while ((d = readdir(dir)) != nullptr) { + char section_name[128]; + sprintf(section_name, "%s: DTS=%d, MBS=%d, AM=%d", d->d_name, tablesize, streams, ackmode); + SECTION(section_name) + { + qif_file[strlen(qifdir)] = '/'; + qif_file[strlen(qifdir) + 1] = '\0'; + ink_strlcat(qif_file, d->d_name, sizeof(qif_file)); + stat(qif_file, &st); + if (S_ISREG(st.st_mode) && strstr(d->d_name, ".qif") == (d->d_name + (strlen(d->d_name) - 4))) { + CHECK(test_encode(qif_file, tablesize, streams, ackmode) == 0); + } + } + } +} + +TEST_CASE("Decoding", "[qpack]") +{ + struct dirent *d; + DIR *dir = opendir(qifdir); + + if (dir == nullptr) { + return; + } + + struct stat st; + char qif_file[PATH_MAX + 1] = ""; + strcat(qif_file, qifdir); + + while ((d = readdir(dir)) != nullptr) { + char section_name[128]; + sprintf(section_name, "%s: DTS=%d, MBS=%d, AM=%d, APP=%s", d->d_name, tablesize, streams, ackmode, appname); + SECTION(section_name) + { + qif_file[strlen(qifdir)] = '/'; + qif_file[strlen(qifdir) + 1] = '\0'; + ink_strlcat(qif_file, d->d_name, sizeof(qif_file)); + stat(qif_file, &st); + if (S_ISREG(st.st_mode) && strstr(d->d_name, ".qif") == (d->d_name + (strlen(d->d_name) - 4))) { + CHECK(test_decode(qif_file, tablesize, streams, ackmode, appname) == 0); + } + } + } +} From ea29ae141cc5891b92f87835cc00f5feaf35a790 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 27 Aug 2018 14:59:27 +0900 Subject: [PATCH 0769/1313] Cleanup: Suppress nbytes on debug log if it is INT64_MAX --- iocore/net/quic/QUICApplication.cc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 54bf199ead8..1d771354264 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -62,8 +62,13 @@ int64_t QUICStreamIO::read(uint8_t *buf, int64_t len) { if (is_debug_tag_set(tag_stream_io)) { - QUICStreamIODebug("nbytes=%" PRId64 " ndone=%" PRId64 " read_avail=%" PRId64 " read_len=%" PRId64, this->_read_vio->nbytes, - this->_read_vio->ndone, this->_read_buffer_reader->read_avail(), len); + if (this->_read_vio->nbytes == INT64_MAX) { + QUICStreamIODebug("nbytes=-" PRId64 " ndone=%" PRId64 " read_avail=%" PRId64 " read_len=%" PRId64, this->_read_vio->ndone, + this->_read_buffer_reader->read_avail(), len); + } else { + QUICStreamIODebug("nbytes=%" PRId64 " ndone=%" PRId64 " read_avail=%" PRId64 " read_len=%" PRId64, this->_read_vio->nbytes, + this->_read_vio->ndone, this->_read_buffer_reader->read_avail(), len); + } } int64_t nread = this->_read_buffer_reader->read(buf, len); @@ -114,8 +119,13 @@ QUICStreamIO::write(IOBufferReader *r, int64_t len) if (bytes_avail > 0) { if (is_debug_tag_set(tag_stream_io)) { - QUICStreamIODebug("nbytes=%" PRId64 " ndone=%" PRId64 " write_avail=%" PRId64 " write_len=%" PRId64, this->_write_vio->nbytes, - this->_write_vio->ndone, bytes_avail, len); + if (this->_write_vio->nbytes == INT64_MAX) { + QUICStreamIODebug("nbytes=- ndone=%" PRId64 " write_avail=%" PRId64 " write_len=%" PRId64, this->_write_vio->ndone, + bytes_avail, len); + } else { + QUICStreamIODebug("nbytes=%" PRId64 " ndone=%" PRId64 " write_avail=%" PRId64 " write_len=%" PRId64, + this->_write_vio->nbytes, this->_write_vio->ndone, bytes_avail, len); + } } int64_t bytes_len = std::min(bytes_avail, len); From 45dd5aecb93d3a6d809a2ed0ae3f6e7badb0bbec Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 27 Aug 2018 15:34:12 +0900 Subject: [PATCH 0770/1313] Fix sending generated STREAM frame --- iocore/net/QUICNetVConnection.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index af40685aac0..a44f136ffac 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1260,9 +1260,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); while (frame) { ++frame_count; - if (++this->_stream_frames_sent % MAX_CONSECUTIVE_STREAMS == 0) { - break; - } if (frame->type() == QUICFrameType::STREAM) { int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), @@ -1271,6 +1268,10 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } this->_store_frame(buf, len, max_frame_size, std::move(frame)); + if (++this->_stream_frames_sent % MAX_CONSECUTIVE_STREAMS == 0) { + break; + } + frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); } From d9e1e1a86d83ef6fa50ce1a7b76c96df9e4dbc13 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 27 Aug 2018 12:57:55 +0900 Subject: [PATCH 0771/1313] Remove handshake stream check --- iocore/net/quic/QUICStreamManager.cc | 4 +--- iocore/net/quic/test/test_QUICStreamManager.cc | 5 ----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index fa8f63734b8..f63715ec8a7 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -302,9 +302,7 @@ QUICStreamManager::total_offset_received() const // FIXME Iterating all (open + closed) streams is expensive for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { - if (s->id() != 0) { - total_offset_received += s->largest_offset_received(); - } + total_offset_received += s->largest_offset_received(); } return total_offset_received; } diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 9f017169685..5f21f279cc1 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -120,11 +120,6 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") CHECK(sm.stream_count() == 2); CHECK(sm.total_offset_received() == 0); - // Stream 0 shoud be out of flow control - std::shared_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(data, 1024, 0, 0); - sm.handle_frame(level, stream_frame_0); - CHECK(sm.total_offset_received() == 0); - // total_offset should be a integer in unit of 1024 octets std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); sm.handle_frame(level, stream_frame_1); From 6e20b57400f0e48f936185cbdf1833ea5939bea6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Aug 2018 10:31:19 +0900 Subject: [PATCH 0772/1313] Remove an unnecessary header inclusion --- iocore/net/quic/QUICStatelessRetry.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/iocore/net/quic/QUICStatelessRetry.cc b/iocore/net/quic/QUICStatelessRetry.cc index 2776537f57c..b9413e343be 100644 --- a/iocore/net/quic/QUICStatelessRetry.cc +++ b/iocore/net/quic/QUICStatelessRetry.cc @@ -27,8 +27,6 @@ #include #include -#include "P_QUICNetVConnection.h" - #include "QUICGlobals.h" #include "QUICConnection.h" From 346940d7e15ccd69c20a948476c4386b6b6433b7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Aug 2018 10:32:29 +0900 Subject: [PATCH 0773/1313] QUICFrameHandler accepts frame as reference but not as smart pointer --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 12 ++-- iocore/net/quic/Mock.h | 8 +-- iocore/net/quic/QUICFrameDispatcher.cc | 2 +- iocore/net/quic/QUICFrameHandler.h | 4 +- iocore/net/quic/QUICHandshake.cc | 12 ++-- iocore/net/quic/QUICHandshake.h | 2 +- iocore/net/quic/QUICLossDetector.cc | 24 ++++---- iocore/net/quic/QUICLossDetector.h | 4 +- iocore/net/quic/QUICPathValidator.cc | 16 +++--- iocore/net/quic/QUICPathValidator.h | 6 +- iocore/net/quic/QUICStreamManager.cc | 56 +++++++++---------- iocore/net/quic/QUICStreamManager.h | 14 ++--- iocore/net/quic/test/test_QUICLossDetector.cc | 8 +-- .../net/quic/test/test_QUICStreamManager.cc | 24 ++++---- 15 files changed, 97 insertions(+), 97 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index b2efbdf8680..ca02b1977ff 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -214,7 +214,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub // QUICConnection (QUICFrameHandler) std::vector interests() override; - QUICErrorUPtr handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) override; + QUICErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICConnection (QUICFrameGenerator) // bool will_generate_frame(QUICEncryptionLevel level); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a44f136ffac..f943c06874f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -450,13 +450,13 @@ QUICNetVConnection::interests() } QUICErrorUPtr -QUICNetVConnection::handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) +QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - switch (frame->type()) { + switch (frame.type()) { case QUICFrameType::MAX_DATA: - this->_remote_flow_controller->forward_limit(std::static_pointer_cast(frame)->maximum_data()); + this->_remote_flow_controller->forward_limit(static_cast(frame).maximum_data()); QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); this->_schedule_packet_write_ready(); @@ -475,14 +475,16 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, std::shared_ptr_switch_to_draining_state(QUICConnectionErrorUPtr( - new QUICConnectionError(std::static_pointer_cast(frame)->error_code()))); + new QUICConnectionError(static_cast(frame).error_code()))); break; default: - QUICConDebug("Unexpected frame type: %02x", static_cast(frame->type())); + QUICConDebug("Unexpected frame type: %02x", static_cast(frame.type())); ink_assert(false); break; } diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index df68c420b86..15bd1883da6 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -37,9 +37,9 @@ class MockQUICStreamManager : public QUICStreamManager MockQUICStreamManager() : QUICStreamManager() {} // Override virtual QUICErrorUPtr - handle_frame(QUICEncryptionLevel level, std::shared_ptr f) override + handle_frame(QUICEncryptionLevel level, const QUICFrame &f) override { - ++_frameCount[static_cast(f->type())]; + ++_frameCount[static_cast(f.type())]; ++_totalFrameCount; return QUICErrorUPtr(new QUICNoError()); @@ -198,9 +198,9 @@ class MockQUICConnection : public QUICConnection } QUICErrorUPtr - handle_frame(QUICEncryptionLevel level, std::shared_ptr f) override + handle_frame(QUICEncryptionLevel level, const QUICFrame &f) override { - ++_frameCount[static_cast(f->type())]; + ++_frameCount[static_cast(f.type())]; ++_totalFrameCount; return QUICErrorUPtr(new QUICNoError()); diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index afb90dd2743..3d5c8769715 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -69,7 +69,7 @@ QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *pa std::vector handlers = this->_handlers[static_cast(type)]; for (auto h : handlers) { - error = h->handle_frame(level, frame); + error = h->handle_frame(level, *frame.get()); // TODO: is there any case to continue this loop even if error? if (error->cls != QUICErrorClass::NONE) { return error; diff --git a/iocore/net/quic/QUICFrameHandler.h b/iocore/net/quic/QUICFrameHandler.h index 2384d609312..005797700dc 100644 --- a/iocore/net/quic/QUICFrameHandler.h +++ b/iocore/net/quic/QUICFrameHandler.h @@ -30,6 +30,6 @@ class QUICFrameHandler { public: virtual ~QUICFrameHandler(){}; - virtual std::vector interests() = 0; - virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) = 0; + virtual std::vector interests() = 0; + virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) = 0; }; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 637b8cc2125..17d1144594d 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -337,18 +337,16 @@ QUICHandshake::interests() } QUICErrorUPtr -QUICHandshake::handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) +QUICHandshake::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - switch (frame->type()) { - case QUICFrameType::CRYPTO: { - QUICCryptoFrameSPtr crypto_frame = std::static_pointer_cast(frame); - error = this->_crypto_streams[static_cast(level)].recv(*crypto_frame); + switch (frame.type()) { + case QUICFrameType::CRYPTO: + error = this->_crypto_streams[static_cast(level)].recv(static_cast(frame)); break; - } default: - QUICHSDebug("Unexpected frame type: %02x", static_cast(frame->type())); + QUICHSDebug("Unexpected frame type: %02x", static_cast(frame.type())); ink_assert(false); break; } diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 4d1ea43a087..eb79f4a1b02 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -47,7 +47,7 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameHandler virtual std::vector interests() override; - virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) override; + virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 548ee9b67db..a316dd7dcbd 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -106,7 +106,7 @@ QUICLossDetector::interests() } QUICErrorUPtr -QUICLossDetector::handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) +QUICLossDetector::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); @@ -114,13 +114,13 @@ QUICLossDetector::handle_frame(QUICEncryptionLevel level, std::shared_ptrtype()) { + switch (frame.type()) { case QUICFrameType::ACK: this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); - this->_on_ack_received(std::dynamic_pointer_cast(frame)); + this->_on_ack_received(static_cast(frame)); break; default: - QUICLDDebug("Unexpected frame type: %02x", static_cast(frame->type())); + QUICLDDebug("Unexpected frame type: %02x", static_cast(frame.type())); ink_assert(false); break; } @@ -209,28 +209,28 @@ QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_ack_on } void -QUICLossDetector::_on_ack_received(const std::shared_ptr &ack_frame) +QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame) { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - this->_largest_acked_packet = ack_frame->largest_acknowledged(); + this->_largest_acked_packet = ack_frame.largest_acknowledged(); // If the largest acked is newly acked, update the RTT. - auto pi = this->_sent_packets.find(ack_frame->largest_acknowledged()); + auto pi = this->_sent_packets.find(ack_frame.largest_acknowledged()); if (pi != this->_sent_packets.end()) { this->_latest_rtt = Thread::get_hrtime() - pi->second->time; - // _latest_rtt is nanosecond but ack_frame->ack_delay is microsecond and scaled + // _latest_rtt is nanosecond but ack_frame.ack_delay is microsecond and scaled // FIXME ack delay exponent has to be read from transport parameters uint8_t ack_delay_exponent = 3; - ink_hrtime delay = HRTIME_USECONDS(ack_frame->ack_delay() << ack_delay_exponent); - this->_update_rtt(this->_latest_rtt, delay, ack_frame->largest_acknowledged()); + ink_hrtime delay = HRTIME_USECONDS(ack_frame.ack_delay() << ack_delay_exponent); + this->_update_rtt(this->_latest_rtt, delay, ack_frame.largest_acknowledged()); } QUICLDVDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); // Find all newly acked packets. - for (auto &&range : this->_determine_newly_acked_packets(*ack_frame)) { + for (auto &&range : this->_determine_newly_acked_packets(ack_frame)) { for (auto ite = this->_sent_packets.begin(); ite != this->_sent_packets.end(); /* no increment here*/) { auto tmp_ite = ite; tmp_ite++; @@ -244,7 +244,7 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr &ac QUICLDVDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); - this->_detect_lost_packets(ack_frame->largest_acknowledged()); + this->_detect_lost_packets(ack_frame.largest_acknowledged()); QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 4bb26ec396f..4adfbee7674 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -116,7 +116,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler int event_handler(int event, Event *edata); std::vector interests() override; - virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, std::shared_ptr) override; + virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; void on_packet_sent(QUICPacketUPtr packet); QUICPacketNumber largest_acked_packet_number(); void reset(); @@ -175,7 +175,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes, QUICPacketUPtr packet); - void _on_ack_received(const std::shared_ptr &ack_frame); + void _on_ack_received(const QUICAckFrame &ack_frame); void _on_packet_acked(const PacketInfo &acked_packet); void _update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICPacketNumber largest_acked); void _detect_lost_packets(QUICPacketNumber largest_acked); diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index bdc6cc6696b..2a54e4fd8df 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -51,19 +51,19 @@ QUICPathValidator::_generate_challenge() } void -QUICPathValidator::_generate_response(std::shared_ptr frame) +QUICPathValidator::_generate_response(const QUICPathChallengeFrame &frame) { - memcpy(this->_incoming_challenge, frame->data(), QUICPathChallengeFrame::DATA_LEN); + memcpy(this->_incoming_challenge, frame.data(), QUICPathChallengeFrame::DATA_LEN); this->_has_outgoing_response = true; } QUICErrorUPtr -QUICPathValidator::_validate_response(std::shared_ptr frame) +QUICPathValidator::_validate_response(const QUICPathResponseFrame &frame) { QUICErrorUPtr error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE)); for (int i = 0; i < 3; ++i) { - if (memcmp(this->_outgoing_challenge + (QUICPathChallengeFrame::DATA_LEN * i), frame->data(), + if (memcmp(this->_outgoing_challenge + (QUICPathChallengeFrame::DATA_LEN * i), frame.data(), QUICPathChallengeFrame::DATA_LEN) == 0) { this->_state = ValidationState::VALIDATED; this->_has_outgoing_challenge = 0; @@ -85,16 +85,16 @@ QUICPathValidator::interests() } QUICErrorUPtr -QUICPathValidator::handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) +QUICPathValidator::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - switch (frame->type()) { + switch (frame.type()) { case QUICFrameType::PATH_CHALLENGE: - this->_generate_response(std::static_pointer_cast(frame)); + this->_generate_response(static_cast(frame)); break; case QUICFrameType::PATH_RESPONSE: - error = this->_validate_response(std::static_pointer_cast(frame)); + error = this->_validate_response(static_cast(frame)); break; default: ink_assert(!"Can't happen"); diff --git a/iocore/net/quic/QUICPathValidator.h b/iocore/net/quic/QUICPathValidator.h index 30d10fb587c..d13723f75c5 100644 --- a/iocore/net/quic/QUICPathValidator.h +++ b/iocore/net/quic/QUICPathValidator.h @@ -37,7 +37,7 @@ class QUICPathValidator : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameHandler std::vector interests() override; - QUICErrorUPtr handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) override; + QUICErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICFrameGeneratro bool will_generate_frame(QUICEncryptionLevel level) override; @@ -56,6 +56,6 @@ class QUICPathValidator : public QUICFrameHandler, public QUICFrameGenerator uint8_t _outgoing_challenge[QUICPathChallengeFrame::DATA_LEN * 3]; void _generate_challenge(); - void _generate_response(std::shared_ptr frame); - QUICErrorUPtr _validate_response(std::shared_ptr frame); + void _generate_response(const QUICPathChallengeFrame &frame); + QUICErrorUPtr _validate_response(const QUICPathResponseFrame &frame); }; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index f63715ec8a7..fd0690b2612 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -136,32 +136,32 @@ QUICStreamManager::reset_stream(QUICStreamId stream_id, QUICStreamErrorUPtr erro } QUICErrorUPtr -QUICStreamManager::handle_frame(QUICEncryptionLevel level, std::shared_ptr frame) +QUICStreamManager::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - switch (frame->type()) { + switch (frame.type()) { case QUICFrameType::MAX_STREAM_DATA: - error = this->_handle_frame(std::static_pointer_cast(frame)); + error = this->_handle_frame(static_cast(frame)); break; case QUICFrameType::STREAM_BLOCKED: // STREAM_BLOCKED frame is for debugging. Just propagate to streams - error = this->_handle_frame(std::static_pointer_cast(frame)); + error = this->_handle_frame(static_cast(frame)); break; case QUICFrameType::STREAM: - error = this->_handle_frame(std::static_pointer_cast(frame)); + error = this->_handle_frame(static_cast(frame)); break; case QUICFrameType::STOP_SENDING: - error = this->_handle_frame(std::static_pointer_cast(frame)); + error = this->_handle_frame(static_cast(frame)); break; case QUICFrameType::RST_STREAM: - error = this->_handle_frame(std::static_pointer_cast(frame)); + error = this->_handle_frame(static_cast(frame)); break; case QUICFrameType::MAX_STREAM_ID: - error = this->_handle_frame(std::static_pointer_cast(frame)); + error = this->_handle_frame(static_cast(frame)); break; default: - Debug(tag, "Unexpected frame type: %02x", static_cast(frame->type())); + Debug(tag, "Unexpected frame type: %02x", static_cast(frame.type())); ink_assert(false); break; } @@ -170,49 +170,49 @@ QUICStreamManager::handle_frame(QUICEncryptionLevel level, std::shared_ptr &frame) +QUICStreamManager::_handle_frame(const QUICMaxStreamDataFrame &frame) { - QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); + QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); if (stream) { - return stream->recv(*frame); + return stream->recv(frame); } else { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); } } QUICErrorUPtr -QUICStreamManager::_handle_frame(const std::shared_ptr &frame) +QUICStreamManager::_handle_frame(const QUICStreamBlockedFrame &frame) { - QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); + QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); if (stream) { - return stream->recv(*frame); + return stream->recv(frame); } else { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); } } QUICErrorUPtr -QUICStreamManager::_handle_frame(const std::shared_ptr &frame) +QUICStreamManager::_handle_frame(const QUICStreamFrame &frame) { - QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); + QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); if (!stream) { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); } - QUICApplication *application = this->_app_map->get(frame->stream_id()); + QUICApplication *application = this->_app_map->get(frame.stream_id()); if (application && !application->is_stream_set(stream)) { application->set_stream(stream); } - QUICErrorUPtr error = stream->recv(*frame); + QUICErrorUPtr error = stream->recv(frame); return error; } QUICErrorUPtr -QUICStreamManager::_handle_frame(const std::shared_ptr &frame) +QUICStreamManager::_handle_frame(const QUICRstStreamFrame &frame) { - QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); + QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); if (stream) { // TODO Reset the stream return QUICErrorUPtr(new QUICNoError()); @@ -222,24 +222,24 @@ QUICStreamManager::_handle_frame(const std::shared_ptr } QUICErrorUPtr -QUICStreamManager::_handle_frame(const std::shared_ptr &frame) +QUICStreamManager::_handle_frame(const QUICStopSendingFrame &frame) { - QUICStream *stream = this->_find_or_create_stream(frame->stream_id()); + QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); if (stream) { - return stream->recv(*frame); + return stream->recv(frame); } else { return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); } } QUICErrorUPtr -QUICStreamManager::_handle_frame(const std::shared_ptr &frame) +QUICStreamManager::_handle_frame(const QUICMaxStreamIdFrame &frame) { - QUICStreamType type = QUICTypeUtil::detect_stream_type(frame->maximum_stream_id()); + QUICStreamType type = QUICTypeUtil::detect_stream_type(frame.maximum_stream_id()); if (type == QUICStreamType::SERVER_BIDI || type == QUICStreamType::CLIENT_BIDI) { - this->_remote_maximum_stream_id_bidi = frame->maximum_stream_id(); + this->_remote_maximum_stream_id_bidi = frame.maximum_stream_id(); } else { - this->_remote_maximum_stream_id_uni = frame->maximum_stream_id(); + this->_remote_maximum_stream_id_uni = frame.maximum_stream_id(); } return QUICErrorUPtr(new QUICNoError()); } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 49bf9b31f84..be5c016c410 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -59,7 +59,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameHandler virtual std::vector interests() override; - virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, std::shared_ptr) override; + virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; @@ -68,12 +68,12 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator private: QUICStream *_find_stream(QUICStreamId id); QUICStream *_find_or_create_stream(QUICStreamId stream_id); - QUICErrorUPtr _handle_frame(const std::shared_ptr &); - QUICErrorUPtr _handle_frame(const std::shared_ptr &); - QUICErrorUPtr _handle_frame(const std::shared_ptr &); - QUICErrorUPtr _handle_frame(const std::shared_ptr &); - QUICErrorUPtr _handle_frame(const std::shared_ptr &); - QUICErrorUPtr _handle_frame(const std::shared_ptr &); + QUICErrorUPtr _handle_frame(const QUICStreamFrame &frame); + QUICErrorUPtr _handle_frame(const QUICRstStreamFrame &frame); + QUICErrorUPtr _handle_frame(const QUICStopSendingFrame &frame); + QUICErrorUPtr _handle_frame(const QUICMaxStreamDataFrame &frame); + QUICErrorUPtr _handle_frame(const QUICStreamBlockedFrame &frame); + QUICErrorUPtr _handle_frame(const QUICMaxStreamIdFrame &frame); std::vector _encryption_level_filter() override { diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 628a96d1409..a414872eb01 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -69,8 +69,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") CHECK(tx->retransmitted.size() > 0); // Receive ACK - std::shared_ptr frame = std::make_shared(0x01, 20, 0); - frame->ack_block_section()->add_ack_block({0, 1ULL}); + QUICAckFrame frame(0x01, 20, 0); + frame.ack_block_section()->add_ack_block({0, 1ULL}); detector.handle_frame(QUICEncryptionLevel::INITIAL, frame); ink_hrtime_sleep(HRTIME_MSECONDS(1500)); int retransmit_count = tx->retransmitted.size(); @@ -144,7 +144,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") ink_hrtime_sleep(HRTIME_MSECONDS(1000)); std::shared_ptr x = afc->generate_frame(QUICEncryptionLevel::INITIAL, 2048, 2048); frame = std::dynamic_pointer_cast(x); - detector.handle_frame(QUICEncryptionLevel::INITIAL, frame); + detector.handle_frame(QUICEncryptionLevel::INITIAL, *frame.get()); ink_hrtime_sleep(HRTIME_MSECONDS(5000)); CHECK(cc->lost_packets.size() == 3); @@ -175,7 +175,7 @@ TEST_CASE("QUICLossDetector_HugeGap", "[quic]") auto t1 = Thread::get_hrtime(); std::shared_ptr ack = QUICFrameFactory::create_ack_frame(100000000, 100, 10000000); ack->ack_block_section()->add_ack_block({20000000, 30000000}); - detector.handle_frame(QUICEncryptionLevel::INITIAL, ack); + detector.handle_frame(QUICEncryptionLevel::INITIAL, *ack.get()); auto t2 = Thread::get_hrtime(); CHECK(t2 - t1 < HRTIME_MSECONDS(100)); } diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 5f21f279cc1..cf463a53428 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -48,31 +48,31 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 1, 0); CHECK(sm.stream_count() == 0); - sm.handle_frame(level, stream_frame_0); + sm.handle_frame(level, *stream_frame_0); CHECK(sm.stream_count() == 1); - sm.handle_frame(level, stream_frame_1); + sm.handle_frame(level, *stream_frame_1); CHECK(sm.stream_count() == 2); // RST_STREAM frames create new streams std::shared_ptr rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(2, static_cast(0x01), 0); - sm.handle_frame(level, rst_stream_frame); + sm.handle_frame(level, *rst_stream_frame); CHECK(sm.stream_count() == 3); // MAX_STREAM_DATA frames create new streams std::shared_ptr max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(3, 0); - sm.handle_frame(level, max_stream_data_frame); + sm.handle_frame(level, *max_stream_data_frame); CHECK(sm.stream_count() == 4); // STREAM_BLOCKED frames create new streams std::shared_ptr stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(4, 0); - sm.handle_frame(level, stream_blocked_frame); + sm.handle_frame(level, *stream_blocked_frame); CHECK(sm.stream_count() == 5); // Set local maximum stream id sm.set_max_stream_id(5); std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_blocked_frame(8, 0); - sm.handle_frame(level, stream_blocked_frame_x); + sm.handle_frame(level, *stream_blocked_frame_x); CHECK(sm.stream_count() == 5); } @@ -93,7 +93,7 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") std::shared_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 7); - sm.handle_frame(level, stream_frame_0); + sm.handle_frame(level, *stream_frame_0); CHECK("succeed"); } @@ -115,14 +115,14 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") // Create a stream with STREAM_BLOCKED (== noop) std::shared_ptr stream_blocked_frame_0 = QUICFrameFactory::create_stream_blocked_frame(0, 0); std::shared_ptr stream_blocked_frame_1 = QUICFrameFactory::create_stream_blocked_frame(1, 0); - sm.handle_frame(level, stream_blocked_frame_0); - sm.handle_frame(level, stream_blocked_frame_1); + sm.handle_frame(level, *stream_blocked_frame_0); + sm.handle_frame(level, *stream_blocked_frame_1); CHECK(sm.stream_count() == 2); CHECK(sm.total_offset_received() == 0); // total_offset should be a integer in unit of 1024 octets std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); - sm.handle_frame(level, stream_frame_1); + sm.handle_frame(level, *stream_frame_1); CHECK(sm.total_offset_received() == 1024); } @@ -146,8 +146,8 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 0); std::shared_ptr stream_frame_1_r = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 1, 0); - sm.handle_frame(level, stream_frame_0_r); - sm.handle_frame(level, stream_frame_1_r); + sm.handle_frame(level, *stream_frame_0_r); + sm.handle_frame(level, *stream_frame_1_r); CHECK(sm.stream_count() == 2); CHECK(sm.total_offset_sent() == 0); From 171d0d0a403b2a6f9fb2c8e6e0c9edcf1194b742 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Aug 2018 10:56:45 +0900 Subject: [PATCH 0774/1313] Cast to appropriate frame type --- iocore/net/QUICNetVConnection.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index f943c06874f..2b833b3e189 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -475,13 +475,16 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra return error; } - // FIXME ConnectionCloseFrame is cast to ApplicationCloseFrame - // 7.9.1. Closing and Draining Connection States // An endpoint MAY transition from the closing period to the draining period if it can confirm that its peer is also closing or // draining. Receiving a closing frame is sufficient confirmation, as is receiving a stateless reset. - this->_switch_to_draining_state(QUICConnectionErrorUPtr( - new QUICConnectionError(static_cast(frame).error_code()))); + if (frame.type() == QUICFrameType::APPLICATION_CLOSE) { + this->_switch_to_draining_state( + QUICConnectionErrorUPtr(new QUICConnectionError(static_cast(frame).error_code()))); + } else { + this->_switch_to_draining_state( + QUICConnectionErrorUPtr(new QUICConnectionError(static_cast(frame).error_code()))); + } break; default: QUICConDebug("Unexpected frame type: %02x", static_cast(frame.type())); From cb79e0257d04b2110dd310d3a1378c99c651e9c2 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Aug 2018 11:28:36 +0900 Subject: [PATCH 0775/1313] Remove ssl_handle() from QUICHandshake --- iocore/net/quic/Mock.h | 13 +++++++++++++ iocore/net/quic/QUICHandshake.cc | 14 ++------------ iocore/net/quic/QUICHandshakeProtocol.h | 2 ++ iocore/net/quic/QUICTLS.cc | 18 ++++++++++++------ iocore/net/quic/QUICTLS.h | 5 ++--- 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 15bd1883da6..b282b8c0e4d 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -556,6 +556,19 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol return 0; } + const char * + negotiated_cipher_suite() const override + { + return nullptr; + } + + void + negotiated_application_name(const uint8_t **name, unsigned int *len) const override + { + *name = reinterpret_cast("hq"); + *len = 2; + } + bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 17d1144594d..96ab76521cb 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -219,23 +219,13 @@ QUICHandshake::negotiated_version() const char * QUICHandshake::negotiated_cipher_suite() { - // FIXME Generalize and remove dynamic_cast - QUICTLS *hs_tls = dynamic_cast(this->_hs_protocol); - if (hs_tls) { - return SSL_get_cipher_name(hs_tls->ssl_handle()); - } - - return nullptr; + return this->_hs_protocol->negotiated_cipher_suite(); } void QUICHandshake::negotiated_application_name(const uint8_t **name, unsigned int *len) { - // FIXME Generalize and remove dynamic_cast - QUICTLS *hs_tls = dynamic_cast(this->_hs_protocol); - if (hs_tls) { - SSL_get0_alpn_selected(hs_tls->ssl_handle(), name, len); - } + this->_hs_protocol->negotiated_application_name(name, len); } void diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 88dc369d3b9..3627e414640 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -76,6 +76,8 @@ class QUICHandshakeProtocol virtual bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const = 0; virtual int initialize_key_materials(QUICConnectionId cid) = 0; virtual int update_key_materials() = 0; + virtual const char *negotiated_cipher_suite() const = 0; + virtual void negotiated_application_name(const uint8_t **name, unsigned int *len) const = 0; virtual bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; virtual bool decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher, size_t cipher_len, diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index fb8803e8dc7..21b35990500 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -122,6 +122,18 @@ QUICTLS::update_key_materials() return 1; } +const char * +QUICTLS::negotiated_cipher_suite() const +{ + return SSL_get_cipher_name(this->_ssl); +} + +void +QUICTLS::negotiated_application_name(const uint8_t **name, unsigned int *len) const +{ + SSL_get0_alpn_selected(this->_ssl, name, len); +} + QUICEncryptionLevel QUICTLS::current_encryption_level() const { @@ -146,12 +158,6 @@ QUICTLS::_update_encryption_level(QUICEncryptionLevel level) return; } -SSL * -QUICTLS::ssl_handle() -{ - return this->_ssl; -} - bool QUICTLS::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 81fd96deed6..febdedfbb74 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -58,6 +58,8 @@ class QUICTLS : public QUICHandshakeProtocol int initialize_key_materials(QUICConnectionId cid) override; int update_key_materials() override; void update_key_materials_on_key_cb(std::unique_ptr km, int name); + const char *negotiated_cipher_suite() const override; + void negotiated_application_name(const uint8_t **name, unsigned int *len) const override; bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override; bool decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher, size_t cipher_len, uint64_t pkt_num, @@ -69,9 +71,6 @@ class QUICTLS : public QUICHandshakeProtocol QUICEncryptionLevel current_encryption_level() const override; void abort_handshake() override; - // FIXME SSL handle should not be exported - SSL *ssl_handle(); - private: QUICKeyGenerator _keygen_for_client = QUICKeyGenerator(QUICKeyGenerator::Context::CLIENT); QUICKeyGenerator _keygen_for_server = QUICKeyGenerator(QUICKeyGenerator::Context::SERVER); From deaa9d0cd1b4b21760a53b35304c6afcb8a71a12 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Aug 2018 12:05:19 +0900 Subject: [PATCH 0776/1313] Remove an unused member QUICTLS::_stateless --- iocore/net/quic/QUICHandshake.cc | 2 +- iocore/net/quic/QUICTLS.h | 2 -- iocore/net/quic/QUICTLS_openssl.cc | 6 ++---- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 96ab76521cb..dc5834e7a99 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -92,7 +92,7 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandsha QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token, bool stateless_retry) : _qc(qc), _ssl(SSL_new(ssl_ctx)), - _hs_protocol(new QUICTLS(this->_ssl, qc->direction(), stateless_retry)), + _hs_protocol(new QUICTLS(this->_ssl, qc->direction())), _version_negotiator(new QUICVersionNegotiator()), _reset_token(token), _stateless_retry(stateless_retry) diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index febdedfbb74..d7c8cbca395 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -40,7 +40,6 @@ class QUICTLS : public QUICHandshakeProtocol { public: QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx); - QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless); ~QUICTLS(); // TODO: integrate with _early_data_processed @@ -97,7 +96,6 @@ class QUICTLS : public QUICHandshakeProtocol QUICPacketProtection *_client_pp = nullptr; QUICPacketProtection *_server_pp = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; - bool _stateless = false; bool _early_data_processed = false; bool _early_data = true; QUICEncryptionLevel _current_level = QUICEncryptionLevel::INITIAL; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 9c1be675b66..319195bf9b9 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -215,10 +215,8 @@ QUICTLS::update_key_materials_on_key_cb(std::unique_ptr km, int nam return; } -QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICTLS(ssl, nvc_ctx, false) {} - -QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless) - : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx), _stateless(stateless) +QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) + : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx) { ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); From f694413937f4a380b71c677a07f76a7595d3918f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Aug 2018 12:35:47 +0900 Subject: [PATCH 0777/1313] Reduce dependency for SSL from QUICHandshake --- iocore/net/QUICNetVConnection.cc | 6 +++-- iocore/net/quic/Mock.h | 5 ++++ iocore/net/quic/QUICHandshake.cc | 25 ++++++++++--------- iocore/net/quic/QUICHandshake.h | 5 ++-- iocore/net/quic/QUICHandshakeProtocol.h | 1 + iocore/net/quic/QUICTLS.cc | 6 +++++ iocore/net/quic/QUICTLS.h | 6 ++++- iocore/net/quic/QUICTLS_openssl.cc | 10 ++++++-- .../quic/test/test_QUICHandshakeProtocol.cc | 4 +-- 9 files changed, 46 insertions(+), 22 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2b833b3e189..6c0d1c4216d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -32,6 +32,7 @@ #include "Log.h" #include "P_SSLNextProtocolSet.h" +#include "QUICTLS.h" #include "QUICStats.h" #include "QUICConfig.h" @@ -204,9 +205,10 @@ QUICNetVConnection::start() // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not if (this->direction() == NET_VCONNECTION_IN) { this->_reset_token.generate(this->_quic_connection_id, params->server_id()); - this->_handshake_handler = new QUICHandshake(this, params->server_ssl_ctx(), this->_reset_token, params->stateless_retry()); + this->_handshake_handler = new QUICHandshake(this, new QUICTLS(params->server_ssl_ctx(), this->direction()), this->_reset_token, + params->stateless_retry()); } else { - this->_handshake_handler = new QUICHandshake(this, params->client_ssl_ctx()); + this->_handshake_handler = new QUICHandshake(this, new QUICTLS(params->client_ssl_ctx(), this->direction())); this->_handshake_handler->start(&this->_packet_factory, params->vn_exercise_enabled()); this->_handshake_handler->do_handshake(); } diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index b282b8c0e4d..dff1afabf13 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -526,6 +526,11 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol return true; } + void + reset() override + { + } + bool is_handshake_finished() const override { diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index dc5834e7a99..b13028c4dbd 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -25,9 +25,6 @@ #include -#include "P_SSLNextProtocolSet.h" -#include "P_VConnection.h" - #include "QUICTLS.h" #include "QUICEvents.h" #include "QUICGlobals.h" @@ -87,18 +84,22 @@ static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527; // TODO: fix size static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527; -QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandshake(qc, ssl_ctx, {}, false) {} +QUICHandshake::QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp) : QUICHandshake(qc, hsp, {}, false) {} -QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token, bool stateless_retry) +QUICHandshake::QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp, QUICStatelessResetToken token, bool stateless_retry) : _qc(qc), - _ssl(SSL_new(ssl_ctx)), - _hs_protocol(new QUICTLS(this->_ssl, qc->direction())), + _hs_protocol(hsp), _version_negotiator(new QUICVersionNegotiator()), _reset_token(token), _stateless_retry(stateless_retry) { - SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc); - SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_hs_index, this); + // FIXME These should be done in another way + if (dynamic_cast(hsp)) { + SSL *ssl = static_cast(hsp)->ssl_handle(); + SSL_set_ex_data(ssl, QUIC::ssl_quic_qc_index, qc); + SSL_set_ex_data(ssl, QUIC::ssl_quic_hs_index, this); + } + this->_hs_protocol->initialize_key_materials(this->_qc->original_connection_id()); if (this->_qc->direction() == NET_VCONNECTION_OUT) { @@ -108,7 +109,7 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless QUICHandshake::~QUICHandshake() { - SSL_free(this->_ssl); + delete this->_hs_protocol; } QUICErrorUPtr @@ -188,7 +189,7 @@ QUICHandshake::is_version_negotiated() const bool QUICHandshake::is_completed() const { - return SSL_is_init_finished(this->_ssl); + return this->_hs_protocol->is_handshake_finished(); } bool @@ -308,7 +309,7 @@ void QUICHandshake::reset() { this->_client_initial = true; - SSL_clear(this->_ssl); + this->_hs_protocol->reset(); for (auto level : QUIC_ENCRYPTION_LEVELS) { int index = static_cast(level); diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index eb79f4a1b02..c5ef75d3aa7 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -40,9 +40,9 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator { public: // Constructor for client side - QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx); + QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp); // Constructor for server side - QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token, bool stateless_retry); + QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp, QUICStatelessResetToken token, bool stateless_retry); ~QUICHandshake(); // QUICFrameHandler @@ -82,7 +82,6 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator private: QUICConnection *_qc = nullptr; - SSL *_ssl = nullptr; QUICHandshakeProtocol *_hs_protocol = nullptr; std::shared_ptr _local_transport_parameters = nullptr; std::shared_ptr _remote_transport_parameters = nullptr; diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 3627e414640..abc441007e9 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -71,6 +71,7 @@ class QUICHandshakeProtocol virtual ~QUICHandshakeProtocol(){}; 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; virtual bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const = 0; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 21b35990500..bfbff386f76 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -31,6 +31,12 @@ constexpr static char tag[] = "quic_tls"; +SSL * +QUICTLS::ssl_handle() +{ + return this->_ssl; +} + QUICTLS::~QUICTLS() { SSL_free(this->_ssl); diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index d7c8cbca395..7e040ac33cf 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -39,7 +39,7 @@ class QUICTLS : public QUICHandshakeProtocol { public: - QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx); + QUICTLS(SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx); ~QUICTLS(); // TODO: integrate with _early_data_processed @@ -50,7 +50,11 @@ class QUICTLS : public QUICHandshakeProtocol static QUICEncryptionLevel get_encryption_level(int msg_type); + // FIXME Should not exist + SSL *ssl_handle(); + int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) override; + void reset() override; bool is_handshake_finished() const override; bool is_ready_to_derive() const override; bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const override; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 319195bf9b9..6f3d25f989f 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -215,8 +215,8 @@ QUICTLS::update_key_materials_on_key_cb(std::unique_ptr km, int nam return; } -QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) - : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx) +QUICTLS::QUICTLS(SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx) + : QUICHandshakeProtocol(), _ssl(SSL_new(ssl_ctx)), _netvc_context(nvc_ctx) { ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); @@ -303,6 +303,12 @@ QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) return 1; } +void +QUICTLS::reset() +{ + SSL_clear(this->_ssl); +} + int QUICTLS::_read_early_data() { diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 22bbfe803db..818cf8acd2d 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -164,7 +164,7 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") #ifdef SSL_MODE_QUIC_HACK SSL_CTX_set_mode(client_ssl_ctx, SSL_MODE_QUIC_HACK); #endif - QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); + QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); // Server SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); @@ -180,7 +180,7 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); EVP_PKEY *pkey = PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr); SSL_CTX_use_PrivateKey(server_ssl_ctx, pkey); - QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); + QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); BIO_free(crt_bio); BIO_free(key_bio); From 40187a3a6943d807b6f18c56b990a0b73f16d706 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Aug 2018 12:51:02 +0900 Subject: [PATCH 0778/1313] Add test_qpack to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a97b1128c8a..79407145589 100644 --- a/.gitignore +++ b/.gitignore @@ -128,6 +128,7 @@ proxy/http2/test_Http2DependencyTree proxy/http2/test_HPACK proxy/http2/hpack-tests/results proxy/hq/test_libhq +proxy/hq/test_qpack proxy/logging/test_LogUtils plugins/header_rewrite/header_rewrite_test From 3d84318fbeb7ef1025aa12d4c608bb74d34494cd Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Aug 2018 13:12:12 +0900 Subject: [PATCH 0779/1313] Remove QUICHandshake::protocol() --- iocore/net/QUICNetVConnection.cc | 8 ++++---- iocore/net/quic/QUICHandshake.cc | 6 ------ iocore/net/quic/QUICHandshake.h | 1 - 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6c0d1c4216d..c7a41fcfcaf 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -205,17 +205,17 @@ QUICNetVConnection::start() // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not if (this->direction() == NET_VCONNECTION_IN) { this->_reset_token.generate(this->_quic_connection_id, params->server_id()); - this->_handshake_handler = new QUICHandshake(this, new QUICTLS(params->server_ssl_ctx(), this->direction()), this->_reset_token, - params->stateless_retry()); + this->_hs_protocol = new QUICTLS(params->server_ssl_ctx(), this->direction()); + this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol, this->_reset_token, params->stateless_retry()); } else { - this->_handshake_handler = new QUICHandshake(this, new QUICTLS(params->client_ssl_ctx(), this->direction())); + this->_hs_protocol = new QUICTLS(params->client_ssl_ctx(), this->direction()); + this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol); this->_handshake_handler->start(&this->_packet_factory, params->vn_exercise_enabled()); this->_handshake_handler->do_handshake(); } this->_application_map = new QUICApplicationMap(); - this->_hs_protocol = this->_handshake_handler->protocol(); this->_frame_dispatcher = new QUICFrameDispatcher(this); this->_packet_factory.set_hs_protocol(this->_hs_protocol); this->_pn_protector.set_hs_protocol(this->_hs_protocol); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index b13028c4dbd..ddaf6862c0f 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -204,12 +204,6 @@ QUICHandshake::has_remote_tp() const return this->_remote_transport_parameters != nullptr; } -QUICHandshakeProtocol * -QUICHandshake::protocol() -{ - return this->_hs_protocol; -} - QUICVersion QUICHandshake::negotiated_version() { diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index c5ef75d3aa7..9c93c7a067f 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -64,7 +64,6 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator int do_handshake(); // Getters - QUICHandshakeProtocol *protocol(); QUICVersion negotiated_version(); const char *negotiated_cipher_suite(); void negotiated_application_name(const uint8_t **name, unsigned int *len); From 4fef001479f58a1fdeac8b5f106dcf40f98d99cf Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 28 Aug 2018 13:14:26 +0900 Subject: [PATCH 0780/1313] Fix build error --- proxy/hq/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proxy/hq/Makefile.am b/proxy/hq/Makefile.am index 0afc84faebd..36dc1a0061b 100644 --- a/proxy/hq/Makefile.am +++ b/proxy/hq/Makefile.am @@ -86,9 +86,9 @@ test_qpack_SOURCES = \ ./test/test_HQFrame.cc \ ./test/test_HQFrameDispatcher.cc \ ./test/test_QPACK.cc \ - $(top_builddir)/proxy/http/HttpConfig.cc \ - $(top_builddir)/proxy/http/HttpConnectionCount.cc \ - $(top_builddir)/proxy/http/ForwardedConfig.cc \ + ../http/HttpConfig.cc \ + ../http/HttpConnectionCount.cc \ + ../http/ForwardedConfig.cc \ ./test/stub.cc test_qpack_LDADD = \ From 33278e7efb767f3067938c0b8cb7a2b4981a0ce7 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 28 Aug 2018 14:43:50 +0900 Subject: [PATCH 0781/1313] Fix QUICSendStreamState::is_allowed_to_send() --- iocore/net/quic/QUICStreamState.cc | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index 8fb3972e2c3..a3605d90db0 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -232,19 +232,13 @@ QUICSendStreamState::is_allowed_to_send(const QUICFrame &frame) const } break; case State::DataSent: - if (type != QUICFrameType::STREAM || type != QUICFrameType::STREAM_BLOCKED || type != QUICFrameType::RST_STREAM) { + if (type == QUICFrameType::RST_STREAM) { return true; } break; case State::DataRecvd: - if (type != QUICFrameType::STREAM || type != QUICFrameType::STREAM_BLOCKED || type != QUICFrameType::RST_STREAM) { - return true; - } break; case State::ResetSent: - if (type != QUICFrameType::STREAM || type != QUICFrameType::STREAM_BLOCKED || type != QUICFrameType::RST_STREAM) { - return true; - } break; case State::ResetRecvd: break; From fd582251820be0444cd477eccc512b8eb2c7a5cb Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 28 Aug 2018 15:12:40 +0900 Subject: [PATCH 0782/1313] Remove QUICTransportParametersInNewSessionTicket --- iocore/net/quic/QUICHandshake.cc | 16 ------ iocore/net/quic/QUICHandshake.h | 1 - iocore/net/quic/QUICTransportParameters.cc | 63 ---------------------- iocore/net/quic/QUICTransportParameters.h | 12 ----- 4 files changed, 92 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index ddaf6862c0f..dffe998856a 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -268,22 +268,6 @@ QUICHandshake::set_transport_parameters(std::shared_ptr tp) -{ - // An endpoint MUST treat receipt of duplicate transport parameters as a connection error of type TRANSPORT_PARAMETER_ERROR. - if (!tp->is_valid()) { - QUICHSDebug("Transport parameter is not valid"); - this->_abort_handshake(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR); - return; - } - - this->_remote_transport_parameters = tp; - - // TODO Add client side implementation - ink_assert(false); -} - std::shared_ptr QUICHandshake::local_transport_parameters() { diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 9c93c7a067f..f9bcd75a68b 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -77,7 +77,6 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator void set_transport_parameters(std::shared_ptr tp); void set_transport_parameters(std::shared_ptr tp); - void set_transport_parameters(std::shared_ptr tp); private: QUICConnection *_qc = nullptr; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 53b2c0be76d..a1db90aad44 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -473,69 +473,6 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const return 0; } -// -// QUICTransportParametersInNewSessionTicket -// - -QUICTransportParametersInNewSessionTicket::QUICTransportParametersInNewSessionTicket(const uint8_t *buf, size_t len) -{ - this->_load(buf, len); - this->_print(); -} - -void -QUICTransportParametersInNewSessionTicket::_store(uint8_t *buf, uint16_t *len) const -{ - // no additional fields defined - *len = 0; -} - -std::ptrdiff_t -QUICTransportParametersInNewSessionTicket::_parameters_offset(const uint8_t *buf) const -{ - return 0; -} - -int -QUICTransportParametersInNewSessionTicket::_validate_parameters() const -{ - int res = QUICTransportParameters::_validate_parameters(); - if (res < 0) { - return res - 100; - } - - decltype(this->_parameters)::const_iterator ite; - - // MAYs - if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) { - if (ite->second->len() != QUICStatelessResetToken::LEN) { - return -1; - } - } - - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS)) != this->_parameters.end()) { - if (ite->second->len() != 4) { - return -3; - } - if (QUICTypeUtil::detect_stream_type(QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != - QUICStreamType::CLIENT_BIDI) { - return -4; - } - } - - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS)) != this->_parameters.end()) { - if (ite->second->len() != 4) { - return -5; - } - if (QUICTypeUtil::detect_stream_type(QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len())) != - QUICStreamType::CLIENT_UNI) { - return -6; - } - } - - return 0; -} - // // QUICTransportParametersHandler // diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 1214001b98c..577478ede4c 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -148,18 +148,6 @@ class QUICTransportParametersInEncryptedExtensions : public QUICTransportParamet QUICVersion _versions[256] = {}; }; -class QUICTransportParametersInNewSessionTicket : public QUICTransportParameters -{ -public: - QUICTransportParametersInNewSessionTicket() : QUICTransportParameters(){}; - QUICTransportParametersInNewSessionTicket(const uint8_t *buf, size_t len); - -protected: - std::ptrdiff_t _parameters_offset(const uint8_t *buf) const override; - int _validate_parameters() const override; - void _store(uint8_t *buf, uint16_t *len) const override; -}; - class QUICTransportParametersHandler { public: From 4e8f6b216a17dc24ef231d208b99b03d0cfa3457 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 28 Aug 2018 15:34:20 +0900 Subject: [PATCH 0783/1313] Add APIs to check Stream State by QUICFrameType --- iocore/net/quic/QUICStreamState.cc | 40 +++++++- iocore/net/quic/QUICStreamState.h | 8 ++ iocore/net/quic/test/test_QUICStreamState.cc | 101 ++++++++++++------- 3 files changed, 105 insertions(+), 44 deletions(-) diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index a3605d90db0..df328b18c19 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -37,8 +37,12 @@ QUICStreamState::_set_state(State s) bool QUICReceiveStreamState::is_allowed_to_send(const QUICFrame &frame) const { - QUICFrameType type = frame.type(); + return this->is_allowed_to_send(frame.type()); +} +bool +QUICReceiveStreamState::is_allowed_to_send(QUICFrameType type) const +{ // Return true or break out the switch to return false switch (this->get()) { case State::_Init: @@ -96,8 +100,12 @@ QUICReceiveStreamState::is_allowed_to_send(const QUICFrame &frame) const bool QUICReceiveStreamState::is_allowed_to_receive(const QUICFrame &frame) const { - QUICFrameType type = frame.type(); + return this->is_allowed_to_receive(frame.type()); +} +bool +QUICReceiveStreamState::is_allowed_to_receive(QUICFrameType type) const +{ // Return true or break out the switch to return false switch (this->get()) { case State::_Init: @@ -216,8 +224,12 @@ QUICReceiveStreamState::update(const QUICStreamState &opposite_side) bool QUICSendStreamState::is_allowed_to_send(const QUICFrame &frame) const { - QUICFrameType type = frame.type(); + return this->is_allowed_to_send(frame.type()); +} +bool +QUICSendStreamState::is_allowed_to_send(QUICFrameType type) const +{ switch (this->get()) { case State::_Init: break; @@ -254,6 +266,12 @@ QUICSendStreamState::is_allowed_to_send(const QUICFrame &frame) const bool QUICSendStreamState::is_allowed_to_receive(const QUICFrame &frame) const +{ + return this->is_allowed_to_receive(frame.type()); +} + +bool +QUICSendStreamState::is_allowed_to_receive(QUICFrameType type) const { return false; } @@ -393,11 +411,23 @@ QUICBidirectionalStreamState::update_with_receiving_frame(const QUICFrame &frame bool QUICBidirectionalStreamState::is_allowed_to_send(const QUICFrame &frame) const { - return this->_send_stream_state.is_allowed_to_send(frame) || this->_recv_stream_state.is_allowed_to_send(frame); + return this->is_allowed_to_send(frame.type()); +} + +bool +QUICBidirectionalStreamState::is_allowed_to_send(QUICFrameType type) const +{ + return this->_send_stream_state.is_allowed_to_send(type) || this->_recv_stream_state.is_allowed_to_send(type); } bool QUICBidirectionalStreamState::is_allowed_to_receive(const QUICFrame &frame) const { - return this->_send_stream_state.is_allowed_to_receive(frame) || this->_recv_stream_state.is_allowed_to_receive(frame); + return this->is_allowed_to_receive(frame.type()); +} + +bool +QUICBidirectionalStreamState::is_allowed_to_receive(QUICFrameType type) const +{ + return this->_send_stream_state.is_allowed_to_receive(type) || this->_recv_stream_state.is_allowed_to_receive(type); } diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h index 7d3bcfc15dc..1179a480924 100644 --- a/iocore/net/quic/QUICStreamState.h +++ b/iocore/net/quic/QUICStreamState.h @@ -65,7 +65,9 @@ class QUICStreamState virtual void update_with_sending_frame(const QUICFrame &frame) = 0; virtual void update_with_receiving_frame(const QUICFrame &frame) = 0; + virtual bool is_allowed_to_send(QUICFrameType type) const = 0; virtual bool is_allowed_to_send(const QUICFrame &frame) const = 0; + virtual bool is_allowed_to_receive(QUICFrameType type) const = 0; virtual bool is_allowed_to_receive(const QUICFrame &frame) const = 0; protected: @@ -101,7 +103,9 @@ class QUICSendStreamState : public QUICUnidirectionalStreamState void update_with_receiving_frame(const QUICFrame &frame) override; void update(const QUICStreamState &opposite_side) override; + bool is_allowed_to_send(QUICFrameType type) const override; bool is_allowed_to_send(const QUICFrame &frame) const override; + bool is_allowed_to_receive(QUICFrameType type) const override; bool is_allowed_to_receive(const QUICFrame &frame) const override; }; @@ -117,7 +121,9 @@ class QUICReceiveStreamState : public QUICUnidirectionalStreamState void update_with_receiving_frame(const QUICFrame &frame) override; void update(const QUICStreamState &opposite_side) override; + bool is_allowed_to_send(QUICFrameType type) const override; bool is_allowed_to_send(const QUICFrame &frame) const override; + bool is_allowed_to_receive(QUICFrameType type) const override; bool is_allowed_to_receive(const QUICFrame &frame) const override; }; @@ -135,7 +141,9 @@ class QUICBidirectionalStreamState : public QUICStreamState void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; + bool is_allowed_to_send(QUICFrameType type) const override; bool is_allowed_to_send(const QUICFrame &frame) const override; + bool is_allowed_to_receive(QUICFrameType type) const override; bool is_allowed_to_receive(const QUICFrame &frame) const override; private: diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index 875072a6539..7c4d1d69beb 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -29,6 +29,7 @@ #include "quic/QUICStreamState.h" #include "quic/Mock.h" +// Unidirectional (sending) TEST_CASE("QUICSendStreamState", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); @@ -36,64 +37,86 @@ TEST_CASE("QUICSendStreamState", "[quic]") auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0, 0); - SECTION("_Init") + SECTION("Ready -> Send -> Data Sent") { // Case1. Create Stream (Sending) - QUICSendStreamState ss1(nullptr, nullptr); - CHECK(ss1.get() == QUICStreamState::State::Ready); + QUICSendStreamState ss(nullptr, nullptr); + CHECK(ss.get() == QUICStreamState::State::Ready); // Case2. Send STREAM - QUICSendStreamState ss2(nullptr, nullptr); - ss2.update_with_sending_frame(*stream_frame); - CHECK(ss2.get() == QUICStreamState::State::Send); - - // Case3. Send RST_STREAM - QUICSendStreamState ss3(nullptr, nullptr); - ss3.update_with_sending_frame(*rst_stream_frame); - CHECK(ss3.get() == QUICStreamState::State::ResetSent); - - // Case4. Send FIN in a STREAM - QUICSendStreamState ss4(nullptr, nullptr); - ss4.update_with_sending_frame(*stream_frame_with_fin); - CHECK(ss4.get() == QUICStreamState::State::DataSent); + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame); + CHECK(ss.get() == QUICStreamState::State::Send); + + // Case3. Send STREAM_BLOCKED + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_BLOCKED)); + ss.update_with_sending_frame(*stream_blocked_frame); + CHECK(ss.get() == QUICStreamState::State::Send); + + // Case3. Send FIN in a STREAM + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICStreamState::State::DataSent); + + // Case4. STREAM is not allowed to send + CHECK(!ss.is_allowed_to_send(QUICFrameType::STREAM)); + } + + SECTION("Ready -> Reset Sent") + { + // Case1. Create Stream (Sending) + QUICSendStreamState ss(nullptr, nullptr); + CHECK(ss.get() == QUICStreamState::State::Ready); + + // Case2. Send RST_STREAM + CHECK(ss.is_allowed_to_send(QUICFrameType::RST_STREAM)); + ss.update_with_sending_frame(*rst_stream_frame); + CHECK(ss.get() == QUICStreamState::State::ResetSent); } } +// Unidirectional (receiving) TEST_CASE("QUICReceiveStreamState", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); - auto max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(0, 0); auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0, 0); - SECTION("_Init") + SECTION("Recv -> Size Known -> Data Recvd") { MockQUICTransferProgressProvider in_progress; // Case1. Recv STREAM - QUICReceiveStreamState ss1(&in_progress, nullptr); - ss1.update_with_receiving_frame(*stream_frame); - CHECK(ss1.get() == QUICStreamState::State::Recv); + QUICReceiveStreamState ss(&in_progress, nullptr); + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + CHECK(ss.get() == QUICStreamState::State::Recv); // Case2. Recv STREAM_BLOCKED - QUICReceiveStreamState ss2(&in_progress, nullptr); - ss2.update_with_receiving_frame(*stream_blocked_frame); - CHECK(ss2.get() == QUICStreamState::State::Recv); - - // Case3. Recv RST_STREAM - QUICReceiveStreamState ss3(&in_progress, nullptr); - ss3.update_with_receiving_frame(*rst_stream_frame); - CHECK(ss3.get() == QUICStreamState::State::ResetRecvd); - - // Case4. Recv MAX_STREAM_DATA - QUICReceiveStreamState ss4(&in_progress, nullptr); - ss4.update_with_receiving_frame(*max_stream_data_frame); - CHECK(ss4.get() == QUICStreamState::State::Recv); - - // Case5. Recv FIN in a STREAM - QUICReceiveStreamState ss5(&in_progress, nullptr); - ss5.update_with_receiving_frame(*stream_frame_with_fin); - CHECK(ss5.get() == QUICStreamState::State::SizeKnown); + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM_BLOCKED)); + ss.update_with_receiving_frame(*stream_blocked_frame); + CHECK(ss.get() == QUICStreamState::State::Recv); + + // Case3. Recv FIN in a STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICStreamState::State::SizeKnown); + } + + SECTION("Recv -> Reset Recvd") + { + MockQUICTransferProgressProvider in_progress; + + // Case1. Recv STREAM + QUICReceiveStreamState ss(&in_progress, nullptr); + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + CHECK(ss.get() == QUICStreamState::State::Recv); + + // Case2. Recv RST_STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::RST_STREAM)); + ss.update_with_receiving_frame(*rst_stream_frame); + CHECK(ss.get() == QUICStreamState::State::ResetRecvd); } } From e1f2f3c79e9619d666a9b7305cfac0e071ab4b97 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 28 Aug 2018 16:14:23 +0900 Subject: [PATCH 0784/1313] Refacoring QUICStream::generate_frame() --- iocore/net/quic/QUICApplication.cc | 2 +- iocore/net/quic/QUICStream.cc | 104 ++++++++++++++---------- iocore/net/quic/test/test_QUICStream.cc | 12 +-- 3 files changed, 68 insertions(+), 50 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 1d771354264..f4d09a40c97 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -63,7 +63,7 @@ QUICStreamIO::read(uint8_t *buf, int64_t len) { if (is_debug_tag_set(tag_stream_io)) { if (this->_read_vio->nbytes == INT64_MAX) { - QUICStreamIODebug("nbytes=-" PRId64 " ndone=%" PRId64 " read_avail=%" PRId64 " read_len=%" PRId64, this->_read_vio->ndone, + QUICStreamIODebug("nbytes=- ndone=%" PRId64 " read_avail=%" PRId64 " read_len=%" PRId64, this->_read_vio->ndone, this->_read_buffer_reader->read_avail(), len); } else { QUICStreamIODebug("nbytes=%" PRId64 " ndone=%" PRId64 " read_avail=%" PRId64 " read_len=%" PRId64, this->_read_vio->nbytes, diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 37f1130d745..18f3f7376d4 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -391,80 +391,98 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit { SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); - QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); - + // RST_STREAM if (this->_reset_reason) { return QUICFrameFactory::create_rst_stream_frame(std::move(this->_reset_reason)); } QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - frame = this->_local_flow_controller.generate_frame(level, connection_credit, maximum_frame_size); + + // MAX_STREAM_DATA + frame = this->_local_flow_controller.generate_frame(level, UINT16_MAX, maximum_frame_size); if (frame) { return frame; } - if (connection_credit == 0) { + if (!this->_state.is_allowed_to_send(QUICFrameType::STREAM)) { return frame; } + uint64_t maximum_data_size = 0; if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) { return frame; } + maximum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD; - IOBufferReader *reader = this->_write_vio.get_reader(); - int64_t bytes_avail = reader->read_avail(); - if (bytes_avail == 0) { - return frame; + bool pure_fin = false; + bool fin = false; + if ((this->_write_vio.nbytes != 0 || this->_write_vio.nbytes != INT64_MAX) && + this->_write_vio.nbytes == static_cast(this->_send_offset)) { + // Pure FIN stream should be sent regardless status of remote flow controller, because the length is zero. + pure_fin = true; + fin = true; } - // STREAM_BLOCKED - uint64_t stream_credit = this->_remote_flow_controller.credit(); - // The `bytes_avail` should be also checked before calling QUICRemoteFlowController::generate_frame(), but we don't need it. - // Because it's already checked in above. - if (stream_credit == 0) { - frame = this->_remote_flow_controller.generate_frame(level, connection_credit, maximum_frame_size); - if (frame) { + uint64_t len = 0; + IOBufferReader *reader = this->_write_vio.get_reader(); + if (!pure_fin) { + uint64_t data_len = reader->block_read_avail(); + if (data_len == 0) { return frame; } - } - int64_t data_len = reader->block_read_avail(); - int64_t len = 0; - bool fin = false; + // Check Connection/Stream level credit only if the generating STREAM frame is not pure fin + uint64_t stream_credit = this->_remote_flow_controller.credit(); + if (stream_credit == 0) { + // STREAM_BLOCKED + frame = this->_remote_flow_controller.generate_frame(level, UINT16_MAX, maximum_frame_size); + return frame; + } - len = std::min(data_len, static_cast(std::min(static_cast(maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD), - std::min(stream_credit, static_cast(connection_credit))))); + if (connection_credit == 0) { + // BLOCKED - BLOCKED frame will be sent by connection level remote flow controller + return frame; + } - if (this->_write_vio.nbytes == static_cast(this->_send_offset + len)) { - fin = true; - } + len = std::min(data_len, std::min(maximum_data_size, std::min(stream_credit, connection_credit))); - if (len > 0) { - frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, this->_id, - this->_send_offset, fin, true); - if (!this->_state.is_allowed_to_send(*frame)) { - QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); - return frame; + // data_len, maximum_data_size, stream_credit and connection_credit are already checked they're larger than 0 + ink_assert(len != 0); + + if (this->_write_vio.nbytes == static_cast(this->_send_offset + len)) { + fin = true; } - } else { - len = bytes_avail; } - int ret = this->_remote_flow_controller.update(this->_send_offset + len); - // We cannot cancel sending the frame after updating the flow controller + // STREAM - Pure FIN or data length is lager than 0 + frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, this->_id, + this->_send_offset, fin, true); + if (!this->_state.is_allowed_to_send(*frame)) { + QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); + return frame; + } + + if (!pure_fin) { + int ret = this->_remote_flow_controller.update(this->_send_offset + len); + // We cannot cancel sending the frame after updating the flow controller + + // Calling update always success, because len is always less than stream_credit + ink_assert(ret == 0); + + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); + if (this->_remote_flow_controller.current_offset() == this->_remote_flow_controller.current_limit()) { + QUICStreamDebug("Flow Controller will block sending a STREAM frame"); + } - QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), - this->_remote_flow_controller.current_limit()); - if (frame && ret == 0) { - this->_send_offset += len; reader->consume(len); + this->_send_offset += len; this->_write_vio.ndone += len; - this->_signal_write_event(); - this->_state.update_with_sending_frame(*frame); - } else if (ret != 0) { - QUICStreamDebug("Flow Controller blocked sending a STREAM frame"); - frame = this->_remote_flow_controller.generate_frame(level, connection_credit, maximum_frame_size); } + + this->_signal_write_event(); + this->_state.update_with_sending_frame(*frame); + return frame; } diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index a5a0eec3ea0..535b89ba121 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -71,7 +71,7 @@ TEST_CASE("QUICStream", "[quic]") std::unique_ptr stream( new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, 1024, 1024)); - stream->do_io_read(nullptr, 0, read_buffer); + stream->do_io_read(nullptr, INT64_MAX, read_buffer); stream->recv(*frame_1); stream->recv(*frame_2); @@ -97,7 +97,7 @@ TEST_CASE("QUICStream", "[quic]") std::unique_ptr stream( new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, UINT64_MAX, UINT64_MAX)); - stream->do_io_read(nullptr, 0, read_buffer); + stream->do_io_read(nullptr, INT64_MAX, read_buffer); stream->recv(*frame_8); stream->recv(*frame_7); @@ -123,7 +123,7 @@ TEST_CASE("QUICStream", "[quic]") std::unique_ptr stream( new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, UINT64_MAX, UINT64_MAX)); - stream->do_io_read(nullptr, 0, read_buffer); + stream->do_io_read(nullptr, INT64_MAX, read_buffer); stream->recv(*frame_8); stream->recv(*frame_7); @@ -153,7 +153,7 @@ TEST_CASE("QUICStream", "[quic]") std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id)); stream->init_flow_control_params(4096, 4096); - stream->do_io_read(nullptr, 0, read_buffer); + stream->do_io_read(nullptr, INT64_MAX, read_buffer); // Start with 1024 but not 0 so received frames won't be processed error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 1024)); @@ -190,8 +190,8 @@ TEST_CASE("QUICStream", "[quic]") std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id)); stream->init_flow_control_params(4096, 4096); MockContinuation mock_cont(stream->mutex); - stream->do_io_read(nullptr, 0, read_buffer); - stream->do_io_write(&mock_cont, 0, write_buffer_reader); + stream->do_io_read(nullptr, INT64_MAX, read_buffer); + stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; From f429053851d5a9b340f1cc6348443ed3094a889c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 29 Aug 2018 08:31:23 +0900 Subject: [PATCH 0785/1313] [draft-13] Bump HQ version in ALPN --- iocore/net/quic/QUICConfig.cc | 2 +- iocore/net/quic/QUICTypes.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 949a2841812..a3334c95307 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -37,7 +37,7 @@ // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html // Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? using namespace std::literals; -static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-12"sv); +static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-13"sv); int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index c3f53f00255..3076a2d1bb0 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -46,6 +46,7 @@ using QUICOffset = uint64_t; // TODO: Update version number // Note: Prefix for drafts (0xff000000) + draft number // Note: Fix "Supported Version" field in test case of QUICPacketFactory_Create_VersionNegotiationPacket +// Note: Fix QUIC_ALPN_PROTO_LIST in QUICConfig.cc // Note: Change ExtensionType (QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID) if it's changed constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { 0xff00000d, From cfa1d0da9a00b61b3fa75c984e59f76439ce517e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 29 Aug 2018 14:48:46 +0900 Subject: [PATCH 0786/1313] Fix HQ to replace AclRecord with IpAllow::ACL --- proxy/hq/HQSessionAccept.cc | 11 ++++++----- proxy/hq/QUICSimpleApp.cc | 10 +++------- proxy/hq/QUICSimpleApp.h | 4 +++- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/proxy/hq/HQSessionAccept.cc b/proxy/hq/HQSessionAccept.cc index 4f9299f78c3..e16b6c5304c 100644 --- a/proxy/hq/HQSessionAccept.cc +++ b/proxy/hq/HQSessionAccept.cc @@ -25,7 +25,7 @@ #include "P_Net.h" #include "I_Machine.h" -#include "../IPAllow.h" +#include "IPAllow.h" #include "QUICSimpleApp.h" HQSessionAccept::HQSessionAccept(const HttpSessionAccept::Options &_o) : SessionAccept(nullptr), options(_o) @@ -38,13 +38,14 @@ HQSessionAccept::~HQSessionAccept() {} bool HQSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader *reader) { - sockaddr const *client_ip = netvc->get_remote_addr(); - const AclRecord *session_acl_record = testIpAllowPolicy(client_ip); - if (!session_acl_record) { + sockaddr const *client_ip = netvc->get_remote_addr(); + IpAllow::ACL session_acl = IpAllow::match(client_ip, IpAllow::SRC_ADDR); + if (!session_acl.isValid()) { ip_port_text_buffer ipb; Warning("QUIC client '%s' prohibited by ip-allow policy", ats_ip_ntop(client_ip, ipb, sizeof(ipb))); return false; } + netvc->attributes = this->options.transport_type; if (is_debug_tag_set("hq")) { @@ -55,7 +56,7 @@ HQSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader ats_ip_nptop(client_ip, ipb, sizeof(ipb)), netvc->attributes); } - new QUICSimpleApp(static_cast(netvc)); + new QUICSimpleApp(static_cast(netvc), std::move(session_acl)); return true; } diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index 7dc50272582..6d77af7937c 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -29,18 +29,14 @@ #include "HQClientSession.h" #include "HQClientTransaction.h" -#include "../IPAllow.h" static constexpr char tag[] = "quic_simple_app"; static constexpr char tag_v[] = "v_quic_simple_app"; -QUICSimpleApp::QUICSimpleApp(QUICNetVConnection *client_vc) : QUICApplication(client_vc) +QUICSimpleApp::QUICSimpleApp(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QUICApplication(client_vc) { - sockaddr const *client_ip = client_vc->get_remote_addr(); - const AclRecord *session_acl_record = SessionAccept::testIpAllowPolicy(client_ip); - - this->_client_session = new HQClientSession(client_vc); - this->_client_session->acl_record = session_acl_record; + this->_client_session = new HQClientSession(client_vc); + this->_client_session->acl = std::move(session_acl); this->_client_session->new_connection(client_vc, nullptr, nullptr, false); this->_qc->stream_manager()->set_default_application(this); diff --git a/proxy/hq/QUICSimpleApp.h b/proxy/hq/QUICSimpleApp.h index 12804eb6554..492aed30781 100644 --- a/proxy/hq/QUICSimpleApp.h +++ b/proxy/hq/QUICSimpleApp.h @@ -23,6 +23,8 @@ #pragma once +#include "IPAllow.h" + #include "QUICApplication.h" class QUICNetVConnection; @@ -36,7 +38,7 @@ class HQClientSession; class QUICSimpleApp : public QUICApplication { public: - QUICSimpleApp(QUICNetVConnection *client_vc); + QUICSimpleApp(QUICNetVConnection *client_vc, IpAllow::ACL session_acl); ~QUICSimpleApp(); int main_event_handler(int event, Event *data); From 4067503ebb037bfe1deb880162b2f65e3b647054 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 29 Aug 2018 14:49:16 +0900 Subject: [PATCH 0787/1313] Remove HQClientSession::release_netvc() --- proxy/hq/HQClientSession.cc | 7 ------- proxy/hq/HQClientSession.h | 1 - 2 files changed, 8 deletions(-) diff --git a/proxy/hq/HQClientSession.cc b/proxy/hq/HQClientSession.cc index 3761e7f7996..29af2e045f0 100644 --- a/proxy/hq/HQClientSession.cc +++ b/proxy/hq/HQClientSession.cc @@ -96,13 +96,6 @@ HQClientSession::get_netvc() const return this->_client_vc; } -void -HQClientSession::release_netvc() -{ - ink_assert(false); - return; -} - int HQClientSession::get_transact_count() const { diff --git a/proxy/hq/HQClientSession.h b/proxy/hq/HQClientSession.h index 928503fe86c..ff4e4daa648 100644 --- a/proxy/hq/HQClientSession.h +++ b/proxy/hq/HQClientSession.h @@ -46,7 +46,6 @@ class HQClientSession : public ProxyClientSession void destroy() override; void new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader, bool backdoor) override; NetVConnection *get_netvc() const override; - void release_netvc() override; int get_transact_count() const override; const char *get_protocol_string() const override; void release(ProxyClientTransaction *trans) override; From 2621a0716f0e76f3a403383a87a154132960ac4e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 29 Aug 2018 14:51:04 +0900 Subject: [PATCH 0788/1313] Acquire mutex lock before handleEvent() call --- iocore/net/QUICNet.cc | 3 +++ iocore/net/QUICNetProcessor.cc | 2 ++ iocore/net/QUICNetVConnection.cc | 6 +++++- proxy/hq/QUICSimpleApp.cc | 2 ++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index 85682803fbd..9a4b649c0f0 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -69,14 +69,17 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) QUICPacketType ptype = static_cast(buf[0] & 0x7f); if (ptype == QUICPacketType::INITIAL && !vc->read.triggered) { + SCOPED_MUTEX_LOCK(lock, vc->mutex, this_ethread()); vc->read.triggered = 1; vc->handle_received_packet(p); vc->handleEvent(QUIC_EVENT_PACKET_READ_READY, nullptr); e->free(); + return; } if (vc) { + SCOPED_MUTEX_LOCK(lock, vc->mutex, this_ethread()); vc->read.triggered = 1; vc->handle_received_packet(p); } else { diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 8807a1517cf..e4c4ab1acf2 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -192,6 +192,7 @@ QUICNetProcessor::main_accept(Continuation *cont, SOCKET fd, AcceptOptions const // char thr_name[MAX_THREAD_NAME_LENGTH]; NetAccept *na = createNetAccept(opt); + if (accept_threads < 0) { REC_ReadConfigInteger(accept_threads, "proxy.config.accept_threads"); } @@ -216,6 +217,7 @@ QUICNetProcessor::main_accept(Continuation *cont, SOCKET fd, AcceptOptions const na->action_->server = &na->server; na->init_accept(); + SCOPED_MUTEX_LOCK(lock, na->mutex, this_ethread()); udpNet.UDPBind((Continuation *)na, &na->server.accept_addr.sa, 1048576, 1048576); return na->action_.get(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index c7a41fcfcaf..7b79c483834 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -720,7 +720,9 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) // TODO: Drop record from Connection-ID - QUICNetVConnection table in QUICPacketHandler // Shutdown loss detector for (auto s : QUIC_PN_SPACES) { - this->_loss_detector[static_cast(s)]->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); + QUICLossDetector *ld = this->_loss_detector[static_cast(s)]; + SCOPED_MUTEX_LOCK(lock, ld->mutex, this_ethread()); + ld->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); } if (this->nh) { @@ -750,7 +752,9 @@ QUICNetVConnection::get_udp_con() void QUICNetVConnection::net_read_io(NetHandler *nh, EThread *lthread) { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); this->handleEvent(QUIC_EVENT_PACKET_READ_READY, nullptr); + return; } diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index 6d77af7937c..fb42b259b05 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -75,6 +75,7 @@ QUICSimpleApp::main_event_handler(int event, Event *data) txn->new_transaction(); } else { + SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); txn->handleEvent(event); } } @@ -82,6 +83,7 @@ QUICSimpleApp::main_event_handler(int event, Event *data) case VC_EVENT_WRITE_READY: case VC_EVENT_WRITE_COMPLETE: if (txn != nullptr) { + SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); txn->handleEvent(event); } break; From 5b9a089f1261fb8d6558dcd589310e5dc6b1477c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 30 Aug 2018 15:03:32 +0900 Subject: [PATCH 0789/1313] The smallest bidi stream id is 0 --- iocore/net/quic/QUICStreamManager.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index fd0690b2612..1dff812bd70 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -36,8 +36,7 @@ QUICStreamManager::QUICStreamManager(QUICConnectionInfoProvider *info, QUICRTTPr : _info(info), _rtt_provider(rtt_provider), _app_map(app_map) { if (this->_info->direction() == NET_VCONNECTION_OUT) { - // stream 0 is for handshake, smallest client bidi stream id is 4 - this->_next_stream_id_bidi = static_cast(QUICStreamType::CLIENT_BIDI) + 4; + this->_next_stream_id_bidi = static_cast(QUICStreamType::CLIENT_BIDI); this->_next_stream_id_uni = static_cast(QUICStreamType::CLIENT_UNI); } else { this->_next_stream_id_bidi = static_cast(QUICStreamType::SERVER_BIDI); From 68b9428e7e99f8b6c58694a153ec8edc3a66e6e9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 31 Aug 2018 11:33:59 +0900 Subject: [PATCH 0790/1313] Const Correctness --- iocore/net/quic/QUICFlowController.cc | 6 +++--- iocore/net/quic/QUICFlowController.h | 6 +++--- iocore/net/quic/QUICStream.cc | 4 ++-- iocore/net/quic/QUICStream.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 70ff1817522..4cbca28d863 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -46,19 +46,19 @@ QUICRateAnalyzer::expect_recv_bytes(ink_hrtime time) // QUICFlowController // uint64_t -QUICFlowController::credit() +QUICFlowController::credit() const { return this->current_limit() - this->current_offset(); } QUICOffset -QUICFlowController::current_offset() +QUICFlowController::current_offset() const { return this->_offset; } QUICOffset -QUICFlowController::current_limit() +QUICFlowController::current_limit() const { return this->_limit; } diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index 8f9e3873f40..2f36fd9bbec 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -43,9 +43,9 @@ class QUICRateAnalyzer class QUICFlowController : public QUICFrameGenerator { public: - uint64_t credit(); - QUICOffset current_offset(); - QUICOffset current_limit(); + uint64_t credit() const; + QUICOffset current_offset() const; + QUICOffset current_limit() const; /* * Returns 0 if succeed diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 18f3f7376d4..a4d22ef38b3 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -585,13 +585,13 @@ QUICStream::reset(QUICStreamErrorUPtr error) } QUICOffset -QUICStream::largest_offset_received() +QUICStream::largest_offset_received() const { return this->_local_flow_controller.current_offset(); } QUICOffset -QUICStream::largest_offset_sent() +QUICStream::largest_offset_sent() const { return this->_remote_flow_controller.current_offset(); } diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index e70cbd9060e..e9defc7acca 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -83,8 +83,8 @@ class QUICStream : public VConnection, public QUICFrameGenerator void reset(QUICStreamErrorUPtr error); - QUICOffset largest_offset_received(); - QUICOffset largest_offset_sent(); + QUICOffset largest_offset_received() const; + QUICOffset largest_offset_sent() const; LINK(QUICStream, link); From 4094f6b7bbe2fc8242b879444aa2773fb9f6eed4 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 31 Aug 2018 11:44:07 +0900 Subject: [PATCH 0791/1313] Acquire mutex lock before handleEvent() call in unit test of QUICStream --- iocore/net/quic/test/test_QUICStream.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 535b89ba121..b88abd35a65 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -188,6 +188,8 @@ TEST_CASE("QUICStream", "[quic]") IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id)); + SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); + stream->init_flow_control_params(4096, 4096); MockContinuation mock_cont(stream->mutex); stream->do_io_read(nullptr, INT64_MAX, read_buffer); @@ -197,6 +199,7 @@ TEST_CASE("QUICStream", "[quic]") const char data[1024] = {0}; QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame(level) == true); From 4d48f656b0e088d10c717a25478909d516b1d3bd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 31 Aug 2018 12:08:48 +0900 Subject: [PATCH 0792/1313] Send MAX_DATA frame --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 14 +++++++++++++- iocore/net/quic/QUICStream.cc | 12 +++++++++--- iocore/net/quic/QUICStream.h | 2 ++ iocore/net/quic/QUICStreamManager.cc | 12 ++++++++++++ iocore/net/quic/QUICStreamManager.h | 1 + 6 files changed, 38 insertions(+), 4 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index ca02b1977ff..2fc8c631e04 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -272,6 +272,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICConnectionErrorUPtr _connection_error = nullptr; uint32_t _state_closing_recv_packet_count = 0; uint32_t _state_closing_recv_packet_window = 1; + uint64_t _flow_control_buffer_size = 1024; void _schedule_packet_write_ready(bool delay = false); void _unschedule_packet_write_ready(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 7b79c483834..81a32a0d6dc 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1258,6 +1258,13 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_packet_retransmitter.generate_frame(level, UINT16_MAX, max_frame_size); } + // MAX_DATA + frame = this->_local_flow_controller->generate_frame(level, UINT16_MAX, max_frame_size); + if (frame) { + ++frame_count; + this->_store_frame(buf, len, max_frame_size, std::move(frame)); + } + // BLOCKED if (this->_remote_flow_controller->credit() == 0 && this->_stream_manager->will_generate_frame(level)) { frame = this->_remote_flow_controller->generate_frame(level, UINT16_MAX, max_frame_size); @@ -1382,6 +1389,10 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } + this->_local_flow_controller->forward_limit(this->_stream_manager->total_reordered_bytes() + this->_flow_control_buffer_size); + QUICFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); + this->_ack_frame_creator.update(level, packet_num, should_send_ack); return error; @@ -1443,7 +1454,8 @@ QUICNetVConnection::_init_flow_control_params(const std::shared_ptrgetAsUInt32(QUICTransportParameterId::INITIAL_MAX_DATA); + local_initial_max_data = local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_DATA); + this->_flow_control_buffer_size = local_initial_max_data; } if (remote_tp) { remote_initial_max_data = remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_DATA); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index a4d22ef38b3..5949c1858f6 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -334,8 +334,9 @@ QUICStream::recv(const QUICStreamFrame &frame) this->_write_to_read_vio(stream_frame->offset(), stream_frame->data(), stream_frame->data_length(), stream_frame->has_fin_flag()); - this->_local_flow_controller.forward_limit(stream_frame->offset() + stream_frame->data_length() + - this->_flow_control_buffer_size); + + this->_reordered_bytes = stream_frame->offset() + stream_frame->data_length(); + this->_local_flow_controller.forward_limit(this->_reordered_bytes + this->_flow_control_buffer_size); QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), this->_local_flow_controller.current_limit()); this->_state.update_with_receiving_frame(*new_frame); @@ -355,7 +356,6 @@ QUICStream::recv(const QUICMaxStreamDataFrame &frame) QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), this->_remote_flow_controller.current_limit()); - QUICStreamDebug("restart sending"); int64_t len = this->_process_write_vio(); if (len > 0) { this->_signal_write_event(); @@ -584,6 +584,12 @@ QUICStream::reset(QUICStreamErrorUPtr error) this->_reset_reason = std::move(error); } +QUICOffset +QUICStream::reordered_bytes() const +{ + return this->_reordered_bytes; +} + QUICOffset QUICStream::largest_offset_received() const { diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index e9defc7acca..c05f985d425 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -83,6 +83,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator void reset(QUICStreamErrorUPtr error); + QUICOffset reordered_bytes() const; QUICOffset largest_offset_received() const; QUICOffset largest_offset_sent() const; @@ -105,6 +106,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator QUICConnectionInfoProvider *_info = nullptr; QUICStreamId _id = 0; QUICOffset _send_offset = 0; + QUICOffset _reordered_bytes = 0; QUICRemoteStreamFlowController _remote_flow_controller; QUICLocalStreamFlowController _local_flow_controller; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 1dff812bd70..b6e8fe09f95 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -294,6 +294,18 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) return stream; } +uint64_t +QUICStreamManager::total_reordered_bytes() const +{ + uint64_t total_bytes = 0; + + // FIXME Iterating all (open + closed) streams is expensive + for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + total_bytes += s->reordered_bytes(); + } + return total_bytes; +} + uint64_t QUICStreamManager::total_offset_received() const { diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index be5c016c410..0e0266e4fbe 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -43,6 +43,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator void init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); void set_max_stream_id(QUICStreamId id); + uint64_t total_reordered_bytes() const; uint64_t total_offset_received() const; uint64_t total_offset_sent() const; void add_total_offset_sent(uint32_t sent_byte); From 01030555a4cfe8e421886673e8dfdc592e13c53a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 31 Aug 2018 14:24:26 +0900 Subject: [PATCH 0793/1313] Update connection level FC (local) only if received packet include STREAM frame --- iocore/net/QUICNetVConnection.cc | 23 +++++++++++-------- iocore/net/quic/QUICFrameDispatcher.cc | 8 ++++++- iocore/net/quic/QUICFrameDispatcher.h | 3 ++- .../net/quic/test/test_QUICFrameDispatcher.cc | 5 ++-- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 81a32a0d6dc..83a3cb00010 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1369,10 +1369,11 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) QUICEncryptionLevel level = QUICTypeUtil::encryption_level(packet->type()); bool should_send_ack; + bool is_flow_controlled; QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - error = this->_frame_dispatcher->receive_frames(level, payload, size, should_send_ack); + error = this->_frame_dispatcher->receive_frames(level, payload, size, should_send_ack, is_flow_controlled); if (error->cls != QUICErrorClass::NONE) { return error; } @@ -1381,17 +1382,19 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) should_send_ack = false; } - int ret = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); - QUICFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), - this->_local_flow_controller->current_limit()); + if (is_flow_controlled) { + int ret = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); + QUICFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); - if (ret != 0) { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); - } + if (ret != 0) { + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); + } - this->_local_flow_controller->forward_limit(this->_stream_manager->total_reordered_bytes() + this->_flow_control_buffer_size); - QUICFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), - this->_local_flow_controller->current_limit()); + this->_local_flow_controller->forward_limit(this->_stream_manager->total_reordered_bytes() + this->_flow_control_buffer_size); + QUICFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), + this->_local_flow_controller->current_limit()); + } this->_ack_frame_creator.update(level, packet_num, should_send_ack); diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 3d5c8769715..543a147f833 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -42,11 +42,13 @@ QUICFrameDispatcher::add_handler(QUICFrameHandler *handler) } QUICErrorUPtr -QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, bool &should_send_ack) +QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, bool &should_send_ack, + bool &is_flow_controlled) { std::shared_ptr frame(nullptr); uint16_t cursor = 0; should_send_ack = false; + is_flow_controlled = false; QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); while (cursor < size) { @@ -59,6 +61,10 @@ QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *pa QUICFrameType type = frame->type(); + if (type == QUICFrameType::STREAM) { + is_flow_controlled = true; + } + if (is_debug_tag_set(tag) && type != QUICFrameType::PADDING) { char msg[1024]; frame->debug_msg(msg, sizeof(msg)); diff --git a/iocore/net/quic/QUICFrameDispatcher.h b/iocore/net/quic/QUICFrameDispatcher.h index 6db357d5785..bd65ba1f880 100644 --- a/iocore/net/quic/QUICFrameDispatcher.h +++ b/iocore/net/quic/QUICFrameDispatcher.h @@ -37,7 +37,8 @@ class QUICFrameDispatcher /* * Returns true if ACK frame should be sent */ - QUICErrorUPtr receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, bool &should_send_ack); + QUICErrorUPtr receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, bool &should_send_ackbool, + bool &is_flow_controlled); void add_handler(QUICFrameHandler *handler); diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 30b38ceb2e0..a90752dd109 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -57,14 +57,15 @@ TEST_CASE("QUICFrameHandler", "[quic]") size_t len = 0; streamFrame.store(buf, &len, 4096); bool should_send_ack; - quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack); + bool is_flow_controlled; + quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack, is_flow_controlled); CHECK(connection->getTotalFrameCount() == 0); CHECK(streamManager->getTotalFrameCount() == 1); // CONNECTION_CLOSE frame QUICConnectionCloseFrame connectionCloseFrame({}); connectionCloseFrame.store(buf, &len, 4096); - quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack); + quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack, is_flow_controlled); CHECK(connection->getTotalFrameCount() == 1); CHECK(streamManager->getTotalFrameCount() == 1); } From d74d6369a13f3154523cb722adc6a5bfe9bbe2f7 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 3 Sep 2018 11:42:16 +0900 Subject: [PATCH 0794/1313] Rename create_server_protected_packet to create_protected_packet --- iocore/net/QUICNetVConnection.cc | 6 +-- iocore/net/quic/QUICPacket.cc | 4 +- iocore/net/quic/QUICPacket.h | 4 +- iocore/net/quic/test/test_QUICFrame.cc | 4 +- iocore/net/quic/test/test_QUICLossDetector.cc | 54 +++++++++---------- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 83a3cb00010..ab150be35d9 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1434,9 +1434,9 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi break; } case QUICPacketType::PROTECTED: { - packet = this->_packet_factory.create_server_protected_packet(this->_peer_quic_connection_id, - this->largest_acked_packet_number(QUICEncryptionLevel::ONE_RTT), - std::move(buf), len, retransmittable); + packet = this->_packet_factory.create_protected_packet(this->_peer_quic_connection_id, + this->largest_acked_packet_number(QUICEncryptionLevel::ONE_RTT), + std::move(buf), len, retransmittable); break; } default: diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index ebd9f68d87a..bbda5c61296 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -1150,8 +1150,8 @@ QUICPacketFactory::create_handshake_packet(QUICConnectionId destination_cid, QUI } QUICPacketUPtr -QUICPacketFactory::create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable) +QUICPacketFactory::create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, + ats_unique_buf payload, size_t len, bool retransmittable) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ONE_RTT); QUICPacketNumber pn = this->_packet_number_generator[index].next(); diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 4760bf274cd..d4fb0fc4b0e 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -398,8 +398,8 @@ class QUICPacketFactory QUICPacketUPtr create_handshake_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); - QUICPacketUPtr create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable); + QUICPacketUPtr create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, + ats_unique_buf payload, size_t len, bool retransmittable); void set_version(QUICVersion negotiated_version); void set_hs_protocol(QUICHandshakeProtocol *hs_protocol); bool is_ready_to_create_protected_packet(); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 711d30fcbb2..d7dc8f933b9 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1270,8 +1270,8 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") QUICPacketFactory factory; MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); - QUICPacketUPtr packet = factory.create_server_protected_packet({reinterpret_cast("\x01\x02\x03\x04"), 4}, 0, - {nullptr, [](void *p) { ats_free(p); }}, 0, true); + QUICPacketUPtr packet = factory.create_protected_packet({reinterpret_cast("\x01\x02\x03\x04"), 4}, 0, + {nullptr, [](void *p) { ats_free(p); }}, 0, true); SECTION("STREAM frame split") { size_t len; diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index a414872eb01..8ba4f1d03d5 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -84,33 +84,33 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") CHECK(tx->retransmitted.size() == 0); // Send packet (1) to (7) - payload = ats_unique_malloc(16); - QUICPacketUPtr packet1 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), - std::move(payload), payload_len, true); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet2 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), - std::move(payload), payload_len, true); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet3 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), - std::move(payload), payload_len, true); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet4 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), - std::move(payload), payload_len, true); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet5 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), - std::move(payload), payload_len, true); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet6 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), - std::move(payload), payload_len, true); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet7 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), - std::move(payload), payload_len, true); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet8 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), - std::move(payload), payload_len, true); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet9 = pf.create_server_protected_packet(connection_id, detector.largest_acked_packet_number(), - std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet1 = + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet2 = + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet3 = + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet4 = + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet5 = + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet6 = + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet7 = + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet8 = + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet9 = + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); QUICPacketNumber pn1 = packet1->packet_number(); QUICPacketNumber pn2 = packet2->packet_number(); From 75a00c564f11e59a5145e1f9a0c1332770fd11bf Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 3 Sep 2018 15:52:32 +0900 Subject: [PATCH 0795/1313] Fix QUICLocalFlowContoroller --- iocore/net/quic/QUICFlowController.cc | 32 ++++++++++++++++++--------- iocore/net/quic/QUICFlowController.h | 20 ++++++++--------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 4cbca28d863..9fddb31204f 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -87,12 +87,6 @@ QUICFlowController::forward_limit(QUICOffset limit) this->_limit = limit; } -void -QUICFlowController::set_threshold(uint64_t threshold) -{ - this->_threshold = threshold; -} - void QUICFlowController::set_limit(QUICOffset limit) { @@ -156,29 +150,45 @@ QUICRemoteFlowController::update(QUICOffset offset) // // QUICLocalFlowController // +QUICOffset +QUICLocalFlowController::current_limit() const +{ + return this->_advertized_limit; +} + void QUICLocalFlowController::forward_limit(QUICOffset offset) { QUICFlowController::forward_limit(offset); - // Send MAX_(STREAM_)DATA frame + // Create MAX_(STREAM_)DATA frame. The frame will be sent on next WRITE_READY event on QUICNetVC if (this->_need_to_gen_frame()) { - this->_frame = this->_create_frame(); + this->_frame = this->_create_frame(); + this->_advertized_limit = this->_limit; } } int QUICLocalFlowController::update(QUICOffset offset) { - this->_analyzer.update(offset); + if (this->_offset <= offset) { + this->_analyzer.update(offset); + } return QUICFlowController::update(offset); } +void +QUICLocalFlowController::set_limit(QUICOffset limit) +{ + this->_advertized_limit = limit; + QUICFlowController::set_limit(limit); +} + bool QUICLocalFlowController::_need_to_gen_frame() { - this->_threshold = this->_analyzer.expect_recv_bytes(2 * this->_rtt_provider->smoothed_rtt()); - if (this->_offset + this->_threshold > this->_limit) { + QUICOffset threshold = this->_analyzer.expect_recv_bytes(2 * this->_rtt_provider->smoothed_rtt()); + if (this->_offset + threshold > this->_advertized_limit) { return true; } diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index 2f36fd9bbec..f849efbeae0 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -45,7 +45,7 @@ class QUICFlowController : public QUICFrameGenerator public: uint64_t credit() const; QUICOffset current_offset() const; - QUICOffset current_limit() const; + virtual QUICOffset current_limit() const; /* * Returns 0 if succeed @@ -53,13 +53,11 @@ class QUICFlowController : public QUICFrameGenerator virtual int update(QUICOffset offset); virtual void forward_limit(QUICOffset limit); - void set_threshold(uint64_t threshold); - /** * This is only for flow controllers initialized without a limit (== UINT64_MAX). * Once a limit is set, it should be updated with forward_limit(). */ - void set_limit(QUICOffset limit); + virtual void set_limit(QUICOffset limit); // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; @@ -69,10 +67,9 @@ class QUICFlowController : public QUICFrameGenerator QUICFlowController(uint64_t initial_limit) : _limit(initial_limit) {} virtual QUICFrameUPtr _create_frame() = 0; - QUICOffset _offset = 0; - QUICOffset _limit = 0; - QUICOffset _threshold = 1024; - QUICFrameUPtr _frame = QUICFrameFactory::create_null_frame(); + QUICOffset _offset = 0; //< Largest sent/received offset + QUICOffset _limit = 0; //< Maximum amount of data to send/receive + QUICFrameUPtr _frame = QUICFrameFactory::create_null_frame(); }; class QUICRemoteFlowController : public QUICFlowController @@ -90,16 +87,19 @@ class QUICLocalFlowController : public QUICFlowController { public: QUICLocalFlowController(QUICRTTProvider *rtt_provider, uint64_t initial_limit) - : QUICFlowController(initial_limit), _rtt_provider(rtt_provider) + : QUICFlowController(initial_limit), _advertized_limit(initial_limit), _rtt_provider(rtt_provider) { } + QUICOffset current_limit() const override; void forward_limit(QUICOffset limit) override; int update(QUICOffset offset) override; + void set_limit(QUICOffset limit) override; private: bool _need_to_gen_frame(); - QUICRateAnalyzer _analyzer; + QUICRateAnalyzer _analyzer; + QUICOffset _advertized_limit = 0; //< Advertized limit via MAX(_STREAM)_DATA frame to the remote endpoint QUICRTTProvider *_rtt_provider = nullptr; }; From abc0835abf2fc1df7dd0c9d413455067e5a7ed46 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 4 Sep 2018 11:32:13 +0900 Subject: [PATCH 0796/1313] Cleanup: Remove QUICStream::init_flow_control_params() --- iocore/net/quic/QUICStream.cc | 18 +++++------------- iocore/net/quic/QUICStream.h | 6 ++---- iocore/net/quic/test/test_QUICStream.cc | 8 ++++---- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 5949c1858f6..3b545dbaba6 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -50,13 +50,17 @@ QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider _id(sid), _remote_flow_controller(send_max_stream_data, _id), _local_flow_controller(rtt_provider, recv_max_stream_data, _id), + _flow_control_buffer_size(recv_max_stream_data), _received_stream_frame_buffer(this), _state(nullptr, nullptr, &_received_stream_frame_buffer, nullptr) { SET_HANDLER(&QUICStream::state_stream_open); mutex = new_ProxyMutex(); - this->init_flow_control_params(recv_max_stream_data, send_max_stream_data); + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), + this->_local_flow_controller.current_limit()); + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); } QUICStream::~QUICStream() @@ -72,18 +76,6 @@ QUICStream::~QUICStream() } } -void -QUICStream::init_flow_control_params(uint64_t recv_max_stream_data, uint64_t send_max_stream_data) -{ - this->_flow_control_buffer_size = recv_max_stream_data; - this->_local_flow_controller.forward_limit(recv_max_stream_data); - this->_remote_flow_controller.forward_limit(send_max_stream_data); - QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), - this->_local_flow_controller.current_limit()); - QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), - this->_remote_flow_controller.current_limit()); -} - QUICStreamId QUICStream::id() const { diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index c05f985d425..70cc6f2c49d 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -55,15 +55,13 @@ class QUICStream : public VConnection, public QUICFrameGenerator _state(nullptr, nullptr, nullptr, nullptr) { } - QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICStreamId sid, uint64_t recv_max_stream_data = 0, - uint64_t send_max_stream_data = 0); + QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICStreamId sid, uint64_t recv_max_stream_data, + uint64_t send_max_stream_data); ~QUICStream(); // void start(); int state_stream_open(int event, void *data); int state_stream_closed(int event, void *data); - void init_flow_control_params(uint64_t recv_max_stream_data, uint64_t send_max_stream_data); - QUICStreamId id() const; const QUICConnectionInfoProvider *info() const; QUICOffset final_offset() const; diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index b88abd35a65..f178279cbeb 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -151,8 +151,8 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id)); - stream->init_flow_control_params(4096, 4096); + std::unique_ptr stream( + new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, 4096, 4096)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); // Start with 1024 but not 0 so received frames won't be processed @@ -187,10 +187,10 @@ TEST_CASE("QUICStream", "[quic]") IOBufferReader *read_buffer_reader = read_buffer->alloc_reader(); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - std::unique_ptr stream(new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id)); + std::unique_ptr stream( + new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, 4096, 4096)); SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); - stream->init_flow_control_params(4096, 4096); MockContinuation mock_cont(stream->mutex); stream->do_io_read(nullptr, INT64_MAX, read_buffer); stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); From 5e65a99094e4a921466236dd0de90768b5b6d361 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 4 Sep 2018 11:34:45 +0900 Subject: [PATCH 0797/1313] Cleanup: Remove _advertized_limit from QUICLocalFlowController --- iocore/net/quic/QUICFlowController.cc | 21 +++++++++------------ iocore/net/quic/QUICFlowController.h | 13 ++++++++----- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 9fddb31204f..b7d738e7cfe 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -126,9 +126,9 @@ QUICFlowController::generate_frame(QUICEncryptionLevel level, uint64_t connectio // QUICRemoteFlowController // void -QUICRemoteFlowController::forward_limit(QUICOffset offset) +QUICRemoteFlowController::forward_limit(QUICOffset new_limit) { - QUICFlowController::forward_limit(offset); + QUICFlowController::forward_limit(new_limit); this->_blocked = false; } @@ -153,18 +153,16 @@ QUICRemoteFlowController::update(QUICOffset offset) QUICOffset QUICLocalFlowController::current_limit() const { - return this->_advertized_limit; + return this->_limit; } void -QUICLocalFlowController::forward_limit(QUICOffset offset) +QUICLocalFlowController::forward_limit(QUICOffset new_limit) { - QUICFlowController::forward_limit(offset); - // Create MAX_(STREAM_)DATA frame. The frame will be sent on next WRITE_READY event on QUICNetVC - if (this->_need_to_gen_frame()) { - this->_frame = this->_create_frame(); - this->_advertized_limit = this->_limit; + if (this->_need_to_forward_limit()) { + QUICFlowController::forward_limit(new_limit); + this->_frame = this->_create_frame(); } } @@ -180,15 +178,14 @@ QUICLocalFlowController::update(QUICOffset offset) void QUICLocalFlowController::set_limit(QUICOffset limit) { - this->_advertized_limit = limit; QUICFlowController::set_limit(limit); } bool -QUICLocalFlowController::_need_to_gen_frame() +QUICLocalFlowController::_need_to_forward_limit() { QUICOffset threshold = this->_analyzer.expect_recv_bytes(2 * this->_rtt_provider->smoothed_rtt()); - if (this->_offset + threshold > this->_advertized_limit) { + if (this->_offset + threshold >= this->_limit) { return true; } diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index f849efbeae0..4461a73b003 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -77,7 +77,7 @@ class QUICRemoteFlowController : public QUICFlowController public: QUICRemoteFlowController(uint64_t initial_limit) : QUICFlowController(initial_limit) {} int update(QUICOffset offset) override; - void forward_limit(QUICOffset limit) override; + void forward_limit(QUICOffset new_limit) override; private: bool _blocked = false; @@ -87,19 +87,22 @@ class QUICLocalFlowController : public QUICFlowController { public: QUICLocalFlowController(QUICRTTProvider *rtt_provider, uint64_t initial_limit) - : QUICFlowController(initial_limit), _advertized_limit(initial_limit), _rtt_provider(rtt_provider) + : QUICFlowController(initial_limit), _rtt_provider(rtt_provider) { } QUICOffset current_limit() const override; - void forward_limit(QUICOffset limit) override; + + /** + * Unlike QUICRemoteFlowController::forward_limit(), this function forwards limit if needed. + */ + void forward_limit(QUICOffset new_limit) override; int update(QUICOffset offset) override; void set_limit(QUICOffset limit) override; private: - bool _need_to_gen_frame(); + bool _need_to_forward_limit(); QUICRateAnalyzer _analyzer; - QUICOffset _advertized_limit = 0; //< Advertized limit via MAX(_STREAM)_DATA frame to the remote endpoint QUICRTTProvider *_rtt_provider = nullptr; }; From dafca89d479ab5ad411b11ee4338648e34865a55 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 4 Sep 2018 11:37:31 +0900 Subject: [PATCH 0798/1313] Forward limit of local flow controller with the largest reordered stream frame To cover reordering cases. (e.g. QUICStream Unit Test Section "QUICStream_flow_control_local") --- iocore/net/quic/QUICStream.cc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 3b545dbaba6..564e6b542f6 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -319,21 +319,25 @@ QUICStream::recv(const QUICStreamFrame &frame) return error; } - auto new_frame = this->_received_stream_frame_buffer.pop(); + auto new_frame = this->_received_stream_frame_buffer.pop(); + QUICStreamFrameSPtr stream_frame = nullptr; while (new_frame != nullptr) { - QUICStreamFrameSPtr stream_frame = std::static_pointer_cast(new_frame); + stream_frame = std::static_pointer_cast(new_frame); this->_write_to_read_vio(stream_frame->offset(), stream_frame->data(), stream_frame->data_length(), stream_frame->has_fin_flag()); + this->_state.update_with_receiving_frame(*new_frame); + + new_frame = this->_received_stream_frame_buffer.pop(); + } + // Forward limit of local flow controller with the largest reordered stream frame + if (stream_frame) { this->_reordered_bytes = stream_frame->offset() + stream_frame->data_length(); this->_local_flow_controller.forward_limit(this->_reordered_bytes + this->_flow_control_buffer_size); QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), this->_local_flow_controller.current_limit()); - this->_state.update_with_receiving_frame(*new_frame); - - new_frame = this->_received_stream_frame_buffer.pop(); } this->_signal_read_event(); From 6c7cef9c8d1c927d6f856e8eaa514ae9d532113f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 4 Sep 2018 14:20:47 +0900 Subject: [PATCH 0799/1313] [draft-13] Update Transport Error Codes --- iocore/net/QUICNetVConnection.cc | 4 ++-- iocore/net/quic/QUICDebugNames.cc | 17 +++++++---------- iocore/net/quic/QUICTypes.h | 8 +++----- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ab150be35d9..4732751aa3a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -549,7 +549,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) if (result == QUICPacketCreationResult::NOT_READY) { error = QUICErrorUPtr(new QUICNoError()); } else if (result == QUICPacketCreationResult::FAILED) { - error = QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); + error = QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); } else if (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::UNSUPPORTED) { error = this->_state_handshake_process_packet(std::move(packet)); } @@ -974,7 +974,7 @@ QUICNetVConnection::_state_common_receive_packet() do { QUICPacketUPtr p = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::FAILED) { - return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED)); + return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); } else if (result == QUICPacketCreationResult::NO_PACKET) { return QUICErrorUPtr(new QUICNoError()); } else if (result == QUICPacketCreationResult::NOT_READY) { diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index de86f8e7cd6..a30e97cd917 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -125,24 +125,21 @@ QUICDebugNames::error_code(QUICTransErrorCode code) return "STREAM_STATE_ERROR"; case QUICTransErrorCode::FINAL_OFFSET_ERROR: return "FINAL_OFFSET_ERROR"; - case QUICTransErrorCode::FRAME_FORMAT_ERROR: - return "FRAME_FORMAT_ERROR"; + case QUICTransErrorCode::FRAME_ENCODING_ERROR: + return "FRAME_ENCODING_ERROR"; case QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR: return "TRANSPORT_PARAMETER_ERROR"; case QUICTransErrorCode::VERSION_NEGOTIATION_ERROR: return "VERSION_NEGOTIATION_ERROR"; case QUICTransErrorCode::PROTOCOL_VIOLATION: return "PROTOCOL_VIOLATION"; - case QUICTransErrorCode::TLS_HANDSHAKE_FAILED: - return "TLS_HANDSHAKE_FAILED"; - case QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED: - return "TLS_FATAL_ALERT_GENERATED"; - case QUICTransErrorCode::TLS_FATAL_ALERT_RECEIVED: - return "TLS_FATAL_ALERT_RECEIVED"; + case QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE: + return "UNSOLICITED_PATH_RESPONSE"; + case QUICTransErrorCode::INVALID_MIGRATION: + return "INVALID_MIGRATION"; default: if (0x0100 <= static_cast(code) && static_cast(code) <= 0x01FF) { - // TODO: Add frame types - return "FRAME_ERROR"; + return "CRYPTO_ERROR"; } return "UNKNOWN"; } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 3076a2d1bb0..1089619503d 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -152,15 +152,13 @@ enum class QUICTransErrorCode : uint16_t { STREAM_ID_ERROR, STREAM_STATE_ERROR, FINAL_OFFSET_ERROR, - FRAME_FORMAT_ERROR, + FRAME_ENCODING_ERROR, TRANSPORT_PARAMETER_ERROR, VERSION_NEGOTIATION_ERROR, PROTOCOL_VIOLATION, UNSOLICITED_PATH_RESPONSE = 0x0B, - FRAME_ERROR = 0x0100, // 0x100 - 0x1FF - TLS_HANDSHAKE_FAILED = 0x0201, - TLS_FATAL_ALERT_GENERATED, - TLS_FATAL_ALERT_RECEIVED, + INVALID_MIGRATION = 0x0C, + CRYPTO_ERROR = 0x0100, // 0x100 - 0x1FF }; // Application Protocol Error Codes defined in application From e7c493ae72eef75958409ccade0b1b8313ace494 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 4 Sep 2018 16:20:30 +0900 Subject: [PATCH 0800/1313] Handle TLS Alerts on msg_cb --- iocore/net/quic/QUICHandshakeProtocol.h | 7 +- iocore/net/quic/QUICTLS.cc | 6 + iocore/net/quic/QUICTLS.h | 1 + iocore/net/quic/QUICTLS_openssl.cc | 31 +-- .../quic/test/test_QUICHandshakeProtocol.cc | 221 ++++++++++-------- 5 files changed, 158 insertions(+), 108 deletions(-) diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index abc441007e9..f489e302cc2 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -59,9 +59,10 @@ class QUICPacketNumberProtector }; struct QUICHandshakeMsgs { - uint8_t *buf = nullptr; //< pointer to the buffer - size_t max_buf_len = 0; //< size of buffer - size_t offsets[5] = {0}; //< offset to the each encryption level - {initial, zero_rtt, handshake, one_rtt, total length} + uint8_t *buf = nullptr; //< pointer to the buffer + size_t max_buf_len = 0; //< size of buffer + size_t offsets[5] = {0}; //< offset to the each encryption level - {initial, zero_rtt, handshake, one_rtt, total length} + uint16_t error_code = 0; //< CRYPTO_ERROR - TLS Alert Desciption + 0x100 }; class QUICHandshakeProtocol diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index bfbff386f76..23dbfab4c37 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -45,6 +45,12 @@ QUICTLS::~QUICTLS() delete this->_server_pp; } +uint16_t +QUICTLS::convert_to_quic_trans_error_code(uint8_t alert) +{ + return 0x100 | alert; +} + bool QUICTLS::is_handshake_finished() const { diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 7e040ac33cf..d7f2ec1d44f 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -49,6 +49,7 @@ class QUICTLS : public QUICHandshakeProtocol }; static QUICEncryptionLevel get_encryption_level(int msg_type); + static uint16_t convert_to_quic_trans_error_code(uint8_t alert); // FIXME Should not exist SSL *ssl_handle(); diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 6f3d25f989f..bdeda68efbc 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -39,7 +39,7 @@ content_type_str(int type) case SSL3_RT_CHANGE_CIPHER_SPEC: return "SSL3_RT_CHANGE_CIPHER_SPEC"; case SSL3_RT_ALERT: - return "SSL3_RT_ALERT 21"; + return "SSL3_RT_ALERT"; case SSL3_RT_HANDSHAKE: return "SSL3_RT_HANDSHAKE"; case SSL3_RT_APPLICATION_DATA: @@ -102,25 +102,30 @@ msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, return; } - const uint8_t *tmp = reinterpret_cast(buf); - int msg_type = tmp[0]; - - QUICEncryptionLevel level = QUICTLS::get_encryption_level(msg_type); - int index = static_cast(level); - int next_index = index + 1; - QUICHandshakeMsgs *msg = reinterpret_cast(arg); if (msg == nullptr) { return; } - size_t offset = msg->offsets[next_index]; - size_t next_level_offset = offset + len; + const uint8_t *msg_buf = reinterpret_cast(buf); + + if (content_type == SSL3_RT_HANDSHAKE) { + int msg_type = msg_buf[0]; - memcpy(msg->buf + offset, buf, len); + QUICEncryptionLevel level = QUICTLS::get_encryption_level(msg_type); + int index = static_cast(level); + int next_index = index + 1; - for (int i = next_index; i < 5; ++i) { - msg->offsets[i] = next_level_offset; + size_t offset = msg->offsets[next_index]; + size_t next_level_offset = offset + len; + + memcpy(msg->buf + offset, buf, len); + + for (int i = next_index; i < 5; ++i) { + msg->offsets[i] = next_level_offset; + } + } else if (content_type == SSL3_RT_ALERT && msg_buf[0] == SSL3_AL_FATAL && len == 2) { + msg->error_code = QUICTLS::convert_to_quic_trans_error_code(msg_buf[1]); } return; diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 818cf8acd2d..cf81b88559a 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -154,7 +154,7 @@ static const uint8_t ad[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // delete server; // } -TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") +TEST_CASE("QUICHandshakeProtocol") { // Client SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); @@ -164,7 +164,6 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") #ifdef SSL_MODE_QUIC_HACK SSL_CTX_set_mode(client_ssl_ctx, SSL_MODE_QUIC_HACK); #endif - QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); // Server SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); @@ -180,116 +179,154 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]") BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); EVP_PKEY *pkey = PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr); SSL_CTX_use_PrivateKey(server_ssl_ctx, pkey); - QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); - BIO_free(crt_bio); - BIO_free(key_bio); + SECTION("Full Handshake", "[quic]") + { + QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); + QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); - X509_free(x509); - EVP_PKEY_free(pkey); + CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + // CH + QUICHandshakeMsgs msg1; + uint8_t msg1_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg1.buf = msg1_buf; + msg1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - // CH - QUICHandshakeMsgs msg1; - uint8_t msg1_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; - msg1.buf = msg1_buf; - msg1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + REQUIRE(client->handshake(&msg1, nullptr) == 1); + std::cout << "### Messages from client" << std::endl; + print_hex(msg1.buf, msg1.offsets[4]); - REQUIRE(client->handshake(&msg1, nullptr) == 1); - std::cout << "### Messages from client" << std::endl; - print_hex(msg1.buf, msg1.offsets[4]); + // SH, EE, CERT, CV, FIN + QUICHandshakeMsgs msg2; + uint8_t msg2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2.buf = msg2_buf; + msg2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - // SH, EE, CERT, CV, FIN - QUICHandshakeMsgs msg2; - uint8_t msg2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; - msg2.buf = msg2_buf; - msg2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + REQUIRE(server->handshake(&msg2, &msg1) == 1); + std::cout << "### Messages from server" << std::endl; + print_hex(msg2.buf, msg2.offsets[4]); - REQUIRE(server->handshake(&msg2, &msg1) == 1); - std::cout << "### Messages from server" << std::endl; - print_hex(msg2.buf, msg2.offsets[4]); - - // FIN - QUICHandshakeMsgs msg3; - uint8_t msg3_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; - msg3.buf = msg3_buf; - msg3.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + // FIN + QUICHandshakeMsgs msg3; + uint8_t msg3_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg3.buf = msg3_buf; + msg3.max_buf_len = MAX_HANDSHAKE_MSG_LEN; #ifdef SSL_MODE_QUIC_HACK - // -- Hacks for OpenSSL with SSL_MODE_QUIC_HACK -- - // SH - QUICHandshakeMsgs msg2_1; - uint8_t msg2_1_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; - msg2_1.buf = msg2_1_buf; - msg2_1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - - memcpy(msg2_1.buf, msg2.buf, msg2.offsets[1]); - msg2_1.offsets[0] = 0; - msg2_1.offsets[1] = msg2.offsets[1]; - msg2_1.offsets[2] = msg2.offsets[1]; - msg2_1.offsets[3] = msg2.offsets[1]; - msg2_1.offsets[4] = msg2.offsets[1]; - - // EE - FIN - QUICHandshakeMsgs msg2_2; - uint8_t msg2_2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; - msg2_2.buf = msg2_2_buf; - msg2_2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; - - size_t len = msg2.offsets[3] - msg2.offsets[2]; - memcpy(msg2_2.buf, msg2.buf + msg2.offsets[1], len); - msg2_2.offsets[0] = 0; - msg2_2.offsets[1] = 0; - msg2_2.offsets[2] = 0; - msg2_2.offsets[3] = len; - msg2_2.offsets[4] = len; - - REQUIRE(client->handshake(&msg3, &msg2_1) == 1); - REQUIRE(client->handshake(&msg3, &msg2_2) == 1); + // -- Hacks for OpenSSL with SSL_MODE_QUIC_HACK -- + // SH + QUICHandshakeMsgs msg2_1; + uint8_t msg2_1_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2_1.buf = msg2_1_buf; + msg2_1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + memcpy(msg2_1.buf, msg2.buf, msg2.offsets[1]); + msg2_1.offsets[0] = 0; + msg2_1.offsets[1] = msg2.offsets[1]; + msg2_1.offsets[2] = msg2.offsets[1]; + msg2_1.offsets[3] = msg2.offsets[1]; + msg2_1.offsets[4] = msg2.offsets[1]; + + // EE - FIN + QUICHandshakeMsgs msg2_2; + uint8_t msg2_2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2_2.buf = msg2_2_buf; + msg2_2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + size_t len = msg2.offsets[3] - msg2.offsets[2]; + memcpy(msg2_2.buf, msg2.buf + msg2.offsets[1], len); + msg2_2.offsets[0] = 0; + msg2_2.offsets[1] = 0; + msg2_2.offsets[2] = 0; + msg2_2.offsets[3] = len; + msg2_2.offsets[4] = len; + + REQUIRE(client->handshake(&msg3, &msg2_1) == 1); + REQUIRE(client->handshake(&msg3, &msg2_2) == 1); #else - REQUIRE(client->handshake(&msg3, &msg2) == 1); + REQUIRE(client->handshake(&msg3, &msg2) == 1); #endif - std::cout << "### Messages from client" << std::endl; - print_hex(msg3.buf, msg3.offsets[4]); + std::cout << "### Messages from client" << std::endl; + print_hex(msg3.buf, msg3.offsets[4]); + + // NS + QUICHandshakeMsgs msg4; + uint8_t msg4_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg4.buf = msg4_buf; + msg4.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + REQUIRE(server->handshake(&msg4, &msg3) == 1); + std::cout << "### Messages from server" << std::endl; + print_hex(msg4.buf, msg4.offsets[4]); - // NS - QUICHandshakeMsgs msg4; - uint8_t msg4_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; - msg4.buf = msg4_buf; - msg4.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + // encrypt - decrypt + // client (encrypt) - server (decrypt) + std::cout << "### Original Text" << std::endl; + print_hex(original, sizeof(original)); - REQUIRE(server->handshake(&msg4, &msg3) == 1); - std::cout << "### Messages from server" << std::endl; - print_hex(msg4.buf, msg4.offsets[4]); + uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead + size_t cipher_len = 0; + CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), + QUICKeyPhase::PHASE_0)); - // encrypt - decrypt - // client (encrypt) - server (decrypt) - std::cout << "### Original Text" << std::endl; - print_hex(original, sizeof(original)); + std::cout << "### Encrypted Text" << std::endl; + print_hex(cipher, cipher_len); - uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead - size_t cipher_len = 0; - CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), - QUICKeyPhase::PHASE_0)); + uint8_t plain[128] = {0}; + size_t plain_len = 0; + CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); - std::cout << "### Encrypted Text" << std::endl; - print_hex(cipher, cipher_len); + std::cout << "### Decrypted Text" << std::endl; + print_hex(plain, plain_len); - uint8_t plain[128] = {0}; - size_t plain_len = 0; - CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); + CHECK(sizeof(original) == (plain_len)); + CHECK(memcmp(original, plain, plain_len) == 0); - std::cout << "### Decrypted Text" << std::endl; - print_hex(plain, plain_len); + // Teardown + delete client; + delete server; + } - CHECK(sizeof(original) == (plain_len)); - CHECK(memcmp(original, plain, plain_len) == 0); + SECTION("Alert", "[quic]") + { + QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); + CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + + // Malformed CH (finished) + uint8_t msg1_buf[] = {0x14, 0x00, 0x00, 0x30, 0x35, 0xb9, 0x82, 0x9d, 0xb9, 0x14, 0x70, 0x03, 0x60, + 0xd2, 0x5a, 0x03, 0x12, 0x12, 0x3d, 0x17, 0xc2, 0x13, 0x8c, 0xd7, 0x8b, 0x6e, + 0xc5, 0x4e, 0x50, 0x0a, 0x78, 0x6e, 0xa8, 0x54, 0x5f, 0x74, 0xfb, 0xf5, 0x6e, + 0x09, 0x90, 0x07, 0x58, 0x5a, 0x30, 0x5a, 0xe9, 0xcb, 0x1b, 0xa0, 0x69, 0x35}; + size_t msg1_len = sizeof(msg1_buf); + + QUICHandshakeMsgs msg1; + msg1.buf = msg1_buf; + msg1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + msg1.offsets[0] = 0; + msg1.offsets[1] = msg1_len; + msg1.offsets[2] = msg1_len; + msg1.offsets[3] = msg1_len; + msg1.offsets[4] = msg1_len; + + QUICHandshakeMsgs msg2; + uint8_t msg2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2.buf = msg2_buf; + msg2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + CHECK(server->handshake(&msg2, &msg1) != 1); + CHECK(msg2.error_code == 0x10a); //< 0x100 + unexpected_message(10) + + // Teardown + delete server; + } - // Teardown - delete client; - delete server; + BIO_free(crt_bio); + BIO_free(key_bio); + + X509_free(x509); + EVP_PKEY_free(pkey); SSL_CTX_free(server_ssl_ctx); SSL_CTX_free(client_ssl_ctx); From 656dffaa349db242141ba88deb3a03147d527325 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 6 Sep 2018 16:28:22 +0900 Subject: [PATCH 0801/1313] Make type of error code uint16_t for CRYPTO_ERROR (0x100 - 0x1FF) --- iocore/net/QUICNetVConnection.cc | 14 ++++---- iocore/net/quic/QUICDebugNames.cc | 29 +++++++++-------- iocore/net/quic/QUICDebugNames.h | 2 +- iocore/net/quic/QUICFrame.cc | 21 ++++++------ iocore/net/quic/QUICFrame.h | 11 +++---- iocore/net/quic/QUICStream.cc | 6 ++-- iocore/net/quic/QUICTypes.cc | 12 ++----- iocore/net/quic/QUICTypes.h | 32 +++++++++---------- iocore/net/quic/test/test_QUICFrame.cc | 14 ++++---- .../quic/test/test_QUICIncomingFrameBuffer.cc | 12 ++++--- iocore/net/quic/test/test_QUICStream.cc | 2 +- 11 files changed, 76 insertions(+), 79 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 4732751aa3a..abe1b461b7d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -481,11 +481,11 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra // An endpoint MAY transition from the closing period to the draining period if it can confirm that its peer is also closing or // draining. Receiving a closing frame is sufficient confirmation, as is receiving a stateless reset. if (frame.type() == QUICFrameType::APPLICATION_CLOSE) { - this->_switch_to_draining_state( - QUICConnectionErrorUPtr(new QUICConnectionError(static_cast(frame).error_code()))); + this->_switch_to_draining_state(QUICConnectionErrorUPtr( + new QUICConnectionError(QUICErrorClass::APPLICATION, static_cast(frame).error_code()))); } else { - this->_switch_to_draining_state( - QUICConnectionErrorUPtr(new QUICConnectionError(static_cast(frame).error_code()))); + this->_switch_to_draining_state(QUICConnectionErrorUPtr( + new QUICConnectionError(QUICErrorClass::TRANSPORT, static_cast(frame).error_code()))); } break; default: @@ -629,7 +629,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) } if (error->cls != QUICErrorClass::NONE) { - QUICConDebug("QUICError: cls=%u, code=0x%" PRIu16, static_cast(error->cls), error->code()); + QUICConDebug("QUICError: cls=%u, code=0x%" PRIu16, static_cast(error->cls), error->code); this->_handle_error(std::move(error)); } @@ -1477,10 +1477,10 @@ QUICNetVConnection::_handle_error(QUICErrorUPtr error) { if (error->cls == QUICErrorClass::APPLICATION) { QUICError("QUICError: %s (%u), APPLICATION ERROR (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls), - static_cast(error->cls), error->code()); + static_cast(error->cls), error->code); } else { QUICError("QUICError: %s (%u), %s (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls), - static_cast(error->cls), QUICDebugNames::error_code(error->trans_error_code), error->code()); + static_cast(error->cls), QUICDebugNames::error_code(error->code), error->code); } if (dynamic_cast(error.get()) != nullptr) { diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index a30e97cd917..44f13ebb8bc 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -110,37 +110,38 @@ QUICDebugNames::error_class(QUICErrorClass cls) } const char * -QUICDebugNames::error_code(QUICTransErrorCode code) +QUICDebugNames::error_code(uint16_t code) { switch (code) { - case QUICTransErrorCode::NO_ERROR: + case static_cast(QUICTransErrorCode::NO_ERROR): return "NO_ERROR"; - case QUICTransErrorCode::INTERNAL_ERROR: + case static_cast(QUICTransErrorCode::INTERNAL_ERROR): return "INTERNAL_ERROR"; - case QUICTransErrorCode::FLOW_CONTROL_ERROR: + case static_cast(QUICTransErrorCode::FLOW_CONTROL_ERROR): return "FLOW_CONTROL_ERROR"; - case QUICTransErrorCode::STREAM_ID_ERROR: + case static_cast(QUICTransErrorCode::STREAM_ID_ERROR): return "STREAM_ID_ERROR"; - case QUICTransErrorCode::STREAM_STATE_ERROR: + case static_cast(QUICTransErrorCode::STREAM_STATE_ERROR): return "STREAM_STATE_ERROR"; - case QUICTransErrorCode::FINAL_OFFSET_ERROR: + case static_cast(QUICTransErrorCode::FINAL_OFFSET_ERROR): return "FINAL_OFFSET_ERROR"; - case QUICTransErrorCode::FRAME_ENCODING_ERROR: + case static_cast(QUICTransErrorCode::FRAME_ENCODING_ERROR): return "FRAME_ENCODING_ERROR"; - case QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR: + case static_cast(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR): return "TRANSPORT_PARAMETER_ERROR"; - case QUICTransErrorCode::VERSION_NEGOTIATION_ERROR: + case static_cast(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR): return "VERSION_NEGOTIATION_ERROR"; - case QUICTransErrorCode::PROTOCOL_VIOLATION: + case static_cast(QUICTransErrorCode::PROTOCOL_VIOLATION): return "PROTOCOL_VIOLATION"; - case QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE: + case static_cast(QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE): return "UNSOLICITED_PATH_RESPONSE"; - case QUICTransErrorCode::INVALID_MIGRATION: + case static_cast(QUICTransErrorCode::INVALID_MIGRATION): return "INVALID_MIGRATION"; default: - if (0x0100 <= static_cast(code) && static_cast(code) <= 0x01FF) { + if (0x0100 <= code && code <= 0x01FF) { return "CRYPTO_ERROR"; } + return "UNKNOWN"; } } diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index b2ce4ecaab7..25411cf0532 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -34,7 +34,7 @@ class QUICDebugNames static const char *packet_type(QUICPacketType type); static const char *frame_type(QUICFrameType type); static const char *error_class(QUICErrorClass cls); - static const char *error_code(QUICTransErrorCode code); + static const char *error_code(uint16_t code); static const char *transport_parameter_id(QUICTransportParameterId id); static const char *stream_state(const QUICStreamState &state); static const char *quic_event(int event); diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 71ae8963f28..43459f26485 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1214,8 +1214,8 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len, size_t limit) const // // CONNECTION_CLOSE frame // -QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode error_code, QUICFrameType frame_type, - uint64_t reason_phrase_length, const char *reason_phrase, bool protection) +QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, + const char *reason_phrase, bool protection) : QUICFrame(protection), _error_code(error_code), _frame_type(frame_type), @@ -1312,7 +1312,7 @@ QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const return len; } -QUICTransErrorCode +uint16_t QUICConnectionCloseFrame::error_code() const { if (this->_buf) { @@ -2625,8 +2625,8 @@ QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64 } std::unique_ptr -QUICFrameFactory::create_connection_close_frame(QUICTransErrorCode error_code, QUICFrameType frame_type, - uint16_t reason_phrase_length, const char *reason_phrase) +QUICFrameFactory::create_connection_close_frame(uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length, + const char *reason_phrase) { QUICConnectionCloseFrame *frame = quicConnectionCloseFrameAllocator.alloc(); new (frame) QUICConnectionCloseFrame(error_code, frame_type, reason_phrase_length, reason_phrase); @@ -2638,10 +2638,9 @@ QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error) { ink_assert(error->cls == QUICErrorClass::TRANSPORT); if (error->msg) { - return QUICFrameFactory::create_connection_close_frame(error->trans_error_code, error->frame_type(), strlen(error->msg), - error->msg); + return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type(), strlen(error->msg), error->msg); } else { - return QUICFrameFactory::create_connection_close_frame(error->trans_error_code, error->frame_type()); + return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type()); } } @@ -2659,9 +2658,9 @@ QUICFrameFactory::create_application_close_frame(QUICConnectionErrorUPtr error) { ink_assert(error->cls == QUICErrorClass::APPLICATION); if (error->msg) { - return QUICFrameFactory::create_application_close_frame(error->app_error_code, strlen(error->msg), error->msg); + return QUICFrameFactory::create_application_close_frame(error->code, strlen(error->msg), error->msg); } else { - return QUICFrameFactory::create_application_close_frame(error->app_error_code); + return QUICFrameFactory::create_application_close_frame(error->code); } } @@ -2754,7 +2753,7 @@ QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCo std::unique_ptr QUICFrameFactory::create_rst_stream_frame(QUICStreamErrorUPtr error) { - return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->app_error_code, error->stream->final_offset()); + return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->code, error->stream->final_offset()); } std::unique_ptr diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index a82ac077587..0a9769d8015 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -350,15 +350,15 @@ class QUICConnectionCloseFrame : public QUICFrame public: QUICConnectionCloseFrame() : QUICFrame() {} QUICConnectionCloseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICConnectionCloseFrame(QUICTransErrorCode error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, - const char *reason_phrase, bool protection = true); + QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase, + bool protection = true); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual int debug_msg(char *msg, size_t msg_len) const override; - QUICTransErrorCode error_code() const; + uint16_t error_code() const; QUICFrameType frame_type() const; uint64_t reason_phrase_length() const; const char *reason_phrase() const; @@ -369,7 +369,7 @@ class QUICConnectionCloseFrame : public QUICFrame size_t _get_reason_phrase_length_field_length() const; size_t _get_reason_phrase_field_offset() const; - QUICTransErrorCode _error_code; + uint16_t _error_code; QUICFrameType _frame_type = QUICFrameType::UNKNOWN; uint64_t _reason_phrase_length = 0; const char *_reason_phrase = nullptr; @@ -938,8 +938,7 @@ class QUICFrameFactory * Creates a CONNECTION_CLOSE frame. */ static std::unique_ptr create_connection_close_frame( - QUICTransErrorCode error_code, QUICFrameType frame_type, uint16_t reason_phrase_length = 0, - const char *reason_phrase = nullptr); + uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr); static std::unique_ptr create_connection_close_frame( QUICConnectionErrorUPtr error); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 564e6b542f6..f0a1addf655 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -136,11 +136,11 @@ QUICStream::state_stream_open(int event, void *data) if (error->cls != QUICErrorClass::NONE) { if (error->cls == QUICErrorClass::TRANSPORT) { QUICStreamDebug("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), - static_cast(error->cls), QUICDebugNames::error_code(error->trans_error_code), - static_cast(error->trans_error_code)); + static_cast(error->cls), QUICDebugNames::error_code(error->code), + static_cast(error->code)); } else { QUICStreamDebug("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls), - static_cast(error->cls), static_cast(error->app_error_code)); + static_cast(error->cls), static_cast(error->code)); } if (dynamic_cast(error.get()) != nullptr) { // Stream Error diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 46988230136..535e495a500 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -182,10 +182,10 @@ QUICTypeUtil::read_QUICOffset(const uint8_t *buf) return static_cast(QUICIntUtil::read_QUICVariableInt(buf)); } -QUICTransErrorCode +uint16_t QUICTypeUtil::read_QUICTransErrorCode(const uint8_t *buf) { - return static_cast(QUICIntUtil::read_nbytes_as_uint(buf, 2)); + return QUICIntUtil::read_nbytes_as_uint(buf, 2); } QUICAppErrorCode @@ -242,7 +242,7 @@ QUICTypeUtil::write_QUICOffset(QUICOffset offset, uint8_t *buf, size_t *len) } void -QUICTypeUtil::write_QUICTransErrorCode(QUICTransErrorCode error_code, uint8_t *buf, size_t *len) +QUICTypeUtil::write_QUICTransErrorCode(uint16_t error_code, uint8_t *buf, size_t *len) { QUICIntUtil::write_uint_as_nbytes(static_cast(error_code), 2, buf, len); } @@ -274,12 +274,6 @@ QUICStatelessResetToken::_gen_token(uint64_t data) QUICIntUtil::write_uint_as_nbytes(_hash.u64[1], 8, _token + 8, &dummy); } -uint16_t -QUICError::code() -{ - return static_cast(this->trans_error_code); -} - QUICFrameType QUICConnectionError::frame_type() const { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 1089619503d..5e7a01e9adf 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -169,21 +169,17 @@ class QUICError { public: virtual ~QUICError() {} - uint16_t code(); QUICErrorClass cls = QUICErrorClass::NONE; - union { - QUICTransErrorCode trans_error_code = QUICTransErrorCode::NO_ERROR; - QUICAppErrorCode app_error_code; - }; - const char *msg = nullptr; + uint16_t code = 0; + const char *msg = nullptr; protected: QUICError(){}; - QUICError(const QUICTransErrorCode error_code, const char *error_msg = nullptr) - : cls(QUICErrorClass::TRANSPORT), trans_error_code(error_code), msg(error_msg){}; - QUICError(const QUICAppErrorCode error_code, const char *error_msg = nullptr) - : cls(QUICErrorClass::APPLICATION), app_error_code(error_code), msg(error_msg){}; + QUICError(QUICErrorClass error_class, uint16_t error_code, const char *error_msg = nullptr) + : cls(error_class), code(error_code), msg(error_msg) + { + } }; class QUICNoError : public QUICError @@ -196,10 +192,12 @@ class QUICConnectionError : public QUICError { public: QUICConnectionError() : QUICError() {} - QUICConnectionError(const QUICTransErrorCode error_code, const char *error_msg = nullptr, + QUICConnectionError(QUICTransErrorCode error_code, const char *error_msg = nullptr, + QUICFrameType frame_type = QUICFrameType::UNKNOWN) + : QUICError(QUICErrorClass::TRANSPORT, static_cast(error_code), error_msg), _frame_type(frame_type){}; + QUICConnectionError(QUICErrorClass error_class, uint16_t error_code, const char *error_msg = nullptr, QUICFrameType frame_type = QUICFrameType::UNKNOWN) - : QUICError(error_code, error_msg), _frame_type(frame_type){}; - QUICConnectionError(const QUICAppErrorCode error_code, const char *error_msg = nullptr) : QUICError(error_code, error_msg){}; + : QUICError(error_class, error_code, error_msg), _frame_type(frame_type){}; QUICFrameType frame_type() const; @@ -214,9 +212,9 @@ class QUICStreamError : public QUICError public: QUICStreamError() : QUICError() {} QUICStreamError(const QUICStream *s, const QUICTransErrorCode error_code, const char *error_msg = nullptr) - : QUICError(error_code, error_msg), stream(s){}; + : QUICError(QUICErrorClass::TRANSPORT, static_cast(error_code), error_msg), stream(s){}; QUICStreamError(const QUICStream *s, const QUICAppErrorCode error_code, const char *error_msg = nullptr) - : QUICError(error_code, error_msg), stream(s){}; + : QUICError(QUICErrorClass::APPLICATION, static_cast(error_code), error_msg), stream(s){}; const QUICStream *stream; }; @@ -349,7 +347,7 @@ class QUICTypeUtil static QUICVersion read_QUICVersion(const uint8_t *buf); static QUICStreamId read_QUICStreamId(const uint8_t *buf); static QUICOffset read_QUICOffset(const uint8_t *buf); - static QUICTransErrorCode read_QUICTransErrorCode(const uint8_t *buf); + static uint16_t read_QUICTransErrorCode(const uint8_t *buf); static QUICAppErrorCode read_QUICAppErrorCode(const uint8_t *buf); static uint64_t read_QUICMaxData(const uint8_t *buf); @@ -358,7 +356,7 @@ class QUICTypeUtil static void write_QUICVersion(QUICVersion version, uint8_t *buf, size_t *len); static void write_QUICStreamId(QUICStreamId stream_id, uint8_t *buf, size_t *len); static void write_QUICOffset(QUICOffset offset, uint8_t *buf, size_t *len); - static void write_QUICTransErrorCode(QUICTransErrorCode error_code, uint8_t *buf, size_t *len); + static void write_QUICTransErrorCode(uint16_t error_code, uint8_t *buf, size_t *len); static void write_QUICAppErrorCode(QUICAppErrorCode error_code, uint8_t *buf, size_t *len); static void write_QUICMaxData(uint64_t max_data, uint8_t *buf, size_t *len); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index d7dc8f933b9..d488a2a9464 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -647,7 +647,7 @@ TEST_CASE("ConnectionClose Frame", "[quic]") std::shared_ptr conn_close_frame = std::dynamic_pointer_cast(frame); CHECK(conn_close_frame != nullptr); - CHECK(conn_close_frame->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION); + CHECK(conn_close_frame->error_code() == static_cast(QUICTransErrorCode::PROTOCOL_VIOLATION)); CHECK(conn_close_frame->frame_type() == QUICFrameType::UNKNOWN); CHECK(conn_close_frame->reason_phrase_length() == reason_phrase_len); CHECK(memcmp(conn_close_frame->reason_phrase(), reason_phrase, reason_phrase_len) == 0); @@ -668,7 +668,7 @@ TEST_CASE("ConnectionClose Frame", "[quic]") std::shared_ptr conn_close_frame = std::dynamic_pointer_cast(frame); CHECK(conn_close_frame != nullptr); - CHECK(conn_close_frame->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION); + CHECK(conn_close_frame->error_code() == static_cast(QUICTransErrorCode::PROTOCOL_VIOLATION)); CHECK(conn_close_frame->frame_type() == QUICFrameType::RST_STREAM); CHECK(conn_close_frame->reason_phrase_length() == 0); } @@ -685,7 +685,8 @@ TEST_CASE("ConnectionClose Frame", "[quic]") 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; - QUICConnectionCloseFrame connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, QUICFrameType::STREAM, 5, "ABCDE"); + QUICConnectionCloseFrame connection_close_frame(static_cast(QUICTransErrorCode::PROTOCOL_VIOLATION), + QUICFrameType::STREAM, 5, "ABCDE"); CHECK(connection_close_frame.size() == sizeof(expected)); connection_close_frame.store(buf, &len, 32); @@ -704,7 +705,8 @@ TEST_CASE("ConnectionClose Frame", "[quic]") 0x00, // Frame Type 0x00, // Reason Phrase Length }; - QUICConnectionCloseFrame connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, QUICFrameType::UNKNOWN, 0, nullptr); + QUICConnectionCloseFrame connection_close_frame(static_cast(QUICTransErrorCode::PROTOCOL_VIOLATION), + QUICFrameType::UNKNOWN, 0, nullptr); connection_close_frame.store(buf, &len, 32); CHECK(len == sizeof(expected)); CHECK(memcmp(buf, expected, len) == 0); @@ -1238,14 +1240,14 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", std::unique_ptr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); std::unique_ptr connection_close_frame1 = QUICFrameFactory::create_connection_close_frame(std::move(error)); - CHECK(connection_close_frame1->error_code() == QUICTransErrorCode::INTERNAL_ERROR); + CHECK(connection_close_frame1->error_code() == static_cast(QUICTransErrorCode::INTERNAL_ERROR)); CHECK(connection_close_frame1->reason_phrase_length() == 0); CHECK(connection_close_frame1->reason_phrase() == nullptr); error = std::unique_ptr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR, "test")); std::unique_ptr connection_close_frame2 = QUICFrameFactory::create_connection_close_frame(std::move(error)); - CHECK(connection_close_frame2->error_code() == QUICTransErrorCode::INTERNAL_ERROR); + CHECK(connection_close_frame2->error_code() == static_cast(QUICTransErrorCode::INTERNAL_ERROR)); CHECK(connection_close_frame2->reason_phrase_length() == 4); CHECK(memcmp(connection_close_frame2->reason_phrase(), "test", 4) == 0); } diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index e8c104938fd..1ee7add8605 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -40,7 +40,8 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0, true); err = buffer.insert(*stream1_frame_0_r); - CHECK(err->trans_error_code != QUICTransErrorCode::FINAL_OFFSET_ERROR); + CHECK(err->cls == QUICErrorClass::NONE); + CHECK(err->code != static_cast(QUICTransErrorCode::FINAL_OFFSET_ERROR)); } SECTION("multiple frames") @@ -55,7 +56,8 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") buffer.insert(*stream1_frame_1_r); buffer.insert(*stream1_frame_2_r); err = buffer.insert(*stream1_frame_3_r); - CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); + CHECK(err->cls == QUICErrorClass::TRANSPORT); + CHECK(err->code == static_cast(QUICTransErrorCode::FINAL_OFFSET_ERROR)); QUICIncomingStreamFrameBuffer buffer2(stream); @@ -63,13 +65,15 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") buffer2.insert(*stream1_frame_0_r); buffer2.insert(*stream1_frame_1_r); err = buffer2.insert(*stream1_frame_2_r); - CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); + CHECK(err->cls == QUICErrorClass::TRANSPORT); + CHECK(err->code == static_cast(QUICTransErrorCode::FINAL_OFFSET_ERROR)); QUICIncomingStreamFrameBuffer buffer3(stream); buffer3.insert(*stream1_frame_4_r); err = buffer3.insert(*stream1_frame_3_r); - CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR); + CHECK(err->cls == QUICErrorClass::TRANSPORT); + CHECK(err->code == static_cast(QUICTransErrorCode::FINAL_OFFSET_ERROR)); } SECTION("Pure FIN") diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index f178279cbeb..e7a791cba28 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -175,7 +175,7 @@ TEST_CASE("QUICStream", "[quic]") // this should exceed the limit error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 8192)); CHECK(error->cls == QUICErrorClass::TRANSPORT); - CHECK(error->trans_error_code == QUICTransErrorCode::FLOW_CONTROL_ERROR); + CHECK(error->code == static_cast(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } SECTION("QUICStream_flow_control_remote", "[quic]") From 0014b3664c83d33b0fa1aabb6bfeacbc083698d0 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 7 Sep 2018 11:41:54 +0900 Subject: [PATCH 0802/1313] Return QUICConnectionError if QUICHandshakeMsgs has error_code --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICHandshake.cc | 27 +++++++++++++++++---------- iocore/net/quic/QUICHandshake.h | 2 +- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index abe1b461b7d..63a41486b25 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -900,7 +900,7 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe if (this->_handshake_handler->is_version_negotiated()) { error = this->_recv_and_ack(std::move(packet)); - if (!this->_handshake_handler->has_remote_tp()) { + if (error->cls == QUICErrorClass::NONE && !this->_handshake_handler->has_remote_tp()) { error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR)); } } diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index dffe998856a..a949011fad8 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -320,7 +320,7 @@ QUICHandshake::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) break; } - this->do_handshake(); + error = this->do_handshake(); return error; } @@ -389,9 +389,11 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi this->_local_transport_parameters = std::unique_ptr(tp); } -int +QUICErrorUPtr QUICHandshake::do_handshake() { + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICHandshakeMsgs in; uint8_t in_buf[UDP_MAXIMUM_PAYLOAD_SIZE] = {0}; in.buf = in_buf; @@ -420,17 +422,22 @@ QUICHandshake::do_handshake() int result = this->_hs_protocol->handshake(&out, &in); - for (auto level : QUIC_ENCRYPTION_LEVELS) { - int index = static_cast(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 (result == 1) { + for (auto level : QUIC_ENCRYPTION_LEVELS) { + int index = static_cast(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) { + this->_hs_protocol->abort_handshake(); + error = std::make_unique(QUICErrorClass::TRANSPORT, out.error_code); } - return result; + return error; } void diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index f9bcd75a68b..fb5cc2160a0 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -61,7 +61,7 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator // for server side QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); - int do_handshake(); + QUICErrorUPtr do_handshake(); // Getters QUICVersion negotiated_version(); From 83dfc5a11be6b795b7715ce4189f849cb0893223 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 7 Sep 2018 14:57:23 +0900 Subject: [PATCH 0803/1313] Cleanup: Remove QUICFrame::_protection --- iocore/net/quic/QUICAckFrameCreator.cc | 10 ++- iocore/net/quic/QUICFrame.cc | 94 +++++++++---------------- iocore/net/quic/QUICFrame.h | 97 +++++++++++--------------- iocore/net/quic/QUICStream.cc | 4 +- iocore/net/quic/test/test_QUICFrame.cc | 6 +- 5 files changed, 83 insertions(+), 128 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 3b0422a63a7..391934e1ea0 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -90,8 +90,6 @@ QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) size_t i = 0; uint8_t gap = 0; uint64_t length = 0; - // TODO: remove protection - bool protection = false; while (i < packet_numbers->size()) { QUICPacketNumber pn = (*packet_numbers)[i]; @@ -105,10 +103,10 @@ QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) ink_assert(length > 0); if (ack_frame) { - ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}, protection); + ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { uint64_t delay = this->_calculate_delay(level); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, protection); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1); } gap = last_ack_number - pn; @@ -117,10 +115,10 @@ QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) } if (ack_frame) { - ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}, protection); + ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { uint64_t delay = this->_calculate_delay(level); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, protection); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1); } return ack_frame; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 43459f26485..392696105cd 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -75,12 +75,6 @@ QUICFrame::reset(const uint8_t *buf, size_t len) this->_len = len; } -bool -QUICFrame::is_protected() const -{ - return this->_protection; -} - int QUICFrame::debug_msg(char *msg, size_t msg_len) const { @@ -97,9 +91,7 @@ QUICFrame::split(size_t size) // STREAM Frame // -QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, - bool protection) - : QUICFrame(protection) +QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last) { this->_data = std::move(data); this->_data_len = data_len; @@ -141,8 +133,8 @@ QUICStreamFrame::split(size_t size) this->reset(nullptr, 0); QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) - QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin, this->is_protected()); + new (frame) QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin); + return frame; } @@ -150,7 +142,7 @@ QUICFrameUPtr QUICStreamFrame::clone() const { return QUICFrameFactory::create_stream_frame(this->data(), this->data_length(), this->stream_id(), this->offset(), - this->has_fin_flag(), this->is_protected()); + this->has_fin_flag()); } QUICFrameType @@ -392,7 +384,7 @@ QUICStreamFrame::_get_length_field_len() const // CRYPTO frame // -QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffset offset, bool protection) : QUICFrame(protection) +QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffset offset) { this->_data = std::move(data); this->_data_len = data_len; @@ -423,14 +415,15 @@ QUICCryptoFrame::split(size_t size) this->reset(nullptr, 0); QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); - new (frame) QUICCryptoFrame(std::move(buf2), buf2_len, this->offset() + this->data_length(), this->is_protected()); + new (frame) QUICCryptoFrame(std::move(buf2), buf2_len, this->offset() + this->data_length()); + return frame; } QUICFrameUPtr QUICCryptoFrame::clone() const { - return QUICFrameFactory::create_crypto_frame(this->data(), this->data_length(), this->offset(), this->is_protected()); + return QUICFrameFactory::create_crypto_frame(this->data(), this->data_length(), this->offset()); } QUICFrameType @@ -559,13 +552,12 @@ QUICCryptoFrame::_get_length_field_len() const // ACK frame // -QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len, bool protection) : QUICFrame(buf, len, protection) +QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) { this->reset(buf, len); } -QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, bool protection) - : QUICFrame(protection) +QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block) { this->_largest_acknowledged = largest_acknowledged; this->_ack_delay = ack_delay; @@ -594,7 +586,7 @@ QUICFrameUPtr QUICAckFrame::clone() const { std::unique_ptr newframe = QUICFrameFactory::create_ack_frame( - this->largest_acknowledged(), this->ack_delay(), this->ack_block_section()->first_ack_block(), this->is_protected()); + this->largest_acknowledged(), this->ack_delay(), this->ack_block_section()->first_ack_block()); // TODO Copy ack block section return newframe; } @@ -654,12 +646,6 @@ QUICAckFrame::debug_msg(char *msg, size_t msg_len) const return len; } -bool -QUICAckFrame::is_protected() const -{ - return QUICFrame::is_protected() || this->_ack_block_section->has_protected(); -} - QUICPacketNumber QUICAckFrame::largest_acknowledged() const { @@ -912,16 +898,9 @@ QUICAckFrame::AckBlockSection::first_ack_block() const } void -QUICAckFrame::AckBlockSection::add_ack_block(AckBlock block, bool protection) +QUICAckFrame::AckBlockSection::add_ack_block(AckBlock block) { this->_ack_blocks.push_back(block); - this->_protection |= protection; -} - -bool -QUICAckFrame::AckBlockSection::has_protected() const -{ - return this->_protection; } QUICAckFrame::AckBlockSection::const_iterator @@ -1016,9 +995,8 @@ QUICAckFrame::AckBlockSection::const_iterator::operator==(const const_iterator & // RST_STREAM frame // -QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, - bool protection) - : QUICFrame(protection), _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset) +QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset) + : _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset) { } @@ -1215,12 +1193,8 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len, size_t limit) const // CONNECTION_CLOSE frame // QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, - const char *reason_phrase, bool protection) - : QUICFrame(protection), - _error_code(error_code), - _frame_type(frame_type), - _reason_phrase_length(reason_phrase_length), - _reason_phrase(reason_phrase) + const char *reason_phrase) + : _error_code(error_code), _frame_type(frame_type), _reason_phrase_length(reason_phrase_length), _reason_phrase(reason_phrase) { } @@ -1405,8 +1379,7 @@ QUICConnectionCloseFrame::_get_reason_phrase_field_offset() const // APPLICATION_CLOSE frame // QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, - const char *reason_phrase, bool protection) - : QUICFrame(protection) + const char *reason_phrase) { this->_error_code = error_code; this->_reason_phrase_length = reason_phrase_length; @@ -1517,7 +1490,7 @@ QUICApplicationCloseFrame::_get_reason_phrase_field_offset() const // // MAX_DATA frame // -QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, bool protection) +QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data) { this->_maximum_data = maximum_data; } @@ -1593,8 +1566,7 @@ QUICMaxDataFrame::_get_max_data_field_length() const // // MAX_STREAM_DATA // -QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, bool protection) - : QUICFrame(protection) +QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data) { this->_stream_id = stream_id; this->_maximum_stream_data = maximum_stream_data; @@ -1703,7 +1675,7 @@ QUICMaxStreamDataFrame::_get_max_stream_data_field_length() const // // MAX_STREAM_ID // -QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, bool protection) : QUICFrame(protection) +QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id) { this->_maximum_stream_id = maximum_stream_id; } @@ -2107,8 +2079,8 @@ QUICNewConnectionIdFrame::_get_connection_id_field_offset() const // STOP_SENDING frame // -QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, bool protection) - : QUICFrame(protection), _stream_id(stream_id), _error_code(error_code) +QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code) + : _stream_id(stream_id), _error_code(error_code) { } @@ -2403,7 +2375,7 @@ QUICNewTokenFrame::_get_token_field_offset() const // QUICRetransmissionFrame // QUICRetransmissionFrame::QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet) - : QUICFrame(original_frame->is_protected()), _packet_type(original_packet.type()) + : _packet_type(original_packet.type()) { this->_frame = std::move(original_frame); } @@ -2582,25 +2554,24 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) } QUICStreamFrameUPtr -QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, - bool protection) +QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last) { ats_unique_buf buf = ats_unique_malloc(data_len); memcpy(buf.get(), data, data_len); QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last, protection); + new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last); return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); } QUICCryptoFrameUPtr -QUICFrameFactory::create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, bool protection) +QUICFrameFactory::create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset) { ats_unique_buf buf = ats_unique_malloc(data_len); memcpy(buf.get(), data, data_len); QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); - new (frame) QUICCryptoFrame(std::move(buf), data_len, offset, protection); + new (frame) QUICCryptoFrame(std::move(buf), data_len, offset); return QUICCryptoFrameUPtr(frame, &QUICFrameDeleter::delete_crypto_frame); } @@ -2616,11 +2587,10 @@ QUICFrameFactory::split_frame(QUICFrame *frame, size_t size) } std::unique_ptr -QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, - bool protection) +QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block) { QUICAckFrame *frame = quicAckFrameAllocator.alloc(); - new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block, protection); + new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block); return std::unique_ptr(frame, &QUICFrameDeleter::delete_ack_frame); } @@ -2692,7 +2662,7 @@ std::unique_ptr QUICFrameFactory::create_ping_frame() { QUICPingFrame *frame = quicPingFrameAllocator.alloc(); - new (frame) QUICPingFrame(true); + new (frame) QUICPingFrame(); return std::unique_ptr(frame, &QUICFrameDeleter::delete_ping_frame); } @@ -2703,7 +2673,7 @@ QUICFrameFactory::create_path_challenge_frame(const uint8_t *data) memcpy(buf.get(), data, QUICPathChallengeFrame::DATA_LEN); QUICPathChallengeFrame *frame = quicPathChallengeFrameAllocator.alloc(); - new (frame) QUICPathChallengeFrame(std::move(buf), false); + new (frame) QUICPathChallengeFrame(std::move(buf)); return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_challenge_frame); } @@ -2714,7 +2684,7 @@ QUICFrameFactory::create_path_response_frame(const uint8_t *data) memcpy(buf.get(), data, QUICPathResponseFrame::DATA_LEN); QUICPathResponseFrame *frame = quicPathResponseFrameAllocator.alloc(); - new (frame) QUICPathResponseFrame(std::move(buf), false); + new (frame) QUICPathResponseFrame(std::move(buf)); return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_response_frame); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 0a9769d8015..2453ec1cdfd 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -47,8 +47,7 @@ using QUICCryptoFrameSPtr = std::shared_ptr; class QUICFrame { public: - QUICFrame(const uint8_t *buf, size_t len, bool protection) : _buf(buf), _len(len), _protection(protection) {} - QUICFrame(bool protection) : _protection(protection) {} + QUICFrame(const uint8_t *buf, size_t len) : _buf(buf), _len(len) {} virtual ~QUICFrame() {} static QUICFrameType type(const uint8_t *buf); @@ -57,7 +56,6 @@ class QUICFrame virtual size_t size() const = 0; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const = 0; virtual void reset(const uint8_t *buf, size_t len); - virtual bool is_protected() const; virtual QUICFrame *split(size_t size); virtual int debug_msg(char *msg, size_t msg_len) const; LINK(QUICFrame, link); @@ -66,7 +64,6 @@ class QUICFrame QUICFrame() {} const uint8_t *_buf = nullptr; size_t _len = 0; - bool _protection = true; }; // @@ -77,9 +74,8 @@ class QUICStreamFrame : public QUICFrame { public: QUICStreamFrame() : QUICFrame() {} - QUICStreamFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false, - bool protection = true); + QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false); QUICFrame *split(size_t size) override; QUICFrameUPtr clone() const override; @@ -123,8 +119,8 @@ class QUICCryptoFrame : public QUICFrame { public: QUICCryptoFrame() : QUICFrame() {} - QUICCryptoFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICCryptoFrame(ats_unique_buf buf, size_t len, QUICOffset offset, bool protection = true); + QUICCryptoFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICCryptoFrame(ats_unique_buf buf, size_t len, QUICOffset offset); QUICFrame *split(size_t size) override; QUICFrameUPtr clone() const override; @@ -228,7 +224,7 @@ class QUICAckFrame : public QUICFrame size_t size() const; size_t store(uint8_t *buf, size_t *len, size_t limit) const; uint64_t first_ack_block() const; - void add_ack_block(const AckBlock block, bool protection = true); + void add_ack_block(const AckBlock block); const_iterator begin() const; const_iterator end() const; bool has_protected() const; @@ -240,12 +236,11 @@ class QUICAckFrame : public QUICFrame uint64_t _first_ack_block = 0; uint8_t _ack_block_count = 0; std::vector _ack_blocks; - bool _protection = false; }; QUICAckFrame() : QUICFrame() {} - QUICAckFrame(const uint8_t *buf, size_t len, bool protection = true); - QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, bool protection = true); + QUICAckFrame(const uint8_t *buf, size_t len); + QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block); virtual ~QUICAckFrame(); virtual void reset(const uint8_t *buf, size_t len) override; @@ -254,7 +249,6 @@ class QUICAckFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual int debug_msg(char *msg, size_t msg_len) const override; - bool is_protected() const override; QUICPacketNumber largest_acknowledged() const; uint64_t ack_delay() const; @@ -284,8 +278,8 @@ class QUICRstStreamFrame : public QUICFrame { public: QUICRstStreamFrame() : QUICFrame() {} - QUICRstStreamFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, bool protection = true); + QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -316,8 +310,7 @@ class QUICPingFrame : public QUICFrame { public: QUICPingFrame() : QUICFrame() {} - QUICPingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICPingFrame(bool protection) : QUICFrame(protection) {} + QUICPingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -334,7 +327,7 @@ class QUICPaddingFrame : public QUICFrame { public: QUICPaddingFrame() : QUICFrame() {} - QUICPaddingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} + QUICPaddingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -349,9 +342,8 @@ class QUICConnectionCloseFrame : public QUICFrame { public: QUICConnectionCloseFrame() : QUICFrame() {} - QUICConnectionCloseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase, - bool protection = true); + QUICConnectionCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -383,9 +375,8 @@ class QUICApplicationCloseFrame : public QUICFrame { public: QUICApplicationCloseFrame() : QUICFrame() {} - QUICApplicationCloseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase, - bool protection = true); + QUICApplicationCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -412,8 +403,8 @@ class QUICMaxDataFrame : public QUICFrame { public: QUICMaxDataFrame() : QUICFrame() {} - QUICMaxDataFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICMaxDataFrame(uint64_t maximum_data, bool protection = true); + QUICMaxDataFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICMaxDataFrame(uint64_t maximum_data); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -436,8 +427,8 @@ class QUICMaxStreamDataFrame : public QUICFrame { public: QUICMaxStreamDataFrame() : QUICFrame() {} - QUICMaxStreamDataFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, bool protection = true); + QUICMaxStreamDataFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -465,8 +456,8 @@ class QUICMaxStreamIdFrame : public QUICFrame { public: QUICMaxStreamIdFrame() : QUICFrame() {} - QUICMaxStreamIdFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, bool protection = true); + QUICMaxStreamIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -486,8 +477,8 @@ class QUICBlockedFrame : public QUICFrame { public: QUICBlockedFrame() : QUICFrame() {} - QUICBlockedFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICBlockedFrame(QUICOffset offset, bool protection = true) : QUICFrame(protection), _offset(offset){}; + QUICBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICBlockedFrame(QUICOffset offset) : _offset(offset){}; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -510,8 +501,8 @@ class QUICStreamBlockedFrame : public QUICFrame { public: QUICStreamBlockedFrame() : QUICFrame() {} - QUICStreamBlockedFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o, bool protection = true) : QUICFrame(protection), _stream_id(s), _offset(o){}; + QUICStreamBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o) : _stream_id(s), _offset(o){}; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -537,8 +528,8 @@ class QUICStreamIdBlockedFrame : public QUICFrame { public: QUICStreamIdBlockedFrame() : QUICFrame() {} - QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICStreamIdBlockedFrame(QUICStreamId s, bool protection = true) : QUICFrame(protection), _stream_id(s) {} + QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICStreamIdBlockedFrame(QUICStreamId s) : _stream_id(s) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -560,9 +551,9 @@ class QUICNewConnectionIdFrame : public QUICFrame { public: QUICNewConnectionIdFrame() : QUICFrame() {} - QUICNewConnectionIdFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId id, QUICStatelessResetToken token, bool protection = true) - : QUICFrame(protection), _sequence(seq), _connection_id(id), _stateless_reset_token(token){}; + QUICNewConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId id, QUICStatelessResetToken token) + : _sequence(seq), _connection_id(id), _stateless_reset_token(token){}; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -591,8 +582,8 @@ class QUICStopSendingFrame : public QUICFrame { public: QUICStopSendingFrame() : QUICFrame() {} - QUICStopSendingFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, bool protection = true); + QUICStopSendingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -619,8 +610,8 @@ class QUICPathChallengeFrame : public QUICFrame public: static constexpr uint8_t DATA_LEN = 8; QUICPathChallengeFrame() : QUICFrame() {} - QUICPathChallengeFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICPathChallengeFrame(ats_unique_buf data, bool protection = true) : QUICFrame(protection), _data(std::move(data)) {} + QUICPathChallengeFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICPathChallengeFrame(ats_unique_buf data) : _data(std::move(data)) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -643,8 +634,8 @@ class QUICPathResponseFrame : public QUICFrame public: static constexpr uint8_t DATA_LEN = 8; QUICPathResponseFrame() : QUICFrame() {} - QUICPathResponseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICPathResponseFrame(ats_unique_buf data, bool protection = true) : QUICFrame(protection), _data(std::move(data)) {} + QUICPathResponseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICPathResponseFrame(ats_unique_buf data) : _data(std::move(data)) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -666,11 +657,8 @@ class QUICNewTokenFrame : public QUICFrame { public: QUICNewTokenFrame() : QUICFrame() {} - QUICNewTokenFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {} - QUICNewTokenFrame(ats_unique_buf token, size_t token_length, bool protection = true) - : QUICFrame(protection), _token_length(token_length), _token(std::move(token)) - { - } + QUICNewTokenFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICNewTokenFrame(ats_unique_buf token, size_t token_length) : _token_length(token_length), _token(std::move(token)) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -918,13 +906,13 @@ class QUICFrameFactory * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ static QUICStreamFrameUPtr create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, - bool last = false, bool protection = true); + bool last = false); /* * Creates a CRYPTO frame. * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ - static QUICCryptoFrameUPtr create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, bool protection = true); + static QUICCryptoFrameUPtr create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset); /* * Creates a ACK frame. @@ -932,8 +920,7 @@ class QUICFrameFactory * need to ack. */ static std::unique_ptr create_ack_frame(QUICPacketNumber largest_acknowledged, - uint64_t ack_delay, uint64_t first_ack_block, - bool protection = true); + uint64_t ack_delay, uint64_t first_ack_block); /* * Creates a CONNECTION_CLOSE frame. */ diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index f0a1addf655..9b69c174eaf 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -452,7 +452,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit // STREAM - Pure FIN or data length is lager than 0 frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, this->_id, - this->_send_offset, fin, true); + this->_send_offset, fin); if (!this->_state.is_allowed_to_send(*frame)) { QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); return frame; @@ -699,7 +699,7 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ } frame = QUICFrameFactory::create_crypto_frame(reinterpret_cast(this->_write_buffer_reader->start()), - frame_payload_size, this->_send_offset, true); + frame_payload_size, this->_send_offset); this->_send_offset += frame_payload_size; this->_write_buffer_reader->consume(frame_payload_size); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index d488a2a9464..c7c9b7789f8 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -591,7 +591,7 @@ TEST_CASE("Store Ping Frame", "[quic]") 0x07, // Type }; - QUICPingFrame frame(true); + QUICPingFrame frame; CHECK(frame.size() == 1); frame.store(buf, &len, 16); @@ -1098,7 +1098,7 @@ TEST_CASE("Store PATH_CHALLENGE Frame", "[quic]") ats_unique_buf data = ats_unique_malloc(raw_len); memcpy(data.get(), raw, raw_len); - QUICPathChallengeFrame frame(std::move(data), QUICPathChallengeFrame::DATA_LEN); + QUICPathChallengeFrame frame(std::move(data)); CHECK(frame.size() == 9); frame.store(buf, &len, 16); @@ -1136,7 +1136,7 @@ TEST_CASE("Store PATH_RESPONSE Frame", "[quic]") ats_unique_buf data = ats_unique_malloc(raw_len); memcpy(data.get(), raw, raw_len); - QUICPathResponseFrame frame(std::move(data), QUICPathResponseFrame::DATA_LEN); + QUICPathResponseFrame frame(std::move(data)); CHECK(frame.size() == 9); frame.store(buf, &len, 16); From 17159040c6eab84b93186e59d53b6c6cbe5fd16a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 7 Sep 2018 16:09:55 +0900 Subject: [PATCH 0804/1313] Fix sending only one NEW_CONNECTION_ID frame The bug is introduced by 49f8be8763e60c2ee4c13c5d10956e2059cc712c --- iocore/net/quic/QUICAltConnectionManager.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index feb1aa8646a..88763fe0945 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -125,8 +125,12 @@ QUICAltConnectionManager::generate_frame(QUICEncryptionLevel level, uint64_t con } else { this->_alt_quic_connection_ids[i].advertised = true; } + + return frame; } } + this->_need_advertise = false; + return frame; } From 41f043e53d02d782cd24d3dbc74b21369c58f1c6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 30 Aug 2018 14:00:45 +0900 Subject: [PATCH 0805/1313] Reduce dependency for SSL library --- iocore/net/quic/QUICGlobals.cc | 8 ++-- iocore/net/quic/QUICGlobals.h | 2 +- iocore/net/quic/QUICHandshake.cc | 44 +++++++++++++++------- iocore/net/quic/QUICHandshake.h | 16 ++++---- iocore/net/quic/QUICHandshakeProtocol.h | 24 +++++++----- iocore/net/quic/QUICTLS.cc | 24 ++++++++++++ iocore/net/quic/QUICTLS.h | 10 +++++ iocore/net/quic/QUICTLS_openssl.cc | 2 + iocore/net/quic/QUICTransportParameters.cc | 13 ++++--- 9 files changed, 102 insertions(+), 41 deletions(-) diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index ceb4c9549ed..c318feb3651 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -31,15 +31,15 @@ RecRawStatBlock *quic_rsb; -int QUIC::ssl_quic_qc_index = -1; -int QUIC::ssl_quic_hs_index = -1; +int QUIC::ssl_quic_qc_index = -1; +int QUIC::ssl_quic_tls_index = -1; void QUIC::init() { QUIC::_register_stats(); - ssl_quic_qc_index = SSL_get_ex_new_index(0, (void *)"QUICConnection index", nullptr, nullptr, nullptr); - ssl_quic_hs_index = SSL_get_ex_new_index(0, (void *)"QUICHandshake index", nullptr, nullptr, nullptr); + ssl_quic_qc_index = SSL_get_ex_new_index(0, (void *)"QUICConnection index", nullptr, nullptr, nullptr); + ssl_quic_tls_index = SSL_get_ex_new_index(0, (void *)"QUICTLS index", nullptr, nullptr, nullptr); } int diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h index 379fa18619c..0e1c1ebc9f9 100644 --- a/iocore/net/quic/QUICGlobals.h +++ b/iocore/net/quic/QUICGlobals.h @@ -35,7 +35,7 @@ class QUIC unsigned inlen, void *); static int ssl_quic_qc_index; - static int ssl_quic_hs_index; + static int ssl_quic_tls_index; private: static void _register_stats(); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index a949011fad8..645ef6ed95f 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -97,7 +97,6 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp, QUI if (dynamic_cast(hsp)) { SSL *ssl = static_cast(hsp)->ssl_handle(); SSL_set_ex_data(ssl, QUIC::ssl_quic_qc_index, qc); - SSL_set_ex_data(ssl, QUIC::ssl_quic_hs_index, this); } this->_hs_protocol->initialize_key_materials(this->_qc->original_connection_id()); @@ -223,14 +222,26 @@ QUICHandshake::negotiated_application_name(const uint8_t **name, unsigned int *l this->_hs_protocol->negotiated_application_name(name, len); } -void -QUICHandshake::set_transport_parameters(std::shared_ptr tp) +bool +QUICHandshake::check_remote_transport_parameters() +{ + auto tp = this->_hs_protocol->remote_transport_parameters(); + if (std::dynamic_pointer_cast(tp)) { + return this->_check_remote_transport_parameters(std::static_pointer_cast(tp)); + } else { + return this->_check_remote_transport_parameters( + std::static_pointer_cast(tp)); + } +} + +bool +QUICHandshake::_check_remote_transport_parameters(std::shared_ptr tp) { // An endpoint MUST treat receipt of duplicate transport parameters as a connection error of type TRANSPORT_PARAMETER_ERROR. if (!tp->is_valid()) { QUICHSDebug("Transport parameter is not valid"); this->_abort_handshake(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR); - return; + return false; } this->_remote_transport_parameters = tp; @@ -239,21 +250,21 @@ QUICHandshake::set_transport_parameters(std::shared_ptr_version_negotiator->validate(tp.get()) != QUICVersionNegotiationStatus::VALIDATED) { QUICHSDebug("Version revalidation failed"); this->_abort_handshake(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR); - return; + return false; } QUICHSDebug("Version negotiation validated: %x", tp->initial_version()); - return; + return true; } -void -QUICHandshake::set_transport_parameters(std::shared_ptr tp) +bool +QUICHandshake::_check_remote_transport_parameters(std::shared_ptr tp) { // An endpoint MUST treat receipt of duplicate transport parameters as a connection error of type TRANSPORT_PARAMETER_ERROR. if (!tp->is_valid()) { QUICHSDebug("Transport parameter is not valid"); this->_abort_handshake(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR); - return; + return false; } this->_remote_transport_parameters = tp; @@ -262,10 +273,10 @@ QUICHandshake::set_transport_parameters(std::shared_ptr_version_negotiator->validate(tp.get()) != QUICVersionNegotiationStatus::VALIDATED) { QUICHSDebug("Version revalidation failed"); this->_abort_handshake(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR); - return; + return false; } - return; + return true; } std::shared_ptr @@ -365,9 +376,9 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve // MAYs tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_in()); tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_in()); - // this->_local_transport_parameters.add(QUICTransportParameterId::MAX_PACKET_SIZE, {{0x00, 0x00}, 2}); + this->_local_transport_parameters = std::shared_ptr(tp); - this->_local_transport_parameters = std::unique_ptr(tp); + this->_hs_protocol->set_local_transport_parameters(this->_local_transport_parameters); } void @@ -386,7 +397,7 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_out()); tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_out()); - this->_local_transport_parameters = std::unique_ptr(tp); + this->_hs_protocol->set_local_transport_parameters(std::unique_ptr(tp)); } QUICErrorUPtr @@ -421,6 +432,11 @@ QUICHandshake::do_handshake() out.max_buf_len = MAX_HANDSHAKE_MSG_LEN; int result = this->_hs_protocol->handshake(&out, &in); + if (this->_remote_transport_parameters == nullptr) { + if (!this->check_remote_transport_parameters()) { + result = 0; + } + } if (result == 1) { for (auto level : QUIC_ENCRYPTION_LEVELS) { diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index fb5cc2160a0..ce016bfe9ae 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -63,6 +63,8 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator QUICErrorUPtr do_handshake(); + bool check_remote_transport_parameters(); + // Getters QUICVersion negotiated_version(); const char *negotiated_cipher_suite(); @@ -75,14 +77,9 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator bool is_stateless_retry_enabled() const; bool has_remote_tp() const; - void set_transport_parameters(std::shared_ptr tp); - void set_transport_parameters(std::shared_ptr tp); - private: - QUICConnection *_qc = nullptr; - QUICHandshakeProtocol *_hs_protocol = nullptr; - std::shared_ptr _local_transport_parameters = nullptr; - std::shared_ptr _remote_transport_parameters = nullptr; + QUICConnection *_qc = nullptr; + QUICHandshakeProtocol *_hs_protocol = nullptr; QUICVersionNegotiator *_version_negotiator = nullptr; QUICStatelessResetToken _reset_token; @@ -103,5 +100,10 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator } void _load_local_server_transport_parameters(QUICVersion negotiated_version); void _load_local_client_transport_parameters(QUICVersion initial_version); + bool _check_remote_transport_parameters(std::shared_ptr tp); + bool _check_remote_transport_parameters(std::shared_ptr tp); + std::shared_ptr _local_transport_parameters = nullptr; + std::shared_ptr _remote_transport_parameters = nullptr; + void _abort_handshake(QUICTransErrorCode code); }; diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index f489e302cc2..21eef3979c9 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -25,6 +25,7 @@ #include "QUICKeyGenerator.h" #include "QUICTypes.h" +#include "QUICTransportParameters.h" class QUICHandshakeProtocol; @@ -71,15 +72,20 @@ class QUICHandshakeProtocol QUICHandshakeProtocol(){}; virtual ~QUICHandshakeProtocol(){}; - 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; - virtual bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const = 0; - virtual int initialize_key_materials(QUICConnectionId cid) = 0; - virtual int update_key_materials() = 0; - virtual const char *negotiated_cipher_suite() const = 0; - virtual void negotiated_application_name(const uint8_t **name, unsigned int *len) const = 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; + virtual bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const = 0; + virtual int initialize_key_materials(QUICConnectionId cid) = 0; + virtual int update_key_materials() = 0; + virtual const char *negotiated_cipher_suite() const = 0; + virtual void negotiated_application_name(const uint8_t **name, unsigned int *len) const = 0; + virtual std::shared_ptr local_transport_parameters() = 0; + virtual std::shared_ptr remote_transport_parameters() = 0; + virtual void set_local_transport_parameters(std::shared_ptr tp) = 0; + virtual void set_remote_transport_parameters(std::shared_ptr tp) = 0; + virtual bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; virtual bool decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher, size_t cipher_len, diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 23dbfab4c37..363fca2e9a3 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -37,6 +37,30 @@ QUICTLS::ssl_handle() return this->_ssl; } +std::shared_ptr +QUICTLS::local_transport_parameters() +{ + return this->_local_transport_parameters; +} + +std::shared_ptr +QUICTLS::remote_transport_parameters() +{ + return this->_remote_transport_parameters; +} + +void +QUICTLS::set_local_transport_parameters(std::shared_ptr tp) +{ + this->_local_transport_parameters = tp; +} + +void +QUICTLS::set_remote_transport_parameters(std::shared_ptr tp) +{ + this->_remote_transport_parameters = tp; +} + QUICTLS::~QUICTLS() { SSL_free(this->_ssl); diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index d7f2ec1d44f..9ac6cc178fa 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -51,9 +51,16 @@ class QUICTLS : public QUICHandshakeProtocol static QUICEncryptionLevel get_encryption_level(int msg_type); static uint16_t convert_to_quic_trans_error_code(uint8_t alert); + std::shared_ptr local_transport_parameters() override; + std::shared_ptr remote_transport_parameters() override; + void set_local_transport_parameters(std::shared_ptr tp) override; + void set_remote_transport_parameters(std::shared_ptr tp) override; + // FIXME Should not exist SSL *ssl_handle(); + // QUICHandshakeProtocol + int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) override; void reset() override; bool is_handshake_finished() const override; @@ -105,4 +112,7 @@ class QUICTLS : public QUICHandshakeProtocol bool _early_data = true; QUICEncryptionLevel _current_level = QUICEncryptionLevel::INITIAL; HandshakeState _state = HandshakeState::PROCESSING; + + std::shared_ptr _local_transport_parameters = nullptr; + std::shared_ptr _remote_transport_parameters = nullptr; }; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index bdeda68efbc..ba7d278f151 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -20,6 +20,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "QUICGlobals.h" #include "QUICTLS.h" #include @@ -228,6 +229,7 @@ QUICTLS::QUICTLS(SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx) this->_client_pp = new QUICPacketProtection(); this->_server_pp = new QUICPacketProtection(); + SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_tls_index, this); SSL_set_key_callback(this->_ssl, key_cb, this); } diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index a1db90aad44..de7382f714d 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -29,6 +29,7 @@ #include "QUICConnection.h" #include "QUICHandshake.h" #include "QUICDebugNames.h" +#include "QUICTLS.h" static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; static constexpr char tag[] = "quic_handshake"; @@ -481,9 +482,9 @@ int QUICTransportParametersHandler::add(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char **out, size_t *outlen, X509 *x, size_t chainidx, int *al, void *add_arg) { - QUICHandshake *hs = static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_hs_index)); - *out = reinterpret_cast(ats_malloc(TRANSPORT_PARAMETERS_MAXIMUM_SIZE)); - hs->local_transport_parameters()->store(const_cast(*out), reinterpret_cast(outlen)); + QUICTLS *qtls = static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_tls_index)); + *out = reinterpret_cast(ats_malloc(TRANSPORT_PARAMETERS_MAXIMUM_SIZE)); + qtls->local_transport_parameters()->store(const_cast(*out), reinterpret_cast(outlen)); return 1; } @@ -498,14 +499,14 @@ int QUICTransportParametersHandler::parse(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *in, size_t inlen, X509 *x, size_t chainidx, int *al, void *parse_arg) { - QUICHandshake *hs = static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_hs_index)); + QUICTLS *qtls = static_cast(SSL_get_ex_data(s, QUIC::ssl_quic_tls_index)); switch (context) { case SSL_EXT_CLIENT_HELLO: - hs->set_transport_parameters(std::make_shared(in, inlen)); + qtls->set_remote_transport_parameters(std::make_shared(in, inlen)); break; case SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS: - hs->set_transport_parameters(std::make_shared(in, inlen)); + qtls->set_remote_transport_parameters(std::make_shared(in, inlen)); break; default: // Do nothing From 38a177115e38e83b25c03274025487a2ac47dcec Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 11 Sep 2018 12:20:49 +0900 Subject: [PATCH 0806/1313] [draft-13] Add QUICTransportParameterId::DISABLE_MIGRATION --- iocore/net/quic/QUICDebugNames.cc | 2 + iocore/net/quic/QUICTransportParameters.cc | 14 ++ iocore/net/quic/QUICTransportParameters.h | 4 +- .../quic/test/test_QUICTransportParameters.cc | 133 ++++++++++++++---- 4 files changed, 127 insertions(+), 26 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 44f13ebb8bc..567266b7239 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -191,6 +191,8 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) return "ACK_DELAY_EXPONENT"; case QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS: return "INITIAL_MAX_UNI_STREAMS"; + case QUICTransportParameterId::DISABLE_MIGRATION: + return "DISABLE_MIGRATION"; default: return "UNKNOWN"; } diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index de7382f714d..6797ab654e7 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -201,6 +201,12 @@ QUICTransportParameters::_validate_parameters() const } } + if ((ite = this->_parameters.find(QUICTransportParameterId::DISABLE_MIGRATION)) != this->_parameters.end()) { + if (ite->second->len() != 0) { + return -6; + } + } + return 0; } @@ -253,6 +259,14 @@ QUICTransportParameters::getAsUInt32(QUICTransportParameterId tpid) const } } +bool +QUICTransportParameters::contains(QUICTransportParameterId id) const +{ + // Use std::map::contains when C++20 is supported + auto p = this->_parameters.find(id); + return (p != this->_parameters.end()); +} + void QUICTransportParameters::set(QUICTransportParameterId id, const uint8_t *value, uint16_t value_len) { diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 577478ede4c..aef3b69c8aa 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -42,7 +42,8 @@ class QUICTransportParameterId MAX_PACKET_SIZE, STATELESS_RESET_TOKEN, ACK_DELAY_EXPONENT, - INITIAL_MAX_UNI_STREAMS + INITIAL_MAX_UNI_STREAMS, + DISABLE_MIGRATION, }; explicit operator bool() const { return true; } @@ -78,6 +79,7 @@ class QUICTransportParameters uint8_t getAsUInt8(QUICTransportParameterId id) const; uint16_t getAsUInt16(QUICTransportParameterId id) const; uint32_t getAsUInt32(QUICTransportParameterId id) const; + bool contains(QUICTransportParameterId id) const; void set(QUICTransportParameterId id, const uint8_t *value, uint16_t value_len); void set(QUICTransportParameterId id, uint16_t value); diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index 9dff13cb5fa..4053ed25643 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -174,6 +174,49 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") data = params_in_ee.getAsBytes(QUICTransportParameterId::STATELESS_RESET_TOKEN, len); CHECK(len == 16); CHECK(memcmp(data, buf + 37, 16) == 0); + + CHECK(!params_in_ee.contains(QUICTransportParameterId::DISABLE_MIGRATION)); + } + + SECTION("OK case - zero length value") + { + uint8_t buf[] = { + 0x01, 0x02, 0x03, 0x04, // negotiated version + 0x04, // size of supported versions + 0x01, 0x02, 0x03, 0x04, // + 0x00, 0x1a, // size of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value + 0x00, 0x01, // parameter id + 0x00, 0x04, // length of value + 0x12, 0x34, 0x56, 0x78, // value + 0x00, 0x03, // parameter id + 0x00, 0x02, // length of value + 0x01, 0x23, // value + 0x00, 0x09, // parameter id + 0x00, 0x00, // length of value + }; + + QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf)); + CHECK(params_in_ee.is_valid()); + + uint16_t len = 0; + const uint8_t *data = nullptr; + + data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); + + data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_DATA, len); + CHECK(len == 4); + CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); + + data = params_in_ee.getAsBytes(QUICTransportParameterId::IDLE_TIMEOUT, len); + CHECK(len == 2); + CHECK(memcmp(data, "\x01\x23", 2) == 0); + + CHECK(params_in_ee.contains(QUICTransportParameterId::DISABLE_MIGRATION)); } SECTION("Duplicate parameters") @@ -198,34 +241,74 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") { - uint8_t buf[65536]; - uint16_t len; + SECTION("OK cases") + { + uint8_t buf[65536]; + uint16_t len; - uint8_t expected[] = { - 0x01, 0x02, 0x03, 0x04, // negotiated version - 0x08, // size of supported versions - 0x01, 0x02, 0x03, 0x04, // version 1 - 0x05, 0x06, 0x07, 0x08, // version 2 - 0x00, 0x0e, // size of parameters - 0x00, 0x00, // parameter id - 0x00, 0x04, // length of value - 0x11, 0x22, 0x33, 0x44, // value - 0x00, 0x05, // parameter id - 0x00, 0x02, // length of value - 0xab, 0xcd, // value - }; + uint8_t expected[] = { + 0x01, 0x02, 0x03, 0x04, // negotiated version + 0x08, // size of supported versions + 0x01, 0x02, 0x03, 0x04, // version 1 + 0x05, 0x06, 0x07, 0x08, // version 2 + 0x00, 0x0e, // size of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value + 0x00, 0x05, // parameter id + 0x00, 0x02, // length of value + 0xab, 0xcd, // value + }; - QUICTransportParametersInEncryptedExtensions params_in_ee(0x01020304); + QUICTransportParametersInEncryptedExtensions params_in_ee(0x01020304); - uint32_t max_stream_data = 0x11223344; - params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, max_stream_data); + uint32_t max_stream_data = 0x11223344; + params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, max_stream_data); - uint16_t max_packet_size = 0xabcd; - params_in_ee.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size); + uint16_t max_packet_size = 0xabcd; + params_in_ee.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size); - params_in_ee.add_version(0x01020304); - params_in_ee.add_version(0x05060708); - params_in_ee.store(buf, &len); - CHECK(len == 29); - CHECK(memcmp(buf, expected, len) == 0); + params_in_ee.add_version(0x01020304); + params_in_ee.add_version(0x05060708); + params_in_ee.store(buf, &len); + CHECK(len == 29); + CHECK(memcmp(buf, expected, len) == 0); + } + + SECTION("OK cases - include zero length value") + { + uint8_t buf[65536]; + uint16_t len; + + uint8_t expected[] = { + 0x01, 0x02, 0x03, 0x04, // negotiated version + 0x08, // size of supported versions + 0x01, 0x02, 0x03, 0x04, // version 1 + 0x05, 0x06, 0x07, 0x08, // version 2 + 0x00, 0x12, // size of parameters + 0x00, 0x00, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value + 0x00, 0x05, // parameter id + 0x00, 0x02, // length of value + 0xab, 0xcd, // value + 0x00, 0x09, // parameter id + 0x00, 0x00, // length of value + }; + + QUICTransportParametersInEncryptedExtensions params_in_ee(0x01020304); + + uint32_t max_stream_data = 0x11223344; + params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, max_stream_data); + + uint16_t max_packet_size = 0xabcd; + params_in_ee.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size); + params_in_ee.set(QUICTransportParameterId::DISABLE_MIGRATION, nullptr, 0); + + params_in_ee.add_version(0x01020304); + params_in_ee.add_version(0x05060708); + params_in_ee.store(buf, &len); + CHECK(len == 33); + CHECK(memcmp(buf, expected, len) == 0); + } } From b2a9a9b057ced8c7fdb5d7900dc088e6fdf04677 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Sep 2018 12:38:52 +0900 Subject: [PATCH 0807/1313] Fix a compile error on test_qpack --- proxy/hq/test/test_QPACK.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proxy/hq/test/test_QPACK.cc b/proxy/hq/test/test_QPACK.cc index 2e1e91c1865..3fe6bc0b703 100644 --- a/proxy/hq/test/test_QPACK.cc +++ b/proxy/hq/test/test_QPACK.cc @@ -62,7 +62,9 @@ class QUICApplicationDriver class TestQUICStream : public QUICStream { public: - TestQUICStream(QUICStreamId sid) : QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), sid) {} + TestQUICStream(QUICStreamId sid) : QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), sid, 65536, 65536) + { + } void write(const uint8_t *buf, size_t buf_len, QUICOffset offset, bool last) From 7c089c1906827eae2b331267e48380098922456c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Sep 2018 15:08:53 +0900 Subject: [PATCH 0808/1313] Update mock class for QUIC --- iocore/net/quic/Mock.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index dff1afabf13..9c7efeb1eb5 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -615,6 +615,28 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol { return; } + + std::shared_ptr + local_transport_parameters() override + { + return nullptr; + } + + std::shared_ptr + remote_transport_parameters() override + { + return nullptr; + } + + void + set_local_transport_parameters(std::shared_ptr tp) override + { + } + + void + set_remote_transport_parameters(std::shared_ptr tp) override + { + } }; class MockContinuation : public Continuation From 18b507739d251f3319352c9c16a5cab58d91fad7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Sep 2018 15:09:27 +0900 Subject: [PATCH 0809/1313] Remove dependency for QUICTLS from QUICHandshake --- iocore/net/P_QUICNetVConnection.h | 2 ++ iocore/net/QUICNetVConnection.cc | 16 +++++++++++++--- iocore/net/quic/QUICHandshake.cc | 7 ------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 2fc8c631e04..9b18fe84a2b 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -345,6 +345,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _rerandomize_original_cid(); bool _is_src_addr_verified(); + QUICHandshakeProtocol *_setup_handshake_protocol(SSL_CTX *ctx); + QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet(); QUICStatelessResetToken _reset_token; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 63a41486b25..55a347b5b0b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -35,7 +35,7 @@ #include "QUICTLS.h" #include "QUICStats.h" -#include "QUICConfig.h" +#include "QUICGlobals.h" #include "QUICDebugNames.h" #include "QUICEvents.h" #include "QUICConfig.h" @@ -205,10 +205,10 @@ QUICNetVConnection::start() // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not if (this->direction() == NET_VCONNECTION_IN) { this->_reset_token.generate(this->_quic_connection_id, params->server_id()); - this->_hs_protocol = new QUICTLS(params->server_ssl_ctx(), this->direction()); + this->_hs_protocol = this->_setup_handshake_protocol(params->server_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol, this->_reset_token, params->stateless_retry()); } else { - this->_hs_protocol = new QUICTLS(params->client_ssl_ctx(), this->direction()); + this->_hs_protocol = this->_setup_handshake_protocol(params->client_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol); this->_handshake_handler->start(&this->_packet_factory, params->vn_exercise_enabled()); this->_handshake_handler->do_handshake(); @@ -1879,3 +1879,13 @@ QUICNetVConnection::_is_src_addr_verified() { return this->_src_addr_verified; } + +QUICHandshakeProtocol * +QUICNetVConnection::_setup_handshake_protocol(SSL_CTX *ctx) +{ + // Initialize handshake protocol specific stuff + // For QUICv1 TLS is the only option + QUICTLS *tls = new QUICTLS(ctx, this->direction()); + SSL_set_ex_data(tls->ssl_handle(), QUIC::ssl_quic_qc_index, static_cast(this)); + return tls; +} diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 645ef6ed95f..5f340ac2ce5 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -25,7 +25,6 @@ #include -#include "QUICTLS.h" #include "QUICEvents.h" #include "QUICGlobals.h" #include "QUICVersionNegotiator.h" @@ -93,12 +92,6 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, QUICHandshakeProtocol *hsp, QUI _reset_token(token), _stateless_retry(stateless_retry) { - // FIXME These should be done in another way - if (dynamic_cast(hsp)) { - SSL *ssl = static_cast(hsp)->ssl_handle(); - SSL_set_ex_data(ssl, QUIC::ssl_quic_qc_index, qc); - } - this->_hs_protocol->initialize_key_materials(this->_qc->original_connection_id()); if (this->_qc->direction() == NET_VCONNECTION_OUT) { From 57207119b1cf51b3118462a42402149b1fa8ce4b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Sep 2018 15:18:13 +0900 Subject: [PATCH 0810/1313] Remove unused declarations --- iocore/net/quic/QUICStream.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 70cc6f2c49d..1a0bbc96ffc 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -36,10 +36,6 @@ #include "QUICLossDetector.h" #include "QUICConnection.h" -class QUICNetVConnection; -class QUICStreamState; -class QUICStreamManager; - /** * @brief QUIC Stream * TODO: This is similar to Http2Stream. Need to think some integration. From 244bf34d95ea01c0a5d303a09c2274e08ae469ee Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Sep 2018 15:22:46 +0900 Subject: [PATCH 0811/1313] Remove unused header inclusions --- iocore/net/quic/QUICStream.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 1a0bbc96ffc..a88f660f67a 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -24,7 +24,6 @@ #pragma once #include "ts/List.h" -#include "ts/PriorityQueue.h" #include "I_VConnection.h" @@ -33,7 +32,6 @@ #include "QUICFlowController.h" #include "QUICIncomingFrameBuffer.h" #include "QUICFrameGenerator.h" -#include "QUICLossDetector.h" #include "QUICConnection.h" /** From fdd6f7e9ddd78d6a9e3ccb71330123d7124bef17 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Sep 2018 15:29:39 +0900 Subject: [PATCH 0812/1313] Rename QUICStream::_info to QUICStream::_connection_info --- iocore/net/quic/QUICApplication.cc | 5 +++-- iocore/net/quic/QUICStream.cc | 20 ++++++++++---------- iocore/net/quic/QUICStream.h | 14 +++++++------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index f4d09a40c97..b0904c73e72 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -27,8 +27,9 @@ static constexpr char tag_stream_io[] = "quic_stream_io"; static constexpr char tag_app[] = "quic_app"; -#define QUICStreamIODebug(fmt, ...) \ - Debug(tag_stream_io, "[%s] [%" PRIu64 "] " fmt, this->_stream->info()->cids().data(), this->_stream->id(), ##__VA_ARGS__) +#define QUICStreamIODebug(fmt, ...) \ + Debug(tag_stream_io, "[%s] [%" PRIu64 "] " fmt, this->_stream->connection_info()->cids().data(), this->_stream->id(), \ + ##__VA_ARGS__) // // QUICStreamIO diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 9b69c174eaf..32da6535b07 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -28,25 +28,25 @@ #include "QUICStreamManager.h" #include "QUICDebugNames.h" -#define QUICStreamDebug(fmt, ...) \ - Debug("quic_stream", "[%s] [%" PRIx64 "] [%s] " fmt, this->_info->cids().data(), this->_id, \ +#define QUICStreamDebug(fmt, ...) \ + Debug("quic_stream", "[%s] [%" PRIx64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) -#define QUICVStreamDebug(fmt, ...) \ - Debug("v_quic_stream", "[%s] [%" PRIx64 "] [%s] " fmt, this->_info->cids().data(), this->_id, \ +#define QUICVStreamDebug(fmt, ...) \ + Debug("v_quic_stream", "[%s] [%" PRIx64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) -#define QUICStreamFCDebug(fmt, ...) \ - Debug("quic_flow_ctrl", "[%s] [%" PRIx64 "] [%s] " fmt, this->_info->cids().data(), this->_id, \ +#define QUICStreamFCDebug(fmt, ...) \ + Debug("quic_flow_ctrl", "[%s] [%" PRIx64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; -QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICStreamId sid, +QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data) : VConnection(nullptr), - _info(info), + _connection_info(cinfo), _id(sid), _remote_flow_controller(send_max_stream_data, _id), _local_flow_controller(rtt_provider, recv_max_stream_data, _id), @@ -83,9 +83,9 @@ QUICStream::id() const } const QUICConnectionInfoProvider * -QUICStream::info() const +QUICStream::connection_info() const { - return this->_info; + return this->_connection_info; } QUICOffset diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index a88f660f67a..aea4f6a5256 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -49,7 +49,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator _state(nullptr, nullptr, nullptr, nullptr) { } - QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICStreamId sid, uint64_t recv_max_stream_data, + QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data); ~QUICStream(); // void start(); @@ -57,7 +57,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator int state_stream_closed(int event, void *data); QUICStreamId id() const; - const QUICConnectionInfoProvider *info() const; + const QUICConnectionInfoProvider *connection_info() const; QUICOffset final_offset() const; QUICStreamFrameUPtr generete_frame(uint16_t flow_control_credit, uint16_t maximum_frame_size); @@ -94,11 +94,11 @@ class QUICStream : public VConnection, public QUICFrameGenerator void _write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin); - QUICStreamErrorUPtr _reset_reason = nullptr; - QUICConnectionInfoProvider *_info = nullptr; - QUICStreamId _id = 0; - QUICOffset _send_offset = 0; - QUICOffset _reordered_bytes = 0; + QUICStreamErrorUPtr _reset_reason = nullptr; + QUICConnectionInfoProvider *_connection_info = nullptr; + QUICStreamId _id = 0; + QUICOffset _send_offset = 0; + QUICOffset _reordered_bytes = 0; QUICRemoteStreamFlowController _remote_flow_controller; QUICLocalStreamFlowController _local_flow_controller; From 4fa51aabea268a2d39e6e6dd992e0b8fff52e4b9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Sep 2018 15:36:00 +0900 Subject: [PATCH 0813/1313] Remove unused function declarations from QUICStream --- iocore/net/quic/QUICStream.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index aea4f6a5256..07b29c6385b 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -52,14 +52,13 @@ class QUICStream : public VConnection, public QUICFrameGenerator QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data); ~QUICStream(); - // void start(); + int state_stream_open(int event, void *data); int state_stream_closed(int event, void *data); QUICStreamId id() const; const QUICConnectionInfoProvider *connection_info() const; QUICOffset final_offset() const; - QUICStreamFrameUPtr generete_frame(uint16_t flow_control_credit, uint16_t maximum_frame_size); // Implement VConnection Interface. VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; From ad7f44d83823bf75127fbcbda63172178ce0b0e6 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 11 Sep 2018 15:31:46 +0900 Subject: [PATCH 0814/1313] Fix setting Transport Parameters on client side --- iocore/net/quic/QUICHandshake.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 5f340ac2ce5..7865bf45550 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -219,6 +219,12 @@ bool QUICHandshake::check_remote_transport_parameters() { auto tp = this->_hs_protocol->remote_transport_parameters(); + + if (tp == nullptr) { + // nothing to check + return true; + } + if (std::dynamic_pointer_cast(tp)) { return this->_check_remote_transport_parameters(std::static_pointer_cast(tp)); } else { @@ -369,8 +375,8 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve // MAYs tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_in()); tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_in()); - this->_local_transport_parameters = std::shared_ptr(tp); + this->_local_transport_parameters = std::shared_ptr(tp); this->_hs_protocol->set_local_transport_parameters(this->_local_transport_parameters); } @@ -390,6 +396,7 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_out()); tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_out()); + this->_local_transport_parameters = std::shared_ptr(tp); this->_hs_protocol->set_local_transport_parameters(std::unique_ptr(tp)); } From 9867db720f5473287e240cec6f9bc7e1055e0597 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 11 Sep 2018 15:59:59 +0900 Subject: [PATCH 0815/1313] Cleanup: Remove local_max_stream_data for stream 0 --- iocore/net/quic/QUICStreamManager.cc | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index b6e8fe09f95..aa5d38abd4a 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -274,15 +274,11 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) return nullptr; } - uint64_t local_max_stream_data = 0; - uint64_t remote_max_stream_data = 0; - if (this->_local_tp) { - local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA), - remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); - } else { - QUICConfig::scoped_config params; - local_max_stream_data = params->initial_max_stream_data(); - } + ink_assert(this->_local_tp); + ink_assert(this->_remote_tp); + + uint64_t local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); + uint64_t remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); // TODO Free the stream somewhere stream = THREAD_ALLOC(quicStreamAllocator, this_ethread()); From 0bd40e8ac1d6490469520fcec68973c438eb8a32 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Sep 2018 17:01:04 +0900 Subject: [PATCH 0816/1313] Move encrypt_pn/decrypt_pn impls to QUICPacketNumberEncryptor --- iocore/net/quic/Makefile.am | 3 + iocore/net/quic/Mock.h | 32 +++--- iocore/net/quic/QUICHandshakeProtocol.cc | 31 +++++- iocore/net/quic/QUICHandshakeProtocol.h | 41 +++---- .../net/quic/QUICHandshakeProtocol_openssl.cc | 72 +++++++++++++ iocore/net/quic/QUICTLS.cc | 52 +++------ iocore/net/quic/QUICTLS.h | 13 +-- iocore/net/quic/QUICTLS_openssl.cc | 100 +++++------------- 8 files changed, 188 insertions(+), 156 deletions(-) create mode 100644 iocore/net/quic/QUICHandshakeProtocol_openssl.cc diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 4b53388bd59..655713d3798 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -34,9 +34,11 @@ AM_CPPFLAGS += \ noinst_LIBRARIES = libquic.a if OPENSSL_IS_BORINGSSL +QUICHSProtocol_impl = QUICHandshakeProtocol_boringssl.cc QUICTLS_impl = QUICTLS_boringssl.cc QUICKeyGenerator_impl = QUICKeyGenerator_boringssl.cc else +QUICHSProtocol_impl = QUICHandshakeProtocol_openssl.cc QUICTLS_impl = QUICTLS_openssl.cc QUICKeyGenerator_impl = QUICKeyGenerator_openssl.cc endif @@ -57,6 +59,7 @@ libquic_a_SOURCES = \ QUICStream.cc \ QUICHandshake.cc \ QUICHandshakeProtocol.cc \ + $(QUICHSProtocol_impl) \ QUICTLS.cc \ $(QUICTLS_impl) \ QUICKeyGenerator.cc \ diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 9c7efeb1eb5..3edf6d73285 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -574,33 +574,37 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol *len = 2; } - bool - encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, - const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override + const KeyMaterial * + key_material_for_encryption(QUICKeyPhase phase) const override { - memcpy(cipher, plain, plain_len); - return true; + return nullptr; } - bool - decrypt(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, QUICKeyPhase phase) const override + const KeyMaterial * + key_material_for_decryption(QUICKeyPhase phase) const override { - memcpy(plain, cipher, cipher_len); - return true; + return nullptr; + } + + const QUIC_EVP_CIPHER * + cipher_for_pne(QUICKeyPhase phase) const override + { + return nullptr; } bool - encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, - const uint8_t *sample, QUICKeyPhase phase) const override + encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, + const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override { + memcpy(cipher, plain, plain_len); return true; } bool - decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, - const uint8_t *sample, QUICKeyPhase phase) const override + decrypt(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, QUICKeyPhase phase) const override { + memcpy(plain, cipher, cipher_len); return true; } diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index 84028eaaca9..5f1a34750c6 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -22,6 +22,7 @@ */ #include "QUICGlobals.h" #include "QUICHandshakeProtocol.h" +#include "QUICDebugNames.h" #include "ts/Diags.h" #include "QUICTypes.h" @@ -59,16 +60,38 @@ bool QUICPacketNumberProtector::protect(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const { - // FIXME HandshakeProtocol shouldn't do this. The logic should be moved from there to here. - return this->_hs_protocol->encrypt_pn(protected_pn, protected_pn_len, unprotected_pn, unprotected_pn_len, sample, phase); + const KeyMaterial *km = this->_hs_protocol->key_material_for_encryption(phase); + if (!km) { + Debug("quic_pne", "Failed to encrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); + return false; + } + + const QUIC_EVP_CIPHER *aead = this->_hs_protocol->cipher_for_pne(phase); + + bool ret = this->_encrypt_pn(protected_pn, protected_pn_len, unprotected_pn, unprotected_pn_len, sample, *km, aead); + if (!ret) { + Debug("quic_pne", "Failed to encrypt a packet number"); + } + return ret; } bool QUICPacketNumberProtector::unprotect(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const { - // FIXME HandshakeProtocol shouldn't do this. The logic should be moved from there to here. - return this->_hs_protocol->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, phase); + const KeyMaterial *km = this->_hs_protocol->key_material_for_decryption(phase); + if (!km) { + Debug("quic_pne", "Failed to decrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); + return false; + } + + const QUIC_EVP_CIPHER *aead = this->_hs_protocol->cipher_for_pne(phase); + + bool ret = this->_decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, *km, aead); + if (!ret) { + Debug("quic_pne", "Failed to decrypt a packet number"); + } + return ret; } void diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 21eef3979c9..cce0eda0f9f 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -56,7 +56,12 @@ class QUICPacketNumberProtector void set_hs_protocol(QUICHandshakeProtocol *hs_protocol); private: - QUICHandshakeProtocol *_hs_protocol = nullptr; + const QUICHandshakeProtocol *_hs_protocol = nullptr; + + bool _encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, + const uint8_t *sample, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead) const; + bool _decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, + const uint8_t *sample, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead) const; }; struct QUICHandshakeMsgs { @@ -72,28 +77,28 @@ class QUICHandshakeProtocol QUICHandshakeProtocol(){}; virtual ~QUICHandshakeProtocol(){}; - 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; - virtual bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const = 0; - virtual int initialize_key_materials(QUICConnectionId cid) = 0; - virtual int update_key_materials() = 0; - virtual const char *negotiated_cipher_suite() const = 0; - virtual void negotiated_application_name(const uint8_t **name, unsigned int *len) const = 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; + virtual bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const = 0; + virtual int initialize_key_materials(QUICConnectionId cid) = 0; + virtual int update_key_materials() = 0; + virtual const char *negotiated_cipher_suite() const = 0; + virtual void negotiated_application_name(const uint8_t **name, unsigned int *len) const = 0; + virtual const KeyMaterial *key_material_for_encryption(QUICKeyPhase phase) const = 0; + virtual const KeyMaterial *key_material_for_decryption(QUICKeyPhase phase) const = 0; + virtual const QUIC_EVP_CIPHER *cipher_for_pne(QUICKeyPhase phase) const = 0; + virtual std::shared_ptr local_transport_parameters() = 0; virtual std::shared_ptr remote_transport_parameters() = 0; virtual void set_local_transport_parameters(std::shared_ptr tp) = 0; virtual void set_remote_transport_parameters(std::shared_ptr tp) = 0; virtual bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; virtual bool decrypt(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, QUICKeyPhase phase) const = 0; - virtual bool encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, - uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const = 0; - virtual bool decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, - uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const = 0; - virtual QUICEncryptionLevel current_encryption_level() const = 0; - virtual void abort_handshake() = 0; + uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; + virtual QUICEncryptionLevel current_encryption_level() const = 0; + virtual void abort_handshake() = 0; }; diff --git a/iocore/net/quic/QUICHandshakeProtocol_openssl.cc b/iocore/net/quic/QUICHandshakeProtocol_openssl.cc new file mode 100644 index 00000000000..77f82c51dea --- /dev/null +++ b/iocore/net/quic/QUICHandshakeProtocol_openssl.cc @@ -0,0 +1,72 @@ +/** @file + * + * QUIC Handshake Protocol (OpenSSL specific code) + * + * @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 "QUICHandshakeProtocol.h" + +bool +QUICPacketNumberProtector::_encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, + uint8_t unprotected_pn_len, const uint8_t *sample, const KeyMaterial &km, + const EVP_CIPHER *aead) const +{ + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + int len = 0; + + if (!ctx || !EVP_EncryptInit_ex(ctx, aead, nullptr, km.pn, sample)) { + return false; + } + if (!EVP_EncryptUpdate(ctx, protected_pn, &len, unprotected_pn, unprotected_pn_len)) { + return false; + } + protected_pn_len = len; + if (!EVP_EncryptFinal_ex(ctx, protected_pn + len, &len)) { + return false; + } + protected_pn_len += len; + EVP_CIPHER_CTX_free(ctx); + + return true; +} + +bool +QUICPacketNumberProtector::_decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, + uint8_t protected_pn_len, const uint8_t *sample, const KeyMaterial &km, + const EVP_CIPHER *aead) const +{ + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + int len = 0; + + if (!ctx || !EVP_DecryptInit_ex(ctx, aead, nullptr, km.pn, sample)) { + return false; + } + if (!EVP_DecryptUpdate(ctx, unprotected_pn, &len, protected_pn, protected_pn_len)) { + return false; + } + unprotected_pn_len = len; + if (!EVP_DecryptFinal_ex(ctx, unprotected_pn, &len)) { + return false; + } + unprotected_pn_len += len; + EVP_CIPHER_CTX_free(ctx); + + return true; +} diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 363fca2e9a3..0499d1fc437 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -158,6 +158,18 @@ QUICTLS::update_key_materials() return 1; } +const KeyMaterial * +QUICTLS::key_material_for_encryption(QUICKeyPhase phase) const +{ + return this->_get_km(phase, true); +} + +const KeyMaterial * +QUICTLS::key_material_for_decryption(QUICKeyPhase phase) const +{ + return this->_get_km(phase, false); +} + const char * QUICTLS::negotiated_cipher_suite() const { @@ -199,7 +211,7 @@ QUICTLS::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, con uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const { size_t tag_len = this->_get_aead_tag_len(phase); - const KeyMaterial *km = this->_get_km(phase, true); + const KeyMaterial *km = this->key_material_for_encryption(phase); if (!km) { Debug(tag, "Failed to encrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; @@ -218,7 +230,7 @@ QUICTLS::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const { size_t tag_len = this->_get_aead_tag_len(phase); - const KeyMaterial *km = this->_get_km(phase, false); + const KeyMaterial *km = this->key_material_for_decryption(phase); if (!km) { Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; @@ -231,42 +243,6 @@ QUICTLS::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const return ret; } -bool -QUICTLS::encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, - const uint8_t *sample, QUICKeyPhase phase) const -{ - const KeyMaterial *km = this->_get_km(phase, true); - if (!km) { - Debug(tag, "Failed to encrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); - return false; - } - - const QUIC_EVP_CIPHER *aead = this->_get_evp_aead_for_pne(phase); - bool ret = this->_encrypt_pn(protected_pn, protected_pn_len, unprotected_pn, unprotected_pn_len, sample, *km, aead); - if (!ret) { - Debug(tag, "Failed to encrypt a packet number"); - } - return ret; -} - -bool -QUICTLS::decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, - const uint8_t *sample, QUICKeyPhase phase) const -{ - const KeyMaterial *km = this->_get_km(phase, false); - if (!km) { - Debug(tag, "Failed to decrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); - return false; - } - - const QUIC_EVP_CIPHER *aead = this->_get_evp_aead_for_pne(phase); - bool ret = this->_decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, *km, aead); - if (!ret) { - Debug(tag, "Failed to decrypt a packet number"); - } - return ret; -} - /** * Example iv_len = 12 * diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 9ac6cc178fa..001c08ad777 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -71,14 +71,14 @@ class QUICTLS : public QUICHandshakeProtocol void update_key_materials_on_key_cb(std::unique_ptr km, int name); const char *negotiated_cipher_suite() const override; void negotiated_application_name(const uint8_t **name, unsigned int *len) const override; + const KeyMaterial *key_material_for_encryption(QUICKeyPhase phase) const override; + const KeyMaterial *key_material_for_decryption(QUICKeyPhase phase) const override; + const QUIC_EVP_CIPHER *cipher_for_pne(QUICKeyPhase phase) const override; + bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override; bool decrypt(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, QUICKeyPhase phase) const override; - bool encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, - const uint8_t *sample, QUICKeyPhase phase) const override; - bool decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, - const uint8_t *sample, QUICKeyPhase phase) const override; QUICEncryptionLevel current_encryption_level() const override; void abort_handshake() override; @@ -87,7 +87,6 @@ class QUICTLS : public QUICHandshakeProtocol QUICKeyGenerator _keygen_for_server = QUICKeyGenerator(QUICKeyGenerator::Context::SERVER); void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; const QUIC_EVP_CIPHER *_get_evp_aead(QUICKeyPhase phase) const; - const QUIC_EVP_CIPHER *_get_evp_aead_for_pne(QUICKeyPhase phase) const; size_t _get_aead_tag_len(QUICKeyPhase phase) const; const KeyMaterial *_get_km(QUICKeyPhase phase, bool for_encryption) const; @@ -96,10 +95,6 @@ class QUICTLS : public QUICHandshakeProtocol size_t tag_len) const; bool _decrypt(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 KeyMaterial &km, const QUIC_EVP_CIPHER *aead, size_t tag_len) const; - bool _encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, - const uint8_t *sample, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead) const; - bool _decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, - const uint8_t *sample, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead) const; int _read_early_data(); void _generate_0rtt_key(); void _update_encryption_level(QUICEncryptionLevel level); diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index ba7d278f151..9fffe46ebb3 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -316,39 +316,24 @@ QUICTLS::reset() SSL_clear(this->_ssl); } -int -QUICTLS::_read_early_data() -{ - uint8_t early_data[8]; - size_t early_data_len = 0; - int ret = 0; - - do { - ERR_clear_error(); - ret = SSL_read_early_data(this->_ssl, early_data, sizeof(early_data), &early_data_len); - } while (ret == SSL_READ_EARLY_DATA_SUCCESS); - - return ret == SSL_READ_EARLY_DATA_FINISH ? 1 : 0; -} - const EVP_CIPHER * -QUICTLS::_get_evp_aead(QUICKeyPhase phase) const +QUICTLS::cipher_for_pne(QUICKeyPhase phase) const { if (phase == QUICKeyPhase::INITIAL) { - return EVP_aes_128_gcm(); + return EVP_aes_128_ctr(); } else { const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); if (cipher) { switch (SSL_CIPHER_get_id(cipher)) { case TLS1_3_CK_AES_128_GCM_SHA256: - return EVP_aes_128_gcm(); + return EVP_aes_128_ctr(); case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_aes_256_gcm(); + return EVP_aes_256_ctr(); case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_chacha20_poly1305(); + return EVP_chacha20(); case TLS1_3_CK_AES_128_CCM_SHA256: case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_aes_128_ccm(); + return EVP_aes_128_ctr(); default: ink_assert(false); return nullptr; @@ -360,24 +345,39 @@ QUICTLS::_get_evp_aead(QUICKeyPhase phase) const } } +int +QUICTLS::_read_early_data() +{ + uint8_t early_data[8]; + size_t early_data_len = 0; + int ret = 0; + + do { + ERR_clear_error(); + ret = SSL_read_early_data(this->_ssl, early_data, sizeof(early_data), &early_data_len); + } while (ret == SSL_READ_EARLY_DATA_SUCCESS); + + return ret == SSL_READ_EARLY_DATA_FINISH ? 1 : 0; +} + const EVP_CIPHER * -QUICTLS::_get_evp_aead_for_pne(QUICKeyPhase phase) const +QUICTLS::_get_evp_aead(QUICKeyPhase phase) const { if (phase == QUICKeyPhase::INITIAL) { - return EVP_aes_128_ctr(); + return EVP_aes_128_gcm(); } else { const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); if (cipher) { switch (SSL_CIPHER_get_id(cipher)) { case TLS1_3_CK_AES_128_GCM_SHA256: - return EVP_aes_128_ctr(); + return EVP_aes_128_gcm(); case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_aes_256_ctr(); + return EVP_aes_256_gcm(); case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_chacha20(); + return EVP_chacha20_poly1305(); case TLS1_3_CK_AES_128_CCM_SHA256: case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_aes_128_ctr(); + return EVP_aes_128_ccm(); default: ink_assert(false); return nullptr; @@ -521,49 +521,3 @@ QUICTLS::_decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const return false; } } - -bool -QUICTLS::_encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, - const uint8_t *sample, const KeyMaterial &km, const EVP_CIPHER *aead) const -{ - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); - int len = 0; - - if (!ctx || !EVP_EncryptInit_ex(ctx, aead, nullptr, km.pn, sample)) { - return false; - } - if (!EVP_EncryptUpdate(ctx, protected_pn, &len, unprotected_pn, unprotected_pn_len)) { - return false; - } - protected_pn_len = len; - if (!EVP_EncryptFinal_ex(ctx, protected_pn + len, &len)) { - return false; - } - protected_pn_len += len; - EVP_CIPHER_CTX_free(ctx); - - return true; -} - -bool -QUICTLS::_decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, - const uint8_t *sample, const KeyMaterial &km, const EVP_CIPHER *aead) const -{ - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); - int len = 0; - - if (!ctx || !EVP_DecryptInit_ex(ctx, aead, nullptr, km.pn, sample)) { - return false; - } - if (!EVP_DecryptUpdate(ctx, unprotected_pn, &len, protected_pn, protected_pn_len)) { - return false; - } - unprotected_pn_len = len; - if (!EVP_DecryptFinal_ex(ctx, unprotected_pn, &len)) { - return false; - } - unprotected_pn_len += len; - EVP_CIPHER_CTX_free(ctx); - - return true; -} From 00953882b5f29686bdcec69216413bdcd86e177e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Sep 2018 17:36:44 +0900 Subject: [PATCH 0817/1313] Add const qualifier to _hs_protocol --- iocore/net/quic/QUICHandshakeProtocol.cc | 2 +- iocore/net/quic/QUICHandshakeProtocol.h | 5 +++-- iocore/net/quic/QUICPacket.cc | 2 +- iocore/net/quic/QUICPacket.h | 10 +++++++--- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index 5f1a34750c6..9aec095839c 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -95,7 +95,7 @@ QUICPacketNumberProtector::unprotect(uint8_t *unprotected_pn, uint8_t &unprotect } void -QUICPacketNumberProtector::set_hs_protocol(QUICHandshakeProtocol *hs_protocol) +QUICPacketNumberProtector::set_hs_protocol(const QUICHandshakeProtocol *hs_protocol) { this->_hs_protocol = hs_protocol; } diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index cce0eda0f9f..32715930cbd 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -52,8 +52,9 @@ class QUICPacketNumberProtector bool unprotect(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const; - // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICPacketProtection instead. - void set_hs_protocol(QUICHandshakeProtocol *hs_protocol); + // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICCryptoInfoProvider or somethign instead. + // For now it receives a CONST pointer so PacketNubmerProtector cannot bother handshake. + void set_hs_protocol(const QUICHandshakeProtocol *hs_protocol); private: const QUICHandshakeProtocol *_hs_protocol = nullptr; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index bbda5c61296..054de41d3dd 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -1229,7 +1229,7 @@ QUICPacketFactory::set_version(QUICVersion negotiated_version) } void -QUICPacketFactory::set_hs_protocol(QUICHandshakeProtocol *hs_protocol) +QUICPacketFactory::set_hs_protocol(const QUICHandshakeProtocol *hs_protocol) { this->_hs_protocol = hs_protocol; } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index d4fb0fc4b0e..0d24d82aed0 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -401,12 +401,16 @@ class QUICPacketFactory QUICPacketUPtr create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable); void set_version(QUICVersion negotiated_version); - void set_hs_protocol(QUICHandshakeProtocol *hs_protocol); + + // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICCryptoInfoProvider or somethign instead. + // For now it receives a CONST pointer so PacketFactory cannot bother handshake. + void set_hs_protocol(const QUICHandshakeProtocol *hs_protocol); + bool is_ready_to_create_protected_packet(); private: - QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; - QUICHandshakeProtocol *_hs_protocol = nullptr; + QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; + const QUICHandshakeProtocol *_hs_protocol = nullptr; // Initial, 0/1-RTT, and Handshake QUICPacketNumberGenerator _packet_number_generator[3]; From d497bfa4bf2b50f651908dbfe966e582363dbfb7 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 10 Sep 2018 09:54:47 +0900 Subject: [PATCH 0818/1313] [draft-14] Bump version --- iocore/net/quic/QUICConfig.cc | 2 +- iocore/net/quic/QUICTypes.h | 2 +- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index a3334c95307..8d71a0882d1 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -37,7 +37,7 @@ // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html // Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? using namespace std::literals; -static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-13"sv); +static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-14"sv); int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 5e7a01e9adf..e7de7a7d1d2 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -49,7 +49,7 @@ using QUICOffset = uint64_t; // Note: Fix QUIC_ALPN_PROTO_LIST in QUICConfig.cc // Note: Change ExtensionType (QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID) if it's changed constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff00000d, + 0xff00000e, }; constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index d56bc146c93..0f47d0b6a8d 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -53,7 +53,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x55, // DCIL/SCIL 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Destination Connection ID 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection ID - 0xff, 0x00, 0x00, 0x0d, // Supported Version + 0xff, 0x00, 0x00, 0x0e, // Supported Version }; uint8_t buf[1024] = {0}; size_t buf_len; From 786ec670eb2336d3354b1276ad2c53ec34791bcd Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 10 Sep 2018 13:47:36 +0900 Subject: [PATCH 0819/1313] [draft-14] Split INITIAL_MAX_STREAM_DATA into 3 transport parameters --- iocore/net/quic/QUICDebugNames.cc | 8 +- iocore/net/quic/QUICHandshake.cc | 15 ++-- iocore/net/quic/QUICStreamManager.cc | 70 +++++++++++++---- iocore/net/quic/QUICTransportParameters.cc | 75 +++++++++++-------- iocore/net/quic/QUICTransportParameters.h | 4 +- .../net/quic/test/test_QUICStreamManager.cc | 4 +- .../quic/test/test_QUICTransportParameters.cc | 16 ++-- 7 files changed, 128 insertions(+), 64 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 567266b7239..7b799bb4bdb 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -173,8 +173,8 @@ const char * QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) { switch (id) { - case QUICTransportParameterId::INITIAL_MAX_STREAM_DATA: - return "INITIAL_MAX_STREAM_DATA"; + case QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL: + return "INITIAL_MAX_STREAM_DATA_BIDI_LOCAL"; case QUICTransportParameterId::INITIAL_MAX_DATA: return "INITIAL_MAX_DATA"; case QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS: @@ -193,6 +193,10 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) return "INITIAL_MAX_UNI_STREAMS"; case QUICTransportParameterId::DISABLE_MIGRATION: return "DISABLE_MIGRATION"; + case QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE: + return "INITIAL_MAX_STREAM_DATA_BIDI_REMOTE"; + case QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI: + return "INITIAL_MAX_STREAM_DATA_UNI"; default: return "UNKNOWN"; } diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 7865bf45550..0349ab9a227 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -366,15 +366,18 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(negotiated_version); // MUSTs - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); - tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); - tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN); - tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); // MAYs + tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_in()); tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_in()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, params->initial_max_stream_data()); + + // MAYs (server) + tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN); + + tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); this->_local_transport_parameters = std::shared_ptr(tp); this->_hs_protocol->set_local_transport_parameters(this->_local_transport_parameters); @@ -388,13 +391,13 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi QUICTransportParametersInClientHello *tp = new QUICTransportParametersInClientHello(initial_version); // MUSTs - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, params->initial_max_stream_data()); - tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_out())); // MAYs + tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_out()); tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_out()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, params->initial_max_stream_data()); this->_local_transport_parameters = std::shared_ptr(tp); this->_hs_protocol->set_local_transport_parameters(std::unique_ptr(tp)); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index aa5d38abd4a..a106ac1827c 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -259,26 +259,68 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) { QUICStream *stream = this->_find_stream(stream_id); if (!stream) { - QUICStreamType type = QUICTypeUtil::detect_stream_type(stream_id); - if (type == QUICStreamType::CLIENT_BIDI && stream_id > this->_local_maximum_stream_id_bidi && - this->_local_maximum_stream_id_bidi != 0) { - return nullptr; - } else if (type == QUICStreamType::CLIENT_UNI && stream_id > this->_local_maximum_stream_id_uni && - this->_local_maximum_stream_id_uni != 0) { - return nullptr; - } else if (type == QUICStreamType::SERVER_BIDI && stream_id > this->_remote_maximum_stream_id_bidi && - this->_remote_maximum_stream_id_bidi != 0) { - return nullptr; - } else if (type == QUICStreamType::SERVER_UNI && stream_id > this->_remote_maximum_stream_id_uni && - this->_remote_maximum_stream_id_uni != 0) { + if (!this->_local_tp) { return nullptr; } ink_assert(this->_local_tp); ink_assert(this->_remote_tp); - uint64_t local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); - uint64_t remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA); + uint64_t local_max_stream_data = 0; + uint64_t remote_max_stream_data = 0; + + switch (QUICTypeUtil::detect_stream_type(stream_id)) { + case QUICStreamType::CLIENT_BIDI: + if (stream_id > this->_local_maximum_stream_id_bidi && this->_local_maximum_stream_id_bidi != 0) { + return nullptr; + } + + if (this->_info->direction() == NET_VCONNECTION_OUT) { + // client + local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); + remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); + } else { + // server + local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); + remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); + } + + break; + case QUICStreamType::CLIENT_UNI: + if (stream_id > this->_local_maximum_stream_id_uni && this->_local_maximum_stream_id_uni != 0) { + return nullptr; + } + + local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); + remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); + + break; + case QUICStreamType::SERVER_BIDI: + if (stream_id > this->_remote_maximum_stream_id_bidi && this->_remote_maximum_stream_id_bidi != 0) { + return nullptr; + } + + if (this->_info->direction() == NET_VCONNECTION_OUT) { + // client + local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); + remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); + } else { + // server + local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); + remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); + } + + break; + case QUICStreamType::SERVER_UNI: + if (stream_id > this->_remote_maximum_stream_id_uni && this->_remote_maximum_stream_id_uni != 0) { + return nullptr; + } + + local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); + remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); + + break; + } // TODO Free the stream somewhere stream = THREAD_ALLOC(quicStreamAllocator, this_ethread()); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 6797ab654e7..00dff4d9535 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -34,6 +34,11 @@ static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; static constexpr char tag[] = "quic_handshake"; +static constexpr uint32_t TP_ERROR_LENGTH = 0x010000; +static constexpr uint32_t TP_ERROR_VALUE = 0x020000; +static constexpr uint32_t TP_ERROR_MUST_EXIST = 0x030000; +static constexpr uint32_t TP_ERROR_MUST_NOT_EXIST = 0x040000; + QUICTransportParameters::Value::Value(const uint8_t *data, uint16_t len) : _len(len) { this->_data = static_cast(ats_malloc(len)); @@ -142,62 +147,70 @@ QUICTransportParameters::_validate_parameters() const decltype(this->_parameters)::const_iterator ite; // MUSTs - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA)) != this->_parameters.end()) { - if (ite->second->len() != 4) { - return -1; + if ((ite = this->_parameters.find(QUICTransportParameterId::IDLE_TIMEOUT)) != this->_parameters.end()) { + if (ite->second->len() != 2) { + return -(TP_ERROR_LENGTH | QUICTransportParameterId::IDLE_TIMEOUT); + } + if (QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 600) { + return -(TP_ERROR_VALUE | QUICTransportParameterId::IDLE_TIMEOUT); } } else { - return -2; + return -(TP_ERROR_MUST_EXIST | QUICTransportParameterId::IDLE_TIMEOUT); } + // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_DATA)) != this->_parameters.end()) { if (ite->second->len() != 4) { - return -3; + return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_DATA); } - } else { - return -4; } - if ((ite = this->_parameters.find(QUICTransportParameterId::IDLE_TIMEOUT)) != this->_parameters.end()) { + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS)) != this->_parameters.end()) { if (ite->second->len() != 2) { - return -5; + return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS); } - if (QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 600) { - return -6; + } + + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS)) != this->_parameters.end()) { + if (ite->second->len() != 2) { + return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS); } - } else { - return -7; } - // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::MAX_PACKET_SIZE)) != this->_parameters.end()) { if (ite->second->len() != 2) { - return -9; + return -(TP_ERROR_LENGTH | QUICTransportParameterId::MAX_PACKET_SIZE); } if (QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) < 1200) { - return -10; + return -(TP_ERROR_LENGTH | QUICTransportParameterId::MAX_PACKET_SIZE); } } if ((ite = this->_parameters.find(QUICTransportParameterId::ACK_DELAY_EXPONENT)) != this->_parameters.end()) { if (ite->second->len() != 1) { - return -11; + return -(TP_ERROR_LENGTH | QUICTransportParameterId::ACK_DELAY_EXPONENT); } if (QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 20) { - return -12; + return -(TP_ERROR_LENGTH | QUICTransportParameterId::ACK_DELAY_EXPONENT); } } - // MAYs - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS)) != this->_parameters.end()) { - if (ite->second->len() != 2) { - return -3; + // MAYs (initial values for the flow control on each type of stream) + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL)) != this->_parameters.end()) { + if (ite->second->len() != 4) { + return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); } } - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS)) != this->_parameters.end()) { - if (ite->second->len() != 2) { - return -5; + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE)) != this->_parameters.end()) { + if (ite->second->len() != 4) { + return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); + } + } + + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI)) != this->_parameters.end()) { + if (ite->second->len() != 4) { + return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); } } @@ -374,18 +387,18 @@ QUICTransportParametersInClientHello::_validate_parameters() const { int res = QUICTransportParameters::_validate_parameters(); if (res < 0) { - return res - 100; + return res; } decltype(this->_parameters)::const_iterator ite; // MUST NOTs if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) { - return -1; + return -(TP_ERROR_MUST_NOT_EXIST | QUICTransportParameterId::STATELESS_RESET_TOKEN); } if ((ite = this->_parameters.find(QUICTransportParameterId::PREFERRED_ADDRESS)) != this->_parameters.end()) { - return -2; + return -(TP_ERROR_MUST_NOT_EXIST | QUICTransportParameterId::PREFERRED_ADDRESS); } return 0; @@ -467,7 +480,7 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const { int res = QUICTransportParameters::_validate_parameters(); if (res < 0) { - return res - 100; + return res; } decltype(this->_parameters)::const_iterator ite; @@ -475,13 +488,13 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) { if (ite->second->len() != QUICStatelessResetToken::LEN) { - return -1; + return -(TP_ERROR_LENGTH | QUICTransportParameterId::STATELESS_RESET_TOKEN); } } if ((ite = this->_parameters.find(QUICTransportParameterId::PREFERRED_ADDRESS)) != this->_parameters.end()) { if (ite->second->len() < QUICPreferredAddress::MIN_LEN || QUICPreferredAddress::MAX_LEN < ite->second->len()) { - return -3; + return -(TP_ERROR_LENGTH | QUICTransportParameterId::PREFERRED_ADDRESS); } } diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index aef3b69c8aa..f1b7a1ef150 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -34,7 +34,7 @@ class QUICTransportParameterId { public: enum { - INITIAL_MAX_STREAM_DATA = 0, + INITIAL_MAX_STREAM_DATA_BIDI_LOCAL = 0, INITIAL_MAX_DATA, INITIAL_MAX_BIDI_STREAMS, IDLE_TIMEOUT, @@ -44,6 +44,8 @@ class QUICTransportParameterId ACK_DELAY_EXPONENT, INITIAL_MAX_UNI_STREAMS, DISABLE_MIGRATION, + INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, + INITIAL_MAX_STREAM_DATA_UNI, }; explicit operator bool() const { return true; } diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index cf463a53428..4711aa180e8 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -106,7 +106,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); std::shared_ptr local_tp = std::make_shared(static_cast(0)); - local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); + local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, UINT32_C(4096)); std::shared_ptr remote_tp = std::make_shared(static_cast(0)); sm.init_flow_control_params(local_tp, remote_tp); @@ -135,7 +135,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); std::shared_ptr local_tp = std::make_shared(static_cast(0)); - local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, UINT32_C(4096)); + local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, UINT32_C(4096)); std::shared_ptr remote_tp = std::make_shared(static_cast(0)); sm.init_flow_control_params(local_tp, remote_tp); diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index 4053ed25643..8f563699117 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -53,7 +53,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") uint16_t len = 0; const uint8_t *data = nullptr; - data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, len); + data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, len); CHECK(len == 4); CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); @@ -115,7 +115,7 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") QUICTransportParametersInClientHello params_in_ch(0x05060708); uint32_t max_stream_data = 0x11223344; - params_in_ch.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, max_stream_data); + params_in_ch.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, max_stream_data); uint16_t max_packet_size = 0xabcd; params_in_ch.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size); @@ -137,7 +137,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") 0x04, // size of supported versions 0x01, 0x02, 0x03, 0x04, // 0x00, 0x2a, // size of parameters - 0x00, 0x00, // parameter id + 0x00, 0x0a, // parameter id 0x00, 0x04, // length of value 0x11, 0x22, 0x33, 0x44, // value 0x00, 0x01, // parameter id @@ -159,7 +159,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") uint16_t len = 0; const uint8_t *data = nullptr; - data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, len); + data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, len); CHECK(len == 4); CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); @@ -252,18 +252,18 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") 0x01, 0x02, 0x03, 0x04, // version 1 0x05, 0x06, 0x07, 0x08, // version 2 0x00, 0x0e, // size of parameters - 0x00, 0x00, // parameter id - 0x00, 0x04, // length of value - 0x11, 0x22, 0x33, 0x44, // value 0x00, 0x05, // parameter id 0x00, 0x02, // length of value 0xab, 0xcd, // value + 0x00, 0x0a, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value }; QUICTransportParametersInEncryptedExtensions params_in_ee(0x01020304); uint32_t max_stream_data = 0x11223344; - params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, max_stream_data); + params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, max_stream_data); uint16_t max_packet_size = 0xabcd; params_in_ee.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size); From 67854c45d848efcd83399600c2b1d5d26704d8c1 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 10 Sep 2018 14:49:38 +0900 Subject: [PATCH 0820/1313] Add configs for Transport Parameters (initial_max_*) Split proxy.config.quic.initial_max_data - proxy.config.quic.initial_max_data_in : 65536 - proxy.config.quic.initial_max_data_out : 65536 Split proxy.config.quic.initial_max_stream_data - proxy.config.quic.initial_max_stream_data_bidi_local_in :0 - proxy.config.quic.initial_max_stream_data_bidi_local_out : 4096 - proxy.config.quic.initial_max_stream_data_bidi_remote_in : 4096 - proxy.config.quic.initial_max_stream_data_bidi_remote_out : 0 - proxy.config.quic.initial_max_stream_data_uni_in : 0 - proxy.config.quic.initial_max_stream_data_uni_out : 0 Add configs for initial_max_(bidi|uni)_streams - proxy.config.quic.initial_max_bidi_streams_in : 100 - proxy.config.quic.initial_max_bidi_streams_out : 0 - proxy.config.quic.initial_max_uni_streams_in : 0 - proxy.config.quic.initial_max_uni_streams_out : 0 --- iocore/net/quic/QUICConfig.cc | 70 ++++++++++++++++++++++++++++---- iocore/net/quic/QUICConfig.h | 60 +++++++++++++++++---------- iocore/net/quic/QUICHandshake.cc | 44 ++++++++++++++++---- mgmt/RecordsConfig.cc | 37 +++++++++++++---- 4 files changed, 165 insertions(+), 46 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 8d71a0882d1..e3605385315 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -133,10 +133,6 @@ QUICConfigParams::~QUICConfigParams() void QUICConfigParams::initialize() { - REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_in, "proxy.config.quic.no_activity_timeout_in"); - REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_out, "proxy.config.quic.no_activity_timeout_out"); - REC_EstablishStaticConfigInt32U(this->_initial_max_data, "proxy.config.quic.initial_max_data"); - REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data, "proxy.config.quic.initial_max_stream_data"); REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); REC_EstablishStaticConfigInt32(this->_connection_table_size, "proxy.config.quic.connection_table.size"); REC_EstablishStaticConfigInt32U(this->_max_alt_connection_ids, "proxy.config.quic.max_alt_connection_ids"); @@ -146,6 +142,27 @@ QUICConfigParams::initialize() REC_ReadConfigStringAlloc(this->_server_supported_groups, "proxy.config.quic.server.supported_groups"); REC_ReadConfigStringAlloc(this->_client_supported_groups, "proxy.config.quic.client.supported_groups"); + // Transport Parameters + REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_in, "proxy.config.quic.no_activity_timeout_in"); + REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_out, "proxy.config.quic.no_activity_timeout_out"); + REC_EstablishStaticConfigInt32U(this->_initial_max_data_in, "proxy.config.quic.initial_max_data_in"); + REC_EstablishStaticConfigInt32U(this->_initial_max_data_out, "proxy.config.quic.initial_max_data_out"); + REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data_bidi_local_in, + "proxy.config.quic.initial_max_stream_data_bidi_local_in"); + REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data_bidi_local_out, + "proxy.config.quic.initial_max_stream_data_bidi_local_out"); + REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data_bidi_remote_in, + "proxy.config.quic.initial_max_stream_data_bidi_remote_in"); + REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data_bidi_remote_out, + "proxy.config.quic.initial_max_stream_data_bidi_remote_out"); + REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data_uni_in, "proxy.config.quic.initial_max_stream_data_uni_in"); + REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data_uni_out, "proxy.config.quic.initial_max_stream_data_uni_out"); + REC_EstablishStaticConfigInt32U(this->_initial_max_bidi_streams_in, "proxy.config.quic.initial_max_bidi_streams_in"); + REC_EstablishStaticConfigInt32U(this->_initial_max_bidi_streams_out, "proxy.config.quic.initial_max_bidi_streams_out"); + REC_EstablishStaticConfigInt32U(this->_initial_max_uni_streams_in, "proxy.config.quic.initial_max_uni_streams_in"); + REC_EstablishStaticConfigInt32U(this->_initial_max_uni_streams_out, "proxy.config.quic.initial_max_uni_streams_out"); + + // Loss Detection REC_EstablishStaticConfigInt32U(this->_ld_max_tlps, "proxy.config.quic.loss_detection.max_tlps"); REC_EstablishStaticConfigInt32U(this->_ld_reordering_threshold, "proxy.config.quic.loss_detection.reordering_threshold"); REC_EstablishStaticConfigFloat(this->_ld_time_reordering_fraction, "proxy.config.quic.loss_detection.time_reordering_fraction"); @@ -164,6 +181,7 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(timeout, "proxy.config.quic.loss_detection.default_initial_rtt"); this->_ld_default_initial_rtt = HRTIME_MSECONDS(timeout); + // Congestion Control REC_EstablishStaticConfigInt32U(this->_cc_default_mss, "proxy.config.quic.congestion_control.default_mss"); REC_EstablishStaticConfigInt32U(this->_cc_initial_window_scale, "proxy.config.quic.congestion_control.initial_window_scale"); REC_EstablishStaticConfigInt32U(this->_cc_minimum_window_scale, "proxy.config.quic.congestion_control.minimum_window_scale"); @@ -218,15 +236,51 @@ QUICConfigParams::vn_exercise_enabled() const } uint32_t -QUICConfigParams::initial_max_data() const +QUICConfigParams::initial_max_data_in() const +{ + return this->_initial_max_data_in; +} + +uint32_t +QUICConfigParams::initial_max_data_out() const +{ + return this->_initial_max_data_out; +} + +uint32_t +QUICConfigParams::initial_max_stream_data_bidi_local_in() const +{ + return this->_initial_max_stream_data_bidi_local_in; +} + +uint32_t +QUICConfigParams::initial_max_stream_data_bidi_local_out() const +{ + return this->_initial_max_stream_data_bidi_local_out; +} + +uint32_t +QUICConfigParams::initial_max_stream_data_bidi_remote_in() const +{ + return this->_initial_max_stream_data_bidi_remote_in; +} + +uint32_t +QUICConfigParams::initial_max_stream_data_bidi_remote_out() const +{ + return this->_initial_max_stream_data_bidi_remote_out; +} + +uint32_t +QUICConfigParams::initial_max_stream_data_uni_in() const { - return this->_initial_max_data; + return this->_initial_max_stream_data_uni_in; } uint32_t -QUICConfigParams::initial_max_stream_data() const +QUICConfigParams::initial_max_stream_data_uni_out() const { - return this->_initial_max_stream_data; + return this->_initial_max_stream_data_uni_out; } uint16_t diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 1c0d46692bc..f7d93735010 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -35,14 +35,6 @@ class QUICConfigParams : public ConfigInfo void initialize(); - uint32_t no_activity_timeout_in() const; - uint32_t no_activity_timeout_out() const; - uint32_t initial_max_data() const; - uint32_t initial_max_stream_data() const; - uint16_t initial_max_bidi_streams_in() const; - uint16_t initial_max_bidi_streams_out() const; - uint16_t initial_max_uni_streams_in() const; - uint16_t initial_max_uni_streams_out() const; uint32_t server_id() const; uint32_t max_alt_connection_ids() const; uint32_t stateless_retry() const; @@ -54,6 +46,23 @@ class QUICConfigParams : public ConfigInfo SSL_CTX *server_ssl_ctx() const; SSL_CTX *client_ssl_ctx() const; + // Transport Parameters + uint32_t no_activity_timeout_in() const; + uint32_t no_activity_timeout_out() const; + uint32_t initial_max_data_in() const; + uint32_t initial_max_data_out() const; + uint32_t initial_max_stream_data_bidi_local_in() const; + uint32_t initial_max_stream_data_bidi_local_out() const; + uint32_t initial_max_stream_data_bidi_remote_in() const; + uint32_t initial_max_stream_data_bidi_remote_out() const; + uint32_t initial_max_stream_data_uni_in() const; + uint32_t initial_max_stream_data_uni_out() const; + uint16_t initial_max_bidi_streams_in() const; + uint16_t initial_max_bidi_streams_out() const; + uint16_t initial_max_uni_streams_in() const; + uint16_t initial_max_uni_streams_out() const; + + // Loss Detection uint32_t ld_max_tlps() const; uint32_t ld_reordering_threshold() const; float ld_time_reordering_fraction() const; @@ -63,6 +72,7 @@ class QUICConfigParams : public ConfigInfo ink_hrtime ld_delayed_ack_timeout() const; ink_hrtime ld_default_initial_rtt() const; + // Congestion Control uint32_t cc_default_mss() const; uint32_t cc_initial_window() const; uint32_t cc_minimum_window() const; @@ -76,20 +86,10 @@ class QUICConfigParams : public ConfigInfo // TODO: make configurable static const uint8_t _scid_len = 18; //< Length of Source Connection ID - // FIXME Fill appropriate default values in RecordsConfig.cc - uint32_t _no_activity_timeout_in = 0; - uint32_t _no_activity_timeout_out = 0; - uint32_t _initial_max_data = 0; - uint32_t _initial_max_stream_data = 0; - uint32_t _server_id = 0; - uint32_t _max_alt_connection_ids = 0; - uint32_t _stateless_retry = 0; - uint32_t _vn_exercise_enabled = 0; - - uint32_t _initial_max_bidi_streams_in = 100; - uint32_t _initial_max_bidi_streams_out = 100; - uint32_t _initial_max_uni_streams_in = 100; - uint32_t _initial_max_uni_streams_out = 100; + uint32_t _server_id = 0; + uint32_t _max_alt_connection_ids = 0; + uint32_t _stateless_retry = 0; + uint32_t _vn_exercise_enabled = 0; char *_server_supported_groups = nullptr; char *_client_supported_groups = nullptr; @@ -98,6 +98,22 @@ class QUICConfigParams : public ConfigInfo SSL_CTX *_server_ssl_ctx = nullptr; SSL_CTX *_client_ssl_ctx = nullptr; + // Transport Parameters + uint32_t _no_activity_timeout_in = 0; + uint32_t _no_activity_timeout_out = 0; + uint32_t _initial_max_data_in = 0; + uint32_t _initial_max_data_out = 0; + uint32_t _initial_max_stream_data_bidi_local_in = 0; + uint32_t _initial_max_stream_data_bidi_local_out = 0; + uint32_t _initial_max_stream_data_bidi_remote_in = 0; + uint32_t _initial_max_stream_data_bidi_remote_out = 0; + uint32_t _initial_max_stream_data_uni_in = 0; + uint32_t _initial_max_stream_data_uni_out = 0; + uint32_t _initial_max_bidi_streams_in = 0; + uint32_t _initial_max_bidi_streams_out = 0; + uint32_t _initial_max_uni_streams_in = 0; + uint32_t _initial_max_uni_streams_out = 0; + // [draft-11 recovery] 3.5.1. Constants of interest uint32_t _ld_max_tlps = 2; uint32_t _ld_reordering_threshold = 3; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 0349ab9a227..01425fbd680 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -369,10 +369,24 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); // MAYs - tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); - tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_in()); - tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_in()); - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, params->initial_max_stream_data()); + if (params->initial_max_data_in() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data_in()); + } + if (params->initial_max_bidi_streams_in() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_in()); + } + if (params->initial_max_uni_streams_in() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_in()); + } + if (params->initial_max_stream_data_bidi_local_in() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, params->initial_max_stream_data_bidi_local_in()); + } + if (params->initial_max_stream_data_bidi_remote_in() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, params->initial_max_stream_data_bidi_remote_in()); + } + if (params->initial_max_stream_data_uni_out() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, params->initial_max_stream_data_uni_out()); + } // MAYs (server) tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN); @@ -394,10 +408,24 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_out())); // MAYs - tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data()); - tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_out()); - tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_out()); - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, params->initial_max_stream_data()); + if (params->initial_max_data_out() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data_out()); + } + if (params->initial_max_bidi_streams_out() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_out()); + } + if (params->initial_max_uni_streams_out() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_out()); + } + if (params->initial_max_stream_data_bidi_local_out() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, params->initial_max_stream_data_bidi_local_out()); + } + if (params->initial_max_stream_data_bidi_remote_out() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, params->initial_max_stream_data_bidi_remote_out()); + } + if (params->initial_max_stream_data_uni_out() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, params->initial_max_stream_data_uni_out()); + } this->_local_transport_parameters = std::shared_ptr(tp); this->_hs_protocol->set_local_transport_parameters(std::unique_ptr(tp)); diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 822130f3066..b4581dc1b4a 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1314,14 +1314,6 @@ static const RecordElement RecordsConfig[] = //# QUIC global configuration. //# //############ - {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_in", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} - , - {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_out", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} - , - {RECT_CONFIG, "proxy.config.quic.initial_max_data", RECD_INT, "131072", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} - , - {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data", RECD_INT, "2048", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} - , {RECT_CONFIG, "proxy.config.quic.server_id", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.connection_table.size", RECD_INT, "65521", RECU_RESTART_TS, RR_NULL, RECC_INT, "[1-536870909]", RECA_NULL} @@ -1336,6 +1328,35 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.client.supported_groups", RECD_STRING, "P-256:X25519:P-384:P-521" , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , + // Transport Parameters + {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_in", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_out", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_data_in", RECD_INT, "65536", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_data_out", RECD_INT, "65536", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_bidi_local_in", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_bidi_local_out", RECD_INT, "4096", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_bidi_remote_in", RECD_INT, "4096", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_bidi_remote_out", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_uni_in", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_uni_out", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_bidi_streams_in", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_bidi_streams_out", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_uni_streams_in", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.initial_max_uni_streams_out", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , // Constants of Loss Detection {RECT_CONFIG, "proxy.config.quic.loss_detection.max_tlps", RECD_INT, "2", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , From 0a4524d825279ee8289ea673b46bd9e300279836 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 11 Sep 2018 11:27:05 +0900 Subject: [PATCH 0821/1313] [draft-14] Remove QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE --- iocore/net/quic/QUICDebugNames.cc | 2 -- iocore/net/quic/QUICPathValidator.cc | 2 +- iocore/net/quic/QUICTypes.h | 5 ++--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 7b799bb4bdb..59fd5aa4e12 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -133,8 +133,6 @@ QUICDebugNames::error_code(uint16_t code) return "VERSION_NEGOTIATION_ERROR"; case static_cast(QUICTransErrorCode::PROTOCOL_VIOLATION): return "PROTOCOL_VIOLATION"; - case static_cast(QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE): - return "UNSOLICITED_PATH_RESPONSE"; case static_cast(QUICTransErrorCode::INVALID_MIGRATION): return "INVALID_MIGRATION"; default: diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index 2a54e4fd8df..f9d1b2b0ae0 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -60,7 +60,7 @@ QUICPathValidator::_generate_response(const QUICPathChallengeFrame &frame) QUICErrorUPtr QUICPathValidator::_validate_response(const QUICPathResponseFrame &frame) { - QUICErrorUPtr error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE)); + QUICErrorUPtr error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); for (int i = 0; i < 3; ++i) { if (memcmp(this->_outgoing_challenge + (QUICPathChallengeFrame::DATA_LEN * i), frame.data(), diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index e7de7a7d1d2..6acb872e5eb 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -156,9 +156,8 @@ enum class QUICTransErrorCode : uint16_t { TRANSPORT_PARAMETER_ERROR, VERSION_NEGOTIATION_ERROR, PROTOCOL_VIOLATION, - UNSOLICITED_PATH_RESPONSE = 0x0B, - INVALID_MIGRATION = 0x0C, - CRYPTO_ERROR = 0x0100, // 0x100 - 0x1FF + INVALID_MIGRATION = 0x0C, + CRYPTO_ERROR = 0x0100, // 0x100 - 0x1FF }; // Application Protocol Error Codes defined in application From 0c3470265ca930b9a98c78cfb05d740d4a964f95 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 12 Sep 2018 15:51:47 +0900 Subject: [PATCH 0822/1313] Add unit tests using draft-14 test vectors for clear text AEAD key derivation --- iocore/net/quic/test/test_QUICKeyGenerator.cc | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index 1c19a2c003a..d0a2ec0461d 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -32,7 +32,6 @@ #include -// #include "Mock.h" #include "QUICKeyGenerator.h" TEST_CASE("QUICKeyGenerator", "[quic]") @@ -59,6 +58,8 @@ TEST_CASE("QUICKeyGenerator", "[quic]") CHECK(memcmp(actual_km->key, expected_client_key, sizeof(expected_client_key)) == 0); CHECK(actual_km->iv_len == sizeof(expected_client_iv)); CHECK(memcmp(actual_km->iv, expected_client_iv, sizeof(expected_client_iv)) == 0); + CHECK(actual_km->pn_len == sizeof(expected_client_pn)); + CHECK(memcmp(actual_km->pn, expected_client_pn, sizeof(expected_client_pn)) == 0); } SECTION("SERVER Initial") @@ -83,5 +84,63 @@ TEST_CASE("QUICKeyGenerator", "[quic]") CHECK(memcmp(actual_km->key, expected_server_key, sizeof(expected_server_key)) == 0); CHECK(actual_km->iv_len == sizeof(expected_server_iv)); CHECK(memcmp(actual_km->iv, expected_server_iv, sizeof(expected_server_iv)) == 0); + CHECK(actual_km->pn_len == sizeof(expected_server_pn)); + CHECK(memcmp(actual_km->pn, expected_server_pn, sizeof(expected_server_pn)) == 0); + } +} + +// https://github.com/quicwg/base-drafts/wiki/Test-Vector-for-the-Clear-Text-AEAD-key-derivation#draft-14-test-vectors +TEST_CASE("draft-14 Test Vectors", "[quic]") +{ + SECTION("CLIENT Initial") + { + QUICKeyGenerator keygen(QUICKeyGenerator::Context::CLIENT); + + QUICConnectionId cid = {reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x08"), 8}; + + uint8_t expected_client_key[] = { + 0xf2, 0x92, 0x8f, 0x26, 0x14, 0xad, 0x6c, 0x20, 0xb9, 0xbd, 0x00, 0x8e, 0x9c, 0x89, 0x63, 0x1c, + }; + uint8_t expected_client_iv[] = { + 0xab, 0x95, 0x0b, 0x01, 0x98, 0x63, 0x79, 0x78, 0xcf, 0x44, 0xaa, 0xb9, + }; + uint8_t expected_client_pn[] = { + 0x68, 0xc3, 0xf6, 0x4e, 0x2d, 0x66, 0x34, 0x41, 0x2b, 0x8e, 0x32, 0x94, 0x62, 0x8d, 0x76, 0xf1, + }; + + std::unique_ptr actual_km = keygen.generate(cid); + + CHECK(actual_km->key_len == sizeof(expected_client_key)); + CHECK(memcmp(actual_km->key, expected_client_key, sizeof(expected_client_key)) == 0); + CHECK(actual_km->iv_len == sizeof(expected_client_iv)); + CHECK(memcmp(actual_km->iv, expected_client_iv, sizeof(expected_client_iv)) == 0); + CHECK(actual_km->pn_len == sizeof(expected_client_pn)); + CHECK(memcmp(actual_km->pn, expected_client_pn, sizeof(expected_client_pn)) == 0); + } + + SECTION("SERVER Initial") + { + QUICKeyGenerator keygen(QUICKeyGenerator::Context::SERVER); + + QUICConnectionId cid = {reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x08"), 8}; + + uint8_t expected_server_key[] = { + 0xf5, 0x68, 0x17, 0xd0, 0xfc, 0x59, 0x5c, 0xfc, 0x0a, 0x2b, 0x0b, 0xcf, 0xb1, 0x87, 0x35, 0xec, + }; + uint8_t expected_server_iv[] = { + 0x32, 0x05, 0x03, 0x5a, 0x3c, 0x93, 0x7c, 0x90, 0x2e, 0xe4, 0xf4, 0xd6, + }; + uint8_t expected_server_pn[] = { + 0xa3, 0x13, 0xc8, 0x6d, 0x13, 0x73, 0xec, 0xbc, 0xcb, 0x32, 0x94, 0xb1, 0x49, 0x74, 0x22, 0x6c, + }; + + std::unique_ptr actual_km = keygen.generate(cid); + + CHECK(actual_km->key_len == sizeof(expected_server_key)); + CHECK(memcmp(actual_km->key, expected_server_key, sizeof(expected_server_key)) == 0); + CHECK(actual_km->iv_len == sizeof(expected_server_iv)); + CHECK(memcmp(actual_km->iv, expected_server_iv, sizeof(expected_server_iv)) == 0); + CHECK(actual_km->pn_len == sizeof(expected_server_pn)); + CHECK(memcmp(actual_km->pn, expected_server_pn, sizeof(expected_server_pn)) == 0); } } From 54be99c2bc1fcbdca1f586f491432654a4067d6e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 12 Sep 2018 16:10:28 +0900 Subject: [PATCH 0823/1313] Simplify content type strings and handshake type strings --- iocore/net/quic/QUICTLS_openssl.cc | 34 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 9fffe46ebb3..7754ed38a31 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -38,21 +38,21 @@ content_type_str(int type) { switch (type) { case SSL3_RT_CHANGE_CIPHER_SPEC: - return "SSL3_RT_CHANGE_CIPHER_SPEC"; + return "CHANGE_CIPHER_SPEC"; case SSL3_RT_ALERT: - return "SSL3_RT_ALERT"; + return "ALERT"; case SSL3_RT_HANDSHAKE: - return "SSL3_RT_HANDSHAKE"; + return "HANDSHAKE"; case SSL3_RT_APPLICATION_DATA: - return "SSL3_RT_APPLICATION_DATA"; + return "APPLICATION_DATA"; case SSL3_RT_HEADER: // The buf contains the record header bytes only - return "SSL3_RT_HEADER"; + return "HEADER"; case SSL3_RT_INNER_CONTENT_TYPE: // Used when an encrypted TLSv1.3 record is sent or received. In encrypted TLSv1.3 records the content type in the record header // is always SSL3_RT_APPLICATION_DATA. The real content type for the record is contained in an "inner" content type. buf // contains the encoded "inner" content type byte. - return "SSL3_RT_INNER_CONTENT_TYPE"; + return "INNER_CONTENT_TYPE"; default: return "UNKNOWN"; } @@ -63,25 +63,25 @@ hs_type_str(int type) { switch (type) { case SSL3_MT_CLIENT_HELLO: - return "SSL3_MT_CLIENT_HELLO"; + return "CLIENT_HELLO"; case SSL3_MT_SERVER_HELLO: - return "SSL3_MT_SERVER_HELLO"; + return "SERVER_HELLO"; case SSL3_MT_NEWSESSION_TICKET: - return "SSL3_MT_NEWSESSION_TICKET"; + return "NEWSESSION_TICKET"; case SSL3_MT_END_OF_EARLY_DATA: - return "SSL3_MT_END_OF_EARLY_DATA"; + return "END_OF_EARLY_DATA"; case SSL3_MT_ENCRYPTED_EXTENSIONS: - return "SSL3_MT_ENCRYPTED_EXTENSIONS"; + return "ENCRYPTED_EXTENSIONS"; case SSL3_MT_CERTIFICATE: - return "SSL3_MT_CERTIFICATE"; + return "CERTIFICATE"; case SSL3_MT_CERTIFICATE_VERIFY: - return "SSL3_MT_CERTIFICATE_VERIFY"; + return "CERTIFICATE_VERIFY"; case SSL3_MT_FINISHED: - return "SSL3_MT_FINISHED"; + return "FINISHED"; case SSL3_MT_KEY_UPDATE: - return "SSL3_MT_KEY_UPDATE"; + return "KEY_UPDATE"; case SSL3_MT_MESSAGE_HASH: - return "SSL3_MT_MESSAGE_HASH"; + return "MESSAGE_HASH"; default: return "UNKNOWN"; } @@ -95,7 +95,7 @@ msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, const uint8_t *tmp = reinterpret_cast(buf); int msg_type = tmp[0]; - Debug("v_quic_crypto", "%s (%d), %s (%d)", content_type_str(content_type), content_type, hs_type_str(msg_type), msg_type); + Debug(tag, "%s (%d), %s (%d)", content_type_str(content_type), content_type, hs_type_str(msg_type), msg_type); return; } From 0af26d2decd6b60c135eafc968e2a36b66b35429 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 12 Sep 2018 17:14:01 +0900 Subject: [PATCH 0824/1313] Update QPACK static table --- proxy/hq/QPACK.cc | 70 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/proxy/hq/QPACK.cc b/proxy/hq/QPACK.cc index 127e3051f17..626d5aeaf89 100644 --- a/proxy/hq/QPACK.cc +++ b/proxy/hq/QPACK.cc @@ -28,12 +28,70 @@ #include "ts/ink_memory.h" #define QPACKDebug(fmt, ...) Debug("qpack", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) - -const QPACK::Header QPACK::StaticTable::STATIC_HEADER_FIELDS[] = { - {"", ""}, // Index 0 is invalid - {"static_1", "svalue1"}, - {"static_2", ""}, -}; +#define QPACKDTDebug(fmt, ...) Debug("qpack", "" fmt, ##__VA_ARGS__) + +const QPACK::Header QPACK::StaticTable::STATIC_HEADER_FIELDS[] = {{"", ""}, // Index 0 is invalid + {":authority", ""}, + {":method", "GET"}, + {":method", "POST"}, + {":path", "/"}, + {":path", "/index.html"}, + {":scheme", "http"}, + {":scheme", "https"}, + {":status", "200"}, + {":status", "204"}, + {":status", "206"}, + {":status", "304"}, + {":status", "400"}, + {":status", "404"}, + {":status", "500"}, + {"accept-charset", ""}, + {"accept-encoding", "gzip, deflate"}, + {"accept-language", ""}, + {"accept-ranges", ""}, + {"accept", ""}, + {"access-control-allow-origin", ""}, + {"age", ""}, + {"allow", ""}, + {"authorization", ""}, + {"cache-control", ""}, + {"content-disposition", ""}, + {"content-encoding", ""}, + {"content-language", ""}, + {"content-length", ""}, + {"content-location", ""}, + {"content-range", ""}, + {"content-type", ""}, + {"cookie", ""}, + {"date", ""}, + {"etag", ""}, + {"expect", ""}, + {"expires", ""}, + {"from", ""}, + {"host", ""}, + {"if-match", ""}, + {"if-modified-since", ""}, + {"if-none-match", ""}, + {"if-range", ""}, + {"if-unmodified-since", ""}, + {"last-modified", ""}, + {"link", ""}, + {"location", ""}, + {"max-forwards", ""}, + {"proxy-authenticate", ""}, + {"proxy-authorization", ""}, + {"range", ""}, + {"referer", ""}, + {"refresh", ""}, + {"retry-after", ""}, + {"server", ""}, + {"set-cookie", ""}, + {"strict-transport-security", ""}, + {"transfer-encoding", ""}, + {"user-agent", ""}, + {"vary", ""}, + {"via", ""}, + {"www-authenticate", ""}}; QPACK::QPACK(QUICConnection *qc, size_t maximum_size) : QUICApplication(qc), _dynamic_table(SETTINGS_HEADER_TABLE_SIZE) { From da89f6932ec8ef2c49d67c3340685710737e73d9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 12 Sep 2018 17:16:10 +0900 Subject: [PATCH 0825/1313] Convert heaeder names to lowercase befor encoding and after decoding --- proxy/hq/QPACK.cc | 41 +++++++++++++++++++++---------------- proxy/hq/test/test_QPACK.cc | 9 ++++++-- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/proxy/hq/QPACK.cc b/proxy/hq/QPACK.cc index 626d5aeaf89..404d88a1f3b 100644 --- a/proxy/hq/QPACK.cc +++ b/proxy/hq/QPACK.cc @@ -237,8 +237,13 @@ QPACK::_encode_prefix(uint16_t largest_reference, uint16_t base_index, IOBufferB int QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock *compressed_header, uint16_t &referred_index) { + Arena arena; int name_len; - const char *name = field.name_get(&name_len); + const char *name = field.name_get(&name_len); + char *lowered_name = arena.str_store(name, name_len); + for (int i = 0; i < name_len; i++) { + lowered_name[i] = ParseRules::ink_tolower(lowered_name[i]); + } int value_len; const char *value = field.value_get(&value_len); @@ -248,9 +253,9 @@ QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock // Find from tables, and insert / duplicate a entry prior to encode it LookupResult lookup_result_static; LookupResult lookup_result_dynamic; - lookup_result_static = StaticTable::lookup(name, name_len, value, value_len); + lookup_result_static = StaticTable::lookup(lowered_name, name_len, value, value_len); if (lookup_result_static.match_type != LookupResult::MatchType::EXACT) { - lookup_result_dynamic = this->_dynamic_table.lookup(name, name_len, value, value_len); + lookup_result_dynamic = this->_dynamic_table.lookup(lowered_name, name_len, value, value_len); if (lookup_result_dynamic.match_type == LookupResult::MatchType::EXACT) { if (this->_dynamic_table.should_duplicate(lookup_result_dynamic.index)) { // Duplicate an entry and use the new entry @@ -266,10 +271,10 @@ QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock // Name in static table is always available. Do nothing. } else { // Insert both the name and the value - lookup_result_dynamic = this->_dynamic_table.insert_entry(name, name_len, value, value_len); + lookup_result_dynamic = this->_dynamic_table.insert_entry(lowered_name, name_len, value, value_len); if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { - this->_write_insert_without_name_ref(name, name_len, value, value_len); - QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, name, value_len, value); + this->_write_insert_without_name_ref(lowered_name, name_len, value, value_len); + QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, lowered_name, value_len, value); } } } else if (lookup_result_dynamic.match_type == LookupResult::MatchType::NAME) { @@ -294,27 +299,27 @@ QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock } } else { // Insert both the name and the value - lookup_result_dynamic = this->_dynamic_table.insert_entry(name, name_len, value, value_len); + lookup_result_dynamic = this->_dynamic_table.insert_entry(lowered_name, name_len, value, value_len); if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { - this->_write_insert_without_name_ref(name, name_len, value, value_len); - QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, name, value_len, value); + this->_write_insert_without_name_ref(lowered_name, name_len, value, value_len); + QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, lowered_name, value_len, value); } } } } else { if (never_index) { // Insert only the name - lookup_result_dynamic = this->_dynamic_table.insert_entry(name, name_len, "", 0); + lookup_result_dynamic = this->_dynamic_table.insert_entry(lowered_name, name_len, "", 0); if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { - this->_write_insert_without_name_ref(name, name_len, "", 0); - QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, name, 0, ""); + this->_write_insert_without_name_ref(lowered_name, name_len, "", 0); + QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, lowered_name, 0, ""); } } else { // Insert both the name and the value - lookup_result_dynamic = this->_dynamic_table.insert_entry(name, name_len, value, value_len); + lookup_result_dynamic = this->_dynamic_table.insert_entry(lowered_name, name_len, value, value_len); if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { - this->_write_insert_without_name_ref(name, name_len, value, value_len); - QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, name, value_len, value); + this->_write_insert_without_name_ref(lowered_name, name_len, value, value_len); + QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, lowered_name, value_len, value); } } } @@ -362,9 +367,9 @@ QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock this->_dynamic_table.ref_entry(lookup_result_dynamic.index); referred_index = lookup_result_dynamic.index; } else { - this->_encode_literal_header_field_without_name_ref(name, name_len, value, value_len, never_index, compressed_header); - QPACKDebug("Encoded Literal Header Field Without Name Ref: name=%.*s, value=%.*s, never_index=%d", name_len, name, value_len, - value, never_index); + this->_encode_literal_header_field_without_name_ref(lowered_name, name_len, value, value_len, never_index, compressed_header); + QPACKDebug("Encoded Literal Header Field Without Name Ref: name=%.*s, value=%.*s, never_index=%d", name_len, lowered_name, + value_len, value, never_index); } return 0; diff --git a/proxy/hq/test/test_QPACK.cc b/proxy/hq/test/test_QPACK.cc index 3fe6bc0b703..b8f8c07a78b 100644 --- a/proxy/hq/test/test_QPACK.cc +++ b/proxy/hq/test/test_QPACK.cc @@ -216,9 +216,14 @@ output_decoded_headers(FILE *fd, HTTPHdr **headers, uint64_t n) field = header_set->iter_get_next(&field_iter)) { int name_len; int value_len; - const char *name = field->name_get(&name_len); + Arena arena; + const char *name = field->name_get(&name_len); + char *lowered_name = arena.str_store(name, name_len); + for (int i = 0; i < name_len; i++) { + lowered_name[i] = ParseRules::ink_tolower(lowered_name[i]); + } const char *value = field->value_get(&value_len); - fprintf(fd, "%.*s\t%.*s\n", name_len, name, value_len, value); + fprintf(fd, "%.*s\t%.*s\n", name_len, lowered_name, value_len, value); } fprintf(fd, "\n"); } From b5de7df0b6d8cac355f212b50f63aa72c653e388 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 12 Sep 2018 17:19:14 +0900 Subject: [PATCH 0826/1313] Fix a sizeof/countof bug in QPACK --- proxy/hq/QPACK.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/hq/QPACK.h b/proxy/hq/QPACK.h index 53845efdd12..bc340f8301e 100644 --- a/proxy/hq/QPACK.h +++ b/proxy/hq/QPACK.h @@ -138,8 +138,8 @@ class QPACK : public QUICApplication // FIXME It may be better to split this array into small arrays to reduce memory footprint struct DynamicTableEntry _entries[SETTINGS_HEADER_TABLE_SIZE] = {{}}; - uint16_t _entries_head = sizeof(_entries) - 1; - uint16_t _entries_tail = sizeof(_entries) - 1; + uint16_t _entries_head = countof(_entries) - 1; + uint16_t _entries_tail = countof(_entries) - 1; DynamicTableStorage *_storage = nullptr; }; From bfd04179ba77d1ba3e1ea0b619b84510137c6705 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 12 Sep 2018 17:20:39 +0900 Subject: [PATCH 0827/1313] Increase maximum number of test sequences for QPACK test --- proxy/hq/test/test_QPACK.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/proxy/hq/test/test_QPACK.cc b/proxy/hq/test/test_QPACK.cc index b8f8c07a78b..81b69717845 100644 --- a/proxy/hq/test/test_QPACK.cc +++ b/proxy/hq/test/test_QPACK.cc @@ -40,6 +40,8 @@ extern char appname[256]; constexpr int ACK_MODE_IMMEDIATE = 1; constexpr int ACK_MODE_NONE = 0; +constexpr int MAX_SEQUENCE = 1024; + class TestQUICConnection : public MockQUICConnection { }; @@ -279,8 +281,8 @@ test_encode(const char *qif_file, int dts, int mbs, int am) sprintf(output_filename, "%s.ats.%d.%d.%d", qif_file, dts, mbs, am); FILE *fd = fopen(output_filename, "w"); - HTTPHdr *requests[256] = {nullptr}; - int n_requests = load_qif_file(qif_file, requests); + HTTPHdr *requests[MAX_SEQUENCE] = {nullptr}; + int n_requests = load_qif_file(qif_file, requests); QUICApplicationDriver driver; QPACK *qpack = new QPACK(driver.get_connection(), dts); @@ -328,7 +330,7 @@ test_decode(const char *qif_file, int dts, int mbs, int am, const char *app_name sprintf(output_filename, "%s.decoded", data_filename); FILE *fd_out = fopen(output_filename, "w"); - HTTPHdr *requests[256]; + HTTPHdr *requests[MAX_SEQUENCE]; int n_requests = load_qif_file(qif_file, requests); TestQPACKEventHandler *event_handler = new TestQPACKEventHandler(); @@ -343,9 +345,9 @@ test_decode(const char *qif_file, int dts, int mbs, int am, const char *app_name uint32_t block_len; int read_len = 0; - uint64_t stream_id = 1; - HTTPHdr *header_sets[256] = {nullptr}; - int n_headers = 0; + uint64_t stream_id = 1; + HTTPHdr *header_sets[MAX_SEQUENCE] = {nullptr}; + int n_headers = 0; while ((read_len = read_block(fd_in, stream_id, &block, block_len)) >= 0) { if (stream_id == encoder_stream->id()) { encoder_stream->write(block, block_len, offset, false); From 00397dfa42846b68f9e4b6345e656e3e35151ce9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 12 Sep 2018 17:21:40 +0900 Subject: [PATCH 0828/1313] Fix dup header name bug in QPACK test driver --- proxy/hq/test/test_QPACK.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proxy/hq/test/test_QPACK.cc b/proxy/hq/test/test_QPACK.cc index 81b69717845..d1906e210ee 100644 --- a/proxy/hq/test/test_QPACK.cc +++ b/proxy/hq/test/test_QPACK.cc @@ -132,7 +132,9 @@ load_qif_file(const char *filename, HTTPHdr **headers) auto tab = line.find_first_of('\t'); auto name = line.substr(0, tab); auto value = line.substr(tab + 1); - hdr->value_set(name.c_str(), tab, value.c_str(), line.length() - tab - 1); + auto field = hdr->field_create(name.c_str(), tab); + hdr->field_attach(field); + hdr->field_value_set(field, value.c_str(), line.length() - tab - 1); } } if (hdr) { From f1da5b0872f67a587ed81c57e9f9c9a912715c88 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 13 Sep 2018 10:32:44 +0900 Subject: [PATCH 0829/1313] Print derived secret on key_cb for debug --- iocore/net/quic/QUICDebugNames.h | 2 +- iocore/net/quic/QUICTLS_openssl.cc | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index 25411cf0532..8bc2c100662 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -47,7 +47,7 @@ class QUICDebug { public: static void - to_hex(uint8_t *out, uint8_t *in, int in_len) + to_hex(uint8_t *out, const uint8_t *in, int in_len) { for (int i = 0; i < in_len; ++i) { int u4 = in[i] / 16; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 7754ed38a31..7863e7be6ac 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -172,7 +172,9 @@ key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, const break; } - uint8_t print_buf[512]; + uint8_t print_buf[128]; + QUICDebug::to_hex(print_buf, static_cast(secret), secret_len); + Debug("vv_quic_crypto", "secret=%s", print_buf); QUICDebug::to_hex(print_buf, km->key, km->key_len); Debug("vv_quic_crypto", "key=%s", print_buf); QUICDebug::to_hex(print_buf, km->iv, km->iv_len); From 730a57dda5a197427090c950d192d057582a9849 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 13 Sep 2018 10:39:54 +0900 Subject: [PATCH 0830/1313] Print error reason on debug log only if it is provided --- iocore/net/QUICNetVConnection.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 55a347b5b0b..7be9e29a5d8 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1734,9 +1734,8 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) } if (error->msg) { QUICConDebug("Reason: %.*s", static_cast(strlen(error->msg)), error->msg); - } else { - QUICConDebug("Reason was not provided"); } + this->_connection_error = std::move(error); this->_schedule_packet_write_ready(); @@ -1763,8 +1762,6 @@ QUICNetVConnection::_switch_to_draining_state(QUICConnectionErrorUPtr error) } if (error->msg) { QUICConDebug("Reason: %.*s", static_cast(strlen(error->msg)), error->msg); - } else { - QUICConDebug("Reason was not provided"); } this->remove_from_active_queue(); From d673c783ac7c4469ed174f0a2fb5d99df02f8179 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 13 Sep 2018 15:14:12 +0900 Subject: [PATCH 0831/1313] Ignore VN packets on closing state --- iocore/net/QUICNetVConnection.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 7be9e29a5d8..46557af2ae6 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1028,7 +1028,14 @@ QUICNetVConnection::_state_closing_receive_packet() QUICPacketCreationResult result; QUICPacketUPtr packet = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::SUCCESS) { - this->_recv_and_ack(std::move(packet)); + switch (packet->type()) { + case QUICPacketType::VERSION_NEGOTIATION: + // Ignore VN packets on closing state + break; + default: + this->_recv_and_ack(std::move(packet)); + break; + } } ++this->_state_closing_recv_packet_count; From d6515064c024c3f71cd1e1cdbd5f8fe14f916247 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 13 Sep 2018 17:55:44 +0900 Subject: [PATCH 0832/1313] Fix bugs around static table reference --- proxy/hq/QPACK.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/proxy/hq/QPACK.cc b/proxy/hq/QPACK.cc index 404d88a1f3b..ad74a514a33 100644 --- a/proxy/hq/QPACK.cc +++ b/proxy/hq/QPACK.cc @@ -330,7 +330,7 @@ QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock this->_encode_indexed_header_field(lookup_result_static.index, base_index, false, compressed_header); QPACKDebug("Encoded Indexed Header Field: abs_index=%d, base_index=%d, dynamic_table=%d", lookup_result_static.index, base_index, false); - referred_index = lookup_result_static.index; + referred_index = 0; } else if (lookup_result_dynamic.match_type == LookupResult::MatchType::EXACT) { if (lookup_result_dynamic.index < this->_largest_known_received_index) { this->_encode_indexed_header_field(lookup_result_dynamic.index, base_index, true, compressed_header); @@ -350,7 +350,7 @@ QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock QPACKDebug( "Encoded Literal Header Field With Name Ref: abs_index=%d, base_index=%d, dynamic_table=%d, value=%.*s, never_index=%d", lookup_result_static.index, base_index, false, value_len, value, never_index); - referred_index = lookup_result_static.index; + referred_index = 0; } else if (lookup_result_dynamic.match_type == LookupResult::MatchType::NAME) { if (lookup_result_dynamic.index <= this->_largest_known_received_index) { this->_encode_literal_header_field_with_name_ref(lookup_result_dynamic.index, true, base_index, value, value_len, never_index, @@ -595,7 +595,7 @@ QPACK::_decode_literal_header_field_with_name_ref(int16_t base_index, const uint // Never index field bool never_index = false; - if (buf[0] & 0x40) { + if (buf[0] & 0x20) { never_index = true; } @@ -1051,13 +1051,14 @@ QPACK::StaticTable::lookup(const char *name, int name_len, const char *value, in { QPACK::LookupResult::MatchType match_type = QPACK::LookupResult::MatchType::NONE; uint16_t i = 0; - int candidate_index = 0; + uint16_t candidate_index = 0; int n = countof(STATIC_HEADER_FIELDS); for (; i < n; ++i) { const Header &h = STATIC_HEADER_FIELDS[i]; if (h.name_len == name_len) { if (memcmp(name, h.name, name_len) == 0) { + candidate_index = i; if (value_len == h.value_len && memcmp(value, h.value, value_len) == 0) { // Exact match match_type = QPACK::LookupResult::MatchType::EXACT; @@ -1066,11 +1067,10 @@ QPACK::StaticTable::lookup(const char *name, int name_len, const char *value, in // Name match -- Keep it for no exact matchs match_type = QPACK::LookupResult::MatchType::NAME; } - candidate_index = i; } } } - return {i, match_type}; + return {candidate_index, match_type}; } uint16_t From 035d09aa74353f3b75762a1d7a9e8ee1822d73df Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 14 Sep 2018 08:19:25 +0900 Subject: [PATCH 0833/1313] Ignore invalid packets which failed to migrate connection --- iocore/net/QUICNetVConnection.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 46557af2ae6..90d01180b52 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -997,8 +997,10 @@ QUICNetVConnection::_state_common_receive_packet() QUICConDebug("Connection migrated"); this->_validate_new_path(); } else { - QUICConDebug("Connection migration failed"); - ink_assert(!"Connection migration failed"); + char dcid_str[QUICConnectionId::MAX_HEX_STR_LENGTH]; + p->destination_cid().hex(dcid_str, QUICConnectionId::MAX_HEX_STR_LENGTH); + QUICConDebug("Connection migration failed cid=%s", dcid_str); + break; } } error = this->_state_connection_established_process_packet(std::move(p)); From 8df035b43b9bc7b5065fde918b7f3ef5585b66d2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 14 Sep 2018 10:09:47 +0900 Subject: [PATCH 0834/1313] Print generated alt quic connection ids for debug --- iocore/net/quic/QUICAltConnectionManager.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 88763fe0945..044e02a5e48 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -25,6 +25,10 @@ #include "QUICConnectionTable.h" #include "QUICConfig.h" +static constexpr char DEBUG_TAG[] = "quic_alt_con"; + +#define QUICACMDebug(fmt, ...) Debug(DEBUG_TAG, "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) + QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable) : _qc(qc), _ctable(ctable) { QUICConfig::scoped_config params; @@ -66,6 +70,12 @@ QUICAltConnectionManager::_update_alt_connection_ids(int8_t chosen) token.generate(conn_id, params->server_id()); this->_alt_quic_connection_ids[index] = {this->_alt_quic_connection_id_seq_num + i, conn_id, token, false}; this->_ctable.insert(conn_id, this->_qc); + + if (is_debug_tag_set(DEBUG_TAG)) { + char new_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH]; + conn_id.hex(new_cid_str, QUICConnectionId::MAX_HEX_STR_LENGTH); + QUICACMDebug("alt-cid=%s", new_cid_str); + } } this->_alt_quic_connection_id_seq_num += count; this->_need_advertise = true; From aede93e79ab51393c53e40ad382cf9b6e2150514 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 14 Sep 2018 11:04:19 +0900 Subject: [PATCH 0835/1313] Update test_QPACK to decode speciied encoded files --- proxy/hq/test/main_qpack.cc | 14 ++++++--- proxy/hq/test/test_QPACK.cc | 61 +++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/proxy/hq/test/main_qpack.cc b/proxy/hq/test/main_qpack.cc index b5c7380887a..20d8bf4e7af 100644 --- a/proxy/hq/test/main_qpack.cc +++ b/proxy/hq/test/main_qpack.cc @@ -40,7 +40,9 @@ #define TEST_THREADS 1 -char qifdir[256] = "test/qif/"; +char qifdir[256] = "./qifs/qifs"; +char encdir[256] = "./qifs/encoded"; +char decdir[256] = "./qifs/decoded"; int tablesize = 4096; int streams = 100; int ackmode = 0; @@ -83,10 +85,12 @@ main(int argc, char *argv[]) { Catch::Session session; using namespace Catch::clara; - auto cli = session.cli() | Opt(qifdir, "dir")["--q-qif-dir"]("path for a directory that contains QIF files (default:test/qif/") | - Opt(tablesize, "size")["--q-dynamic-table-size"]("dynamic table size: 0-65535 (default:4096)") | - Opt(streams, "n")["--q-max-blocked-streams"]("max blocked streams: 0-65535 (default:100)") | - Opt(ackmode, "mode")["--q-ack-mode"]("acknowledgement mode: none(default:0) or immediate(1)") | + auto cli = session.cli() | Opt(qifdir, "qifdir")["--q-qif-dir"]("path for a directory that contains QIF files (default:qifs/qifs") | + Opt(encdir, "encdir")["--q-encoded-dir"]("path for a directory that encoded files will be stored (default:qifs/encoded)") | + Opt(encdir, "decdir")["--q-decoded-dir"]("path for a directory that decoded files will be stored (default:qifs/decoded)") | + Opt(tablesize, "size")["--q-dynamic-table-size"]("dynamic table size for encoding: 0-65535 (default:4096)") | + Opt(streams, "n")["--q-max-blocked-streams"]("max blocked streams for encoding: 0-65535 (default:100)") | + Opt(ackmode, "mode")["--q-ack-mode"]("acknowledgement modes for encoding: none(default:0) or immediate(1)") | Opt(appname, "app")["--q-app"]("app name: app name (default:ats)"); session.cli(cli); diff --git a/proxy/hq/test/test_QPACK.cc b/proxy/hq/test/test_QPACK.cc index d1906e210ee..911f86efb7a 100644 --- a/proxy/hq/test/test_QPACK.cc +++ b/proxy/hq/test/test_QPACK.cc @@ -32,6 +32,8 @@ // Declared in main_qpack.cc extern char qifdir[256]; +extern char encdir[256]; +extern char decdir[256]; extern int tablesize; extern int streams; extern int ackmode; @@ -275,13 +277,11 @@ acknowledge_header_block(TestQUICStream *stream, uint64_t stream_id) } static int -test_encode(const char *qif_file, int dts, int mbs, int am) +test_encode(const char *qif_file, const char *out_file, int dts, int mbs, int am) { int ret = 0; - char output_filename[256]; - sprintf(output_filename, "%s.ats.%d.%d.%d", qif_file, dts, mbs, am); - FILE *fd = fopen(output_filename, "w"); + FILE *fd = fopen(out_file, "w"); HTTPHdr *requests[MAX_SEQUENCE] = {nullptr}; int n_requests = load_qif_file(qif_file, requests); @@ -320,20 +320,15 @@ test_encode(const char *qif_file, int dts, int mbs, int am) } static int -test_decode(const char *qif_file, int dts, int mbs, int am, const char *app_name) +test_decode(const char *enc_file, const char *out_file, int dts, int mbs, int am, const char *app_name) { int ret = 0; - char data_filename[256]; - sprintf(data_filename, "%s.%s.%d.%d.%d", qif_file, app_name, dts, mbs, am); - FILE *fd_in = fopen(data_filename, "r"); + FILE *fd_in = fopen(enc_file, "r"); + FILE *fd_out = fopen(out_file, "w"); - char output_filename[256]; - sprintf(output_filename, "%s.decoded", data_filename); - FILE *fd_out = fopen(output_filename, "w"); - - HTTPHdr *requests[MAX_SEQUENCE]; - int n_requests = load_qif_file(qif_file, requests); + // HTTPHdr *requests[MAX_SEQUENCE]; + // int n_requests = load_qif_file(qif_file, requests); TestQPACKEventHandler *event_handler = new TestQPACKEventHandler(); @@ -369,7 +364,7 @@ test_decode(const char *qif_file, int dts, int mbs, int am, const char *app_name return -1; } - sleep(3); + sleep(5); CHECK(event_handler->last_event() == QPACK_EVENT_DECODE_COMPLETE); @@ -385,7 +380,7 @@ test_decode(const char *qif_file, int dts, int mbs, int am, const char *app_name return ret; } -TEST_CASE("Encoding", "[qpack]") +TEST_CASE("Encoding", "[qpack-encode]") { struct dirent *d; DIR *dir = opendir(qifdir); @@ -396,7 +391,9 @@ TEST_CASE("Encoding", "[qpack]") struct stat st; char qif_file[PATH_MAX + 1] = ""; + char out_file[PATH_MAX + 1] = ""; strcat(qif_file, qifdir); + strcat(out_file, encdir); while ((d = readdir(dir)) != nullptr) { char section_name[128]; @@ -408,36 +405,46 @@ TEST_CASE("Encoding", "[qpack]") ink_strlcat(qif_file, d->d_name, sizeof(qif_file)); stat(qif_file, &st); if (S_ISREG(st.st_mode) && strstr(d->d_name, ".qif") == (d->d_name + (strlen(d->d_name) - 4))) { - CHECK(test_encode(qif_file, tablesize, streams, ackmode) == 0); + out_file[strlen(encdir)] = '\0'; + sprintf(out_file, "%s/ats/%s.ats.%d.%d.%d", out_file, d->d_name, tablesize, streams, ackmode); + CHECK(test_encode(qif_file, out_file, tablesize, streams, ackmode) == 0); } } } } -TEST_CASE("Decoding", "[qpack]") +TEST_CASE("Decoding", "[qpack-decode]") { + char app_dir[PATH_MAX + 1] = ""; + sprintf(app_dir, "%s/%s", encdir, appname); struct dirent *d; - DIR *dir = opendir(qifdir); + DIR *dir = opendir(app_dir); if (dir == nullptr) { return; } struct stat st; - char qif_file[PATH_MAX + 1] = ""; - strcat(qif_file, qifdir); + char enc_file[PATH_MAX + 1] = ""; + char out_file[PATH_MAX + 1] = ""; + char pattern[PATH_MAX + 1] = ""; + strcat(enc_file, encdir); + strcat(out_file, decdir); + sprintf(pattern, ".%d.%d.%d", tablesize, streams, ackmode); while ((d = readdir(dir)) != nullptr) { char section_name[128]; sprintf(section_name, "%s: DTS=%d, MBS=%d, AM=%d, APP=%s", d->d_name, tablesize, streams, ackmode, appname); SECTION(section_name) { - qif_file[strlen(qifdir)] = '/'; - qif_file[strlen(qifdir) + 1] = '\0'; - ink_strlcat(qif_file, d->d_name, sizeof(qif_file)); - stat(qif_file, &st); - if (S_ISREG(st.st_mode) && strstr(d->d_name, ".qif") == (d->d_name + (strlen(d->d_name) - 4))) { - CHECK(test_decode(qif_file, tablesize, streams, ackmode, appname) == 0); + enc_file[strlen(encdir)] = '/'; + enc_file[strlen(encdir) + 1] = '\0'; + sprintf(enc_file, "%s/%s/%s", enc_file, appname, d->d_name); + stat(enc_file, &st); + if (S_ISREG(st.st_mode) && strstr(d->d_name, pattern)) { + out_file[strlen(encdir)] = '\0'; + sprintf(out_file, "%s/%s/%s.decoded", out_file, appname, d->d_name); + CHECK(test_decode(enc_file, out_file, tablesize, streams, ackmode, appname) == 0); } } } From 1e5bacae50d6c16d23c710c2d5590c903ecf3f74 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 14 Sep 2018 11:07:22 +0900 Subject: [PATCH 0836/1313] Support QPACK instruction Insert With Name Ref --- proxy/hq/QPACK.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/proxy/hq/QPACK.cc b/proxy/hq/QPACK.cc index ad74a514a33..fc01c523372 100644 --- a/proxy/hq/QPACK.cc +++ b/proxy/hq/QPACK.cc @@ -1162,9 +1162,17 @@ QPACK::DynamicTable::lookup(const char *name, int name_len, const char *value, i const QPACK::LookupResult QPACK::DynamicTable::insert_entry(bool is_static, uint16_t index, const char *value, uint16_t value_len) { - // TODO Implement it. - ink_assert(!"not implemented"); - return {}; + const char *name; + int name_len; + const char *dummy; + int dummy_len; + + if (is_static) { + StaticTable::lookup(index, &name, &name_len, &dummy, &dummy_len); + } else { + this->lookup(index, &name, &name_len, &dummy, &dummy_len); + } + return this->insert_entry(name, name_len, value, value_len); } const QPACK::LookupResult From 66798aa2a9c9c745d68161eaab58e4988c218e30 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 14 Sep 2018 12:29:45 +0900 Subject: [PATCH 0837/1313] Update peer cid on server side when connection migration is initiated --- iocore/net/P_QUICNetVConnection.h | 3 +++ iocore/net/QUICNetVConnection.cc | 28 +++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 9b18fe84a2b..4e16a5ceeb5 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -235,6 +235,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICConnectionId _original_quic_connection_id; // dst cid of initial packet from client QUICConnectionId _quic_connection_id; // src cid in local QUICFiveTuple _five_tuple; + bool _connection_migration_initiated = false; char _cids_data[MAX_CIDS_SIZE] = {0}; std::string_view _cids; @@ -339,6 +340,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _handle_idle_timeout(); + QUICErrorUPtr _handle_frame(const QUICNewConnectionIdFrame &frame); + void _update_cids(); void _update_peer_cid(const QUICConnectionId &new_cid); void _update_local_cid(const QUICConnectionId &new_cid); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 90d01180b52..cd8bdcb7d10 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -448,7 +448,7 @@ QUICNetVConnection::close(QUICConnectionErrorUPtr error) std::vector QUICNetVConnection::interests() { - return {QUICFrameType::CONNECTION_CLOSE, QUICFrameType::BLOCKED, QUICFrameType::MAX_DATA}; + return {QUICFrameType::CONNECTION_CLOSE, QUICFrameType::BLOCKED, QUICFrameType::MAX_DATA, QUICFrameType::NEW_CONNECTION_ID}; } QUICErrorUPtr @@ -470,6 +470,9 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra case QUICFrameType::BLOCKED: // BLOCKED frame is for debugging. Nothing to do here. break; + case QUICFrameType::NEW_CONNECTION_ID: + error = this->_handle_frame(static_cast(frame)); + break; case QUICFrameType::APPLICATION_CLOSE: case QUICFrameType::CONNECTION_CLOSE: if (this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closed) || @@ -497,6 +500,28 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra return error; } +QUICErrorUPtr +QUICNetVConnection::_handle_frame(const QUICNewConnectionIdFrame &frame) +{ + QUICErrorUPtr error = std::make_unique(); + + if (frame.connection_id() == QUICConnectionId::ZERO()) { + return std::make_unique(QUICTransErrorCode::PROTOCOL_VIOLATION, "received zero-length cid", + QUICFrameType::NEW_CONNECTION_ID); + } + + if (this->netvc_context == NET_VCONNECTION_IN && this->_connection_migration_initiated) { + // For connection migration testing, server update peer cid every time when it's offered + // TODO: update peer cid only if client's local adress is changed + this->_connection_migration_initiated = false; + this->_update_peer_cid(frame.connection_id()); + } else { + // TODO: on client side, store offered alt cids from server + } + + return error; +} + // XXX Setup QUICNetVConnection on regular EThread. // QUICNetVConnection::init() and QUICNetVConnection::start() might be called on ET_UDP EThread. int @@ -995,6 +1020,7 @@ QUICNetVConnection::_state_common_receive_packet() con.setRemote(&p->from().sa); this->con.move(con); QUICConDebug("Connection migrated"); + this->_connection_migration_initiated = true; this->_validate_new_path(); } else { char dcid_str[QUICConnectionId::MAX_HEX_STR_LENGTH]; From b3383588c1d207415dbdee088a63412147e82950 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 14 Sep 2018 20:41:42 +0900 Subject: [PATCH 0838/1313] Make QUICNetVC handle APPLICATION_CLOSE frame --- iocore/net/QUICNetVConnection.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index cd8bdcb7d10..40f20572a5d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -448,7 +448,8 @@ QUICNetVConnection::close(QUICConnectionErrorUPtr error) std::vector QUICNetVConnection::interests() { - return {QUICFrameType::CONNECTION_CLOSE, QUICFrameType::BLOCKED, QUICFrameType::MAX_DATA, QUICFrameType::NEW_CONNECTION_ID}; + return {QUICFrameType::APPLICATION_CLOSE, QUICFrameType::CONNECTION_CLOSE, QUICFrameType::BLOCKED, QUICFrameType::MAX_DATA, + QUICFrameType::NEW_CONNECTION_ID}; } QUICErrorUPtr From e8118051b7f93516f18a54c8c0c5aa84759b8bd3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 14 Sep 2018 21:26:30 +0900 Subject: [PATCH 0839/1313] Support non-default table size of QPACK --- proxy/hq/QPACK.cc | 26 ++++++++++++++++++++------ proxy/hq/QPACK.h | 13 ++++++++----- proxy/hq/test/main_qpack.cc | 15 ++++++++------- proxy/hq/test/test_QPACK.cc | 8 ++++---- 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/proxy/hq/QPACK.cc b/proxy/hq/QPACK.cc index fc01c523372..00e76e172f5 100644 --- a/proxy/hq/QPACK.cc +++ b/proxy/hq/QPACK.cc @@ -93,7 +93,11 @@ const QPACK::Header QPACK::StaticTable::STATIC_HEADER_FIELDS[] = {{"", ""}, // I {"via", ""}, {"www-authenticate", ""}}; -QPACK::QPACK(QUICConnection *qc, size_t maximum_size) : QUICApplication(qc), _dynamic_table(SETTINGS_HEADER_TABLE_SIZE) +QPACK::QPACK(QUICConnection *qc, uint16_t max_table_size, uint16_t max_blocking_streams) + : QUICApplication(qc), + _dynamic_table(max_table_size), + _max_table_size(max_table_size), + _max_blocking_streams(max_blocking_streams) { SET_HANDLER(&QPACK::event_handler); @@ -1108,7 +1112,13 @@ QPACK::_attach_header(HTTPHdr &hdr, const char *name, int name_len, const char * // // DynamicTable // -QPACK::DynamicTable::DynamicTable(uint16_t size) : _available(size), _storage(new DynamicTableStorage(size)) {} +QPACK::DynamicTable::DynamicTable(uint16_t size) : _available(size), _max_entries(size), _storage(new DynamicTableStorage(size)) +{ + QPACKDTDebug("Dynamic table size: %u", size); + this->_entries = static_cast(ats_malloc(sizeof(struct DynamicTableEntry) * size)); + this->_entries_head = size - 1; + this->_entries_tail = size - 1; +} QPACK::DynamicTable::~DynamicTable() { @@ -1116,12 +1126,16 @@ QPACK::DynamicTable::~DynamicTable() delete this->_storage; this->_storage = nullptr; } + if (this->_entries) { + delete this->_entries; + this->_entries = nullptr; + } } const QPACK::LookupResult QPACK::DynamicTable::lookup(uint16_t index, const char **name, int *name_len, const char **value, int *value_len) { - uint16_t pos = (this->_entries_head + (index - this->_entries[this->_entries_head].index)) % countof(this->_entries); + uint16_t pos = (this->_entries_head + (index - this->_entries[this->_entries_head].index)) % this->_max_entries; *name_len = this->_entries[pos].name_len; *value_len = this->_entries[pos].value_len; this->_storage->read(this->_entries[pos].offset, name, *name_len, value, *value_len); @@ -1136,7 +1150,7 @@ QPACK::DynamicTable::lookup(const char *name, int name_len, const char *value, i uint16_t candidate_index = 0; const char *tmp_name = nullptr; const char *tmp_value = nullptr; - int n = countof(this->_entries); + int n = this->_max_entries; // TODO Use a tree for better perfomance for (; i < n; ++i) { @@ -1187,7 +1201,7 @@ QPACK::DynamicTable::insert_entry(const char *name, uint16_t name_len, const cha break; } available += this->_entries[tail].name_len + this->_entries[tail].value_len; - tail = (tail + 1) % countof(this->_entries); + tail = (tail + 1) % this->_max_entries; } if (available < required_len) { // We can't insert a new entry because some stream(s) refer an entry that need to be evicted @@ -1199,7 +1213,7 @@ QPACK::DynamicTable::insert_entry(const char *name, uint16_t name_len, const cha this->_entries_tail = tail; // Insert - this->_entries_head = (this->_entries_head + 1) % countof(this->_entries); + this->_entries_head = (this->_entries_head + 1) % this->_max_entries; this->_entries[this->_entries_head] = {++this->_entries_inserted, this->_storage->write(name, name_len, value, value_len), name_len, value_len, 0}; this->_available -= required_len; diff --git a/proxy/hq/QPACK.h b/proxy/hq/QPACK.h index bc340f8301e..7d99d65d387 100644 --- a/proxy/hq/QPACK.h +++ b/proxy/hq/QPACK.h @@ -43,7 +43,7 @@ constexpr int SETTINGS_QPACK_BLOCKED_STREAMS = 100; class QPACK : public QUICApplication { public: - QPACK(QUICConnection *qc, size_t maximum_size); + QPACK(QUICConnection *qc, uint16_t max_table_size, uint16_t max_blocking_streams); virtual ~QPACK(); int event_handler(int event, Event *data); @@ -137,10 +137,11 @@ class QPACK : public QUICApplication uint16_t _entries_inserted = 0; // FIXME It may be better to split this array into small arrays to reduce memory footprint - struct DynamicTableEntry _entries[SETTINGS_HEADER_TABLE_SIZE] = {{}}; - uint16_t _entries_head = countof(_entries) - 1; - uint16_t _entries_tail = countof(_entries) - 1; - DynamicTableStorage *_storage = nullptr; + struct DynamicTableEntry *_entries = nullptr; + uint16_t _max_entries = 0; + uint16_t _entries_head = 0; + uint16_t _entries_tail = 0; + DynamicTableStorage *_storage = nullptr; }; class DecodeRequest @@ -236,6 +237,8 @@ class QPACK : public QUICApplication DynamicTable _dynamic_table; std::map _references; + uint16_t _max_table_size = 0; + uint16_t _max_blocking_streams = 0; Continuation *_event_handler = nullptr; void _resume_decode(); diff --git a/proxy/hq/test/main_qpack.cc b/proxy/hq/test/main_qpack.cc index 20d8bf4e7af..cba1230ec8d 100644 --- a/proxy/hq/test/main_qpack.cc +++ b/proxy/hq/test/main_qpack.cc @@ -85,13 +85,14 @@ main(int argc, char *argv[]) { Catch::Session session; using namespace Catch::clara; - auto cli = session.cli() | Opt(qifdir, "qifdir")["--q-qif-dir"]("path for a directory that contains QIF files (default:qifs/qifs") | - Opt(encdir, "encdir")["--q-encoded-dir"]("path for a directory that encoded files will be stored (default:qifs/encoded)") | - Opt(encdir, "decdir")["--q-decoded-dir"]("path for a directory that decoded files will be stored (default:qifs/decoded)") | - Opt(tablesize, "size")["--q-dynamic-table-size"]("dynamic table size for encoding: 0-65535 (default:4096)") | - Opt(streams, "n")["--q-max-blocked-streams"]("max blocked streams for encoding: 0-65535 (default:100)") | - Opt(ackmode, "mode")["--q-ack-mode"]("acknowledgement modes for encoding: none(default:0) or immediate(1)") | - Opt(appname, "app")["--q-app"]("app name: app name (default:ats)"); + auto cli = + session.cli() | Opt(qifdir, "qifdir")["--q-qif-dir"]("path for a directory that contains QIF files (default:qifs/qifs") | + Opt(encdir, "encdir")["--q-encoded-dir"]("path for a directory that encoded files will be stored (default:qifs/encoded)") | + Opt(encdir, "decdir")["--q-decoded-dir"]("path for a directory that decoded files will be stored (default:qifs/decoded)") | + Opt(tablesize, "size")["--q-dynamic-table-size"]("dynamic table size for encoding: 0-65535 (default:4096)") | + Opt(streams, "n")["--q-max-blocked-streams"]("max blocked streams for encoding: 0-65535 (default:100)") | + Opt(ackmode, "mode")["--q-ack-mode"]("acknowledgement modes for encoding: none(default:0) or immediate(1)") | + Opt(appname, "app")["--q-app"]("app name: app name (default:ats)"); session.cli(cli); diff --git a/proxy/hq/test/test_QPACK.cc b/proxy/hq/test/test_QPACK.cc index 911f86efb7a..a4b71e57035 100644 --- a/proxy/hq/test/test_QPACK.cc +++ b/proxy/hq/test/test_QPACK.cc @@ -287,7 +287,7 @@ test_encode(const char *qif_file, const char *out_file, int dts, int mbs, int am int n_requests = load_qif_file(qif_file, requests); QUICApplicationDriver driver; - QPACK *qpack = new QPACK(driver.get_connection(), dts); + QPACK *qpack = new QPACK(driver.get_connection(), dts, mbs); TestQUICStream *encoder_stream = new TestQUICStream(0); TestQUICStream *decoder_stream = new TestQUICStream(9999); qpack->set_stream(encoder_stream); @@ -324,7 +324,7 @@ test_decode(const char *enc_file, const char *out_file, int dts, int mbs, int am { int ret = 0; - FILE *fd_in = fopen(enc_file, "r"); + FILE *fd_in = fopen(enc_file, "r"); FILE *fd_out = fopen(out_file, "w"); // HTTPHdr *requests[MAX_SEQUENCE]; @@ -333,7 +333,7 @@ test_decode(const char *enc_file, const char *out_file, int dts, int mbs, int am TestQPACKEventHandler *event_handler = new TestQPACKEventHandler(); QUICApplicationDriver driver; - QPACK *qpack = new QPACK(driver.get_connection(), dts); + QPACK *qpack = new QPACK(driver.get_connection(), dts, mbs); TestQUICStream *encoder_stream = new TestQUICStream(0); qpack->set_stream(encoder_stream); @@ -442,7 +442,7 @@ TEST_CASE("Decoding", "[qpack-decode]") sprintf(enc_file, "%s/%s/%s", enc_file, appname, d->d_name); stat(enc_file, &st); if (S_ISREG(st.st_mode) && strstr(d->d_name, pattern)) { - out_file[strlen(encdir)] = '\0'; + out_file[strlen(decdir)] = '\0'; sprintf(out_file, "%s/%s/%s.decoded", out_file, appname, d->d_name); CHECK(test_decode(enc_file, out_file, tablesize, streams, ackmode, appname) == 0); } From 9f1a5456a0e5e1c3f19e239b17ccc183b4425537 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 18 Sep 2018 00:38:27 +0900 Subject: [PATCH 0840/1313] Add QUICApplicationCloseFrame::debug_msg() --- iocore/net/quic/QUICFrame.cc | 22 ++++++++++++++++++++++ iocore/net/quic/QUICFrame.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 392696105cd..38569ee9899 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1281,6 +1281,8 @@ QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const int phrase_len = std::min(msg_len - len, static_cast(this->reason_phrase_length())); memcpy(msg + len, this->reason_phrase(), phrase_len); len += phrase_len; + msg[len] = '\0'; + ++len; } return len; @@ -1435,6 +1437,26 @@ QUICApplicationCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const return *len; } +int +QUICApplicationCloseFrame::debug_msg(char *msg, size_t msg_len) const +{ + int len = + snprintf(msg, msg_len, "| APPLICATION_CLOSE size=%zu code=%s", this->size(), QUICDebugNames::error_code(this->error_code())); + + if (this->reason_phrase_length() != 0 && this->reason_phrase() != nullptr) { + memcpy(msg + len, " reason=", 8); + len += 8; + + int phrase_len = std::min(msg_len - len, static_cast(this->reason_phrase_length())); + memcpy(msg + len, this->reason_phrase(), phrase_len); + len += phrase_len; + msg[len] = '\0'; + ++len; + } + + return len; +} + QUICAppErrorCode QUICApplicationCloseFrame::error_code() const { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 2453ec1cdfd..0143d969576 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -378,9 +378,11 @@ class QUICApplicationCloseFrame : public QUICFrame QUICApplicationCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase); QUICFrameUPtr clone() const override; + virtual int debug_msg(char *msg, size_t msg_len) const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + QUICAppErrorCode error_code() const; uint64_t reason_phrase_length() const; const char *reason_phrase() const; From e81a8c350690e5c1854f421d5f14acf14ba75fa7 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 18 Sep 2018 15:20:29 +0900 Subject: [PATCH 0841/1313] Add debug logs on sending/receiving QUIC packet --- iocore/net/QUICPacketHandler.cc | 34 +++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index e1b58daf5cb..168aa9a5ffd 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -107,6 +107,28 @@ QUICPacketHandler::_send_packet(Continuation *c, QUICNetVConnection *vc, Ptrcon.addr; UDPPacket *udp_packet = new_UDPPacket(addr, 0, udp_payload); + if (is_debug_tag_set(tag)) { + ip_port_text_buffer ipb; + QUICConnectionId dcid = QUICConnectionId::ZERO(); + QUICConnectionId scid = QUICConnectionId::ZERO(); + + const uint8_t *buf = reinterpret_cast(udp_payload->buf()); + uint64_t buf_len = udp_payload->size(); + + if (!QUICInvariants::dcid(dcid, buf, buf_len)) { + ink_assert(false); + } + + if (QUICInvariants::is_long_header(buf)) { + if (!QUICInvariants::scid(scid, buf, buf_len)) { + ink_assert(false); + } + } + + QUICDebugDS(dcid, scid, "send %s packet to %s size=%" PRId64, (QUICInvariants::is_long_header(buf) ? "LH" : "SH"), + ats_ip_nptop(&addr, ipb, sizeof(ipb)), buf_len); + } + udp_con->send(c, udp_packet); } @@ -377,10 +399,14 @@ QUICPacketHandlerOut::send_packet(QUICNetVConnection *vc, Ptr udp void QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet) { - ip_port_text_buffer ipb; - // TODO: print packet type - QUICDebugQC(this->_vc, "recv packet from %s size=%" PRId64, ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), - udp_packet->getPktLength()); + if (is_debug_tag_set(tag)) { + IOBufferBlock *block = udp_packet->getIOBlockChain(); + const uint8_t *buf = reinterpret_cast(block->buf()); + + ip_port_text_buffer ipb; + QUICDebugQC(this->_vc, "recv %s packet from %s size=%" PRId64, (QUICInvariants::is_long_header(buf) ? "LH" : "SH"), + ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); + } this->_vc->handle_received_packet(udp_packet); eventProcessor.schedule_imm(this->_vc, ET_CALL, QUIC_EVENT_PACKET_READ_READY, nullptr); From e6f705db3b5f0ee8c00aaff615fda0a21b394c1b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 19 Sep 2018 00:23:45 +0900 Subject: [PATCH 0842/1313] Print stream id in decimal in debug logs --- iocore/net/quic/QUICStream.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 32da6535b07..6d37419572d 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -29,15 +29,15 @@ #include "QUICDebugNames.h" #define QUICStreamDebug(fmt, ...) \ - Debug("quic_stream", "[%s] [%" PRIx64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ + Debug("quic_stream", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) #define QUICVStreamDebug(fmt, ...) \ - Debug("v_quic_stream", "[%s] [%" PRIx64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ + Debug("v_quic_stream", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) #define QUICStreamFCDebug(fmt, ...) \ - Debug("quic_flow_ctrl", "[%s] [%" PRIx64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ + Debug("quic_flow_ctrl", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; From 31527a02cd52ab871319a2769fe8ca9c658dc424 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 19 Sep 2018 20:14:32 +0900 Subject: [PATCH 0843/1313] [draft-14] Fix test_QUICTransportParameters --- iocore/net/quic/test/test_QUICTransportParameters.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index 8f563699117..43d66675c87 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -185,7 +185,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") 0x04, // size of supported versions 0x01, 0x02, 0x03, 0x04, // 0x00, 0x1a, // size of parameters - 0x00, 0x00, // parameter id + 0x00, 0x0a, // parameter id 0x00, 0x04, // length of value 0x11, 0x22, 0x33, 0x44, // value 0x00, 0x01, // parameter id @@ -204,7 +204,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") uint16_t len = 0; const uint8_t *data = nullptr; - data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, len); + data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, len); CHECK(len == 4); CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); @@ -286,20 +286,20 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") 0x01, 0x02, 0x03, 0x04, // version 1 0x05, 0x06, 0x07, 0x08, // version 2 0x00, 0x12, // size of parameters - 0x00, 0x00, // parameter id - 0x00, 0x04, // length of value - 0x11, 0x22, 0x33, 0x44, // value 0x00, 0x05, // parameter id 0x00, 0x02, // length of value 0xab, 0xcd, // value 0x00, 0x09, // parameter id 0x00, 0x00, // length of value + 0x00, 0x0a, // parameter id + 0x00, 0x04, // length of value + 0x11, 0x22, 0x33, 0x44, // value }; QUICTransportParametersInEncryptedExtensions params_in_ee(0x01020304); uint32_t max_stream_data = 0x11223344; - params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA, max_stream_data); + params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, max_stream_data); uint16_t max_packet_size = 0xabcd; params_in_ee.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size); From 1676ab5962c99beea51a8c34ea5823f27226a12e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 19 Sep 2018 20:58:21 +0900 Subject: [PATCH 0844/1313] Fix zero-length DCIL & SCIL --- iocore/net/quic/QUICPacket.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 054de41d3dd..c83148e352d 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -242,7 +242,9 @@ bool QUICPacketLongHeader::dcil(uint8_t &dcil, const uint8_t *packet, size_t packet_len) { if (QUICInvariants::dcil(dcil, packet, packet_len)) { - dcil += 3; + if (dcil != 0) { + dcil += 3; + } return true; } else { return false; @@ -253,7 +255,9 @@ bool QUICPacketLongHeader::scil(uint8_t &scil, const uint8_t *packet, size_t packet_len) { if (QUICInvariants::scil(scil, packet, packet_len)) { - scil += 3; + if (scil != 0) { + scil += 3; + } return true; } else { return false; From 1698fbac42297356fb20fd177ff423e60f553e7b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 19 Sep 2018 22:17:39 +0900 Subject: [PATCH 0845/1313] Omit zero-length DCID/SCID on sending packets --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICPacket.cc | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 40f20572a5d..63debc36b2d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1145,7 +1145,7 @@ QUICNetVConnection::_state_common_send_packet() written += len; // TODO: Avoid static function. We don't need to parse buffer again. Get packet number offset from packet. - QUICPacket::protect_packet_number(buf, len, &this->_pn_protector, this->_peer_quic_connection_id.length()); + QUICPacket::protect_packet_number(buf, len, &this->_pn_protector, (this->_peer_quic_connection_id == QUICConnectionId::ZERO()) ? 0 : this->_peer_quic_connection_id.length()); QUICConDebug("[TX] %s packet #%" PRIu64 " size=%zu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), len); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index c83148e352d..ed8301c8bac 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -465,14 +465,18 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const QUICTypeUtil::write_QUICVersion(this->_version, buf + *len, &n); *len += n; - buf[*len] = (this->_destination_cid.length() == 0 ? 0 : this->_destination_cid.length() - 3) << 4; - buf[*len] += this->_source_cid.length() == 0 ? 0 : this->_source_cid.length() - 3; + buf[*len] = this->_destination_cid == QUICConnectionId::ZERO() ? 0 : (this->_destination_cid.length() - 3) << 4; + buf[*len] += this->_source_cid == QUICConnectionId::ZERO() ? 0 : this->_source_cid.length() - 3; *len += 1; - QUICTypeUtil::write_QUICConnectionId(this->_destination_cid, buf + *len, &n); - *len += n; - QUICTypeUtil::write_QUICConnectionId(this->_source_cid, buf + *len, &n); - *len += n; + if (this->_destination_cid != QUICConnectionId::ZERO()) { + QUICTypeUtil::write_QUICConnectionId(this->_destination_cid, buf + *len, &n); + *len += n; + } + if (this->_source_cid != QUICConnectionId::ZERO()) { + QUICTypeUtil::write_QUICConnectionId(this->_source_cid, buf + *len, &n); + *len += n; + } if (this->_type != QUICPacketType::VERSION_NEGOTIATION) { if (this->_type == QUICPacketType::INITIAL) { @@ -662,7 +666,9 @@ uint16_t QUICPacketShortHeader::size() const { uint16_t len = 1; - len += this->_connection_id.length(); + if (this->_connection_id != QUICConnectionId::ZERO()) { + len += this->_connection_id.length(); + } len += this->_packet_number_len; return len; @@ -679,8 +685,11 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const } buf[0] += 0x30; *len += 1; - QUICTypeUtil::write_QUICConnectionId(this->_connection_id, buf + *len, &n); - *len += n; + + if (this->_connection_id != QUICConnectionId::ZERO()) { + QUICTypeUtil::write_QUICConnectionId(this->_connection_id, buf + *len, &n); + *len += n; + } QUICPacketNumber dst = 0; size_t dst_len = this->_packet_number_len; From 5f167189ae44847c912dcd5dcc7d55180219e3cc Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 20 Sep 2018 10:33:22 -0400 Subject: [PATCH 0846/1313] Fix several bugs in QPACK --- proxy/hq/QPACK.cc | 54 +++++++++++++++++++++++++++---------- proxy/hq/test/main_qpack.cc | 2 ++ proxy/hq/test/test_QPACK.cc | 5 ++-- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/proxy/hq/QPACK.cc b/proxy/hq/QPACK.cc index 00e76e172f5..0f14b24ac00 100644 --- a/proxy/hq/QPACK.cc +++ b/proxy/hq/QPACK.cc @@ -268,6 +268,7 @@ QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { this->_write_duplicate(current_index); QPACKDebug("Wrote Duplicate: current_index=%d", current_index); + this->_dynamic_table.ref_entry(current_index); } } } else if (lookup_result_static.match_type == LookupResult::MatchType::NAME) { @@ -277,8 +278,8 @@ QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock // Insert both the name and the value lookup_result_dynamic = this->_dynamic_table.insert_entry(lowered_name, name_len, value, value_len); if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { - this->_write_insert_without_name_ref(lowered_name, name_len, value, value_len); - QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, lowered_name, value_len, value); + this->_write_insert_with_name_ref(lookup_result_static.index, false, value, value_len); + QPACKDebug("Wrote Insert With Name Ref: index=%u, dynamic_table=%d value=%.*s", lookup_result_static.index, false, value_len, value); } } } else if (lookup_result_dynamic.match_type == LookupResult::MatchType::NAME) { @@ -290,6 +291,7 @@ QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { this->_write_duplicate(current_index); QPACKDebug("Wrote Duplicate: current_index=%d", current_index); + this->_dynamic_table.ref_entry(current_index); } } } else { @@ -300,13 +302,15 @@ QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { this->_write_duplicate(current_index); QPACKDebug("Wrote Duplicate: current_index=%d", current_index); + this->_dynamic_table.ref_entry(current_index); } } else { // Insert both the name and the value + uint16_t current_index = lookup_result_dynamic.index; lookup_result_dynamic = this->_dynamic_table.insert_entry(lowered_name, name_len, value, value_len); if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { - this->_write_insert_without_name_ref(lowered_name, name_len, value, value_len); - QPACKDebug("Wrote Insert Without Name Ref: name=%.*s value=%.*s", name_len, lowered_name, value_len, value); + this->_write_insert_with_name_ref(current_index, true, value, value_len); + QPACKDebug("Wrote Insert With Name Ref: index=%u, dynamic_table=%d, value=%.*s", current_index, true, value_len, value); } } } @@ -863,7 +867,9 @@ void QPACK::_update_reference_counts(uint64_t stream_id) { uint16_t smallest_ref_index = this->_references[stream_id].smallest; - this->_dynamic_table.unref_entry(smallest_ref_index); + if (smallest_ref_index) { + this->_dynamic_table.unref_entry(smallest_ref_index); + } } void @@ -1135,6 +1141,8 @@ QPACK::DynamicTable::~DynamicTable() const QPACK::LookupResult QPACK::DynamicTable::lookup(uint16_t index, const char **name, int *name_len, const char **value, int *value_len) { + // ink_assert(index >= this->_entries[(this->_entries_tail + 1) % this->_max_entries].index); + // ink_assert(index <= this->_entries[this->_entries_head].index); uint16_t pos = (this->_entries_head + (index - this->_entries[this->_entries_head].index)) % this->_max_entries; *name_len = this->_entries[pos].name_len; *value_len = this->_entries[pos].value_len; @@ -1146,14 +1154,14 @@ const QPACK::LookupResult QPACK::DynamicTable::lookup(const char *name, int name_len, const char *value, int value_len) { QPACK::LookupResult::MatchType match_type = QPACK::LookupResult::MatchType::NONE; - uint16_t i = 0; + uint16_t i = this->_entries_tail + 1; + int end = this->_entries_head; uint16_t candidate_index = 0; const char *tmp_name = nullptr; const char *tmp_value = nullptr; - int n = this->_max_entries; // TODO Use a tree for better perfomance - for (; i < n; ++i) { + for (; i <= end; i = (i + 1) % this->_max_entries) { if (name_len != 0 && this->_entries[i].name_len == name_len) { this->_storage->read(this->_entries[i].offset, &tmp_name, this->_entries[i].name_len, &tmp_value, this->_entries[i].value_len); @@ -1195,13 +1203,14 @@ QPACK::DynamicTable::insert_entry(const char *name, uint16_t name_len, const cha // Check if we can make enough space to insert a new entry uint16_t required_len = name_len + value_len; uint16_t available = this->_available; - uint16_t tail = this->_entries_tail; + uint16_t tail = (this->_entries_tail + 1) % this->_max_entries; while (available < required_len) { if (this->_entries[tail].ref_count) { break; } available += this->_entries[tail].name_len + this->_entries[tail].value_len; tail = (tail + 1) % this->_max_entries; + } if (available < required_len) { // We can't insert a new entry because some stream(s) refer an entry that need to be evicted @@ -1209,8 +1218,12 @@ QPACK::DynamicTable::insert_entry(const char *name, uint16_t name_len, const cha } // Evict - this->_available = available; - this->_entries_tail = tail; + if (this->_available != available) { + QPACKDTDebug("Evict entries: from %u to %u", this->_entries[(this->_entries_tail + 1) % this->_max_entries].index, this->_entries[tail - 1].index); + this->_available = available; + this->_entries_tail = tail - 1; + QPACKDTDebug("Available size: %u", this->_available); + } // Insert this->_entries_head = (this->_entries_head + 1) % this->_max_entries; @@ -1218,6 +1231,8 @@ QPACK::DynamicTable::insert_entry(const char *name, uint16_t name_len, const cha name_len, value_len, 0}; this->_available -= required_len; + QPACKDTDebug("Insert Entry: entry=%u, index=%u, size=%u", this->_entries_head, this->_entries_inserted, name_len + value_len); + QPACKDTDebug("Available size: %u", this->_available); return {this->_entries_inserted, value_len ? LookupResult::MatchType::EXACT : LookupResult::MatchType::NAME}; } @@ -1228,9 +1243,18 @@ QPACK::DynamicTable::duplicate_entry(uint16_t current_index) int name_len; const char *value; int value_len; + char *duped_name; + char *duped_value; this->lookup(current_index, &name, &name_len, &value, &value_len); - return this->insert_entry(name, name_len, value, value_len); + // We need to dup name and value to avoid memcpy-param-overlap + duped_name = ats_strndup(name, name_len); + duped_value = ats_strndup(value, value_len); + const LookupResult result = this->insert_entry(duped_name, name_len, duped_value, value_len); + ats_free(duped_name); + ats_free(duped_value); + + return result; } bool @@ -1250,13 +1274,15 @@ QPACK::DynamicTable::update_size(uint16_t max_size) void QPACK::DynamicTable::ref_entry(uint16_t index) { - ++this->_entries[index].ref_count; + uint16_t pos = (this->_entries_head + (index - this->_entries[this->_entries_head].index)) % this->_max_entries; + ++this->_entries[pos].ref_count; } void QPACK::DynamicTable::unref_entry(uint16_t index) { - --this->_entries[index].ref_count; + uint16_t pos = (this->_entries_head + (index - this->_entries[this->_entries_head].index)) % this->_max_entries; + --this->_entries[pos].ref_count; } uint16_t diff --git a/proxy/hq/test/main_qpack.cc b/proxy/hq/test/main_qpack.cc index cba1230ec8d..8d7a58072dc 100644 --- a/proxy/hq/test/main_qpack.cc +++ b/proxy/hq/test/main_qpack.cc @@ -47,6 +47,7 @@ int tablesize = 4096; int streams = 100; int ackmode = 0; char appname[256] = "ats"; +char pattern[256] = ""; struct EventProcessorListener : Catch::TestEventListenerBase { using TestEventListenerBase::TestEventListenerBase; // inherit constructor @@ -92,6 +93,7 @@ main(int argc, char *argv[]) Opt(tablesize, "size")["--q-dynamic-table-size"]("dynamic table size for encoding: 0-65535 (default:4096)") | Opt(streams, "n")["--q-max-blocked-streams"]("max blocked streams for encoding: 0-65535 (default:100)") | Opt(ackmode, "mode")["--q-ack-mode"]("acknowledgement modes for encoding: none(default:0) or immediate(1)") | + Opt(pattern, "pattern")["--q-pattern"]("filename pattern: file name pattern for decoding (default:)") | Opt(appname, "app")["--q-app"]("app name: app name (default:ats)"); session.cli(cli); diff --git a/proxy/hq/test/test_QPACK.cc b/proxy/hq/test/test_QPACK.cc index a4b71e57035..02fd505ad3e 100644 --- a/proxy/hq/test/test_QPACK.cc +++ b/proxy/hq/test/test_QPACK.cc @@ -38,6 +38,7 @@ extern int tablesize; extern int streams; extern int ackmode; extern char appname[256]; +extern char pattern[256]; constexpr int ACK_MODE_IMMEDIATE = 1; constexpr int ACK_MODE_NONE = 0; @@ -364,7 +365,7 @@ test_decode(const char *enc_file, const char *out_file, int dts, int mbs, int am return -1; } - sleep(5); + sleep(1); CHECK(event_handler->last_event() == QPACK_EVENT_DECODE_COMPLETE); @@ -427,11 +428,9 @@ TEST_CASE("Decoding", "[qpack-decode]") struct stat st; char enc_file[PATH_MAX + 1] = ""; char out_file[PATH_MAX + 1] = ""; - char pattern[PATH_MAX + 1] = ""; strcat(enc_file, encdir); strcat(out_file, decdir); - sprintf(pattern, ".%d.%d.%d", tablesize, streams, ackmode); while ((d = readdir(dir)) != nullptr) { char section_name[128]; sprintf(section_name, "%s: DTS=%d, MBS=%d, AM=%d, APP=%s", d->d_name, tablesize, streams, ackmode, appname); From 4b2821ad4d40436bfa00f903a946e75ecc644264 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 25 Sep 2018 13:59:58 +0900 Subject: [PATCH 0847/1313] Replace libtsutil.la with libtscore.la --- src/traffic_quic/Makefile.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/traffic_quic/Makefile.inc b/src/traffic_quic/Makefile.inc index 8a6e9f6251b..3325faa1b96 100644 --- a/src/traffic_quic/Makefile.inc +++ b/src/traffic_quic/Makefile.inc @@ -47,10 +47,10 @@ traffic_quic_traffic_quic_LDADD = \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/lib/ts/libtsutil.la \ + $(top_builddir)/src/tscore/libtscore.la \ $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ @LIBTCL@ \ @HWLOC_LIBS@ \ - @YAMLCPP_LIBS@ \ + @YAMLCPP_LIBS@ \ @OPENSSL_LIBS@ From 904d2c8698b5d0e9df97d085eb75d7dacd7ed7db Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 26 Sep 2018 14:31:44 +0900 Subject: [PATCH 0848/1313] Cleanup: rename _state_common_receive_packet and _state_connection_established_process_packet - _state_common_receive_packet() -> _state_connection_established_receive_packet() - _state_connection_established_process_packet(QUICPacketUPtr packet) -> _state_connection_established_process_protected_packet(QUICPacketUPtr packet) --- iocore/net/P_QUICNetVConnection.h | 13 +++++++------ iocore/net/QUICNetVConnection.cc | 8 ++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 27ce729af66..5f19070db57 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -125,19 +125,20 @@ class SSLNextProtocolSet; * v * state_connection_established() * | READ: - * | _state_connection_established_process_packet() + * | _state_connection_established_receive_packet() + * | _state_connection_established_process_protected_packet() * | WRITE: * | _state_common_send_packet() * v * state_connection_closing() (If closing actively) * | READ: - * | _state_connection_established_process_packet() + * | _state_closing_receive_packet() * | WRITE: - * | _state_common_send_packet() + * | _state_closing_send_packet() * v * state_connection_draining() (If closing passively) * | READ: - * | _state_connection_established_process_packet() + * | _state_draining_receive_packet() * | WRITE: * | Do nothing * v @@ -311,8 +312,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICErrorUPtr _state_handshake_process_retry_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_handshake_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); - QUICErrorUPtr _state_connection_established_process_packet(QUICPacketUPtr packet); - QUICErrorUPtr _state_common_receive_packet(); + QUICErrorUPtr _state_connection_established_receive_packet(); + QUICErrorUPtr _state_connection_established_process_protected_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_closing_receive_packet(); QUICErrorUPtr _state_draining_receive_packet(); QUICErrorUPtr _state_common_send_packet(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index eef67856949..bde994b1115 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -629,7 +629,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (event) { case QUIC_EVENT_PACKET_READ_READY: { - error = this->_state_common_receive_packet(); + error = this->_state_connection_established_receive_packet(); break; } case QUIC_EVENT_PACKET_WRITE_READY: { @@ -984,13 +984,13 @@ QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacke } QUICErrorUPtr -QUICNetVConnection::_state_connection_established_process_packet(QUICPacketUPtr packet) +QUICNetVConnection::_state_connection_established_process_protected_packet(QUICPacketUPtr packet) { return this->_recv_and_ack(std::move(packet)); } QUICErrorUPtr -QUICNetVConnection::_state_common_receive_packet() +QUICNetVConnection::_state_connection_established_receive_packet() { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); QUICPacketCreationResult result; @@ -1030,7 +1030,7 @@ QUICNetVConnection::_state_common_receive_packet() break; } } - error = this->_state_connection_established_process_packet(std::move(p)); + error = this->_state_connection_established_process_protected_packet(std::move(p)); break; case QUICPacketType::INITIAL: case QUICPacketType::HANDSHAKE: From 1c9fa8b03b8834dd8e46ff331936d3d1d7ab6ff5 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 27 Sep 2018 11:47:29 +0900 Subject: [PATCH 0849/1313] Print cid field of NEW_CONNECTION_ID on debug log --- iocore/net/quic/QUICAltConnectionManager.cc | 8 ++++---- iocore/net/quic/QUICFrame.cc | 9 +++++++++ iocore/net/quic/QUICFrame.h | 1 + 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 044e02a5e48..eb3da7bd519 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -25,9 +25,9 @@ #include "QUICConnectionTable.h" #include "QUICConfig.h" -static constexpr char DEBUG_TAG[] = "quic_alt_con"; +static constexpr char V_DEBUG_TAG[] = "v_quic_alt_con"; -#define QUICACMDebug(fmt, ...) Debug(DEBUG_TAG, "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) +#define QUICACMVDebug(fmt, ...) Debug(V_DEBUG_TAG, "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable) : _qc(qc), _ctable(ctable) { @@ -71,10 +71,10 @@ QUICAltConnectionManager::_update_alt_connection_ids(int8_t chosen) this->_alt_quic_connection_ids[index] = {this->_alt_quic_connection_id_seq_num + i, conn_id, token, false}; this->_ctable.insert(conn_id, this->_qc); - if (is_debug_tag_set(DEBUG_TAG)) { + 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); - QUICACMDebug("alt-cid=%s", new_cid_str); + QUICACMVDebug("alt-cid=%s", new_cid_str); } } this->_alt_quic_connection_id_seq_num += count; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 38569ee9899..c002e9fd434 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2040,6 +2040,15 @@ QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len, size_t limit) const return *len; } +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 cid=0x%s", this->size(), cid_str); +} + uint64_t QUICNewConnectionIdFrame::sequence() const { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index f4511fad0ad..ed95b2cf8ef 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -561,6 +561,7 @@ class QUICNewConnectionIdFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual int debug_msg(char *msg, size_t msg_len) const override; uint64_t sequence() const; QUICConnectionId connection_id() const; From 1a5e471d5b60946216ab132150665e5cc7f8f77c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 27 Sep 2018 11:53:48 +0900 Subject: [PATCH 0850/1313] Ran clang-format --- iocore/net/QUICNetVConnection.cc | 4 +++- proxy/hq/QPACK.cc | 13 +++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index bde994b1115..ed9b4217fc1 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1145,7 +1145,9 @@ QUICNetVConnection::_state_common_send_packet() written += len; // TODO: Avoid static function. We don't need to parse buffer again. Get packet number offset from packet. - QUICPacket::protect_packet_number(buf, len, &this->_pn_protector, (this->_peer_quic_connection_id == QUICConnectionId::ZERO()) ? 0 : this->_peer_quic_connection_id.length()); + QUICPacket::protect_packet_number( + buf, len, &this->_pn_protector, + (this->_peer_quic_connection_id == QUICConnectionId::ZERO()) ? 0 : this->_peer_quic_connection_id.length()); QUICConDebug("[TX] %s packet #%" PRIu64 " size=%zu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), len); diff --git a/proxy/hq/QPACK.cc b/proxy/hq/QPACK.cc index bc1925d8b28..b1fb3e6df85 100644 --- a/proxy/hq/QPACK.cc +++ b/proxy/hq/QPACK.cc @@ -279,7 +279,8 @@ QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock lookup_result_dynamic = this->_dynamic_table.insert_entry(lowered_name, name_len, value, value_len); if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { this->_write_insert_with_name_ref(lookup_result_static.index, false, value, value_len); - QPACKDebug("Wrote Insert With Name Ref: index=%u, dynamic_table=%d value=%.*s", lookup_result_static.index, false, value_len, value); + QPACKDebug("Wrote Insert With Name Ref: index=%u, dynamic_table=%d value=%.*s", lookup_result_static.index, false, + value_len, value); } } } else if (lookup_result_dynamic.match_type == LookupResult::MatchType::NAME) { @@ -307,7 +308,7 @@ QPACK::_encode_header(const MIMEField &field, uint16_t base_index, IOBufferBlock } else { // Insert both the name and the value uint16_t current_index = lookup_result_dynamic.index; - lookup_result_dynamic = this->_dynamic_table.insert_entry(lowered_name, name_len, value, value_len); + lookup_result_dynamic = this->_dynamic_table.insert_entry(lowered_name, name_len, value, value_len); if (lookup_result_dynamic.match_type != LookupResult::MatchType::NONE) { this->_write_insert_with_name_ref(current_index, true, value, value_len); QPACKDebug("Wrote Insert With Name Ref: index=%u, dynamic_table=%d, value=%.*s", current_index, true, value_len, value); @@ -1210,7 +1211,6 @@ QPACK::DynamicTable::insert_entry(const char *name, uint16_t name_len, const cha } available += this->_entries[tail].name_len + this->_entries[tail].value_len; tail = (tail + 1) % this->_max_entries; - } if (available < required_len) { // We can't insert a new entry because some stream(s) refer an entry that need to be evicted @@ -1219,7 +1219,8 @@ QPACK::DynamicTable::insert_entry(const char *name, uint16_t name_len, const cha // Evict if (this->_available != available) { - QPACKDTDebug("Evict entries: from %u to %u", this->_entries[(this->_entries_tail + 1) % this->_max_entries].index, this->_entries[tail - 1].index); + QPACKDTDebug("Evict entries: from %u to %u", this->_entries[(this->_entries_tail + 1) % this->_max_entries].index, + this->_entries[tail - 1].index); this->_available = available; this->_entries_tail = tail - 1; QPACKDTDebug("Available size: %u", this->_available); @@ -1248,8 +1249,8 @@ QPACK::DynamicTable::duplicate_entry(uint16_t current_index) this->lookup(current_index, &name, &name_len, &value, &value_len); // We need to dup name and value to avoid memcpy-param-overlap - duped_name = ats_strndup(name, name_len); - duped_value = ats_strndup(value, value_len); + duped_name = ats_strndup(name, name_len); + duped_value = ats_strndup(value, value_len); const LookupResult result = this->insert_entry(duped_name, name_len, duped_value, value_len); ats_free(duped_name); ats_free(duped_value); From d054c42cc8bfda86ca465cb6caed13e9374e098f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 27 Sep 2018 12:35:15 +0900 Subject: [PATCH 0851/1313] Improve connection migration implementation - Store advertised Connection IDs - Initiate Connection Migration from client side To start connection migration exercise, set `proxy.config.quic.client.cm_exercise_enabled` 1. ``` PROXY_CONFIG_QUIC_CLIENT_CM_EXERCISE_ENABLED=1 /opt/ats/bin/traffic_quic ``` --- iocore/net/P_QUICNetVConnection.h | 4 + iocore/net/QUICNetVConnection.cc | 118 +++++++++++++++----- iocore/net/quic/QUICAltConnectionManager.cc | 4 +- iocore/net/quic/QUICConfig.cc | 7 ++ iocore/net/quic/QUICConfig.h | 2 + mgmt/RecordsConfig.cc | 2 + 6 files changed, 110 insertions(+), 27 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 5f19070db57..00a1d95db57 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -237,6 +237,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICConnectionId _quic_connection_id; // src cid in local QUICFiveTuple _five_tuple; bool _connection_migration_initiated = false; + // TODO: Revisit life cycle of cids when draft-15 is published + std::queue _remote_alt_cids; char _cids_data[MAX_CIDS_SIZE] = {0}; std::string_view _cids; @@ -314,6 +316,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_connection_established_receive_packet(); QUICErrorUPtr _state_connection_established_process_protected_packet(QUICPacketUPtr packet); + QUICErrorUPtr _state_connection_established_migrate_connection(const QUICPacket &p); + QUICErrorUPtr _state_connection_established_initiate_connection_migration(); QUICErrorUPtr _state_closing_receive_packet(); QUICErrorUPtr _state_draining_receive_packet(); QUICErrorUPtr _state_common_send_packet(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ed9b4217fc1..81171226637 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -511,14 +511,7 @@ QUICNetVConnection::_handle_frame(const QUICNewConnectionIdFrame &frame) QUICFrameType::NEW_CONNECTION_ID); } - if (this->netvc_context == NET_VCONNECTION_IN && this->_connection_migration_initiated) { - // For connection migration testing, server update peer cid every time when it's offered - // TODO: update peer cid only if client's local adress is changed - this->_connection_migration_initiated = false; - this->_update_peer_cid(frame.connection_id()); - } else { - // TODO: on client side, store offered alt cids from server - } + this->_remote_alt_cids.push(frame.connection_id()); return error; } @@ -1012,24 +1005,16 @@ QUICNetVConnection::_state_connection_established_receive_packet() // Process the packet switch (p->type()) { case QUICPacketType::PROTECTED: - // Check connection migration - if (this->_handshake_handler->is_completed() && p->destination_cid() != this->_quic_connection_id) { - if (this->_alt_con_manager->migrate_to(p->destination_cid(), this->_reset_token)) { - // Migrate connection - this->_update_local_cid(p->destination_cid()); - Connection con; - con.setRemote(&p->from().sa); - this->con.move(con); - QUICConDebug("Connection migrated"); - this->_connection_migration_initiated = true; - this->_validate_new_path(); - } else { - char dcid_str[QUICConnectionId::MAX_HEX_STR_LENGTH]; - p->destination_cid().hex(dcid_str, QUICConnectionId::MAX_HEX_STR_LENGTH); - QUICConDebug("Connection migration failed cid=%s", dcid_str); - break; - } + // Migrate connection if required + error = this->_state_connection_established_migrate_connection(*p); + if (error->cls != QUICErrorClass::NONE) { + break; } + + if (this->netvc_context == NET_VCONNECTION_OUT) { + this->_state_connection_established_initiate_connection_migration(); + } + error = this->_state_connection_established_process_protected_packet(std::move(p)); break; case QUICPacketType::INITIAL: @@ -1755,7 +1740,11 @@ QUICNetVConnection::_switch_to_established_state() SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); - if (netvc_context == NET_VCONNECTION_IN) { + std::shared_ptr remote_tp = this->_handshake_handler->remote_transport_parameters(); + QUICConfig::scoped_config params; + + if (netvc_context == NET_VCONNECTION_IN || (netvc_context == NET_VCONNECTION_OUT && params->cm_exercise_enabled() && + !remote_tp->contains(QUICTransportParameterId::DISABLE_MIGRATION))) { this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable); } } else { @@ -1924,3 +1913,80 @@ QUICNetVConnection::_setup_handshake_protocol(SSL_CTX *ctx) SSL_set_ex_data(tls->ssl_handle(), QUIC::ssl_quic_qc_index, static_cast(this)); return tls; } + +QUICErrorUPtr +QUICNetVConnection::_state_connection_established_migrate_connection(const QUICPacket &p) +{ + ink_assert(this->_handshake_handler->is_completed()); + + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionId dcid = p.destination_cid(); + + if (dcid == this->_quic_connection_id) { + return error; + } + + if (this->netvc_context == NET_VCONNECTION_IN) { + if (this->_remote_alt_cids.empty()) { + // TODO: Should endpoint send connection error when remote endpoint doesn't send NEW_CONNECTION_ID frames before initiating + // connection migration ? + QUICConDebug("Ignore connection migration - remote endpoint initiated CM before sending NEW_CONNECTION_ID frames"); + + return error; + } else { + QUICConDebug("Connection migration is initiated by remote"); + } + } + + if (this->_alt_con_manager->migrate_to(dcid, this->_reset_token)) { + // DCID of received packet is local cid + this->_update_local_cid(dcid); + + // On client side (NET_VCONNECTION_OUT), nothing to do any more + if (this->netvc_context == NET_VCONNECTION_IN) { + Connection con; + con.setRemote(&(p.from().sa)); + this->con.move(con); + + this->_update_peer_cid(this->_remote_alt_cids.front()); + this->_remote_alt_cids.pop(); + this->_validate_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); + } + + return error; +} + +/** + * Connection Migration Excercise from client + */ +QUICErrorUPtr +QUICNetVConnection::_state_connection_established_initiate_connection_migration() +{ + ink_assert(this->_handshake_handler->is_completed()); + ink_assert(this->netvc_context == NET_VCONNECTION_OUT); + + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + + std::shared_ptr remote_tp = this->_handshake_handler->remote_transport_parameters(); + QUICConfig::scoped_config params; + + if (!params->cm_exercise_enabled() || this->_connection_migration_initiated || + remote_tp->contains(QUICTransportParameterId::DISABLE_MIGRATION) || this->_remote_alt_cids.empty()) { + return error; + } + + QUICConDebug("Initiated connection migration"); + this->_connection_migration_initiated = true; + + this->_update_peer_cid(this->_remote_alt_cids.front()); + this->_remote_alt_cids.pop(); + + this->_validate_new_path(); + + return error; +} diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index eb3da7bd519..bdf09e76dba 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -69,7 +69,9 @@ QUICAltConnectionManager::_update_alt_connection_ids(int8_t chosen) conn_id.randomize(); token.generate(conn_id, params->server_id()); this->_alt_quic_connection_ids[index] = {this->_alt_quic_connection_id_seq_num + i, conn_id, token, false}; - this->_ctable.insert(conn_id, this->_qc); + if (this->_qc->direction() == NET_VCONNECTION_IN) { + this->_ctable.insert(conn_id, this->_qc); + } if (is_debug_tag_set(V_DEBUG_TAG)) { char new_cid_str[QUICConnectionId::MAX_HEX_STR_LENGTH]; diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index e3605385315..1ce79c81201 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -138,6 +138,7 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_max_alt_connection_ids, "proxy.config.quic.max_alt_connection_ids"); REC_EstablishStaticConfigInt32U(this->_stateless_retry, "proxy.config.quic.stateless_retry"); 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_ReadConfigStringAlloc(this->_server_supported_groups, "proxy.config.quic.server.supported_groups"); REC_ReadConfigStringAlloc(this->_client_supported_groups, "proxy.config.quic.client.supported_groups"); @@ -235,6 +236,12 @@ QUICConfigParams::vn_exercise_enabled() const return this->_vn_exercise_enabled; } +uint32_t +QUICConfigParams::cm_exercise_enabled() const +{ + return this->_cm_exercise_enabled; +} + uint32_t QUICConfigParams::initial_max_data_in() const { diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index f7d93735010..88953de3dc1 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -39,6 +39,7 @@ class QUICConfigParams : public ConfigInfo uint32_t max_alt_connection_ids() const; uint32_t stateless_retry() const; uint32_t vn_exercise_enabled() const; + uint32_t cm_exercise_enabled() const; const char *server_supported_groups() const; const char *client_supported_groups() const; @@ -90,6 +91,7 @@ class QUICConfigParams : public ConfigInfo uint32_t _max_alt_connection_ids = 0; uint32_t _stateless_retry = 0; uint32_t _vn_exercise_enabled = 0; + uint32_t _cm_exercise_enabled = 0; char *_server_supported_groups = nullptr; char *_client_supported_groups = nullptr; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 243cd92f9e1..f275de01a74 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1339,6 +1339,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.client.vn_exercise_enabled", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.client.cm_exercise_enabled", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} + , {RECT_CONFIG, "proxy.config.quic.server.supported_groups", RECD_STRING, "P-256:X25519:P-384:P-521" , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.client.supported_groups", RECD_STRING, "P-256:X25519:P-384:P-521" , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} From db38d2f865f0c8cb54eabdb3d1bc16edc29a9091 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 27 Sep 2018 16:22:41 +0900 Subject: [PATCH 0852/1313] Stop sending STREAM frame while proving a new path --- iocore/net/QUICNetVConnection.cc | 30 +++++++++++++++------------- iocore/net/quic/QUICPathValidator.cc | 6 ++++++ iocore/net/quic/QUICPathValidator.h | 1 + 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 81171226637..57611835b88 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1298,22 +1298,24 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } // STREAM, MAX_STREAM_DATA, STREAM_BLOCKED - frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); - while (frame) { - ++frame_count; - if (frame->type() == QUICFrameType::STREAM) { - int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); - QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); - ink_assert(ret == 0); - } - this->_store_frame(buf, len, max_frame_size, std::move(frame)); + if (!this->_path_validator->is_validating()) { + frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + while (frame) { + ++frame_count; + if (frame->type() == QUICFrameType::STREAM) { + int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); + QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); + ink_assert(ret == 0); + } + this->_store_frame(buf, len, max_frame_size, std::move(frame)); - if (++this->_stream_frames_sent % MAX_CONSECUTIVE_STREAMS == 0) { - break; - } + if (++this->_stream_frames_sent % MAX_CONSECUTIVE_STREAMS == 0) { + break; + } - frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + } } // ACK diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index f9d1b2b0ae0..f222d7c8df7 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -23,6 +23,12 @@ #include "QUICPathValidator.h" +bool +QUICPathValidator::is_validating() +{ + return this->_state == ValidationState::VALIDATING; +} + bool QUICPathValidator::is_validated() { diff --git a/iocore/net/quic/QUICPathValidator.h b/iocore/net/quic/QUICPathValidator.h index d13723f75c5..260ed006f81 100644 --- a/iocore/net/quic/QUICPathValidator.h +++ b/iocore/net/quic/QUICPathValidator.h @@ -32,6 +32,7 @@ class QUICPathValidator : public QUICFrameHandler, public QUICFrameGenerator { public: QUICPathValidator() {} + bool is_validating(); bool is_validated(); void validate(); From 43ce284fed15d455be127c008261444cb51b8382 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 28 Sep 2018 15:09:36 +0900 Subject: [PATCH 0853/1313] Do not initiate connection migration before advertising new connection ids --- iocore/net/QUICNetVConnection.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 57611835b88..45ffa0fe02f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1978,7 +1978,8 @@ QUICNetVConnection::_state_connection_established_initiate_connection_migration( QUICConfig::scoped_config params; if (!params->cm_exercise_enabled() || this->_connection_migration_initiated || - remote_tp->contains(QUICTransportParameterId::DISABLE_MIGRATION) || this->_remote_alt_cids.empty()) { + remote_tp->contains(QUICTransportParameterId::DISABLE_MIGRATION) || this->_remote_alt_cids.empty() || + this->_alt_con_manager->will_generate_frame(QUICEncryptionLevel::ONE_RTT)) { return error; } From 304ca803270207dbd47f238d7ddb73996e7936be Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 28 Sep 2018 17:56:11 +0900 Subject: [PATCH 0854/1313] Restore unit test for full handshake with HRR --- .../quic/test/test_QUICHandshakeProtocol.cc | 256 ++++++++++-------- 1 file changed, 139 insertions(+), 117 deletions(-) diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index cf81b88559a..e7aa31c0ca5 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -289,6 +289,145 @@ TEST_CASE("QUICHandshakeProtocol") delete server; } + SECTION("Full Handshake with HRR", "[quic]") + { + // client key_share will be X25519 (default of OpenSSL) + if (SSL_CTX_set1_groups_list(server_ssl_ctx, "P-521:P-384:P-256") != 1) { + REQUIRE(false); + } + + QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); + QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); + + CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + + // CH + QUICHandshakeMsgs msg1; + uint8_t msg1_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg1.buf = msg1_buf; + msg1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + REQUIRE(client->handshake(&msg1, nullptr) == 1); + std::cout << "### Messages from client" << std::endl; + print_hex(msg1.buf, msg1.offsets[4]); + + // HRR + QUICHandshakeMsgs msg2; + uint8_t msg2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2.buf = msg2_buf; + msg2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + REQUIRE(server->handshake(&msg2, &msg1) == 1); + std::cout << "### Messages from server" << std::endl; + print_hex(msg2.buf, msg2.offsets[4]); + + // CH + QUICHandshakeMsgs msg3; + uint8_t msg3_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg3.buf = msg3_buf; + msg3.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + REQUIRE(client->handshake(&msg3, &msg2) == 1); + std::cout << "### Messages from client" << std::endl; + print_hex(msg3.buf, msg3.offsets[4]); + + // SH, EE, CERT, CV, FIN + QUICHandshakeMsgs msg4; + uint8_t msg4_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg4.buf = msg4_buf; + msg4.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + REQUIRE(server->handshake(&msg4, &msg3) == 1); + std::cout << "### Messages from server" << std::endl; + print_hex(msg4.buf, msg4.offsets[4]); + + // FIN + QUICHandshakeMsgs msg5; + uint8_t msg5_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg5.buf = msg5_buf; + msg5.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + +#ifdef SSL_MODE_QUIC_HACK + // -- Hacks for OpenSSL with SSL_MODE_QUIC_HACK -- + // SH + QUICHandshakeMsgs msg4_1; + uint8_t msg4_1_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg4_1.buf = msg4_1_buf; + msg4_1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + memcpy(msg4_1.buf, msg4.buf, msg4.offsets[1]); + msg4_1.offsets[0] = 0; + msg4_1.offsets[1] = msg4.offsets[1]; + msg4_1.offsets[2] = msg4.offsets[1]; + msg4_1.offsets[3] = msg4.offsets[1]; + msg4_1.offsets[4] = msg4.offsets[1]; + + // EE - FIN + QUICHandshakeMsgs msg4_2; + uint8_t msg4_2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg4_2.buf = msg4_2_buf; + msg4_2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + size_t len = msg4.offsets[3] - msg4.offsets[2]; + memcpy(msg4_2.buf, msg4.buf + msg4.offsets[1], len); + msg4_2.offsets[0] = 0; + msg4_2.offsets[1] = 0; + msg4_2.offsets[2] = 0; + msg4_2.offsets[3] = len; + msg4_2.offsets[4] = len; + + REQUIRE(client->handshake(&msg5, &msg4_1) == 1); + REQUIRE(client->handshake(&msg5, &msg4_2) == 1); +#else + REQUIRE(client->handshake(&msg5, &msg4) == 1); +#endif + std::cout << "### Messages from client" << std::endl; + print_hex(msg5.buf, msg5.offsets[4]); + + // NS + QUICHandshakeMsgs msg6; + uint8_t msg6_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg6.buf = msg6_buf; + msg6.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + REQUIRE(server->handshake(&msg6, &msg5) == 1); + std::cout << "### Messages from server" << std::endl; + print_hex(msg6.buf, msg6.offsets[4]); + + // encrypt - decrypt + // client (encrypt) - server (decrypt) + std::cout << "### Original Text" << std::endl; + print_hex(original, sizeof(original)); + + uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead + size_t cipher_len = 0; + CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), + QUICKeyPhase::PHASE_0)); + + std::cout << "### Encrypted Text" << std::endl; + print_hex(cipher, cipher_len); + + uint8_t plain[128] = {0}; + size_t plain_len = 0; + CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); + + std::cout << "### Decrypted Text" << std::endl; + print_hex(plain, plain_len); + + CHECK(sizeof(original) == (plain_len)); + CHECK(memcmp(original, plain, plain_len) == 0); + + // Teardown + // Make it back to the default settings + if (SSL_CTX_set1_groups_list(server_ssl_ctx, "X25519:P-521:P-384:P-256") != 1) { + REQUIRE(false); + } + + delete client; + delete server; + } + SECTION("Alert", "[quic]") { QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); @@ -332,123 +471,6 @@ TEST_CASE("QUICHandshakeProtocol") SSL_CTX_free(client_ssl_ctx); } -// // HRR - Incorrect DHE Share -// // NOTE: This is *NOT* client address validation. -// // https://tools.ietf.org/html/draft-ietf-tls-tls13-26 - 2.1. Incorrect DHE Share -// TEST_CASE("QUICHandshakeProtocol 1-RTT HRR key_share mismatch", "[quic]") -// { -// // Client -// SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); -// SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); -// SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); -// SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); -// -// QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); -// -// // Server -// SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); -// SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); -// SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); -// SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); -// BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); -// SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); -// BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); -// SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); -// -// // client key_share will be X25519 (default of OpenSSL) -// if (SSL_CTX_set1_groups_list(server_ssl_ctx, "P-521:P-384:P-256") != 1) { -// REQUIRE(false); -// } -// -// QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); -// -// CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); -// CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); -// -// // Client Hello -// uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; -// size_t client_hello_len = 0; -// REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); -// REQUIRE(client_hello_len > 0); -// std::cout << "### Client Hello" << std::endl; -// print_hex(client_hello, client_hello_len); -// -// // Hello Retry Request w/o cookie -// uint8_t retry[MAX_HANDSHAKE_MSG_LEN] = {0}; -// size_t retry_len = 0; -// REQUIRE(server->handshake(retry, retry_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == SSL_ERROR_WANT_READ); -// REQUIRE(retry_len > 0); -// REQUIRE(is_hrr(retry, retry_len)); -// std::cout << "### HRR" << std::endl; -// print_hex(retry, retry_len); -// -// // Client Hello w/ cookie -// memset(client_hello, 0, MAX_HANDSHAKE_MSG_LEN); -// client_hello_len = 0; -// REQUIRE(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, retry, retry_len) == SSL_ERROR_WANT_READ); -// REQUIRE(client_hello_len > 0); -// std::cout << "### Client Hello" << std::endl; -// print_hex(client_hello, client_hello_len); -// -// // Server Hello -// uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; -// size_t server_hello_len = 0; -// REQUIRE(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == -// SSL_ERROR_WANT_READ); -// REQUIRE(server_hello_len > 0); -// std::cout << "### Server Hello" << std::endl; -// print_hex(server_hello, server_hello_len); -// -// // Client Fnished -// uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; -// size_t client_finished_len = 0; -// REQUIRE(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == -// SSL_ERROR_NONE); -// REQUIRE(client_finished_len > 0); -// std::cout << "### Client Finished" << std::endl; -// print_hex(client_finished, client_finished_len); -// -// CHECK(client->update_key_materials()); -// -// // Post Handshake Msg -// uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; -// size_t post_handshake_msg_len = 0; -// REQUIRE(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, -// client_finished_len) == SSL_ERROR_NONE); -// std::cout << "### Post Handshake Message" << std::endl; -// print_hex(post_handshake_msg, post_handshake_msg_len); -// -// CHECK(server->update_key_materials()); -// -// // encrypt - decrypt -// // client (encrypt) - server (decrypt) -// std::cout << "### Original Text" << std::endl; -// print_hex(original, sizeof(original)); -// -// uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead -// size_t cipher_len = 0; -// CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), -// QUICKeyPhase::PHASE_0)); -// -// std::cout << "### Encrypted Text" << std::endl; -// print_hex(cipher, cipher_len); -// -// uint8_t plain[128] = {0}; -// size_t plain_len = 0; -// CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); -// -// std::cout << "### Decrypted Text" << std::endl; -// print_hex(plain, plain_len); -// -// CHECK(sizeof(original) == (plain_len)); -// CHECK(memcmp(original, plain, plain_len) == 0); -// -// // Teardown -// delete client; -// delete server; -// } -// -// // TEST_CASE("QUICHandshakeProtocol PNE", "[quic]") // { // // Client From 6f4dc5f5390838c384cd7baac2472474eabf524e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 28 Sep 2018 14:52:54 -0600 Subject: [PATCH 0855/1313] Remove key phase changing logic completely for now It was destroyed when draft-13 was supported, and is causing a compile warning. --- iocore/net/quic/Mock.h | 6 ------ iocore/net/quic/QUICHandshakeProtocol.h | 1 - iocore/net/quic/QUICTLS.cc | 21 --------------------- iocore/net/quic/QUICTLS.h | 1 - 4 files changed, 29 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 3edf6d73285..8e89b41003e 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -555,12 +555,6 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol return 0; } - int - update_key_materials() override - { - return 0; - } - const char * negotiated_cipher_suite() const override { diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 32715930cbd..5bd77b41f17 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -84,7 +84,6 @@ class QUICHandshakeProtocol virtual bool is_ready_to_derive() const = 0; virtual bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const = 0; virtual int initialize_key_materials(QUICConnectionId cid) = 0; - virtual int update_key_materials() = 0; virtual const char *negotiated_cipher_suite() const = 0; virtual void negotiated_application_name(const uint8_t **name, unsigned int *len) const = 0; virtual const KeyMaterial *key_material_for_encryption(QUICKeyPhase phase) const = 0; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 0499d1fc437..8eb81b39f38 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -137,27 +137,6 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) return 1; } -int -QUICTLS::update_key_materials() -{ - // Switch key phase - QUICKeyPhase next_key_phase; - switch (this->_client_pp->key_phase()) { - case QUICKeyPhase::PHASE_0: - next_key_phase = QUICKeyPhase::PHASE_1; - break; - case QUICKeyPhase::PHASE_1: - next_key_phase = QUICKeyPhase::PHASE_0; - break; - default: - Error("QUICKeyPhase value is undefined"); - ink_assert(false); - next_key_phase = QUICKeyPhase::PHASE_0; - } - - return 1; -} - const KeyMaterial * QUICTLS::key_material_for_encryption(QUICKeyPhase phase) const { diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 001c08ad777..4652187d0a7 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -67,7 +67,6 @@ class QUICTLS : public QUICHandshakeProtocol bool is_ready_to_derive() const override; bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const override; int initialize_key_materials(QUICConnectionId cid) override; - int update_key_materials() override; void update_key_materials_on_key_cb(std::unique_ptr km, int name); const char *negotiated_cipher_suite() const override; void negotiated_application_name(const uint8_t **name, unsigned int *len) const override; From 0f208a33ef0acf0038cf7887e7be185503921ad3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 4 Oct 2018 17:44:21 -0700 Subject: [PATCH 0856/1313] Fix a build issue This should fix #4353 --- src/traffic_quic/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traffic_quic/Makefile.inc b/src/traffic_quic/Makefile.inc index 3325faa1b96..3cbc16b9b2d 100644 --- a/src/traffic_quic/Makefile.inc +++ b/src/traffic_quic/Makefile.inc @@ -41,8 +41,8 @@ traffic_quic_traffic_quic_SOURCES = \ traffic_quic/traffic_quic.cc traffic_quic_traffic_quic_LDADD = \ - $(top_builddir)/iocore/aio/libinkaio.a \ $(top_builddir)/iocore/net/libinknet.a \ + $(top_builddir)/iocore/aio/libinkaio.a \ $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/mgmt/libmgmt_p.la \ From f446a02d2c8a4e0a37f8e65d4af9c8cdffa79318 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sat, 13 Oct 2018 18:06:16 +0900 Subject: [PATCH 0857/1313] Cleanup tests for QUIC transport Fix memory leaks Remove unused variables --- iocore/net/quic/Mock.h | 3 +- .../net/quic/test/test_QUICFrameDispatcher.cc | 32 ++++----- iocore/net/quic/test/test_QUICLossDetector.cc | 69 +++++++++---------- .../net/quic/test/test_QUICPacketFactory.cc | 12 +--- iocore/net/quic/test/test_QUICStream.cc | 27 ++++---- .../net/quic/test/test_QUICStreamManager.cc | 20 ++++-- 6 files changed, 83 insertions(+), 80 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 8e89b41003e..db1c44beeb2 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -447,7 +447,8 @@ class MockQUICLossDetector : public QUICLossDetector class MockQUICApplication : public QUICApplication { public: - MockQUICApplication() : QUICApplication(new MockQUICConnection) { SET_HANDLER(&MockQUICApplication::main_event_handler); } + MockQUICApplication(QUICConnection *c) : QUICApplication(c) { SET_HANDLER(&MockQUICApplication::main_event_handler); } + int main_event_handler(int event, Event *data) { diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index a90752dd109..a69faad5d8a 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -35,22 +35,22 @@ TEST_CASE("QUICFrameHandler", "[quic]") QUICStreamFrame streamFrame(std::move(payload), 1, 0x03, 0); - auto connection = new MockQUICConnection(); - auto streamManager = new MockQUICStreamManager(); - auto tx = new MockQUICPacketTransmitter(); - auto info = new MockQUICConnectionInfoProvider(); - auto cc = new MockQUICCongestionController(info); + MockQUICConnection connection; + MockQUICStreamManager streamManager; + MockQUICPacketTransmitter tx; + MockQUICConnectionInfoProvider info; + MockQUICCongestionController cc(&info); QUICRTTMeasure rtt_measure; - auto lossDetector = new MockQUICLossDetector(tx, info, cc, &rtt_measure, 0); + MockQUICLossDetector lossDetector(&tx, &info, &cc, &rtt_measure, 0); - QUICFrameDispatcher quicFrameDispatcher(info); - quicFrameDispatcher.add_handler(connection); - quicFrameDispatcher.add_handler(streamManager); - quicFrameDispatcher.add_handler(lossDetector); + QUICFrameDispatcher quicFrameDispatcher(&info); + quicFrameDispatcher.add_handler(&connection); + quicFrameDispatcher.add_handler(&streamManager); + quicFrameDispatcher.add_handler(&lossDetector); // Initial state - CHECK(connection->getTotalFrameCount() == 0); - CHECK(streamManager->getTotalFrameCount() == 0); + CHECK(connection.getTotalFrameCount() == 0); + CHECK(streamManager.getTotalFrameCount() == 0); // STREAM frame uint8_t buf[4096] = {0}; @@ -59,13 +59,13 @@ TEST_CASE("QUICFrameHandler", "[quic]") bool should_send_ack; bool is_flow_controlled; quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack, is_flow_controlled); - CHECK(connection->getTotalFrameCount() == 0); - CHECK(streamManager->getTotalFrameCount() == 1); + CHECK(connection.getTotalFrameCount() == 0); + CHECK(streamManager.getTotalFrameCount() == 1); // CONNECTION_CLOSE frame QUICConnectionCloseFrame connectionCloseFrame({}); connectionCloseFrame.store(buf, &len, 4096); quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack, is_flow_controlled); - CHECK(connection->getTotalFrameCount() == 1); - CHECK(streamManager->getTotalFrameCount() == 1); + CHECK(connection.getTotalFrameCount() == 1); + CHECK(streamManager.getTotalFrameCount() == 1); } diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 950dc67d52e..00f85823655 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -35,22 +35,21 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") pf.set_hs_protocol(&hs_protocol); QUICRTTMeasure rtt_measure; - QUICAckFrameCreator *afc = new QUICAckFrameCreator(); - QUICConnectionId connection_id = {reinterpret_cast("\x01"), 1}; - MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); - MockQUICConnectionInfoProvider *info = new MockQUICConnectionInfoProvider(); - MockQUICCongestionController *cc = new MockQUICCongestionController(info); - QUICLossDetector detector(tx, info, cc, &rtt_measure, 0); + QUICAckFrameCreator afc; + QUICConnectionId connection_id = {reinterpret_cast("\x01"), 1}; + MockQUICPacketTransmitter tx; + MockQUICConnectionInfoProvider info; + MockQUICCongestionController cc(&info); + QUICLossDetector detector(&tx, &info, &cc, &rtt_measure, 0); ats_unique_buf payload = ats_unique_malloc(16); size_t payload_len = 16; QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); std::shared_ptr frame = QUICFrameFactory::create_null_ack_frame(); - uint16_t ack_delay = 50; SECTION("Handshake") { // Check initial state - CHECK(tx->retransmitted.size() == 0); + CHECK(tx.retransmitted.size() == 0); // Send SERVER_CLEARTEXT (Handshake message) uint8_t raw[4] = {0}; @@ -66,22 +65,22 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true), [](QUICPacket *p) { delete p; }); detector.on_packet_sent(std::move(packet)); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); - CHECK(tx->retransmitted.size() > 0); + CHECK(tx.retransmitted.size() > 0); // Receive ACK QUICAckFrame frame(0x01, 20, 0); frame.ack_block_section()->add_ack_block({0, 1ULL}); detector.handle_frame(QUICEncryptionLevel::INITIAL, frame); ink_hrtime_sleep(HRTIME_MSECONDS(1500)); - int retransmit_count = tx->retransmitted.size(); + int retransmit_count = tx.retransmitted.size(); ink_hrtime_sleep(HRTIME_MSECONDS(1500)); - CHECK(tx->retransmitted.size() == retransmit_count); + CHECK(tx.retransmitted.size() == retransmit_count); } SECTION("1-RTT") { // Check initial state - CHECK(tx->retransmitted.size() == 0); + CHECK(tx.retransmitted.size() == 0); // Send packet (1) to (7) payload = ats_unique_malloc(16); @@ -135,42 +134,42 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") ink_hrtime_sleep(HRTIME_MSECONDS(1000)); // Receive an ACK for (1) (4) (5) (7) (8) (9) - afc->update(QUICEncryptionLevel::INITIAL, pn1, true); - afc->update(QUICEncryptionLevel::INITIAL, pn4, true); - afc->update(QUICEncryptionLevel::INITIAL, pn5, true); - afc->update(QUICEncryptionLevel::INITIAL, pn7, true); - afc->update(QUICEncryptionLevel::INITIAL, pn8, true); - afc->update(QUICEncryptionLevel::INITIAL, pn9, true); + afc.update(QUICEncryptionLevel::INITIAL, pn1, true); + afc.update(QUICEncryptionLevel::INITIAL, pn4, true); + afc.update(QUICEncryptionLevel::INITIAL, pn5, true); + afc.update(QUICEncryptionLevel::INITIAL, pn7, true); + afc.update(QUICEncryptionLevel::INITIAL, pn8, true); + afc.update(QUICEncryptionLevel::INITIAL, pn9, true); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); - std::shared_ptr x = afc->generate_frame(QUICEncryptionLevel::INITIAL, 2048, 2048); + std::shared_ptr x = afc.generate_frame(QUICEncryptionLevel::INITIAL, 2048, 2048); frame = std::dynamic_pointer_cast(x); detector.handle_frame(QUICEncryptionLevel::INITIAL, *frame.get()); ink_hrtime_sleep(HRTIME_MSECONDS(5000)); - CHECK(cc->lost_packets.size() == 3); - - CHECK(cc->lost_packets.find(pn1) == cc->lost_packets.end()); - CHECK(cc->lost_packets.find(pn2) != cc->lost_packets.end()); - CHECK(cc->lost_packets.find(pn3) != cc->lost_packets.end()); - CHECK(cc->lost_packets.find(pn4) == cc->lost_packets.end()); - CHECK(cc->lost_packets.find(pn5) == cc->lost_packets.end()); - CHECK(cc->lost_packets.find(pn6) != cc->lost_packets.end()); - CHECK(cc->lost_packets.find(pn7) == cc->lost_packets.end()); - CHECK(cc->lost_packets.find(pn8) == cc->lost_packets.end()); - CHECK(cc->lost_packets.find(pn9) == cc->lost_packets.end()); + CHECK(cc.lost_packets.size() == 3); + + CHECK(cc.lost_packets.find(pn1) == cc.lost_packets.end()); + CHECK(cc.lost_packets.find(pn2) != cc.lost_packets.end()); + CHECK(cc.lost_packets.find(pn3) != cc.lost_packets.end()); + CHECK(cc.lost_packets.find(pn4) == cc.lost_packets.end()); + CHECK(cc.lost_packets.find(pn5) == cc.lost_packets.end()); + CHECK(cc.lost_packets.find(pn6) != cc.lost_packets.end()); + CHECK(cc.lost_packets.find(pn7) == cc.lost_packets.end()); + CHECK(cc.lost_packets.find(pn8) == cc.lost_packets.end()); + CHECK(cc.lost_packets.find(pn9) == cc.lost_packets.end()); } } TEST_CASE("QUICLossDetector_HugeGap", "[quic]") { - MockQUICPacketTransmitter *tx = new MockQUICPacketTransmitter(); - MockQUICConnectionInfoProvider *info = new MockQUICConnectionInfoProvider(); - MockQUICCongestionController *cc = new MockQUICCongestionController(info); + MockQUICPacketTransmitter tx; + MockQUICConnectionInfoProvider info; + MockQUICCongestionController cc(&info); QUICRTTMeasure rtt_measure; - QUICLossDetector detector(tx, info, cc, &rtt_measure, 0); + QUICLossDetector detector(&tx, &info, &cc, &rtt_measure, 0); // Check initial state - CHECK(tx->retransmitted.size() == 0); + CHECK(tx.retransmitted.size() == 0); auto t1 = Thread::get_hrtime(); std::shared_ptr ack = QUICFrameFactory::create_ack_frame(100000000, 100, 10000000); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 0f47d0b6a8d..83eb4b04b76 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -58,7 +58,8 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") uint8_t buf[1024] = {0}; size_t buf_len; vn_packet->store(buf, &buf_len); - CHECK(memcmp(buf, expected, buf_len) == 0); + CHECK((buf[0] & 0x80) == 0x80); // Lower 7 bits of the first byte is random + CHECK(memcmp(buf + 1, expected + 1, buf_len - 1) == 0); } TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") @@ -110,15 +111,6 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") factory.set_hs_protocol(&hs_protocol); QUICStatelessResetToken token; token.generate({reinterpret_cast("\x30\x39"), 2}, 67890); - uint8_t expected_output[] = { - 0x41, // 0CK0001 - 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, // Connection ID - 0xa1, 0x45, 0x7b, 0x7e, 0x8f, 0x85, 0x0b, 0x14, // Token - 0xd2, 0x43, 0xa1, 0xaf, 0x7c, 0xe2, 0x91, 0x50, - // Random data - }; - uint8_t output[1024]; - size_t out_len = 0; QUICPacketUPtr packet = factory.create_stateless_reset_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), token); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index e7a791cba28..a0ddf0c6098 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -69,8 +69,9 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream( - new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, 1024, 1024)); + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, 1024, 1024)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); stream->recv(*frame_1); @@ -95,8 +96,9 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream( - new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, UINT64_MAX, UINT64_MAX)); + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); stream->recv(*frame_8); @@ -121,8 +123,9 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream( - new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, UINT64_MAX, UINT64_MAX)); + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); stream->recv(*frame_8); @@ -149,10 +152,10 @@ TEST_CASE("QUICStream", "[quic]") std::unique_ptr error = nullptr; MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); - IOBufferReader *reader = read_buffer->alloc_reader(); - std::unique_ptr stream( - new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, 4096, 4096)); + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, 4096, 4096)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); // Start with 1024 but not 0 so received frames won't be processed @@ -184,11 +187,11 @@ TEST_CASE("QUICStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); - IOBufferReader *read_buffer_reader = read_buffer->alloc_reader(); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - std::unique_ptr stream( - new QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), stream_id, 4096, 4096)); + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, 4096, 4096)); SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); MockContinuation mock_cont(stream->mutex); diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 4711aa180e8..dcf696d253d 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -33,9 +33,12 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") { QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; QUICApplicationMap app_map; - MockQUICApplication mock_app; + MockQUICConnection connection; + MockQUICApplication mock_app(&connection); app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); + MockQUICConnectionInfoProvider cinfo_provider; + MockQUICRTTProvider rtt_provider; + QUICStreamManager sm(&cinfo_provider, &rtt_provider, &app_map); std::shared_ptr local_tp = std::make_shared(static_cast(0)); std::shared_ptr remote_tp = @@ -80,9 +83,12 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") { QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; QUICApplicationMap app_map; - MockQUICApplication mock_app; + MockQUICConnection connection; + MockQUICApplication mock_app(&connection); app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); + MockQUICConnectionInfoProvider cinfo_provider; + MockQUICRTTProvider rtt_provider; + QUICStreamManager sm(&cinfo_provider, &rtt_provider, &app_map); std::shared_ptr local_tp = std::make_shared(static_cast(0)); std::shared_ptr remote_tp = @@ -101,7 +107,8 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") { QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; QUICApplicationMap app_map; - MockQUICApplication mock_app; + MockQUICConnection connection; + MockQUICApplication mock_app(&connection); app_map.set_default(&mock_app); QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); std::shared_ptr local_tp = @@ -130,7 +137,8 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") { QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; QUICApplicationMap app_map; - MockQUICApplication mock_app; + MockQUICConnection connection; + MockQUICApplication mock_app(&connection); app_map.set_default(&mock_app); QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); std::shared_ptr local_tp = From 411094535d1d241b576cb60208e2fae67520d14d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sat, 13 Oct 2018 18:12:44 +0900 Subject: [PATCH 0858/1313] Fix a memory leak in QUICApplication --- iocore/net/quic/QUICApplication.cc | 7 +++++++ iocore/net/quic/QUICApplication.h | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index b0904c73e72..49299334c27 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -207,6 +207,13 @@ QUICApplication::QUICApplication(QUICConnection *qc) : Continuation(new_ProxyMut this->_qc = qc; } +QUICApplication::~QUICApplication() +{ + for (const auto& [stream_id, stream_io] : this->_stream_map) { + delete stream_io; + } +} + // @brief Bind stream and application void QUICApplication::set_stream(QUICStream *stream, QUICStreamIO *stream_io) diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 87d84ebd1b9..3cd23ec7f49 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -86,7 +86,7 @@ class QUICApplication : public Continuation { public: QUICApplication(QUICConnection *qc); - virtual ~QUICApplication(){}; + virtual ~QUICApplication(); void set_stream(QUICStream *stream, QUICStreamIO *stream_io = nullptr); bool is_stream_set(QUICStream *stream); From 51534c72c12d081324d34df93cbce9fc834c875b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sat, 13 Oct 2018 18:59:43 +0900 Subject: [PATCH 0859/1313] Cleanup QPACK --- proxy/hq/QPACK.cc | 12 +++++++----- proxy/hq/QPACK.h | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/proxy/hq/QPACK.cc b/proxy/hq/QPACK.cc index b1fb3e6df85..941740864b5 100644 --- a/proxy/hq/QPACK.cc +++ b/proxy/hq/QPACK.cc @@ -125,6 +125,7 @@ QPACK::event_handler(int event, Event *data) break; case VC_EVENT_WRITE_READY: ret = this->_on_write_ready(*stream_io); + break; case VC_EVENT_WRITE_COMPLETE: ret = EVENT_DONE; break; @@ -643,7 +644,7 @@ QPACK::_decode_literal_header_field_with_name_ref(int16_t base_index, const uint read_len += ret; // Create and attach a header - this->_attach_header(hdr, name, name_len, value, value_len); + this->_attach_header(hdr, name, name_len, value, value_len, never_index); QPACKDebug("Decoded Literal Header Field With Name Ref: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index, result.index, name_len, name, static_cast(value_len), value); @@ -680,7 +681,7 @@ QPACK::_decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t read_len += ret; // Create and attach a header - this->_attach_header(hdr, name, name_len, value, value_len); + this->_attach_header(hdr, name, name_len, value, value_len, never_index); QPACKDebug("Decoded Literal Header Field Without Name Ref: name=%.*s, value=%.*s", static_cast(name_len), name, static_cast(value_len), value); @@ -714,7 +715,7 @@ QPACK::_decode_indexed_header_field_with_postbase_index(int16_t base_index, cons } // Create and attach a header - this->_attach_header(hdr, name, name_len, value, value_len); + this->_attach_header(hdr, name, name_len, value, value_len, false); QPACKDebug("Decoded Indexed Header Field With Postbase Index: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index, result.index, name_len, name, value_len, value); @@ -764,7 +765,7 @@ QPACK::_decode_literal_header_field_with_postbase_name_ref(int16_t base_index, c read_len += ret; // Create and attach a header - this->_attach_header(hdr, name, name_len, value, value_len); + this->_attach_header(hdr, name, name_len, value, value_len, never_index); QPACKDebug("Decoded Literal Header Field With Postbase Name Ref: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index, static_cast(index), name_len, name, static_cast(value_len), value); @@ -1109,8 +1110,9 @@ QPACK::_calc_postbase_index_from_absolute_index(uint16_t base_index, uint16_t ab } void -QPACK::_attach_header(HTTPHdr &hdr, const char *name, int name_len, const char *value, int value_len) +QPACK::_attach_header(HTTPHdr &hdr, const char *name, int name_len, const char *value, int value_len, bool never_index) { + // TODO If never_index is true, we need to mark this header as sensitive to not index the header when passing it to the other side MIMEField *new_field = hdr.field_create(name, name_len); new_field->value_set(hdr.m_heap, hdr.m_mime, value, value_len); hdr.field_attach(new_field); diff --git a/proxy/hq/QPACK.h b/proxy/hq/QPACK.h index b7e6d4b7ba5..3c97584515e 100644 --- a/proxy/hq/QPACK.h +++ b/proxy/hq/QPACK.h @@ -302,7 +302,7 @@ class QPACK : public QUICApplication uint16_t _calc_absolute_index_from_postbase_index(uint16_t base_index, uint16_t postbase_index); uint16_t _calc_relative_index_from_absolute_index(uint16_t base_index, uint16_t absolute_index); uint16_t _calc_postbase_index_from_absolute_index(uint16_t base_index, uint16_t absolute_index); - void _attach_header(HTTPHdr &hdr, const char *name, int name_len, const char *value, int value_len); + void _attach_header(HTTPHdr &hdr, const char *name, int name_len, const char *value, int value_len, bool never_index); int _on_read_ready(QUICStreamIO &stream_io); int _on_decoder_stream_read_ready(QUICStreamIO &stream_io); From a47a34a7b3117461afba38fa62468dc944f25637 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sat, 13 Oct 2018 19:04:49 +0900 Subject: [PATCH 0860/1313] Don't use deprecated functions of QUICStreamIO --- proxy/hq/HQClientTransaction.cc | 39 ++++++++++++++------------- proxy/hq/HQFrame.cc | 15 +++++++++++ proxy/hq/HQFrame.h | 2 ++ proxy/hq/HQFrameDispatcher.cc | 48 +++++++++++++++++++++++---------- proxy/hq/HQFrameDispatcher.h | 10 ++++++- proxy/hq/QUICSimpleApp.cc | 3 ++- src/traffic_quic/quic_client.cc | 11 +++----- 7 files changed, 87 insertions(+), 41 deletions(-) diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/hq/HQClientTransaction.cc index 0d49914f47c..16f1f13b98b 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/hq/HQClientTransaction.cc @@ -406,59 +406,62 @@ HQClientTransaction::_process_read_vio() SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); - IOBufferReader *client_vio_reader = this->_stream_io->get_read_buffer_reader(); - int64_t bytes_avail = client_vio_reader->read_avail(); - // Nuke this block when we drop 0.9 support if (!this->_protocol_detected) { - if (bytes_avail < 3) { + uint8_t start[3]; + if (this->_stream_io->peek(start, 3) < 3) { return 0; } // If the first two bit are 0 and 1, the 3rd byte is type field. // Because there is no type value larger than 0x20, we can assume that the // request is HTTP/0.9 if the value is larger than 0x20. - const uint8_t *start = reinterpret_cast(client_vio_reader->start()); - if (0x40 <= *start && *start < 0x80 && *(start + 2) > 0x20) { + if (0x40 <= start[0] && start[0] < 0x80 && start[2] > 0x20) { this->_legacy_request = true; } this->_protocol_detected = true; } if (this->_legacy_request) { + uint64_t nread = 0; MIOBuffer *writer = this->_read_vio.get_writer(); // Nuke this branch when we drop 0.9 support if (!this->_client_req_header_complete) { - int n = 2; + uint8_t buf[4096]; + int len = this->_stream_io->peek(buf, 4096); // Check client request is complete or not - if (bytes_avail < 2 || client_vio_reader->start()[bytes_avail - 1] != '\n') { + if (len < 2 || buf[len - 1] != '\n') { return 0; } + this->_stream_io->consume(len); + nread += len; this->_client_req_header_complete = true; // Check "CRLF" or "LF" - if (client_vio_reader->start()[bytes_avail - 2] != '\r') { + int n = 2; + if (buf[len - 2] != '\r') { n = 1; } - writer->write(client_vio_reader, bytes_avail - n); - client_vio_reader->consume(bytes_avail); - + writer->write(buf, len - n); // FIXME: Get hostname from SNI? const char version[] = " HTTP/1.1\r\nHost: localhost\r\n\r\n"; writer->write(version, sizeof(version)); } else { - writer->write(client_vio_reader, bytes_avail); - client_vio_reader->consume(bytes_avail); + uint8_t buf[4096]; + int len; + while ((len = this->_stream_io->read(buf, 4096)) > 0) { + nread += len; + writer->write(buf, len); + } } - return bytes_avail; + return nread; // End of code for HTTP/0.9 } else { // This branch is for HQ - uint16_t nread = 0; - this->_frame_dispatcher.on_read_ready(reinterpret_cast(client_vio_reader->start()), bytes_avail, nread); - client_vio_reader->consume(nread); + uint64_t nread = 0; + this->_frame_dispatcher.on_read_ready(*this->_stream_io, nread); return nread; } } diff --git a/proxy/hq/HQFrame.cc b/proxy/hq/HQFrame.cc index dfd48d6ddd5..6ab87d7b390 100644 --- a/proxy/hq/HQFrame.cc +++ b/proxy/hq/HQFrame.cc @@ -286,6 +286,21 @@ HQFrameFactory::fast_create(const uint8_t *buf, size_t len) return frame; } +std::shared_ptr +HQFrameFactory::fast_create(QUICStreamIO &stream_io, size_t len) +{ + uint8_t buf[65536]; + + // FIXME DATA frames can be giga bytes + ink_assert(sizeof(buf) > len); + + if (stream_io.peek(buf, sizeof(buf) < len)) { + // Return if whole frame data is not available + return nullptr; + } + return this->fast_create(buf, len); +} + HQHeadersFrameUPtr HQFrameFactory::create_headers_frame(const uint8_t *header_block, size_t header_block_len) { diff --git a/proxy/hq/HQFrame.h b/proxy/hq/HQFrame.h index 28f7091026e..b786d753975 100644 --- a/proxy/hq/HQFrame.h +++ b/proxy/hq/HQFrame.h @@ -26,6 +26,7 @@ #include "tscore/Allocator.h" #include "tscore/ink_memory.h" #include "tscore/ink_assert.h" +#include "QUICApplication.h" #include "HQTypes.h" class HQFrame @@ -172,6 +173,7 @@ class HQFrameFactory * 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. */ + std::shared_ptr fast_create(QUICStreamIO &stream_io, size_t len); std::shared_ptr fast_create(const uint8_t *buf, size_t len); /* diff --git a/proxy/hq/HQFrameDispatcher.cc b/proxy/hq/HQFrameDispatcher.cc index 797582e371e..59a393fa3de 100644 --- a/proxy/hq/HQFrameDispatcher.cc +++ b/proxy/hq/HQFrameDispatcher.cc @@ -21,12 +21,11 @@ * limitations under the License. */ +#include "QUICIntUtil.h" #include "HQFrameDispatcher.h" #include "HQDebugNames.h" #include "tscore/Diags.h" -static constexpr char tag[] = "hq_frame"; - // // Frame Dispatcher // @@ -40,23 +39,45 @@ HQFrameDispatcher::add_handler(HQFrameHandler *handler) } HQErrorUPtr -HQFrameDispatcher::on_read_ready(const uint8_t *src, uint16_t read_avail, uint16_t &nread) +HQFrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) { std::shared_ptr frame(nullptr); - const uint8_t *cursor = src; - HQErrorUPtr error = HQErrorUPtr(new HQNoError()); - uint64_t frame_length = 0; + HQErrorUPtr error = HQErrorUPtr(new HQNoError()); + nread = 0; - while (HQFrame::length(cursor, read_avail, frame_length) != -1 && read_avail >= frame_length) { - frame = this->_frame_factory.fast_create(cursor, read_avail); + while (true) { + if (_reading_state == READING_LENGTH_LEN) { + // Read a length of Length field + uint8_t head; + if (stream_io.peek(&head, 1) <= 0) { + break; + } + _reading_frame_length_len = QUICVariableInt::size(&head); + _reading_state = READING_PAYLOAD_LEN; + } + + if (_reading_state < READING_PAYLOAD_LEN) { + // Read a payload length + uint8_t length_buf[8]; + if (stream_io.read(length_buf, _reading_frame_length_len) != _reading_frame_length_len) { + break; + } + nread += _reading_frame_length_len; + size_t dummy; + if (QUICVariableInt::decode(_reading_frame_payload_len, dummy, length_buf, sizeof(length_buf)) < 0) { + error = HQErrorUPtr(new HQStreamError()); + } + _reading_state = READING_PAYLOAD; + } + + // Create a frame + frame = this->_frame_factory.fast_create(stream_io, _reading_frame_payload_len); if (frame == nullptr) { - Debug(tag, "Failed to create a frame"); - // error = HQErrorUPtr(new HQStreamError()); break; } - cursor += frame->total_length(); - read_avail -= frame->total_length(); + nread += 1 + _reading_frame_payload_len; // Type field length (1) + Payload length + // Dispatch HQFrameType type = frame->type(); std::vector handlers = this->_handlers[static_cast(type)]; for (auto h : handlers) { @@ -65,9 +86,8 @@ HQFrameDispatcher::on_read_ready(const uint8_t *src, uint16_t read_avail, uint16 return error; } } + _reading_state = READING_LENGTH_LEN; } - nread = cursor - src; - return error; } diff --git a/proxy/hq/HQFrameDispatcher.h b/proxy/hq/HQFrameDispatcher.h index 6fa893ddc2c..ced9ca65234 100644 --- a/proxy/hq/HQFrameDispatcher.h +++ b/proxy/hq/HQFrameDispatcher.h @@ -23,6 +23,7 @@ #pragma once +#include "QUICApplication.h" #include "HQFrame.h" #include "HQFrameHandler.h" #include @@ -30,11 +31,18 @@ class HQFrameDispatcher { public: - HQErrorUPtr on_read_ready(const uint8_t *source, uint16_t read_avail, uint16_t &nread); + HQErrorUPtr on_read_ready(QUICStreamIO &stream_io, uint64_t &nread); void add_handler(HQFrameHandler *handler); private: + enum READING_STATE { + READING_LENGTH_LEN, + READING_PAYLOAD_LEN, + READING_PAYLOAD, + } _reading_state = READING_LENGTH_LEN; + int64_t _reading_frame_length_len; + uint64_t _reading_frame_payload_len; HQFrameFactory _frame_factory; std::vector _handlers[256]; }; diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/hq/QUICSimpleApp.cc index fb42b259b05..d2f20e33a03 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/hq/QUICSimpleApp.cc @@ -65,10 +65,11 @@ QUICSimpleApp::main_event_handler(int event, Event *data) QUICStreamId stream_id = stream_io->stream_id(); HQClientTransaction *txn = this->_client_session->get_transaction(stream_id); + uint8_t dummy; switch (event) { case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: - if (stream_io->is_read_avail_more_than(0)) { + if (stream_io->peek(&dummy, 1)) { if (txn == nullptr) { txn = new HQClientTransaction(this->_client_session, stream_io); SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc index b5237ac4cbe..ae8fcd34a4a 100644 --- a/src/traffic_quic/quic_client.cc +++ b/src/traffic_quic/quic_client.cc @@ -174,13 +174,10 @@ QUICClientApp::main_event_handler(int event, Event *data) std::cout.rdbuf(f_stream.rdbuf()); } - while (stream_io->is_read_avail_more_than(0)) { - uint8_t buf[8192] = {0}; - int64_t len = stream_io->get_read_buffer_reader()->block_read_avail(); - len = std::min(len, (int64_t)sizeof(buf)); - stream_io->read(buf, len); - - std::cout.write(reinterpret_cast(buf), len); + uint8_t buf[8192] = {0}; + int64_t nread; + while ((nread = stream_io->read(buf, sizeof(buf))) > 0) { + std::cout.write(reinterpret_cast(buf), nread); } std::cout.flush(); From 84f168f433f33583467827945a6b8df41239cb34 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sat, 13 Oct 2018 19:09:41 +0900 Subject: [PATCH 0861/1313] Remove deprecated functions in QUICStreamIO --- iocore/net/quic/QUICApplication.cc | 31 ------------------------------ iocore/net/quic/QUICApplication.h | 6 ------ 2 files changed, 37 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 49299334c27..ca0b9795478 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -156,31 +156,6 @@ QUICStreamIO::write_done() this->_write_vio->nbytes = this->_nwritten; } -// !!! DEPRECATED !!! -int64_t -QUICStreamIO::read_avail() -{ - return this->_read_buffer_reader->read_avail(); -} - -bool -QUICStreamIO::is_read_avail_more_than(int64_t size) -{ - return this->_read_buffer_reader->is_read_avail_more_than(size); -} - -int64_t -QUICStreamIO::write_avail() -{ - return this->_write_buffer->write_avail(); -} - -void -QUICStreamIO::set_write_vio_nbytes(int64_t nbytes) -{ - this->_write_vio->nbytes = nbytes; -} - void QUICStreamIO::read_reenable() { @@ -193,12 +168,6 @@ QUICStreamIO::write_reenable() return this->_write_vio->reenable(); } -IOBufferReader * -QUICStreamIO::get_read_buffer_reader() -{ - return this->_read_buffer_reader; -} - // // QUICApplication // diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 3cd23ec7f49..649101ddf60 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -54,12 +54,6 @@ class QUICStreamIO void write_done(); virtual void write_reenable(); - [[deprecated]] int64_t read_avail(); - [[deprecated]] bool is_read_avail_more_than(int64_t size); - [[deprecated]] int64_t write_avail(); - [[deprecated]] void set_write_vio_nbytes(int64_t); - [[deprecated]] IOBufferReader *get_read_buffer_reader(); - protected: MIOBuffer *_read_buffer = nullptr; MIOBuffer *_write_buffer = nullptr; From 30ed26a920b2995f6eca5f941d2d3ed964f08368 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 15 Oct 2018 10:13:37 +0900 Subject: [PATCH 0862/1313] clang-format --- iocore/net/quic/QUICApplication.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index ca0b9795478..f931e6451b5 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -178,7 +178,7 @@ QUICApplication::QUICApplication(QUICConnection *qc) : Continuation(new_ProxyMut QUICApplication::~QUICApplication() { - for (const auto& [stream_id, stream_io] : this->_stream_map) { + for (const auto &[stream_id, stream_io] : this->_stream_map) { delete stream_io; } } From 5e1c9166359a7f2afd66549a38701152ca9d3d04 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 15 Oct 2018 12:11:28 +0800 Subject: [PATCH 0863/1313] QUIC Read new session ticket msg and send it back --- iocore/net/quic/QUICTLS.h | 2 + iocore/net/quic/QUICTLS_boringssl.cc | 7 +++ iocore/net/quic/QUICTLS_openssl.cc | 55 ++++++++++++++++++- .../quic/test/test_QUICHandshakeProtocol.cc | 8 +++ 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 4652187d0a7..4972678e5c4 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -95,6 +95,8 @@ class QUICTLS : public QUICHandshakeProtocol bool _decrypt(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 KeyMaterial &km, const QUIC_EVP_CIPHER *aead, size_t tag_len) const; int _read_early_data(); + int _handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in); + int _process_post_handshake_messages(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in); void _generate_0rtt_key(); void _update_encryption_level(QUICEncryptionLevel level); diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc index a2e9f70952b..f80c80e3a84 100644 --- a/iocore/net/quic/QUICTLS_boringssl.cc +++ b/iocore/net/quic/QUICTLS_boringssl.cc @@ -49,6 +49,13 @@ QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) return 0; } +int +QUICTLS::_process_post_handshake_messages(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) +{ + ink_assert(false); + return 0; +} + int QUICTLS::_read_early_data() { diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 7863e7be6ac..2e1357da0b3 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -260,9 +260,19 @@ QUICTLS::get_encryption_level(int msg_type) int QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) +{ + if (this->is_handshake_finished()) { + return this->_process_post_handshake_messages(out, in); + } + + return this->_handshake(out, in); +} + +int +QUICTLS::_handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) { ink_assert(this->_ssl != nullptr); - if (SSL_is_init_finished(this->_ssl) || this->_state == HandshakeState::ABORTED) { + if (this->_state == HandshakeState::ABORTED) { return 0; } @@ -312,6 +322,49 @@ QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) return 1; } +int +QUICTLS::_process_post_handshake_messages(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) +{ + ink_assert(this->_ssl != nullptr); + + int err = SSL_ERROR_NONE; + ERR_clear_error(); + int ret = 0; + + SSL_set_msg_callback(this->_ssl, msg_cb); + SSL_set_msg_callback_arg(this->_ssl, out); + + // TODO: set BIO_METHOD which read from QUICHandshakeMsgs directly + BIO *rbio = BIO_new(BIO_s_mem()); + // TODO: set dummy BIO_METHOD which do nothing + BIO *wbio = BIO_new(BIO_s_mem()); + if (in != nullptr && in->offsets[4] != 0) { + BIO_write(rbio, in->buf, in->offsets[4]); + } + SSL_set_bio(this->_ssl, rbio, wbio); + + uint8_t data[2048]; + size_t l = 0; + ret = SSL_read_ex(this->_ssl, data, 2048, &l); + + 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; + } + } + + return 1; +} + void QUICTLS::reset() { diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index e7aa31c0ca5..4c2a4b8d34f 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -261,6 +261,14 @@ TEST_CASE("QUICHandshakeProtocol") std::cout << "### Messages from server" << std::endl; print_hex(msg4.buf, msg4.offsets[4]); + QUICHandshakeMsgs msg5; + uint8_t msg5_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg5.buf = msg5_buf; + msg5.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + REQUIRE(client->handshake(&msg5, &msg4) == 1); + std::cout << "### Messages from server" << std::endl; + print_hex(msg4.buf, msg4.offsets[4]); + // encrypt - decrypt // client (encrypt) - server (decrypt) std::cout << "### Original Text" << std::endl; From 3d6b0f5212aed5c21cdbe764a3f8fc6353384374 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 13 Oct 2018 11:46:22 +0800 Subject: [PATCH 0864/1313] QUIC Client session reused by new session ticket --- iocore/net/quic/QUICConfig.cc | 12 ++++++++++++ iocore/net/quic/QUICConfig.h | 2 ++ iocore/net/quic/QUICGlobals.cc | 16 ++++++++++++++++ iocore/net/quic/QUICGlobals.h | 1 + iocore/net/quic/QUICTLS.h | 1 + iocore/net/quic/QUICTLS_openssl.cc | 26 ++++++++++++++++++++++++++ mgmt/RecordsConfig.cc | 2 ++ 7 files changed, 60 insertions(+) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 1ce79c81201..48b43a58ed5 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -115,6 +115,11 @@ quic_init_client_ssl_ctx(const QUICConfigParams *params) } } + if (params->session_file() != nullptr) { + SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE); + SSL_CTX_sess_set_new_cb(ssl_ctx, QUIC::ssl_client_new_session); + } + return ssl_ctx; } @@ -142,6 +147,7 @@ QUICConfigParams::initialize() 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->_session_file, "proxy.config.quic.client.session_file"); // Transport Parameters REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_in, "proxy.config.quic.no_activity_timeout_in"); @@ -416,6 +422,12 @@ QUICConfigParams::scid_len() return QUICConfigParams::_scid_len; } +const char * +QUICConfigParams::session_file() const +{ + return _session_file; +} + // // QUICConfig // diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 88953de3dc1..d0de94c7ee9 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -43,6 +43,7 @@ class QUICConfigParams : public ConfigInfo const char *server_supported_groups() const; const char *client_supported_groups() const; + const char *session_file() const; SSL_CTX *server_ssl_ctx() const; SSL_CTX *client_ssl_ctx() const; @@ -95,6 +96,7 @@ class QUICConfigParams : public ConfigInfo char *_server_supported_groups = nullptr; char *_client_supported_groups = nullptr; + char *_session_file = nullptr; // TODO: integrate with SSLCertLookup or SNIConfigParams SSL_CTX *_server_ssl_ctx = nullptr; diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index c318feb3651..0520f3ebfae 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -27,6 +27,7 @@ #include "P_SSLNextProtocolSet.h" #include "QUICStats.h" +#include "QUICConfig.h" #include "QUICConnection.h" RecRawStatBlock *quic_rsb; @@ -60,6 +61,21 @@ QUIC::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned cha return SSL_TLSEXT_ERR_NOACK; } +int +QUIC::ssl_client_new_session(SSL *ssl, SSL_SESSION *session) +{ + QUICConfig::scoped_config params; + auto file = BIO_new_file(params->session_file(), "w"); + if (file == nullptr) { + Debug("quic_global", "Could not write TLS session in %s", params->session_file()); + return 0; + } + + PEM_write_bio_SSL_SESSION(file, session); + BIO_free(file); + return 0; +} + void QUIC::_register_stats() { diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h index 0e1c1ebc9f9..4da21d16045 100644 --- a/iocore/net/quic/QUICGlobals.h +++ b/iocore/net/quic/QUICGlobals.h @@ -33,6 +33,7 @@ class QUIC // SSL callbacks static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen, void *); + static int ssl_client_new_session(SSL *ssl, SSL_SESSION *session); static int ssl_quic_qc_index; static int ssl_quic_tls_index; diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 4972678e5c4..b11991373ad 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -105,6 +105,7 @@ class QUICTLS : public QUICHandshakeProtocol QUICPacketProtection *_server_pp = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; bool _early_data_processed = false; + bool _is_session_reused = false; bool _early_data = true; QUICEncryptionLevel _current_level = QUICEncryptionLevel::INITIAL; HandshakeState _state = HandshakeState::PROCESSING; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 2e1357da0b3..42656e23da0 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -29,6 +29,8 @@ #include #include +#include "QUICConfig.h" + #include "QUICDebugNames.h" static constexpr char tag[] = "quic_tls"; @@ -233,6 +235,30 @@ QUICTLS::QUICTLS(SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx) SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_tls_index, this); SSL_set_key_callback(this->_ssl, key_cb, this); + + QUICConfig::scoped_config params; + if (params->session_file() && this->_netvc_context == NET_VCONNECTION_OUT) { + auto file = BIO_new_file(params->session_file(), "r"); + if (file == nullptr) { + Debug(tag, "Could not read tls session file %s", params->session_file()); + return; + } + + auto session = PEM_read_bio_SSL_SESSION(file, nullptr, 0, nullptr); + if (session == nullptr) { + Debug(tag, "Could not read tls session file %s", params->session_file()); + } else { + if (!SSL_set_session(this->_ssl, session)) { + Debug(tag, "Session resumption failed : %s", params->session_file()); + } else { + Debug(tag, "Session resumption success : %s", params->session_file()); + this->_is_session_reused = true; + } + SSL_SESSION_free(session); + } + + BIO_free(file); + } } QUICEncryptionLevel diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index f275de01a74..457ab2e7e50 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1345,6 +1345,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.client.supported_groups", RECD_STRING, "P-256:X25519:P-384:P-521" , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.client.session_file", RECD_STRING, nullptr , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} + , // Transport Parameters {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_in", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , From 73bddb3bb4c093ad073d9cafff17b10e5e242a74 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sun, 14 Oct 2018 09:48:34 +0800 Subject: [PATCH 0865/1313] QUIC: Changes QUICErrorUPtr to QUICConnectionUPtr to terminate the connection --- iocore/net/P_QUICNetVConnection.h | 40 +++---- iocore/net/QUICNetVConnection.cc | 133 ++++++++++----------- iocore/net/quic/QUICDebugNames.cc | 4 +- iocore/net/quic/QUICFrameDispatcher.cc | 12 +- iocore/net/quic/QUICFrameDispatcher.h | 4 +- iocore/net/quic/QUICFrameHandler.h | 4 +- iocore/net/quic/QUICHandshake.cc | 38 +++--- iocore/net/quic/QUICHandshake.h | 10 +- iocore/net/quic/QUICIncomingFrameBuffer.cc | 32 ++--- iocore/net/quic/QUICIncomingFrameBuffer.h | 8 +- iocore/net/quic/QUICLossDetector.cc | 4 +- iocore/net/quic/QUICLossDetector.h | 2 +- iocore/net/quic/QUICPathValidator.cc | 10 +- iocore/net/quic/QUICPathValidator.h | 4 +- iocore/net/quic/QUICStream.cc | 39 +++--- iocore/net/quic/QUICStream.h | 10 +- iocore/net/quic/QUICStreamManager.cc | 54 ++++----- iocore/net/quic/QUICStreamManager.h | 20 ++-- iocore/net/quic/QUICTypes.h | 10 +- src/traffic_quic/quic_client.cc | 4 +- 20 files changed, 215 insertions(+), 227 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 00a1d95db57..46909e07648 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -215,7 +215,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub // QUICConnection (QUICFrameHandler) std::vector interests() override; - QUICErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; + QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICConnection (QUICFrameGenerator) // bool will_generate_frame(QUICEncryptionLevel level); @@ -306,30 +306,30 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketType type = QUICPacketType::UNINITIALIZED); QUICPacketUPtr _build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable); - QUICErrorUPtr _recv_and_ack(QUICPacketUPtr packet); - - QUICErrorUPtr _state_handshake_process_packet(QUICPacketUPtr packet); - QUICErrorUPtr _state_handshake_process_version_negotiation_packet(QUICPacketUPtr packet); - QUICErrorUPtr _state_handshake_process_initial_packet(QUICPacketUPtr packet); - QUICErrorUPtr _state_handshake_process_retry_packet(QUICPacketUPtr packet); - QUICErrorUPtr _state_handshake_process_handshake_packet(QUICPacketUPtr packet); - QUICErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); - QUICErrorUPtr _state_connection_established_receive_packet(); - QUICErrorUPtr _state_connection_established_process_protected_packet(QUICPacketUPtr packet); - QUICErrorUPtr _state_connection_established_migrate_connection(const QUICPacket &p); - QUICErrorUPtr _state_connection_established_initiate_connection_migration(); - QUICErrorUPtr _state_closing_receive_packet(); - QUICErrorUPtr _state_draining_receive_packet(); - QUICErrorUPtr _state_common_send_packet(); - QUICErrorUPtr _state_handshake_send_retry_packet(); - QUICErrorUPtr _state_closing_send_packet(); + QUICConnectionErrorUPtr _recv_and_ack(QUICPacketUPtr packet); + + QUICConnectionErrorUPtr _state_handshake_process_packet(QUICPacketUPtr packet); + QUICConnectionErrorUPtr _state_handshake_process_version_negotiation_packet(QUICPacketUPtr packet); + QUICConnectionErrorUPtr _state_handshake_process_initial_packet(QUICPacketUPtr packet); + QUICConnectionErrorUPtr _state_handshake_process_retry_packet(QUICPacketUPtr packet); + QUICConnectionErrorUPtr _state_handshake_process_handshake_packet(QUICPacketUPtr packet); + QUICConnectionErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); + QUICConnectionErrorUPtr _state_connection_established_receive_packet(); + QUICConnectionErrorUPtr _state_connection_established_process_protected_packet(QUICPacketUPtr packet); + QUICConnectionErrorUPtr _state_connection_established_migrate_connection(const QUICPacket &p); + QUICConnectionErrorUPtr _state_connection_established_initiate_connection_migration(); + QUICConnectionErrorUPtr _state_closing_receive_packet(); + QUICConnectionErrorUPtr _state_draining_receive_packet(); + QUICConnectionErrorUPtr _state_common_send_packet(); + QUICConnectionErrorUPtr _state_handshake_send_retry_packet(); + QUICConnectionErrorUPtr _state_closing_send_packet(); Ptr _packet_transmitter_mutex; Ptr _frame_transmitter_mutex; void _init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); - void _handle_error(QUICErrorUPtr error); + void _handle_error(QUICConnectionErrorUPtr error); QUICPacketUPtr _dequeue_recv_packet(QUICPacketCreationResult &result); void _validate_new_path(); @@ -345,7 +345,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _handle_idle_timeout(); - QUICErrorUPtr _handle_frame(const QUICNewConnectionIdFrame &frame); + QUICConnectionErrorUPtr _handle_frame(const QUICNewConnectionIdFrame &frame); void _update_cids(); void _update_peer_cid(const QUICConnectionId &new_cid); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 45ffa0fe02f..5312a2be785 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -452,10 +452,10 @@ QUICNetVConnection::interests() QUICFrameType::NEW_CONNECTION_ID}; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) { - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; switch (frame.type()) { case QUICFrameType::MAX_DATA: @@ -485,11 +485,12 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra // An endpoint MAY transition from the closing period to the draining period if it can confirm that its peer is also closing or // draining. Receiving a closing frame is sufficient confirmation, as is receiving a stateless reset. if (frame.type() == QUICFrameType::APPLICATION_CLOSE) { - this->_switch_to_draining_state(QUICConnectionErrorUPtr( - new QUICConnectionError(QUICErrorClass::APPLICATION, static_cast(frame).error_code()))); + this->_switch_to_draining_state(QUICConnectionErrorUPtr(std::make_unique( + QUICErrorClass::APPLICATION, static_cast(frame).error_code()))); } else { - this->_switch_to_draining_state(QUICConnectionErrorUPtr( - new QUICConnectionError(QUICErrorClass::TRANSPORT, static_cast(frame).error_code()))); + uint16_t error_code = static_cast(frame).error_code(); + this->_switch_to_draining_state( + QUICConnectionErrorUPtr(std::make_unique(static_cast(error_code)))); } break; default: @@ -501,10 +502,10 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra return error; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_handle_frame(const QUICNewConnectionIdFrame &frame) { - QUICErrorUPtr error = std::make_unique(); + QUICConnectionErrorUPtr error = nullptr; if (frame.connection_id() == QUICConnectionId::ZERO()) { return std::make_unique(QUICTransErrorCode::PROTOCOL_VIOLATION, "received zero-length cid", @@ -557,7 +558,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) return this->handleEvent(event, data); } - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; switch (event) { case QUIC_EVENT_PACKET_READ_READY: { @@ -566,9 +567,9 @@ QUICNetVConnection::state_handshake(int event, Event *data) do { QUICPacketUPtr packet = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::NOT_READY) { - error = QUICErrorUPtr(new QUICNoError()); + error = nullptr; } else if (result == QUICPacketCreationResult::FAILED) { - error = QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); + error = std::make_unique(QUICTransErrorCode::INTERNAL_ERROR); } else if (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::UNSUPPORTED) { error = this->_state_handshake_process_packet(std::move(packet)); } @@ -579,8 +580,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) return this->handleEvent(event, data); } - } while (error->cls == QUICErrorClass::NONE && - (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::IGNORED)); + } while (error == nullptr && (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::IGNORED)); break; } case QUIC_EVENT_PACKET_WRITE_READY: { @@ -608,7 +608,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); } - if (error->cls != QUICErrorClass::NONE) { + if (error != nullptr) { this->_handle_error(std::move(error)); } @@ -619,7 +619,7 @@ int QUICNetVConnection::state_connection_established(int event, Event *data) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; switch (event) { case QUIC_EVENT_PACKET_READ_READY: { error = this->_state_connection_established_receive_packet(); @@ -647,7 +647,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); } - if (error->cls != QUICErrorClass::NONE) { + if (error != nullptr) { QUICConDebug("QUICError: cls=%u, code=0x%" PRIu16, static_cast(error->cls), error->code); this->_handle_error(std::move(error)); } @@ -660,7 +660,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; switch (event) { case QUIC_EVENT_PACKET_READ_READY: error = this->_state_closing_receive_packet(); @@ -692,7 +692,7 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; switch (event) { case QUIC_EVENT_PACKET_READ_READY: error = this->_state_draining_receive_packet(); @@ -837,10 +837,10 @@ QUICNetVConnection::largest_acked_packet_number(QUICEncryptionLevel level) const return this->_loss_detector[index]->largest_acked_packet_number(); } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) { - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; switch (packet->type()) { case QUICPacketType::VERSION_NEGOTIATION: error = this->_state_handshake_process_version_negotiation_packet(std::move(packet)); @@ -861,16 +861,16 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) default: QUICConDebug("Ignore %s(%" PRIu8 ") packet", QUICDebugNames::packet_type(packet->type()), static_cast(packet->type())); - error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); + error = std::make_unique(QUICTransErrorCode::INTERNAL_ERROR); break; } return error; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPacketUPtr packet) { - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; if (packet->destination_cid() != this->connection_id()) { QUICConDebug("Ignore Version Negotiation packet"); @@ -899,7 +899,7 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack return error; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packet) { // QUIC packet could be smaller than MINIMUM_INITIAL_PACKET_SIZE when coalescing packets @@ -909,7 +909,7 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe // return QUICErrorUPtr(new QUICNoError()); // } - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; // Start handshake if (this->netvc_context == NET_VCONNECTION_IN) { @@ -919,8 +919,8 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe if (this->_handshake_handler->is_version_negotiated()) { error = this->_recv_and_ack(std::move(packet)); - if (error->cls == QUICErrorClass::NONE && !this->_handshake_handler->has_remote_tp()) { - error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR)); + if (error == nullptr && !this->_handshake_handler->has_remote_tp()) { + error = std::make_unique(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR); } } } else { @@ -931,7 +931,7 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe return error; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) { // discard all transport state @@ -943,7 +943,7 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); this->_packet_retransmitter.reset(); - QUICErrorUPtr error = this->_recv_and_ack(std::move(packet)); + QUICConnectionErrorUPtr error = this->_recv_and_ack(std::move(packet)); // Packet number of RETRY packet is echo of INITIAL packet this->_packet_recv_queue.reset(); @@ -956,7 +956,7 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) return error; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_handshake_process_handshake_packet(QUICPacketUPtr packet) { // Source address is verified by receiving any message from the client encrypted using the @@ -967,7 +967,7 @@ QUICNetVConnection::_state_handshake_process_handshake_packet(QUICPacketUPtr pac return this->_recv_and_ack(std::move(packet)); } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet) { this->_stream_manager->init_flow_control_params(this->_handshake_handler->local_transport_parameters(), @@ -976,16 +976,16 @@ QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacke return this->_recv_and_ack(std::move(packet)); } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_connection_established_process_protected_packet(QUICPacketUPtr packet) { return this->_recv_and_ack(std::move(packet)); } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_connection_established_receive_packet() { - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; QUICPacketCreationResult result; // Receive a QUIC packet @@ -995,9 +995,9 @@ QUICNetVConnection::_state_connection_established_receive_packet() if (result == QUICPacketCreationResult::FAILED) { return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); } else if (result == QUICPacketCreationResult::NO_PACKET) { - return QUICErrorUPtr(new QUICNoError()); + return error; } else if (result == QUICPacketCreationResult::NOT_READY) { - return QUICErrorUPtr(new QUICNoError()); + return error; } else if (result == QUICPacketCreationResult::IGNORED) { continue; } @@ -1007,7 +1007,7 @@ QUICNetVConnection::_state_connection_established_receive_packet() case QUICPacketType::PROTECTED: // Migrate connection if required error = this->_state_connection_established_migrate_connection(*p); - if (error->cls != QUICErrorClass::NONE) { + if (error != nullptr) { break; } @@ -1026,16 +1026,15 @@ QUICNetVConnection::_state_connection_established_receive_packet() default: QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(p->type()), static_cast(p->type())); - error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); + error = std::make_unique(QUICTransErrorCode::INTERNAL_ERROR); break; } - } while (error->cls == QUICErrorClass::NONE && - (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::IGNORED)); + } while (error == nullptr && (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::IGNORED)); return error; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_closing_receive_packet() { while (this->_packet_recv_queue.size() > 0) { @@ -1063,10 +1062,10 @@ QUICNetVConnection::_state_closing_receive_packet() } } - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_draining_receive_packet() { while (this->_packet_recv_queue.size() > 0) { @@ -1079,7 +1078,7 @@ QUICNetVConnection::_state_draining_receive_packet() } } - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } /** @@ -1089,7 +1088,7 @@ QUICNetVConnection::_state_draining_receive_packet() * 4. Store data to the paylaod * 5. Send UDP Packet */ -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_common_send_packet() { uint32_t packet_count = 0; @@ -1156,11 +1155,11 @@ QUICNetVConnection::_state_common_send_packet() net_activity(this, this_ethread()); } - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } // RETRY packet contains ONLY a single STREAM frame -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_handshake_send_retry_packet() { // size_t len = 0; @@ -1186,10 +1185,10 @@ QUICNetVConnection::_state_handshake_send_retry_packet() // QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, 1); - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_closing_send_packet() { this->_packetize_closing_frame(); @@ -1204,7 +1203,8 @@ QUICNetVConnection::_state_closing_send_packet() if (this->_the_final_packet) { this->_packet_handler->send_packet(*this->_the_final_packet, this, this->_pn_protector); } - return QUICErrorUPtr(new QUICNoError()); + + return nullptr; } void @@ -1385,7 +1385,7 @@ QUICNetVConnection::_packetize_closing_frame() this->_the_final_packet = this->_build_packet(level, std::move(buf), len, false); } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) { const uint8_t *payload = packet->payload(); @@ -1396,10 +1396,10 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) bool should_send_ack; bool is_flow_controlled; - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; error = this->_frame_dispatcher->receive_frames(level, payload, size, should_send_ack, is_flow_controlled); - if (error->cls != QUICErrorClass::NONE) { + if (error != nullptr) { return error; } @@ -1413,7 +1413,7 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) this->_local_flow_controller->current_limit()); if (ret != 0) { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); + return std::make_unique(QUICTransErrorCode::FLOW_CONTROL_ERROR); } this->_local_flow_controller->forward_limit(this->_stream_manager->total_reordered_bytes() + this->_flow_control_buffer_size); @@ -1498,7 +1498,7 @@ QUICNetVConnection::_init_flow_control_params(const std::shared_ptrcls == QUICErrorClass::APPLICATION) { QUICError("QUICError: %s (%u), APPLICATION ERROR (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls), @@ -1508,15 +1508,8 @@ QUICNetVConnection::_handle_error(QUICErrorUPtr error) static_cast(error->cls), QUICDebugNames::error_code(error->code), error->code); } - if (dynamic_cast(error.get()) != nullptr) { - // Stream Error - QUICStreamError *serror = static_cast(error.release()); - this->_stream_manager->reset_stream(serror->stream->id(), QUICStreamErrorUPtr(serror)); - } else { - // Connection Error - QUICConnectionError *cerror = static_cast(error.release()); - this->close(QUICConnectionErrorUPtr(cerror)); - } + // Connection Error + this->close(std::move(error)); } QUICPacketUPtr @@ -1716,7 +1709,7 @@ QUICNetVConnection::_start_application() if (netvc_context == NET_VCONNECTION_IN) { Continuation *endpoint = this->_next_protocol_set->findEndpoint(app_name, app_name_len); if (endpoint == nullptr) { - this->_handle_error(QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR))); + this->_handle_error(std::make_unique(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR)); } else { endpoint->handleEvent(NET_EVENT_ACCEPT, this); } @@ -1916,13 +1909,13 @@ QUICNetVConnection::_setup_handshake_protocol(SSL_CTX *ctx) return tls; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_connection_established_migrate_connection(const QUICPacket &p) { ink_assert(this->_handshake_handler->is_completed()); - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - QUICConnectionId dcid = p.destination_cid(); + QUICConnectionErrorUPtr error = nullptr; + QUICConnectionId dcid = p.destination_cid(); if (dcid == this->_quic_connection_id) { return error; @@ -1966,13 +1959,13 @@ QUICNetVConnection::_state_connection_established_migrate_connection(const QUICP /** * Connection Migration Excercise from client */ -QUICErrorUPtr +QUICConnectionErrorUPtr QUICNetVConnection::_state_connection_established_initiate_connection_migration() { ink_assert(this->_handshake_handler->is_completed()); ink_assert(this->netvc_context == NET_VCONNECTION_OUT); - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; std::shared_ptr remote_tp = this->_handshake_handler->remote_transport_parameters(); QUICConfig::scoped_config params; diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 59fd5aa4e12..6340d1c0ceb 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -98,8 +98,8 @@ const char * QUICDebugNames::error_class(QUICErrorClass cls) { switch (cls) { - case QUICErrorClass::NONE: - return "NONE"; + case QUICErrorClass::UNDEFINED: + return "UNDEFINED"; case QUICErrorClass::TRANSPORT: return "TRANSPORT"; case QUICErrorClass::APPLICATION: diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 543a147f833..992be66cfba 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -41,15 +41,15 @@ QUICFrameDispatcher::add_handler(QUICFrameHandler *handler) } } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, bool &should_send_ack, bool &is_flow_controlled) { std::shared_ptr frame(nullptr); - uint16_t cursor = 0; - should_send_ack = false; - is_flow_controlled = false; - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + uint16_t cursor = 0; + should_send_ack = false; + is_flow_controlled = false; + QUICConnectionErrorUPtr error = nullptr; while (cursor < size) { frame = this->_frame_factory.fast_create(payload + cursor, size - cursor); @@ -77,7 +77,7 @@ QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *pa for (auto h : handlers) { error = h->handle_frame(level, *frame.get()); // TODO: is there any case to continue this loop even if error? - if (error->cls != QUICErrorClass::NONE) { + if (error != nullptr) { return error; } } diff --git a/iocore/net/quic/QUICFrameDispatcher.h b/iocore/net/quic/QUICFrameDispatcher.h index bd65ba1f880..25162d0fd5b 100644 --- a/iocore/net/quic/QUICFrameDispatcher.h +++ b/iocore/net/quic/QUICFrameDispatcher.h @@ -37,8 +37,8 @@ class QUICFrameDispatcher /* * Returns true if ACK frame should be sent */ - QUICErrorUPtr receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, bool &should_send_ackbool, - bool &is_flow_controlled); + QUICConnectionErrorUPtr receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, + bool &should_send_ackbool, bool &is_flow_controlled); void add_handler(QUICFrameHandler *handler); diff --git a/iocore/net/quic/QUICFrameHandler.h b/iocore/net/quic/QUICFrameHandler.h index 005797700dc..e237d438e4a 100644 --- a/iocore/net/quic/QUICFrameHandler.h +++ b/iocore/net/quic/QUICFrameHandler.h @@ -30,6 +30,6 @@ class QUICFrameHandler { public: virtual ~QUICFrameHandler(){}; - virtual std::vector interests() = 0; - virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) = 0; + virtual std::vector interests() = 0; + virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) = 0; }; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 01425fbd680..37c3d0af5a7 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -104,7 +104,7 @@ QUICHandshake::~QUICHandshake() delete this->_hs_protocol; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICHandshake::start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled) { QUICVersion initital_version = QUIC_SUPPORTED_VERSIONS[0]; @@ -115,16 +115,16 @@ QUICHandshake::start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled this->_load_local_client_transport_parameters(initital_version); packet_factory->set_version(initital_version); - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory) { // Negotiate version if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) { if (initial_packet->type() != QUICPacketType::INITIAL) { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); + return std::make_unique(QUICTransErrorCode::PROTOCOL_VIOLATION); } if (initial_packet->version()) { if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { @@ -135,13 +135,13 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet ink_assert(!"Unsupported version initial packet should be droped QUICPakcetHandler"); } } else { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); + return std::make_unique(QUICTransErrorCode::PROTOCOL_VIOLATION); } } - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICHandshake::negotiate_version(const QUICPacket *vn, QUICPacketFactory *packet_factory) { // Client side only @@ -151,12 +151,12 @@ QUICHandshake::negotiate_version(const QUICPacket *vn, QUICPacketFactory *packet if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED || this->_version_negotiator->status() == QUICVersionNegotiationStatus::VALIDATED) { QUICHSDebug("Ignore Version Negotiation packet"); - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } if (vn->version() != 0x00) { QUICHSDebug("Version field must be 0x00000000"); - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); + return std::make_unique(QUICTransErrorCode::PROTOCOL_VIOLATION); } if (this->_version_negotiator->negotiate(vn) == QUICVersionNegotiationStatus::NEGOTIATED) { @@ -165,10 +165,10 @@ QUICHandshake::negotiate_version(const QUICPacket *vn, QUICPacketFactory *packet packet_factory->set_version(version); } else { QUICHSDebug("Version negotiation failed"); - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR)); + return std::make_unique(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR); } - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } bool @@ -315,14 +315,16 @@ QUICHandshake::interests() }; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICHandshake::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) { - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); - + QUICConnectionErrorUPtr error = nullptr; switch (frame.type()) { case QUICFrameType::CRYPTO: error = this->_crypto_streams[static_cast(level)].recv(static_cast(frame)); + if (error != nullptr) { + return error; + } break; default: QUICHSDebug("Unexpected frame type: %02x", static_cast(frame.type())); @@ -330,9 +332,7 @@ QUICHandshake::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) break; } - error = this->do_handshake(); - - return error; + return this->do_handshake(); } bool @@ -431,10 +431,10 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi this->_hs_protocol->set_local_transport_parameters(std::unique_ptr(tp)); } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICHandshake::do_handshake() { - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; QUICHandshakeMsgs in; uint8_t in_buf[UDP_MAXIMUM_PAYLOAD_SIZE] = {0}; diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index ce016bfe9ae..f85384ba9fa 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -47,21 +47,21 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameHandler virtual std::vector interests() override; - virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; + virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; // for client side - QUICErrorUPtr start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled); - QUICErrorUPtr negotiate_version(const QUICPacket *packet, QUICPacketFactory *packet_factory); + QUICConnectionErrorUPtr start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled); + QUICConnectionErrorUPtr negotiate_version(const QUICPacket *packet, QUICPacketFactory *packet_factory); void reset(); // for server side - QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); + QUICConnectionErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); - QUICErrorUPtr do_handshake(); + QUICConnectionErrorUPtr do_handshake(); bool check_remote_transport_parameters(); diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index afb735bbad3..efc8f417934 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -75,7 +75,7 @@ QUICIncomingStreamFrameBuffer::pop() return nullptr; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICIncomingStreamFrameBuffer::insert(const QUICFrame &frame) { const QUICStreamFrame *stream_frame = static_cast(&frame); @@ -83,19 +83,19 @@ QUICIncomingStreamFrameBuffer::insert(const QUICFrame &frame) QUICOffset offset = stream_frame->offset(); size_t len = stream_frame->data_length(); - QUICErrorUPtr err = this->_check_and_set_fin_flag(offset, len, stream_frame->has_fin_flag()); - if (err->cls != QUICErrorClass::NONE) { + QUICConnectionErrorUPtr err = this->_check_and_set_fin_flag(offset, len, stream_frame->has_fin_flag()); + if (err != nullptr) { return err; } // Ignore empty stream frame except pure fin stream frame if (len == 0 && !stream_frame->has_fin_flag()) { - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } if (this->_recv_offset > offset) { // dup frame; - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } else if (this->_recv_offset == offset) { this->_recv_offset = offset + len; QUICFrameSPtr cloned = frame.clone(); @@ -105,7 +105,7 @@ QUICIncomingStreamFrameBuffer::insert(const QUICFrame &frame) this->_out_of_order_queue.insert(std::make_pair(offset, cloned)); } - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } void @@ -117,7 +117,7 @@ QUICIncomingStreamFrameBuffer::clear() super::clear(); } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICIncomingStreamFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t len, bool fin_flag) { // stream with fin flag {11.3. Stream Final Offset} @@ -134,23 +134,23 @@ QUICIncomingStreamFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t if (this->_fin_offset != UINT64_MAX) { if (this->_fin_offset == offset + len) { // dup fin frame - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } - return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::FINAL_OFFSET_ERROR)); + return std::make_unique(QUICTransErrorCode::FINAL_OFFSET_ERROR); } this->_fin_offset = offset + len; if (this->_max_offset > this->_fin_offset) { - return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::FINAL_OFFSET_ERROR)); + return std::make_unique(QUICTransErrorCode::FINAL_OFFSET_ERROR); } } else if (this->_fin_offset != UINT64_MAX && this->_fin_offset <= offset) { - return QUICErrorUPtr(new QUICStreamError(this->_stream, QUICTransErrorCode::FINAL_OFFSET_ERROR)); + return std::make_unique(QUICTransErrorCode::FINAL_OFFSET_ERROR); } this->_max_offset = std::max(offset + len, this->_max_offset); - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } bool @@ -209,7 +209,7 @@ QUICIncomingCryptoFrameBuffer::pop() return nullptr; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICIncomingCryptoFrameBuffer::insert(const QUICFrame &frame) { const QUICCryptoFrame *crypto_frame = static_cast(&frame); @@ -219,12 +219,12 @@ QUICIncomingCryptoFrameBuffer::insert(const QUICFrame &frame) // Ignore empty stream frame if (len == 0) { - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } if (this->_recv_offset > offset) { // dup frame; - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } else if (this->_recv_offset == offset) { this->_recv_offset = offset + len; QUICFrameSPtr cloned = frame.clone(); @@ -234,5 +234,5 @@ QUICIncomingCryptoFrameBuffer::insert(const QUICFrame &frame) this->_out_of_order_queue.insert(std::make_pair(offset, cloned)); } - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index 904b0bce3c4..11eb82fa5b6 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -37,7 +37,7 @@ class QUICIncomingFrameBuffer /* * Becasue frames passed by FrameDispatcher is temporal, this clones a passed frame to ensure that we can use it later. */ - virtual QUICErrorUPtr insert(const QUICFrame &frame) = 0; + virtual QUICConnectionErrorUPtr insert(const QUICFrame &frame) = 0; virtual void clear(); virtual bool empty(); @@ -57,7 +57,7 @@ class QUICIncomingStreamFrameBuffer : public QUICIncomingFrameBuffer, public QUI ~QUICIncomingStreamFrameBuffer(); QUICFrameSPtr pop() override; - QUICErrorUPtr insert(const QUICFrame &frame) override; + QUICConnectionErrorUPtr insert(const QUICFrame &frame) override; void clear() override; // QUICTransferProgressProvider @@ -67,7 +67,7 @@ class QUICIncomingStreamFrameBuffer : public QUICIncomingFrameBuffer, public QUI uint64_t transfer_goal() const override; private: - QUICErrorUPtr _check_and_set_fin_flag(QUICOffset offset, size_t len = 0, bool fin_flag = false); + QUICConnectionErrorUPtr _check_and_set_fin_flag(QUICOffset offset, size_t len = 0, bool fin_flag = false); const QUICStream *_stream = nullptr; QUICOffset _max_offset = 0; @@ -83,7 +83,7 @@ class QUICIncomingCryptoFrameBuffer : public QUICIncomingFrameBuffer ~QUICIncomingCryptoFrameBuffer(); QUICFrameSPtr pop() override; - QUICErrorUPtr insert(const QUICFrame &frame) override; + QUICConnectionErrorUPtr insert(const QUICFrame &frame) override; private: }; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index dabda03cf09..5aa580dafc8 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -105,10 +105,10 @@ QUICLossDetector::interests() return {QUICFrameType::ACK}; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICLossDetector::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) { - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; if (this->_pn_space_index != QUICTypeUtil::pn_space_index(level)) { return error; diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 3dd243762a2..354698eae0c 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -116,7 +116,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler int event_handler(int event, Event *edata); std::vector interests() override; - virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; + virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; void on_packet_sent(QUICPacketUPtr packet); QUICPacketNumber largest_acked_packet_number(); void reset(); diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index f222d7c8df7..eafc54ea532 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -63,17 +63,17 @@ QUICPathValidator::_generate_response(const QUICPathChallengeFrame &frame) this->_has_outgoing_response = true; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICPathValidator::_validate_response(const QUICPathResponseFrame &frame) { - QUICErrorUPtr error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); + QUICConnectionErrorUPtr error = std::make_unique(QUICTransErrorCode::PROTOCOL_VIOLATION); for (int i = 0; i < 3; ++i) { if (memcmp(this->_outgoing_challenge + (QUICPathChallengeFrame::DATA_LEN * i), frame.data(), QUICPathChallengeFrame::DATA_LEN) == 0) { this->_state = ValidationState::VALIDATED; this->_has_outgoing_challenge = 0; - error = QUICErrorUPtr(new QUICNoError()); + error = nullptr; break; } } @@ -90,10 +90,10 @@ QUICPathValidator::interests() return {QUICFrameType::PATH_CHALLENGE, QUICFrameType::PATH_RESPONSE}; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICPathValidator::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) { - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; switch (frame.type()) { case QUICFrameType::PATH_CHALLENGE: diff --git a/iocore/net/quic/QUICPathValidator.h b/iocore/net/quic/QUICPathValidator.h index 260ed006f81..afa4abfb8ff 100644 --- a/iocore/net/quic/QUICPathValidator.h +++ b/iocore/net/quic/QUICPathValidator.h @@ -38,7 +38,7 @@ class QUICPathValidator : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameHandler std::vector interests() override; - QUICErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; + QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICFrameGeneratro bool will_generate_frame(QUICEncryptionLevel level) override; @@ -58,5 +58,5 @@ class QUICPathValidator : public QUICFrameHandler, public QUICFrameGenerator void _generate_challenge(); void _generate_response(const QUICPathChallengeFrame &frame); - QUICErrorUPtr _validate_response(const QUICPathResponseFrame &frame); + QUICConnectionErrorUPtr _validate_response(const QUICPathResponseFrame &frame); }; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 6d37419572d..93128741dc3 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -99,7 +99,7 @@ int QUICStream::state_stream_open(int event, void *data) { QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); - QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); + QUICErrorUPtr error = nullptr; switch (event) { case VC_EVENT_READ_READY: @@ -133,7 +133,8 @@ QUICStream::state_stream_open(int event, void *data) ink_assert(false); } - if (error->cls != QUICErrorClass::NONE) { + // FIXME error is always nullptr + if (error != nullptr) { if (error->cls == QUICErrorClass::TRANSPORT) { QUICStreamDebug("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), static_cast(error->cls), QUICDebugNames::error_code(error->code), @@ -293,7 +294,7 @@ QUICStream::_write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t * If the reordering or writting operation is heavy, split out them to read function, * which is called by application via do_io_read() or reenable(). */ -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStream::recv(const QUICStreamFrame &frame) { ink_assert(_id == frame.stream_id()); @@ -302,7 +303,7 @@ QUICStream::recv(const QUICStreamFrame &frame) // Check stream state - Do this first before accept the frame if (!this->_state.is_allowed_to_receive(frame)) { QUICStreamDebug("Canceled receiving %s frame due to the stream state", QUICDebugNames::frame_type(frame.type())); - return QUICErrorUPtr(new QUICStreamError(this, QUICTransErrorCode::STREAM_STATE_ERROR)); + return std::make_unique(QUICTransErrorCode::STREAM_STATE_ERROR); } // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit @@ -310,11 +311,11 @@ QUICStream::recv(const QUICStreamFrame &frame) QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), this->_local_flow_controller.current_limit()); if (ret != 0) { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::FLOW_CONTROL_ERROR)); + return std::make_unique(QUICTransErrorCode::FLOW_CONTROL_ERROR); } - QUICErrorUPtr error = this->_received_stream_frame_buffer.insert(frame); - if (error->cls != QUICErrorClass::NONE) { + QUICConnectionErrorUPtr error = this->_received_stream_frame_buffer.insert(frame); + if (error != nullptr) { this->_received_stream_frame_buffer.clear(); return error; } @@ -342,10 +343,10 @@ QUICStream::recv(const QUICStreamFrame &frame) this->_signal_read_event(); - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStream::recv(const QUICMaxStreamDataFrame &frame) { this->_remote_flow_controller.forward_limit(frame.maximum_stream_data()); @@ -357,23 +358,23 @@ QUICStream::recv(const QUICMaxStreamDataFrame &frame) this->_signal_write_event(); } - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStream::recv(const QUICStreamBlockedFrame &frame) { // STREAM_BLOCKED frames are for debugging. Nothing to do here. - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStream::recv(const QUICStopSendingFrame &frame) { this->_state.update_with_receiving_frame(frame); this->_reset_reason = QUICStreamErrorUPtr(new QUICStreamError(this, QUIC_APP_ERROR_CODE_STOPPING)); // We received and processed STOP_SENDING frame, so return NO_ERROR here - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } bool @@ -632,11 +633,11 @@ QUICCryptoStream::reset_recv_offset() this->_received_stream_frame_buffer.clear(); } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICCryptoStream::recv(const QUICCryptoFrame &frame) { - QUICErrorUPtr error = this->_received_stream_frame_buffer.insert(frame); - if (error->cls != QUICErrorClass::NONE) { + QUICConnectionErrorUPtr error = this->_received_stream_frame_buffer.insert(frame); + if (error != nullptr) { this->_received_stream_frame_buffer.clear(); return error; } @@ -649,7 +650,7 @@ QUICCryptoStream::recv(const QUICCryptoFrame &frame) new_frame = this->_received_stream_frame_buffer.pop(); } - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } int64_t @@ -679,7 +680,7 @@ QUICCryptoStream::will_generate_frame(QUICEncryptionLevel level) QUICFrameUPtr QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { - QUICErrorUPtr error = std::unique_ptr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; if (this->_reset_reason) { return QUICFrameFactory::create_rst_stream_frame(std::move(this->_reset_reason)); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 20d751ff2bb..b2b43bb0fb4 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -67,10 +67,10 @@ class QUICStream : public VConnection, public QUICFrameGenerator void do_io_shutdown(ShutdownHowTo_t howto) override; void reenable(VIO *vio) override; - QUICErrorUPtr recv(const QUICStreamFrame &frame); - QUICErrorUPtr recv(const QUICMaxStreamDataFrame &frame); - QUICErrorUPtr recv(const QUICStreamBlockedFrame &frame); - QUICErrorUPtr recv(const QUICStopSendingFrame &frame); + QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame); + QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame); + QUICConnectionErrorUPtr recv(const QUICStreamBlockedFrame &frame); + QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame); void reset(QUICStreamErrorUPtr error); @@ -138,7 +138,7 @@ class QUICCryptoStream : public QUICFrameGenerator void reset_send_offset(); void reset_recv_offset(); - QUICErrorUPtr recv(const QUICCryptoFrame &frame); + QUICConnectionErrorUPtr recv(const QUICCryptoFrame &frame); int64_t read_avail(); int64_t read(uint8_t *buf, int64_t len); int64_t write(const uint8_t *buf, int64_t len); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index a106ac1827c..6d047579800 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -85,13 +85,14 @@ QUICStreamManager::set_max_stream_id(QUICStreamId id) } } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStreamManager::create_stream(QUICStreamId stream_id) { // TODO: check stream_id - QUICStream *stream = this->_find_or_create_stream(stream_id); + QUICConnectionErrorUPtr error = nullptr; + QUICStream *stream = this->_find_or_create_stream(stream_id); if (!stream) { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); + return std::make_unique(QUICTransErrorCode::STREAM_ID_ERROR); } QUICApplication *application = this->_app_map->get(stream_id); @@ -100,14 +101,14 @@ QUICStreamManager::create_stream(QUICStreamId stream_id) application->set_stream(stream); } - return QUICErrorUPtr(new QUICNoError()); + return error; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStreamManager::create_uni_stream(QUICStreamId &new_stream_id) { - QUICErrorUPtr error = this->create_stream(this->_next_stream_id_uni); - if (error->cls == QUICErrorClass::NONE) { + QUICConnectionErrorUPtr error = this->create_stream(this->_next_stream_id_uni); + if (error == nullptr) { new_stream_id = this->_next_stream_id_uni; this->_next_stream_id_uni += 2; } @@ -115,11 +116,11 @@ QUICStreamManager::create_uni_stream(QUICStreamId &new_stream_id) return error; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStreamManager::create_bidi_stream(QUICStreamId &new_stream_id) { - QUICErrorUPtr error = this->create_stream(this->_next_stream_id_bidi); - if (error->cls == QUICErrorClass::NONE) { + QUICConnectionErrorUPtr error = this->create_stream(this->_next_stream_id_bidi); + if (error == nullptr) { new_stream_id = this->_next_stream_id_bidi; this->_next_stream_id_bidi += 2; } @@ -134,10 +135,10 @@ QUICStreamManager::reset_stream(QUICStreamId stream_id, QUICStreamErrorUPtr erro stream->reset(std::move(error)); } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStreamManager::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) { - QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + QUICConnectionErrorUPtr error = nullptr; switch (frame.type()) { case QUICFrameType::MAX_STREAM_DATA: @@ -168,34 +169,34 @@ QUICStreamManager::handle_frame(QUICEncryptionLevel level, const QUICFrame &fram return error; } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStreamManager::_handle_frame(const QUICMaxStreamDataFrame &frame) { QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); if (stream) { return stream->recv(frame); } else { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); + return std::make_unique(QUICTransErrorCode::STREAM_ID_ERROR); } } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStreamManager::_handle_frame(const QUICStreamBlockedFrame &frame) { QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); if (stream) { return stream->recv(frame); } else { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); + return std::make_unique(QUICTransErrorCode::STREAM_ID_ERROR); } } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStreamManager::_handle_frame(const QUICStreamFrame &frame) { QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); if (!stream) { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); + return std::make_unique(QUICTransErrorCode::STREAM_ID_ERROR); } QUICApplication *application = this->_app_map->get(frame.stream_id()); @@ -203,35 +204,34 @@ QUICStreamManager::_handle_frame(const QUICStreamFrame &frame) if (application && !application->is_stream_set(stream)) { application->set_stream(stream); } - QUICErrorUPtr error = stream->recv(frame); - return error; + return stream->recv(frame); } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStreamManager::_handle_frame(const QUICRstStreamFrame &frame) { QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); if (stream) { // TODO Reset the stream - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } else { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); + return std::make_unique(QUICTransErrorCode::STREAM_ID_ERROR); } } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStreamManager::_handle_frame(const QUICStopSendingFrame &frame) { QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); if (stream) { return stream->recv(frame); } else { - return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::STREAM_ID_ERROR)); + return std::make_unique(QUICTransErrorCode::STREAM_ID_ERROR); } } -QUICErrorUPtr +QUICConnectionErrorUPtr QUICStreamManager::_handle_frame(const QUICMaxStreamIdFrame &frame) { QUICStreamType type = QUICTypeUtil::detect_stream_type(frame.maximum_stream_id()); @@ -240,7 +240,7 @@ QUICStreamManager::_handle_frame(const QUICMaxStreamIdFrame &frame) } else { this->_remote_maximum_stream_id_uni = frame.maximum_stream_id(); } - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } QUICStream * diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 0e0266e4fbe..3f5d563a324 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -49,9 +49,9 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator void add_total_offset_sent(uint32_t sent_byte); uint32_t stream_count() const; - QUICErrorUPtr create_stream(QUICStreamId stream_id); - QUICErrorUPtr create_uni_stream(QUICStreamId &new_stream_id); - QUICErrorUPtr create_bidi_stream(QUICStreamId &new_stream_id); + QUICConnectionErrorUPtr create_stream(QUICStreamId stream_id); + QUICConnectionErrorUPtr create_uni_stream(QUICStreamId &new_stream_id); + QUICConnectionErrorUPtr create_bidi_stream(QUICStreamId &new_stream_id); void reset_stream(QUICStreamId stream_id, QUICStreamErrorUPtr error); void set_default_application(QUICApplication *app); @@ -60,7 +60,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameHandler virtual std::vector interests() override; - virtual QUICErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; + virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; @@ -69,12 +69,12 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator private: QUICStream *_find_stream(QUICStreamId id); QUICStream *_find_or_create_stream(QUICStreamId stream_id); - QUICErrorUPtr _handle_frame(const QUICStreamFrame &frame); - QUICErrorUPtr _handle_frame(const QUICRstStreamFrame &frame); - QUICErrorUPtr _handle_frame(const QUICStopSendingFrame &frame); - QUICErrorUPtr _handle_frame(const QUICMaxStreamDataFrame &frame); - QUICErrorUPtr _handle_frame(const QUICStreamBlockedFrame &frame); - QUICErrorUPtr _handle_frame(const QUICMaxStreamIdFrame &frame); + QUICConnectionErrorUPtr _handle_frame(const QUICStreamFrame &frame); + QUICConnectionErrorUPtr _handle_frame(const QUICRstStreamFrame &frame); + QUICConnectionErrorUPtr _handle_frame(const QUICStopSendingFrame &frame); + QUICConnectionErrorUPtr _handle_frame(const QUICMaxStreamDataFrame &frame); + QUICConnectionErrorUPtr _handle_frame(const QUICStreamBlockedFrame &frame); + QUICConnectionErrorUPtr _handle_frame(const QUICMaxStreamIdFrame &frame); std::vector _encryption_level_filter() override { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 7d617bfccbd..5c1b1b954d8 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -139,7 +139,7 @@ enum class QUICPacketCreationResult { }; enum class QUICErrorClass { - NONE, + UNDEFINED, TRANSPORT, APPLICATION, }; @@ -169,7 +169,7 @@ class QUICError public: virtual ~QUICError() {} - QUICErrorClass cls = QUICErrorClass::NONE; + QUICErrorClass cls = QUICErrorClass::UNDEFINED; uint16_t code = 0; const char *msg = nullptr; @@ -181,12 +181,6 @@ class QUICError } }; -class QUICNoError : public QUICError -{ -public: - QUICNoError() : QUICError() {} -}; - class QUICConnectionError : public QUICError { public: diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc index ae8fcd34a4a..547240e428e 100644 --- a/src/traffic_quic/quic_client.cc +++ b/src/traffic_quic/quic_client.cc @@ -129,9 +129,9 @@ QUICClientApp::start(const char *path) } QUICStreamId stream_id; - QUICErrorUPtr error = this->_qc->stream_manager()->create_bidi_stream(stream_id); + QUICConnectionErrorUPtr error = this->_qc->stream_manager()->create_bidi_stream(stream_id); - if (error->cls != QUICErrorClass::NONE) { + if (error != nullptr) { Error("%s", error->msg); ink_assert(!error->msg); } From 5d6bd76131a828a0b1993a5eba7d51c94ce8476f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 16 Oct 2018 14:11:24 +0900 Subject: [PATCH 0866/1313] Remove unused variable --- iocore/net/quic/QUICIncomingFrameBuffer.h | 7 +++---- iocore/net/quic/QUICStream.cc | 2 +- iocore/net/quic/QUICStream.h | 2 +- iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc | 10 +++++----- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index 11eb82fa5b6..456ea41dec0 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -53,7 +53,7 @@ class QUICIncomingStreamFrameBuffer : public QUICIncomingFrameBuffer, public QUI public: using super = QUICIncomingFrameBuffer; ///< Parent type. - QUICIncomingStreamFrameBuffer(const QUICStream *stream) : _stream(stream) {} + QUICIncomingStreamFrameBuffer() {} ~QUICIncomingStreamFrameBuffer(); QUICFrameSPtr pop() override; @@ -69,9 +69,8 @@ class QUICIncomingStreamFrameBuffer : public QUICIncomingFrameBuffer, public QUI private: QUICConnectionErrorUPtr _check_and_set_fin_flag(QUICOffset offset, size_t len = 0, bool fin_flag = false); - const QUICStream *_stream = nullptr; - QUICOffset _max_offset = 0; - QUICOffset _fin_offset = UINT64_MAX; + QUICOffset _max_offset = 0; + QUICOffset _fin_offset = UINT64_MAX; }; class QUICIncomingCryptoFrameBuffer : public QUICIncomingFrameBuffer diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 93128741dc3..cad165345cc 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -51,7 +51,7 @@ QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider _remote_flow_controller(send_max_stream_data, _id), _local_flow_controller(rtt_provider, recv_max_stream_data, _id), _flow_control_buffer_size(recv_max_stream_data), - _received_stream_frame_buffer(this), + _received_stream_frame_buffer(), _state(nullptr, nullptr, &_received_stream_frame_buffer, nullptr) { SET_HANDLER(&QUICStream::state_stream_open); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index b2b43bb0fb4..c5a7967e507 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -45,7 +45,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator : VConnection(nullptr), _remote_flow_controller(0, 0), _local_flow_controller(nullptr, 0, 0), - _received_stream_frame_buffer(this), + _received_stream_frame_buffer(), _state(nullptr, nullptr, nullptr, nullptr) { } diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 1ee7add8605..3cbea36c23d 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -30,7 +30,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") { QUICStream *stream = new QUICStream(); - QUICIncomingStreamFrameBuffer buffer(stream); + QUICIncomingStreamFrameBuffer buffer; QUICErrorUPtr err = nullptr; uint8_t data[1024] = {0}; @@ -59,7 +59,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") CHECK(err->cls == QUICErrorClass::TRANSPORT); CHECK(err->code == static_cast(QUICTransErrorCode::FINAL_OFFSET_ERROR)); - QUICIncomingStreamFrameBuffer buffer2(stream); + QUICIncomingStreamFrameBuffer buffer2; buffer2.insert(*stream1_frame_3_r); buffer2.insert(*stream1_frame_0_r); @@ -68,7 +68,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") CHECK(err->cls == QUICErrorClass::TRANSPORT); CHECK(err->code == static_cast(QUICTransErrorCode::FINAL_OFFSET_ERROR)); - QUICIncomingStreamFrameBuffer buffer3(stream); + QUICIncomingStreamFrameBuffer buffer3; buffer3.insert(*stream1_frame_4_r); err = buffer3.insert(*stream1_frame_3_r); @@ -98,7 +98,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") { QUICStream *stream = new QUICStream(); - QUICIncomingStreamFrameBuffer buffer(stream); + QUICIncomingStreamFrameBuffer buffer; QUICErrorUPtr err = nullptr; uint8_t data[1024] = {0}; @@ -157,7 +157,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") { QUICStream *stream = new QUICStream(); - QUICIncomingStreamFrameBuffer buffer(stream); + QUICIncomingStreamFrameBuffer buffer; QUICErrorUPtr err = nullptr; uint8_t data[1024] = {0}; From bfa09998a69508c120fc93e8846f7788c06aa478 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 16 Oct 2018 14:26:31 +0900 Subject: [PATCH 0867/1313] Fix unit tests --- iocore/net/quic/Mock.h | 8 ++++---- .../net/quic/test/test_QUICIncomingFrameBuffer.cc | 13 ++++++------- iocore/net/quic/test/test_QUICStream.cc | 12 ++++++------ 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index db1c44beeb2..4f5742f4857 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -36,13 +36,13 @@ class MockQUICStreamManager : public QUICStreamManager public: MockQUICStreamManager() : QUICStreamManager() {} // Override - virtual QUICErrorUPtr + virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &f) override { ++_frameCount[static_cast(f.type())]; ++_totalFrameCount; - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } // for Test @@ -197,13 +197,13 @@ class MockQUICConnection : public QUICConnection return {QUICFrameType::CONNECTION_CLOSE}; } - QUICErrorUPtr + QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &f) override { ++_frameCount[static_cast(f.type())]; ++_totalFrameCount; - return QUICErrorUPtr(new QUICNoError()); + return nullptr; } uint32_t diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 3cbea36c23d..64325a0e543 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -40,8 +40,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0, true); err = buffer.insert(*stream1_frame_0_r); - CHECK(err->cls == QUICErrorClass::NONE); - CHECK(err->code != static_cast(QUICTransErrorCode::FINAL_OFFSET_ERROR)); + CHECK(err == nullptr); } SECTION("multiple frames") @@ -83,13 +82,13 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") std::shared_ptr stream1_frame_pure_fin = QUICFrameFactory::create_stream_frame(data, 0, 1, 1024, true); err = buffer.insert(*stream1_frame_0_r); - CHECK(err->cls == QUICErrorClass::NONE); + CHECK(err == nullptr); err = buffer.insert(*stream1_frame_empty); - CHECK(err->cls == QUICErrorClass::NONE); + CHECK(err == nullptr); err = buffer.insert(*stream1_frame_pure_fin); - CHECK(err->cls == QUICErrorClass::NONE); + CHECK(err == nullptr); } delete stream; @@ -171,7 +170,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") buffer.insert(*stream1_frame_1_r); buffer.insert(*stream1_frame_2_r); err = buffer.insert(*stream1_frame_3_r); - CHECK(err->cls == QUICErrorClass::NONE); + CHECK(err == nullptr); auto frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 0); @@ -194,7 +193,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") buffer.insert(*stream2_frame_1_r); buffer.insert(*stream2_frame_2_r); err = buffer.insert(*stream2_frame_3_r); - CHECK(err->cls == QUICErrorClass::NONE); + CHECK(err == nullptr); frame = std::static_pointer_cast(buffer.pop()); CHECK(frame->offset() == 0); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index a0ddf0c6098..e1268bd2557 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -160,21 +160,21 @@ TEST_CASE("QUICStream", "[quic]") // Start with 1024 but not 0 so received frames won't be processed error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 1024)); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(error == nullptr); // duplicate error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 1024)); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(error == nullptr); error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 3072)); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(error == nullptr); // delay error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 2048)); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(error == nullptr); // all frames should be processed error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 0)); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(error == nullptr); // start again without the first block error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 5120)); - CHECK(error->cls == QUICErrorClass::NONE); + CHECK(error == nullptr); // this should exceed the limit error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 8192)); CHECK(error->cls == QUICErrorClass::TRANSPORT); From f2db48fb4147fa03b6ca6f4fea67c9f4db24a9af Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 16 Oct 2018 16:58:57 +0800 Subject: [PATCH 0868/1313] QUIC: Ignore empty msg when handshake success --- iocore/net/quic/QUICTLS_openssl.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 42656e23da0..17431b47f57 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -288,7 +288,11 @@ int QUICTLS::handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) { if (this->is_handshake_finished()) { - return this->_process_post_handshake_messages(out, in); + if (in != nullptr && in->offsets[4] != 0) { + return this->_process_post_handshake_messages(out, in); + } + + return 0; } return this->_handshake(out, in); @@ -330,7 +334,7 @@ QUICTLS::_handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) ret = SSL_connect(this->_ssl); } - if (ret < 0) { + if (ret <= 0) { err = SSL_get_error(this->_ssl, ret); switch (err) { @@ -373,7 +377,7 @@ QUICTLS::_process_post_handshake_messages(QUICHandshakeMsgs *out, const QUICHand size_t l = 0; ret = SSL_read_ex(this->_ssl, data, 2048, &l); - if (ret < 0) { + if (ret <= 0) { err = SSL_get_error(this->_ssl, ret); switch (err) { From 372e9c0104a3ea1bd1c9e8ab9bb7da891da05a03 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 19 Oct 2018 11:19:54 +0900 Subject: [PATCH 0869/1313] Add is_probing_frame() and is_probing_packet() --- iocore/net/P_QUICNetVConnection.h | 4 +-- iocore/net/QUICNetVConnection.cc | 27 ++++++++++------ iocore/net/quic/QUICFrame.cc | 24 ++++++++++++++ iocore/net/quic/QUICFrame.h | 6 +++- iocore/net/quic/QUICPacket.cc | 31 ++++++++++++------- iocore/net/quic/QUICPacket.h | 14 +++++---- iocore/net/quic/test/test_QUICFrame.cc | 2 +- iocore/net/quic/test/test_QUICLossDetector.cc | 20 ++++++------ .../net/quic/test/test_QUICPacketFactory.cc | 4 +-- .../quic/test/test_QUICVersionNegotiator.cc | 8 ++--- 10 files changed, 93 insertions(+), 47 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 46909e07648..04394ac9bd1 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -302,9 +302,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr frame); QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size); void _packetize_closing_frame(); - QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, + QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, bool probing, QUICPacketType type = QUICPacketType::UNINITIALIZED); - QUICPacketUPtr _build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable); + QUICPacketUPtr _build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing); QUICConnectionErrorUPtr _recv_and_ack(QUICPacketUPtr packet); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5312a2be785..1a35baf8110 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1238,6 +1238,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa uint64_t max_frame_size = max_packet_size - MAX_PACKET_OVERHEAD; max_frame_size = std::min(max_frame_size, this->_maximum_stream_frame_data_size()); + bool probing = false; int frame_count = 0; size_t len = 0; ats_unique_buf buf = ats_unique_malloc(max_packet_size); @@ -1250,6 +1251,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); while (frame) { ++frame_count; + probing |= frame->is_probing_frame(); this->_store_frame(buf, len, max_frame_size, std::move(frame)); frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); } @@ -1258,6 +1260,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_path_validator->generate_frame(level, UINT16_MAX, max_frame_size); if (frame) { ++frame_count; + probing |= frame->is_probing_frame(); this->_store_frame(buf, len, max_frame_size, std::move(frame)); } @@ -1266,6 +1269,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_alt_con_manager->generate_frame(level, UINT16_MAX, max_frame_size); while (frame) { ++frame_count; + probing |= frame->is_probing_frame(); this->_store_frame(buf, len, max_frame_size, std::move(frame)); frame = this->_alt_con_manager->generate_frame(level, UINT16_MAX, max_frame_size); @@ -1276,6 +1280,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_packet_retransmitter.generate_frame(level, UINT16_MAX, max_frame_size); while (frame) { ++frame_count; + probing |= frame->is_probing_frame(); this->_store_frame(buf, len, max_frame_size, std::move(frame)); frame = this->_packet_retransmitter.generate_frame(level, UINT16_MAX, max_frame_size); @@ -1285,6 +1290,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_local_flow_controller->generate_frame(level, UINT16_MAX, max_frame_size); if (frame) { ++frame_count; + probing |= frame->is_probing_frame(); this->_store_frame(buf, len, max_frame_size, std::move(frame)); } @@ -1293,6 +1299,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_remote_flow_controller->generate_frame(level, UINT16_MAX, max_frame_size); if (frame) { ++frame_count; + probing |= frame->is_probing_frame(); this->_store_frame(buf, len, max_frame_size, std::move(frame)); } } @@ -1302,6 +1309,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); while (frame) { ++frame_count; + probing |= frame->is_probing_frame(); if (frame->type() == QUICFrameType::STREAM) { int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), @@ -1333,6 +1341,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa ack_only = true; } ++frame_count; + probing |= frame->is_probing_frame(); this->_store_frame(buf, len, max_frame_size, std::move(frame)); } @@ -1350,7 +1359,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } // Packet is retransmittable if it's not ack only packet - packet = this->_build_packet(level, std::move(buf), len, !ack_only); + packet = this->_build_packet(level, std::move(buf), len, !ack_only, probing); } return packet; @@ -1382,7 +1391,7 @@ QUICNetVConnection::_packetize_closing_frame() QUICEncryptionLevel level = this->_hs_protocol->current_encryption_level(); ink_assert(level != QUICEncryptionLevel::ZERO_RTT); - this->_the_final_packet = this->_build_packet(level, std::move(buf), len, false); + this->_the_final_packet = this->_build_packet(level, std::move(buf), len, false, false); } QUICConnectionErrorUPtr @@ -1427,13 +1436,13 @@ QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) } QUICPacketUPtr -QUICNetVConnection::_build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable) +QUICNetVConnection::_build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing) { - return this->_build_packet(std::move(buf), len, retransmittable, QUICTypeUtil::packet_type(level)); + return this->_build_packet(std::move(buf), len, retransmittable, probing, QUICTypeUtil::packet_type(level)); } QUICPacketUPtr -QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, QUICPacketType type) +QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, bool probing, QUICPacketType type) { QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); @@ -1443,25 +1452,25 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi (this->netvc_context == NET_VCONNECTION_OUT) ? this->_original_quic_connection_id : this->_peer_quic_connection_id; packet = this->_packet_factory.create_initial_packet(dcid, this->_quic_connection_id, this->largest_acked_packet_number(QUICEncryptionLevel::INITIAL), - std::move(buf), len, retransmittable); + std::move(buf), len, retransmittable, probing); break; } case QUICPacketType::RETRY: { // Echo "_largest_received_packet_number" as packet number. Probably this is the packet number from triggering client packet. packet = this->_packet_factory.create_retry_packet(this->_peer_quic_connection_id, this->_quic_connection_id, std::move(buf), - len, retransmittable); + len, retransmittable, probing); break; } case QUICPacketType::HANDSHAKE: { packet = this->_packet_factory.create_handshake_packet(this->_peer_quic_connection_id, this->_quic_connection_id, this->largest_acked_packet_number(QUICEncryptionLevel::HANDSHAKE), - std::move(buf), len, retransmittable); + std::move(buf), len, retransmittable, 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, retransmittable); + std::move(buf), len, retransmittable, probing); break; } default: diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index c002e9fd434..bfe17f23742 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -56,6 +56,12 @@ QUICFrame::type() const return QUICFrame::type(this->_buf); } +bool +QUICFrame::is_probing_frame() const +{ + return false; +} + QUICFrameType QUICFrame::type(const uint8_t *buf) { @@ -1177,6 +1183,12 @@ QUICPaddingFrame::size() const return 1; } +bool +QUICPaddingFrame::is_probing_frame() const +{ + return true; +} + size_t QUICPaddingFrame::store(uint8_t *buf, size_t *len, size_t limit) const { @@ -2216,6 +2228,12 @@ QUICPathChallengeFrame::size() const return this->_data_offset() + QUICPathChallengeFrame::DATA_LEN; } +bool +QUICPathChallengeFrame::is_probing_frame() const +{ + return true; +} + size_t QUICPathChallengeFrame::store(uint8_t *buf, size_t *len, size_t limit) const { @@ -2272,6 +2290,12 @@ QUICPathResponseFrame::size() const return this->_data_offset() + 8; } +bool +QUICPathResponseFrame::is_probing_frame() const +{ + return true; +} + size_t QUICPathResponseFrame::store(uint8_t *buf, size_t *len, size_t limit) const { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index ed95b2cf8ef..ecc71152f3f 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -53,7 +53,8 @@ class QUICFrame virtual QUICFrameUPtr clone() const = 0; virtual QUICFrameType type() const; - virtual size_t size() const = 0; + virtual size_t size() const = 0; + virtual bool is_probing_frame() const; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const = 0; virtual void reset(const uint8_t *buf, size_t len); virtual QUICFrame *split(size_t size); @@ -331,6 +332,7 @@ class QUICPaddingFrame : public QUICFrame QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; + virtual bool is_probing_frame() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; }; @@ -618,6 +620,7 @@ class QUICPathChallengeFrame : public QUICFrame QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; + virtual bool is_probing_frame() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; const uint8_t *data() const; @@ -642,6 +645,7 @@ class QUICPathResponseFrame : public QUICFrame QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; + virtual bool is_probing_frame() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; const uint8_t *data() const; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index f8a66797842..3646c8ff48b 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -712,12 +712,13 @@ QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size this->_payload_size = payload_len; } -QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable) +QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing) { this->_header = std::move(header); this->_payload = std::move(payload); this->_payload_size = payload_len; this->_is_retransmittable = retransmittable; + this->_is_probing_packet = probing; } QUICPacket::~QUICPacket() @@ -783,6 +784,12 @@ QUICPacket::is_retransmittable() const return this->_is_retransmittable; } +bool +QUICPacket::is_probing_packet() const +{ + return this->_is_probing_packet; +} + uint16_t QUICPacket::size() const { @@ -1131,47 +1138,47 @@ QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUIC 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 retransmittable, bool probing) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); QUICPacketNumber pn = this->_packet_number_generator[index].next(); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, destination_cid, source_cid, pn, base_packet_number, this->_version, std::move(payload), len); - return this->_create_encrypted_packet(std::move(header), retransmittable); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing); } QUICPacketUPtr QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, ats_unique_buf payload, - size_t len, bool retransmittable) + size_t len, bool retransmittable, bool probing) { QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, QUICKeyPhase::INITIAL, destination_cid, source_cid, 0, 0, this->_version, std::move(payload), len); - return this->_create_encrypted_packet(std::move(header), retransmittable); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing); } 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 retransmittable, bool probing) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::HANDSHAKE); QUICPacketNumber pn = this->_packet_number_generator[index].next(); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, QUICKeyPhase::HANDSHAKE, destination_cid, source_cid, pn, base_packet_number, this->_version, std::move(payload), len); - return this->_create_encrypted_packet(std::move(header), retransmittable); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing); } QUICPacketUPtr QUICPacketFactory::create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable) + ats_unique_buf payload, size_t len, bool retransmittable, bool probing) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ONE_RTT); QUICPacketNumber pn = this->_packet_number_generator[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); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing); } QUICPacketUPtr @@ -1205,13 +1212,13 @@ QUICPacketFactory::_create_unprotected_packet(QUICPacketHeaderUPtr header) memcpy(cleartext.get(), header->payload(), cleartext_len); QUICPacket *packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(std::move(header), std::move(cleartext), cleartext_len, false); + new (packet) QUICPacket(std::move(header), std::move(cleartext), cleartext_len, false, false); return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); } QUICPacketUPtr -QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable) +QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing) { // TODO: use pmtu of UnixNetVConnection size_t max_cipher_txt_len = 2048; @@ -1227,7 +1234,7 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool re if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable); + new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable, probing); } else { QUICDebug(dcid, scid, "Failed to encrypt a packet"); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 673cd91fdb9..699ad0df1f9 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -299,7 +299,7 @@ class QUICPacket * 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. */ - QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable); + QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing); ~QUICPacket(); @@ -312,6 +312,7 @@ class QUICPacket const QUICPacketHeader &header() const; const uint8_t *payload() const; bool is_retransmittable() const; + bool is_probing_packet() const; /* * Size of whole QUIC packet (header + payload + integrity check) @@ -347,6 +348,7 @@ class QUICPacket ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); size_t _payload_size = 0; bool _is_retransmittable = false; + bool _is_probing_packet = false; }; class QUICPacketNumberGenerator @@ -392,14 +394,14 @@ class QUICPacketFactory QUICPacketCreationResult &result); QUICPacketUPtr create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, - bool retransmittable); + bool retransmittable, bool probing); QUICPacketUPtr create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, ats_unique_buf payload, - size_t len, bool retransmittable); + size_t len, bool retransmittable, bool probing); QUICPacketUPtr create_handshake_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, - bool retransmittable); + bool retransmittable, bool probing); QUICPacketUPtr create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable); + ats_unique_buf payload, size_t len, bool retransmittable, bool probing); void set_version(QUICVersion negotiated_version); // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICCryptoInfoProvider or somethign instead. @@ -415,5 +417,5 @@ class QUICPacketFactory QUICPacketNumberGenerator _packet_number_generator[3]; static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeaderUPtr header); - QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable); + QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing); }; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index c7c9b7789f8..becf9173698 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1273,7 +1273,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); QUICPacketUPtr packet = factory.create_protected_packet({reinterpret_cast("\x01\x02\x03\x04"), 4}, 0, - {nullptr, [](void *p) { ats_free(p); }}, 0, true); + {nullptr, [](void *p) { ats_free(p); }}, 0, true, false); SECTION("STREAM frame split") { size_t len; diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 00f85823655..8076a32354f 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -62,7 +62,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x00000001, 0, 0x00112233, std::move(payload), sizeof(raw)); QUICPacketUPtr packet = - QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true), [](QUICPacket *p) { delete p; }); + QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true, false), [](QUICPacket *p) { delete p; }); detector.on_packet_sent(std::move(packet)); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); CHECK(tx.retransmitted.size() > 0); @@ -85,31 +85,31 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") // Send packet (1) to (7) payload = ats_unique_malloc(16); QUICPacketUPtr packet1 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); payload = ats_unique_malloc(16); QUICPacketUPtr packet2 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); payload = ats_unique_malloc(16); QUICPacketUPtr packet3 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); payload = ats_unique_malloc(16); QUICPacketUPtr packet4 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); payload = ats_unique_malloc(16); QUICPacketUPtr packet5 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); payload = ats_unique_malloc(16); QUICPacketUPtr packet6 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); payload = ats_unique_malloc(16); QUICPacketUPtr packet7 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); payload = ats_unique_malloc(16); QUICPacketUPtr packet8 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); payload = ats_unique_malloc(16); QUICPacketUPtr packet9 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true); + pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); QUICPacketNumber pn1 = packet1->packet_number(); QUICPacketNumber pn2 = packet2->packet_number(); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 83eb4b04b76..1b9dbed9f27 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -75,7 +75,7 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") QUICPacketUPtr packet = factory.create_retry_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), - std::move(payload), sizeof(raw), false); + std::move(payload), sizeof(raw), false, false); CHECK(packet->type() == QUICPacketType::RETRY); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); @@ -96,7 +96,7 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") QUICPacketUPtr packet = factory.create_handshake_packet( QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), - QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), 0, std::move(payload), sizeof(raw), true); + QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), 0, std::move(payload), sizeof(raw), true, false); CHECK(packet->type() == QUICPacketType::HANDSHAKE); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index a4e6842e90b..f6ccf0da426 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -40,7 +40,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -58,7 +58,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -76,7 +76,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); @@ -118,7 +118,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false); // Server send VN packet based on Initial packet QUICPacketUPtr vn_packet = From 742632709717d042d210cf3f03335f79812b188e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 19 Oct 2018 14:28:43 +0900 Subject: [PATCH 0870/1313] Cleanup path validation event handlers --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 29 +++++++++++++---------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 04394ac9bd1..812e836bbcd 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -343,6 +343,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub bool _application_started = false; void _start_application(); + void _handle_path_validation_timeout(Event *data); void _handle_idle_timeout(); QUICConnectionErrorUPtr _handle_frame(const QUICNewConnectionIdFrame &frame); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 1a35baf8110..312c8460db5 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -595,10 +595,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) break; } case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: - this->_close_path_validation_timeout(data); - if (!this->_path_validator->is_validated()) { - this->_switch_to_close_state(); - } + this->_handle_path_validation_timeout(data); break; case EVENT_IMMEDIATE: // Start Immediate Close because of Idle Timeout @@ -633,10 +630,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) break; } case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: - this->_close_path_validation_timeout(data); - if (!this->_path_validator->is_validated()) { - this->_switch_to_close_state(); - } + this->_handle_path_validation_timeout(data); break; case EVENT_IMMEDIATE: { // Start Immediate Close because of Idle Timeout @@ -670,10 +664,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) this->_state_closing_send_packet(); break; case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: - this->_close_path_validation_timeout(data); - if (!this->_path_validator->is_validated()) { - this->_switch_to_close_state(); - } + this->_handle_path_validation_timeout(data); break; case QUIC_EVENT_CLOSING_TIMEOUT: this->_close_closing_timeout(data); @@ -703,10 +694,7 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) this->_close_packet_write_ready(data); break; case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: - this->_close_path_validation_timeout(data); - if (!this->_path_validator->is_validated()) { - this->_switch_to_close_state(); - } + this->_handle_path_validation_timeout(data); break; case QUIC_EVENT_CLOSING_TIMEOUT: this->_close_closing_timeout(data); @@ -1995,3 +1983,12 @@ QUICNetVConnection::_state_connection_established_initiate_connection_migration( return error; } + +void +QUICNetVConnection::_handle_path_validation_timeout(Event *data) +{ + this->_close_path_validation_timeout(data); + if (!this->_path_validator->is_validated()) { + this->_switch_to_close_state(); + } +} From 6b6a75bf6c52cfb0925620dd36c8741d1aad1fd4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 19 Oct 2018 16:19:38 +0900 Subject: [PATCH 0871/1313] clang-format --- iocore/net/quic/test/test_QUICLossDetector.cc | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 8076a32354f..2a845843e8e 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -61,8 +61,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") {reinterpret_cast("\xff\xdd\xbb\x99\x77\x55\x33\x11"), 8}, {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x00000001, 0, 0x00112233, std::move(payload), sizeof(raw)); - QUICPacketUPtr packet = - QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true, false), [](QUICPacket *p) { delete p; }); + QUICPacketUPtr packet = QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true, false), + [](QUICPacket *p) { delete p; }); detector.on_packet_sent(std::move(packet)); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); CHECK(tx.retransmitted.size() > 0); @@ -83,33 +83,33 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") CHECK(tx.retransmitted.size() == 0); // Send packet (1) to (7) - payload = ats_unique_malloc(16); - QUICPacketUPtr packet1 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet2 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet3 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet4 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet5 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet6 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet7 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet8 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); - payload = ats_unique_malloc(16); - QUICPacketUPtr packet9 = - pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload_len, true, false); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet2 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload_len, true, false); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet3 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload_len, true, false); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet4 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload_len, true, false); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet5 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload_len, true, false); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet6 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload_len, true, false); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet7 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload_len, true, false); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet8 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload_len, true, false); + payload = ats_unique_malloc(16); + QUICPacketUPtr packet9 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload_len, true, false); QUICPacketNumber pn1 = packet1->packet_number(); QUICPacketNumber pn2 = packet2->packet_number(); From a78b908f5a56fc1832cb686c7300f3bde7183779 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 19 Oct 2018 14:39:57 +0800 Subject: [PATCH 0872/1313] QUIC: Add write_early_data to generate 0rtt km --- iocore/net/quic/QUICTLS.h | 1 + iocore/net/quic/QUICTLS_openssl.cc | 39 ++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index b11991373ad..32498fc03e8 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -95,6 +95,7 @@ class QUICTLS : public QUICHandshakeProtocol bool _decrypt(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 KeyMaterial &km, const QUIC_EVP_CIPHER *aead, size_t tag_len) const; int _read_early_data(); + int _write_early_data(); int _handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in); int _process_post_handshake_messages(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in); void _generate_0rtt_key(); diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 17431b47f57..92131bd08cb 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -230,6 +230,12 @@ QUICTLS::QUICTLS(SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx) { ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); + if (this->_netvc_context == NET_VCONNECTION_OUT) { + SSL_set_connect_state(this->_ssl); + } else { + SSL_set_accept_state(this->_ssl); + } + this->_client_pp = new QUICPacketProtection(); this->_server_pp = new QUICPacketProtection(); @@ -324,13 +330,22 @@ QUICTLS::_handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) if (this->_netvc_context == NET_VCONNECTION_IN) { if (!this->_early_data_processed) { - if (this->_read_early_data()) { + if (this->_read_early_data() != 1) { + out->error_code = static_cast(QUICTransErrorCode::PROTOCOL_VIOLATION); + return 0; + } else { this->_early_data_processed = true; } } 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); } @@ -435,14 +450,24 @@ QUICTLS::_read_early_data() { uint8_t early_data[8]; size_t early_data_len = 0; - int ret = 0; - do { - ERR_clear_error(); - ret = SSL_read_early_data(this->_ssl, early_data, sizeof(early_data), &early_data_len); - } while (ret == SSL_READ_EARLY_DATA_SUCCESS); + // Early data within the TLS connection MUST NOT be used. As it is for other TLS application data, a server MUST treat receiving + // early data on the TLS connection as a connection error of type PROTOCOL_VIOLATION. + SSL_read_early_data(this->_ssl, early_data, sizeof(early_data), &early_data_len); + // error or reading empty data return 1, otherwise return 0. + return early_data_len != 0 ? 0 : 1; +} - return ret == SSL_READ_EARLY_DATA_FINISH ? 1 : 0; +int +QUICTLS::_write_early_data() +{ + size_t early_data_len = 0; + + // Early data within the TLS connection MUST NOT be used. As it is for other TLS application data, a server MUST treat receiving + // early data on the TLS connection as a connection error of type PROTOCOL_VIOLATION. + SSL_write_early_data(this->_ssl, "", 0, &early_data_len); + // always return 1 + return 1; } const EVP_CIPHER * From c26e6937767b2f17de66fd70df019b6d2fbe3efc Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 22 Oct 2018 10:01:36 +0900 Subject: [PATCH 0873/1313] Update debug log output --- iocore/net/QUICNetVConnection.cc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 312c8460db5..27258ce8397 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -49,6 +49,7 @@ static constexpr std::string_view QUIC_DEBUG_TAG = "quic_net"sv; #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__) +#define QUICConVVVDebug(fmt, ...) Debug("vvv_quic_net", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__) #define QUICFCDebug(fmt, ...) Debug("quic_flow_ctrl", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__) @@ -1564,7 +1565,7 @@ QUICNetVConnection::_schedule_packet_write_ready(bool delay) { SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); if (!this->_packet_write_ready) { - QUICConVDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); + QUICConVVVDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); if (delay) { this->_packet_write_ready = this->thread->schedule_in(this, WRITE_READY_INTERVAL, QUIC_EVENT_PACKET_WRITE_READY, nullptr); } else { @@ -1595,7 +1596,7 @@ void QUICNetVConnection::_schedule_closing_timeout(ink_hrtime interval) { if (!this->_closing_timeout) { - QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_CLOSING_TIMEOUT)); + QUICConDebug("Schedule %s event %" PRIu64 "ms", QUICDebugNames::quic_event(QUIC_EVENT_CLOSING_TIMEOUT), interval); this->_closing_timeout = this->thread->schedule_in_local(this, interval, QUIC_EVENT_CLOSING_TIMEOUT); } } @@ -1604,6 +1605,7 @@ void QUICNetVConnection::_unschedule_closing_timeout() { if (this->_closing_timeout) { + QUICConDebug("Unschedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_CLOSING_TIMEOUT)); this->_closing_timeout->cancel(); this->_closing_timeout = nullptr; } @@ -1629,6 +1631,7 @@ void QUICNetVConnection::_unschedule_closed_event() { if (!this->_closed_event) { + QUICConDebug("Unschedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_SHUTDOWN)); this->_closed_event->cancel(); this->_closed_event = nullptr; } @@ -1668,7 +1671,7 @@ void QUICNetVConnection::_schedule_path_validation_timeout(ink_hrtime interval) { if (!this->_path_validation_timeout) { - QUICConDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PATH_VALIDATION_TIMEOUT)); + QUICConDebug("Schedule %s event in %" PRIu64 "ms", QUICDebugNames::quic_event(QUIC_EVENT_PATH_VALIDATION_TIMEOUT), interval); this->_path_validation_timeout = this->thread->schedule_in_local(this, interval, QUIC_EVENT_PATH_VALIDATION_TIMEOUT); } } @@ -1677,6 +1680,7 @@ void QUICNetVConnection::_unschedule_path_validation_timeout() { if (this->_path_validation_timeout) { + QUICConDebug("Unschedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PATH_VALIDATION_TIMEOUT)); this->_path_validation_timeout->cancel(); this->_path_validation_timeout = nullptr; } @@ -1764,7 +1768,7 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) int index = QUICTypeUtil::pn_space_index(this->_hs_protocol->current_encryption_level()); ink_hrtime rto = this->_loss_detector[index]->current_rto_period(); - QUICConDebug("Enter state_connection_closing %" PRIu64 "ms", 3 * rto / HRTIME_MSECOND); + QUICConDebug("Enter state_connection_closing"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); // This states SHOULD persist for three times the @@ -1789,7 +1793,7 @@ QUICNetVConnection::_switch_to_draining_state(QUICConnectionErrorUPtr error) int index = QUICTypeUtil::pn_space_index(this->_hs_protocol->current_encryption_level()); ink_hrtime rto = this->_loss_detector[index]->current_rto_period(); - QUICConDebug("Enter state_connection_draining %" PRIu64 "ms", 3 * rto / HRTIME_MSECOND); + QUICConDebug("Enter state_connection_draining"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_draining); // This states SHOULD persist for three times the From 5ce7ab64e1201649f240d64511cc1debb3abddc7 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 3 Oct 2018 14:41:28 +0900 Subject: [PATCH 0874/1313] Load/Store RETRY Packet --- iocore/net/QUICNetVConnection.cc | 36 ---- iocore/net/quic/QUICPacket.cc | 161 +++++++++++++----- iocore/net/quic/QUICPacket.h | 29 +++- iocore/net/quic/test/test_QUICPacket.cc | 83 ++++++++- .../net/quic/test/test_QUICPacketFactory.cc | 5 +- 5 files changed, 224 insertions(+), 90 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 27258ce8397..a157863488c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1147,36 +1147,6 @@ QUICNetVConnection::_state_common_send_packet() return nullptr; } -// RETRY packet contains ONLY a single STREAM frame -QUICConnectionErrorUPtr -QUICNetVConnection::_state_handshake_send_retry_packet() -{ - // size_t len = 0; - // ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); }); - // QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED; - - // QUICFrameUPtr frame(nullptr, nullptr); - // bool retransmittable = this->_handshake_handler->is_stateless_retry_enabled() ? false : true; - - // SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); - // SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); - - // frame = this->_stream_manager->generate_frame(this->_remote_flow_controller->credit(), - // this->_maximum_stream_frame_data_size()); ink_assert(frame); ink_assert(frame->type() == QUICFrameType::STREAM); - // this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame)); - // if (len == 0) { - // return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); - // } - - // QUICPacketUPtr packet = this->_build_packet(std::move(buf), len, retransmittable, QUICPacketType::RETRY); - // this->_packet_handler->send_packet(*packet, this, this->_pn_protector); - // this->_loss_detector->on_packet_sent(std::move(packet)); - - // QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, 1); - - return nullptr; -} - QUICConnectionErrorUPtr QUICNetVConnection::_state_closing_send_packet() { @@ -1444,12 +1414,6 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi std::move(buf), len, retransmittable, probing); break; } - case QUICPacketType::RETRY: { - // Echo "_largest_received_packet_number" as packet number. Probably this is the packet number from triggering client packet. - packet = this->_packet_factory.create_retry_packet(this->_peer_quic_connection_id, this->_quic_connection_id, std::move(buf), - len, retransmittable, probing); - break; - } case QUICPacketType::HANDSHAKE: { packet = this->_packet_factory.create_handshake_packet(this->_peer_quic_connection_id, this->_quic_connection_id, this->largest_acked_packet_number(QUICEncryptionLevel::HANDSHAKE), diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 3646c8ff48b..a1511cd0a4b 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -102,6 +102,17 @@ QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnect return QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); } +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) +{ + 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); +} + QUICPacketHeaderUPtr QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len) @@ -149,23 +160,31 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf offset += scil; if (this->type() != QUICPacketType::VERSION_NEGOTIATION) { - 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 (this->type() == QUICPacketType::RETRY) { + uint8_t odcil = 0; + this->_odcil(odcil, raw_buf + offset, len - offset); + ++offset; + 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; + } - // Length Field - offset += QUICVariableInt::size(raw_buf + offset); + // Length Field + offset += QUICVariableInt::size(raw_buf + offset); - // PN Field - int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf + offset); - QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset), pn_len, - this->_base_packet_number); - offset += pn_len; + // PN Field + int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf + offset); + QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset), pn_len, + this->_base_packet_number); + offset += pn_len; + } } this->_payload_offset = offset; @@ -198,6 +217,24 @@ QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key } } +QUICPacketLongHeader::QUICPacketLongHeader(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) +{ + this->_type = type; + this->_destination_cid = destination_cid; + this->_source_cid = source_cid; + this->_original_dcid = original_dcid; + this->_has_version = true; + this->_version = version; + this->_payload = std::move(retry_token); + this->_payload_length = retry_token_len; + this->_key_phase = key_phase; + + // this->_buf_len will be set + this->buf(); +} + QUICPacketType QUICPacketLongHeader::type() const { @@ -358,6 +395,12 @@ QUICPacketLongHeader::source_cid() const return this->_source_cid; } +QUICConnectionId +QUICPacketLongHeader::original_dcid() const +{ + return this->_original_dcid; +} + QUICPacketNumber QUICPacketLongHeader::packet_number() const { @@ -479,40 +522,70 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const } if (this->_type != QUICPacketType::VERSION_NEGOTIATION) { - if (this->_type == QUICPacketType::INITIAL) { - // Token Length Field - QUICIntUtil::write_QUICVariableInt(this->_token_len, buf + *len, &n); - *len += n; + if (this->_type == QUICPacketType::RETRY) { + std::random_device rnd; - // 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); + buf[*len] += rnd() & 0xF0; + buf[*len] = this->_original_dcid == QUICConnectionId::ZERO() ? 0 : (this->_original_dcid.length() - 3); + *len += 1; - if (pn > 0x3FFF) { - pn_len = 4; - } else if (pn > 0x7F) { - pn_len = 2; + if (this->_original_dcid != QUICConnectionId::ZERO()) { + QUICTypeUtil::write_QUICConnectionId(this->_original_dcid, buf + *len, &n); + *len += n; + } } else { - pn_len = 1; - } + 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(); + } - // Length Field - QUICIntUtil::write_QUICVariableInt(pn_len + this->_payload_length + aead_tag_len, buf + *len, &n); - *len += n; + QUICPacketNumber pn = 0; + size_t pn_len = 4; + QUICPacket::encode_packet_number(pn, this->_packet_number, pn_len); - // PN Field - QUICTypeUtil::write_QUICPacketNumber(pn, pn_len, buf + *len, &n); - *len += n; + if (pn > 0x3FFF) { + pn_len = 4; + } else if (pn > 0x7F) { + pn_len = 2; + } else { + pn_len = 1; + } + + // Length Field + QUICIntUtil::write_QUICVariableInt(pn_len + this->_payload_length + aead_tag_len, buf + *len, &n); + *len += n; + + // PN Field + QUICTypeUtil::write_QUICPacketNumber(pn, pn_len, buf + *len, &n); + *len += n; + } // Payload will be stored } } +bool +QUICPacketLongHeader::_odcil(uint8_t &odcil, const uint8_t *buf, size_t buf_len) +{ + if (buf_len <= 0) { + return false; + } + + // the least significant 4 bits are odcil and the most significant 4 bits are random + odcil = buf[0]; + + if (odcil != 0) { + odcil += 3; + } + + return true; +} + // // QUICPacketShortHeader // @@ -1148,12 +1221,12 @@ QUICPacketFactory::create_initial_packet(QUICConnectionId destination_cid, QUICC } QUICPacketUPtr -QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, ats_unique_buf payload, - size_t len, bool retransmittable, bool probing) +QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, + QUICConnectionId original_dcid, ats_unique_buf payload, size_t len) { - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, QUICKeyPhase::INITIAL, destination_cid, source_cid, - 0, 0, this->_version, std::move(payload), len); - return this->_create_encrypted_packet(std::move(header), retransmittable, probing); + QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, QUICKeyPhase::INITIAL, QUIC_SUPPORTED_VERSIONS[0], + destination_cid, source_cid, original_dcid, std::move(payload), len); + return QUICPacketFactory::_create_unprotected_packet(std::move(header)); } QUICPacketUPtr diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 699ad0df1f9..0c9545703bf 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -128,6 +128,15 @@ class QUICPacketHeader QUICConnectionId source_cid, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); + /* + * 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); + /* * Build a QUICPacketHeader * @@ -139,7 +148,7 @@ class QUICPacketHeader /* * Build a QUICPacketHeader * - * This creates a QUICPacketShortHeader that doesn't contain a ConnectionID.. + * This creates a QUICPacketShortHeader that doesn't contain a ConnectionID (Stateless Reset Packet). */ static QUICPacketHeaderUPtr build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload, @@ -178,9 +187,14 @@ class QUICPacketLongHeader : public QUICPacketHeader QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len, ats_unique_buf token = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }), size_t token_len = 0); + QUICPacketLongHeader(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); + QUICPacketType type() const; QUICConnectionId destination_cid() const; QUICConnectionId source_cid() const; + QUICConnectionId original_dcid() const; QUICPacketNumber packet_number() const; bool has_version() const; bool is_valid() const; @@ -208,12 +222,15 @@ class QUICPacketLongHeader : public QUICPacketHeader static bool packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len); private: + bool _odcil(uint8_t &odcil, const uint8_t *buf, size_t buf_len); + QUICPacketNumber _packet_number; QUICConnectionId _destination_cid = QUICConnectionId::ZERO(); QUICConnectionId _source_cid = QUICConnectionId::ZERO(); - size_t _token_len = 0; //< only INITIAL packet - size_t _token_offset = 0; //< only INITIAL packet - ats_unique_buf _token = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); //< only INITIAL packet + 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, [](void *p) { ats_free(p); }); //< INITIAL packet only size_t _payload_offset = 0; }; @@ -389,14 +406,14 @@ class QUICPacketFactory 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, ats_unique_buf payload, size_t len); QUICPacketUPtr create(IpEndpoint from, 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 retransmittable, bool probing); - QUICPacketUPtr create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, ats_unique_buf payload, - size_t len, bool retransmittable, bool probing); QUICPacketUPtr create_handshake_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable, bool probing); diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 67cc2959a67..39813766ec8 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -51,7 +51,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") CHECK(header->has_key_phase() == false); } - SECTION("Long Header (load)") + SECTION("Long Header (load) INITIAL Packet") { const uint8_t input[] = { 0xFF, // Long header, Type: INITIAL @@ -78,7 +78,41 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") CHECK(header->has_key_phase() == false); } - SECTION("Long Header (store)") + SECTION("Long Header (load) RETRY Packet") + { + const uint8_t input[] = { + 0xFE, // Long header, Type: RETRY + 0x11, 0x22, 0x33, 0x44, // Version + 0x55, // DCIL/SCIL + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID + 0x05, // ODCIL + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, // Original Destination Connection ID + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Retry Token + 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + }; + + const uint8_t retry_token[] = {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0}; + + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); + CHECK(header->size() == sizeof(input) - 16); // Packet Length - Payload Length (Retry Token) + CHECK(header->packet_size() == sizeof(input)); + CHECK(header->type() == QUICPacketType::RETRY); + CHECK( + (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); + CHECK((header->source_cid() == QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8))); + + QUICPacketLongHeader *retry_header = static_cast(header.get()); + CHECK((retry_header->original_dcid() == + QUICConnectionId(reinterpret_cast("\x08\x07\x06\x05\x04\x03\x02\x01"), 8))); + + CHECK(memcmp(header->payload(), retry_token, 16) == 0); + CHECK(header->has_version() == true); + CHECK(header->version() == 0x11223344); + CHECK(header->has_key_phase() == false); + } + + SECTION("Long Header (store) INITIAL Packet") { uint8_t buf[64] = {0}; size_t len = 0; @@ -116,6 +150,51 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") CHECK(len == header->size()); CHECK(memcmp(buf, expected, len) == 0); } + + SECTION("Long Header (store) RETRY Packet") + { + uint8_t buf[64] = {0}; + size_t len = 0; + + const uint8_t expected[] = { + 0xFE, // Long header, Type: RETRY + 0x11, 0x22, 0x33, 0x44, // Version + 0x55, // DCIL/SCIL + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID + 0x05, // ODCIL + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, // Original Destination Connection ID + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Retry Token + 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + }; + ats_unique_buf payload = ats_unique_malloc(16); + memcpy(payload.get(), expected + 31, 16); + + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::RETRY, QUICKeyPhase::INITIAL, 0x11223344, + {reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, + {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, + {reinterpret_cast("\x08\x07\x06\x05\x04\x03\x02\x01"), 8}, std::move(payload), 16); + + CHECK(header->size() == sizeof(expected) - 16); + CHECK(header->has_key_phase() == false); + CHECK(header->packet_size() == sizeof(expected)); + CHECK(header->type() == QUICPacketType::RETRY); + CHECK( + (header->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8))); + CHECK((header->source_cid() == QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8))); + CHECK(header->has_version() == true); + CHECK(header->version() == 0x11223344); + + QUICPacketLongHeader *retry_header = static_cast(header.get()); + CHECK((retry_header->original_dcid() == + QUICConnectionId(reinterpret_cast("\x08\x07\x06\x05\x04\x03\x02\x01"), 8))); + + header->store(buf, &len); + CHECK(len == header->size()); + CHECK(memcmp(buf, expected, 22) == 0); + CHECK(memcmp(buf + 22, expected + 22, 8) == 0); + } } TEST_CASE("QUICPacketHeader - Short", "[quic]") diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 1b9dbed9f27..a987d617189 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -75,12 +75,13 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") QUICPacketUPtr packet = factory.create_retry_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), - std::move(payload), sizeof(raw), false, false); + QUICConnectionId(reinterpret_cast("\x04\x03\x02\x01"), 4), + std::move(payload), sizeof(raw)); CHECK(packet->type() == QUICPacketType::RETRY); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); CHECK(packet->packet_number() == 0); - CHECK(packet->version() == 0x11223344); + CHECK(packet->version() == QUIC_SUPPORTED_VERSIONS[0]); } TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") From 30c2af2ff40b35bfab49f1fa03140d787f0b13b5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 22 Oct 2018 14:54:15 +0900 Subject: [PATCH 0875/1313] Add check for probing packet --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 84 +++++++++++++++----------- iocore/net/quic/QUICFrameDispatcher.cc | 5 +- iocore/net/quic/QUICFrameDispatcher.h | 5 +- 4 files changed, 56 insertions(+), 40 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 812e836bbcd..7c7eaa205f7 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -306,7 +306,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketType type = QUICPacketType::UNINITIALIZED); QUICPacketUPtr _build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing); - QUICConnectionErrorUPtr _recv_and_ack(QUICPacketUPtr packet); + QUICConnectionErrorUPtr _recv_and_ack(QUICPacket &packet, bool *has_non_probing_frame = nullptr); QUICConnectionErrorUPtr _state_handshake_process_packet(QUICPacketUPtr packet); QUICConnectionErrorUPtr _state_handshake_process_version_negotiation_packet(QUICPacketUPtr packet); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a157863488c..3d560ee9354 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -906,7 +906,7 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe // 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(std::move(packet)); + error = this->_recv_and_ack(*packet); if (error == nullptr && !this->_handshake_handler->has_remote_tp()) { error = std::make_unique(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR); @@ -914,7 +914,7 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe } } else { // on client side, _handshake_handler is already started. Just process packet like _state_handshake_process_handshake_packet() - error = this->_recv_and_ack(std::move(packet)); + error = this->_recv_and_ack(*packet); } return error; @@ -932,7 +932,7 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); this->_packet_retransmitter.reset(); - QUICConnectionErrorUPtr error = this->_recv_and_ack(std::move(packet)); + QUICConnectionErrorUPtr error = this->_recv_and_ack(*packet); // Packet number of RETRY packet is echo of INITIAL packet this->_packet_recv_queue.reset(); @@ -953,7 +953,7 @@ QUICNetVConnection::_state_handshake_process_handshake_packet(QUICPacketUPtr pac if (this->netvc_context == NET_VCONNECTION_IN && !this->_src_addr_verified) { this->_src_addr_verified = true; } - return this->_recv_and_ack(std::move(packet)); + return this->_recv_and_ack(*packet); } QUICConnectionErrorUPtr @@ -962,13 +962,42 @@ QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacke this->_stream_manager->init_flow_control_params(this->_handshake_handler->local_transport_parameters(), this->_handshake_handler->remote_transport_parameters()); this->_start_application(); - return this->_recv_and_ack(std::move(packet)); + return this->_recv_and_ack(*packet); } QUICConnectionErrorUPtr QUICNetVConnection::_state_connection_established_process_protected_packet(QUICPacketUPtr packet) { - return this->_recv_and_ack(std::move(packet)); + QUICConnectionErrorUPtr error = nullptr; + bool has_non_probing_frame = false; + + error = this->_recv_and_ack(*packet, &has_non_probing_frame); + if (error != nullptr) { + 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) { + if (this->_alt_con_manager != nullptr && packet->destination_cid() != this->_quic_connection_id) { + if (!has_non_probing_frame) { + QUICConDebug("FIXME: Connection migration has been initiated without non-probing frames"); + } + error = this->_state_connection_established_migrate_connection(*packet); + if (error != nullptr) { + return error; + } + } + + // For Connection Migration excercise + QUICConfig::scoped_config params; + if (this->netvc_context == NET_VCONNECTION_OUT && params->cm_exercise_enabled()) { + this->_state_connection_established_initiate_connection_migration(); + } + + return error; } QUICConnectionErrorUPtr @@ -994,23 +1023,13 @@ QUICNetVConnection::_state_connection_established_receive_packet() // Process the packet switch (p->type()) { case QUICPacketType::PROTECTED: - // Migrate connection if required - error = this->_state_connection_established_migrate_connection(*p); - if (error != nullptr) { - break; - } - - if (this->netvc_context == NET_VCONNECTION_OUT) { - this->_state_connection_established_initiate_connection_migration(); - } - error = this->_state_connection_established_process_protected_packet(std::move(p)); 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(std::move(p)); + error = this->_recv_and_ack(*p); break; default: QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(p->type()), static_cast(p->type())); @@ -1035,7 +1054,7 @@ QUICNetVConnection::_state_closing_receive_packet() // Ignore VN packets on closing state break; default: - this->_recv_and_ack(std::move(packet)); + this->_recv_and_ack(*packet); break; } } @@ -1061,7 +1080,7 @@ QUICNetVConnection::_state_draining_receive_packet() QUICPacketCreationResult result; QUICPacketUPtr packet = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::SUCCESS) { - this->_recv_and_ack(std::move(packet)); + this->_recv_and_ack(*packet); // Do NOT schedule WRITE_READY event from this point. // An endpoint in the draining state MUST NOT send any packets. } @@ -1354,24 +1373,27 @@ QUICNetVConnection::_packetize_closing_frame() } QUICConnectionErrorUPtr -QUICNetVConnection::_recv_and_ack(QUICPacketUPtr packet) +QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_frame) { - const uint8_t *payload = packet->payload(); - uint16_t size = packet->payload_length(); - QUICPacketNumber packet_num = packet->packet_number(); - QUICEncryptionLevel level = QUICTypeUtil::encryption_level(packet->type()); + const uint8_t *payload = packet.payload(); + uint16_t size = packet.payload_length(); + QUICPacketNumber packet_num = packet.packet_number(); + QUICEncryptionLevel level = QUICTypeUtil::encryption_level(packet.type()); bool should_send_ack; bool is_flow_controlled; QUICConnectionErrorUPtr error = nullptr; + if (has_non_probing_frame) { + *has_non_probing_frame = false; + } - error = this->_frame_dispatcher->receive_frames(level, payload, size, should_send_ack, is_flow_controlled); + error = this->_frame_dispatcher->receive_frames(level, payload, size, should_send_ack, is_flow_controlled, has_non_probing_frame); if (error != nullptr) { return error; } - if (packet->type() == QUICPacketType::RETRY) { + if (packet.type() == QUICPacketType::RETRY) { should_send_ack = false; } @@ -1882,10 +1904,6 @@ QUICNetVConnection::_state_connection_established_migrate_connection(const QUICP QUICConnectionErrorUPtr error = nullptr; QUICConnectionId dcid = p.destination_cid(); - if (dcid == this->_quic_connection_id) { - return error; - } - if (this->netvc_context == NET_VCONNECTION_IN) { if (this->_remote_alt_cids.empty()) { // TODO: Should endpoint send connection error when remote endpoint doesn't send NEW_CONNECTION_ID frames before initiating @@ -1933,11 +1951,9 @@ QUICNetVConnection::_state_connection_established_initiate_connection_migration( QUICConnectionErrorUPtr error = nullptr; std::shared_ptr remote_tp = this->_handshake_handler->remote_transport_parameters(); - QUICConfig::scoped_config params; - if (!params->cm_exercise_enabled() || this->_connection_migration_initiated || - remote_tp->contains(QUICTransportParameterId::DISABLE_MIGRATION) || this->_remote_alt_cids.empty() || - this->_alt_con_manager->will_generate_frame(QUICEncryptionLevel::ONE_RTT)) { + if (this->_connection_migration_initiated || remote_tp->contains(QUICTransportParameterId::DISABLE_MIGRATION) || + this->_remote_alt_cids.empty() || this->_alt_con_manager->will_generate_frame(QUICEncryptionLevel::ONE_RTT)) { return error; } diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 992be66cfba..54b5a4ae637 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -43,7 +43,7 @@ QUICFrameDispatcher::add_handler(QUICFrameHandler *handler) QUICConnectionErrorUPtr QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, bool &should_send_ack, - bool &is_flow_controlled) + bool &is_flow_controlled, bool *has_non_probing_frame) { std::shared_ptr frame(nullptr); uint16_t cursor = 0; @@ -57,6 +57,9 @@ QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *pa QUICDebug("Failed to create a frame (%u bytes skipped)", size - cursor); break; } + if (has_non_probing_frame) { + *has_non_probing_frame |= !frame->is_probing_frame(); + } cursor += frame->size(); QUICFrameType type = frame->type(); diff --git a/iocore/net/quic/QUICFrameDispatcher.h b/iocore/net/quic/QUICFrameDispatcher.h index 25162d0fd5b..79d71316c41 100644 --- a/iocore/net/quic/QUICFrameDispatcher.h +++ b/iocore/net/quic/QUICFrameDispatcher.h @@ -34,11 +34,8 @@ class QUICFrameDispatcher public: QUICFrameDispatcher(QUICConnectionInfoProvider *info); - /* - * Returns true if ACK frame should be sent - */ QUICConnectionErrorUPtr receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, - bool &should_send_ackbool, bool &is_flow_controlled); + bool &should_send_ackbool, bool &is_flow_controlled, bool *has_non_probing_frame); void add_handler(QUICFrameHandler *handler); From 0b56b02629ccf46b497920c0c7d51157cea3ee62 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 22 Oct 2018 15:59:32 +0900 Subject: [PATCH 0876/1313] Fix log output --- iocore/net/QUICNetVConnection.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3d560ee9354..24524bbbb41 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1582,7 +1582,7 @@ void QUICNetVConnection::_schedule_closing_timeout(ink_hrtime interval) { if (!this->_closing_timeout) { - QUICConDebug("Schedule %s event %" PRIu64 "ms", QUICDebugNames::quic_event(QUIC_EVENT_CLOSING_TIMEOUT), interval); + QUICConDebug("Schedule %s event in %" PRIu64 "ms", QUICDebugNames::quic_event(QUIC_EVENT_CLOSING_TIMEOUT), interval / HRTIME_MSECOND); this->_closing_timeout = this->thread->schedule_in_local(this, interval, QUIC_EVENT_CLOSING_TIMEOUT); } } @@ -1657,7 +1657,7 @@ void QUICNetVConnection::_schedule_path_validation_timeout(ink_hrtime interval) { if (!this->_path_validation_timeout) { - QUICConDebug("Schedule %s event in %" PRIu64 "ms", QUICDebugNames::quic_event(QUIC_EVENT_PATH_VALIDATION_TIMEOUT), interval); + QUICConDebug("Schedule %s event in %" PRIu64 "ms", QUICDebugNames::quic_event(QUIC_EVENT_PATH_VALIDATION_TIMEOUT), interval / HRTIME_MSECOND); this->_path_validation_timeout = this->thread->schedule_in_local(this, interval, QUIC_EVENT_PATH_VALIDATION_TIMEOUT); } } From 3517a33e590dafe5c07b802b765f79e82c89f811 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 23 Oct 2018 13:46:17 +0900 Subject: [PATCH 0877/1313] Fix compile errors in tests --- iocore/net/quic/test/test_QUICFrameDispatcher.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index a69faad5d8a..781eb40c7e8 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -58,14 +58,14 @@ TEST_CASE("QUICFrameHandler", "[quic]") streamFrame.store(buf, &len, 4096); bool should_send_ack; bool is_flow_controlled; - quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack, is_flow_controlled); + quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack, is_flow_controlled, nullptr); CHECK(connection.getTotalFrameCount() == 0); CHECK(streamManager.getTotalFrameCount() == 1); // CONNECTION_CLOSE frame QUICConnectionCloseFrame connectionCloseFrame({}); connectionCloseFrame.store(buf, &len, 4096); - quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack, is_flow_controlled); + quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack, is_flow_controlled, nullptr); CHECK(connection.getTotalFrameCount() == 1); CHECK(streamManager.getTotalFrameCount() == 1); } From 65c88702f08ff59d96f7ff47115d9f24c355581f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 23 Oct 2018 13:47:08 +0900 Subject: [PATCH 0878/1313] clang-format --- iocore/net/QUICNetVConnection.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 24524bbbb41..37e1d038cc5 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1582,7 +1582,8 @@ void QUICNetVConnection::_schedule_closing_timeout(ink_hrtime interval) { if (!this->_closing_timeout) { - QUICConDebug("Schedule %s event in %" PRIu64 "ms", QUICDebugNames::quic_event(QUIC_EVENT_CLOSING_TIMEOUT), interval / HRTIME_MSECOND); + QUICConDebug("Schedule %s event in %" PRIu64 "ms", QUICDebugNames::quic_event(QUIC_EVENT_CLOSING_TIMEOUT), + interval / HRTIME_MSECOND); this->_closing_timeout = this->thread->schedule_in_local(this, interval, QUIC_EVENT_CLOSING_TIMEOUT); } } @@ -1657,7 +1658,8 @@ void QUICNetVConnection::_schedule_path_validation_timeout(ink_hrtime interval) { if (!this->_path_validation_timeout) { - QUICConDebug("Schedule %s event in %" PRIu64 "ms", QUICDebugNames::quic_event(QUIC_EVENT_PATH_VALIDATION_TIMEOUT), interval / HRTIME_MSECOND); + QUICConDebug("Schedule %s event in %" PRIu64 "ms", QUICDebugNames::quic_event(QUIC_EVENT_PATH_VALIDATION_TIMEOUT), + interval / HRTIME_MSECOND); this->_path_validation_timeout = this->thread->schedule_in_local(this, interval, QUIC_EVENT_PATH_VALIDATION_TIMEOUT); } } From e1b945981bb4a18aa2ea3c724b13b41cbe357eb8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 23 Oct 2018 13:58:58 +0900 Subject: [PATCH 0879/1313] Copy ACK block section in QUICAckFrame::clone() --- iocore/net/quic/QUICFrame.cc | 6 +++++- iocore/net/quic/test/test_QUICFrame.cc | 27 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index bfe17f23742..813d7f515b2 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -593,7 +593,11 @@ QUICAckFrame::clone() const { std::unique_ptr newframe = QUICFrameFactory::create_ack_frame( this->largest_acknowledged(), this->ack_delay(), this->ack_block_section()->first_ack_block()); - // TODO Copy ack block section + + for (auto &ack_block : *this->ack_block_section()) { + newframe->ack_block_section()->add_ack_block({ack_block.gap(), ack_block.length()}); + } + return newframe; } diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index becf9173698..809e41f2211 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -530,6 +530,33 @@ TEST_CASE("Store Ack Frame", "[quic]") CHECK(len == 21); CHECK(memcmp(buf, expected, len) == 0); } + + SECTION("Clone ACK frame", "[quic]") + { + uint8_t buf[32] = {0}; + size_t len; + + uint8_t expected[] = { + 0x0d, // Type + 0x12, // Largest Acknowledged + 0x74, 0x56, // Ack Delay + 0x02, // Ack Block Count + 0x01, // Ack Block Section (First ACK Block Length) + 0x02, // Ack Block Section (Gap 1) + 0x43, 0x04, // Ack Block Section (ACK Block 1 Length) + 0x85, 0x06, 0x07, 0x08, // Ack Block Section (Gap 2) + 0xc9, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, // Ack Block Section (ACK Block 2 Length) + }; + QUICAckFrame ack_frame(0x12, 0x3456, 0x01); + QUICAckFrame::AckBlockSection *section = ack_frame.ack_block_section(); + section->add_ack_block({0x02, 0x0304}); + section->add_ack_block({0x05060708, 0x090a0b0c0d0e0f10}); + + auto cloned = ack_frame.clone(); + cloned->store(buf, &len, sizeof(buf)); + CHECK(len == 21); + CHECK(memcmp(buf, expected, len) == 0); + } } TEST_CASE("Load RST_STREAM Frame", "[quic]") From ed96c690290c2690fdc355f26510d8a9d4d4b617 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 23 Oct 2018 15:45:48 +0900 Subject: [PATCH 0880/1313] Build INITIAL packet with token --- iocore/net/quic/QUICPacket.cc | 22 +++++++++++++++++----- iocore/net/quic/QUICPacket.h | 14 +++++++++++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index a1511cd0a4b..a6057b89ff2 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -102,6 +102,17 @@ QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnect return QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); } +QUICPacketHeaderUPtr +QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid, + QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, + ats_unique_buf payload, size_t len, ats_unique_buf token, size_t token_len) +{ + QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); + new (long_header) QUICPacketLongHeader(type, key_phase, destination_cid, source_cid, packet_number, base_packet_number, version, + std::move(payload), len, std::move(token), token_len); + return QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); +} + QUICPacketHeaderUPtr QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICVersion version, QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICConnectionId original_dcid, ats_unique_buf retry_token, @@ -1211,12 +1222,13 @@ QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUIC 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 retransmittable, bool probing, ats_unique_buf token, size_t token_len) { - int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); - QUICPacketNumber pn = this->_packet_number_generator[index].next(); - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, destination_cid, source_cid, - pn, base_packet_number, this->_version, std::move(payload), len); + int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); + QUICPacketNumber pn = this->_packet_number_generator[index].next(); + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, destination_cid, source_cid, pn, base_packet_number, + this->_version, std::move(payload), len, std::move(token), token_len); return this->_create_encrypted_packet(std::move(header), retransmittable, probing); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 0c9545703bf..5cef215cf7e 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -128,6 +128,16 @@ class QUICPacketHeader QUICConnectionId source_cid, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); + /* + * 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, ats_unique_buf payload, size_t len, + ats_unique_buf token, size_t token_len); + /* * Build a QUICPacketHeader * @@ -413,7 +423,9 @@ class QUICPacketFactory QUICPacketCreationResult &result); QUICPacketUPtr 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 retransmittable, bool probing, + ats_unique_buf token = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }), + 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, bool retransmittable, bool probing); From 9b76a39cc4da6adf39ca49563796cf80092ba1f9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 23 Oct 2018 15:46:28 +0900 Subject: [PATCH 0881/1313] Cleanup QUICStatelessRetry --- iocore/net/quic/QUICConfig.cc | 5 ----- iocore/net/quic/QUICStatelessRetry.cc | 10 ++++------ iocore/net/quic/QUICStatelessRetry.h | 10 +++++++--- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 48b43a58ed5..7b44a72a191 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -83,11 +83,6 @@ quic_init_server_ssl_ctx(const QUICConfigParams *params) Error("check private key failed"); } - // callbacks for cookie ext - // Requires OpenSSL-1.1.1-pre3+ : https://github.com/openssl/openssl/pull/5463 - SSL_CTX_set_stateless_cookie_generate_cb(ssl_ctx, QUICStatelessRetry::generate_cookie); - SSL_CTX_set_stateless_cookie_verify_cb(ssl_ctx, QUICStatelessRetry::verify_cookie); - SSL_CTX_set_alpn_select_cb(ssl_ctx, QUIC::ssl_select_next_protocol, nullptr); if (params->server_supported_groups() != nullptr) { diff --git a/iocore/net/quic/QUICStatelessRetry.cc b/iocore/net/quic/QUICStatelessRetry.cc index b9413e343be..86cf8037e43 100644 --- a/iocore/net/quic/QUICStatelessRetry.cc +++ b/iocore/net/quic/QUICStatelessRetry.cc @@ -41,13 +41,11 @@ QUICStatelessRetry::init() } int -QUICStatelessRetry::generate_cookie(SSL *ssl, unsigned char *cookie, size_t *cookie_len) +QUICStatelessRetry::generate_cookie(unsigned char *cookie, size_t *cookie_len, IpEndpoint src) { - QUICConnection *qc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); - uint8_t key[INET6_ADDRPORTSTRLEN] = {0}; size_t key_len = INET6_ADDRPORTSTRLEN; - ats_ip_nptop(qc->five_tuple().source(), reinterpret_cast(key), key_len); + ats_ip_nptop(src, reinterpret_cast(key), key_len); unsigned int dst_len = 0; HMAC(EVP_sha1(), stateless_cookie_secret, STATELESS_COOKIE_SECRET_LENGTH, key, key_len, cookie, &dst_len); @@ -57,12 +55,12 @@ QUICStatelessRetry::generate_cookie(SSL *ssl, unsigned char *cookie, size_t *coo } int -QUICStatelessRetry::verify_cookie(SSL *ssl, const unsigned char *cookie, size_t cookie_len) +QUICStatelessRetry::verify_cookie(const unsigned char *cookie, size_t cookie_len, IpEndpoint src) { uint8_t token[EVP_MAX_MD_SIZE]; size_t token_len; - if (QUICStatelessRetry::generate_cookie(ssl, token, &token_len) && cookie_len == token_len && + if (QUICStatelessRetry::generate_cookie(token, &token_len, src) && cookie_len == token_len && memcmp(token, cookie, cookie_len) == 0) { return 1; } else { diff --git a/iocore/net/quic/QUICStatelessRetry.h b/iocore/net/quic/QUICStatelessRetry.h index a63081ba951..dc213f7794b 100644 --- a/iocore/net/quic/QUICStatelessRetry.h +++ b/iocore/net/quic/QUICStatelessRetry.h @@ -23,12 +23,16 @@ #pragma once -#include +#include + +#include "tscore/ink_inet.h" class QUICStatelessRetry { public: + static constexpr size_t MAX_TOKEN_LEN = EVP_MAX_MD_SIZE; + static void init(); - static int generate_cookie(SSL *ssl, unsigned char *cookie, size_t *cookie_len); - static int verify_cookie(SSL *ssl, const unsigned char *cookie, size_t cookie_len); + static int generate_cookie(unsigned char *cookie, size_t *cookie_len, IpEndpoint src); + static int verify_cookie(const unsigned char *cookie, size_t cookie_len, IpEndpoint src); }; From 7e2d0ab498a109d0b3e06e4150d14e4f1284eafe Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 23 Oct 2018 15:47:19 +0900 Subject: [PATCH 0882/1313] Add reset API to QUICPacketNumberGenerator and QUICPacketFactory --- iocore/net/quic/QUICPacket.cc | 15 +++++++++++++++ iocore/net/quic/QUICPacket.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index a6057b89ff2..fc489efb965 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -1344,6 +1344,15 @@ QUICPacketFactory::is_ready_to_create_protected_packet() { return this->_hs_protocol->is_handshake_finished(); } + +void +QUICPacketFactory::reset() +{ + for (auto s : QUIC_PN_SPACES) { + this->_packet_number_generator[static_cast(s)].reset(); + } +} + // // QUICPacketNumberGenerator // @@ -1355,3 +1364,9 @@ QUICPacketNumberGenerator::next() // TODO Increment the number at least one but not only always one return this->_current++; } + +void +QUICPacketNumberGenerator::reset() +{ + this->_current = 0; +} diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 5cef215cf7e..b938f35e8cb 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -383,6 +383,7 @@ class QUICPacketNumberGenerator public: QUICPacketNumberGenerator(); QUICPacketNumber next(); + void reset(); private: std::atomic _current = 0; @@ -438,6 +439,7 @@ class QUICPacketFactory void set_hs_protocol(const QUICHandshakeProtocol *hs_protocol); bool is_ready_to_create_protected_packet(); + void reset(); private: QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; From 28832e086be5640d1990eef40c6b7a3373320a84 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 23 Oct 2018 15:48:55 +0900 Subject: [PATCH 0883/1313] Expand buffer size for serialized packet header --- iocore/net/quic/QUICPacket.cc | 4 ++++ iocore/net/quic/QUICPacket.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index fc489efb965..1a19f35a2c0 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -58,6 +58,10 @@ QUICPacketHeader::buf() } 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"); + } + this->_buf_len += this->_payload_length; return this->_serialized; } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index b938f35e8cb..d6d37c2511e 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -166,6 +166,7 @@ class QUICPacketHeader protected: QUICPacketHeader(){}; + static constexpr size_t MAX_PACKET_HEADER_LEN = 128; const IpEndpoint _from = {}; @@ -174,7 +175,7 @@ class QUICPacketHeader size_t _buf_len = 0; // These are used only if the instance was created without a buffer - uint8_t _serialized[64]; + uint8_t _serialized[MAX_PACKET_HEADER_LEN]; ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); QUICPacketType _type = QUICPacketType::UNINITIALIZED; QUICKeyPhase _key_phase = QUICKeyPhase::INITIAL; From 75f95ee6e834a03dd21eb142ac47dcc7f11b54f0 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 23 Oct 2018 15:57:26 +0900 Subject: [PATCH 0884/1313] Add Server Stateless Retry Support (take 2) --- iocore/net/P_QUICPacketHandler.h | 2 ++ iocore/net/QUICPacketHandler.cc | 60 +++++++++++++++++++++++++++++++- iocore/net/quic/QUICPacket.cc | 16 +-------- 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index 8acccb31e69..f96deaafdae 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -79,6 +79,8 @@ class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler 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); QUICConnectionTable *_ctable = nullptr; }; diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 56567c4f1c7..7be90fd4712 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -29,8 +29,10 @@ #include "QUICPacket.h" #include "QUICDebugNames.h" #include "QUICEvents.h" +#include "QUICStatelessRetry.h" -static constexpr char tag[] = "quic_sec"; +static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6; +static constexpr char tag[] = "quic_sec"; #define QUICDebug(fmt, ...) Debug(tag, fmt, ##__VA_ARGS__) #define QUICDebugQC(qc, fmt, ...) Debug(tag, "[%s] " fmt, qc->cids().data(), ##__VA_ARGS__) @@ -258,6 +260,15 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) return; } + QUICConfig::scoped_config params; + if (params->stateless_retry()) { + int ret = this->_stateless_retry(buf, buf_len, udp_packet->getConnection(), udp_packet->from, dcid, scid); + if (ret < 0) { + udp_packet->free(); + return; + } + } + if (dcid == QUICConnectionId::ZERO()) { // TODO: lookup DCID by 5-tuple when ATS omits SCID return; @@ -345,6 +356,53 @@ QUICPacketHandlerIn::send_packet(QUICNetVConnection *vc, Ptr udp_ this->_send_packet(this, vc, udp_payload); } +int +QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPConnection *connection, IpEndpoint from, + QUICConnectionId dcid, QUICConnectionId scid) +{ + QUICPacketType type = QUICPacketType::UNINITIALIZED; + QUICPacketLongHeader::type(type, buf, buf_len); + + if (type != QUICPacketType::INITIAL) { + return 1; + } + + // TODO: refine packet parsers in here, QUICPacketLongHeader, and QUICPacketReceiveQueue + size_t token_length = 0; + uint8_t token_length_field_len = 0; + if (!QUICPacketLongHeader::token_length(token_length, &token_length_field_len, buf, buf_len)) { + return -1; + } + + if (token_length == 0) { + ats_unique_buf retry_token = ats_unique_malloc(QUICStatelessRetry::MAX_TOKEN_LEN); + size_t retry_token_len = 0; + QUICStatelessRetry::generate_cookie(retry_token.get(), &retry_token_len, from); + + QUICConnectionId local_cid; + local_cid.randomize(); + QUICPacketUPtr retry_packet = + QUICPacketFactory::create_retry_packet(scid, local_cid, dcid, std::move(retry_token), retry_token_len); + + this->_send_packet(this, *retry_packet, connection, from, 1200, nullptr, 0); + + return -2; + } else { + uint8_t dcil, scil; + QUICPacketLongHeader::dcil(dcil, buf, buf_len); + QUICPacketLongHeader::scil(scil, buf, buf_len); + + const uint8_t *token = buf + LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil + token_length_field_len; + if (QUICStatelessRetry::verify_cookie(token, token_length, from)) { + return 0; + } else { + return -3; + } + } + + return 0; +} + // // QUICPacketHandlerOut // diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 1a19f35a2c0..f3642a81119 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -1112,6 +1112,7 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } else { 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(); @@ -1147,21 +1148,6 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP result = QUICPacketCreationResult::IGNORED; } break; - case QUICPacketType::RETRY: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::INITIAL, false)) { - if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::INITIAL)) { - result = QUICPacketCreationResult::SUCCESS; - } else { - // ignore failure - probably clear text key is already updated - // FIXME: make sure packet number is smaller than largest sent packet number - result = QUICPacketCreationResult::IGNORED; - } - } else { - result = QUICPacketCreationResult::IGNORED; - } - break; case QUICPacketType::HANDSHAKE: if (this->_hs_protocol->is_key_derived(QUICKeyPhase::HANDSHAKE, false)) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), From 359ac53182da0a1ee386aa16a5e4a7f8bd6c196d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 23 Oct 2018 15:58:39 +0900 Subject: [PATCH 0885/1313] Rename config for server stateless retry --- iocore/net/quic/QUICConfig.cc | 2 +- mgmt/RecordsConfig.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 7b44a72a191..a7092b8773f 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -136,7 +136,7 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); REC_EstablishStaticConfigInt32(this->_connection_table_size, "proxy.config.quic.connection_table.size"); REC_EstablishStaticConfigInt32U(this->_max_alt_connection_ids, "proxy.config.quic.max_alt_connection_ids"); - REC_EstablishStaticConfigInt32U(this->_stateless_retry, "proxy.config.quic.stateless_retry"); + 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"); diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 7f450de2246..3efc5be6aaa 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1339,7 +1339,7 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.max_alt_connection_ids", RECD_INT, "3", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-5]", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.stateless_retry", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.server.stateless_retry_enabled", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.client.vn_exercise_enabled", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} , From 4c31a88af57dfef66ec7dd859345ba56bcfee467 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 23 Oct 2018 16:00:45 +0900 Subject: [PATCH 0886/1313] Handle RETRY packet on quic client --- iocore/net/P_QUICNetVConnection.h | 3 + iocore/net/QUICNetVConnection.cc | 72 +++++++++++++++++------ iocore/net/quic/QUICPacketReceiveQueue.cc | 22 ++++--- 3 files changed, 69 insertions(+), 28 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 7c7eaa205f7..de284a9a069 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -359,6 +359,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet(); QUICStatelessResetToken _reset_token; + ats_unique_buf _retry_token = {nullptr, [](void *p) { ats_free(p); }}; + size_t _retry_token_len = 0; + // This is for limiting number of packets that a server can send without path validation uint32_t _handshake_packets_sent = 0; uint64_t _stream_frames_sent = 0; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 37e1d038cc5..fe1efc86104 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -39,6 +39,7 @@ #include "QUICDebugNames.h" #include "QUICEvents.h" #include "QUICConfig.h" +#include "QUICIntUtil.h" #define STATE_FROM_VIO(_x) ((NetState *)(((char *)(_x)) - STATE_VIO_OFFSET)) #define STATE_VIO_OFFSET ((uintptr_t) & ((NetState *)0)->vio) @@ -920,29 +921,44 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe return error; } +/** + This doesn't call this->_recv_and_ack(), because RETRY packet doesn't have any frames. + */ QUICConnectionErrorUPtr QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) { + ink_assert(this->netvc_context == NET_VCONNECTION_OUT); + + if (this->_retry_token) { + QUICConDebug("Ignore RETRY packet - already processed before"); + return nullptr; + } + + // TODO: move packet->payload to _retry_token + this->_retry_token_len = packet->payload_length(); + this->_retry_token = ats_unique_malloc(this->_retry_token_len); + memcpy(this->_retry_token.get(), packet->payload(), this->_retry_token_len); + // discard all transport state this->_handshake_handler->reset(); + this->_packet_factory.reset(); for (auto s : QUIC_PN_SPACES) { this->_loss_detector[static_cast(s)]->reset(); } this->_congestion_controller->reset(); SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); this->_packet_retransmitter.reset(); - - QUICConnectionErrorUPtr error = this->_recv_and_ack(*packet); - - // Packet number of RETRY packet is echo of INITIAL packet this->_packet_recv_queue.reset(); - // Generate new Connection ID - this->_rerandomize_original_cid(); + // Initialize Key Materials with peer CID. Because peer CID is DCID of (second) INITIAL packet from client which reply to RETRY + // packet from server + this->_hs_protocol->initialize_key_materials(this->_peer_quic_connection_id); - this->_hs_protocol->initialize_key_materials(this->_original_quic_connection_id); + // start handshake over + this->_handshake_handler->do_handshake(); + this->_schedule_packet_write_ready(); - return error; + return nullptr; } QUICConnectionErrorUPtr @@ -1214,7 +1230,10 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa // TODO: adjust MAX_PACKET_OVERHEAD for each encryption level uint64_t max_frame_size = max_packet_size - MAX_PACKET_OVERHEAD; - max_frame_size = std::min(max_frame_size, this->_maximum_stream_frame_data_size()); + if (level == QUICEncryptionLevel::INITIAL && this->_retry_token) { + max_frame_size = max_frame_size - (QUICVariableInt::size(this->_retry_token_len) + this->_retry_token_len); + } + max_frame_size = std::min(max_frame_size, this->_maximum_stream_frame_data_size()); bool probing = false; int frame_count = 0; @@ -1328,7 +1347,11 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa if (level == QUICEncryptionLevel::INITIAL && this->netvc_context == NET_VCONNECTION_OUT) { // Pad with PADDING frames uint64_t min_size = this->minimum_quic_packet_size(); - min_size = std::min(min_size, max_packet_size); + if (this->_retry_token) { + min_size = min_size - this->_retry_token_len; + } + min_size = std::min(min_size, max_packet_size); + if (min_size > len) { // FIXME QUICNetVConnection should not know the actual type value of PADDING frame memset(buf.get() + len, 0, min_size - len); @@ -1375,6 +1398,8 @@ QUICNetVConnection::_packetize_closing_frame() QUICConnectionErrorUPtr QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_frame) { + ink_assert(packet.type() != QUICPacketType::RETRY); + const uint8_t *payload = packet.payload(); uint16_t size = packet.payload_length(); QUICPacketNumber packet_num = packet.packet_number(); @@ -1393,10 +1418,6 @@ QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_fram return error; } - if (packet.type() == QUICPacketType::RETRY) { - should_send_ack = false; - } - if (is_flow_controlled) { int ret = this->_local_flow_controller->update(this->_stream_manager->total_offset_received()); QUICFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller->current_offset(), @@ -1429,11 +1450,24 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi switch (type) { case QUICPacketType::INITIAL: { - QUICConnectionId dcid = - (this->netvc_context == NET_VCONNECTION_OUT) ? this->_original_quic_connection_id : this->_peer_quic_connection_id; - packet = this->_packet_factory.create_initial_packet(dcid, this->_quic_connection_id, - this->largest_acked_packet_number(QUICEncryptionLevel::INITIAL), - std::move(buf), len, retransmittable, probing); + QUICConnectionId dcid = this->_peer_quic_connection_id; + ats_unique_buf token = {nullptr, [](void *p) { ats_free(p); }}; + size_t token_len = 0; + + if (this->netvc_context == NET_VCONNECTION_OUT) { + // TODO: Add a case of using token which is advertized by NEW_TOKEN frame + if (this->_retry_token) { + token = ats_unique_malloc(this->_retry_token_len); + token_len = this->_retry_token_len; + memcpy(token.get(), this->_retry_token.get(), token_len); + } else { + dcid = this->_original_quic_connection_id; + } + } + + packet = this->_packet_factory.create_initial_packet( + dcid, this->_quic_connection_id, this->largest_acked_packet_number(QUICEncryptionLevel::INITIAL), std::move(buf), len, + retransmittable, probing, std::move(token), token_len); break; } case QUICPacketType::HANDSHAKE: { diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 309e3b37f41..8de9993da36 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -122,15 +122,19 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) pkt_len = remaining_len; } else { QUICPacketLongHeader::type(type, this->_payload.get() + this->_offset, remaining_len); - if (!long_hdr_pkt_len(pkt_len, this->_payload.get() + this->_offset, remaining_len)) { - this->_payload.release(); - this->_payload = nullptr; - this->_payload_len = 0; - this->_offset = 0; - - result = QUICPacketCreationResult::IGNORED; - - return quic_packet; + if (type == QUICPacketType::RETRY) { + pkt_len = remaining_len; + } else { + if (!long_hdr_pkt_len(pkt_len, this->_payload.get() + this->_offset, remaining_len)) { + this->_payload.release(); + this->_payload = nullptr; + this->_payload_len = 0; + this->_offset = 0; + + result = QUICPacketCreationResult::IGNORED; + + return quic_packet; + } } } } else { From 1ed85fa00005bab727aa1730000fcdea9e55ee05 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 23 Oct 2018 17:37:37 +0900 Subject: [PATCH 0887/1313] Add support for ack_delay_exponent --- iocore/net/QUICNetVConnection.cc | 8 ++++++++ iocore/net/quic/QUICAckFrameCreator.cc | 18 ++++++++++++++---- iocore/net/quic/QUICAckFrameCreator.h | 4 ++++ iocore/net/quic/QUICConfig.cc | 14 ++++++++++++++ iocore/net/quic/QUICConfig.h | 4 ++++ iocore/net/quic/QUICHandshake.cc | 2 ++ iocore/net/quic/QUICLossDetector.cc | 10 +++++++--- iocore/net/quic/QUICLossDetector.h | 3 +++ iocore/net/quic/QUICTransportParameters.cc | 10 ++++++++++ iocore/net/quic/QUICTransportParameters.h | 1 + mgmt/RecordsConfig.cc | 4 ++++ 11 files changed, 71 insertions(+), 7 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index fe1efc86104..ff73cf3f098 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -206,10 +206,12 @@ QUICNetVConnection::start() this->_five_tuple.update(this->local_addr, this->remote_addr, SOCK_DGRAM); // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not if (this->direction() == NET_VCONNECTION_IN) { + this->_ack_frame_creator.set_ack_delay_exponent(params->ack_delay_exponent_in()); this->_reset_token.generate(this->_quic_connection_id, params->server_id()); this->_hs_protocol = this->_setup_handshake_protocol(params->server_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol, this->_reset_token, params->stateless_retry()); } else { + this->_ack_frame_creator.set_ack_delay_exponent(params->ack_delay_exponent_out()); this->_hs_protocol = this->_setup_handshake_protocol(params->client_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol); this->_handshake_handler->start(&this->_packet_factory, params->vn_exercise_enabled()); @@ -1683,6 +1685,12 @@ QUICNetVConnection::_complete_handshake_if_possible() this->_init_flow_control_params(this->_handshake_handler->local_transport_parameters(), this->_handshake_handler->remote_transport_parameters()); + // PN space doesn't matter but seems like this is the way to pick the LossDetector for 0-RTT and Short packet + int index_for_1rtt = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ONE_RTT); + uint8_t ack_delay_exponent = + this->_handshake_handler->remote_transport_parameters()->getAsUInt8(QUICTransportParameterId::ACK_DELAY_EXPONENT); + this->_loss_detector[index_for_1rtt]->update_ack_delay_exponent(ack_delay_exponent); + this->_start_application(); return 0; diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 391934e1ea0..d1700d7e55a 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -25,6 +25,14 @@ #include "QUICAckFrameCreator.h" #include +void +QUICAckFrameCreator::set_ack_delay_exponent(uint8_t ack_delay_exponent) +{ + // This function should be called only once + ink_assert(this->_ack_delay_exponent == 0); + this->_ack_delay_exponent = ack_delay_exponent; +} + int QUICAckFrameCreator::update(QUICEncryptionLevel level, QUICPacketNumber packet_number, bool should_send) { @@ -140,11 +148,13 @@ uint64_t QUICAckFrameCreator::_calculate_delay(QUICEncryptionLevel level) { // Ack delay is in microseconds and scaled - ink_hrtime now = Thread::get_hrtime(); - int index = QUICTypeUtil::pn_space_index(level); - uint64_t delay = (now - this->_packet_numbers[index].largest_ack_received_time()) / 1000; - // FXIME ack delay exponent has to be read from transport parameters + ink_hrtime now = Thread::get_hrtime(); + int index = QUICTypeUtil::pn_space_index(level); + uint64_t delay = (now - this->_packet_numbers[index].largest_ack_received_time()) / 1000; uint8_t ack_delay_exponent = 3; + if (level != QUICEncryptionLevel::INITIAL && level != QUICEncryptionLevel::HANDSHAKE) { + ack_delay_exponent = this->_ack_delay_exponent; + } return delay >> ack_delay_exponent; } diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index d527174bf32..738dfb3daa1 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -58,6 +58,8 @@ class QUICAckFrameCreator : public QUICFrameGenerator static constexpr int MAXIMUM_PACKET_COUNT = 256; QUICAckFrameCreator(){}; + void set_ack_delay_exponent(uint8_t ack_delay_exponent); + /* * All packet numbers ATS received need to be passed to this method. * Returns 0 if updated successfully. @@ -97,4 +99,6 @@ class QUICAckFrameCreator : public QUICFrameGenerator // Initial, 0/1-RTT, and Handshake QUICAckPacketNumbers _packet_numbers[3]; + + uint8_t _ack_delay_exponent = 0; }; diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index a7092b8773f..1a8f73c6085 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -163,6 +163,8 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_initial_max_bidi_streams_out, "proxy.config.quic.initial_max_bidi_streams_out"); REC_EstablishStaticConfigInt32U(this->_initial_max_uni_streams_in, "proxy.config.quic.initial_max_uni_streams_in"); REC_EstablishStaticConfigInt32U(this->_initial_max_uni_streams_out, "proxy.config.quic.initial_max_uni_streams_out"); + REC_EstablishStaticConfigInt32U(this->_ack_delay_exponent_in, "proxy.config.quic.ack_delay_exponent_in"); + REC_EstablishStaticConfigInt32U(this->_ack_delay_exponent_out, "proxy.config.quic.ack_delay_exponent_out"); // Loss Detection REC_EstablishStaticConfigInt32U(this->_ld_max_tlps, "proxy.config.quic.loss_detection.max_tlps"); @@ -315,6 +317,18 @@ QUICConfigParams::initial_max_uni_streams_out() const return this->_initial_max_uni_streams_out; } +uint8_t +QUICConfigParams::ack_delay_exponent_in() const +{ + return this->_ack_delay_exponent_in; +} + +uint8_t +QUICConfigParams::ack_delay_exponent_out() const +{ + return this->_ack_delay_exponent_out; +} + const char * QUICConfigParams::server_supported_groups() const { diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index d0de94c7ee9..be783590a83 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -63,6 +63,8 @@ class QUICConfigParams : public ConfigInfo uint16_t initial_max_bidi_streams_out() const; uint16_t initial_max_uni_streams_in() const; uint16_t initial_max_uni_streams_out() const; + uint8_t ack_delay_exponent_in() const; + uint8_t ack_delay_exponent_out() const; // Loss Detection uint32_t ld_max_tlps() const; @@ -117,6 +119,8 @@ class QUICConfigParams : public ConfigInfo uint32_t _initial_max_bidi_streams_out = 0; uint32_t _initial_max_uni_streams_in = 0; uint32_t _initial_max_uni_streams_out = 0; + uint32_t _ack_delay_exponent_in = 0; + uint32_t _ack_delay_exponent_out = 0; // [draft-11 recovery] 3.5.1. Constants of interest uint32_t _ld_max_tlps = 2; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 37c3d0af5a7..bd4a7506a65 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -390,6 +390,7 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve // MAYs (server) tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN); + tp->set(QUICTransportParameterId::ACK_DELAY_EXPONENT, params->ack_delay_exponent_in()); tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); @@ -426,6 +427,7 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi if (params->initial_max_stream_data_uni_out() != 0) { tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, params->initial_max_stream_data_uni_out()); } + tp->set(QUICTransportParameterId::ACK_DELAY_EXPONENT, params->ack_delay_exponent_out()); this->_local_transport_parameters = std::shared_ptr(tp); this->_hs_protocol->set_local_transport_parameters(std::unique_ptr(tp)); diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 5aa580dafc8..a6ef2d2007b 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -180,6 +180,12 @@ QUICLossDetector::reset() } } +void +QUICLossDetector::update_ack_delay_exponent(uint8_t ack_delay_exponent) +{ + this->_ack_delay_exponent = ack_delay_exponent; +} + void QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes, QUICPacketUPtr packet) @@ -220,9 +226,7 @@ QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame) if (pi != this->_sent_packets.end()) { this->_latest_rtt = Thread::get_hrtime() - pi->second->time; // _latest_rtt is nanosecond but ack_frame.ack_delay is microsecond and scaled - // FIXME ack delay exponent has to be read from transport parameters - uint8_t ack_delay_exponent = 3; - ink_hrtime delay = HRTIME_USECONDS(ack_frame.ack_delay() << ack_delay_exponent); + ink_hrtime delay = HRTIME_USECONDS(ack_frame.ack_delay() << this->_ack_delay_exponent); this->_update_rtt(this->_latest_rtt, delay, ack_frame.largest_acknowledged()); } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 354698eae0c..7ac4d3328ca 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -119,12 +119,15 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; void on_packet_sent(QUICPacketUPtr packet); QUICPacketNumber largest_acked_packet_number(); + void update_ack_delay_exponent(uint8_t ack_delay_exponent); void reset(); ink_hrtime current_rto_period(); private: Ptr _loss_detection_mutex; + uint8_t _ack_delay_exponent = 3; + // [draft-11 recovery] 3.5.1. Constants of interest // Values will be loaded from records.config via QUICConfig at constructor uint32_t _k_max_tlps = 0; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 2f3353779e9..2bcb307104a 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -289,6 +289,15 @@ QUICTransportParameters::set(QUICTransportParameterId id, const uint8_t *value, this->_parameters.insert(std::make_pair(id, new Value(value, value_len))); } +void +QUICTransportParameters::set(QUICTransportParameterId id, uint8_t value) +{ + uint8_t v[1]; + size_t n; + QUICIntUtil::write_uint_as_nbytes(value, 1, v, &n); + this->set(id, v, 1); +} + void QUICTransportParameters::set(QUICTransportParameterId id, uint16_t value) { @@ -322,6 +331,7 @@ QUICTransportParameters::store(uint8_t *buf, uint16_t *len) const p += sizeof(uint16_t); for (auto &it : this->_parameters) { + // TODO Skip non-MUST parameters that have their default values p[0] = (it.first & 0xff00) >> 8; p[1] = it.first & 0xff; p += 2; diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 52a85021c47..98434098a7c 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -84,6 +84,7 @@ class QUICTransportParameters bool contains(QUICTransportParameterId id) const; void set(QUICTransportParameterId id, const uint8_t *value, uint16_t value_len); + void set(QUICTransportParameterId id, uint8_t value); void set(QUICTransportParameterId id, uint16_t value); void set(QUICTransportParameterId id, uint32_t value); diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 3efc5be6aaa..eca840112fb 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1380,6 +1380,10 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.initial_max_uni_streams_out", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.ack_delay_exponent_in", RECD_INT, "3", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.ack_delay_exponent_out", RECD_INT, "3", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , // Constants of Loss Detection {RECT_CONFIG, "proxy.config.quic.loss_detection.max_tlps", RECD_INT, "2", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , From 29bba883ce44ddbfa329b957a36e8509f2af4432 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 24 Oct 2018 10:32:38 +0900 Subject: [PATCH 0888/1313] Create 0-RTT packet if needed --- iocore/net/QUICNetVConnection.cc | 8 +++++++- iocore/net/quic/QUICPacket.cc | 13 +++++++++++++ iocore/net/quic/QUICPacket.h | 3 +++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ff73cf3f098..b2ff21d0a25 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1478,6 +1478,12 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi std::move(buf), len, retransmittable, probing); break; } + case QUICPacketType::ZERO_RTT_PROTECTED: { + packet = this->_packet_factory.create_zero_rtt_packet(this->_original_quic_connection_id, this->_quic_connection_id, + this->largest_acked_packet_number(QUICEncryptionLevel::ZERO_RTT), + std::move(buf), len, retransmittable, 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), @@ -1485,7 +1491,7 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi break; } default: - // should not be here except zero_rtt + // should not be here ink_assert(false); break; } diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index f3642a81119..d369f74add8 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -1244,6 +1244,19 @@ QUICPacketFactory::create_handshake_packet(QUICConnectionId destination_cid, QUI return this->_create_encrypted_packet(std::move(header), retransmittable, probing); } +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) +{ + int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ZERO_RTT); + QUICPacketNumber pn = this->_packet_number_generator[index].next(); + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::ZERO_RTT_PROTECTED, QUICKeyPhase::ZERO_RTT, destination_cid, source_cid, pn, + base_packet_number, this->_version, std::move(payload), len); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing); +} + QUICPacketUPtr QUICPacketFactory::create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable, bool probing) diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index d6d37c2511e..19408e7270b 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -431,6 +431,9 @@ class QUICPacketFactory QUICPacketUPtr create_handshake_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable, bool probing); + QUICPacketUPtr 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); QUICPacketUPtr create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable, bool probing); void set_version(QUICVersion negotiated_version); From 49c53dac3da49bc327b56237b26a8341a99331fe Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 24 Oct 2018 14:28:12 +0900 Subject: [PATCH 0889/1313] Start server stateless retry only if QUICNetVConnection doesn't exist --- iocore/net/QUICPacketHandler.cc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 7be90fd4712..727a27bd0d7 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -260,15 +260,6 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) return; } - QUICConfig::scoped_config params; - if (params->stateless_retry()) { - int ret = this->_stateless_retry(buf, buf_len, udp_packet->getConnection(), udp_packet->from, dcid, scid); - if (ret < 0) { - udp_packet->free(); - return; - } - } - if (dcid == QUICConnectionId::ZERO()) { // TODO: lookup DCID by 5-tuple when ATS omits SCID return; @@ -285,6 +276,16 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) QUICConnection *qc = this->_ctable->lookup(dcid); QUICNetVConnection *vc = static_cast(qc); + // Server Stateless Retry + QUICConfig::scoped_config params; + if (!vc && params->stateless_retry()) { + int ret = this->_stateless_retry(buf, buf_len, udp_packet->getConnection(), udp_packet->from, dcid, scid); + if (ret < 0) { + udp_packet->free(); + return; + } + } + // [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. From e89bed2d2243fd511dff7141acbe1095a4f44bee Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 25 Oct 2018 11:45:20 +0900 Subject: [PATCH 0890/1313] Cleanup test_QUICHandshakeProtocol --- .../quic/test/test_QUICHandshakeProtocol.cc | 296 +++++++----------- 1 file changed, 121 insertions(+), 175 deletions(-) diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 4c2a4b8d34f..3da69fee8a2 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -66,94 +66,6 @@ static const uint8_t original[] = { static const uint64_t pkt_num = 0x123456789; static const uint8_t ad[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; -// /* Fixed value used in the ServerHello random field to identify an HRR */ -// const unsigned char hrr_random[] = { -// 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91, -// 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c, -// }; - -// static const bool -// is_hrr(uint8_t *msg, size_t msg_len) -// { -// return memmem(msg, msg_len, hrr_random, sizeof(hrr_random)) != nullptr; -// } - -// // dummy token to simplify test -// static uint8_t token[] = {0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, -// 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, -// 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, -// 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef}; - -// static int -// generate_cookie_callback(SSL * /* ssl */, unsigned char *cookie, size_t *cookie_len) -// { -// memcpy(cookie, token, sizeof(token)); -// *cookie_len = sizeof(token); - -// return 1; -// } - -// static int -// verify_cookie_callback(SSL *ssl, const unsigned char *cookie, size_t cookie_len) -// { -// if (memcmp(token, cookie, sizeof(token)) == 0) { -// return 1; -// } else { -// return 0; -// } -// } - -// TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]") -// { -// // Client -// SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); -// SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); -// SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); -// SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); -// QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); - -// // Server -// SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); -// SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); -// SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); -// SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); -// BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); -// SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); -// BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); -// SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); -// QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); - -// CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); -// CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - -// // encrypt - decrypt -// // client (encrypt) - server (decrypt) -// std::cout << "### Original Text" << std::endl; -// print_hex(original, sizeof(original)); - -// uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead -// size_t cipher_len = 0; -// CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), -// QUICKeyPhase::INITIAL)); - -// std::cout << "### Encrypted Text" << std::endl; -// print_hex(cipher, cipher_len); - -// uint8_t plain[128] = {0}; -// size_t plain_len = 0; -// CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::INITIAL)); - -// std::cout << "### Decrypted Text" << std::endl; -// print_hex(plain, plain_len); - -// CHECK(sizeof(original) == (plain_len)); -// CHECK(memcmp(original, plain, plain_len) == 0); - -// // Teardown -// delete client; -// delete server; -// } - TEST_CASE("QUICHandshakeProtocol") { // Client @@ -469,6 +381,127 @@ TEST_CASE("QUICHandshakeProtocol") delete server; } + SECTION("Full Handshake + Packet Number Protection", "[quic]") + { + QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); + QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); + + CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + + QUICPacketNumberProtector client_pn_protector; + QUICPacketNumberProtector server_pn_protector; + + client_pn_protector.set_hs_protocol(client); + server_pn_protector.set_hs_protocol(server); + + uint8_t expected[] = {0x01, 0x02, 0x03, 0x04, 0x05}; + uint8_t sample[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; + uint8_t protected_pn[18], unprotected_pn[18]; + uint8_t protected_pn_len = 0, unprotected_pn_len = 0; + + // ## Client -> Server + client_pn_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); + server_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::INITIAL); + CHECK(unprotected_pn_len == sizeof(expected)); + CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); + // ## Server -> Client + server_pn_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); + client_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::INITIAL); + CHECK(unprotected_pn_len == sizeof(expected)); + CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); + + // # Start Handshake + + // CH + QUICHandshakeMsgs msg1; + uint8_t msg1_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg1.buf = msg1_buf; + msg1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + REQUIRE(client->handshake(&msg1, nullptr) == 1); + + // SH, EE, CERT, CV, FIN + QUICHandshakeMsgs msg2; + uint8_t msg2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2.buf = msg2_buf; + msg2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + REQUIRE(server->handshake(&msg2, &msg1) == 1); + + // FIN + QUICHandshakeMsgs msg3; + uint8_t msg3_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg3.buf = msg3_buf; + msg3.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + +#ifdef SSL_MODE_QUIC_HACK + // -- Hacks for OpenSSL with SSL_MODE_QUIC_HACK -- + // SH + QUICHandshakeMsgs msg2_1; + uint8_t msg2_1_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2_1.buf = msg2_1_buf; + msg2_1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + memcpy(msg2_1.buf, msg2.buf, msg2.offsets[1]); + msg2_1.offsets[0] = 0; + msg2_1.offsets[1] = msg2.offsets[1]; + msg2_1.offsets[2] = msg2.offsets[1]; + msg2_1.offsets[3] = msg2.offsets[1]; + msg2_1.offsets[4] = msg2.offsets[1]; + + // EE - FIN + QUICHandshakeMsgs msg2_2; + uint8_t msg2_2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2_2.buf = msg2_2_buf; + msg2_2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + size_t len = msg2.offsets[3] - msg2.offsets[2]; + memcpy(msg2_2.buf, msg2.buf + msg2.offsets[1], len); + msg2_2.offsets[0] = 0; + msg2_2.offsets[1] = 0; + msg2_2.offsets[2] = 0; + msg2_2.offsets[3] = len; + msg2_2.offsets[4] = len; + + REQUIRE(client->handshake(&msg3, &msg2_1) == 1); + REQUIRE(client->handshake(&msg3, &msg2_2) == 1); +#else + REQUIRE(client->handshake(&msg3, &msg2) == 1); +#endif + + // NS + QUICHandshakeMsgs msg4; + uint8_t msg4_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg4.buf = msg4_buf; + msg4.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + REQUIRE(server->handshake(&msg4, &msg3) == 1); + + QUICHandshakeMsgs msg5; + uint8_t msg5_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg5.buf = msg5_buf; + msg5.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + REQUIRE(client->handshake(&msg5, &msg4) == 1); + + // # End Handshake + + // ## Client -> Server + client_pn_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); + server_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); + CHECK(unprotected_pn_len == sizeof(expected)); + CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); + // ## Server -> Client + server_pn_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); + client_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); + CHECK(unprotected_pn_len == sizeof(expected)); + CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); + + // Teardown + delete client; + delete server; + } + BIO_free(crt_bio); BIO_free(key_bio); @@ -478,90 +511,3 @@ TEST_CASE("QUICHandshakeProtocol") SSL_CTX_free(server_ssl_ctx); SSL_CTX_free(client_ssl_ctx); } - -// TEST_CASE("QUICHandshakeProtocol PNE", "[quic]") -// { -// // Client -// SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); -// SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); -// SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); -// SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); -// QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), NET_VCONNECTION_OUT); -// -// // Server -// SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); -// SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); -// SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); -// SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); -// BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); -// SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); -// BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); -// SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); -// QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN); -// -// uint8_t expected[] = {0x01, 0x02, 0x03, 0x04, 0x05}; -// uint8_t sample[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; -// uint8_t protected_pn[18], unprotected_pn[18]; -// uint8_t protected_pn_len = 0, unprotected_pn_len = 0; -// -// // # Before handshake -// CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); -// CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); -// -// // ## Client -> Server -// client->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); -// server->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::INITIAL); -// CHECK(unprotected_pn_len == sizeof(expected)); -// CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); -// // ## Server -> Client -// server->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); -// client->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::INITIAL); -// CHECK(unprotected_pn_len == sizeof(expected)); -// CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); -// -// // # After handshake -// uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; -// size_t client_hello_len = 0; -// CHECK(client->handshake(client_hello, client_hello_len, MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ); -// std::cout << "### Client Hello" << std::endl; -// print_hex(client_hello, client_hello_len); -// -// // Server Hello -// uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0}; -// size_t server_hello_len = 0; -// CHECK(server->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) == -// SSL_ERROR_WANT_READ); -// std::cout << "### Server Hello" << std::endl; -// print_hex(server_hello, server_hello_len); -// -// // Client Fnished -// uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0}; -// size_t client_finished_len = 0; -// CHECK(client->handshake(client_finished, client_finished_len, MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) == -// SSL_ERROR_NONE); -// std::cout << "### Client Finished" << std::endl; -// print_hex(client_finished, client_finished_len); -// -// CHECK(client->update_key_materials()); -// -// // Post Handshake Msg -// uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0}; -// size_t post_handshake_msg_len = 0; -// CHECK(server->handshake(post_handshake_msg, post_handshake_msg_len, MAX_HANDSHAKE_MSG_LEN, client_finished, -// client_finished_len) == SSL_ERROR_NONE); -// std::cout << "### Post Handshake Message" << std::endl; -// print_hex(post_handshake_msg, post_handshake_msg_len); -// -// CHECK(server->update_key_materials()); -// -// // ## Client -> Server -// client->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); -// server->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); -// CHECK(unprotected_pn_len == sizeof(expected)); -// CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); -// // ## Server -> Client -// server->encrypt_pn(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); -// client->decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); -// CHECK(unprotected_pn_len == sizeof(expected)); -// CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); -// } From 738f94a0c596940c8933c2db01ae2c5fd6803875 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 15 Oct 2018 15:58:50 +0900 Subject: [PATCH 0891/1313] Apply minimum changes for draf-15 - Update Version - Update validation rule for Transport Parameters - Update frame type values - Update NEW_CONNECTION_ID frame format --- iocore/net/quic/QUICDebugNames.cc | 6 ++++ iocore/net/quic/QUICFrame.cc | 5 ++-- iocore/net/quic/QUICTransportParameters.cc | 34 ++++++++++++++-------- iocore/net/quic/QUICTransportParameters.h | 2 ++ iocore/net/quic/QUICTypes.h | 5 ++-- 5 files changed, 36 insertions(+), 16 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 6340d1c0ceb..3fc496d959a 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -88,6 +88,8 @@ QUICDebugNames::frame_type(QUICFrameType type) return "STREAM"; case QUICFrameType::CRYPTO: return "CRYPTO"; + case QUICFrameType::RETIRE_CONNECTION_ID: + return "RETIRE_CONNECTION_ID"; case QUICFrameType::UNKNOWN: default: return "UNKNOWN"; @@ -195,6 +197,10 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) return "INITIAL_MAX_STREAM_DATA_BIDI_REMOTE"; case QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI: return "INITIAL_MAX_STREAM_DATA_UNI"; + case QUICTransportParameterId::MAX_ACK_DELAY: + return "INITIAL_MAX_ACK_DELAY"; + case QUICTransportParameterId::ORIGINAL_CONNECTION_ID: + return "INITIAL_ORIGINAL_CONNECTION_ID"; default: return "UNKNOWN"; } diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 813d7f515b2..aa335c293a6 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -604,6 +604,7 @@ QUICAckFrame::clone() const QUICFrameType QUICAckFrame::type() const { + // TODO ECN return QUICFrameType::ACK; } @@ -2041,10 +2042,10 @@ QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len, size_t limit) const uint8_t *p = buf; *p = static_cast(QUICFrameType::NEW_CONNECTION_ID); ++p; - QUICIntUtil::write_QUICVariableInt(this->_sequence, p, &n); - p += n; *p = this->_connection_id.length(); p += 1; + QUICIntUtil::write_QUICVariableInt(this->_sequence, p, &n); + p += n; QUICTypeUtil::write_QUICConnectionId(this->_connection_id, p, &n); p += n; memcpy(p, this->_stateless_reset_token.buf(), QUICStatelessResetToken::LEN); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 2bcb307104a..476020198c7 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -35,7 +35,7 @@ static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; static constexpr char tag[] = "quic_handshake"; static constexpr uint32_t TP_ERROR_LENGTH = 0x010000; -static constexpr uint32_t TP_ERROR_VALUE = 0x020000; +// static constexpr uint32_t TP_ERROR_VALUE = 0x020000; static constexpr uint32_t TP_ERROR_MUST_EXIST = 0x030000; static constexpr uint32_t TP_ERROR_MUST_NOT_EXIST = 0x040000; @@ -147,16 +147,6 @@ QUICTransportParameters::_validate_parameters() const decltype(this->_parameters)::const_iterator ite; // MUSTs - if ((ite = this->_parameters.find(QUICTransportParameterId::IDLE_TIMEOUT)) != this->_parameters.end()) { - if (ite->second->len() != 2) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::IDLE_TIMEOUT); - } - if (QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 600) { - return -(TP_ERROR_VALUE | QUICTransportParameterId::IDLE_TIMEOUT); - } - } else { - return -(TP_ERROR_MUST_EXIST | QUICTransportParameterId::IDLE_TIMEOUT); - } // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_DATA)) != this->_parameters.end()) { @@ -177,6 +167,12 @@ QUICTransportParameters::_validate_parameters() const } } + if ((ite = this->_parameters.find(QUICTransportParameterId::IDLE_TIMEOUT)) != this->_parameters.end()) { + if (ite->second->len() != 2) { + return -(TP_ERROR_LENGTH | QUICTransportParameterId::IDLE_TIMEOUT); + } + } + if ((ite = this->_parameters.find(QUICTransportParameterId::MAX_PACKET_SIZE)) != this->_parameters.end()) { if (ite->second->len() != 2) { return -(TP_ERROR_LENGTH | QUICTransportParameterId::MAX_PACKET_SIZE); @@ -216,7 +212,13 @@ QUICTransportParameters::_validate_parameters() const if ((ite = this->_parameters.find(QUICTransportParameterId::DISABLE_MIGRATION)) != this->_parameters.end()) { if (ite->second->len() != 0) { - return -6; + return -(TP_ERROR_LENGTH | QUICTransportParameterId::DISABLE_MIGRATION); + } + } + + if ((ite = this->_parameters.find(QUICTransportParameterId::MAX_ACK_DELAY)) != this->_parameters.end()) { + if (ite->second->len() != 1) { + return -(TP_ERROR_LENGTH | QUICTransportParameterId::MAX_ACK_DELAY); } } @@ -495,6 +497,14 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const decltype(this->_parameters)::const_iterator ite; + // MUSTs if the server sent a Retry packet + if ((ite = this->_parameters.find(QUICTransportParameterId::ORIGINAL_CONNECTION_ID)) != this->_parameters.end()) { + // We cannot check the length because it's not a fixed length. + } else { + // TODO Need a way that checks if we received a Retry from the server + // return -(TP_ERROR_MUST_EXIST | QUICTransportParameterId::ORIGINAL_CONNECTION_ID); + } + // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) { if (ite->second->len() != QUICStatelessResetToken::LEN) { diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 98434098a7c..a9b4dcd719d 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -46,6 +46,8 @@ class QUICTransportParameterId DISABLE_MIGRATION, INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, INITIAL_MAX_STREAM_DATA_UNI, + MAX_ACK_DELAY, + ORIGINAL_CONNECTION_ID, }; explicit operator bool() const { return true; } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 5c1b1b954d8..8050e36a1c2 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -49,7 +49,7 @@ using QUICOffset = uint64_t; // Note: Fix QUIC_ALPN_PROTO_LIST in QUICConfig.cc // Note: Change ExtensionType (QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID) if it's changed constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff00000e, + 0xff00000f, }; constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; @@ -105,12 +105,13 @@ enum class QUICFrameType : uint8_t { STREAM_ID_BLOCKED, NEW_CONNECTION_ID, STOP_SENDING, - ACK, + RETIRE_CONNECTION_ID, PATH_CHALLENGE, PATH_RESPONSE, STREAM = 0x10, // 0x10 - 0x17 CRYPTO = 0x18, NEW_TOKEN, + ACK, // 0x1a - 0x1b UNKNOWN, }; From 4c2b886301523949294a76e32baa0dba55bc9bc5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 17 Oct 2018 11:24:46 +0900 Subject: [PATCH 0892/1313] Fix tests for ACK frame --- iocore/net/quic/test/test_QUICFrame.cc | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 809e41f2211..e808098e0ef 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -42,14 +42,23 @@ TEST_CASE("QUICFrame Type", "[quic]") CHECK(QUICFrame::type(reinterpret_cast("\x0a")) == QUICFrameType::STREAM_ID_BLOCKED); CHECK(QUICFrame::type(reinterpret_cast("\x0b")) == QUICFrameType::NEW_CONNECTION_ID); CHECK(QUICFrame::type(reinterpret_cast("\x0c")) == QUICFrameType::STOP_SENDING); - CHECK(QUICFrame::type(reinterpret_cast("\x0d")) == QUICFrameType::ACK); + CHECK(QUICFrame::type(reinterpret_cast("\x0d")) == QUICFrameType::RETIRE_CONNECTION_ID); CHECK(QUICFrame::type(reinterpret_cast("\x0e")) == QUICFrameType::PATH_CHALLENGE); CHECK(QUICFrame::type(reinterpret_cast("\x0f")) == QUICFrameType::PATH_RESPONSE); + // Range of STREAM CHECK(QUICFrame::type(reinterpret_cast("\x10")) == QUICFrameType::STREAM); CHECK(QUICFrame::type(reinterpret_cast("\x17")) == QUICFrameType::STREAM); + + CHECK(QUICFrame::type(reinterpret_cast("\x18")) == QUICFrameType::CRYPTO); + CHECK(QUICFrame::type(reinterpret_cast("\x19")) == QUICFrameType::NEW_TOKEN); CHECK(QUICFrame::type(reinterpret_cast("\x18")) == QUICFrameType::CRYPTO); CHECK(QUICFrame::type(reinterpret_cast("\x19")) == QUICFrameType::NEW_TOKEN); + + // Range of ACK + CHECK(QUICFrame::type(reinterpret_cast("\x1a")) == QUICFrameType::ACK); + CHECK(QUICFrame::type(reinterpret_cast("\x1b")) == QUICFrameType::ACK); + // Undefined ragne CHECK(QUICFrame::type(reinterpret_cast("\x21")) == QUICFrameType::UNKNOWN); CHECK(QUICFrame::type(reinterpret_cast("\xff")) == QUICFrameType::UNKNOWN); @@ -404,7 +413,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") { uint8_t buf1[] = { - 0x0d, // Type + 0x1a, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x00, // Ack Block Count @@ -423,7 +432,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") { uint8_t buf1[] = { - 0x0d, // Type + 0x1a, // Type 0x80, 0x00, 0x00, 0x01, // Largest Acknowledged 0x41, 0x71, // Ack Delay 0x00, // Ack Block Count @@ -446,7 +455,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("2 Ack Block, 8 bit packet number length, 8 bit block length") { uint8_t buf1[] = { - 0x0d, // Type + 0x1a, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x02, // Ack Block Count @@ -489,7 +498,7 @@ TEST_CASE("Store Ack Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x0d, // Type + 0x1a, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x00, // Ack Block Count @@ -510,7 +519,7 @@ TEST_CASE("Store Ack Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x0d, // Type + 0x1a, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x02, // Ack Block Count From 73576459916de7cd1662559fff96b6c7c7ecdac9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 17 Oct 2018 11:36:35 +0900 Subject: [PATCH 0893/1313] Fix NEW_CONNECTION_ID --- iocore/net/quic/QUICFrame.cc | 6 +++--- iocore/net/quic/test/test_QUICFrame.cc | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index aa335c293a6..4bb2e214e0c 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2070,7 +2070,7 @@ uint64_t QUICNewConnectionIdFrame::sequence() const { if (this->_buf) { - return QUICIntUtil::read_QUICVariableInt(this->_buf + sizeof(QUICFrameType)); + return QUICIntUtil::read_QUICVariableInt(this->_buf + sizeof(QUICFrameType) + 1); } else { return this->_sequence; } @@ -2101,7 +2101,7 @@ size_t QUICNewConnectionIdFrame::_get_sequence_field_length() const { if (this->_buf) { - return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); + return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType) + 1); } else { return QUICVariableInt::size(this->_sequence); } @@ -2111,7 +2111,7 @@ size_t QUICNewConnectionIdFrame::_get_connection_id_length() const { if (this->_buf) { - return this->_buf[sizeof(QUICFrameType) + this->_get_sequence_field_length()]; + return this->_buf[sizeof(QUICFrameType)]; } else { return this->_connection_id.length(); } diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index e808098e0ef..2462593f9f1 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1028,8 +1028,8 @@ TEST_CASE("Load NewConnectionId Frame", "[quic]") { uint8_t buf1[] = { 0x0b, // Type - 0x41, 0x02, // Sequence 0x08, // Length + 0x41, 0x02, // Sequence 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, @@ -1053,8 +1053,8 @@ TEST_CASE("Store NewConnectionId Frame", "[quic]") uint8_t expected[] = { 0x0b, // Type - 0x41, 0x02, // Sequence 0x08, // Length + 0x41, 0x02, // Sequence 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Stateless Reset Token 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, @@ -1585,8 +1585,8 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") { uint8_t frame_buf[] = { 0x0b, // Type - 0x41, 0x02, // Sequence 0x08, // Length + 0x41, 0x02, // Sequence 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, From 236323f61d36eb77b29006b66cad004e2e1e32fa Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 17 Oct 2018 11:39:35 +0900 Subject: [PATCH 0894/1313] Add RETIRE_CONNECTION_ID --- iocore/net/quic/QUICFrame.cc | 85 ++++++++++++++++++++++++++ iocore/net/quic/QUICFrame.h | 37 +++++++++++ iocore/net/quic/test/test_QUICFrame.cc | 35 +++++++++++ 3 files changed, 157 insertions(+) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 4bb2e214e0c..02c9c0a96d1 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -48,6 +48,7 @@ ClassAllocator quicStopSendingFrameAllocator("quicStopSend ClassAllocator quicPathChallengeFrameAllocator("quicPathChallengeFrameAllocator"); ClassAllocator quicPathResponseFrameAllocator("quicPathResponseFrameAllocator"); ClassAllocator quicNewTokenFrameAllocator("quicNewTokenFrameAllocator"); +ClassAllocator quicRetireConnectionIdFrameAllocator("quicRetireConnectionIdFrameAllocator"); ClassAllocator quicRetransmissionFrameAllocator("quicRetransmissionFrameAllocator"); QUICFrameType @@ -2431,6 +2432,78 @@ QUICNewTokenFrame::_get_token_field_offset() const return sizeof(QUICFrameType) + this->_get_token_length_field_length(); } +// +// RETIRE_CONNECTION_ID frame +// +QUICFrameUPtr +QUICRetireConnectionIdFrame::clone() const +{ + return QUICFrameFactory::create_retire_connection_id_frame(this->seq_num()); +} + +QUICFrameType +QUICRetireConnectionIdFrame::type() const +{ + return QUICFrameType::RETIRE_CONNECTION_ID; +} + +size_t +QUICRetireConnectionIdFrame::size() const +{ + return sizeof(QUICFrameType) + this->_get_seq_num_field_length(); +} + +size_t +QUICRetireConnectionIdFrame::store(uint8_t *buf, size_t *len, size_t limit) const +{ + if (limit < this->size()) { + return 0; + } + + if (this->_buf) { + *len = this->size(); + memcpy(buf, this->_buf, *len); + } else { + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::RETIRE_CONNECTION_ID); + ++p; + QUICIntUtil::write_QUICVariableInt(this->_seq_num, p, &n); + p += n; + + *len = p - buf; + } + + return *len; +} + +int +QUICRetireConnectionIdFrame::debug_msg(char *msg, size_t msg_len) const +{ + return snprintf(msg, msg_len, "| RETIRE_CONNECTION_ID size=%zu seq_num=%" PRIu64, this->size(), this->seq_num()); +} + +uint64_t +QUICRetireConnectionIdFrame::seq_num() const +{ + if (this->_buf) { + return QUICIntUtil::read_QUICVariableInt(this->_buf + sizeof(QUICFrameType)); + } else { + return this->_seq_num; + } +} + +size_t +QUICRetireConnectionIdFrame::_get_seq_num_field_length() const +{ + if (this->_buf) { + return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); + } else { + return QUICVariableInt::size(this->_seq_num); + } +} + + // // QUICRetransmissionFrame // @@ -2585,6 +2658,10 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicNewTokenFrameAllocator.alloc(); new (frame) QUICNewTokenFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_new_token_frame); + case QUICFrameType::RETIRE_CONNECTION_ID: + frame = quicRetireConnectionIdFrameAllocator.alloc(); + new (frame) QUICRetireConnectionIdFrame(buf, len); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_retire_connection_id_frame); default: // Unknown frame Debug("quic_frame_factory", "Unknown frame type %x", buf[0]); @@ -2811,6 +2888,14 @@ QUICFrameFactory::create_new_token_frame(const uint8_t *token, uint64_t token_le return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_token_frame); } +std::unique_ptr +QUICFrameFactory::create_retire_connection_id_frame(uint64_t seq_num) +{ + QUICRetireConnectionIdFrame *frame = quicRetireConnectionIdFrameAllocator.alloc(); + new (frame) QUICRetireConnectionIdFrame(seq_num); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_retire_connection_id_frame); +} + std::unique_ptr QUICFrameFactory::create_retransmission_frame(QUICFrameUPtr original_frame, const QUICPacket &original_packet) { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index ecc71152f3f..7d4e00b6c25 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -683,6 +683,30 @@ class QUICNewTokenFrame : public QUICFrame ats_unique_buf _token = {nullptr, [](void *p) { ats_free(p); }}; }; +// +// RETIRE_CONNECTION_ID +// + +class QUICRetireConnectionIdFrame : public QUICFrame +{ +public: + QUICRetireConnectionIdFrame() : QUICFrame() {} + QUICRetireConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICRetireConnectionIdFrame(uint64_t seq_num) : _seq_num(seq_num) {} + QUICFrameUPtr clone() const override; + virtual QUICFrameType type() const override; + virtual size_t size() const override; + virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual int debug_msg(char *msg, size_t msg_len) const override; + + uint64_t seq_num() const; + +private: + size_t _get_seq_num_field_length() const; + + uint64_t _seq_num = 0; +}; + // // Retransmission Frame - Not on the spec // @@ -725,6 +749,7 @@ extern ClassAllocator quicStopSendingFrameAllocator; extern ClassAllocator quicPathChallengeFrameAllocator; extern ClassAllocator quicPathResponseFrameAllocator; extern ClassAllocator quicNewTokenFrameAllocator; +extern ClassAllocator quicRetireConnectionIdFrameAllocator; extern ClassAllocator quicRetransmissionFrameAllocator; class QUICFrameDeleter @@ -870,6 +895,13 @@ class QUICFrameDeleter quicNewTokenFrameAllocator.free(static_cast(frame)); } + static void + delete_retire_connection_id_frame(QUICFrame *frame) + { + frame->~QUICFrame(); + quicRetireConnectionIdFrameAllocator.free(static_cast(frame)); + } + static void delete_retransmission_frame(QUICFrame *frame) { @@ -1016,6 +1048,11 @@ class QUICFrameFactory */ static std::unique_ptr create_new_token_frame(const uint8_t *token, uint64_t token_len); + /* + * Creates a RETIRE_CONNECTION_ID frame + */ + static std::unique_ptr create_retire_connection_id_frame(uint64_t seq_num); + /* * Creates a retransmission frame, which is very special. * This retransmission frame will be used only for retransmission and it's not a standard frame type. diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 2462593f9f1..2c2ad4c4b11 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1221,6 +1221,41 @@ TEST_CASE("NEW_TOKEN Frame", "[quic]") } } +TEST_CASE("RETIRE_CONNECTION_ID Frame", "[quic]") +{ + uint8_t raw_retire_connection_id_frame[] = { + 0x0d, // Type + 0x08, // Sequence Number (i) + }; + size_t raw_retire_connection_id_frame_len = sizeof(raw_retire_connection_id_frame); + uint64_t seq_num = 8; + + SECTION("load") + { + std::shared_ptr frame = QUICFrameFactory::create(raw_retire_connection_id_frame, raw_retire_connection_id_frame_len); + CHECK(frame->type() == QUICFrameType::RETIRE_CONNECTION_ID); + CHECK(frame->size() == raw_retire_connection_id_frame_len); + + std::shared_ptr retire_connection_id_frame = std::dynamic_pointer_cast(frame); + CHECK(retire_connection_id_frame != nullptr); + CHECK(retire_connection_id_frame->seq_num() == seq_num); + } + + SECTION("store") + { + uint8_t buf[32]; + size_t len; + + QUICRetireConnectionIdFrame frame(seq_num); + CHECK(frame.size() == raw_retire_connection_id_frame_len); + + frame.store(buf, &len, 16); + CHECK(len == raw_retire_connection_id_frame_len); + CHECK(memcmp(buf, raw_retire_connection_id_frame, len) == 0); + } +} + TEST_CASE("QUICFrameFactory Create Unknown Frame", "[quic]") { uint8_t buf1[] = { From 50a0c033b99f63e242d7b5282192f52fb6b9bfbe Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 17 Oct 2018 11:55:38 +0900 Subject: [PATCH 0895/1313] Fix frame type detection --- iocore/net/quic/QUICFrame.cc | 2 ++ iocore/net/quic/QUICTypes.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 02c9c0a96d1..c0ae43fb982 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -70,6 +70,8 @@ QUICFrame::type(const uint8_t *buf) return QUICFrameType::UNKNOWN; } else if (static_cast(QUICFrameType::STREAM) <= buf[0] && buf[0] < static_cast(QUICFrameType::CRYPTO)) { return QUICFrameType::STREAM; + } else if (static_cast(QUICFrameType::ACK) <= buf[0] && buf[0] < static_cast(QUICFrameType::UNKNOWN)) { + return QUICFrameType::ACK; } else { return static_cast(buf[0]); } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 8050e36a1c2..1a05852b6ee 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -112,7 +112,7 @@ enum class QUICFrameType : uint8_t { CRYPTO = 0x18, NEW_TOKEN, ACK, // 0x1a - 0x1b - UNKNOWN, + UNKNOWN = 0x1c, }; enum class QUICVersionNegotiationStatus { From 1f1f22cf6e00a3508ded9d4f836005ee78b7e5df Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 17 Oct 2018 12:04:11 +0900 Subject: [PATCH 0896/1313] Fix a test for VN packet --- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index a987d617189..4ffedbc22f8 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -53,7 +53,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x55, // DCIL/SCIL 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Destination Connection ID 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection ID - 0xff, 0x00, 0x00, 0x0e, // Supported Version + 0xff, 0x00, 0x00, 0x0f, // Supported Version }; uint8_t buf[1024] = {0}; size_t buf_len; From 156c6827f8093f75e977057b6437e6d539eec811 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 17 Oct 2018 16:52:36 +0900 Subject: [PATCH 0897/1313] Add partial support for ECN Section It can read ECN Section but cannot write ECN Section --- iocore/net/quic/QUICFrame.cc | 68 ++++++++++++++++++++++++-- iocore/net/quic/QUICFrame.h | 19 +++++++ iocore/net/quic/test/test_QUICFrame.cc | 42 +++++++++++++--- 3 files changed, 120 insertions(+), 9 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index c0ae43fb982..3e2db22063f 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -579,6 +579,10 @@ QUICAckFrame::~QUICAckFrame() delete this->_ack_block_section; this->_ack_block_section = nullptr; } + if (this->_ecn_section) { + delete this->_ecn_section; + this->_ecn_section = nullptr; + } } void @@ -588,7 +592,14 @@ QUICAckFrame::reset(const uint8_t *buf, size_t len) if (this->_ack_block_section) { delete this->_ack_block_section; } + if (this->_ecn_section) { + delete this->_ecn_section; + } + this->_ack_block_section = new AckBlockSection(buf + this->_get_ack_block_section_offset(), this->ack_block_count()); + if (buf[0] == static_cast(QUICFrameType::ACK) + 1) { + this->_ecn_section = new EcnSection(buf + this->_get_ack_block_section_offset() + this->_ack_block_section->size()); + } } QUICFrameUPtr @@ -614,7 +625,11 @@ QUICAckFrame::type() const size_t QUICAckFrame::size() const { - return this->_get_ack_block_section_offset() + this->_ack_block_section->size(); + if (this->_ecn_section) { + return this->_get_ack_block_section_offset() + this->_ack_block_section->size() + this->_ecn_section->size(); + } else { + return this->_get_ack_block_section_offset() + this->_ack_block_section->size(); + } } size_t @@ -706,6 +721,18 @@ QUICAckFrame::ack_block_section() const return this->_ack_block_section; } +QUICAckFrame::EcnSection * +QUICAckFrame::ecn_section() +{ + return this->_ecn_section; +} + +const QUICAckFrame::EcnSection * +QUICAckFrame::ecn_section() const +{ + return this->_ecn_section; +} + size_t QUICAckFrame::_get_largest_acknowledged_offset() const { @@ -1005,6 +1032,41 @@ QUICAckFrame::AckBlockSection::const_iterator::operator==(const const_iterator & return this->_index == ite._index; } +QUICAckFrame::EcnSection::EcnSection(const uint8_t *buf) +{ + size_t ect0_length; + size_t ect1_length; + size_t ecn_ce_length; + QUICVariableInt::decode(this->_ect0_count, ect0_length, buf); + QUICVariableInt::decode(this->_ect1_count, ect1_length, buf + ect0_length); + QUICVariableInt::decode(this->_ecn_ce_count, ecn_ce_length, buf + ect0_length + ect1_length); + this->_section_size = ect0_length + ect1_length + ecn_ce_length; +} + +size_t +QUICAckFrame::EcnSection::size() const +{ + return this->_section_size; +} + +uint64_t +QUICAckFrame::EcnSection::ect0_count() const +{ + return this->_ect0_count; +} + +uint64_t +QUICAckFrame::EcnSection::ect1_count() const +{ + return this->_ect1_count; +} + +uint64_t +QUICAckFrame::EcnSection::ecn_ce_count() const +{ + return this->_ecn_ce_count; +} + // // RST_STREAM frame // @@ -2505,7 +2567,6 @@ QUICRetireConnectionIdFrame::_get_seq_num_field_length() const } } - // // QUICRetransmissionFrame // @@ -2895,7 +2956,8 @@ QUICFrameFactory::create_retire_connection_id_frame(uint64_t seq_num) { QUICRetireConnectionIdFrame *frame = quicRetireConnectionIdFrameAllocator.alloc(); new (frame) QUICRetireConnectionIdFrame(seq_num); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_retire_connection_id_frame); + return std::unique_ptr(frame, + &QUICFrameDeleter::delete_retire_connection_id_frame); } std::unique_ptr diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 7d4e00b6c25..c0c1da7fddc 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -239,6 +239,22 @@ class QUICAckFrame : public QUICFrame std::vector _ack_blocks; }; + class EcnSection + { + public: + EcnSection(const uint8_t *buf); + size_t size() const; + uint64_t ect0_count() const; + uint64_t ect1_count() const; + uint64_t ecn_ce_count() const; + + private: + uint64_t _section_size = 0; + uint64_t _ect0_count = 0; + uint64_t _ect1_count = 0; + uint64_t _ecn_ce_count = 0; + }; + QUICAckFrame() : QUICFrame() {} QUICAckFrame(const uint8_t *buf, size_t len); QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block); @@ -256,6 +272,8 @@ class QUICAckFrame : public QUICFrame uint64_t ack_block_count() const; const AckBlockSection *ack_block_section() const; AckBlockSection *ack_block_section(); + const EcnSection *ecn_section() const; + EcnSection *ecn_section(); private: size_t _get_largest_acknowledged_offset() const; @@ -269,6 +287,7 @@ class QUICAckFrame : public QUICFrame QUICPacketNumber _largest_acknowledged = 0; uint64_t _ack_delay = 0; AckBlockSection *_ack_block_section = nullptr; + EcnSection *_ecn_section = nullptr; }; // diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 2c2ad4c4b11..58ca5641154 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -447,6 +447,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") CHECK(ack_frame1->largest_acknowledged() == 0x01); CHECK(ack_frame1->ack_delay() == 0x0171); CHECK(ack_frame1->ack_block_count() == 0); + CHECK(ack_frame1->ecn_section() == nullptr); const QUICAckFrame::AckBlockSection *section = ack_frame1->ack_block_section(); CHECK(section->first_ack_block() == 0x01); @@ -474,6 +475,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") CHECK(ack_frame1->largest_acknowledged() == 0x12); CHECK(ack_frame1->ack_delay() == 0x3456); CHECK(ack_frame1->ack_block_count() == 2); + CHECK(ack_frame1->ecn_section() == nullptr); const QUICAckFrame::AckBlockSection *section = ack_frame1->ack_block_section(); CHECK(section->first_ack_block() == 0x01); @@ -488,6 +490,33 @@ TEST_CASE("Load Ack Frame 1", "[quic]") ++ite; CHECK(ite == section->end()); } + + SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length with ECN section") + { + uint8_t buf1[] = { + 0x1b, // Type + 0x12, // Largest Acknowledged + 0x74, 0x56, // Ack Delay + 0x00, // Ack Block Count + 0x00, // Ack Block Section + // ECN + 0x01, // ECT0 + 0x02, // ECT1 + 0x03, // ECN-CE + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::ACK); + CHECK(frame1->size() == 9); + std::shared_ptr ack_frame1 = std::dynamic_pointer_cast(frame1); + CHECK(ack_frame1 != nullptr); + CHECK(ack_frame1->ack_block_count() == 0); + CHECK(ack_frame1->largest_acknowledged() == 0x12); + CHECK(ack_frame1->ack_delay() == 0x3456); + CHECK(ack_frame1->ecn_section()); + CHECK(ack_frame1->ecn_section()->ect0_count() == 1); + CHECK(ack_frame1->ecn_section()->ect1_count() == 2); + CHECK(ack_frame1->ecn_section()->ecn_ce_count() == 3); + } } TEST_CASE("Store Ack Frame", "[quic]") @@ -1224,20 +1253,21 @@ TEST_CASE("NEW_TOKEN Frame", "[quic]") TEST_CASE("RETIRE_CONNECTION_ID Frame", "[quic]") { uint8_t raw_retire_connection_id_frame[] = { - 0x0d, // Type - 0x08, // Sequence Number (i) + 0x0d, // Type + 0x08, // Sequence Number (i) }; size_t raw_retire_connection_id_frame_len = sizeof(raw_retire_connection_id_frame); - uint64_t seq_num = 8; + uint64_t seq_num = 8; SECTION("load") { - std::shared_ptr frame = QUICFrameFactory::create(raw_retire_connection_id_frame, raw_retire_connection_id_frame_len); + std::shared_ptr frame = + QUICFrameFactory::create(raw_retire_connection_id_frame, raw_retire_connection_id_frame_len); CHECK(frame->type() == QUICFrameType::RETIRE_CONNECTION_ID); CHECK(frame->size() == raw_retire_connection_id_frame_len); - std::shared_ptr retire_connection_id_frame = std::dynamic_pointer_cast(frame); + std::shared_ptr retire_connection_id_frame = + std::dynamic_pointer_cast(frame); CHECK(retire_connection_id_frame != nullptr); CHECK(retire_connection_id_frame->seq_num() == seq_num); } From 7350bc218752f45e754ccc90b14f8e1fd38dafca Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 18 Oct 2018 11:35:19 +0900 Subject: [PATCH 0898/1313] An endpoint should provide and maintain at least 8 CIDs --- iocore/net/quic/QUICAltConnectionManager.cc | 2 +- iocore/net/quic/QUICConfig.cc | 6 +++--- iocore/net/quic/QUICConfig.h | 4 ++-- mgmt/RecordsConfig.cc | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index bdf09e76dba..641e2e11737 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -33,7 +33,7 @@ QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConne { QUICConfig::scoped_config params; - this->_nids = params->max_alt_connection_ids(); + this->_nids = params->num_alt_connection_ids(); this->_alt_quic_connection_ids = static_cast(ats_malloc(sizeof(AltConnectionInfo) * this->_nids)); this->_update_alt_connection_ids(-1); } diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 1a8f73c6085..fa953c53c8d 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -135,7 +135,7 @@ QUICConfigParams::initialize() { REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); REC_EstablishStaticConfigInt32(this->_connection_table_size, "proxy.config.quic.connection_table.size"); - REC_EstablishStaticConfigInt32U(this->_max_alt_connection_ids, "proxy.config.quic.max_alt_connection_ids"); + REC_EstablishStaticConfigInt32U(this->_num_alt_connection_ids, "proxy.config.quic.num_alt_connection_ids"); 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"); @@ -222,9 +222,9 @@ QUICConfigParams::connection_table_size() } uint32_t -QUICConfigParams::max_alt_connection_ids() const +QUICConfigParams::num_alt_connection_ids() const { - return this->_max_alt_connection_ids; + return this->_num_alt_connection_ids; } uint32_t diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index be783590a83..d689e848aa0 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -36,7 +36,7 @@ class QUICConfigParams : public ConfigInfo void initialize(); uint32_t server_id() const; - uint32_t max_alt_connection_ids() const; + uint32_t num_alt_connection_ids() const; uint32_t stateless_retry() const; uint32_t vn_exercise_enabled() const; uint32_t cm_exercise_enabled() const; @@ -91,7 +91,7 @@ class QUICConfigParams : public ConfigInfo static const uint8_t _scid_len = 18; //< Length of Source Connection ID uint32_t _server_id = 0; - uint32_t _max_alt_connection_ids = 0; + uint32_t _num_alt_connection_ids = 0; uint32_t _stateless_retry = 0; uint32_t _vn_exercise_enabled = 0; uint32_t _cm_exercise_enabled = 0; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index eca840112fb..0d81bbeda44 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1337,7 +1337,7 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.connection_table.size", RECD_INT, "65521", RECU_RESTART_TS, RR_NULL, RECC_INT, "[1-536870909]", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.max_alt_connection_ids", RECD_INT, "3", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-5]", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.num_alt_connection_ids", RECD_INT, "8", RECU_RESTART_TS, RR_NULL, RECC_INT, "[8-256]", RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.server.stateless_retry_enabled", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} , From 992aa470edd1af361e5993ab66b9820c1b6201e5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 19 Oct 2018 14:30:51 +0900 Subject: [PATCH 0899/1313] Update connection migration --- iocore/net/P_QUICNetVConnection.h | 5 +- iocore/net/QUICNetVConnection.cc | 47 ++-- iocore/net/quic/QUICAltConnectionManager.cc | 235 +++++++++++++++----- iocore/net/quic/QUICAltConnectionManager.h | 61 ++++- iocore/net/quic/QUICFrame.cc | 2 +- iocore/net/quic/QUICTransportParameters.cc | 2 +- 6 files changed, 253 insertions(+), 99 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index de284a9a069..71cc078ae2f 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -31,8 +31,6 @@ ****************************************************************************/ #pragma once -#include - #include "tscore/ink_platform.h" #include "P_Net.h" #include "P_EventSystem.h" @@ -233,12 +231,11 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub std::random_device _rnd; QUICConnectionId _peer_quic_connection_id; // dst cid in local + QUICConnectionId _peer_old_quic_connection_id; // dst previous cid in local QUICConnectionId _original_quic_connection_id; // dst cid of initial packet from client QUICConnectionId _quic_connection_id; // src cid in local QUICFiveTuple _five_tuple; bool _connection_migration_initiated = false; - // TODO: Revisit life cycle of cids when draft-15 is published - std::queue _remote_alt_cids; char _cids_data[MAX_CIDS_SIZE] = {0}; std::string_view _cids; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b2ff21d0a25..6bc25ef1f8e 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -452,8 +452,7 @@ QUICNetVConnection::close(QUICConnectionErrorUPtr error) std::vector QUICNetVConnection::interests() { - return {QUICFrameType::APPLICATION_CLOSE, QUICFrameType::CONNECTION_CLOSE, QUICFrameType::BLOCKED, QUICFrameType::MAX_DATA, - QUICFrameType::NEW_CONNECTION_ID}; + return {QUICFrameType::APPLICATION_CLOSE, QUICFrameType::CONNECTION_CLOSE, QUICFrameType::BLOCKED, QUICFrameType::MAX_DATA}; } QUICConnectionErrorUPtr @@ -475,9 +474,6 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra case QUICFrameType::BLOCKED: // BLOCKED frame is for debugging. Nothing to do here. break; - case QUICFrameType::NEW_CONNECTION_ID: - error = this->_handle_frame(static_cast(frame)); - break; case QUICFrameType::APPLICATION_CLOSE: case QUICFrameType::CONNECTION_CLOSE: if (this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closed) || @@ -506,21 +502,6 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra return error; } -QUICConnectionErrorUPtr -QUICNetVConnection::_handle_frame(const QUICNewConnectionIdFrame &frame) -{ - QUICConnectionErrorUPtr error = nullptr; - - if (frame.connection_id() == QUICConnectionId::ZERO()) { - return std::make_unique(QUICTransErrorCode::PROTOCOL_VIOLATION, "received zero-length cid", - QUICFrameType::NEW_CONNECTION_ID); - } - - this->_remote_alt_cids.push(frame.connection_id()); - - return error; -} - // XXX Setup QUICNetVConnection on regular EThread. // QUICNetVConnection::init() and QUICNetVConnection::start() might be called on ET_UDP EThread. int @@ -1777,7 +1758,8 @@ QUICNetVConnection::_switch_to_established_state() if (netvc_context == NET_VCONNECTION_IN || (netvc_context == NET_VCONNECTION_OUT && params->cm_exercise_enabled() && !remote_tp->contains(QUICTransportParameterId::DISABLE_MIGRATION))) { - this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable); + this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id); + this->_frame_dispatcher->add_handler(this->_alt_con_manager); } } else { // Illegal state change @@ -1894,7 +1876,8 @@ QUICNetVConnection::_update_peer_cid(const QUICConnectionId &new_cid) QUICConDebug("dcid: %s -> %s", old_cid_str, new_cid_str); } - this->_peer_quic_connection_id = new_cid; + this->_peer_old_quic_connection_id = this->_peer_quic_connection_id; + this->_peer_quic_connection_id = new_cid; this->_update_cids(); } @@ -1955,15 +1938,13 @@ QUICNetVConnection::_state_connection_established_migrate_connection(const QUICP QUICConnectionId dcid = p.destination_cid(); if (this->netvc_context == NET_VCONNECTION_IN) { - if (this->_remote_alt_cids.empty()) { + if (!this->_alt_con_manager->is_ready_to_migrate()) { // TODO: Should endpoint send connection error when remote endpoint doesn't send NEW_CONNECTION_ID frames before initiating // connection migration ? QUICConDebug("Ignore connection migration - remote endpoint initiated CM before sending NEW_CONNECTION_ID frames"); - return error; - } else { - QUICConDebug("Connection migration is initiated by remote"); } + QUICConDebug("Connection migration is initiated by remote"); } if (this->_alt_con_manager->migrate_to(dcid, this->_reset_token)) { @@ -1976,8 +1957,7 @@ QUICNetVConnection::_state_connection_established_migrate_connection(const QUICP con.setRemote(&(p.from().sa)); this->con.move(con); - this->_update_peer_cid(this->_remote_alt_cids.front()); - this->_remote_alt_cids.pop(); + this->_update_peer_cid(this->_alt_con_manager->migrate_to_alt_cid()); this->_validate_new_path(); } } else { @@ -2003,15 +1983,14 @@ QUICNetVConnection::_state_connection_established_initiate_connection_migration( std::shared_ptr remote_tp = this->_handshake_handler->remote_transport_parameters(); if (this->_connection_migration_initiated || remote_tp->contains(QUICTransportParameterId::DISABLE_MIGRATION) || - this->_remote_alt_cids.empty() || this->_alt_con_manager->will_generate_frame(QUICEncryptionLevel::ONE_RTT)) { + !this->_alt_con_manager->is_ready_to_migrate() || this->_alt_con_manager->will_generate_frame(QUICEncryptionLevel::ONE_RTT)) { return error; } QUICConDebug("Initiated connection migration"); this->_connection_migration_initiated = true; - this->_update_peer_cid(this->_remote_alt_cids.front()); - this->_remote_alt_cids.pop(); + this->_update_peer_cid(this->_alt_con_manager->migrate_to_alt_cid()); this->_validate_new_path(); @@ -2022,7 +2001,11 @@ void QUICNetVConnection::_handle_path_validation_timeout(Event *data) { this->_close_path_validation_timeout(data); - if (!this->_path_validator->is_validated()) { + if (this->_path_validator->is_validated()) { + QUICConDebug("Path validated"); + this->_alt_con_manager->drop_cid(this->_peer_old_quic_connection_id); + } else { + QUICConDebug("Path validation failed"); this->_switch_to_close_state(); } } diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 641e2e11737..8ca5018e022 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -29,81 +29,206 @@ 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) : _qc(qc), _ctable(ctable) +QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, + QUICConnectionId peer_initial_cid) + : _qc(qc), _ctable(ctable) { QUICConfig::scoped_config params; - this->_nids = params->num_alt_connection_ids(); - this->_alt_quic_connection_ids = static_cast(ats_malloc(sizeof(AltConnectionInfo) * this->_nids)); - this->_update_alt_connection_ids(-1); + // Sequence number of the initial CID is 0 + this->_alt_quic_connection_ids_remote.push_back({0, peer_initial_cid, {}, {true}}); + + // TODO If preferred_address was provided, sequence number of the provided CID is 1 + + if (this->_qc->direction() == NET_VCONNECTION_IN) { + this->_nids = params->num_alt_connection_ids(); + this->_alt_quic_connection_ids_local = static_cast(ats_malloc(sizeof(AltConnectionInfo) * this->_nids)); + this->_init_alt_connection_ids(); + } else { + this->_nids = 1; + this->_alt_quic_connection_ids_local = static_cast(ats_malloc(sizeof(AltConnectionInfo) * this->_nids)); + // If this is a client, new connection id will be generated on demand + } } QUICAltConnectionManager::~QUICAltConnectionManager() { - ats_free(this->_alt_quic_connection_ids); + ats_free(this->_alt_quic_connection_ids_local); +} + +std::vector +QUICAltConnectionManager::interests() +{ + return {QUICFrameType::NEW_CONNECTION_ID, QUICFrameType::RETIRE_CONNECTION_ID}; +} + +QUICConnectionErrorUPtr +QUICAltConnectionManager::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) +{ + QUICConnectionErrorUPtr error = nullptr; + + switch (frame.type()) { + case QUICFrameType::NEW_CONNECTION_ID: + error = this->_register_remote_connection_id(static_cast(frame)); + break; + case QUICFrameType::RETIRE_CONNECTION_ID: + error = this->_retire_remote_connection_id(static_cast(frame)); + break; + default: + QUICACMVDebug("Unexpected frame type: %02x", static_cast(frame.type())); + ink_assert(false); + break; + } + + return error; +} + +QUICAltConnectionManager::AltConnectionInfo +QUICAltConnectionManager::_generate_next_alt_con_info() +{ + QUICConfig::scoped_config params; + QUICConnectionId conn_id; + QUICStatelessResetToken token; + conn_id.randomize(); + token.generate(conn_id, params->server_id()); + AltConnectionInfo aci = {++this->_alt_quic_connection_id_seq_num, conn_id, token, {false}}; + + if (this->_qc->direction() == NET_VCONNECTION_IN) { + this->_ctable.insert(conn_id, this->_qc); + } + + 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); + } + + return aci; } void -QUICAltConnectionManager::_update_alt_connection_ids(int8_t chosen) +QUICAltConnectionManager::_init_alt_connection_ids() { - if (this->_nids == 0) { - // Connection migration is disabled - return; + for (int i = 0; i < this->_nids; ++i) { + this->_alt_quic_connection_ids_local[i] = this->_generate_next_alt_con_info(); } + this->_need_advertise = true; +} - if (chosen == -1) { - chosen = (this->_nids - 1) & 0xff; +bool +QUICAltConnectionManager::_update_alt_connection_id(uint64_t chosen_seq_num) +{ + for (int i = 0; i < this->_nids; ++i) { + if (_alt_quic_connection_ids_local[i].seq_num == chosen_seq_num) { + _alt_quic_connection_ids_local[i] = this->_generate_next_alt_con_info(); + this->_need_advertise = true; + return true; + } } - QUICConfig::scoped_config params; - int n = this->_nids; - int current = this->_alt_quic_connection_id_seq_num % n; - int delta = chosen - current; - int count = (n + delta) % n + 1; - - for (int i = 0; i < count; ++i) { - int index = (current + i) % n; - QUICConnectionId conn_id; - QUICStatelessResetToken token; - - conn_id.randomize(); - token.generate(conn_id, params->server_id()); - this->_alt_quic_connection_ids[index] = {this->_alt_quic_connection_id_seq_num + i, conn_id, token, false}; - if (this->_qc->direction() == NET_VCONNECTION_IN) { - this->_ctable.insert(conn_id, this->_qc); + return false; +} + +QUICConnectionErrorUPtr +QUICAltConnectionManager::_register_remote_connection_id(const QUICNewConnectionIdFrame &frame) +{ + QUICConnectionErrorUPtr error = nullptr; + + if (frame.connection_id() == QUICConnectionId::ZERO()) { + error = std::make_unique(QUICTransErrorCode::PROTOCOL_VIOLATION, "received zero-length cid", + QUICFrameType::NEW_CONNECTION_ID); + } else { + this->_alt_quic_connection_ids_remote.push_back( + {frame.sequence(), frame.connection_id(), frame.stateless_reset_token(), {false}}); + } + + return error; +} + +QUICConnectionErrorUPtr +QUICAltConnectionManager::_retire_remote_connection_id(const QUICRetireConnectionIdFrame &frame) +{ + QUICConnectionErrorUPtr error = nullptr; + + if (!this->_update_alt_connection_id(frame.seq_num())) { + error = std::make_unique(QUICTransErrorCode::PROTOCOL_VIOLATION, "received unused sequence number", + QUICFrameType::RETIRE_CONNECTION_ID); + } + return error; +} + +bool +QUICAltConnectionManager::is_ready_to_migrate() const +{ + if (this->_alt_quic_connection_ids_remote.empty()) { + return false; + } + + for (auto &info : this->_alt_quic_connection_ids_remote) { + if (!info.used) { + return true; } + } + return false; +} + +QUICConnectionId +QUICAltConnectionManager::migrate_to_alt_cid() +{ + if (this->_qc->direction() == NET_VCONNECTION_OUT) { + this->_init_alt_connection_ids(); + } - 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); + for (auto &info : this->_alt_quic_connection_ids_remote) { + if (info.used) { + continue; } + info.used = true; + return info.id; } - this->_alt_quic_connection_id_seq_num += count; - this->_need_advertise = true; + + ink_assert(!"Could not find CID available"); + return QUICConnectionId::ZERO(); } bool QUICAltConnectionManager::migrate_to(QUICConnectionId cid, QUICStatelessResetToken &new_reset_token) { for (unsigned int i = 0; i < this->_nids; ++i) { - AltConnectionInfo &info = this->_alt_quic_connection_ids[i]; + AltConnectionInfo &info = this->_alt_quic_connection_ids_local[i]; if (info.id == cid) { // Migrate connection - // TODO Unregister the old connection id (Should we wait for a while?) new_reset_token = info.token; - this->_update_alt_connection_ids(i); + + if (this->_qc->direction() == NET_VCONNECTION_IN) { + // Replace alt connection info with a new one for future use + this->_update_alt_connection_id(info.seq_num); + } + return true; } } return false; } +void +QUICAltConnectionManager::drop_cid(QUICConnectionId cid) +{ + for (auto it = this->_alt_quic_connection_ids_remote.begin(); it != this->_alt_quic_connection_ids_remote.end(); ++it) { + if (it->id == cid) { + QUICACMVDebug("Droppoing advertized CID seq# %" PRIu64, it->seq_num); + this->_retired_seq_nums.push(it->seq_num); + this->_alt_quic_connection_ids_remote.erase(it); + return; + } + } +} + void QUICAltConnectionManager::invalidate_alt_connections() { for (unsigned int i = 0; i < this->_nids; ++i) { - this->_ctable.erase(this->_alt_quic_connection_ids[i].id, this->_qc); + this->_ctable.erase(this->_alt_quic_connection_ids_local[i].id, this->_qc); } } @@ -114,7 +239,7 @@ QUICAltConnectionManager::will_generate_frame(QUICEncryptionLevel level) return false; } - return this->_need_advertise; + return this->_need_advertise || !this->_retired_seq_nums.empty(); } QUICFrameUPtr @@ -125,24 +250,34 @@ QUICAltConnectionManager::generate_frame(QUICEncryptionLevel level, uint64_t con return frame; } - int count = this->_nids; - for (int i = 0; i < count; ++i) { - if (!this->_alt_quic_connection_ids[i].advertised) { - frame = QUICFrameFactory::create_new_connection_id_frame( - this->_alt_quic_connection_ids[i].seq_num, this->_alt_quic_connection_ids[i].id, this->_alt_quic_connection_ids[i].token); + if (this->_need_advertise) { + int count = this->_nids; + for (int i = 0; i < count; ++i) { + if (!this->_alt_quic_connection_ids_local[i].advertised) { + frame = QUICFrameFactory::create_new_connection_id_frame(this->_alt_quic_connection_ids_local[i].seq_num, + this->_alt_quic_connection_ids_local[i].id, + this->_alt_quic_connection_ids_local[i].token); - if (frame && frame->size() > maximum_frame_size) { - // Cancel generating frame - frame = QUICFrameFactory::create_null_frame(); - } else { - this->_alt_quic_connection_ids[i].advertised = true; + if (frame && frame->size() > maximum_frame_size) { + // Cancel generating frame + frame = QUICFrameFactory::create_null_frame(); + } else { + this->_alt_quic_connection_ids_local[i].advertised = true; + } + + return frame; } + } + this->_need_advertise = false; + } + if (!this->_retired_seq_nums.empty()) { + if (auto s = this->_retired_seq_nums.front()) { + frame = QUICFrameFactory::create_retire_connection_id_frame(s); + this->_retired_seq_nums.pop(); return frame; } } - this->_need_advertise = false; - return frame; } diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index 1727a322db7..f25ada51c8f 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -24,40 +24,79 @@ #pragma once #include +#include + #include "QUICFrameGenerator.h" #include "QUICTypes.h" #include "QUICConnection.h" class QUICConnectionTable; -class QUICAltConnectionManager : public QUICFrameGenerator +class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenerator { public: - QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable); + QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, QUICConnectionId peer_initial_cid); ~QUICAltConnectionManager(); + + /** + * Check if AltConnectionManager has at least one CID advertised by the peer. + */ + bool is_ready_to_migrate() const; + + /** + * Prepare for new CID for the peer, and return one of CIDs advertised by the peer. + * New CID for the peer will be sent on next call for generate_frame() + */ + QUICConnectionId migrate_to_alt_cid(); + + /** + * Migrate to new CID + * + * cid need to match with one of alt CID that AltConnnectionManager prepared. + */ bool migrate_to(QUICConnectionId cid, QUICStatelessResetToken &new_reset_token); + + void drop_cid(QUICConnectionId cid); + + /** + * Invalidate all CIDs prepared + */ void invalidate_alt_connections(); + // QUICFrameHandler + virtual std::vector interests() override; + virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; + // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level); - QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size); + bool will_generate_frame(QUICEncryptionLevel level) override; + QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; private: class AltConnectionInfo { public: - int seq_num; + uint64_t seq_num; QUICConnectionId id; QUICStatelessResetToken token; - bool advertised; + union { + bool advertised; // For local info + bool used; // For remote info + }; }; QUICConnection *_qc = nullptr; QUICConnectionTable &_ctable; - AltConnectionInfo *_alt_quic_connection_ids; - uint8_t _nids = 0; - int8_t _alt_quic_connection_id_seq_num = 0; - bool _need_advertise = false; + AltConnectionInfo *_alt_quic_connection_ids_local; + std::vector _alt_quic_connection_ids_remote; + std::queue _retired_seq_nums; + uint8_t _nids = 0; + uint64_t _alt_quic_connection_id_seq_num = 0; + bool _need_advertise = false; + + AltConnectionInfo _generate_next_alt_con_info(); + void _init_alt_connection_ids(); + bool _update_alt_connection_id(uint64_t chosen_seq_num); - void _update_alt_connection_ids(int8_t chosen = -1); + QUICConnectionErrorUPtr _register_remote_connection_id(const QUICNewConnectionIdFrame &frame); + QUICConnectionErrorUPtr _retire_remote_connection_id(const QUICRetireConnectionIdFrame &frame); }; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 3e2db22063f..8d4494d3634 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2128,7 +2128,7 @@ 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 cid=0x%s", this->size(), cid_str); + return snprintf(msg, msg_len, "| NEW_CONNECTION_ID size=%zu seq=%" PRIu64 " cid=0x%s", this->size(), this->sequence(), cid_str); } uint64_t diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 476020198c7..dfc5e6b6f1e 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -34,7 +34,7 @@ static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; static constexpr char tag[] = "quic_handshake"; -static constexpr uint32_t TP_ERROR_LENGTH = 0x010000; +static constexpr uint32_t TP_ERROR_LENGTH = 0x010000; // static constexpr uint32_t TP_ERROR_VALUE = 0x020000; static constexpr uint32_t TP_ERROR_MUST_EXIST = 0x030000; static constexpr uint32_t TP_ERROR_MUST_NOT_EXIST = 0x040000; From 11f8b06119aef6e300e22c22db1deda7454a85e7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 24 Oct 2018 11:31:54 +0900 Subject: [PATCH 0900/1313] Add proxy.config.quic.max_ack_delay_in/out --- iocore/net/quic/QUICConfig.cc | 14 ++++++++++++++ iocore/net/quic/QUICConfig.h | 4 ++++ mgmt/RecordsConfig.cc | 4 ++++ 3 files changed, 22 insertions(+) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index fa953c53c8d..26310b81990 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -165,6 +165,8 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_initial_max_uni_streams_out, "proxy.config.quic.initial_max_uni_streams_out"); REC_EstablishStaticConfigInt32U(this->_ack_delay_exponent_in, "proxy.config.quic.ack_delay_exponent_in"); REC_EstablishStaticConfigInt32U(this->_ack_delay_exponent_out, "proxy.config.quic.ack_delay_exponent_out"); + REC_EstablishStaticConfigInt32U(this->_max_ack_delay_in, "proxy.config.quic.max_ack_delay_in"); + REC_EstablishStaticConfigInt32U(this->_max_ack_delay_out, "proxy.config.quic.max_ack_delay_out"); // Loss Detection REC_EstablishStaticConfigInt32U(this->_ld_max_tlps, "proxy.config.quic.loss_detection.max_tlps"); @@ -329,6 +331,18 @@ QUICConfigParams::ack_delay_exponent_out() const return this->_ack_delay_exponent_out; } +uint8_t +QUICConfigParams::max_ack_delay_in() const +{ + return this->_max_ack_delay_in; +} + +uint8_t +QUICConfigParams::max_ack_delay_out() const +{ + return this->_max_ack_delay_out; +} + const char * QUICConfigParams::server_supported_groups() const { diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index d689e848aa0..7987453d97e 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -65,6 +65,8 @@ class QUICConfigParams : public ConfigInfo uint16_t initial_max_uni_streams_out() const; uint8_t ack_delay_exponent_in() const; uint8_t ack_delay_exponent_out() const; + uint8_t max_ack_delay_in() const; + uint8_t max_ack_delay_out() const; // Loss Detection uint32_t ld_max_tlps() const; @@ -121,6 +123,8 @@ class QUICConfigParams : public ConfigInfo uint32_t _initial_max_uni_streams_out = 0; uint32_t _ack_delay_exponent_in = 0; uint32_t _ack_delay_exponent_out = 0; + uint32_t _max_ack_delay_in = 0; + uint32_t _max_ack_delay_out = 0; // [draft-11 recovery] 3.5.1. Constants of interest uint32_t _ld_max_tlps = 2; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 0d81bbeda44..062cd24e26b 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1384,6 +1384,10 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.ack_delay_exponent_out", RECD_INT, "3", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.max_ack_delay_in", RECD_INT, "25", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.max_ack_delay_out", RECD_INT, "25", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , // Constants of Loss Detection {RECT_CONFIG, "proxy.config.quic.loss_detection.max_tlps", RECD_INT, "2", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , From 10cce9ed3ff726c369a070c32a65312fb6668d0c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 2 Nov 2018 10:58:41 +0900 Subject: [PATCH 0901/1313] Fix build issues caused by merging master --- proxy/hq/HQClientSession.cc | 12 ++++++++++++ proxy/hq/HQClientSession.h | 2 ++ proxy/hq/QPACK.h | 4 ++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/proxy/hq/HQClientSession.cc b/proxy/hq/HQClientSession.cc index 29af2e045f0..b0c49a64fe3 100644 --- a/proxy/hq/HQClientSession.cc +++ b/proxy/hq/HQClientSession.cc @@ -128,6 +128,18 @@ HQClientSession::populate_protocol(std::string_view *result, int size) const return retval; } +void +HQClientSession::increment_current_active_client_connections_stat() +{ + // TODO Implement stats +} + +void +HQClientSession::decrement_current_active_client_connections_stat() +{ + // TODO Implement stats +} + void HQClientSession::add_transaction(HQClientTransaction *trans) { diff --git a/proxy/hq/HQClientSession.h b/proxy/hq/HQClientSession.h index ff4e4daa648..40578bc0a13 100644 --- a/proxy/hq/HQClientSession.h +++ b/proxy/hq/HQClientSession.h @@ -50,6 +50,8 @@ class HQClientSession : public ProxyClientSession const char *get_protocol_string() const override; void release(ProxyClientTransaction *trans) override; int populate_protocol(std::string_view *result, int size) const override; + void increment_current_active_client_connections_stat() override; + void decrement_current_active_client_connections_stat() override; // HQClientSession specific methods void add_transaction(HQClientTransaction *); diff --git a/proxy/hq/QPACK.h b/proxy/hq/QPACK.h index 3c97584515e..dc255408f3c 100644 --- a/proxy/hq/QPACK.h +++ b/proxy/hq/QPACK.h @@ -25,7 +25,7 @@ #include "I_EventSystem.h" #include "I_Event.h" -#include "tscore/IntrusiveDList.h" +#include "tscpp/util/IntrusiveDList.h" #include "MIME.h" #include "QUICApplication.h" @@ -246,7 +246,7 @@ class QPACK : public QUICApplication bool _invalid = false; - IntrusiveDList _blocked_list; + ts::IntrusiveDList _blocked_list; bool _add_to_blocked_list(DecodeRequest *decode_request); uint16_t _largest_known_received_index = 0; From fbd453272279cd59f18039d08612d4bfcf5f93f4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 2 Nov 2018 11:00:20 +0900 Subject: [PATCH 0902/1313] clang-format --- iocore/net/quic/test/test_QUICHandshakeProtocol.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 3da69fee8a2..7a4e1cd4cc4 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -402,12 +402,14 @@ TEST_CASE("QUICHandshakeProtocol") // ## Client -> Server client_pn_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); - server_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::INITIAL); + server_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, + QUICKeyPhase::INITIAL); CHECK(unprotected_pn_len == sizeof(expected)); CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); // ## Server -> Client server_pn_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); - client_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::INITIAL); + client_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, + QUICKeyPhase::INITIAL); CHECK(unprotected_pn_len == sizeof(expected)); CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); @@ -488,12 +490,14 @@ TEST_CASE("QUICHandshakeProtocol") // ## Client -> Server client_pn_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); - server_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); + server_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, + QUICKeyPhase::PHASE_0); CHECK(unprotected_pn_len == sizeof(expected)); CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); // ## Server -> Client server_pn_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); - client_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); + client_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, + QUICKeyPhase::PHASE_0); CHECK(unprotected_pn_len == sizeof(expected)); CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); From e8a450606c19a08cc2ed5d1b0125777b2eabd48e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 2 Nov 2018 17:37:03 +0900 Subject: [PATCH 0903/1313] Improve a debug log --- iocore/net/quic/QUICAltConnectionManager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 8ca5018e022..4346b2fe5cf 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -216,7 +216,7 @@ QUICAltConnectionManager::drop_cid(QUICConnectionId cid) { for (auto it = this->_alt_quic_connection_ids_remote.begin(); it != this->_alt_quic_connection_ids_remote.end(); ++it) { if (it->id == cid) { - QUICACMVDebug("Droppoing advertized CID seq# %" PRIu64, it->seq_num); + QUICACMVDebug("Dropping advertized CID %" PRIx32 " seq# %" PRIu64, it->id.h32(), it->seq_num); this->_retired_seq_nums.push(it->seq_num); this->_alt_quic_connection_ids_remote.erase(it); return; From 6eb6b99821089309837f5d12af66b93dc6be15e3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 2 Nov 2018 17:38:09 +0900 Subject: [PATCH 0904/1313] Fix a bug in connection migration --- iocore/net/quic/QUICAltConnectionManager.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 4346b2fe5cf..f2760b77bf5 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -126,6 +126,11 @@ 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; + } + return false; } @@ -199,12 +204,6 @@ QUICAltConnectionManager::migrate_to(QUICConnectionId cid, QUICStatelessResetTok if (info.id == cid) { // Migrate connection new_reset_token = info.token; - - if (this->_qc->direction() == NET_VCONNECTION_IN) { - // Replace alt connection info with a new one for future use - this->_update_alt_connection_id(info.seq_num); - } - return true; } } From 18e9920793909fc7036165766ce95456f1ce68d8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 6 Nov 2018 16:10:30 +0900 Subject: [PATCH 0905/1313] Fix a unit test for QUICFrame --- iocore/net/quic/test/test_QUICFrame.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 58ca5641154..6b2edc2a69d 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -575,7 +575,7 @@ TEST_CASE("Store Ack Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x0d, // Type + 0x1a, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x02, // Ack Block Count From 3bb2ebee9a5707c5679cf1d63fc1555925fe870b Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 3 Nov 2018 11:14:33 +0800 Subject: [PATCH 0906/1313] QUIC: introduce QUICFrameReactor to react the frame sent event and lost event --- iocore/net/P_QUICNetVConnection.h | 8 +-- iocore/net/QUICNetVConnection.cc | 45 ++++++++++------- iocore/net/quic/QUICCongestionController.cc | 2 +- iocore/net/quic/QUICFrame.cc | 13 +++++ iocore/net/quic/QUICFrame.h | 11 ++-- iocore/net/quic/QUICFrameGenerator.h | 9 ++++ iocore/net/quic/QUICLossDetector.cc | 32 +++++++++--- iocore/net/quic/QUICLossDetector.h | 4 +- iocore/net/quic/QUICPacket.cc | 56 +++++++++++++++++---- iocore/net/quic/QUICPacket.h | 32 +++++++++--- 10 files changed, 162 insertions(+), 50 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 71cc078ae2f..8349c338fc3 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -296,12 +296,14 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub Event *_path_validation_timeout = nullptr; uint64_t _maximum_stream_frame_data_size(); - void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr frame); + void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr &frame, + std::vector &frames); QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size); void _packetize_closing_frame(); QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, bool probing, - QUICPacketType type = QUICPacketType::UNINITIALIZED); - QUICPacketUPtr _build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing); + std::vector &frames, QUICPacketType type = QUICPacketType::UNINITIALIZED); + QUICPacketUPtr _build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing, + std::vector &frames); QUICConnectionErrorUPtr _recv_and_ack(QUICPacket &packet, bool *has_non_probing_frame = nullptr); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6bc25ef1f8e..2cc177a8c0b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1185,7 +1185,8 @@ QUICNetVConnection::_state_closing_send_packet() } void -QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr frame) +QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr &frame, + std::vector &frames) { size_t l = 0; frame->store(buf.get() + offset, &l, max_frame_size); @@ -1201,6 +1202,8 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t & frame->debug_msg(msg, sizeof(msg)); QUICConDebug("[TX] %s", msg); } + + frames.push_back(std::move(frame)); } QUICPacketUPtr @@ -1226,13 +1229,14 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); + std::vector frames; // CRYPTO frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); while (frame) { ++frame_count; probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, std::move(frame)); + this->_store_frame(buf, len, max_frame_size, frame, frames); frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); } @@ -1241,7 +1245,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa if (frame) { ++frame_count; probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, std::move(frame)); + this->_store_frame(buf, len, max_frame_size, frame, frames); } // NEW_CONNECTION_ID @@ -1250,7 +1254,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa while (frame) { ++frame_count; probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, std::move(frame)); + this->_store_frame(buf, len, max_frame_size, frame, frames); frame = this->_alt_con_manager->generate_frame(level, UINT16_MAX, max_frame_size); } @@ -1261,7 +1265,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa while (frame) { ++frame_count; probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, std::move(frame)); + this->_store_frame(buf, len, max_frame_size, frame, frames); frame = this->_packet_retransmitter.generate_frame(level, UINT16_MAX, max_frame_size); } @@ -1271,7 +1275,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa if (frame) { ++frame_count; probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, std::move(frame)); + this->_store_frame(buf, len, max_frame_size, frame, frames); } // BLOCKED @@ -1280,7 +1284,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa if (frame) { ++frame_count; probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, std::move(frame)); + this->_store_frame(buf, len, max_frame_size, frame, frames); } } @@ -1296,7 +1300,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa this->_remote_flow_controller->current_limit()); ink_assert(ret == 0); } - this->_store_frame(buf, len, max_frame_size, std::move(frame)); + this->_store_frame(buf, len, max_frame_size, frame, frames); if (++this->_stream_frames_sent % MAX_CONSECUTIVE_STREAMS == 0) { break; @@ -1322,7 +1326,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } ++frame_count; probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, std::move(frame)); + this->_store_frame(buf, len, max_frame_size, frame, frames); } // Schedule a packet @@ -1343,7 +1347,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } // Packet is retransmittable if it's not ack only packet - packet = this->_build_packet(level, std::move(buf), len, !ack_only, probing); + packet = this->_build_packet(level, std::move(buf), len, !ack_only, probing, frames); } return packet; @@ -1371,11 +1375,12 @@ QUICNetVConnection::_packetize_closing_frame() size_t len = 0; uint64_t max_frame_size = static_cast(max_size); - this->_store_frame(buf, len, max_frame_size, std::move(frame)); + std::vector frames; + this->_store_frame(buf, len, 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, std::move(buf), len, false, false); + this->_the_final_packet = this->_build_packet(level, std::move(buf), len, false, false, frames); } QUICConnectionErrorUPtr @@ -1421,13 +1426,15 @@ QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_fram } QUICPacketUPtr -QUICNetVConnection::_build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing) +QUICNetVConnection::_build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing, + std::vector &frames) { - return this->_build_packet(std::move(buf), len, retransmittable, probing, QUICTypeUtil::packet_type(level)); + return this->_build_packet(std::move(buf), len, retransmittable, probing, frames, QUICTypeUtil::packet_type(level)); } QUICPacketUPtr -QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, bool probing, QUICPacketType type) +QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, bool probing, + std::vector &frames, QUICPacketType type) { QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); @@ -1450,25 +1457,25 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi packet = this->_packet_factory.create_initial_packet( dcid, this->_quic_connection_id, this->largest_acked_packet_number(QUICEncryptionLevel::INITIAL), std::move(buf), len, - retransmittable, probing, std::move(token), token_len); + retransmittable, probing, frames, 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, this->largest_acked_packet_number(QUICEncryptionLevel::HANDSHAKE), - std::move(buf), len, retransmittable, probing); + std::move(buf), len, retransmittable, probing, frames); break; } case QUICPacketType::ZERO_RTT_PROTECTED: { packet = this->_packet_factory.create_zero_rtt_packet(this->_original_quic_connection_id, this->_quic_connection_id, this->largest_acked_packet_number(QUICEncryptionLevel::ZERO_RTT), - std::move(buf), len, retransmittable, probing); + std::move(buf), len, retransmittable, probing, frames); 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, retransmittable, probing); + std::move(buf), len, retransmittable, probing, frames); break; } default: diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 03773b383b6..2cd1ea5f4bb 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -86,7 +86,7 @@ QUICCongestionController::on_packet_acked(const PacketInfo &acked_packet) } void -QUICCongestionController::on_packets_lost(const std::map &lost_packets) +QUICCongestionController::on_packets_lost(const std::map &lost_packets) { if (lost_packets.empty()) { return; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 8d4494d3634..18260719b78 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -28,6 +28,7 @@ #include "QUICStream.h" #include "QUICIntUtil.h" #include "QUICDebugNames.h" +#include "QUICPacket.h" ClassAllocator quicStreamFrameAllocator("quicStreamFrameAllocator"); ClassAllocator quicCryptoFrameAllocator("quicCryptoFrameAllocator"); @@ -63,6 +64,18 @@ QUICFrame::is_probing_frame() const return false; } +void +QUICFrame::set_owner(QUICFrameGenerator *owner) +{ + this->_owner = owner; +} + +QUICFrameGenerator * +QUICFrame::generated_by() const +{ + return this->_owner; +} + QUICFrameType QUICFrame::type(const uint8_t *buf) { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index c0c1da7fddc..164f092cde9 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -24,16 +24,18 @@ #pragma once #include +#include "tscore/Allocator.h" #include "tscore/List.h" #include #include #include "QUICTypes.h" -#include "QUICPacket.h" class QUICFrame; class QUICStreamFrame; class QUICCryptoFrame; +class QUICPacket; +class QUICFrameGenerator; using QUICFrameDeleterFunc = void (*)(QUICFrame *p); using QUICFrameUPtr = std::unique_ptr; @@ -59,12 +61,15 @@ class QUICFrame virtual void reset(const uint8_t *buf, size_t len); virtual QUICFrame *split(size_t size); virtual int debug_msg(char *msg, size_t msg_len) const; + virtual void set_owner(QUICFrameGenerator *owner); + virtual QUICFrameGenerator *generated_by() const; LINK(QUICFrame, link); protected: QUICFrame() {} - const uint8_t *_buf = nullptr; - size_t _len = 0; + const uint8_t *_buf = nullptr; + size_t _len = 0; + QUICFrameGenerator *_owner = nullptr; }; // diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index 218b1572b38..e24e742dafe 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -32,6 +32,15 @@ class QUICFrameGenerator virtual bool will_generate_frame(QUICEncryptionLevel level) = 0; virtual QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) = 0; + virtual void + on_frame_acked(QUICFrameUPtr &frame, QUICEncryptionLevel level) + { + } + virtual void + on_frame_lost(QUICFrameUPtr &frame, QUICEncryptionLevel level) + { + } + protected: virtual std::vector _encryption_level_filter() diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index a6ef2d2007b..c03c6bcbc3b 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -28,6 +28,7 @@ #include "QUICConfig.h" #include "QUICEvents.h" #include "QUICDebugNames.h" +#include "QUICFrameGenerator.h" #define QUICLDDebug(fmt, ...) \ Debug("quic_loss_detector", "[%s] [%s] " fmt, this->_info->cids().data(), QUICDebugNames::pn_space(this->_pn_space_index), \ @@ -302,6 +303,16 @@ QUICLossDetector::_on_packet_acked(const PacketInfo &acked_packet) this->_handshake_count = 0; this->_tlp_count = 0; this->_rto_count = 0; + + for (QUICFrameUPtr &frame : acked_packet.packet->frames()) { + auto reactor = frame->generated_by(); + if (reactor == nullptr) { + continue; + } + + reactor->on_frame_acked(frame, QUICTypeUtil::encryption_level(acked_packet.packet->type())); + } + this->_remove_from_sent_packet_list(acked_packet.packet_number); } @@ -424,7 +435,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); this->_loss_time = 0; - std::map lost_packets; + std::map lost_packets; double delay_until_lost = INFINITY; if (this->_k_using_time_loss_detection) { @@ -472,12 +483,12 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num // lets it decide whether to retransmit immediately. if (!lost_packets.empty()) { this->_cc->on_packets_lost(lost_packets); - for (auto &lost_packet : lost_packets) { + for (auto lost_packet : lost_packets) { // -- ADDITIONAL CODE -- // Not sure how we can get feedback from congestion control and when we should retransmit the lost packets but we need to send // them somewhere. // I couldn't find the place so just send them here for now. - this->_retransmit_lost_packet(*lost_packet.second->packet); + this->_retransmit_lost_packet(lost_packet.second->packet); // -- END OF ADDITIONAL CODE -- // -- ADDITIONAL CODE -- this->_remove_from_sent_packet_list(lost_packet.first); @@ -494,7 +505,7 @@ QUICLossDetector::_retransmit_all_unacked_handshake_data() SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); std::set retransmitted_handshake_packets; - std::map lost_packets; + std::map lost_packets; for (auto &info : this->_sent_packets) { retransmitted_handshake_packets.insert(info.first); @@ -538,11 +549,20 @@ QUICLossDetector::_send_two_packets() // ===== Functions below are helper functions ===== void -QUICLossDetector::_retransmit_lost_packet(const QUICPacket &packet) +QUICLossDetector::_retransmit_lost_packet(QUICPacketUPtr &packet) { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - this->_transmitter->retransmit_packet(packet); + + for (QUICFrameUPtr &frame : packet->frames()) { + auto reactor = frame->generated_by(); + if (reactor == nullptr) { + continue; + } + + reactor->on_frame_lost(frame, QUICTypeUtil::encryption_level(packet->type())); + } + this->_transmitter->retransmit_packet(*packet); } std::set diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 7ac4d3328ca..5fa0550a70b 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -74,7 +74,7 @@ class QUICCongestionController virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); void on_packet_acked(const PacketInfo &acked_packet); - virtual void on_packets_lost(const std::map &packets); + virtual void on_packets_lost(const std::map &packets); void on_retransmission_timeout_verified(); bool check_credit() const; uint32_t open_window() const; @@ -184,7 +184,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _detect_lost_packets(QUICPacketNumber largest_acked); void _set_loss_detection_alarm(); void _on_loss_detection_alarm(); - void _retransmit_lost_packet(const QUICPacket &packet); + void _retransmit_lost_packet(QUICPacketUPtr &packet); std::set _determine_newly_acked_packets(const QUICAckFrame &ack_frame); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index d369f74add8..1c853752381 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -787,6 +787,20 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const *len += n; } +// +// QUICTrackablePacket +// +QUICTrackablePacket::QUICTrackablePacket(std::vector &frames) +{ + this->_frames = std::move(frames); +} + +std::vector & +QUICTrackablePacket::frames() +{ + return this->_frames; +} + // // QUICPacket // @@ -800,6 +814,14 @@ QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size this->_payload_size = payload_len; } +QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, std::vector &frames) + : QUICTrackablePacket(frames) +{ + this->_header = std::move(header); + this->_payload = std::move(payload); + this->_payload_size = payload_len; +} + QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing) { this->_header = std::move(header); @@ -809,6 +831,17 @@ QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size this->_is_probing_packet = probing; } +QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing, + std::vector &frames) + : QUICTrackablePacket(frames) +{ + this->_header = std::move(header); + this->_payload = std::move(payload); + this->_payload_size = payload_len; + this->_is_retransmittable = retransmittable; + this->_is_probing_packet = probing; +} + QUICPacket::~QUICPacket() { this->_header = nullptr; @@ -1212,14 +1245,15 @@ QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUIC 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, ats_unique_buf token, size_t token_len) + bool retransmittable, bool probing, std::vector &frames, + ats_unique_buf token, size_t token_len) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); QUICPacketNumber pn = this->_packet_number_generator[index].next(); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, destination_cid, source_cid, pn, base_packet_number, this->_version, std::move(payload), len, std::move(token), token_len); - return this->_create_encrypted_packet(std::move(header), retransmittable, probing); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); } QUICPacketUPtr @@ -1234,39 +1268,40 @@ QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICCon 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 retransmittable, bool probing, std::vector &frames) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::HANDSHAKE); QUICPacketNumber pn = this->_packet_number_generator[index].next(); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, QUICKeyPhase::HANDSHAKE, destination_cid, source_cid, pn, base_packet_number, this->_version, std::move(payload), len); - return this->_create_encrypted_packet(std::move(header), retransmittable, probing); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); } 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) + bool retransmittable, bool probing, std::vector &frames) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ZERO_RTT); QUICPacketNumber pn = this->_packet_number_generator[index].next(); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::ZERO_RTT_PROTECTED, QUICKeyPhase::ZERO_RTT, destination_cid, source_cid, pn, base_packet_number, this->_version, std::move(payload), len); - return this->_create_encrypted_packet(std::move(header), retransmittable, probing); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); } QUICPacketUPtr QUICPacketFactory::create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable, bool probing) + ats_unique_buf payload, size_t len, bool retransmittable, bool probing, + std::vector &frames) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ONE_RTT); QUICPacketNumber pn = this->_packet_number_generator[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); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); } QUICPacketUPtr @@ -1306,7 +1341,8 @@ QUICPacketFactory::_create_unprotected_packet(QUICPacketHeaderUPtr header) } QUICPacketUPtr -QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing) +QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing, + std::vector &frame) { // TODO: use pmtu of UnixNetVConnection size_t max_cipher_txt_len = 2048; @@ -1322,7 +1358,7 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool re if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable, probing); + new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable, probing, frame); } else { QUICDebug(dcid, scid, "Failed to encrypt a packet"); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 19408e7270b..6707113a759 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -32,6 +32,7 @@ #include "QUICTypes.h" #include "QUICHandshakeProtocol.h" +#include "QUICFrame.h" #define QUIC_FIELD_OFFSET_CONNECTION_ID 1 #define QUIC_FIELD_OFFSET_PACKET_NUMBER 4 @@ -49,6 +50,18 @@ extern ClassAllocator quicPacketShortHeaderAllocator; using QUICPacketHeaderDeleterFunc = void (*)(QUICPacketHeader *p); using QUICPacketHeaderUPtr = std::unique_ptr; +class QUICTrackablePacket +{ +public: + virtual ~QUICTrackablePacket() {} + std::vector &frames(); + +protected: + QUICTrackablePacket() {} + QUICTrackablePacket(std::vector &frames); + std::vector _frames; +}; + class QUICPacketHeader { public: @@ -307,7 +320,7 @@ class QUICPacketHeaderDeleter } }; -class QUICPacket +class QUICPacket : public QUICTrackablePacket { public: QUICPacket(); @@ -320,6 +333,8 @@ class QUICPacket */ QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len); + QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, std::vector &frames); + /* * Creates a QUICPacket with a QUICPacketHeader, a buffer that contains payload and a flag that indicates whether the packet is * retransmittable @@ -329,6 +344,9 @@ class QUICPacket */ QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing); + QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing, + std::vector &frames); + ~QUICPacket(); const IpEndpoint &from() const; @@ -425,17 +443,18 @@ class QUICPacketFactory QUICPacketCreationResult &result); QUICPacketUPtr 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 retransmittable, bool probing, std::vector &frame, ats_unique_buf token = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }), 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, - bool retransmittable, bool probing); + bool retransmittable, bool probing, std::vector &frame); QUICPacketUPtr 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); + bool retransmittable, bool probing, std::vector &frame); QUICPacketUPtr create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable, bool probing); + ats_unique_buf payload, size_t len, bool retransmittable, bool probing, + std::vector &frame); void set_version(QUICVersion negotiated_version); // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICCryptoInfoProvider or somethign instead. @@ -452,5 +471,6 @@ class QUICPacketFactory QUICPacketNumberGenerator _packet_number_generator[3]; static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeaderUPtr header); - QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing); + QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing, + std::vector &frame); }; From 1c718c319e7a59b9bb75093ad9663004aa22b0a1 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 6 Nov 2018 11:58:51 +0800 Subject: [PATCH 0907/1313] QUIC: Move set_owner to QUICFrame default constructor --- iocore/net/quic/QUICFrame.cc | 137 +++++++++++++++++------------------ iocore/net/quic/QUICFrame.h | 121 +++++++++++++++---------------- 2 files changed, 127 insertions(+), 131 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 18260719b78..fa77b9d666c 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -64,12 +64,6 @@ QUICFrame::is_probing_frame() const return false; } -void -QUICFrame::set_owner(QUICFrameGenerator *owner) -{ - this->_owner = owner; -} - QUICFrameGenerator * QUICFrame::generated_by() const { @@ -113,7 +107,7 @@ QUICFrame::split(size_t size) // STREAM Frame // -QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last) +QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, QUICFrameGenerator *owner) : QUICFrame(owner) { this->_data = std::move(data); this->_data_len = data_len; @@ -155,7 +149,7 @@ QUICStreamFrame::split(size_t size) this->reset(nullptr, 0); QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin); + new (frame) QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin, this->_owner); return frame; } @@ -164,7 +158,7 @@ QUICFrameUPtr QUICStreamFrame::clone() const { return QUICFrameFactory::create_stream_frame(this->data(), this->data_length(), this->stream_id(), this->offset(), - this->has_fin_flag()); + this->has_fin_flag(), this->_owner); } QUICFrameType @@ -406,7 +400,7 @@ QUICStreamFrame::_get_length_field_len() const // CRYPTO frame // -QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffset offset) +QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffset offset, QUICFrameGenerator *owner) : QUICFrame(owner) { this->_data = std::move(data); this->_data_len = data_len; @@ -579,7 +573,7 @@ QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) this->reset(buf, len); } -QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block) +QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameGenerator *owner) : QUICFrame(owner) { this->_largest_acknowledged = largest_acknowledged; this->_ack_delay = ack_delay; @@ -1084,8 +1078,8 @@ QUICAckFrame::EcnSection::ecn_ce_count() const // RST_STREAM frame // -QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset) - : _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset) +QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameGenerator *owner) + : QUICFrame(owner), _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset) { } @@ -1288,8 +1282,8 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len, size_t limit) const // CONNECTION_CLOSE frame // QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, - const char *reason_phrase) - : _error_code(error_code), _frame_type(frame_type), _reason_phrase_length(reason_phrase_length), _reason_phrase(reason_phrase) + const char *reason_phrase, QUICFrameGenerator *owner) + : QUICFrame(owner), _error_code(error_code), _frame_type(frame_type), _reason_phrase_length(reason_phrase_length), _reason_phrase(reason_phrase) { } @@ -1297,7 +1291,7 @@ QUICFrameUPtr QUICConnectionCloseFrame::clone() const { return QUICFrameFactory::create_connection_close_frame(this->error_code(), this->frame_type(), this->reason_phrase_length(), - this->reason_phrase()); + this->reason_phrase(), this->_owner); } QUICFrameType @@ -1476,7 +1470,7 @@ QUICConnectionCloseFrame::_get_reason_phrase_field_offset() const // APPLICATION_CLOSE frame // QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, - const char *reason_phrase) + const char *reason_phrase, QUICFrameGenerator *owner) : QUICFrame(owner) { this->_error_code = error_code; this->_reason_phrase_length = reason_phrase_length; @@ -1607,7 +1601,7 @@ QUICApplicationCloseFrame::_get_reason_phrase_field_offset() const // // MAX_DATA frame // -QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data) +QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, QUICFrameGenerator *owner) : QUICFrame(owner) { this->_maximum_data = maximum_data; } @@ -1683,7 +1677,7 @@ QUICMaxDataFrame::_get_max_data_field_length() const // // MAX_STREAM_DATA // -QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data) +QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameGenerator *owner) : QUICFrame(owner) { this->_stream_id = stream_id; this->_maximum_stream_data = maximum_stream_data; @@ -1792,7 +1786,7 @@ QUICMaxStreamDataFrame::_get_max_stream_data_field_length() const // // MAX_STREAM_ID // -QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id) +QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICFrameGenerator *owner) : QUICFrame(owner) { this->_maximum_stream_id = maximum_stream_id; } @@ -2205,8 +2199,8 @@ QUICNewConnectionIdFrame::_get_connection_id_field_offset() const // STOP_SENDING frame // -QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code) - : _stream_id(stream_id), _error_code(error_code) +QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameGenerator *owner) + : QUICFrame(owner), _stream_id(stream_id), _error_code(error_code) { } @@ -2420,7 +2414,10 @@ QUICPathResponseFrame::_data_offset() const QUICFrameUPtr QUICNewTokenFrame::clone() const { - return QUICFrameFactory::create_new_token_frame(this->token(), this->token_length()); + ats_unique_buf buf = ats_unique_malloc(this->token_length()); + memcpy(buf.get(), this->token(), this->token_length()); + + return QUICFrameFactory::create_new_token_frame(std::move(buf), this->token_length(), this->_owner); } QUICFrameType @@ -2584,7 +2581,7 @@ QUICRetireConnectionIdFrame::_get_seq_num_field_length() const // QUICRetransmissionFrame // QUICRetransmissionFrame::QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet) - : _packet_type(original_packet.type()) + : QUICFrame(original_frame->generated_by()), _packet_type(original_packet.type()) { this->_frame = std::move(original_frame); } @@ -2767,24 +2764,24 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) } QUICStreamFrameUPtr -QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last) +QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, QUICFrameGenerator *owner) { ats_unique_buf buf = ats_unique_malloc(data_len); memcpy(buf.get(), data, data_len); QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last); + new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last, owner); return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); } QUICCryptoFrameUPtr -QUICFrameFactory::create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset) +QUICFrameFactory::create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, QUICFrameGenerator *owner) { ats_unique_buf buf = ats_unique_malloc(data_len); memcpy(buf.get(), data, data_len); QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); - new (frame) QUICCryptoFrame(std::move(buf), data_len, offset); + new (frame) QUICCryptoFrame(std::move(buf), data_len, offset, owner); return QUICCryptoFrameUPtr(frame, &QUICFrameDeleter::delete_crypto_frame); } @@ -2800,175 +2797,175 @@ QUICFrameFactory::split_frame(QUICFrame *frame, size_t size) } std::unique_ptr -QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block) +QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameGenerator *owner) { QUICAckFrame *frame = quicAckFrameAllocator.alloc(); - new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block); + new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_ack_frame); } std::unique_ptr QUICFrameFactory::create_connection_close_frame(uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length, - const char *reason_phrase) + const char *reason_phrase, QUICFrameGenerator *owner) { QUICConnectionCloseFrame *frame = quicConnectionCloseFrameAllocator.alloc(); - new (frame) QUICConnectionCloseFrame(error_code, frame_type, reason_phrase_length, reason_phrase); + new (frame) QUICConnectionCloseFrame(error_code, frame_type, reason_phrase_length, reason_phrase, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); } std::unique_ptr -QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error) +QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error, QUICFrameGenerator *owner) { ink_assert(error->cls == QUICErrorClass::TRANSPORT); if (error->msg) { - return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type(), strlen(error->msg), error->msg); + return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type(), strlen(error->msg), error->msg, owner); } else { - return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type()); + return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type(), 0, nullptr, owner); } } std::unique_ptr QUICFrameFactory::create_application_close_frame(QUICAppErrorCode error_code, uint16_t reason_phrase_length, - const char *reason_phrase) + const char *reason_phrase, QUICFrameGenerator *owner) { QUICApplicationCloseFrame *frame = quicApplicationCloseFrameAllocator.alloc(); - new (frame) QUICApplicationCloseFrame(error_code, reason_phrase_length, reason_phrase); + new (frame) QUICApplicationCloseFrame(error_code, reason_phrase_length, reason_phrase, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); } std::unique_ptr -QUICFrameFactory::create_application_close_frame(QUICConnectionErrorUPtr error) +QUICFrameFactory::create_application_close_frame(QUICConnectionErrorUPtr error, QUICFrameGenerator *owner) { ink_assert(error->cls == QUICErrorClass::APPLICATION); if (error->msg) { - return QUICFrameFactory::create_application_close_frame(error->code, strlen(error->msg), error->msg); + return QUICFrameFactory::create_application_close_frame(error->code, strlen(error->msg), error->msg, owner); } else { - return QUICFrameFactory::create_application_close_frame(error->code); + return QUICFrameFactory::create_application_close_frame(error->code, 0, nullptr, owner); } } std::unique_ptr -QUICFrameFactory::create_max_data_frame(uint64_t maximum_data) +QUICFrameFactory::create_max_data_frame(uint64_t maximum_data, QUICFrameGenerator *owner) { QUICMaxDataFrame *frame = quicMaxDataFrameAllocator.alloc(); - new (frame) QUICMaxDataFrame(maximum_data); + new (frame) QUICMaxDataFrame(maximum_data, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_data_frame); } std::unique_ptr -QUICFrameFactory::create_max_stream_data_frame(QUICStreamId stream_id, uint64_t maximum_data) +QUICFrameFactory::create_max_stream_data_frame(QUICStreamId stream_id, uint64_t maximum_data, QUICFrameGenerator *owner) { QUICMaxStreamDataFrame *frame = quicMaxStreamDataFrameAllocator.alloc(); - new (frame) QUICMaxStreamDataFrame(stream_id, maximum_data); + new (frame) QUICMaxStreamDataFrame(stream_id, maximum_data, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); } std::unique_ptr -QUICFrameFactory::create_max_stream_id_frame(QUICStreamId maximum_stream_id) +QUICFrameFactory::create_max_stream_id_frame(QUICStreamId maximum_stream_id, QUICFrameGenerator *owner) { QUICMaxStreamIdFrame *frame = quicMaxStreamIdFrameAllocator.alloc(); - new (frame) QUICMaxStreamIdFrame(maximum_stream_id); + new (frame) QUICMaxStreamIdFrame(maximum_stream_id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_id_frame); } std::unique_ptr -QUICFrameFactory::create_ping_frame() +QUICFrameFactory::create_ping_frame(QUICFrameGenerator *owner) { QUICPingFrame *frame = quicPingFrameAllocator.alloc(); - new (frame) QUICPingFrame(); + new (frame) QUICPingFrame(owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_ping_frame); } std::unique_ptr -QUICFrameFactory::create_path_challenge_frame(const uint8_t *data) +QUICFrameFactory::create_path_challenge_frame(const uint8_t *data, QUICFrameGenerator *owner) { ats_unique_buf buf = ats_unique_malloc(QUICPathChallengeFrame::DATA_LEN); memcpy(buf.get(), data, QUICPathChallengeFrame::DATA_LEN); QUICPathChallengeFrame *frame = quicPathChallengeFrameAllocator.alloc(); - new (frame) QUICPathChallengeFrame(std::move(buf)); + new (frame) QUICPathChallengeFrame(std::move(buf), owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_challenge_frame); } std::unique_ptr -QUICFrameFactory::create_path_response_frame(const uint8_t *data) +QUICFrameFactory::create_path_response_frame(const uint8_t *data, QUICFrameGenerator *owner) { ats_unique_buf buf = ats_unique_malloc(QUICPathResponseFrame::DATA_LEN); memcpy(buf.get(), data, QUICPathResponseFrame::DATA_LEN); QUICPathResponseFrame *frame = quicPathResponseFrameAllocator.alloc(); - new (frame) QUICPathResponseFrame(std::move(buf)); + new (frame) QUICPathResponseFrame(std::move(buf), owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_response_frame); } std::unique_ptr -QUICFrameFactory::create_blocked_frame(QUICOffset offset) +QUICFrameFactory::create_blocked_frame(QUICOffset offset, QUICFrameGenerator *owner) { QUICBlockedFrame *frame = quicBlockedFrameAllocator.alloc(); - new (frame) QUICBlockedFrame(offset); + new (frame) QUICBlockedFrame(offset, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_blocked_frame); } std::unique_ptr -QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id, QUICOffset offset) +QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id, QUICOffset offset, QUICFrameGenerator *owner) { QUICStreamBlockedFrame *frame = quicStreamBlockedFrameAllocator.alloc(); - new (frame) QUICStreamBlockedFrame(stream_id, offset); + new (frame) QUICStreamBlockedFrame(stream_id, offset, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); } std::unique_ptr -QUICFrameFactory::create_stream_id_blocked_frame(QUICStreamId stream_id) +QUICFrameFactory::create_stream_id_blocked_frame(QUICStreamId stream_id, QUICFrameGenerator *owner) { QUICStreamIdBlockedFrame *frame = quicStreamIdBlockedFrameAllocator.alloc(); - new (frame) QUICStreamIdBlockedFrame(stream_id); + new (frame) QUICStreamIdBlockedFrame(stream_id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_id_blocked_frame); } std::unique_ptr -QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset) +QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameGenerator *owner) { QUICRstStreamFrame *frame = quicRstStreamFrameAllocator.alloc(); - new (frame) QUICRstStreamFrame(stream_id, error_code, final_offset); + new (frame) QUICRstStreamFrame(stream_id, error_code, final_offset, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_rst_stream_frame); } std::unique_ptr -QUICFrameFactory::create_rst_stream_frame(QUICStreamErrorUPtr error) +QUICFrameFactory::create_rst_stream_frame(QUICStreamErrorUPtr error, QUICFrameGenerator *owner) { - return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->code, error->stream->final_offset()); + return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->code, error->stream->final_offset(), owner); } std::unique_ptr -QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICAppErrorCode error_code) +QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameGenerator *owner) { QUICStopSendingFrame *frame = quicStopSendingFrameAllocator.alloc(); - new (frame) QUICStopSendingFrame(stream_id, error_code); + new (frame) QUICStopSendingFrame(stream_id, error_code, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_stop_sending_frame); } std::unique_ptr QUICFrameFactory::create_new_connection_id_frame(uint32_t sequence, QUICConnectionId connectoin_id, - QUICStatelessResetToken stateless_reset_token) + QUICStatelessResetToken stateless_reset_token, QUICFrameGenerator *owner) { QUICNewConnectionIdFrame *frame = quicNewConnectionIdFrameAllocator.alloc(); - new (frame) QUICNewConnectionIdFrame(sequence, connectoin_id, stateless_reset_token); + new (frame) QUICNewConnectionIdFrame(sequence, connectoin_id, stateless_reset_token, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_connection_id_frame); } std::unique_ptr -QUICFrameFactory::create_new_token_frame(const uint8_t *token, uint64_t token_len) +QUICFrameFactory::create_new_token_frame(ats_unique_buf token, uint64_t token_len, QUICFrameGenerator *owner) { QUICNewTokenFrame *frame = quicNewTokenFrameAllocator.alloc(); - new (frame) QUICNewTokenFrame(token, token_len); + new (frame) QUICNewTokenFrame(std::move(token), token_len, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_token_frame); } std::unique_ptr -QUICFrameFactory::create_retire_connection_id_frame(uint64_t seq_num) +QUICFrameFactory::create_retire_connection_id_frame(uint64_t seq_num, QUICFrameGenerator *owner) { QUICRetireConnectionIdFrame *frame = quicRetireConnectionIdFrameAllocator.alloc(); - new (frame) QUICRetireConnectionIdFrame(seq_num); + new (frame) QUICRetireConnectionIdFrame(seq_num, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_retire_connection_id_frame); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 164f092cde9..9bfa0f94dfe 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -61,12 +61,11 @@ class QUICFrame virtual void reset(const uint8_t *buf, size_t len); virtual QUICFrame *split(size_t size); virtual int debug_msg(char *msg, size_t msg_len) const; - virtual void set_owner(QUICFrameGenerator *owner); virtual QUICFrameGenerator *generated_by() const; LINK(QUICFrame, link); protected: - QUICFrame() {} + QUICFrame(QUICFrameGenerator *owner = nullptr) : _owner(owner) {} const uint8_t *_buf = nullptr; size_t _len = 0; QUICFrameGenerator *_owner = nullptr; @@ -79,9 +78,9 @@ class QUICFrame class QUICStreamFrame : public QUICFrame { public: - QUICStreamFrame() : QUICFrame() {} + QUICStreamFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false); + QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false, QUICFrameGenerator *owner = nullptr); QUICFrame *split(size_t size) override; QUICFrameUPtr clone() const override; @@ -124,9 +123,9 @@ class QUICStreamFrame : public QUICFrame class QUICCryptoFrame : public QUICFrame { public: - QUICCryptoFrame() : QUICFrame() {} + QUICCryptoFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICCryptoFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICCryptoFrame(ats_unique_buf buf, size_t len, QUICOffset offset); + QUICCryptoFrame(ats_unique_buf buf, size_t len, QUICOffset offset, QUICFrameGenerator *owner = nullptr); QUICFrame *split(size_t size) override; QUICFrameUPtr clone() const override; @@ -262,7 +261,7 @@ class QUICAckFrame : public QUICFrame QUICAckFrame() : QUICFrame() {} QUICAckFrame(const uint8_t *buf, size_t len); - QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block); + QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameGenerator *owner = nullptr); virtual ~QUICAckFrame(); virtual void reset(const uint8_t *buf, size_t len) override; @@ -304,7 +303,7 @@ class QUICRstStreamFrame : public QUICFrame public: QUICRstStreamFrame() : QUICFrame() {} QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset); + QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -334,7 +333,7 @@ class QUICRstStreamFrame : public QUICFrame class QUICPingFrame : public QUICFrame { public: - QUICPingFrame() : QUICFrame() {} + QUICPingFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICPingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -367,9 +366,9 @@ class QUICPaddingFrame : public QUICFrame class QUICConnectionCloseFrame : public QUICFrame { public: - QUICConnectionCloseFrame() : QUICFrame() {} + QUICConnectionCloseFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICConnectionCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase); + QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -400,9 +399,9 @@ class QUICConnectionCloseFrame : public QUICFrame class QUICApplicationCloseFrame : public QUICFrame { public: - QUICApplicationCloseFrame() : QUICFrame() {} + QUICApplicationCloseFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICApplicationCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase); + QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual int debug_msg(char *msg, size_t msg_len) const override; virtual QUICFrameType type() const override; @@ -430,9 +429,9 @@ class QUICApplicationCloseFrame : public QUICFrame class QUICMaxDataFrame : public QUICFrame { public: - QUICMaxDataFrame() : QUICFrame() {} + QUICMaxDataFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICMaxDataFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICMaxDataFrame(uint64_t maximum_data); + QUICMaxDataFrame(uint64_t maximum_data, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -454,9 +453,9 @@ class QUICMaxDataFrame : public QUICFrame class QUICMaxStreamDataFrame : public QUICFrame { public: - QUICMaxStreamDataFrame() : QUICFrame() {} + QUICMaxStreamDataFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICMaxStreamDataFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data); + QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -483,9 +482,9 @@ class QUICMaxStreamDataFrame : public QUICFrame class QUICMaxStreamIdFrame : public QUICFrame { public: - QUICMaxStreamIdFrame() : QUICFrame() {} + QUICMaxStreamIdFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICMaxStreamIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id); + QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -504,9 +503,9 @@ class QUICMaxStreamIdFrame : public QUICFrame class QUICBlockedFrame : public QUICFrame { public: - QUICBlockedFrame() : QUICFrame() {} + QUICBlockedFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICBlockedFrame(QUICOffset offset) : _offset(offset){}; + QUICBlockedFrame(QUICOffset offset, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _offset(offset){}; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -528,9 +527,9 @@ class QUICBlockedFrame : public QUICFrame class QUICStreamBlockedFrame : public QUICFrame { public: - QUICStreamBlockedFrame() : QUICFrame() {} + QUICStreamBlockedFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICStreamBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o) : _stream_id(s), _offset(o){}; + QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _stream_id(s), _offset(o){}; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -555,9 +554,9 @@ class QUICStreamBlockedFrame : public QUICFrame class QUICStreamIdBlockedFrame : public QUICFrame { public: - QUICStreamIdBlockedFrame() : QUICFrame() {} + QUICStreamIdBlockedFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamIdBlockedFrame(QUICStreamId s) : _stream_id(s) {} + QUICStreamIdBlockedFrame(QUICStreamId s, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _stream_id(s) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -578,10 +577,10 @@ class QUICStreamIdBlockedFrame : public QUICFrame class QUICNewConnectionIdFrame : public QUICFrame { public: - QUICNewConnectionIdFrame() : QUICFrame() {} + QUICNewConnectionIdFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICNewConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId id, QUICStatelessResetToken token) - : _sequence(seq), _connection_id(id), _stateless_reset_token(token){}; + QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId id, QUICStatelessResetToken token, QUICFrameGenerator *owner = nullptr) + : QUICFrame(owner), _sequence(seq), _connection_id(id), _stateless_reset_token(token){}; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -610,9 +609,9 @@ class QUICNewConnectionIdFrame : public QUICFrame class QUICStopSendingFrame : public QUICFrame { public: - QUICStopSendingFrame() : QUICFrame() {} + QUICStopSendingFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICStopSendingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code); + QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -638,9 +637,9 @@ class QUICPathChallengeFrame : public QUICFrame { public: static constexpr uint8_t DATA_LEN = 8; - QUICPathChallengeFrame() : QUICFrame() {} + QUICPathChallengeFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICPathChallengeFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICPathChallengeFrame(ats_unique_buf data) : _data(std::move(data)) {} + QUICPathChallengeFrame(ats_unique_buf data, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _data(std::move(data)) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -663,9 +662,9 @@ class QUICPathResponseFrame : public QUICFrame { public: static constexpr uint8_t DATA_LEN = 8; - QUICPathResponseFrame() : QUICFrame() {} + QUICPathResponseFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICPathResponseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICPathResponseFrame(ats_unique_buf data) : _data(std::move(data)) {} + QUICPathResponseFrame(ats_unique_buf data, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _data(std::move(data)) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -687,9 +686,9 @@ class QUICPathResponseFrame : public QUICFrame class QUICNewTokenFrame : public QUICFrame { public: - QUICNewTokenFrame() : QUICFrame() {} + QUICNewTokenFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICNewTokenFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICNewTokenFrame(ats_unique_buf token, size_t token_length) : _token_length(token_length), _token(std::move(token)) {} + QUICNewTokenFrame(ats_unique_buf token, size_t token_length, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _token_length(token_length), _token(std::move(token)) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -714,9 +713,9 @@ class QUICNewTokenFrame : public QUICFrame class QUICRetireConnectionIdFrame : public QUICFrame { public: - QUICRetireConnectionIdFrame() : QUICFrame() {} + QUICRetireConnectionIdFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICRetireConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICRetireConnectionIdFrame(uint64_t seq_num) : _seq_num(seq_num) {} + QUICRetireConnectionIdFrame(uint64_t seq_num, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _seq_num(seq_num) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -738,7 +737,7 @@ class QUICRetireConnectionIdFrame : public QUICFrame class QUICRetransmissionFrame : public QUICFrame { public: - QUICRetransmissionFrame() : QUICFrame() {} + QUICRetransmissionFrame() {} QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet); QUICFrameUPtr clone() const override; QUICFrameType type() const override; @@ -969,13 +968,13 @@ class QUICFrameFactory * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ static QUICStreamFrameUPtr create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, - bool last = false); + bool last = false, QUICFrameGenerator *owner = nullptr); /* * Creates a CRYPTO frame. * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ - static QUICCryptoFrameUPtr create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset); + static QUICCryptoFrameUPtr create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, QUICFrameGenerator *owner = nullptr); /* * Creates a ACK frame. @@ -983,99 +982,99 @@ class QUICFrameFactory * need to ack. */ static std::unique_ptr create_ack_frame(QUICPacketNumber largest_acknowledged, - uint64_t ack_delay, uint64_t first_ack_block); + uint64_t ack_delay, uint64_t first_ack_block, QUICFrameGenerator *owner = nullptr); /* * Creates a CONNECTION_CLOSE frame. */ static std::unique_ptr create_connection_close_frame( - uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr); + uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr, QUICFrameGenerator *owner = nullptr); static std::unique_ptr create_connection_close_frame( - QUICConnectionErrorUPtr error); + QUICConnectionErrorUPtr error, QUICFrameGenerator *owner = nullptr); /* * Creates a APPLICATION_CLOSE frame. */ static std::unique_ptr create_application_close_frame( - QUICAppErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr); + QUICAppErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr, QUICFrameGenerator *owner = nullptr); static std::unique_ptr create_application_close_frame( - QUICConnectionErrorUPtr error); + QUICConnectionErrorUPtr error, QUICFrameGenerator *owner = nullptr); /* * Creates a MAX_DATA frame. */ - static std::unique_ptr create_max_data_frame(uint64_t maximum_data); + static std::unique_ptr create_max_data_frame(uint64_t maximum_data, QUICFrameGenerator *owner = nullptr); /* / * Creates a MAX_STREAM_DATA frame. */ static std::unique_ptr create_max_stream_data_frame(QUICStreamId stream_id, - uint64_t maximum_stream_data); + uint64_t maximum_stream_data, QUICFrameGenerator *owner = nullptr); /* * Creates a MAX_STREAM_ID frame. */ - static std::unique_ptr create_max_stream_id_frame(QUICStreamId maximum_stream_id); + static std::unique_ptr create_max_stream_id_frame(QUICStreamId maximum_stream_id, QUICFrameGenerator *owner = nullptr); /* * Creates a PING frame */ - static std::unique_ptr create_ping_frame(); + static std::unique_ptr create_ping_frame(QUICFrameGenerator *owner = nullptr); /* * Creates a PATH_CHALLENGE frame */ - static std::unique_ptr create_path_challenge_frame(const uint8_t *data); + static std::unique_ptr create_path_challenge_frame(const uint8_t *data, QUICFrameGenerator *owner = nullptr); /* * Creates a PATH_RESPONSE frame */ - static std::unique_ptr create_path_response_frame(const uint8_t *data); + static std::unique_ptr create_path_response_frame(const uint8_t *data, QUICFrameGenerator *owner = nullptr); /* * Creates a BLOCKED frame. */ - static std::unique_ptr create_blocked_frame(QUICOffset offset); + static std::unique_ptr create_blocked_frame(QUICOffset offset, QUICFrameGenerator *owner = nullptr); /* * Creates a STREAM_BLOCKED frame. */ static std::unique_ptr create_stream_blocked_frame(QUICStreamId stream_id, - QUICOffset offset); + QUICOffset offset, QUICFrameGenerator *owner = nullptr); /* * Creates a STREAM_ID_BLOCKED frame. */ - static std::unique_ptr create_stream_id_blocked_frame(QUICStreamId stream_id); + static std::unique_ptr create_stream_id_blocked_frame(QUICStreamId stream_id, QUICFrameGenerator *owner = nullptr); /* * Creates a RST_STREAM frame. */ static std::unique_ptr create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, - QUICOffset final_offset); - static std::unique_ptr create_rst_stream_frame(QUICStreamErrorUPtr error); + QUICOffset final_offset, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_rst_stream_frame(QUICStreamErrorUPtr error, QUICFrameGenerator *owner = nullptr); /* * Creates a STOP_SENDING frame. */ static std::unique_ptr create_stop_sending_frame(QUICStreamId stream_id, - QUICAppErrorCode error_code); + QUICAppErrorCode error_code, QUICFrameGenerator *owner = nullptr); /* * Creates a NEW_CONNECTION_ID frame. */ static std::unique_ptr create_new_connection_id_frame( - uint32_t sequence, QUICConnectionId connectoin_id, QUICStatelessResetToken stateless_reset_token); + uint32_t sequence, QUICConnectionId connectoin_id, QUICStatelessResetToken stateless_reset_token, QUICFrameGenerator *owner = nullptr); /* * Creates a NEW_TOKEN frame */ - static std::unique_ptr create_new_token_frame(const uint8_t *token, uint64_t token_len); + static std::unique_ptr create_new_token_frame(ats_unique_buf token, uint64_t token_len, QUICFrameGenerator *owner = nullptr); /* * Creates a RETIRE_CONNECTION_ID frame */ - static std::unique_ptr create_retire_connection_id_frame(uint64_t seq_num); + static std::unique_ptr create_retire_connection_id_frame(uint64_t seq_num, QUICFrameGenerator *owner = nullptr); /* * Creates a retransmission frame, which is very special. From bba430f0336baa4b5fa91182fd56faa4aa9facb5 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 6 Nov 2018 11:59:31 +0800 Subject: [PATCH 0908/1313] QUIC: run clang-format --- iocore/net/quic/QUICFrame.cc | 74 ++++++++++++++++++++------------- iocore/net/quic/QUICFrame.h | 79 ++++++++++++++++++++++++------------ 2 files changed, 98 insertions(+), 55 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index fa77b9d666c..5c381b3bc24 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -107,7 +107,9 @@ QUICFrame::split(size_t size) // STREAM Frame // -QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, QUICFrameGenerator *owner) : QUICFrame(owner) +QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, + QUICFrameGenerator *owner) + : QUICFrame(owner) { this->_data = std::move(data); this->_data_len = data_len; @@ -149,7 +151,8 @@ QUICStreamFrame::split(size_t size) this->reset(nullptr, 0); QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin, this->_owner); + new (frame) + QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin, this->_owner); return frame; } @@ -400,7 +403,8 @@ QUICStreamFrame::_get_length_field_len() const // CRYPTO frame // -QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffset offset, QUICFrameGenerator *owner) : QUICFrame(owner) +QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffset offset, QUICFrameGenerator *owner) + : QUICFrame(owner) { this->_data = std::move(data); this->_data_len = data_len; @@ -431,7 +435,7 @@ QUICCryptoFrame::split(size_t size) this->reset(nullptr, 0); QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); - new (frame) QUICCryptoFrame(std::move(buf2), buf2_len, this->offset() + this->data_length()); + new (frame) QUICCryptoFrame(std::move(buf2), buf2_len, this->offset() + this->data_length(), this->_owner); return frame; } @@ -439,7 +443,7 @@ QUICCryptoFrame::split(size_t size) QUICFrameUPtr QUICCryptoFrame::clone() const { - return QUICFrameFactory::create_crypto_frame(this->data(), this->data_length(), this->offset()); + return QUICFrameFactory::create_crypto_frame(this->data(), this->data_length(), this->offset(), this->_owner); } QUICFrameType @@ -573,7 +577,9 @@ QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) this->reset(buf, len); } -QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameGenerator *owner) : QUICFrame(owner) +QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, + QUICFrameGenerator *owner) + : QUICFrame(owner) { this->_largest_acknowledged = largest_acknowledged; this->_ack_delay = ack_delay; @@ -613,7 +619,7 @@ QUICFrameUPtr QUICAckFrame::clone() const { std::unique_ptr newframe = QUICFrameFactory::create_ack_frame( - this->largest_acknowledged(), this->ack_delay(), this->ack_block_section()->first_ack_block()); + this->largest_acknowledged(), this->ack_delay(), this->ack_block_section()->first_ack_block(), this->_owner); for (auto &ack_block : *this->ack_block_section()) { newframe->ack_block_section()->add_ack_block({ack_block.gap(), ack_block.length()}); @@ -1078,7 +1084,8 @@ QUICAckFrame::EcnSection::ecn_ce_count() const // RST_STREAM frame // -QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameGenerator *owner) +QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, + QUICFrameGenerator *owner) : QUICFrame(owner), _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset) { } @@ -1086,7 +1093,7 @@ QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode QUICFrameUPtr QUICRstStreamFrame::clone() const { - return QUICFrameFactory::create_rst_stream_frame(this->stream_id(), this->error_code(), this->final_offset()); + return QUICFrameFactory::create_rst_stream_frame(this->stream_id(), this->error_code(), this->final_offset(), this->_owner); } QUICFrameType @@ -1204,7 +1211,7 @@ QUICRstStreamFrame::_get_final_offset_field_length() const QUICFrameUPtr QUICPingFrame::clone() const { - return QUICFrameFactory::create_ping_frame(); + return QUICFrameFactory::create_ping_frame(this->_owner); } QUICFrameType @@ -1283,7 +1290,11 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len, size_t limit) const // QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase, QUICFrameGenerator *owner) - : QUICFrame(owner), _error_code(error_code), _frame_type(frame_type), _reason_phrase_length(reason_phrase_length), _reason_phrase(reason_phrase) + : QUICFrame(owner), + _error_code(error_code), + _frame_type(frame_type), + _reason_phrase_length(reason_phrase_length), + _reason_phrase(reason_phrase) { } @@ -1470,7 +1481,8 @@ QUICConnectionCloseFrame::_get_reason_phrase_field_offset() const // APPLICATION_CLOSE frame // QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, - const char *reason_phrase, QUICFrameGenerator *owner) : QUICFrame(owner) + const char *reason_phrase, QUICFrameGenerator *owner) + : QUICFrame(owner) { this->_error_code = error_code; this->_reason_phrase_length = reason_phrase_length; @@ -1480,7 +1492,8 @@ QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code QUICFrameUPtr QUICApplicationCloseFrame::clone() const { - return QUICFrameFactory::create_application_close_frame(this->error_code(), this->reason_phrase_length(), this->reason_phrase()); + return QUICFrameFactory::create_application_close_frame(this->error_code(), this->reason_phrase_length(), this->reason_phrase(), + this->_owner); } QUICFrameType @@ -1609,7 +1622,7 @@ QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, QUICFrameGenerator *ow QUICFrameUPtr QUICMaxDataFrame::clone() const { - return QUICFrameFactory::create_max_data_frame(this->maximum_data()); + return QUICFrameFactory::create_max_data_frame(this->maximum_data(), this->_owner); } QUICFrameType @@ -1677,7 +1690,8 @@ QUICMaxDataFrame::_get_max_data_field_length() const // // MAX_STREAM_DATA // -QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameGenerator *owner) : QUICFrame(owner) +QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameGenerator *owner) + : QUICFrame(owner) { this->_stream_id = stream_id; this->_maximum_stream_data = maximum_stream_data; @@ -1686,7 +1700,7 @@ QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t QUICFrameUPtr QUICMaxStreamDataFrame::clone() const { - return QUICFrameFactory::create_max_stream_data_frame(this->stream_id(), this->maximum_stream_data()); + return QUICFrameFactory::create_max_stream_data_frame(this->stream_id(), this->maximum_stream_data(), this->_owner); } QUICFrameType @@ -1794,7 +1808,7 @@ QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICF QUICFrameUPtr QUICMaxStreamIdFrame::clone() const { - return QUICFrameFactory::create_max_stream_id_frame(this->maximum_stream_id()); + return QUICFrameFactory::create_max_stream_id_frame(this->maximum_stream_id(), this->_owner); } QUICFrameType @@ -1858,7 +1872,7 @@ QUICMaxStreamIdFrame::_get_max_stream_id_field_length() const QUICFrameUPtr QUICBlockedFrame::clone() const { - return QUICFrameFactory::create_blocked_frame(this->offset()); + return QUICFrameFactory::create_blocked_frame(this->offset(), this->_owner); } QUICFrameType @@ -1924,7 +1938,7 @@ QUICBlockedFrame::_get_offset_field_length() const QUICFrameUPtr QUICStreamBlockedFrame::clone() const { - return QUICFrameFactory::create_stream_blocked_frame(this->stream_id(), this->offset()); + return QUICFrameFactory::create_stream_blocked_frame(this->stream_id(), this->offset(), this->_owner); } QUICFrameType @@ -2017,7 +2031,7 @@ QUICStreamBlockedFrame::_get_offset_field_length() const QUICFrameUPtr QUICStreamIdBlockedFrame::clone() const { - return QUICFrameFactory::create_stream_id_blocked_frame(this->stream_id()); + return QUICFrameFactory::create_stream_id_blocked_frame(this->stream_id(), this->_owner); } QUICFrameType @@ -2084,7 +2098,8 @@ QUICFrameUPtr QUICNewConnectionIdFrame::clone() const { // FIXME: Connection ID and Stateless rese token have to be the same - return QUICFrameFactory::create_new_connection_id_frame(this->sequence(), this->connection_id(), this->stateless_reset_token()); + return QUICFrameFactory::create_new_connection_id_frame(this->sequence(), this->connection_id(), this->stateless_reset_token(), + this->_owner); } QUICFrameType @@ -2207,7 +2222,7 @@ QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorC QUICFrameUPtr QUICStopSendingFrame::clone() const { - return QUICFrameFactory::create_stop_sending_frame(this->stream_id(), this->error_code()); + return QUICFrameFactory::create_stop_sending_frame(this->stream_id(), this->error_code(), this->_owner); } QUICFrameType @@ -2290,7 +2305,7 @@ QUICStopSendingFrame::_get_error_code_field_offset() const QUICFrameUPtr QUICPathChallengeFrame::clone() const { - return QUICFrameFactory::create_path_challenge_frame(this->data()); + return QUICFrameFactory::create_path_challenge_frame(this->data(), this->_owner); } QUICFrameType @@ -2352,7 +2367,7 @@ QUICPathChallengeFrame::_data_offset() const QUICFrameUPtr QUICPathResponseFrame::clone() const { - return QUICFrameFactory::create_path_response_frame(this->data()); + return QUICFrameFactory::create_path_response_frame(this->data(), this->_owner); } QUICFrameType @@ -2416,7 +2431,7 @@ QUICNewTokenFrame::clone() const { ats_unique_buf buf = ats_unique_malloc(this->token_length()); memcpy(buf.get(), this->token(), this->token_length()); - + return QUICFrameFactory::create_new_token_frame(std::move(buf), this->token_length(), this->_owner); } @@ -2764,7 +2779,8 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) } QUICStreamFrameUPtr -QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, QUICFrameGenerator *owner) +QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, + QUICFrameGenerator *owner) { ats_unique_buf buf = ats_unique_malloc(data_len); memcpy(buf.get(), data, data_len); @@ -2797,7 +2813,8 @@ QUICFrameFactory::split_frame(QUICFrame *frame, size_t size) } std::unique_ptr -QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameGenerator *owner) +QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, + QUICFrameGenerator *owner) { QUICAckFrame *frame = quicAckFrameAllocator.alloc(); new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block, owner); @@ -2923,7 +2940,8 @@ QUICFrameFactory::create_stream_id_blocked_frame(QUICStreamId stream_id, QUICFra } std::unique_ptr -QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameGenerator *owner) +QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, + QUICFrameGenerator *owner) { QUICRstStreamFrame *frame = quicRstStreamFrameAllocator.alloc(); new (frame) QUICRstStreamFrame(stream_id, error_code, final_offset, owner); diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 9bfa0f94dfe..721112a6d32 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -80,7 +80,8 @@ class QUICStreamFrame : public QUICFrame public: QUICStreamFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false, QUICFrameGenerator *owner = nullptr); + QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false, + QUICFrameGenerator *owner = nullptr); QUICFrame *split(size_t size) override; QUICFrameUPtr clone() const override; @@ -261,7 +262,8 @@ class QUICAckFrame : public QUICFrame QUICAckFrame() : QUICFrame() {} QUICAckFrame(const uint8_t *buf, size_t len); - QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameGenerator *owner = nullptr); + QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, + QUICFrameGenerator *owner = nullptr); virtual ~QUICAckFrame(); virtual void reset(const uint8_t *buf, size_t len) override; @@ -303,7 +305,8 @@ class QUICRstStreamFrame : public QUICFrame public: QUICRstStreamFrame() : QUICFrame() {} QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameGenerator *owner = nullptr); + QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, + QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -368,7 +371,8 @@ class QUICConnectionCloseFrame : public QUICFrame public: QUICConnectionCloseFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICConnectionCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase, QUICFrameGenerator *owner = nullptr); + QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase, + QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -401,7 +405,8 @@ class QUICApplicationCloseFrame : public QUICFrame public: QUICApplicationCloseFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICApplicationCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase, QUICFrameGenerator *owner = nullptr); + QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase, + QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual int debug_msg(char *msg, size_t msg_len) const override; virtual QUICFrameType type() const override; @@ -529,7 +534,8 @@ class QUICStreamBlockedFrame : public QUICFrame public: QUICStreamBlockedFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICStreamBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _stream_id(s), _offset(o){}; + QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o, QUICFrameGenerator *owner = nullptr) + : QUICFrame(owner), _stream_id(s), _offset(o){}; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -688,7 +694,10 @@ class QUICNewTokenFrame : public QUICFrame public: QUICNewTokenFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} QUICNewTokenFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICNewTokenFrame(ats_unique_buf token, size_t token_length, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _token_length(token_length), _token(std::move(token)) {} + QUICNewTokenFrame(ats_unique_buf token, size_t token_length, QUICFrameGenerator *owner = nullptr) + : QUICFrame(owner), _token_length(token_length), _token(std::move(token)) + { + } QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -974,7 +983,8 @@ class QUICFrameFactory * Creates a CRYPTO frame. * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ - static QUICCryptoFrameUPtr create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, QUICFrameGenerator *owner = nullptr); + static QUICCryptoFrameUPtr create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, + QUICFrameGenerator *owner = nullptr); /* * Creates a ACK frame. @@ -982,12 +992,14 @@ class QUICFrameFactory * need to ack. */ static std::unique_ptr create_ack_frame(QUICPacketNumber largest_acknowledged, - uint64_t ack_delay, uint64_t first_ack_block, QUICFrameGenerator *owner = nullptr); + uint64_t ack_delay, uint64_t first_ack_block, + QUICFrameGenerator *owner = nullptr); /* * Creates a CONNECTION_CLOSE frame. */ static std::unique_ptr create_connection_close_frame( - uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr, QUICFrameGenerator *owner = nullptr); + uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr, + QUICFrameGenerator *owner = nullptr); static std::unique_ptr create_connection_close_frame( QUICConnectionErrorUPtr error, QUICFrameGenerator *owner = nullptr); @@ -996,24 +1008,27 @@ class QUICFrameFactory * Creates a APPLICATION_CLOSE frame. */ static std::unique_ptr create_application_close_frame( - QUICAppErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr, QUICFrameGenerator *owner = nullptr); + QUICAppErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr, + QUICFrameGenerator *owner = nullptr); static std::unique_ptr create_application_close_frame( QUICConnectionErrorUPtr error, QUICFrameGenerator *owner = nullptr); /* * Creates a MAX_DATA frame. */ - static std::unique_ptr create_max_data_frame(uint64_t maximum_data, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_max_data_frame(uint64_t maximum_data, + QUICFrameGenerator *owner = nullptr); /* / * Creates a MAX_STREAM_DATA frame. */ - static std::unique_ptr create_max_stream_data_frame(QUICStreamId stream_id, - uint64_t maximum_stream_data, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_max_stream_data_frame( + QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameGenerator *owner = nullptr); /* * Creates a MAX_STREAM_ID frame. */ - static std::unique_ptr create_max_stream_id_frame(QUICStreamId maximum_stream_id, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_max_stream_id_frame( + QUICStreamId maximum_stream_id, QUICFrameGenerator *owner = nullptr); /* * Creates a PING frame @@ -1023,58 +1038,68 @@ class QUICFrameFactory /* * Creates a PATH_CHALLENGE frame */ - static std::unique_ptr create_path_challenge_frame(const uint8_t *data, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_path_challenge_frame( + const uint8_t *data, QUICFrameGenerator *owner = nullptr); /* * Creates a PATH_RESPONSE frame */ - static std::unique_ptr create_path_response_frame(const uint8_t *data, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_path_response_frame( + const uint8_t *data, QUICFrameGenerator *owner = nullptr); /* * Creates a BLOCKED frame. */ - static std::unique_ptr create_blocked_frame(QUICOffset offset, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_blocked_frame(QUICOffset offset, + QUICFrameGenerator *owner = nullptr); /* * Creates a STREAM_BLOCKED frame. */ - static std::unique_ptr create_stream_blocked_frame(QUICStreamId stream_id, - QUICOffset offset, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_stream_blocked_frame( + QUICStreamId stream_id, QUICOffset offset, QUICFrameGenerator *owner = nullptr); /* * Creates a STREAM_ID_BLOCKED frame. */ - static std::unique_ptr create_stream_id_blocked_frame(QUICStreamId stream_id, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_stream_id_blocked_frame( + QUICStreamId stream_id, QUICFrameGenerator *owner = nullptr); /* * Creates a RST_STREAM frame. */ static std::unique_ptr create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, - QUICOffset final_offset, QUICFrameGenerator *owner = nullptr); - static std::unique_ptr create_rst_stream_frame(QUICStreamErrorUPtr error, QUICFrameGenerator *owner = nullptr); + QUICOffset final_offset, + QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_rst_stream_frame(QUICStreamErrorUPtr error, + QUICFrameGenerator *owner = nullptr); /* * Creates a STOP_SENDING frame. */ static std::unique_ptr create_stop_sending_frame(QUICStreamId stream_id, - QUICAppErrorCode error_code, QUICFrameGenerator *owner = nullptr); + QUICAppErrorCode error_code, + QUICFrameGenerator *owner = nullptr); /* * Creates a NEW_CONNECTION_ID frame. */ static std::unique_ptr create_new_connection_id_frame( - uint32_t sequence, QUICConnectionId connectoin_id, QUICStatelessResetToken stateless_reset_token, QUICFrameGenerator *owner = nullptr); + uint32_t sequence, QUICConnectionId connectoin_id, QUICStatelessResetToken stateless_reset_token, + QUICFrameGenerator *owner = nullptr); /* * Creates a NEW_TOKEN frame */ - static std::unique_ptr create_new_token_frame(ats_unique_buf token, uint64_t token_len, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_new_token_frame(ats_unique_buf token, uint64_t token_len, + QUICFrameGenerator *owner = nullptr); /* * Creates a RETIRE_CONNECTION_ID frame */ - static std::unique_ptr create_retire_connection_id_frame(uint64_t seq_num, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_retire_connection_id_frame( + uint64_t seq_num, QUICFrameGenerator *owner = nullptr); /* * Creates a retransmission frame, which is very special. From 3407ed3f0db440c5e9444ebc8566e3004d397fc3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 9 Nov 2018 17:00:15 +0900 Subject: [PATCH 0909/1313] Fix unit tests --- iocore/net/quic/Mock.h | 2 +- iocore/net/quic/test/test_QUICFrame.cc | 3 ++- iocore/net/quic/test/test_QUICLossDetector.cc | 19 ++++++++++--------- .../net/quic/test/test_QUICPacketFactory.cc | 3 ++- .../quic/test/test_QUICVersionNegotiator.cc | 10 ++++++---- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 4f5742f4857..b660b97105e 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -386,7 +386,7 @@ class MockQUICCongestionController : public QUICCongestionController MockQUICCongestionController(QUICConnectionInfoProvider *info) : QUICCongestionController(info) {} // Override virtual void - on_packets_lost(const std::map &packets) override + on_packets_lost(const std::map &packets) override { for (auto &p : packets) { lost_packets.insert(p.first); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 6b2edc2a69d..5e430338e6e 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1373,8 +1373,9 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") QUICPacketFactory factory; MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); + std::vector frames; QUICPacketUPtr packet = factory.create_protected_packet({reinterpret_cast("\x01\x02\x03\x04"), 4}, 0, - {nullptr, [](void *p) { ats_free(p); }}, 0, true, false); + {nullptr, [](void *p) { ats_free(p); }}, 0, true, false, frames); SECTION("STREAM frame split") { size_t len; diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 2a845843e8e..fd93aa6e604 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -45,6 +45,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") size_t payload_len = 16; QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); std::shared_ptr frame = QUICFrameFactory::create_null_ack_frame(); + std::vector dummy_frames; SECTION("Handshake") { @@ -85,31 +86,31 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") // Send packet (1) to (7) payload = ats_unique_malloc(16); QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + payload_len, true, false, dummy_frames); payload = ats_unique_malloc(16); QUICPacketUPtr packet2 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + payload_len, true, false, dummy_frames); payload = ats_unique_malloc(16); QUICPacketUPtr packet3 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + payload_len, true, false, dummy_frames); payload = ats_unique_malloc(16); QUICPacketUPtr packet4 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + payload_len, true, false, dummy_frames); payload = ats_unique_malloc(16); QUICPacketUPtr packet5 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + payload_len, true, false, dummy_frames); payload = ats_unique_malloc(16); QUICPacketUPtr packet6 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + payload_len, true, false, dummy_frames); payload = ats_unique_malloc(16); QUICPacketUPtr packet7 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + payload_len, true, false, dummy_frames); payload = ats_unique_malloc(16); QUICPacketUPtr packet8 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + payload_len, true, false, dummy_frames); payload = ats_unique_malloc(16); QUICPacketUPtr packet9 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + payload_len, true, false, dummy_frames); QUICPacketNumber pn1 = packet1->packet_number(); QUICPacketNumber pn2 = packet2->packet_number(); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 4ffedbc22f8..96b95e8ac00 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -90,6 +90,7 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); factory.set_version(0x11223344); + std::vector dummy_frames; uint8_t raw[] = {0xaa, 0xbb, 0xcc, 0xdd}; ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); @@ -97,7 +98,7 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") QUICPacketUPtr packet = factory.create_handshake_packet( QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), - QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), 0, std::move(payload), sizeof(raw), true, false); + QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), 0, std::move(payload), sizeof(raw), true, false, dummy_frames); CHECK(packet->type() == QUICPacketType::HANDSHAKE); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index f6ccf0da426..630e284ff07 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -32,6 +32,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") MockQUICHandshakeProtocol hs_protocol; packet_factory.set_hs_protocol(&hs_protocol); QUICVersionNegotiator vn; + std::vector dummy_frame; SECTION("Normal case") { @@ -40,7 +41,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -58,7 +59,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -76,7 +77,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); @@ -94,6 +95,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") MockQUICHandshakeProtocol hs_protocol; packet_factory.set_hs_protocol(&hs_protocol); QUICVersionNegotiator vn; + std::vector dummy_frame; SECTION("Normal case") { @@ -118,7 +120,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false); + QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); // Server send VN packet based on Initial packet QUICPacketUPtr vn_packet = From 3d038e48d9c15625d84d84df19581635ffcdd13b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 9 Nov 2018 17:06:50 +0900 Subject: [PATCH 0910/1313] Remove conflict marker --- iocore/net/P_Net.h | 1 - 1 file changed, 1 deletion(-) diff --git a/iocore/net/P_Net.h b/iocore/net/P_Net.h index 9f653c3a31e..253026d8b1d 100644 --- a/iocore/net/P_Net.h +++ b/iocore/net/P_Net.h @@ -110,7 +110,6 @@ extern RecRawStatBlock *net_rsb; #include "P_SSLNetAccept.h" #include "P_SSLCertLookup.h" -<<<<<<< HEAD #if TS_USE_QUIC == 1 #include "P_QUICNetVConnection.h" #include "P_QUICNetProcessor.h" From d8a5b919d171c3cb373925a789f856cd59eb1347 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 9 Nov 2018 17:13:08 +0900 Subject: [PATCH 0911/1313] Fix compile error because of incomplete merge --- src/traffic_quic/traffic_quic.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/traffic_quic/traffic_quic.cc b/src/traffic_quic/traffic_quic.cc index d7ad9cce747..ccc56f03eea 100644 --- a/src/traffic_quic/traffic_quic.cc +++ b/src/traffic_quic/traffic_quic.cc @@ -75,7 +75,7 @@ main(int argc, const char **argv) Thread *main_thread = new EThread; main_thread->set_specific(); net_config_poll_timeout = 10; - ink_net_init(makeModuleVersion(1, 0, PRIVATE_MODULE_HEADER)); + ink_net_init(ts::ModuleVersion(1, 0, ts::ModuleVersion::PRIVATE)); SSLInitializeLibrary(); SSLConfig::startup(); @@ -83,7 +83,7 @@ main(int argc, const char **argv) netProcessor.init(); quic_NetProcessor.init(); - ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + ink_event_system_init(EVENT_SYSTEM_MODULE_PUBLIC_VERSION); eventProcessor.start(THREADS); udpNet.start(1, stacksize); quic_NetProcessor.start(-1, stacksize); From 40960ab2f397ea6e9d842b9356905cf0268d6ae5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 9 Nov 2018 17:26:20 +0900 Subject: [PATCH 0912/1313] clang-format --- iocore/net/quic/test/test_QUICPacketFactory.cc | 7 ++++--- iocore/net/quic/test/test_QUICVersionNegotiator.cc | 12 ++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 96b95e8ac00..e9b29c81664 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -96,9 +96,10 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); - QUICPacketUPtr packet = factory.create_handshake_packet( - QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), - QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), 0, std::move(payload), sizeof(raw), true, false, dummy_frames); + QUICPacketUPtr packet = + factory.create_handshake_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), + QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), 0, + std::move(payload), sizeof(raw), true, false, dummy_frames); CHECK(packet->type() == QUICPacketType::HANDSHAKE); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 630e284ff07..95263c96d50 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -41,7 +41,8 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); + QUICPacketUPtr initial_packet = + packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -59,7 +60,8 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); + QUICPacketUPtr initial_packet = + packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -77,7 +79,8 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); + QUICPacketUPtr initial_packet = + packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); @@ -120,7 +123,8 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); - QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); + QUICPacketUPtr initial_packet = + packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); // Server send VN packet based on Initial packet QUICPacketUPtr vn_packet = From b23d1c57c03b689a3b06b2b7719e9674bd9dfb8b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 13 Nov 2018 13:02:26 +0900 Subject: [PATCH 0913/1313] Fix a minor build error --- iocore/net/quic/QUICTransportParameters.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index dfc5e6b6f1e..12681b63578 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -36,7 +36,7 @@ static constexpr char tag[] = "quic_handshake"; static constexpr uint32_t TP_ERROR_LENGTH = 0x010000; // static constexpr uint32_t TP_ERROR_VALUE = 0x020000; -static constexpr uint32_t TP_ERROR_MUST_EXIST = 0x030000; +// static constexpr uint32_t TP_ERROR_MUST_EXIST = 0x030000; static constexpr uint32_t TP_ERROR_MUST_NOT_EXIST = 0x040000; QUICTransportParameters::Value::Value(const uint8_t *data, uint16_t len) : _len(len) From e17ac35a7c7469418341901b3be6a61848e9df86 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 19 Nov 2018 15:13:58 +0800 Subject: [PATCH 0914/1313] QUIC: Fixed the signalActivity is not work on QUIC branch --- iocore/net/UnixNet.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/UnixNet.cc b/iocore/net/UnixNet.cc index eb95841f934..3308d889268 100644 --- a/iocore/net/UnixNet.cc +++ b/iocore/net/UnixNet.cc @@ -234,7 +234,7 @@ initialize_thread_for_net(EThread *thread) thread->schedule_every(inactivityCop, HRTIME_SECONDS(cop_freq)); thread->set_tail_handler(nh); - thread->ep = (EventIO *)ats_malloc(sizeof(EventIO)); + thread->ep = new EventIO(); thread->ep->type = EVENTIO_ASYNC_SIGNAL; #if HAVE_EVENTFD thread->ep->start(pd, thread->evfd, nullptr, EVENTIO_READ); From 88cbdc7f4c2da45683bbf795b87eeb2f06453840 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Nov 2018 15:59:22 +0800 Subject: [PATCH 0915/1313] QUIC: Fixed the signalActivity is not work on QUIC branch Co-Authored-By: scw00 <616955249@qq.com> --- iocore/net/UnixNet.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/UnixNet.cc b/iocore/net/UnixNet.cc index 3308d889268..c60b1916ffd 100644 --- a/iocore/net/UnixNet.cc +++ b/iocore/net/UnixNet.cc @@ -234,7 +234,8 @@ initialize_thread_for_net(EThread *thread) thread->schedule_every(inactivityCop, HRTIME_SECONDS(cop_freq)); thread->set_tail_handler(nh); - thread->ep = new EventIO(); + thread->ep = (EventIO *)ats_malloc(sizeof(EventIO)); + new (thread->ep) EventIO(); thread->ep->type = EVENTIO_ASYNC_SIGNAL; #if HAVE_EVENTFD thread->ep->start(pd, thread->evfd, nullptr, EVENTIO_READ); From b3e8671d6a11eadf58cff4d8e16b95a6c92eefd7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Nov 2018 22:30:26 +0900 Subject: [PATCH 0916/1313] Rename server id to instance id --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/QUICPacketHandler.cc | 2 +- iocore/net/quic/QUICAltConnectionManager.cc | 2 +- iocore/net/quic/QUICConfig.cc | 6 +++--- iocore/net/quic/QUICConfig.h | 4 ++-- iocore/net/quic/QUICTypes.h | 4 ++-- mgmt/RecordsConfig.cc | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2cc177a8c0b..a0003b009ad 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -207,7 +207,7 @@ QUICNetVConnection::start() // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not if (this->direction() == NET_VCONNECTION_IN) { this->_ack_frame_creator.set_ack_delay_exponent(params->ack_delay_exponent_in()); - this->_reset_token.generate(this->_quic_connection_id, params->server_id()); + this->_reset_token.generate(this->_quic_connection_id, params->instance_id()); this->_hs_protocol = this->_setup_handshake_protocol(params->server_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol, this->_reset_token, params->stateless_retry()); } else { diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 727a27bd0d7..d6837312b38 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -293,7 +293,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) QUICStatelessResetToken token; { QUICConfig::scoped_config params; - token.generate(dcid, params->server_id()); + token.generate(dcid, params->instance_id()); } auto packet = QUICPacketFactory::create_stateless_reset_packet(dcid, token); this->_send_packet(this, *packet, udp_packet->getConnection(), udp_packet->from, 1200, nullptr, 0); diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index f2760b77bf5..63298cf1b6b 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -90,7 +90,7 @@ QUICAltConnectionManager::_generate_next_alt_con_info() QUICConnectionId conn_id; QUICStatelessResetToken token; conn_id.randomize(); - token.generate(conn_id, params->server_id()); + token.generate(conn_id, params->instance_id()); AltConnectionInfo aci = {++this->_alt_quic_connection_id_seq_num, conn_id, token, {false}}; if (this->_qc->direction() == NET_VCONNECTION_IN) { diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 26310b81990..265b9dce122 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -133,7 +133,7 @@ QUICConfigParams::~QUICConfigParams() void QUICConfigParams::initialize() { - REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); + REC_EstablishStaticConfigInt32U(this->_instance_id, "proxy.config.quic.instance_id"); REC_EstablishStaticConfigInt32(this->_connection_table_size, "proxy.config.quic.connection_table.size"); REC_EstablishStaticConfigInt32U(this->_num_alt_connection_ids, "proxy.config.quic.num_alt_connection_ids"); REC_EstablishStaticConfigInt32U(this->_stateless_retry, "proxy.config.quic.server.stateless_retry_enabled"); @@ -212,9 +212,9 @@ QUICConfigParams::no_activity_timeout_out() const } uint32_t -QUICConfigParams::server_id() const +QUICConfigParams::instance_id() const { - return this->_server_id; + return this->_instance_id; } int diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 7987453d97e..e99519925cc 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -35,7 +35,7 @@ class QUICConfigParams : public ConfigInfo void initialize(); - uint32_t server_id() const; + uint32_t instance_id() const; uint32_t num_alt_connection_ids() const; uint32_t stateless_retry() const; uint32_t vn_exercise_enabled() const; @@ -92,7 +92,7 @@ class QUICConfigParams : public ConfigInfo // TODO: make configurable static const uint8_t _scid_len = 18; //< Length of Source Connection ID - uint32_t _server_id = 0; + uint32_t _instance_id = 0; uint32_t _num_alt_connection_ids = 0; uint32_t _stateless_retry = 0; uint32_t _vn_exercise_enabled = 0; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 1a05852b6ee..959e172f6b0 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -274,9 +274,9 @@ class QUICStatelessResetToken QUICStatelessResetToken() {} QUICStatelessResetToken(const uint8_t *buf) { memcpy(this->_token, buf, QUICStatelessResetToken::LEN); } void - generate(QUICConnectionId conn_id, uint32_t server_id) + generate(QUICConnectionId conn_id, uint32_t instance_id) { - this->_gen_token(conn_id ^ server_id); + this->_gen_token(conn_id ^ instance_id); } const uint8_t * diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index b28ce5aec60..56d6b9d5b28 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1347,7 +1347,7 @@ static const RecordElement RecordsConfig[] = //# QUIC global configuration. //# //############ - {RECT_CONFIG, "proxy.config.quic.server_id", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.instance_id", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.connection_table.size", RECD_INT, "65521", RECU_RESTART_TS, RR_NULL, RECC_INT, "[1-536870909]", RECA_NULL} , From 8b3effaf622c05b8fec96f3df32d6ad78f3fe4c3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 20 Nov 2018 00:33:24 +0900 Subject: [PATCH 0917/1313] Reduce use of QUICConfig --- iocore/net/P_QUICNetProcessor.h | 1 - iocore/net/QUICNetVConnection.cc | 3 ++- iocore/net/quic/QUICAltConnectionManager.cc | 12 ++++-------- iocore/net/quic/QUICAltConnectionManager.h | 4 +++- iocore/net/quic/QUICConfig.cc | 2 ++ iocore/net/quic/QUICPacket.cc | 5 ++--- iocore/net/quic/QUICPacketReceiveQueue.cc | 1 - iocore/net/quic/QUICStreamManager.cc | 1 - iocore/net/quic/QUICTypes.cc | 9 +++++---- iocore/net/quic/QUICTypes.h | 2 ++ 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h index 039314bcae2..7dfcba5c1d7 100644 --- a/iocore/net/P_QUICNetProcessor.h +++ b/iocore/net/P_QUICNetProcessor.h @@ -39,7 +39,6 @@ #include "tscore/ink_platform.h" #include "P_Net.h" -// #include "P_QUICConfig.h" #include "tscore/Map.h" class UnixNetVConnection; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a0003b009ad..a0285bda2f3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1765,7 +1765,8 @@ QUICNetVConnection::_switch_to_established_state() if (netvc_context == NET_VCONNECTION_IN || (netvc_context == NET_VCONNECTION_OUT && params->cm_exercise_enabled() && !remote_tp->contains(QUICTransportParameterId::DISABLE_MIGRATION))) { - this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id); + this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, + params->instance_id(), params->num_alt_connection_ids()); this->_frame_dispatcher->add_handler(this->_alt_con_manager); } } else { diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 63298cf1b6b..3e917524e49 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -23,25 +23,22 @@ #include "QUICAltConnectionManager.h" #include "QUICConnectionTable.h" -#include "QUICConfig.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, - QUICConnectionId peer_initial_cid) - : _qc(qc), _ctable(ctable) + QUICConnectionId peer_initial_cid, uint32_t instance_id, uint8_t num_alt_con) + : _qc(qc), _ctable(ctable), _instance_id(instance_id) { - QUICConfig::scoped_config params; - // Sequence number of the initial CID is 0 this->_alt_quic_connection_ids_remote.push_back({0, peer_initial_cid, {}, {true}}); // TODO If preferred_address was provided, sequence number of the provided CID is 1 if (this->_qc->direction() == NET_VCONNECTION_IN) { - this->_nids = params->num_alt_connection_ids(); + this->_nids = num_alt_con; this->_alt_quic_connection_ids_local = static_cast(ats_malloc(sizeof(AltConnectionInfo) * this->_nids)); this->_init_alt_connection_ids(); } else { @@ -86,11 +83,10 @@ QUICAltConnectionManager::handle_frame(QUICEncryptionLevel level, const QUICFram QUICAltConnectionManager::AltConnectionInfo QUICAltConnectionManager::_generate_next_alt_con_info() { - QUICConfig::scoped_config params; QUICConnectionId conn_id; QUICStatelessResetToken token; conn_id.randomize(); - token.generate(conn_id, params->instance_id()); + token.generate(conn_id, this->_instance_id); AltConnectionInfo aci = {++this->_alt_quic_connection_id_seq_num, conn_id, token, {false}}; if (this->_qc->direction() == NET_VCONNECTION_IN) { diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index f25ada51c8f..53dcc33a7ef 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -35,7 +35,8 @@ class QUICConnectionTable; class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenerator { public: - QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, QUICConnectionId peer_initial_cid); + QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, QUICConnectionId peer_initial_cid, uint32_t instance_id, + uint8_t num_alt_con); ~QUICAltConnectionManager(); /** @@ -89,6 +90,7 @@ class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenera AltConnectionInfo *_alt_quic_connection_ids_local; std::vector _alt_quic_connection_ids_remote; std::queue _retired_seq_nums; + uint32_t _instance_id = 0; uint8_t _nids = 0; uint64_t _alt_quic_connection_id_seq_num = 0; bool _need_advertise = false; diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 265b9dce122..8f22866a898 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -468,6 +468,8 @@ QUICConfig::reconfigure() // re-read configuration params->initialize(); _config_id = configProcessor.set(_config_id, params); + + QUICConnectionId::SCID_LEN = params->scid_len(); } QUICConfigParams * diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 1c853752381..a5a5edb1d94 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -28,7 +28,6 @@ #include "QUICIntUtil.h" #include "QUICDebugNames.h" -#include "QUICConfig.h" using namespace std::literals; static constexpr std::string_view tag = "quic_packet"sv; @@ -614,7 +613,7 @@ QUICPacketShortHeader::QUICPacketShortHeader(const IpEndpoint from, ats_unique_b this->_packet_number_len = QUICTypeUtil::read_QUICPacketNumberLen(this->_buf.get() + offset); QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + offset); QUICPacket::decode_packet_number(this->_packet_number, src, this->_packet_number_len, this->_base_packet_number); - this->_payload_length = len - (1 + QUICConfigParams::scid_len() + this->_packet_number_len); + this->_payload_length = len - (1 + QUICConnectionId::SCID_LEN + this->_packet_number_len); } QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICPacketNumber packet_number, @@ -1083,7 +1082,7 @@ QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, const QU } else { QUICPacketShortHeader::key_phase(phase, packet, packet_len); - if (!QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, QUICConfigParams::scid_len())) { + if (!QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, QUICConnectionId::SCID_LEN)) { Debug(tag.data(), "Failed to calculate packet number offset"); return false; } diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 8de9993da36..9c572120f73 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -24,7 +24,6 @@ #include "QUICPacketReceiveQueue.h" #include "QUICIntUtil.h" -#include "QUICConfig.h" // FIXME: workaround for coalescing packets static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 6d047579800..9263e7edc30 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -25,7 +25,6 @@ #include "QUICApplication.h" #include "QUICTransportParameters.h" -#include "QUICConfig.h" static constexpr char tag[] = "quic_stream_manager"; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 535e495a500..d427d9d2ccb 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -24,7 +24,8 @@ #include #include "QUICTypes.h" #include "QUICIntUtil.h" -#include "QUICConfig.h" + +uint8_t QUICConnectionId::SCID_LEN = 0; // TODO: move to somewhere in lib/ts/ static int @@ -360,13 +361,13 @@ QUICConnectionId::randomize() { std::random_device rnd; uint32_t x; - for (int i = QUICConfigParams::scid_len(); i >= 0; --i) { + for (int i = QUICConnectionId::SCID_LEN; i >= 0; --i) { if (i % 4 == 0) { x = rnd(); } this->_id[i] = (x >> (8 * (i % 4))) & 0xFF; } - this->_len = QUICConfigParams::scid_len(); + this->_len = QUICConnectionId::SCID_LEN; } uint64_t @@ -466,7 +467,7 @@ QUICInvariants::dcid(QUICConnectionId &dst, const uint8_t *buf, uint64_t buf_len dcid_offset = QUICInvariants::LH_DCID_OFFSET; } else { // remote dcil is local scil - dcid_len = QUICConfigParams::scid_len(); + dcid_len = QUICConnectionId::SCID_LEN; dcid_offset = QUICInvariants::SH_DCID_OFFSET; } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 959e172f6b0..7a1e8de826e 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -220,6 +220,8 @@ using QUICStreamErrorUPtr = std::unique_ptr; class QUICConnectionId { public: + static uint8_t SCID_LEN; + static const int MAX_LENGTH = 18; static const size_t MAX_HEX_STR_LENGTH = MAX_LENGTH * 2 + 1; static QUICConnectionId ZERO(); From 0baa9ce6ccfe754f7091e33367521fe266f4a2ea Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 20 Nov 2018 00:33:44 +0900 Subject: [PATCH 0918/1313] Fix build error in unit tests --- iocore/net/quic/test/event_processor_main.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/test/event_processor_main.cc b/iocore/net/quic/test/event_processor_main.cc index 7294c8f4f11..a56e62023d8 100644 --- a/iocore/net/quic/test/event_processor_main.cc +++ b/iocore/net/quic/test/event_processor_main.cc @@ -54,7 +54,7 @@ struct EventProcessorListener : Catch::TestEventListenerBase { QUICConfig::startup(); - ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + ink_event_system_init(EVENT_SYSTEM_MODULE_PUBLIC_VERSION); eventProcessor.start(TEST_THREADS); Thread *main_thread = new EThread; From fe54897e3ee9fac3473af1da0c67ff0270217369 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 20 Nov 2018 09:30:48 +0800 Subject: [PATCH 0919/1313] QUIC: Fixes receive side delay --- iocore/net/QUICPacketHandler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index d6837312b38..a0ca2c42472 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -340,7 +340,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) qe->init(qc, static_cast(udp_packet)); // Push the packet into QUICPollCont get_QUICPollCont(eth)->inQueue.push(qe); - + get_NetHandler(eth)->signalActivity(); return; } From d64f8c6e96961915de13a3e197ae50bba90aa4f7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 20 Nov 2018 14:29:16 +0900 Subject: [PATCH 0920/1313] Improve performance --- iocore/net/QUICNetVConnection.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a0285bda2f3..d873c836fcc 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -65,8 +65,8 @@ static constexpr uint32_t MAX_PACKET_OVERHEAD = 62; // Max long header len static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; // static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; -static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(20); -static constexpr uint32_t PACKET_PER_EVENT = 32; +static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(2); +static constexpr uint32_t PACKET_PER_EVENT = 256; static constexpr uint32_t MAX_CONSECUTIVE_STREAMS = 8; //< Interrupt sending STREAM frames to send ACK frame static constexpr uint32_t MAX_PACKETS_WITHOUT_SRC_ADDR_VARIDATION = 3; From 5d20eee5ed58c08237bece79ec546a712bfa375d Mon Sep 17 00:00:00 2001 From: Bryan Call Date: Tue, 13 Nov 2018 16:03:24 +0900 Subject: [PATCH 0921/1313] Changed the random number generator for QUICPathValidator --- iocore/net/quic/QUICPathValidator.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index eafc54ea532..8ed8e66839b 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -49,9 +49,12 @@ QUICPathValidator::validate() void QUICPathValidator::_generate_challenge() { - for (int i = countof(this->_outgoing_challenge) - 1; i >= 0; --i) { - // TODO Randomize challenge data - this->_outgoing_challenge[i] = i; + size_t seed = + std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); + std::minstd_rand random(seed); + + for (auto &i : this->_outgoing_challenge) { + i = random(); } this->_has_outgoing_challenge = 3; } From 880e9f6732e2ed09706b0d504684924647b3287c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 21 Nov 2018 10:08:08 +0900 Subject: [PATCH 0922/1313] Signal UDP activity --- iocore/net/QUICPacketHandler.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index a0ca2c42472..a97a871e10a 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -100,6 +100,7 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo // NOTE: packet will be enqueued to udpOutQueue of UDPNetHandler udp_con->send(c, udp_packet); + get_UDPNetHandler(static_cast(udp_con)->ethread)->signalActivity(); } void @@ -132,6 +133,7 @@ QUICPacketHandler::_send_packet(Continuation *c, QUICNetVConnection *vc, Ptrsend(c, udp_packet); + get_UDPNetHandler(static_cast(udp_con)->ethread)->signalActivity(); } // From f3d3bbd92c01c3973cd3b2a03718464a52f6feac Mon Sep 17 00:00:00 2001 From: Walter Karas Date: Tue, 20 Nov 2018 20:32:10 -0600 Subject: [PATCH 0923/1313] Avoid doubling the size of ats_unique_buf instances. It is not necessary to have a pointer to the ats_free() function in each instance. http://coliru.stacked-crooked.com/a/bf9a683da11820c2 --- include/tscore/ink_memory.h | 9 ++++++++- src/tscore/ink_memory.cc | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/tscore/ink_memory.h b/include/tscore/ink_memory.h index 3b2a76bf776..29a2cfdd530 100644 --- a/include/tscore/ink_memory.h +++ b/include/tscore/ink_memory.h @@ -600,7 +600,14 @@ path_join(ats_scoped_str const &lhs, ats_scoped_str const &rhs) return x.release(); } -using ats_unique_buf = std::unique_ptr; +struct ats_unique_buf_deleter { + void + operator()(uint8_t *p) + { + ats_free(p); + } +}; +using ats_unique_buf = std::unique_ptr; ats_unique_buf ats_unique_malloc(size_t size); #endif /* __cplusplus */ diff --git a/src/tscore/ink_memory.cc b/src/tscore/ink_memory.cc index 173ce38fe02..604ce416504 100644 --- a/src/tscore/ink_memory.cc +++ b/src/tscore/ink_memory.cc @@ -164,7 +164,7 @@ ats_mallopt(int param ATS_UNUSED, int value ATS_UNUSED) ats_unique_buf ats_unique_malloc(size_t size) { - return ats_unique_buf(reinterpret_cast(ats_malloc(size)), [](void *p) { ats_free(p); }); + return ats_unique_buf(static_cast(ats_malloc(size))); } int From 13064f8f4e8989166e8edd3e631a93e3f5b6ac0e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 21 Nov 2018 18:11:06 +0900 Subject: [PATCH 0924/1313] Fix build issues --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICFrame.h | 12 ++++++------ iocore/net/quic/QUICPacket.cc | 2 +- iocore/net/quic/QUICPacket.h | 20 +++++++++----------- iocore/net/quic/QUICPacketReceiveQueue.cc | 2 +- iocore/net/quic/QUICPacketReceiveQueue.h | 2 +- iocore/net/quic/QUICPathValidator.cc | 1 + iocore/net/quic/test/test_QUICFrame.cc | 4 ++-- iocore/net/quic/test/test_QUICPacket.cc | 16 ++++++++++++---- proxy/hq/HQFrame.h | 4 ++-- 11 files changed, 37 insertions(+), 30 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 8349c338fc3..0dff55ea208 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -358,7 +358,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet(); QUICStatelessResetToken _reset_token; - ats_unique_buf _retry_token = {nullptr, [](void *p) { ats_free(p); }}; + ats_unique_buf _retry_token = {nullptr}; size_t _retry_token_len = 0; // This is for limiting number of packets that a server can send without path validation diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index d873c836fcc..cea28277aed 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1441,7 +1441,7 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi switch (type) { case QUICPacketType::INITIAL: { QUICConnectionId dcid = this->_peer_quic_connection_id; - ats_unique_buf token = {nullptr, [](void *p) { ats_free(p); }}; + ats_unique_buf token = {nullptr}; size_t token_len = 0; if (this->netvc_context == NET_VCONNECTION_OUT) { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 721112a6d32..b42100997a9 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -102,7 +102,7 @@ class QUICStreamFrame : public QUICFrame LINK(QUICStreamFrame, link); private: - ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; + ats_unique_buf _data = {nullptr}; size_t _data_len = 0; QUICStreamId _stream_id = 0; QUICOffset _offset = 0; @@ -144,7 +144,7 @@ class QUICCryptoFrame : public QUICFrame private: QUICOffset _offset = 0; uint64_t _data_len = 0; - ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; + ats_unique_buf _data = {nullptr}; size_t _get_offset_field_offset() const; size_t _get_length_field_offset() const; @@ -657,7 +657,7 @@ class QUICPathChallengeFrame : public QUICFrame private: const size_t _data_offset() const; - ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; + ats_unique_buf _data = {nullptr}; }; // @@ -682,7 +682,7 @@ class QUICPathResponseFrame : public QUICFrame private: const size_t _data_offset() const; - ats_unique_buf _data = {nullptr, [](void *p) { ats_free(p); }}; + ats_unique_buf _data = {nullptr}; }; // @@ -712,7 +712,7 @@ class QUICNewTokenFrame : public QUICFrame size_t _get_token_field_offset() const; uint64_t _token_length = 0; - ats_unique_buf _token = {nullptr, [](void *p) { ats_free(p); }}; + ats_unique_buf _token = {nullptr}; }; // @@ -758,7 +758,7 @@ class QUICRetransmissionFrame : public QUICFrame private: QUICFrameUPtr _frame = QUICFrameUPtr(nullptr, nullptr); - ats_unique_buf _data = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); + ats_unique_buf _data = ats_unique_buf(nullptr); QUICPacketType _packet_type; }; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index a5a5edb1d94..f9bf099de33 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -1225,7 +1225,7 @@ QUICPacketUPtr QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUICConnectionId scid) { size_t len = sizeof(QUICVersion) * countof(QUIC_SUPPORTED_VERSIONS); - ats_unique_buf versions(reinterpret_cast(ats_malloc(len)), [](void *p) { ats_free(p); }); + ats_unique_buf versions(reinterpret_cast(ats_malloc(len))); uint8_t *p = versions.get(); size_t n; diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 6707113a759..ddb5dfae452 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -184,12 +184,12 @@ class QUICPacketHeader const IpEndpoint _from = {}; // These two are used only if the instance was created with a buffer - ats_unique_buf _buf = {nullptr, [](void *p) { ats_free(p); }}; + 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, [](void *p) { ats_free(p); }); + ats_unique_buf _payload = ats_unique_buf(nullptr); QUICPacketType _type = QUICPacketType::UNINITIALIZED; QUICKeyPhase _key_phase = QUICKeyPhase::INITIAL; QUICConnectionId _connection_id = QUICConnectionId::ZERO(); @@ -209,8 +209,7 @@ class QUICPacketLongHeader : public QUICPacketHeader QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base); QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, - size_t len, ats_unique_buf token = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }), - size_t token_len = 0); + size_t len, ats_unique_buf token = ats_unique_buf(nullptr), size_t token_len = 0); QUICPacketLongHeader(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); @@ -251,10 +250,10 @@ class QUICPacketLongHeader : public QUICPacketHeader QUICPacketNumber _packet_number; 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, [](void *p) { ats_free(p); }); //< INITIAL packet only + 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; }; @@ -391,7 +390,7 @@ class QUICPacket : public QUICTrackablePacket private: QUICPacketHeaderUPtr _header = QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header); - ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }); + ats_unique_buf _payload = ats_unique_buf(nullptr); size_t _payload_size = 0; bool _is_retransmittable = false; bool _is_probing_packet = false; @@ -444,8 +443,7 @@ class QUICPacketFactory QUICPacketUPtr create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable, bool probing, std::vector &frame, - ats_unique_buf token = ats_unique_buf(nullptr, [](void *p) { ats_free(p); }), - size_t token_len = 0); + 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, bool retransmittable, bool probing, std::vector &frame); diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 9c572120f73..0fb445c2dfe 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -100,7 +100,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) } } - ats_unique_buf pkt = {nullptr, [](void *p) { ats_free(p); }}; + ats_unique_buf pkt = {nullptr}; size_t pkt_len = 0; bool has_packet_number = true; QUICPacketType type = QUICPacketType::UNINITIALIZED; diff --git a/iocore/net/quic/QUICPacketReceiveQueue.h b/iocore/net/quic/QUICPacketReceiveQueue.h index 6d3d6a92f4c..8473ab76630 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.h +++ b/iocore/net/quic/QUICPacketReceiveQueue.h @@ -44,7 +44,7 @@ class QUICPacketReceiveQueue QUICPacketNumberProtector &_pn_protector; QUICPacketNumber _largest_received_packet_number = 0; // FIXME: workaround code for coalescing packets - ats_unique_buf _payload = {nullptr, [](void *p) { ats_free(p); }}; + ats_unique_buf _payload = {nullptr}; size_t _payload_len = 0; size_t _offset = 0; IpEndpoint _from; diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index 8ed8e66839b..8cac22a191a 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -21,6 +21,7 @@ limitations under the License. */ +#include #include "QUICPathValidator.h" bool diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 5e430338e6e..3d63261b60b 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1374,8 +1374,8 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); std::vector frames; - QUICPacketUPtr packet = factory.create_protected_packet({reinterpret_cast("\x01\x02\x03\x04"), 4}, 0, - {nullptr, [](void *p) { ats_free(p); }}, 0, true, false, frames); + QUICPacketUPtr packet = factory.create_protected_packet({reinterpret_cast("\x01\x02\x03\x04"), 4}, 0, {nullptr}, + 0, true, false, frames); SECTION("STREAM frame split") { size_t len; diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 39813766ec8..f6e1c1f9f89 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -38,8 +38,10 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0x00, 0x00, 0x00, 0x08, // Supported Version 1 0x00, 0x00, 0x00, 0x09, // Supported Version 1 }; + ats_unique_buf uinput = ats_unique_malloc(sizeof(input)); + memcpy(uinput.get(), input, sizeof(input)); - QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, std::move(uinput), sizeof(input), 0); CHECK(header->size() == 22); CHECK(header->packet_size() == 30); CHECK(header->type() == QUICPacketType::VERSION_NEGOTIATION); @@ -64,8 +66,10 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0xC1, 0x23, 0x45, 0x67, // Packet number 0xff, 0xff, // Payload (dummy) }; + ats_unique_buf uinput = ats_unique_malloc(sizeof(input)); + memcpy(uinput.get(), input, sizeof(input)); - QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, std::move(uinput), sizeof(input), 0); CHECK(header->size() == sizeof(input) - 2); // Packet Length - Payload Length CHECK(header->packet_size() == sizeof(input)); CHECK(header->type() == QUICPacketType::INITIAL); @@ -91,10 +95,12 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Retry Token 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, }; + ats_unique_buf uinput = ats_unique_malloc(sizeof(input)); + memcpy(uinput.get(), input, sizeof(input)); const uint8_t retry_token[] = {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0}; - QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, std::move(uinput), sizeof(input), 0); CHECK(header->size() == sizeof(input) - 16); // Packet Length - Payload Length (Retry Token) CHECK(header->packet_size() == sizeof(input)); CHECK(header->type() == QUICPacketType::RETRY); @@ -216,8 +222,10 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") 0xC1, 0x23, 0x45, 0x67, // Packet number 0xff, 0xff, // Payload (dummy) }; + ats_unique_buf uinput = ats_unique_malloc(sizeof(input)); + memcpy(uinput.get(), input, sizeof(input)); - QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, {const_cast(input), [](void *p) {}}, sizeof(input), 0); + QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, std::move(uinput), sizeof(input), 0); CHECK(header->size() == 23); CHECK(header->packet_size() == 25); CHECK(header->has_key_phase() == true); diff --git a/proxy/hq/HQFrame.h b/proxy/hq/HQFrame.h index b786d753975..6edd2074e85 100644 --- a/proxy/hq/HQFrame.h +++ b/proxy/hq/HQFrame.h @@ -85,7 +85,7 @@ class HQDataFrame : public HQFrame private: const uint8_t *_payload = nullptr; - ats_unique_buf _payload_uptr = {nullptr, [](void *p) { ats_free(p); }}; + ats_unique_buf _payload_uptr = {nullptr}; size_t _payload_len = 0; }; @@ -108,7 +108,7 @@ class HQHeadersFrame : public HQFrame private: const uint8_t *_header_block = nullptr; - ats_unique_buf _header_block_uptr = {nullptr, [](void *p) { ats_free(p); }}; + ats_unique_buf _header_block_uptr = {nullptr}; size_t _header_block_len = 0; }; From 7d2c1a2409a7c7800ea99725d64ffe1b87387015 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 22 Nov 2018 10:56:49 +0900 Subject: [PATCH 0925/1313] Fix CID randomization The last byte was not initialized correctly --- iocore/net/quic/QUICTypes.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index d427d9d2ccb..51b0aab7f02 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -360,8 +360,8 @@ void QUICConnectionId::randomize() { std::random_device rnd; - uint32_t x; - for (int i = QUICConnectionId::SCID_LEN; i >= 0; --i) { + uint32_t x = rnd(); + for (int i = QUICConnectionId::SCID_LEN - 1; i >= 0; --i) { if (i % 4 == 0) { x = rnd(); } From a88e26fbe8444905a44261b985ecc9bb1157959a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 19 Nov 2018 16:54:44 +0900 Subject: [PATCH 0926/1313] Keep frame id and frame generator instead of actual frame instance --- iocore/net/P_QUICNetVConnection.h | 6 +- iocore/net/QUICNetVConnection.cc | 12 +- iocore/net/quic/QUICFrame.cc | 203 ++++++++++-------- iocore/net/quic/QUICFrame.h | 157 +++++++++----- iocore/net/quic/QUICFrameGenerator.h | 4 +- iocore/net/quic/QUICLossDetector.cc | 12 +- iocore/net/quic/QUICPacket.cc | 20 +- iocore/net/quic/QUICPacket.h | 20 +- iocore/net/quic/test/test_QUICFrame.cc | 12 +- iocore/net/quic/test/test_QUICLossDetector.cc | 2 +- .../net/quic/test/test_QUICPacketFactory.cc | 2 +- .../quic/test/test_QUICVersionNegotiator.cc | 12 +- 12 files changed, 264 insertions(+), 198 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 0dff55ea208..27c6919076f 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -297,13 +297,13 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub uint64_t _maximum_stream_frame_data_size(); void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr &frame, - std::vector &frames); + std::vector &frames); QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size); void _packetize_closing_frame(); QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, bool probing, - std::vector &frames, QUICPacketType type = QUICPacketType::UNINITIALIZED); + std::vector &frames, QUICPacketType type = QUICPacketType::UNINITIALIZED); QUICPacketUPtr _build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing, - std::vector &frames); + std::vector &frames); QUICConnectionErrorUPtr _recv_and_ack(QUICPacket &packet, bool *has_non_probing_frame = nullptr); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index cea28277aed..2f07346b905 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1186,7 +1186,7 @@ QUICNetVConnection::_state_closing_send_packet() void QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr &frame, - std::vector &frames) + std::vector &frames) { size_t l = 0; frame->store(buf.get() + offset, &l, max_frame_size); @@ -1203,7 +1203,7 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t & QUICConDebug("[TX] %s", msg); } - frames.push_back(std::move(frame)); + frames.emplace_back(frame->id(), frame->generated_by()); } QUICPacketUPtr @@ -1229,7 +1229,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); - std::vector frames; + std::vector frames; // CRYPTO frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); @@ -1375,7 +1375,7 @@ QUICNetVConnection::_packetize_closing_frame() size_t len = 0; uint64_t max_frame_size = static_cast(max_size); - std::vector frames; + std::vector frames; this->_store_frame(buf, len, max_frame_size, frame, frames); QUICEncryptionLevel level = this->_hs_protocol->current_encryption_level(); @@ -1427,14 +1427,14 @@ QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_fram QUICPacketUPtr QUICNetVConnection::_build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing, - std::vector &frames) + std::vector &frames) { return this->_build_packet(std::move(buf), len, retransmittable, probing, frames, QUICTypeUtil::packet_type(level)); } QUICPacketUPtr QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, bool probing, - std::vector &frames, QUICPacketType type) + std::vector &frames, QUICPacketType type) { QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 5c381b3bc24..b6ca619a62d 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -64,8 +64,14 @@ QUICFrame::is_probing_frame() const return false; } +QUICFrameId +QUICFrame::id() const +{ + return this->_id; +} + QUICFrameGenerator * -QUICFrame::generated_by() const +QUICFrame::generated_by() { return this->_owner; } @@ -108,8 +114,8 @@ QUICFrame::split(size_t size) // QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, - QUICFrameGenerator *owner) - : QUICFrame(owner) + QUICFrameId id, QUICFrameGenerator *owner) + : QUICFrame(id, owner) { this->_data = std::move(data); this->_data_len = data_len; @@ -151,8 +157,8 @@ QUICStreamFrame::split(size_t size) this->reset(nullptr, 0); QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) - QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin, this->_owner); + new (frame) QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin, this->_id, + this->_owner); return frame; } @@ -161,7 +167,7 @@ QUICFrameUPtr QUICStreamFrame::clone() const { return QUICFrameFactory::create_stream_frame(this->data(), this->data_length(), this->stream_id(), this->offset(), - this->has_fin_flag(), this->_owner); + this->has_fin_flag(), this->_id, this->_owner); } QUICFrameType @@ -403,8 +409,8 @@ QUICStreamFrame::_get_length_field_len() const // CRYPTO frame // -QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffset offset, QUICFrameGenerator *owner) - : QUICFrame(owner) +QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) + : QUICFrame(id, owner) { this->_data = std::move(data); this->_data_len = data_len; @@ -435,7 +441,7 @@ QUICCryptoFrame::split(size_t size) this->reset(nullptr, 0); QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); - new (frame) QUICCryptoFrame(std::move(buf2), buf2_len, this->offset() + this->data_length(), this->_owner); + new (frame) QUICCryptoFrame(std::move(buf2), buf2_len, this->offset() + this->data_length(), this->_id, this->_owner); return frame; } @@ -443,7 +449,7 @@ QUICCryptoFrame::split(size_t size) QUICFrameUPtr QUICCryptoFrame::clone() const { - return QUICFrameFactory::create_crypto_frame(this->data(), this->data_length(), this->offset(), this->_owner); + return QUICFrameFactory::create_crypto_frame(this->data(), this->data_length(), this->offset(), this->_id, this->_owner); } QUICFrameType @@ -577,9 +583,9 @@ QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) this->reset(buf, len); } -QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, +QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameId id, QUICFrameGenerator *owner) - : QUICFrame(owner) + : QUICFrame(id, owner) { this->_largest_acknowledged = largest_acknowledged; this->_ack_delay = ack_delay; @@ -619,7 +625,7 @@ QUICFrameUPtr QUICAckFrame::clone() const { std::unique_ptr newframe = QUICFrameFactory::create_ack_frame( - this->largest_acknowledged(), this->ack_delay(), this->ack_block_section()->first_ack_block(), this->_owner); + this->largest_acknowledged(), this->ack_delay(), this->ack_block_section()->first_ack_block(), this->_id, this->_owner); for (auto &ack_block : *this->ack_block_section()) { newframe->ack_block_section()->add_ack_block({ack_block.gap(), ack_block.length()}); @@ -1084,16 +1090,17 @@ QUICAckFrame::EcnSection::ecn_ce_count() const // RST_STREAM frame // -QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, +QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameId id, QUICFrameGenerator *owner) - : QUICFrame(owner), _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset) + : QUICFrame(id, owner), _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset) { } QUICFrameUPtr QUICRstStreamFrame::clone() const { - return QUICFrameFactory::create_rst_stream_frame(this->stream_id(), this->error_code(), this->final_offset(), this->_owner); + return QUICFrameFactory::create_rst_stream_frame(this->stream_id(), this->error_code(), this->final_offset(), this->_id, + this->_owner); } QUICFrameType @@ -1211,7 +1218,7 @@ QUICRstStreamFrame::_get_final_offset_field_length() const QUICFrameUPtr QUICPingFrame::clone() const { - return QUICFrameFactory::create_ping_frame(this->_owner); + return QUICFrameFactory::create_ping_frame(this->_id, this->_owner); } QUICFrameType @@ -1289,8 +1296,8 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len, size_t limit) const // CONNECTION_CLOSE frame // QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, - const char *reason_phrase, QUICFrameGenerator *owner) - : QUICFrame(owner), + const char *reason_phrase, QUICFrameId id, QUICFrameGenerator *owner) + : QUICFrame(id, owner), _error_code(error_code), _frame_type(frame_type), _reason_phrase_length(reason_phrase_length), @@ -1302,7 +1309,7 @@ QUICFrameUPtr QUICConnectionCloseFrame::clone() const { return QUICFrameFactory::create_connection_close_frame(this->error_code(), this->frame_type(), this->reason_phrase_length(), - this->reason_phrase(), this->_owner); + this->reason_phrase(), this->_id, this->_owner); } QUICFrameType @@ -1481,8 +1488,8 @@ QUICConnectionCloseFrame::_get_reason_phrase_field_offset() const // APPLICATION_CLOSE frame // QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, - const char *reason_phrase, QUICFrameGenerator *owner) - : QUICFrame(owner) + const char *reason_phrase, QUICFrameId id, QUICFrameGenerator *owner) + : QUICFrame(id, owner) { this->_error_code = error_code; this->_reason_phrase_length = reason_phrase_length; @@ -1493,7 +1500,7 @@ QUICFrameUPtr QUICApplicationCloseFrame::clone() const { return QUICFrameFactory::create_application_close_frame(this->error_code(), this->reason_phrase_length(), this->reason_phrase(), - this->_owner); + this->_id, this->_owner); } QUICFrameType @@ -1614,7 +1621,7 @@ QUICApplicationCloseFrame::_get_reason_phrase_field_offset() const // // MAX_DATA frame // -QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, QUICFrameGenerator *owner) : QUICFrame(owner) +QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, QUICFrameId id, QUICFrameGenerator *owner) : QUICFrame(id, owner) { this->_maximum_data = maximum_data; } @@ -1622,7 +1629,7 @@ QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, QUICFrameGenerator *ow QUICFrameUPtr QUICMaxDataFrame::clone() const { - return QUICFrameFactory::create_max_data_frame(this->maximum_data(), this->_owner); + return QUICFrameFactory::create_max_data_frame(this->maximum_data(), this->_id, this->_owner); } QUICFrameType @@ -1690,8 +1697,9 @@ QUICMaxDataFrame::_get_max_data_field_length() const // // MAX_STREAM_DATA // -QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameGenerator *owner) - : QUICFrame(owner) +QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameId id, + QUICFrameGenerator *owner) + : QUICFrame(id, owner) { this->_stream_id = stream_id; this->_maximum_stream_data = maximum_stream_data; @@ -1700,7 +1708,7 @@ QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t QUICFrameUPtr QUICMaxStreamDataFrame::clone() const { - return QUICFrameFactory::create_max_stream_data_frame(this->stream_id(), this->maximum_stream_data(), this->_owner); + return QUICFrameFactory::create_max_stream_data_frame(this->stream_id(), this->maximum_stream_data(), this->_id, this->_owner); } QUICFrameType @@ -1800,7 +1808,8 @@ QUICMaxStreamDataFrame::_get_max_stream_data_field_length() const // // MAX_STREAM_ID // -QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICFrameGenerator *owner) : QUICFrame(owner) +QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICFrameId id, QUICFrameGenerator *owner) + : QUICFrame(id, owner) { this->_maximum_stream_id = maximum_stream_id; } @@ -1808,7 +1817,7 @@ QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICF QUICFrameUPtr QUICMaxStreamIdFrame::clone() const { - return QUICFrameFactory::create_max_stream_id_frame(this->maximum_stream_id(), this->_owner); + return QUICFrameFactory::create_max_stream_id_frame(this->maximum_stream_id(), this->_id, this->_owner); } QUICFrameType @@ -1872,7 +1881,7 @@ QUICMaxStreamIdFrame::_get_max_stream_id_field_length() const QUICFrameUPtr QUICBlockedFrame::clone() const { - return QUICFrameFactory::create_blocked_frame(this->offset(), this->_owner); + return QUICFrameFactory::create_blocked_frame(this->offset(), this->_id, this->_owner); } QUICFrameType @@ -1938,7 +1947,7 @@ QUICBlockedFrame::_get_offset_field_length() const QUICFrameUPtr QUICStreamBlockedFrame::clone() const { - return QUICFrameFactory::create_stream_blocked_frame(this->stream_id(), this->offset(), this->_owner); + return QUICFrameFactory::create_stream_blocked_frame(this->stream_id(), this->offset(), this->_id, this->_owner); } QUICFrameType @@ -2031,7 +2040,7 @@ QUICStreamBlockedFrame::_get_offset_field_length() const QUICFrameUPtr QUICStreamIdBlockedFrame::clone() const { - return QUICFrameFactory::create_stream_id_blocked_frame(this->stream_id(), this->_owner); + return QUICFrameFactory::create_stream_id_blocked_frame(this->stream_id(), this->_id, this->_owner); } QUICFrameType @@ -2099,7 +2108,7 @@ QUICNewConnectionIdFrame::clone() const { // FIXME: Connection ID and Stateless rese token have to be the same return QUICFrameFactory::create_new_connection_id_frame(this->sequence(), this->connection_id(), this->stateless_reset_token(), - this->_owner); + this->_id, this->_owner); } QUICFrameType @@ -2214,15 +2223,16 @@ QUICNewConnectionIdFrame::_get_connection_id_field_offset() const // STOP_SENDING frame // -QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameGenerator *owner) - : QUICFrame(owner), _stream_id(stream_id), _error_code(error_code) +QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameId id, + QUICFrameGenerator *owner) + : QUICFrame(id, owner), _stream_id(stream_id), _error_code(error_code) { } QUICFrameUPtr QUICStopSendingFrame::clone() const { - return QUICFrameFactory::create_stop_sending_frame(this->stream_id(), this->error_code(), this->_owner); + return QUICFrameFactory::create_stop_sending_frame(this->stream_id(), this->error_code(), this->_id, this->_owner); } QUICFrameType @@ -2305,7 +2315,7 @@ QUICStopSendingFrame::_get_error_code_field_offset() const QUICFrameUPtr QUICPathChallengeFrame::clone() const { - return QUICFrameFactory::create_path_challenge_frame(this->data(), this->_owner); + return QUICFrameFactory::create_path_challenge_frame(this->data(), this->_id, this->_owner); } QUICFrameType @@ -2367,7 +2377,7 @@ QUICPathChallengeFrame::_data_offset() const QUICFrameUPtr QUICPathResponseFrame::clone() const { - return QUICFrameFactory::create_path_response_frame(this->data(), this->_owner); + return QUICFrameFactory::create_path_response_frame(this->data(), this->_id, this->_owner); } QUICFrameType @@ -2432,7 +2442,7 @@ QUICNewTokenFrame::clone() const ats_unique_buf buf = ats_unique_malloc(this->token_length()); memcpy(buf.get(), this->token(), this->token_length()); - return QUICFrameFactory::create_new_token_frame(std::move(buf), this->token_length(), this->_owner); + return QUICFrameFactory::create_new_token_frame(std::move(buf), this->token_length(), this->_id, this->_owner); } QUICFrameType @@ -2527,7 +2537,7 @@ QUICNewTokenFrame::_get_token_field_offset() const QUICFrameUPtr QUICRetireConnectionIdFrame::clone() const { - return QUICFrameFactory::create_retire_connection_id_frame(this->seq_num()); + return QUICFrameFactory::create_retire_connection_id_frame(this->seq_num(), this->_id, this->_owner); } QUICFrameType @@ -2596,7 +2606,7 @@ QUICRetireConnectionIdFrame::_get_seq_num_field_length() const // QUICRetransmissionFrame // QUICRetransmissionFrame::QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet) - : QUICFrame(original_frame->generated_by()), _packet_type(original_packet.type()) + : QUICFrame(original_frame->id(), original_frame->generated_by()), _packet_type(original_packet.type()) { this->_frame = std::move(original_frame); } @@ -2780,24 +2790,25 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) QUICStreamFrameUPtr QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, - QUICFrameGenerator *owner) + QUICFrameId id, QUICFrameGenerator *owner) { ats_unique_buf buf = ats_unique_malloc(data_len); memcpy(buf.get(), data, data_len); QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last, owner); + new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last, id, owner); return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); } QUICCryptoFrameUPtr -QUICFrameFactory::create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, QUICFrameGenerator *owner) +QUICFrameFactory::create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, QUICFrameId id, + QUICFrameGenerator *owner) { ats_unique_buf buf = ats_unique_malloc(data_len); memcpy(buf.get(), data, data_len); QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); - new (frame) QUICCryptoFrame(std::move(buf), data_len, offset, owner); + new (frame) QUICCryptoFrame(std::move(buf), data_len, offset, id, owner); return QUICCryptoFrameUPtr(frame, &QUICFrameDeleter::delete_crypto_frame); } @@ -2814,176 +2825,180 @@ QUICFrameFactory::split_frame(QUICFrame *frame, size_t size) std::unique_ptr QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, - QUICFrameGenerator *owner) + QUICFrameId id, QUICFrameGenerator *owner) { QUICAckFrame *frame = quicAckFrameAllocator.alloc(); - new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block, owner); + new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_ack_frame); } std::unique_ptr QUICFrameFactory::create_connection_close_frame(uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length, - const char *reason_phrase, QUICFrameGenerator *owner) + const char *reason_phrase, QUICFrameId id, QUICFrameGenerator *owner) { QUICConnectionCloseFrame *frame = quicConnectionCloseFrameAllocator.alloc(); - new (frame) QUICConnectionCloseFrame(error_code, frame_type, reason_phrase_length, reason_phrase, owner); + new (frame) QUICConnectionCloseFrame(error_code, frame_type, reason_phrase_length, reason_phrase, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); } std::unique_ptr -QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error, QUICFrameGenerator *owner) +QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error, QUICFrameId id, QUICFrameGenerator *owner) { ink_assert(error->cls == QUICErrorClass::TRANSPORT); if (error->msg) { - return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type(), strlen(error->msg), error->msg, owner); + return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type(), strlen(error->msg), error->msg, id, + owner); } else { - return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type(), 0, nullptr, owner); + return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type(), 0, nullptr, id, owner); } } std::unique_ptr QUICFrameFactory::create_application_close_frame(QUICAppErrorCode error_code, uint16_t reason_phrase_length, - const char *reason_phrase, QUICFrameGenerator *owner) + const char *reason_phrase, QUICFrameId id, QUICFrameGenerator *owner) { QUICApplicationCloseFrame *frame = quicApplicationCloseFrameAllocator.alloc(); - new (frame) QUICApplicationCloseFrame(error_code, reason_phrase_length, reason_phrase, owner); + new (frame) QUICApplicationCloseFrame(error_code, reason_phrase_length, reason_phrase, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); } std::unique_ptr -QUICFrameFactory::create_application_close_frame(QUICConnectionErrorUPtr error, QUICFrameGenerator *owner) +QUICFrameFactory::create_application_close_frame(QUICConnectionErrorUPtr error, QUICFrameId id, QUICFrameGenerator *owner) { ink_assert(error->cls == QUICErrorClass::APPLICATION); if (error->msg) { - return QUICFrameFactory::create_application_close_frame(error->code, strlen(error->msg), error->msg, owner); + return QUICFrameFactory::create_application_close_frame(error->code, strlen(error->msg), error->msg, id, owner); } else { - return QUICFrameFactory::create_application_close_frame(error->code, 0, nullptr, owner); + return QUICFrameFactory::create_application_close_frame(error->code, 0, nullptr, id, owner); } } std::unique_ptr -QUICFrameFactory::create_max_data_frame(uint64_t maximum_data, QUICFrameGenerator *owner) +QUICFrameFactory::create_max_data_frame(uint64_t maximum_data, QUICFrameId id, QUICFrameGenerator *owner) { QUICMaxDataFrame *frame = quicMaxDataFrameAllocator.alloc(); - new (frame) QUICMaxDataFrame(maximum_data, owner); + new (frame) QUICMaxDataFrame(maximum_data, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_data_frame); } std::unique_ptr -QUICFrameFactory::create_max_stream_data_frame(QUICStreamId stream_id, uint64_t maximum_data, QUICFrameGenerator *owner) +QUICFrameFactory::create_max_stream_data_frame(QUICStreamId stream_id, uint64_t maximum_data, QUICFrameId id, + QUICFrameGenerator *owner) { QUICMaxStreamDataFrame *frame = quicMaxStreamDataFrameAllocator.alloc(); - new (frame) QUICMaxStreamDataFrame(stream_id, maximum_data, owner); + new (frame) QUICMaxStreamDataFrame(stream_id, maximum_data, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); } std::unique_ptr -QUICFrameFactory::create_max_stream_id_frame(QUICStreamId maximum_stream_id, QUICFrameGenerator *owner) +QUICFrameFactory::create_max_stream_id_frame(QUICStreamId maximum_stream_id, QUICFrameId id, QUICFrameGenerator *owner) { QUICMaxStreamIdFrame *frame = quicMaxStreamIdFrameAllocator.alloc(); - new (frame) QUICMaxStreamIdFrame(maximum_stream_id, owner); + new (frame) QUICMaxStreamIdFrame(maximum_stream_id, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_id_frame); } std::unique_ptr -QUICFrameFactory::create_ping_frame(QUICFrameGenerator *owner) +QUICFrameFactory::create_ping_frame(QUICFrameId id, QUICFrameGenerator *owner) { QUICPingFrame *frame = quicPingFrameAllocator.alloc(); - new (frame) QUICPingFrame(owner); + new (frame) QUICPingFrame(id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_ping_frame); } std::unique_ptr -QUICFrameFactory::create_path_challenge_frame(const uint8_t *data, QUICFrameGenerator *owner) +QUICFrameFactory::create_path_challenge_frame(const uint8_t *data, QUICFrameId id, QUICFrameGenerator *owner) { ats_unique_buf buf = ats_unique_malloc(QUICPathChallengeFrame::DATA_LEN); memcpy(buf.get(), data, QUICPathChallengeFrame::DATA_LEN); QUICPathChallengeFrame *frame = quicPathChallengeFrameAllocator.alloc(); - new (frame) QUICPathChallengeFrame(std::move(buf), owner); + new (frame) QUICPathChallengeFrame(std::move(buf), id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_challenge_frame); } std::unique_ptr -QUICFrameFactory::create_path_response_frame(const uint8_t *data, QUICFrameGenerator *owner) +QUICFrameFactory::create_path_response_frame(const uint8_t *data, QUICFrameId id, QUICFrameGenerator *owner) { ats_unique_buf buf = ats_unique_malloc(QUICPathResponseFrame::DATA_LEN); memcpy(buf.get(), data, QUICPathResponseFrame::DATA_LEN); QUICPathResponseFrame *frame = quicPathResponseFrameAllocator.alloc(); - new (frame) QUICPathResponseFrame(std::move(buf), owner); + new (frame) QUICPathResponseFrame(std::move(buf), id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_response_frame); } std::unique_ptr -QUICFrameFactory::create_blocked_frame(QUICOffset offset, QUICFrameGenerator *owner) +QUICFrameFactory::create_blocked_frame(QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) { QUICBlockedFrame *frame = quicBlockedFrameAllocator.alloc(); - new (frame) QUICBlockedFrame(offset, owner); + new (frame) QUICBlockedFrame(offset, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_blocked_frame); } std::unique_ptr -QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id, QUICOffset offset, QUICFrameGenerator *owner) +QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) { QUICStreamBlockedFrame *frame = quicStreamBlockedFrameAllocator.alloc(); - new (frame) QUICStreamBlockedFrame(stream_id, offset, owner); + new (frame) QUICStreamBlockedFrame(stream_id, offset, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); } std::unique_ptr -QUICFrameFactory::create_stream_id_blocked_frame(QUICStreamId stream_id, QUICFrameGenerator *owner) +QUICFrameFactory::create_stream_id_blocked_frame(QUICStreamId stream_id, QUICFrameId id, QUICFrameGenerator *owner) { QUICStreamIdBlockedFrame *frame = quicStreamIdBlockedFrameAllocator.alloc(); - new (frame) QUICStreamIdBlockedFrame(stream_id, owner); + new (frame) QUICStreamIdBlockedFrame(stream_id, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_id_blocked_frame); } std::unique_ptr QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, - QUICFrameGenerator *owner) + QUICFrameId id, QUICFrameGenerator *owner) { QUICRstStreamFrame *frame = quicRstStreamFrameAllocator.alloc(); - new (frame) QUICRstStreamFrame(stream_id, error_code, final_offset, owner); + new (frame) QUICRstStreamFrame(stream_id, error_code, final_offset, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_rst_stream_frame); } std::unique_ptr -QUICFrameFactory::create_rst_stream_frame(QUICStreamErrorUPtr error, QUICFrameGenerator *owner) +QUICFrameFactory::create_rst_stream_frame(QUICStreamErrorUPtr error, QUICFrameId id, QUICFrameGenerator *owner) { - return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->code, error->stream->final_offset(), owner); + return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->code, error->stream->final_offset(), id, owner); } std::unique_ptr -QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameGenerator *owner) +QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameId id, + QUICFrameGenerator *owner) { QUICStopSendingFrame *frame = quicStopSendingFrameAllocator.alloc(); - new (frame) QUICStopSendingFrame(stream_id, error_code, owner); + new (frame) QUICStopSendingFrame(stream_id, error_code, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_stop_sending_frame); } std::unique_ptr QUICFrameFactory::create_new_connection_id_frame(uint32_t sequence, QUICConnectionId connectoin_id, - QUICStatelessResetToken stateless_reset_token, QUICFrameGenerator *owner) + QUICStatelessResetToken stateless_reset_token, QUICFrameId id, + QUICFrameGenerator *owner) { QUICNewConnectionIdFrame *frame = quicNewConnectionIdFrameAllocator.alloc(); - new (frame) QUICNewConnectionIdFrame(sequence, connectoin_id, stateless_reset_token, owner); + new (frame) QUICNewConnectionIdFrame(sequence, connectoin_id, stateless_reset_token, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_connection_id_frame); } std::unique_ptr -QUICFrameFactory::create_new_token_frame(ats_unique_buf token, uint64_t token_len, QUICFrameGenerator *owner) +QUICFrameFactory::create_new_token_frame(ats_unique_buf token, uint64_t token_len, QUICFrameId id, QUICFrameGenerator *owner) { QUICNewTokenFrame *frame = quicNewTokenFrameAllocator.alloc(); - new (frame) QUICNewTokenFrame(std::move(token), token_len, owner); + new (frame) QUICNewTokenFrame(std::move(token), token_len, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_token_frame); } std::unique_ptr -QUICFrameFactory::create_retire_connection_id_frame(uint64_t seq_num, QUICFrameGenerator *owner) +QUICFrameFactory::create_retire_connection_id_frame(uint64_t seq_num, QUICFrameId id, QUICFrameGenerator *owner) { QUICRetireConnectionIdFrame *frame = quicRetireConnectionIdFrameAllocator.alloc(); - new (frame) QUICRetireConnectionIdFrame(seq_num, owner); + new (frame) QUICRetireConnectionIdFrame(seq_num, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_retire_connection_id_frame); } @@ -2995,3 +3010,15 @@ QUICFrameFactory::create_retransmission_frame(QUICFrameUPtr original_frame, cons new (frame) QUICRetransmissionFrame(std::move(original_frame), original_packet); return std::unique_ptr(frame, &QUICFrameDeleter::delete_retransmission_frame); } + +QUICFrameId +QUICFrameInfo::id() +{ + return this->_id; +} + +QUICFrameGenerator * +QUICFrameInfo::generated_by() +{ + return this->_generator; +} diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index b42100997a9..cc73c91db7d 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -46,6 +46,8 @@ using QUICFrameSPtr = std::shared_ptr; using QUICStreamFrameSPtr = std::shared_ptr; using QUICCryptoFrameSPtr = std::shared_ptr; +using QUICFrameId = uint64_t; + class QUICFrame { public: @@ -53,6 +55,8 @@ class QUICFrame virtual ~QUICFrame() {} static QUICFrameType type(const uint8_t *buf); + QUICFrameId id() const; + virtual QUICFrameUPtr clone() const = 0; virtual QUICFrameType type() const; virtual size_t size() const = 0; @@ -61,13 +65,14 @@ class QUICFrame virtual void reset(const uint8_t *buf, size_t len); virtual QUICFrame *split(size_t size); virtual int debug_msg(char *msg, size_t msg_len) const; - virtual QUICFrameGenerator *generated_by() const; + virtual QUICFrameGenerator *generated_by(); LINK(QUICFrame, link); protected: - QUICFrame(QUICFrameGenerator *owner = nullptr) : _owner(owner) {} + QUICFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : _id(id), _owner(owner) {} const uint8_t *_buf = nullptr; size_t _len = 0; + const QUICFrameId _id = 0; QUICFrameGenerator *_owner = nullptr; }; @@ -78,9 +83,9 @@ class QUICFrame class QUICStreamFrame : public QUICFrame { public: - QUICStreamFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICStreamFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false, + QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrame *split(size_t size) override; @@ -124,9 +129,9 @@ class QUICStreamFrame : public QUICFrame class QUICCryptoFrame : public QUICFrame { public: - QUICCryptoFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICCryptoFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICCryptoFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICCryptoFrame(ats_unique_buf buf, size_t len, QUICOffset offset, QUICFrameGenerator *owner = nullptr); + QUICCryptoFrame(ats_unique_buf buf, size_t len, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrame *split(size_t size) override; QUICFrameUPtr clone() const override; @@ -260,9 +265,9 @@ class QUICAckFrame : public QUICFrame uint64_t _ecn_ce_count = 0; }; - QUICAckFrame() : QUICFrame() {} + QUICAckFrame(QUICFrameId id = 0) : QUICFrame(id) {} QUICAckFrame(const uint8_t *buf, size_t len); - QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, + QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); virtual ~QUICAckFrame(); @@ -303,9 +308,9 @@ class QUICAckFrame : public QUICFrame class QUICRstStreamFrame : public QUICFrame { public: - QUICRstStreamFrame() : QUICFrame() {} + QUICRstStreamFrame(QUICFrameId id = 0) : QUICFrame(id) {} QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, + QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; @@ -336,7 +341,7 @@ class QUICRstStreamFrame : public QUICFrame class QUICPingFrame : public QUICFrame { public: - QUICPingFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICPingFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICPingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -369,10 +374,10 @@ class QUICPaddingFrame : public QUICFrame class QUICConnectionCloseFrame : public QUICFrame { public: - QUICConnectionCloseFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICConnectionCloseFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICConnectionCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase, - QUICFrameGenerator *owner = nullptr); + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -403,10 +408,10 @@ class QUICConnectionCloseFrame : public QUICFrame class QUICApplicationCloseFrame : public QUICFrame { public: - QUICApplicationCloseFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICApplicationCloseFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICApplicationCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase, - QUICFrameGenerator *owner = nullptr); + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual int debug_msg(char *msg, size_t msg_len) const override; virtual QUICFrameType type() const override; @@ -434,9 +439,9 @@ class QUICApplicationCloseFrame : public QUICFrame class QUICMaxDataFrame : public QUICFrame { public: - QUICMaxDataFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICMaxDataFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICMaxDataFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICMaxDataFrame(uint64_t maximum_data, QUICFrameGenerator *owner = nullptr); + QUICMaxDataFrame(uint64_t maximum_data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -458,9 +463,10 @@ class QUICMaxDataFrame : public QUICFrame class QUICMaxStreamDataFrame : public QUICFrame { public: - QUICMaxStreamDataFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICMaxStreamDataFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICMaxStreamDataFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameGenerator *owner = nullptr); + QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -487,9 +493,9 @@ class QUICMaxStreamDataFrame : public QUICFrame class QUICMaxStreamIdFrame : public QUICFrame { public: - QUICMaxStreamIdFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICMaxStreamIdFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICMaxStreamIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICFrameGenerator *owner = nullptr); + QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -508,9 +514,10 @@ class QUICMaxStreamIdFrame : public QUICFrame class QUICBlockedFrame : public QUICFrame { public: - QUICBlockedFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICBlockedFrame(QUICOffset offset, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _offset(offset){}; + QUICBlockedFrame(QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) + : QUICFrame(id, owner), _offset(offset){}; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -532,10 +539,10 @@ class QUICBlockedFrame : public QUICFrame class QUICStreamBlockedFrame : public QUICFrame { public: - QUICStreamBlockedFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICStreamBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICStreamBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o, QUICFrameGenerator *owner = nullptr) - : QUICFrame(owner), _stream_id(s), _offset(o){}; + QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) + : QUICFrame(id, owner), _stream_id(s), _offset(o){}; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -560,9 +567,12 @@ class QUICStreamBlockedFrame : public QUICFrame class QUICStreamIdBlockedFrame : public QUICFrame { public: - QUICStreamIdBlockedFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICStreamIdBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamIdBlockedFrame(QUICStreamId s, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _stream_id(s) {} + QUICStreamIdBlockedFrame(QUICStreamId s, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) + : QUICFrame(id, owner), _stream_id(s) + { + } QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -583,10 +593,11 @@ class QUICStreamIdBlockedFrame : public QUICFrame class QUICNewConnectionIdFrame : public QUICFrame { public: - QUICNewConnectionIdFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICNewConnectionIdFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICNewConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId id, QUICStatelessResetToken token, QUICFrameGenerator *owner = nullptr) - : QUICFrame(owner), _sequence(seq), _connection_id(id), _stateless_reset_token(token){}; + QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId cid, QUICStatelessResetToken token, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr) + : QUICFrame(id, owner), _sequence(seq), _connection_id(cid), _stateless_reset_token(token){}; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -615,9 +626,10 @@ class QUICNewConnectionIdFrame : public QUICFrame class QUICStopSendingFrame : public QUICFrame { public: - QUICStopSendingFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICStopSendingFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICStopSendingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameGenerator *owner = nullptr); + QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -643,9 +655,12 @@ class QUICPathChallengeFrame : public QUICFrame { public: static constexpr uint8_t DATA_LEN = 8; - QUICPathChallengeFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICPathChallengeFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICPathChallengeFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICPathChallengeFrame(ats_unique_buf data, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _data(std::move(data)) {} + QUICPathChallengeFrame(ats_unique_buf data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) + : QUICFrame(id, owner), _data(std::move(data)) + { + } QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -668,9 +683,12 @@ class QUICPathResponseFrame : public QUICFrame { public: static constexpr uint8_t DATA_LEN = 8; - QUICPathResponseFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICPathResponseFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICPathResponseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICPathResponseFrame(ats_unique_buf data, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _data(std::move(data)) {} + QUICPathResponseFrame(ats_unique_buf data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) + : QUICFrame(id, owner), _data(std::move(data)) + { + } QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -692,10 +710,10 @@ class QUICPathResponseFrame : public QUICFrame class QUICNewTokenFrame : public QUICFrame { public: - QUICNewTokenFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICNewTokenFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICNewTokenFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICNewTokenFrame(ats_unique_buf token, size_t token_length, QUICFrameGenerator *owner = nullptr) - : QUICFrame(owner), _token_length(token_length), _token(std::move(token)) + 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)) { } QUICFrameUPtr clone() const override; @@ -722,9 +740,12 @@ class QUICNewTokenFrame : public QUICFrame class QUICRetireConnectionIdFrame : public QUICFrame { public: - QUICRetireConnectionIdFrame(QUICFrameGenerator *owner = nullptr) : QUICFrame(owner) {} + QUICRetireConnectionIdFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICRetireConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICRetireConnectionIdFrame(uint64_t seq_num, QUICFrameGenerator *owner = nullptr) : QUICFrame(owner), _seq_num(seq_num) {} + QUICRetireConnectionIdFrame(uint64_t seq_num, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) + : QUICFrame(id, owner), _seq_num(seq_num) + { + } QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -977,13 +998,13 @@ class QUICFrameFactory * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ static QUICStreamFrameUPtr create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, - bool last = false, QUICFrameGenerator *owner = nullptr); + bool last = false, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a CRYPTO frame. * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ - static QUICCryptoFrameUPtr create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, + static QUICCryptoFrameUPtr create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* @@ -993,77 +1014,79 @@ class QUICFrameFactory */ static std::unique_ptr create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a CONNECTION_CLOSE frame. */ static std::unique_ptr create_connection_close_frame( uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr, - QUICFrameGenerator *owner = nullptr); + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); static std::unique_ptr create_connection_close_frame( - QUICConnectionErrorUPtr error, QUICFrameGenerator *owner = nullptr); + QUICConnectionErrorUPtr error, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a APPLICATION_CLOSE frame. */ static std::unique_ptr create_application_close_frame( - QUICAppErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr, + QUICAppErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); static std::unique_ptr create_application_close_frame( - QUICConnectionErrorUPtr error, QUICFrameGenerator *owner = nullptr); + QUICConnectionErrorUPtr error, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a MAX_DATA frame. */ - static std::unique_ptr create_max_data_frame(uint64_t maximum_data, + static std::unique_ptr create_max_data_frame(uint64_t maximum_data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* / * Creates a MAX_STREAM_DATA frame. */ static std::unique_ptr create_max_stream_data_frame( - QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameGenerator *owner = nullptr); + QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a MAX_STREAM_ID frame. */ static std::unique_ptr create_max_stream_id_frame( - QUICStreamId maximum_stream_id, QUICFrameGenerator *owner = nullptr); + QUICStreamId maximum_stream_id, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a PING frame */ - static std::unique_ptr create_ping_frame(QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_ping_frame(QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a PATH_CHALLENGE frame */ static std::unique_ptr create_path_challenge_frame( - const uint8_t *data, QUICFrameGenerator *owner = nullptr); + const uint8_t *data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a PATH_RESPONSE frame */ static std::unique_ptr create_path_response_frame( - const uint8_t *data, QUICFrameGenerator *owner = nullptr); + const uint8_t *data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a BLOCKED frame. */ - static std::unique_ptr create_blocked_frame(QUICOffset offset, + static std::unique_ptr create_blocked_frame(QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a STREAM_BLOCKED frame. */ static std::unique_ptr create_stream_blocked_frame( - QUICStreamId stream_id, QUICOffset offset, QUICFrameGenerator *owner = nullptr); + QUICStreamId stream_id, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a STREAM_ID_BLOCKED frame. */ static std::unique_ptr create_stream_id_blocked_frame( - QUICStreamId stream_id, QUICFrameGenerator *owner = nullptr); + QUICStreamId stream_id, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a RST_STREAM frame. @@ -1071,8 +1094,10 @@ class QUICFrameFactory static std::unique_ptr create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); static std::unique_ptr create_rst_stream_frame(QUICStreamErrorUPtr error, + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* @@ -1080,26 +1105,28 @@ class QUICFrameFactory */ static std::unique_ptr create_stop_sending_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a NEW_CONNECTION_ID frame. */ static std::unique_ptr create_new_connection_id_frame( - uint32_t sequence, QUICConnectionId connectoin_id, QUICStatelessResetToken stateless_reset_token, + uint32_t sequence, QUICConnectionId connectoin_id, QUICStatelessResetToken stateless_reset_token, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a NEW_TOKEN frame */ static std::unique_ptr create_new_token_frame(ats_unique_buf token, uint64_t token_len, + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a RETIRE_CONNECTION_ID frame */ static std::unique_ptr create_retire_connection_id_frame( - uint64_t seq_num, QUICFrameGenerator *owner = nullptr); + uint64_t seq_num, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a retransmission frame, which is very special. @@ -1112,3 +1139,15 @@ class QUICFrameFactory // FIXME Actual number of frame types is several but some of the values are not sequential. std::shared_ptr _reusable_frames[256] = {nullptr}; }; + +class QUICFrameInfo +{ +public: + QUICFrameInfo(QUICFrameId id, QUICFrameGenerator *generator) : _id(id), _generator(generator) {} + QUICFrameId id(); + QUICFrameGenerator *generated_by(); + +private: + QUICFrameId _id = 0; + QUICFrameGenerator *_generator; +}; diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index e24e742dafe..f9bdfb24a8c 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -33,11 +33,11 @@ class QUICFrameGenerator virtual QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) = 0; virtual void - on_frame_acked(QUICFrameUPtr &frame, QUICEncryptionLevel level) + on_frame_acked(QUICFrameId id) { } virtual void - on_frame_lost(QUICFrameUPtr &frame, QUICEncryptionLevel level) + on_frame_lost(QUICFrameId id) { } diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index c03c6bcbc3b..61796d7aa18 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -304,13 +304,13 @@ QUICLossDetector::_on_packet_acked(const PacketInfo &acked_packet) this->_tlp_count = 0; this->_rto_count = 0; - for (QUICFrameUPtr &frame : acked_packet.packet->frames()) { - auto reactor = frame->generated_by(); + for (QUICFrameInfo &frame_info : acked_packet.packet->frames()) { + auto reactor = frame_info.generated_by(); if (reactor == nullptr) { continue; } - reactor->on_frame_acked(frame, QUICTypeUtil::encryption_level(acked_packet.packet->type())); + reactor->on_frame_acked(frame_info.id()); } this->_remove_from_sent_packet_list(acked_packet.packet_number); @@ -554,13 +554,13 @@ QUICLossDetector::_retransmit_lost_packet(QUICPacketUPtr &packet) SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - for (QUICFrameUPtr &frame : packet->frames()) { - auto reactor = frame->generated_by(); + for (QUICFrameInfo &frame_info : packet->frames()) { + auto reactor = frame_info.generated_by(); if (reactor == nullptr) { continue; } - reactor->on_frame_lost(frame, QUICTypeUtil::encryption_level(packet->type())); + reactor->on_frame_lost(frame_info.id()); } this->_transmitter->retransmit_packet(*packet); } diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index f9bf099de33..6f218ee04ca 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -789,12 +789,12 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const // // QUICTrackablePacket // -QUICTrackablePacket::QUICTrackablePacket(std::vector &frames) +QUICTrackablePacket::QUICTrackablePacket(std::vector &frames) { this->_frames = std::move(frames); } -std::vector & +std::vector & QUICTrackablePacket::frames() { return this->_frames; @@ -813,7 +813,7 @@ QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size this->_payload_size = payload_len; } -QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, std::vector &frames) +QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, std::vector &frames) : QUICTrackablePacket(frames) { this->_header = std::move(header); @@ -831,7 +831,7 @@ QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size } QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing, - std::vector &frames) + std::vector &frames) : QUICTrackablePacket(frames) { this->_header = std::move(header); @@ -1244,7 +1244,7 @@ QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUIC 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, std::vector &frames, + bool retransmittable, bool probing, std::vector &frames, ats_unique_buf token, size_t token_len) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); @@ -1267,7 +1267,7 @@ QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICCon 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, std::vector &frames) + bool retransmittable, bool probing, std::vector &frames) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::HANDSHAKE); QUICPacketNumber pn = this->_packet_number_generator[index].next(); @@ -1280,7 +1280,7 @@ QUICPacketFactory::create_handshake_packet(QUICConnectionId destination_cid, QUI 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, std::vector &frames) + bool retransmittable, bool probing, std::vector &frames) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ZERO_RTT); QUICPacketNumber pn = this->_packet_number_generator[index].next(); @@ -1293,7 +1293,7 @@ QUICPacketFactory::create_zero_rtt_packet(QUICConnectionId destination_cid, QUIC QUICPacketUPtr QUICPacketFactory::create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable, bool probing, - std::vector &frames) + std::vector &frames) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ONE_RTT); QUICPacketNumber pn = this->_packet_number_generator[index].next(); @@ -1341,7 +1341,7 @@ QUICPacketFactory::_create_unprotected_packet(QUICPacketHeaderUPtr header) QUICPacketUPtr QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing, - std::vector &frame) + std::vector &frames) { // TODO: use pmtu of UnixNetVConnection size_t max_cipher_txt_len = 2048; @@ -1357,7 +1357,7 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool re if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable, probing, frame); + new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable, probing, frames); } else { QUICDebug(dcid, scid, "Failed to encrypt a packet"); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index ddb5dfae452..3c35fcbf0f7 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -54,12 +54,12 @@ class QUICTrackablePacket { public: virtual ~QUICTrackablePacket() {} - std::vector &frames(); + std::vector &frames(); protected: QUICTrackablePacket() {} - QUICTrackablePacket(std::vector &frames); - std::vector _frames; + QUICTrackablePacket(std::vector &frames); + std::vector _frames; }; class QUICPacketHeader @@ -332,7 +332,7 @@ class QUICPacket : public QUICTrackablePacket */ QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len); - QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, std::vector &frames); + QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, std::vector &frames); /* * Creates a QUICPacket with a QUICPacketHeader, a buffer that contains payload and a flag that indicates whether the packet is @@ -344,7 +344,7 @@ class QUICPacket : public QUICTrackablePacket QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing); QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing, - std::vector &frames); + std::vector &frames); ~QUICPacket(); @@ -442,17 +442,17 @@ class QUICPacketFactory QUICPacketCreationResult &result); QUICPacketUPtr create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, - bool retransmittable, bool probing, std::vector &frame, + bool retransmittable, bool probing, std::vector &frame, 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, - bool retransmittable, bool probing, std::vector &frame); + bool retransmittable, bool probing, std::vector &frames); QUICPacketUPtr 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, std::vector &frame); + bool retransmittable, bool probing, std::vector &frames); QUICPacketUPtr create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable, bool probing, - std::vector &frame); + std::vector &frames); void set_version(QUICVersion negotiated_version); // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICCryptoInfoProvider or somethign instead. @@ -470,5 +470,5 @@ class QUICPacketFactory static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeaderUPtr header); QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing, - std::vector &frame); + std::vector &frames); }; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 3d63261b60b..8c5a37ee25a 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -881,7 +881,7 @@ TEST_CASE("Store MaxData Frame", "[quic]") 0x04, // Type 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data }; - QUICMaxDataFrame max_data_frame(0x1122334455667788); + QUICMaxDataFrame max_data_frame(0x1122334455667788, 0, nullptr); CHECK(max_data_frame.size() == 9); max_data_frame.store(buf, &len, 65535); @@ -947,7 +947,7 @@ TEST_CASE("Store MaxStreamId Frame", "[quic]") 0x06, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID }; - QUICMaxStreamIdFrame max_stream_id_frame(0x01020304); + QUICMaxStreamIdFrame max_stream_id_frame(0x01020304, 0, nullptr); CHECK(max_stream_id_frame.size() == 5); max_stream_id_frame.store(buf, &len, 65535); @@ -978,7 +978,7 @@ TEST_CASE("Store Blocked Frame", "[quic]") 0x08, // Type 0x07, // Offset }; - QUICBlockedFrame blocked_stream_frame(0x07); + QUICBlockedFrame blocked_stream_frame(0x07, 0, nullptr); CHECK(blocked_stream_frame.size() == 2); blocked_stream_frame.store(buf, &len, 65535); @@ -1045,7 +1045,7 @@ TEST_CASE("Store StreamIdBlocked Frame", "[quic]") 0x0a, // Type 0x41, 0x02, // Stream ID }; - QUICStreamIdBlockedFrame stream_id_blocked_frame(0x0102); + QUICStreamIdBlockedFrame stream_id_blocked_frame(0x0102, 0, nullptr); CHECK(stream_id_blocked_frame.size() == 3); stream_id_blocked_frame.store(buf, &len, 65535); @@ -1277,7 +1277,7 @@ TEST_CASE("RETIRE_CONNECTION_ID Frame", "[quic]") uint8_t buf[32]; size_t len; - QUICRetireConnectionIdFrame frame(seq_num); + QUICRetireConnectionIdFrame frame(seq_num, 0, nullptr); CHECK(frame.size() == raw_retire_connection_id_frame_len); frame.store(buf, &len, 16); @@ -1373,7 +1373,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") QUICPacketFactory factory; MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); - std::vector frames; + std::vector frames; QUICPacketUPtr packet = factory.create_protected_packet({reinterpret_cast("\x01\x02\x03\x04"), 4}, 0, {nullptr}, 0, true, false, frames); SECTION("STREAM frame split") diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index fd93aa6e604..9e8d99142ac 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -45,7 +45,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") size_t payload_len = 16; QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); std::shared_ptr frame = QUICFrameFactory::create_null_ack_frame(); - std::vector dummy_frames; + std::vector dummy_frames; SECTION("Handshake") { diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index e9b29c81664..e6cd60fa1c2 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -90,7 +90,7 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); factory.set_version(0x11223344); - std::vector dummy_frames; + std::vector dummy_frames; uint8_t raw[] = {0xaa, 0xbb, 0xcc, 0xdd}; ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 95263c96d50..bfb0a06cae7 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -32,7 +32,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") MockQUICHandshakeProtocol hs_protocol; packet_factory.set_hs_protocol(&hs_protocol); QUICVersionNegotiator vn; - std::vector dummy_frame; + std::vector dummy_frames; SECTION("Normal case") { @@ -42,7 +42,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); + packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frames); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -61,7 +61,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); + packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frames); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -80,7 +80,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); + packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frames); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); @@ -98,7 +98,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") MockQUICHandshakeProtocol hs_protocol; packet_factory.set_hs_protocol(&hs_protocol); QUICVersionNegotiator vn; - std::vector dummy_frame; + std::vector dummy_frames; SECTION("Normal case") { @@ -124,7 +124,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frame); + packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frames); // Server send VN packet based on Initial packet QUICPacketUPtr vn_packet = From d36bc1190631e0879961284e4c86188511caa7fb Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 22 Nov 2018 16:48:48 +0900 Subject: [PATCH 0927/1313] Send Preferred Address if it is set This adds proxy.config.quic.preferred_address . --- iocore/net/QUICNetVConnection.cc | 22 ++-- iocore/net/quic/Makefile.am | 8 ++ iocore/net/quic/QUICAltConnectionManager.cc | 52 +++++--- iocore/net/quic/QUICAltConnectionManager.h | 20 ++- iocore/net/quic/QUICConfig.cc | 14 +++ iocore/net/quic/QUICConfig.h | 7 +- iocore/net/quic/QUICHandshake.cc | 12 +- iocore/net/quic/QUICHandshake.h | 5 +- iocore/net/quic/QUICTransportParameters.cc | 23 +++- iocore/net/quic/QUICTypes.cc | 130 +++++++++++++++++++- iocore/net/quic/QUICTypes.h | 21 +++- mgmt/RecordsConfig.cc | 2 + 12 files changed, 281 insertions(+), 35 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2f07346b905..5873292ddd4 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -886,7 +886,14 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe // Start handshake if (this->netvc_context == NET_VCONNECTION_IN) { - error = this->_handshake_handler->start(packet.get(), &this->_packet_factory); + if (!this->_alt_con_manager) { + QUICConfig::scoped_config params; + this->_alt_con_manager = + new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, params->instance_id(), + params->num_alt_connection_ids(), params->preferred_address()); + this->_frame_dispatcher->add_handler(this->_alt_con_manager); + } + error = this->_handshake_handler->start(packet.get(), &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()) { @@ -1760,13 +1767,14 @@ QUICNetVConnection::_switch_to_established_state() SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_established); - std::shared_ptr remote_tp = this->_handshake_handler->remote_transport_parameters(); - QUICConfig::scoped_config params; - - if (netvc_context == NET_VCONNECTION_IN || (netvc_context == NET_VCONNECTION_OUT && params->cm_exercise_enabled() && - !remote_tp->contains(QUICTransportParameterId::DISABLE_MIGRATION))) { + if (this->direction() == NET_VCONNECTION_OUT) { + std::shared_ptr remote_tp = this->_handshake_handler->remote_transport_parameters(); + const uint8_t *pref_addr_buf; + uint16_t len; + QUICConfig::scoped_config params; + pref_addr_buf = remote_tp->getAsBytes(QUICTransportParameterId::PREFERRED_ADDRESS, len); this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, - params->instance_id(), params->num_alt_connection_ids()); + params->instance_id(), 1, {pref_addr_buf, len}); this->_frame_dispatcher->add_handler(this->_alt_con_manager); } } else { diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 9a86f7cc0c3..e670ae427cc 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -85,6 +85,7 @@ libquic_a_SOURCES = \ # check_PROGRAMS = \ test_QUICAckFrameCreator \ + test_QUICAltConnectionManager \ test_QUICFlowController \ test_QUICFrame \ test_QUICFrameDispatcher \ @@ -133,6 +134,13 @@ test_QUICAckFrameCreator_SOURCES = \ $(test_main_SOURCES) \ ./test/test_QUICAckFrameCreator.cc +test_QUICAltConnectionManager_CPPFLAGS = $(test_CPPFLAGS) +test_QUICAltConnectionManager_LDFLAGS = @AM_LDFLAGS@ +test_QUICAltConnectionManager_LDADD = $(test_LDADD) +test_QUICAltConnectionManager_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICAltConnectionManager.cc + test_QUICFlowController_CPPFLAGS = $(test_CPPFLAGS) test_QUICFlowController_LDFLAGS = @AM_LDFLAGS@ test_QUICFlowController_LDADD = $(test_LDADD) diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 3e917524e49..8bd208e289b 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -29,28 +29,43 @@ 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, - QUICConnectionId peer_initial_cid, uint32_t instance_id, uint8_t num_alt_con) - : _qc(qc), _ctable(ctable), _instance_id(instance_id) + QUICConnectionId peer_initial_cid, uint32_t instance_id, uint8_t num_alt_con, + const QUICPreferredAddress preferred_address) + : _qc(qc), _ctable(ctable), _instance_id(instance_id), _nids(num_alt_con) { // Sequence number of the initial CID is 0 this->_alt_quic_connection_ids_remote.push_back({0, peer_initial_cid, {}, {true}}); - // TODO If preferred_address was provided, sequence number of the provided CID is 1 - - if (this->_qc->direction() == NET_VCONNECTION_IN) { - this->_nids = num_alt_con; - this->_alt_quic_connection_ids_local = static_cast(ats_malloc(sizeof(AltConnectionInfo) * this->_nids)); - this->_init_alt_connection_ids(); - } else { - this->_nids = 1; - this->_alt_quic_connection_ids_local = static_cast(ats_malloc(sizeof(AltConnectionInfo) * this->_nids)); - // If this is a client, new connection id will be generated on demand + // Sequence number of the preferred address is 1 if available + if (preferred_address.is_available()) { + this->_alt_quic_connection_ids_remote.push_back({1, preferred_address.cid(), preferred_address.token(), {false}}); } + + this->_alt_quic_connection_ids_local = static_cast(ats_malloc(sizeof(AltConnectionInfo) * this->_nids)); +} + +QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, + QUICConnectionId peer_initial_cid, uint32_t instance_id, uint8_t num_alt_con, + const IpEndpoint *preferred_endpoint) + : _qc(qc), _ctable(ctable), _instance_id(instance_id), _nids(num_alt_con) +{ + // 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 = static_cast(ats_malloc(sizeof(AltConnectionInfo) * this->_nids)); + this->_init_alt_connection_ids(preferred_endpoint); } QUICAltConnectionManager::~QUICAltConnectionManager() { ats_free(this->_alt_quic_connection_ids_local); + delete this->_preferred_address; +} + +const QUICPreferredAddress * +QUICAltConnectionManager::preferred_address() const +{ + return this->_preferred_address; } std::vector @@ -103,9 +118,18 @@ QUICAltConnectionManager::_generate_next_alt_con_info() } void -QUICAltConnectionManager::_init_alt_connection_ids() +QUICAltConnectionManager::_init_alt_connection_ids(const IpEndpoint *preferred_endpoint) { - for (int i = 0; i < this->_nids; ++i) { + if (preferred_endpoint) { + this->_alt_quic_connection_ids_local[0] = this->_generate_next_alt_con_info(); + // This alt cid will be advertised via Transport Parameter + this->_alt_quic_connection_ids_local[0].advertised = true; + + this->_preferred_address = new QUICPreferredAddress(*preferred_endpoint, this->_alt_quic_connection_ids_local[0].id, + this->_alt_quic_connection_ids_local[0].token); + } + + for (int i = (preferred_endpoint ? 1 : 0); i < this->_nids; ++i) { this->_alt_quic_connection_ids_local[i] = this->_generate_next_alt_con_info(); } this->_need_advertise = true; diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index 53dcc33a7ef..7391b4a32a7 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -35,8 +35,16 @@ class QUICConnectionTable; class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenerator { public: + /** + * Constructor for clients + */ + QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, QUICConnectionId peer_initial_cid, uint32_t instance_id, + uint8_t num_alt_con, const QUICPreferredAddress preferred_address); + /** + * Constructor for servers + */ QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, QUICConnectionId peer_initial_cid, uint32_t instance_id, - uint8_t num_alt_con); + uint8_t num_alt_con, const IpEndpoint *preferred_endpoint = nullptr); ~QUICAltConnectionManager(); /** @@ -64,6 +72,11 @@ class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenera */ void invalidate_alt_connections(); + /** + * Returns server preferred address if available + */ + const QUICPreferredAddress *preferred_address() const; + // QUICFrameHandler virtual std::vector interests() override; virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; @@ -91,12 +104,13 @@ class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenera std::vector _alt_quic_connection_ids_remote; std::queue _retired_seq_nums; uint32_t _instance_id = 0; - uint8_t _nids = 0; + uint8_t _nids = 1; uint64_t _alt_quic_connection_id_seq_num = 0; bool _need_advertise = false; + QUICPreferredAddress *_preferred_address = nullptr; AltConnectionInfo _generate_next_alt_con_info(); - void _init_alt_connection_ids(); + void _init_alt_connection_ids(const IpEndpoint *preferred_endpoint = nullptr); bool _update_alt_connection_id(uint64_t chosen_seq_num); QUICConnectionErrorUPtr _register_remote_connection_id(const QUICNewConnectionIdFrame &frame); diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 8f22866a898..905568b9e43 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -147,6 +147,10 @@ QUICConfigParams::initialize() // Transport Parameters REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_in, "proxy.config.quic.no_activity_timeout_in"); REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_out, "proxy.config.quic.no_activity_timeout_out"); + REC_ReadConfigStringAlloc(this->_preferred_address, "proxy.config.quic.preferred_address"); + if (this->_preferred_address) { + ats_ip_pton(this->_preferred_address, &this->_preferred_endpoint); + } REC_EstablishStaticConfigInt32U(this->_initial_max_data_in, "proxy.config.quic.initial_max_data_in"); REC_EstablishStaticConfigInt32U(this->_initial_max_data_out, "proxy.config.quic.initial_max_data_out"); REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data_bidi_local_in, @@ -211,6 +215,16 @@ QUICConfigParams::no_activity_timeout_out() const return this->_no_activity_timeout_out; } +const IpEndpoint * +QUICConfigParams::preferred_address() const +{ + if (!this->_preferred_address) { + return nullptr; + } + + return &this->_preferred_endpoint; +} + uint32_t QUICConfigParams::instance_id() const { diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index e99519925cc..f33b793fd51 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -51,6 +51,7 @@ class QUICConfigParams : public ConfigInfo // Transport Parameters uint32_t no_activity_timeout_in() const; uint32_t no_activity_timeout_out() const; + const IpEndpoint *preferred_address() const; uint32_t initial_max_data_in() const; uint32_t initial_max_data_out() const; uint32_t initial_max_stream_data_bidi_local_in() const; @@ -107,8 +108,10 @@ class QUICConfigParams : public ConfigInfo SSL_CTX *_client_ssl_ctx = nullptr; // Transport Parameters - uint32_t _no_activity_timeout_in = 0; - uint32_t _no_activity_timeout_out = 0; + uint32_t _no_activity_timeout_in = 0; + uint32_t _no_activity_timeout_out = 0; + const char *_preferred_address = nullptr; + IpEndpoint _preferred_endpoint; uint32_t _initial_max_data_in = 0; uint32_t _initial_max_data_out = 0; uint32_t _initial_max_stream_data_bidi_local_in = 0; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index bd4a7506a65..6b2f829eadc 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -119,7 +119,7 @@ QUICHandshake::start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled } QUICConnectionErrorUPtr -QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory) +QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory, const QUICPreferredAddress *pref_addr) { // Negotiate version if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) { @@ -129,7 +129,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet if (initial_packet->version()) { if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { QUICHSDebug("Version negotiation succeeded: %x", initial_packet->version()); - this->_load_local_server_transport_parameters(initial_packet->version()); + this->_load_local_server_transport_parameters(initial_packet->version(), pref_addr); packet_factory->set_version(this->_version_negotiator->negotiated_version()); } else { ink_assert(!"Unsupported version initial packet should be droped QUICPakcetHandler"); @@ -360,7 +360,7 @@ QUICHandshake::generate_frame(QUICEncryptionLevel level, uint64_t connection_cre } void -QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_version) +QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_version, const QUICPreferredAddress *pref_addr) { QUICConfig::scoped_config params; QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(negotiated_version); @@ -387,6 +387,12 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve if (params->initial_max_stream_data_uni_out() != 0) { tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, params->initial_max_stream_data_uni_out()); } + if (pref_addr != nullptr) { + uint8_t pref_addr_buf[QUICPreferredAddress::MAX_LEN]; + uint16_t len; + pref_addr->store(pref_addr_buf, len); + tp->set(QUICTransportParameterId::PREFERRED_ADDRESS, pref_addr_buf, len); + } // MAYs (server) tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN); diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index f85384ba9fa..bab48e4bd5a 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -59,7 +59,8 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator void reset(); // for server side - QUICConnectionErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); + QUICConnectionErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory, + const QUICPreferredAddress *pref_addr); QUICConnectionErrorUPtr do_handshake(); @@ -98,7 +99,7 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator QUICEncryptionLevel::ONE_RTT, }; } - void _load_local_server_transport_parameters(QUICVersion negotiated_version); + void _load_local_server_transport_parameters(QUICVersion negotiated_version, const QUICPreferredAddress *pref_addr); void _load_local_client_transport_parameters(QUICVersion initial_version); bool _check_remote_transport_parameters(std::shared_ptr tp); bool _check_remote_transport_parameters(std::shared_ptr tp); diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 12681b63578..d2a713717b8 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -30,6 +30,7 @@ #include "QUICHandshake.h" #include "QUICDebugNames.h" #include "QUICTLS.h" +#include "QUICTypes.h" static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; static constexpr char tag[] = "quic_handshake"; @@ -362,6 +363,20 @@ QUICTransportParameters::_print() const Debug(tag, "%s: 0x%" PRIx64 " (%" PRIu64 ")", QUICDebugNames::transport_parameter_id(p.first), QUICIntUtil::read_nbytes_as_uint(p.second->data(), p.second->len()), QUICIntUtil::read_nbytes_as_uint(p.second->data(), p.second->len())); + } else if (p.second->len() <= 24) { + char hex_str[65]; + to_hex_str(hex_str, sizeof(hex_str), p.second->data(), p.second->len()); + Debug(tag, "%s: %s", QUICDebugNames::transport_parameter_id(p.first), hex_str); + } else if (QUICTransportParameterId::PREFERRED_ADDRESS == p.first) { + QUICPreferredAddress pref_addr(p.second->data(), p.second->len()); + char cid_hex_str[QUICConnectionId::MAX_HEX_STR_LENGTH]; + char token_hex_str[QUICStatelessResetToken::LEN * 2 + 1]; + char ep_hex_str[512]; + pref_addr.cid().hex(cid_hex_str, sizeof(cid_hex_str)); + to_hex_str(token_hex_str, sizeof(token_hex_str), pref_addr.token().buf(), QUICStatelessResetToken::LEN); + ats_ip_nptop(pref_addr.endpoint(), ep_hex_str, sizeof(ep_hex_str)); + Debug(tag, "%s: Endpoint=%s, CID=%s, Token=%s", QUICDebugNames::transport_parameter_id(p.first), ep_hex_str, cid_hex_str, + token_hex_str); } else { Debug(tag, "%s: (long data)", QUICDebugNames::transport_parameter_id(p.first)); } @@ -376,7 +391,9 @@ QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const { this->_initial_version = QUICTypeUtil::read_QUICVersion(buf); this->_load(buf, len); - this->_print(); + if (is_debug_tag_set(tag)) { + this->_print(); + } } void @@ -434,7 +451,9 @@ QUICTransportParametersInEncryptedExtensions::QUICTransportParametersInEncrypted this->_versions[i] = QUICTypeUtil::read_QUICVersion(buf + 5 + (i * 4)); } this->_load(buf, len); - this->_print(); + if (is_debug_tag_set(tag)) { + this->_print(); + } } void diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 51b0aab7f02..80973ea7426 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -28,7 +28,7 @@ uint8_t QUICConnectionId::SCID_LEN = 0; // TODO: move to somewhere in lib/ts/ -static int +int to_hex_str(char *dst, size_t dst_len, const uint8_t *src, size_t src_len) { if (dst_len < src_len * 2 + 1) { @@ -282,6 +282,134 @@ QUICConnectionError::frame_type() const return _frame_type; } +// +// QUICPreferredAddress +// + +QUICPreferredAddress::QUICPreferredAddress(const uint8_t *buf, uint16_t len) +{ + if (len < QUICPreferredAddress::MIN_LEN || buf == nullptr) { + return; + } + + const uint8_t *p = buf; + + // ipVersion + uint64_t type = p[0]; + p += 1; + + // ipAddress + uint16_t addr_len = p[0]; + p += 1; + if (type == 4) { + if (addr_len == 4) { + in_addr_t addr; + memcpy(&addr, p, addr_len); + p += 4; + in_port_t port; + memcpy(&port, p, 2); + p += 2; + ats_ip4_set(&this->_endpoint, addr, port); + } else { + return; + } + } else if (type == 6) { + if (addr_len == TS_IP6_SIZE) { + in6_addr addr; + memcpy(&addr, p, addr_len); + p += TS_IP6_SIZE; + in_port_t port; + memcpy(&port, p, 2); + p += 2; + ats_ip6_set(&this->_endpoint, addr, port); + } else { + return; + } + } else { + return; + } + + // CID + uint16_t cid_len = QUICIntUtil::read_nbytes_as_uint(p, 1); + p += 1; + this->_cid = QUICTypeUtil::read_QUICConnectionId(p, cid_len); + p += cid_len; + + // Token + this->_token = {p}; + + this->_valid = true; +} + +bool +QUICPreferredAddress::is_available() const +{ + return this->_valid; +} + +const IpEndpoint +QUICPreferredAddress::endpoint() const +{ + return this->_endpoint; +} + +const QUICConnectionId +QUICPreferredAddress::cid() const +{ + return this->_cid; +} + +const QUICStatelessResetToken +QUICPreferredAddress::token() const +{ + return this->_token; +} + +void +QUICPreferredAddress::store(uint8_t *buf, uint16_t &len) const +{ + size_t dummy; + uint8_t *p = buf; + + // ipVersion + if (this->_endpoint.isIp4()) { + p[0] = 4; + } else if (this->_endpoint.isIp6()) { + p[0] = 6; + } else { + return; + } + p += 1; + + // ipAddress + size_t addr_len = ats_ip_addr_size(this->_endpoint); + p[0] = addr_len; + p += 1; + if (this->_endpoint.isIp4()) { + memcpy(p, &ats_ip4_addr_cast(this->_endpoint), addr_len); + } else { + memcpy(p, &ats_ip6_addr_cast(this->_endpoint), addr_len); + } + p += addr_len; + + // port + memcpy(p, &ats_ip_port_cast(this->_endpoint), 2); + p += 2; + + // CID + uint8_t cid_len = this->_cid.length(); + p[0] = cid_len; + p += 1; + QUICTypeUtil::write_QUICConnectionId(this->_cid, p, &dummy); + p += cid_len; + + // Token + memcpy(p, this->_token.buf(), 16); + p += 16; + + len = p - buf; +} + // // QUICFiveTuple // diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 7a1e8de826e..419daa4d19e 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -299,7 +299,24 @@ class QUICPreferredAddress constexpr static int16_t MIN_LEN = 26; constexpr static int16_t MAX_LEN = 295; - QUICPreferredAddress() {} + QUICPreferredAddress(IpEndpoint endpoint, QUICConnectionId cid, QUICStatelessResetToken token) + : _endpoint(endpoint), _cid(cid), _token(token), _valid(true) + { + } + QUICPreferredAddress(const uint8_t *buf, uint16_t len); + + bool is_available() const; + const IpEndpoint endpoint() const; + const QUICConnectionId cid() const; + const QUICStatelessResetToken token() const; + + void store(uint8_t *buf, uint16_t &len) const; + +private: + IpEndpoint _endpoint; + QUICConnectionId _cid; + QUICStatelessResetToken _token; + bool _valid = false; }; enum class QUICStreamType : uint8_t { @@ -384,3 +401,5 @@ class QUICInvariants static const size_t LH_MIN_LEN = 6; static const size_t SH_MIN_LEN = 1; }; + +int to_hex_str(char *dst, size_t dst_len, const uint8_t *src, size_t src_len); diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 56d6b9d5b28..34f8e091ec7 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1370,6 +1370,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_out", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.preferred_address", RECD_STRING, nullptr , RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} + , {RECT_CONFIG, "proxy.config.quic.initial_max_data_in", RECD_INT, "65536", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.initial_max_data_out", RECD_INT, "65536", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} From 99c968e20cc9dcbcbce9786008a0862ae3ee22d4 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sun, 25 Nov 2018 11:09:35 +0800 Subject: [PATCH 0928/1313] QUIC: Records frame information which needs to be tracked --- iocore/net/quic/Makefile.am | 3 +- iocore/net/quic/QUICFrameGenerator.cc | 73 +++++++++++++++++++++++++++ iocore/net/quic/QUICFrameGenerator.h | 32 +++++------- iocore/net/quic/QUICFrameRecord.h | 43 ++++++++++++++++ 4 files changed, 132 insertions(+), 19 deletions(-) create mode 100644 iocore/net/quic/QUICFrameGenerator.cc create mode 100644 iocore/net/quic/QUICFrameRecord.h diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index e670ae427cc..519ae177bb6 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -78,7 +78,8 @@ libquic_a_SOURCES = \ QUICPacketReceiveQueue.cc \ QUICPacketRetransmitter.cc \ QUICPathValidator.cc \ - QUICStatelessRetry.cc + QUICStatelessRetry.cc \ + QUICFrameGenerator.cc # # Check Programs diff --git a/iocore/net/quic/QUICFrameGenerator.cc b/iocore/net/quic/QUICFrameGenerator.cc new file mode 100644 index 00000000000..5c11fd5792c --- /dev/null +++ b/iocore/net/quic/QUICFrameGenerator.cc @@ -0,0 +1,73 @@ +/** @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 "QUICFrameGenerator.h" +#include "QUICFrameRecord.h" + +void +QUICFrameGenerator::_records_frame(QUICFrameInformation info) +{ + for (auto type : QUIC_RECORD_FRAME) { + if (type == info.type) { + this->_info.insert(std::make_pair(this->_frame_ids++, info)); + return; + } + } +} + +std::vector +QUICFrameGenerator::_encryption_level_filter() +{ + return {QUICEncryptionLevel::ONE_RTT}; +} + +bool +QUICFrameGenerator::_is_level_matched(QUICEncryptionLevel level) +{ + for (auto l : this->_encryption_level_filter()) { + if (l == level) { + return true; + } + } + return false; +} + +void +QUICFrameGenerator::on_frame_acked(QUICFrameId id) +{ + auto it = this->_info.find(id); + if (it != this->_info.end()) { + this->_on_frame_acked(it->second); + this->_info.erase(it); + } +} + +void +QUICFrameGenerator::on_frame_lost(QUICFrameId id) +{ + auto it = this->_info.find(id); + if (it != this->_info.end()) { + this->_on_frame_lost(it->second); + this->_info.erase(it); + } +} diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index f9bdfb24a8c..49fdb7c9aa9 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -24,6 +24,7 @@ #pragma once #include "QUICFrame.h" +#include "QUICFrameRecord.h" class QUICFrameGenerator { @@ -32,31 +33,26 @@ class QUICFrameGenerator virtual bool will_generate_frame(QUICEncryptionLevel level) = 0; virtual QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) = 0; + void on_frame_acked(QUICFrameId id); + void on_frame_lost(QUICFrameId id); + +protected: virtual void - on_frame_acked(QUICFrameId id) + _on_frame_acked(QUICFrameInformation info) { } + virtual void - on_frame_lost(QUICFrameId id) + _on_frame_lost(QUICFrameInformation info) { } -protected: - virtual std::vector - _encryption_level_filter() - { - return {QUICEncryptionLevel::ONE_RTT}; - } + virtual std::vector _encryption_level_filter(); + virtual bool _is_level_matched(QUICEncryptionLevel level); + void _records_frame(QUICFrameInformation info); - virtual bool - _is_level_matched(QUICEncryptionLevel level) - { - for (auto l : this->_encryption_level_filter()) { - if (l == level) { - return true; - } - } + uint64_t _frame_ids = 0; - return false; - } +private: + std::map _info; }; diff --git a/iocore/net/quic/QUICFrameRecord.h b/iocore/net/quic/QUICFrameRecord.h new file mode 100644 index 00000000000..6b11975a1cf --- /dev/null +++ b/iocore/net/quic/QUICFrameRecord.h @@ -0,0 +1,43 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICFrame.h" + +constexpr QUICFrameType QUIC_RECORD_FRAME[] = { + QUICFrameType::ACK, +}; + +struct QUICFrameInformation { + QUICFrameType type; + QUICEncryptionLevel level; + + union { + // ack information + struct QUICAckFrameInfo { + QUICPacketNumber largest_acknowledged; + } ack_frame_info; + + } frame_info; +}; From 253117f65497f52064b13ab50bec5d08fd29fcce Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 26 Nov 2018 10:19:25 +0800 Subject: [PATCH 0929/1313] QUIC Removes frame type checks, user should only call records_frame when you need to track this frame --- iocore/net/quic/QUICFrameGenerator.cc | 7 +------ iocore/net/quic/QUICFrameRecord.h | 6 +----- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICFrameGenerator.cc b/iocore/net/quic/QUICFrameGenerator.cc index 5c11fd5792c..5e038443b85 100644 --- a/iocore/net/quic/QUICFrameGenerator.cc +++ b/iocore/net/quic/QUICFrameGenerator.cc @@ -27,12 +27,7 @@ void QUICFrameGenerator::_records_frame(QUICFrameInformation info) { - for (auto type : QUIC_RECORD_FRAME) { - if (type == info.type) { - this->_info.insert(std::make_pair(this->_frame_ids++, info)); - return; - } - } + this->_info.insert(std::make_pair(this->_frame_ids++, info)); } std::vector diff --git a/iocore/net/quic/QUICFrameRecord.h b/iocore/net/quic/QUICFrameRecord.h index 6b11975a1cf..9553b9643e9 100644 --- a/iocore/net/quic/QUICFrameRecord.h +++ b/iocore/net/quic/QUICFrameRecord.h @@ -25,16 +25,12 @@ #include "QUICFrame.h" -constexpr QUICFrameType QUIC_RECORD_FRAME[] = { - QUICFrameType::ACK, -}; - struct QUICFrameInformation { QUICFrameType type; QUICEncryptionLevel level; union { - // ack information + // ack information struct QUICAckFrameInfo { QUICPacketNumber largest_acknowledged; } ack_frame_info; From b8692528b0c9edeb559d16eb2be1fa2726db7008 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 26 Nov 2018 11:18:56 +0800 Subject: [PATCH 0930/1313] QUIC: Use uint8_t buffer instead of union --- iocore/net/quic/QUICFrameGenerator.cc | 1 - iocore/net/quic/QUICFrameGenerator.h | 8 +++++- iocore/net/quic/QUICFrameRecord.h | 39 --------------------------- 3 files changed, 7 insertions(+), 41 deletions(-) delete mode 100644 iocore/net/quic/QUICFrameRecord.h diff --git a/iocore/net/quic/QUICFrameGenerator.cc b/iocore/net/quic/QUICFrameGenerator.cc index 5e038443b85..f7f8f6e2873 100644 --- a/iocore/net/quic/QUICFrameGenerator.cc +++ b/iocore/net/quic/QUICFrameGenerator.cc @@ -22,7 +22,6 @@ */ #include "QUICFrameGenerator.h" -#include "QUICFrameRecord.h" void QUICFrameGenerator::_records_frame(QUICFrameInformation info) diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index 49fdb7c9aa9..eea0b8e43bc 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -24,7 +24,13 @@ #pragma once #include "QUICFrame.h" -#include "QUICFrameRecord.h" + +struct QUICFrameInformation { + QUICFrameType type; + QUICEncryptionLevel level; + + uint8_t data[1024] = {}; +}; class QUICFrameGenerator { diff --git a/iocore/net/quic/QUICFrameRecord.h b/iocore/net/quic/QUICFrameRecord.h deleted file mode 100644 index 9553b9643e9..00000000000 --- a/iocore/net/quic/QUICFrameRecord.h +++ /dev/null @@ -1,39 +0,0 @@ -/** @file - * - * A brief file description - * - * @section license License - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "QUICFrame.h" - -struct QUICFrameInformation { - QUICFrameType type; - QUICEncryptionLevel level; - - union { - // ack information - struct QUICAckFrameInfo { - QUICPacketNumber largest_acknowledged; - } ack_frame_info; - - } frame_info; -}; From 8d9822a74a77b2a5d80b4379e99e7de3f2144a20 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 26 Nov 2018 20:46:09 +0800 Subject: [PATCH 0931/1313] QUIC: Implement QUIC ack tracing --- iocore/net/quic/QUICAckFrameCreator.cc | 83 +++++++++++++------ iocore/net/quic/QUICAckFrameCreator.h | 19 +++-- .../net/quic/test/test_QUICAckFrameCreator.cc | 35 +++++--- 3 files changed, 93 insertions(+), 44 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index d1700d7e55a..45daf411617 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -62,7 +62,7 @@ QUICAckFrameCreator::update(QUICEncryptionLevel level, QUICPacketNumber packet_n QUICFrameUPtr QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { - QUICFrameUPtr ack_frame = QUICFrameFactory::create_null_frame(); + std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); if (!this->_is_level_matched(level) || level == QUICEncryptionLevel::ZERO_RTT) { return ack_frame; @@ -73,38 +73,48 @@ QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connecti ack_frame = this->_create_ack_frame(level); if (ack_frame && ack_frame->size() > maximum_frame_size) { // Cancel generating frame - ack_frame = QUICFrameFactory::create_null_frame(); + ack_frame = QUICFrameFactory::create_null_ack_frame(); } else { - this->_can_send[index] = false; + this->_can_send[index] = true; this->_should_send[index] = false; - this->_packet_numbers[index].clear(); } } + if (ack_frame != nullptr) { + AckFrameInfomation ack_info; + ack_info.largest_acknowledged = ack_frame->largest_acknowledged(); + + QUICFrameInformation info; + info.level = level; + info.type = ack_frame->type(); + memcpy(info.data, &ack_info, sizeof(ack_info)); + this->_records_frame(info); + } + return ack_frame; } -QUICFrameUPtr +std::unique_ptr QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) { - int index = QUICTypeUtil::pn_space_index(level); - QUICAckPacketNumbers *packet_numbers = &this->_packet_numbers[index]; + int index = QUICTypeUtil::pn_space_index(level); + this->_packet_numbers[index].sort(); + auto list = this->_packet_numbers[index].list(); std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); - packet_numbers->sort(); - QUICPacketNumber largest_ack_number = packet_numbers->largest_ack_number(); - QUICPacketNumber last_ack_number = largest_ack_number; + QUICPacketNumber largest_ack_number = list.front(); + QUICPacketNumber last_ack_number = largest_ack_number; - size_t i = 0; uint8_t gap = 0; uint64_t length = 0; - while (i < packet_numbers->size()) { - QUICPacketNumber pn = (*packet_numbers)[i]; + auto it = list.begin(); + while (it != list.end()) { + QUICPacketNumber pn = *it; if (pn == last_ack_number) { last_ack_number--; length++; - i++; + it++; continue; } @@ -114,7 +124,7 @@ QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { uint64_t delay = this->_calculate_delay(level); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_frame_ids, this); } gap = last_ack_number - pn; @@ -126,7 +136,7 @@ QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { uint64_t delay = this->_calculate_delay(level); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_frame_ids, this); } return ack_frame; @@ -158,9 +168,35 @@ QUICAckFrameCreator::_calculate_delay(QUICEncryptionLevel level) return delay >> ack_delay_exponent; } +void +QUICAckFrameCreator::_on_frame_acked(QUICFrameInformation info) +{ + ink_assert(info.type == QUICFrameType::ACK); + AckFrameInfomation *ack_info = reinterpret_cast(info.data); + int index = QUICTypeUtil::pn_space_index(info.level); + this->_packet_numbers[index].forget(ack_info->largest_acknowledged); + if (this->_packet_numbers[index].size() == 0) { + this->_can_send[index] = false; + this->_should_send[index] = false; + } +} + // // QUICAckPacketNumbers // +void +QUICAckPacketNumbers::forget(QUICPacketNumber largest_acknowledged) +{ + this->sort(); + std::list remove_list; + for (auto it = this->_packet_numbers.begin(); it != this->_packet_numbers.end(); it++) { + if (*it == largest_acknowledged) { + remove_list.splice(remove_list.begin(), this->_packet_numbers, it, this->_packet_numbers.end()); + return; + } + } +} + void QUICAckPacketNumbers::push_back(QUICPacketNumber packet_number) { @@ -172,16 +208,10 @@ QUICAckPacketNumbers::push_back(QUICPacketNumber packet_number) this->_packet_numbers.push_back(packet_number); } -QUICPacketNumber -QUICAckPacketNumbers::front() -{ - return this->_packet_numbers.front(); -} - -QUICPacketNumber -QUICAckPacketNumbers::back() +const std::list +QUICAckPacketNumbers::list() const { - return this->_packet_numbers.back(); + return this->_packet_numbers; } size_t @@ -214,6 +244,5 @@ void QUICAckPacketNumbers::sort() { // TODO Find more smart way - std::sort(this->_packet_numbers.begin(), this->_packet_numbers.end(), - [](QUICPacketNumber a, QUICPacketNumber b) -> bool { return b < a; }); + this->_packet_numbers.sort([] (const QUICPacketNumber a, const QUICPacketNumber b)-> bool { return a > b; }); } diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 738dfb3daa1..166ae5dd1a3 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -27,29 +27,28 @@ #include "QUICFrameGenerator.h" #include "QUICTypes.h" #include "QUICFrame.h" -#include +#include #include class QUICAckPacketNumbers { public: void push_back(QUICPacketNumber packet_number); - QUICPacketNumber front(); - QUICPacketNumber back(); size_t size(); void clear(); void sort(); + void forget(QUICPacketNumber largest_acknowledged); + + const std::list list() const; QUICPacketNumber largest_ack_number(); ink_hrtime largest_ack_received_time(); - const QUICPacketNumber &operator[](int i) const { return this->_packet_numbers[i]; } - private: QUICPacketNumber _largest_ack_number = 0; ink_hrtime _largest_ack_received_time = 0; - std::vector _packet_numbers; + std::list _packet_numbers; }; class QUICAckFrameCreator : public QUICFrameGenerator @@ -77,11 +76,17 @@ class QUICAckFrameCreator : public QUICFrameGenerator QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; private: + struct AckFrameInfomation { + QUICPacketNumber largest_acknowledged = 0; + }; + + virtual void _on_frame_acked(QUICFrameInformation info) override; + /* * Returns QUICAckFrame only if ACK frame is able to be sent. * Caller must send the ACK frame to the peer if it was returned. */ - QUICFrameUPtr _create_ack_frame(QUICEncryptionLevel level); + std::unique_ptr _create_ack_frame(QUICEncryptionLevel level); uint64_t _calculate_delay(QUICEncryptionLevel level); std::vector _encryption_level_filter() override diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 194c34047a8..c1563ef449d 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -45,9 +45,8 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame->largest_acknowledged() == 1); CHECK(frame->ack_block_section()->first_ack_block() == 0); - ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); - CHECK(frame == nullptr); + // retry + CHECK(creator.will_generate_frame(level) == false); // Not sequential creator.update(level, 2, true); @@ -59,7 +58,7 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 5); - CHECK(frame->ack_block_section()->first_ack_block() == 3); + CHECK(frame->ack_block_section()->first_ack_block() == 4); // Loss creator.update(level, 6, true); @@ -72,6 +71,24 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame->largest_acknowledged() == 10); CHECK(frame->ack_block_section()->first_ack_block() == 0); CHECK(frame->ack_block_section()->begin()->gap() == 1); + + // on frame acked + creator.on_frame_acked(frame->id()); + + CHECK(creator.will_generate_frame(level) == false); + ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + CHECK(ack_frame == nullptr); + + creator.update(level, 11, true); + creator.update(level, 12, true); + creator.update(level, 13, true); + ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); + CHECK(frame != nullptr); + CHECK(frame->ack_block_count() == 0); + CHECK(frame->largest_acknowledged() == 13); + CHECK(frame->ack_block_section()->first_ack_block() == 2); + CHECK(frame->ack_block_section()->begin()->gap() == 0); } TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") @@ -98,9 +115,7 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 1); CHECK(frame->ack_block_section()->begin()->gap() == 0); - ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); - CHECK(frame == nullptr); + CHECK(creator.will_generate_frame(level) == false); creator.update(level, 7, true); creator.update(level, 4, true); @@ -108,9 +123,9 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); - CHECK(frame->largest_acknowledged() == 7); - CHECK(frame->ack_block_section()->first_ack_block() == 0); - CHECK(frame->ack_block_section()->begin()->gap() == 1); + CHECK(frame->largest_acknowledged() == 9); + CHECK(frame->ack_block_section()->first_ack_block() == 5); + CHECK(frame->ack_block_section()->begin()->gap() == 0); } TEST_CASE("QUICAckFrameCreator_QUICAckPacketNumbers", "[quic]") From 10ab66a95241ec6fd3ba56417c7d833fd0b90b75 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 26 Nov 2018 20:47:01 +0800 Subject: [PATCH 0932/1313] run clang-format --- iocore/net/quic/QUICAckFrameCreator.cc | 2 +- iocore/net/quic/test/test_QUICAckFrameCreator.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 45daf411617..00c6ea6c159 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -244,5 +244,5 @@ void QUICAckPacketNumbers::sort() { // TODO Find more smart way - this->_packet_numbers.sort([] (const QUICPacketNumber a, const QUICPacketNumber b)-> bool { return a > b; }); + this->_packet_numbers.sort([](const QUICPacketNumber a, const QUICPacketNumber b) -> bool { return a > b; }); } diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index c1563ef449d..329cef8e4f2 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -72,7 +72,7 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 0); CHECK(frame->ack_block_section()->begin()->gap() == 1); - // on frame acked + // on frame acked creator.on_frame_acked(frame->id()); CHECK(creator.will_generate_frame(level) == false); From ab21f0cc4866035150204acdd6deb04865735b7c Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 27 Nov 2018 09:21:42 +0800 Subject: [PATCH 0933/1313] QUIC: Add issue_frame_id to get latest frame id --- iocore/net/quic/QUICAckFrameCreator.cc | 6 +++--- iocore/net/quic/QUICFrameGenerator.cc | 4 ++-- iocore/net/quic/QUICFrameGenerator.h | 13 +++++++++---- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 00c6ea6c159..34d66bb8524 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -88,7 +88,7 @@ QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connecti info.level = level; info.type = ack_frame->type(); memcpy(info.data, &ack_info, sizeof(ack_info)); - this->_records_frame(info); + this->_records_frame(ack_frame->id(), info); } return ack_frame; @@ -124,7 +124,7 @@ QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { uint64_t delay = this->_calculate_delay(level); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_frame_ids, this); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_issue_frame_id(), this); } gap = last_ack_number - pn; @@ -136,7 +136,7 @@ QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { uint64_t delay = this->_calculate_delay(level); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_frame_ids, this); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_issue_frame_id(), this); } return ack_frame; diff --git a/iocore/net/quic/QUICFrameGenerator.cc b/iocore/net/quic/QUICFrameGenerator.cc index f7f8f6e2873..96aa0587d82 100644 --- a/iocore/net/quic/QUICFrameGenerator.cc +++ b/iocore/net/quic/QUICFrameGenerator.cc @@ -24,9 +24,9 @@ #include "QUICFrameGenerator.h" void -QUICFrameGenerator::_records_frame(QUICFrameInformation info) +QUICFrameGenerator::_records_frame(QUICFrameId id, QUICFrameInformation info) { - this->_info.insert(std::make_pair(this->_frame_ids++, info)); + this->_info.insert(std::make_pair(id, info)); } std::vector diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index eea0b8e43bc..c75d7489ab9 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -43,6 +43,12 @@ class QUICFrameGenerator void on_frame_lost(QUICFrameId id); protected: + QUICFrameId + _issue_frame_id() + { + return this->_latest_frame_Id++; + } + virtual void _on_frame_acked(QUICFrameInformation info) { @@ -55,10 +61,9 @@ class QUICFrameGenerator virtual std::vector _encryption_level_filter(); virtual bool _is_level_matched(QUICEncryptionLevel level); - void _records_frame(QUICFrameInformation info); - - uint64_t _frame_ids = 0; + void _records_frame(QUICFrameId id, QUICFrameInformation info); private: - std::map _info; + QUICFrameId _latest_frame_Id = 0; + std::map _info; }; From b17f0f47e4af1d022fcc2b0a9cea3b1b3884a948 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 27 Nov 2018 09:31:21 +0800 Subject: [PATCH 0934/1313] QUIC: Removes unused the memcpy --- iocore/net/quic/QUICAckFrameCreator.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 34d66bb8524..73953ee14ba 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -81,13 +81,12 @@ QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connecti } if (ack_frame != nullptr) { - AckFrameInfomation ack_info; - ack_info.largest_acknowledged = ack_frame->largest_acknowledged(); - QUICFrameInformation info; + AckFrameInfomation *ack_info = reinterpret_cast(info.data); + ack_info->largest_acknowledged = ack_frame->largest_acknowledged(); + info.level = level; info.type = ack_frame->type(); - memcpy(info.data, &ack_info, sizeof(ack_info)); this->_records_frame(ack_frame->id(), info); } From c625b48a78ddb86cd3b5768e37f000295dbb8a31 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 26 Nov 2018 16:13:46 +0900 Subject: [PATCH 0935/1313] Refacotr retry token and stateless reset token --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/QUICPacketHandler.cc | 22 +++--- iocore/net/quic/Makefile.am | 1 - iocore/net/quic/QUICAltConnectionManager.cc | 3 +- iocore/net/quic/QUICConfig.cc | 3 - iocore/net/quic/QUICPacket.cc | 10 ++- iocore/net/quic/QUICPacket.h | 2 +- iocore/net/quic/QUICStatelessRetry.cc | 69 ------------------- iocore/net/quic/QUICStatelessRetry.h | 38 ---------- iocore/net/quic/QUICTypes.cc | 19 ++++- iocore/net/quic/QUICTypes.h | 47 +++++++++++-- .../net/quic/test/test_QUICPacketFactory.cc | 16 ++--- 12 files changed, 83 insertions(+), 149 deletions(-) delete mode 100644 iocore/net/quic/QUICStatelessRetry.cc delete mode 100644 iocore/net/quic/QUICStatelessRetry.h diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5873292ddd4..3556dd9e7dd 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -207,7 +207,7 @@ QUICNetVConnection::start() // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not if (this->direction() == NET_VCONNECTION_IN) { this->_ack_frame_creator.set_ack_delay_exponent(params->ack_delay_exponent_in()); - this->_reset_token.generate(this->_quic_connection_id, params->instance_id()); + this->_reset_token = QUICStatelessResetToken(this->_quic_connection_id, params->instance_id()); this->_hs_protocol = this->_setup_handshake_protocol(params->server_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol, this->_reset_token, params->stateless_retry()); } else { diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index a97a871e10a..fb6b3a0c0c2 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -29,7 +29,6 @@ #include "QUICPacket.h" #include "QUICDebugNames.h" #include "QUICEvents.h" -#include "QUICStatelessRetry.h" static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6; static constexpr char tag[] = "quic_sec"; @@ -292,11 +291,8 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // 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)) { - QUICStatelessResetToken token; - { - QUICConfig::scoped_config params; - token.generate(dcid, params->instance_id()); - } + QUICConfig::scoped_config params; + QUICStatelessResetToken token(dcid, params->instance_id()); auto packet = QUICPacketFactory::create_stateless_reset_packet(dcid, token); this->_send_packet(this, *packet, udp_packet->getConnection(), udp_packet->from, 1200, nullptr, 0); udp_packet->free(); @@ -378,14 +374,10 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC } if (token_length == 0) { - ats_unique_buf retry_token = ats_unique_malloc(QUICStatelessRetry::MAX_TOKEN_LEN); - size_t retry_token_len = 0; - QUICStatelessRetry::generate_cookie(retry_token.get(), &retry_token_len, from); - + QUICRetryToken token(from); QUICConnectionId local_cid; local_cid.randomize(); - QUICPacketUPtr retry_packet = - QUICPacketFactory::create_retry_packet(scid, local_cid, dcid, std::move(retry_token), retry_token_len); + QUICPacketUPtr retry_packet = QUICPacketFactory::create_retry_packet(scid, local_cid, dcid, token); this->_send_packet(this, *retry_packet, connection, from, 1200, nullptr, 0); @@ -394,9 +386,11 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC uint8_t dcil, scil; QUICPacketLongHeader::dcil(dcil, buf, buf_len); QUICPacketLongHeader::scil(scil, buf, buf_len); - const uint8_t *token = buf + LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil + token_length_field_len; - if (QUICStatelessRetry::verify_cookie(token, token_length, from)) { + + QUICRetryToken token1(token, token_length); + QUICRetryToken token2(from); + if (token1 == token2) { return 0; } else { return -3; diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 519ae177bb6..0b68e05dece 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -78,7 +78,6 @@ libquic_a_SOURCES = \ QUICPacketReceiveQueue.cc \ QUICPacketRetransmitter.cc \ QUICPathValidator.cc \ - QUICStatelessRetry.cc \ QUICFrameGenerator.cc # diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 8bd208e289b..d272bf648da 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -99,9 +99,8 @@ QUICAltConnectionManager::AltConnectionInfo QUICAltConnectionManager::_generate_next_alt_con_info() { QUICConnectionId conn_id; - QUICStatelessResetToken token; conn_id.randomize(); - token.generate(conn_id, this->_instance_id); + QUICStatelessResetToken token(conn_id, this->_instance_id); AltConnectionInfo aci = {++this->_alt_quic_connection_id_seq_num, conn_id, token, {false}}; if (this->_qc->direction() == NET_VCONNECTION_IN) { diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 905568b9e43..3b0c8798174 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -31,7 +31,6 @@ #include "QUICGlobals.h" #include "QUICTransportParameters.h" -#include "QUICStatelessRetry.h" // OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings) // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html @@ -197,8 +196,6 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_cc_minimum_window_scale, "proxy.config.quic.congestion_control.minimum_window_scale"); REC_EstablishStaticConfigFloat(this->_cc_loss_reduction_factor, "proxy.config.quic.congestion_control.loss_reduction_factor"); - QUICStatelessRetry::init(); - this->_server_ssl_ctx = quic_init_server_ssl_ctx(this); this->_client_ssl_ctx = quic_init_client_ssl_ctx(this); } diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 6f218ee04ca..670bceeb2cf 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -1257,10 +1257,14 @@ QUICPacketFactory::create_initial_packet(QUICConnectionId destination_cid, QUICC QUICPacketUPtr QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, - QUICConnectionId original_dcid, ats_unique_buf payload, size_t len) + QUICConnectionId original_dcid, QUICRetryToken &token) { - QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, QUICKeyPhase::INITIAL, QUIC_SUPPORTED_VERSIONS[0], - destination_cid, source_cid, original_dcid, std::move(payload), len); + ats_unique_buf payload = ats_unique_malloc(token.length()); + memcpy(payload.get(), token.buf(), token.length()); + + 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)); } diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 3c35fcbf0f7..63ccbdf48f5 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -436,7 +436,7 @@ class QUICPacketFactory 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, ats_unique_buf payload, size_t len); + QUICConnectionId original_dcid, QUICRetryToken &token); QUICPacketUPtr create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result); diff --git a/iocore/net/quic/QUICStatelessRetry.cc b/iocore/net/quic/QUICStatelessRetry.cc deleted file mode 100644 index 86cf8037e43..00000000000 --- a/iocore/net/quic/QUICStatelessRetry.cc +++ /dev/null @@ -1,69 +0,0 @@ -/** @file - * - * Callbacks for Stateless Retry - * - * @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 "QUICStatelessRetry.h" - -#include -#include -#include - -#include "QUICGlobals.h" -#include "QUICConnection.h" - -static constexpr size_t STATELESS_COOKIE_SECRET_LENGTH = 16; -static uint8_t stateless_cookie_secret[STATELESS_COOKIE_SECRET_LENGTH] = {0}; - -void -QUICStatelessRetry::init() -{ - // TODO: read cookie secret from file like SSLTicketKeyConfig - RAND_bytes(stateless_cookie_secret, STATELESS_COOKIE_SECRET_LENGTH); -} - -int -QUICStatelessRetry::generate_cookie(unsigned char *cookie, size_t *cookie_len, IpEndpoint src) -{ - uint8_t key[INET6_ADDRPORTSTRLEN] = {0}; - size_t key_len = INET6_ADDRPORTSTRLEN; - ats_ip_nptop(src, reinterpret_cast(key), key_len); - - unsigned int dst_len = 0; - HMAC(EVP_sha1(), stateless_cookie_secret, STATELESS_COOKIE_SECRET_LENGTH, key, key_len, cookie, &dst_len); - *cookie_len = dst_len; - - return 1; -} - -int -QUICStatelessRetry::verify_cookie(const unsigned char *cookie, size_t cookie_len, IpEndpoint src) -{ - uint8_t token[EVP_MAX_MD_SIZE]; - size_t token_len; - - if (QUICStatelessRetry::generate_cookie(token, &token_len, src) && cookie_len == token_len && - memcmp(token, cookie, cookie_len) == 0) { - return 1; - } else { - return 0; - } -} diff --git a/iocore/net/quic/QUICStatelessRetry.h b/iocore/net/quic/QUICStatelessRetry.h deleted file mode 100644 index dc213f7794b..00000000000 --- a/iocore/net/quic/QUICStatelessRetry.h +++ /dev/null @@ -1,38 +0,0 @@ -/** @file - * - * Callbacks for Stateless Retry - * - * @section license License - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -#include "tscore/ink_inet.h" - -class QUICStatelessRetry -{ -public: - static constexpr size_t MAX_TOKEN_LEN = EVP_MAX_MD_SIZE; - - static void init(); - static int generate_cookie(unsigned char *cookie, size_t *cookie_len, IpEndpoint src); - static int verify_cookie(const unsigned char *cookie, size_t cookie_len, IpEndpoint src); -}; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 80973ea7426..5649619bf12 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -24,6 +24,8 @@ #include #include "QUICTypes.h" #include "QUICIntUtil.h" +#include "tscore/CryptoHash.h" +#include uint8_t QUICConnectionId::SCID_LEN = 0; @@ -260,9 +262,9 @@ QUICTypeUtil::write_QUICMaxData(uint64_t max_data, uint8_t *buf, size_t *len) QUICIntUtil::write_QUICVariableInt(max_data, buf, len); } -void -QUICStatelessResetToken::_gen_token(uint64_t data) +QUICStatelessResetToken::QUICStatelessResetToken(QUICConnectionId conn_id, uint32_t instance_id) { + uint64_t data = conn_id ^ instance_id; CryptoHash _hash; static constexpr char STATELESS_RESET_TOKEN_KEY[] = "stateless_token_reset_key"; CryptoContext ctx; @@ -275,6 +277,19 @@ QUICStatelessResetToken::_gen_token(uint64_t data) QUICIntUtil::write_uint_as_nbytes(_hash.u64[1], 8, _token + 8, &dummy); } +QUICRetryToken::QUICRetryToken(const IpEndpoint &src) +{ + // TODO: read cookie secret from file like SSLTicketKeyConfig + static constexpr char stateless_retry_token_secret[] = "stateless_cookie_secret"; + + uint8_t key[INET6_ADDRPORTSTRLEN] = {0}; + size_t key_len = INET6_ADDRPORTSTRLEN; + ats_ip_nptop(src, reinterpret_cast(key), key_len); + + HMAC(EVP_sha1(), stateless_retry_token_secret, sizeof(stateless_retry_token_secret), key, key_len, this->_token, + &this->_token_len); +} + QUICFrameType QUICConnectionError::frame_type() const { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 419daa4d19e..e3b10083d24 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -29,9 +29,9 @@ #include #include #include -#include "tscore/INK_MD5.h" #include "tscore/ink_memory.h" #include "tscore/ink_inet.h" +#include "openssl/evp.h" // These magical defines should be removed when we implement seriously #define MAGIC_NUMBER_0 0 @@ -274,11 +274,13 @@ class QUICStatelessResetToken constexpr static int8_t LEN = 16; QUICStatelessResetToken() {} + QUICStatelessResetToken(QUICConnectionId conn_id, uint32_t instance_id); QUICStatelessResetToken(const uint8_t *buf) { memcpy(this->_token, buf, QUICStatelessResetToken::LEN); } - void - generate(QUICConnectionId conn_id, uint32_t instance_id) + + bool + operator==(const QUICStatelessResetToken &x) const { - this->_gen_token(conn_id ^ instance_id); + return memcmp(this->_token, x._token, QUICStatelessResetToken::LEN) == 0; } const uint8_t * @@ -288,9 +290,42 @@ class QUICStatelessResetToken } private: - uint8_t _token[16] = {0}; + uint8_t _token[LEN] = {0}; + + void _generate(uint64_t data); +}; + +class QUICRetryToken +{ +public: + QUICRetryToken() {} + QUICRetryToken(const uint8_t *buf, uint8_t len) : _token_len(len) { memcpy(this->_token, buf, len); } + QUICRetryToken(const IpEndpoint &src); + + bool + operator==(const QUICRetryToken &x) const + { + if (this->_token_len != x._token_len) { + return false; + } + return memcmp(this->_token, x._token, this->_token_len) == 0; + } - void _gen_token(uint64_t data); + const uint8_t * + buf() const + { + return this->_token; + } + + uint8_t + length() const + { + return this->_token_len; + } + +private: + uint8_t _token[EVP_MAX_MD_SIZE] = {}; + unsigned int _token_len = 0; }; class QUICPreferredAddress diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index e6cd60fa1c2..65e0d5e867d 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -69,14 +69,13 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") factory.set_hs_protocol(&hs_protocol); factory.set_version(0x11223344); - uint8_t raw[] = {0xaa, 0xbb, 0xcc, 0xdd}; - ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); - memcpy(payload.get(), raw, sizeof(raw)); + uint8_t raw[] = {0xaa, 0xbb, 0xcc, 0xdd}; + QUICRetryToken token(raw, 4); - QUICPacketUPtr packet = factory.create_retry_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), - QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), - QUICConnectionId(reinterpret_cast("\x04\x03\x02\x01"), 4), - std::move(payload), sizeof(raw)); + QUICPacketUPtr packet = + factory.create_retry_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), + QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), + QUICConnectionId(reinterpret_cast("\x04\x03\x02\x01"), 4), token); CHECK(packet->type() == QUICPacketType::RETRY); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); @@ -112,8 +111,7 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") QUICPacketFactory factory; MockQUICHandshakeProtocol hs_protocol; factory.set_hs_protocol(&hs_protocol); - QUICStatelessResetToken token; - token.generate({reinterpret_cast("\x30\x39"), 2}, 67890); + QUICStatelessResetToken token({reinterpret_cast("\x30\x39"), 2}, 67890); QUICPacketUPtr packet = factory.create_stateless_reset_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), token); From 0ef9bce3206ac4bc949003c3a7dc78aacc7780e6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 27 Nov 2018 13:59:23 +0900 Subject: [PATCH 0936/1313] Send original_connection_id TP --- iocore/net/P_QUICNetVConnection.h | 7 +++++-- iocore/net/P_QUICPacketHandler.h | 2 +- iocore/net/QUICNetVConnection.cc | 35 +++++++++++++++++++++++++++++-- iocore/net/QUICPacketHandler.cc | 14 ++++++++----- iocore/net/quic/Mock.h | 12 +++++++++++ iocore/net/quic/QUICConnection.h | 1 + iocore/net/quic/QUICHandshake.cc | 4 ++++ iocore/net/quic/QUICTypes.cc | 26 ++++++++++++++++++----- iocore/net/quic/QUICTypes.h | 9 +++++--- 9 files changed, 92 insertions(+), 18 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 27c6919076f..76e5fe965ac 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -152,8 +152,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub public: QUICNetVConnection() {} - void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *, QUICPacketHandler *, - QUICConnectionTable *ctable = nullptr); + void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *, QUICPacketHandler *); + void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, QUICConnectionId first_cid, UDPConnection *, + QUICPacketHandler *, QUICConnectionTable *ctable); // accept new conn_id int acceptEvent(int event, Event *e); @@ -196,6 +197,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub // QUICConnection (QUICConnectionInfoProvider) QUICConnectionId peer_connection_id() const override; QUICConnectionId original_connection_id() const override; + QUICConnectionId first_connection_id() const override; QUICConnectionId connection_id() const override; std::string_view cids() const override; const QUICFiveTuple five_tuple() const override; @@ -233,6 +235,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICConnectionId _peer_quic_connection_id; // dst cid in local QUICConnectionId _peer_old_quic_connection_id; // dst previous cid in local QUICConnectionId _original_quic_connection_id; // dst cid of initial packet from client + QUICConnectionId _first_quic_connection_id; // dst cid of initial packet from client that doesn't have retry token QUICConnectionId _quic_connection_id; // src cid in local QUICFiveTuple _five_tuple; bool _connection_migration_initiated = false; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index f96deaafdae..c475e9f206d 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -80,7 +80,7 @@ class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler 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 scid, QUICConnectionId *original_cid); QUICConnectionTable *_ctable = nullptr; }; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3556dd9e7dd..2a35eaed0c7 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -79,7 +79,7 @@ ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); // XXX This might be called on ET_UDP thread void QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *udp_con, - QUICPacketHandler *packet_handler, QUICConnectionTable *ctable) + QUICPacketHandler *packet_handler) { SET_HANDLER((NetVConnHandler)&QUICNetVConnection::acceptEvent); this->_packet_transmitter_mutex = new_ProxyMutex(); @@ -89,7 +89,32 @@ QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_ci this->_peer_quic_connection_id = peer_cid; this->_original_quic_connection_id = original_cid; this->_quic_connection_id.randomize(); - // PacketHandler for out going connection doesn't have connection table + + 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); + } +} +void +QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_cid, QUICConnectionId first_cid, + UDPConnection *udp_con, QUICPacketHandler *packet_handler, QUICConnectionTable *ctable) +{ + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::acceptEvent); + this->_packet_transmitter_mutex = new_ProxyMutex(); + this->_frame_transmitter_mutex = new_ProxyMutex(); + this->_udp_con = udp_con; + this->_packet_handler = packet_handler; + this->_peer_quic_connection_id = peer_cid; + this->_original_quic_connection_id = original_cid; + this->_first_quic_connection_id = first_cid; + this->_quic_connection_id.randomize(); + if (ctable) { this->_ctable = ctable; this->_ctable->insert(this->_quic_connection_id, this); @@ -347,6 +372,12 @@ QUICNetVConnection::original_connection_id() const return this->_original_quic_connection_id; } +QUICConnectionId +QUICNetVConnection::first_connection_id() const +{ + return this->_first_quic_connection_id; +} + QUICConnectionId QUICNetVConnection::connection_id() const { diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index fb6b3a0c0c2..55122979dd2 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -279,8 +279,9 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // Server Stateless Retry QUICConfig::scoped_config params; + QUICConnectionId cid_in_retry_token; if (!vc && params->stateless_retry()) { - int ret = this->_stateless_retry(buf, buf_len, udp_packet->getConnection(), udp_packet->from, dcid, scid); + int ret = this->_stateless_retry(buf, buf_len, udp_packet->getConnection(), udp_packet->from, dcid, scid, &cid_in_retry_token); if (ret < 0) { udp_packet->free(); return; @@ -316,7 +317,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) } vc = static_cast(getNetProcessor()->allocate_vc(nullptr)); - vc->init(peer_cid, original_cid, udp_packet->getConnection(), this, this->_ctable); + vc->init(peer_cid, original_cid, cid_in_retry_token, udp_packet->getConnection(), this, this->_ctable); vc->id = net_next_connection_number(); vc->con.move(con); vc->submit_time = Thread::get_hrtime(); @@ -357,7 +358,7 @@ QUICPacketHandlerIn::send_packet(QUICNetVConnection *vc, Ptr udp_ int QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPConnection *connection, IpEndpoint from, - QUICConnectionId dcid, QUICConnectionId scid) + QUICConnectionId dcid, QUICConnectionId scid, QUICConnectionId *original_cid) { QUICPacketType type = QUICPacketType::UNINITIALIZED; QUICPacketLongHeader::type(type, buf, buf_len); @@ -374,7 +375,7 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC } if (token_length == 0) { - QUICRetryToken token(from); + QUICRetryToken token(from, dcid); QUICConnectionId local_cid; local_cid.randomize(); QUICPacketUPtr retry_packet = QUICPacketFactory::create_retry_packet(scid, local_cid, dcid, token); @@ -388,9 +389,12 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC QUICPacketLongHeader::scil(scil, buf, buf_len); const uint8_t *token = buf + LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil + token_length_field_len; + QUICConnectionId attached_cid = QUICTypeUtil::read_QUICConnectionId(token + 20, token_length - 20); QUICRetryToken token1(token, token_length); - QUICRetryToken token2(from); + QUICRetryToken token2(from, attached_cid); if (token1 == token2) { + // Tokein is valid + *original_cid = attached_cid; return 0; } else { return -3; diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index b660b97105e..008b3127c39 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -166,6 +166,12 @@ class MockQUICConnection : public QUICConnection return {reinterpret_cast("\x00"), 1}; } + QUICConnectionId + first_connection_id() const override + { + return {reinterpret_cast("\x00"), 1}; + } + const QUICFiveTuple five_tuple() const override { @@ -301,6 +307,12 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider return {reinterpret_cast("\x00"), 1}; } + QUICConnectionId + first_connection_id() const override + { + return {reinterpret_cast("\x00"), 1}; + } + const QUICFiveTuple five_tuple() const override { diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 7e4ae8b33ca..aa67aec7f69 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -38,6 +38,7 @@ class QUICConnectionInfoProvider public: virtual QUICConnectionId peer_connection_id() const = 0; virtual QUICConnectionId original_connection_id() const = 0; + virtual QUICConnectionId first_connection_id() const = 0; virtual QUICConnectionId connection_id() const = 0; virtual std::string_view cids() const = 0; virtual const QUICFiveTuple five_tuple() const = 0; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 6b2f829eadc..5912a7aae65 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -367,6 +367,10 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve // MUSTs tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); + if (this->_stateless_retry) { + tp->set(QUICTransportParameterId::ORIGINAL_CONNECTION_ID, this->_qc->first_connection_id(), + this->_qc->first_connection_id().length()); + } // MAYs if (params->initial_max_data_in() != 0) { diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 5649619bf12..74c9b95a820 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -277,17 +277,33 @@ QUICStatelessResetToken::QUICStatelessResetToken(QUICConnectionId conn_id, uint3 QUICIntUtil::write_uint_as_nbytes(_hash.u64[1], 8, _token + 8, &dummy); } -QUICRetryToken::QUICRetryToken(const IpEndpoint &src) +QUICRetryToken::QUICRetryToken(const IpEndpoint &src, QUICConnectionId original_dcid) { // TODO: read cookie secret from file like SSLTicketKeyConfig static constexpr char stateless_retry_token_secret[] = "stateless_cookie_secret"; - uint8_t key[INET6_ADDRPORTSTRLEN] = {0}; - size_t key_len = INET6_ADDRPORTSTRLEN; - ats_ip_nptop(src, reinterpret_cast(key), key_len); + uint8_t data[INET6_ADDRPORTSTRLEN + QUICConnectionId::MAX_LENGTH] = {0}; + size_t data_len = 0; + ats_ip_nptop(src, reinterpret_cast(data), sizeof(data)); + data_len = strlen(reinterpret_cast(data)); - HMAC(EVP_sha1(), stateless_retry_token_secret, sizeof(stateless_retry_token_secret), key, key_len, this->_token, + size_t cid_len; + QUICTypeUtil::write_QUICConnectionId(original_dcid, data + data_len, &cid_len); + data_len += cid_len; + + HMAC(EVP_sha1(), stateless_retry_token_secret, sizeof(stateless_retry_token_secret), data, data_len, this->_token, &this->_token_len); + ink_assert(this->_token_len == 20); + + QUICTypeUtil::write_QUICConnectionId(original_dcid, this->_token + this->_token_len, &cid_len); + this->_token_len += cid_len; +} + +const QUICConnectionId +QUICRetryToken::original_dcid() const +{ + // Output of EVP_sha1() should be 160 bits + return QUICTypeUtil::read_QUICConnectionId(this->_token + 20, this->_token_len - 20); } QUICFrameType diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index e3b10083d24..43acd9edcb7 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -300,7 +300,7 @@ class QUICRetryToken public: QUICRetryToken() {} QUICRetryToken(const uint8_t *buf, uint8_t len) : _token_len(len) { memcpy(this->_token, buf, len); } - QUICRetryToken(const IpEndpoint &src); + QUICRetryToken(const IpEndpoint &src, QUICConnectionId original_dcid); bool operator==(const QUICRetryToken &x) const @@ -311,6 +311,8 @@ class QUICRetryToken return memcmp(this->_token, x._token, this->_token_len) == 0; } + const QUICConnectionId original_dcid() const; + const uint8_t * buf() const { @@ -324,8 +326,9 @@ class QUICRetryToken } private: - uint8_t _token[EVP_MAX_MD_SIZE] = {}; - unsigned int _token_len = 0; + uint8_t _token[EVP_MAX_MD_SIZE + QUICConnectionId::MAX_LENGTH] = {}; + unsigned int _token_len = 0; + QUICConnectionId _original_dcid; }; class QUICPreferredAddress From 827548879007c8fc81dcd3aef8506fcdeada9885 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 27 Nov 2018 14:40:02 +0900 Subject: [PATCH 0937/1313] Remove dependency for TCL and tscore/Map.h --- iocore/net/P_QUICNetProcessor.h | 1 - iocore/net/quic/Makefile.am | 2 +- src/traffic_quic/Makefile.inc | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h index 7dfcba5c1d7..5c6bfb434fa 100644 --- a/iocore/net/P_QUICNetProcessor.h +++ b/iocore/net/P_QUICNetProcessor.h @@ -39,7 +39,6 @@ #include "tscore/ink_platform.h" #include "P_Net.h" -#include "tscore/Map.h" class UnixNetVConnection; struct NetAccept; diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 0b68e05dece..f39364cbde3 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -116,7 +116,7 @@ test_LDADD = \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @LIBTCL@ @OPENSSL_LIBS@ \ + @OPENSSL_LIBS@ \ @HWLOC_LIBS@ test_event_main_SOURCES = \ diff --git a/src/traffic_quic/Makefile.inc b/src/traffic_quic/Makefile.inc index 3cbc16b9b2d..c316eaf2d29 100644 --- a/src/traffic_quic/Makefile.inc +++ b/src/traffic_quic/Makefile.inc @@ -50,7 +50,6 @@ traffic_quic_traffic_quic_LDADD = \ $(top_builddir)/src/tscore/libtscore.la \ $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ - @LIBTCL@ \ @HWLOC_LIBS@ \ @YAMLCPP_LIBS@ \ @OPENSSL_LIBS@ From 6fa045be7449d55a5c6befe2add64d4ae601b4e9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 27 Nov 2018 15:40:15 +0900 Subject: [PATCH 0938/1313] PATH_RESPONSE doesn't need to be retransmitted --- iocore/net/quic/QUICPacketRetransmitter.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 1b92ea37b85..2832fdc1a59 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -44,6 +44,7 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) case QUICFrameType::PADDING: case QUICFrameType::ACK: case QUICFrameType::PATH_CHALLENGE: + case QUICFrameType::PATH_RESPONSE: break; default: frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); From 4171c2754683e703f72f5f74366c13bc649b4819 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 28 Nov 2018 16:09:20 +0900 Subject: [PATCH 0939/1313] Update stream state machine All stream states and transitions are covered, but not sure QUICStream uses it correctly. --- iocore/net/quic/Mock.h | 43 +++- iocore/net/quic/QUICApplication.cc | 3 + iocore/net/quic/QUICIncomingFrameBuffer.cc | 12 +- iocore/net/quic/QUICIncomingFrameBuffer.h | 2 +- iocore/net/quic/QUICStream.cc | 107 ++++++++- iocore/net/quic/QUICStream.h | 29 ++- iocore/net/quic/QUICStreamManager.cc | 3 +- iocore/net/quic/QUICStreamState.cc | 51 ++++- iocore/net/quic/QUICStreamState.h | 10 +- .../net/quic/QUICTransferProgressProvider.h | 43 +++- iocore/net/quic/test/test_QUICStreamState.cc | 205 +++++++++++++++++- 11 files changed, 477 insertions(+), 31 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 008b3127c39..ac201a87ce0 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -672,6 +672,7 @@ class MockQUICRTTProvider : public QUICRTTProvider class MockQUICTransferProgressProvider : public QUICTransferProgressProvider { +public: bool is_transfer_goal_set() const override { @@ -681,18 +682,54 @@ class MockQUICTransferProgressProvider : public QUICTransferProgressProvider bool is_transfer_complete() const override { - return false; + return this->_is_transfer_complete; + } + + bool + is_cancelled() const override + { + return this->_is_reset_complete; } uint64_t transfer_progress() const override { - return 0; + return this->_transfer_progress; } uint64_t transfer_goal() const override { - return 0; + return this->_transfer_goal; + } + + void + set_transfer_complete(bool b) + { + this->_is_transfer_complete = b; + } + + void + set_cancelled(bool b) + { + this->_is_reset_complete = b; + } + + void + set_transfer_progress(uint64_t v) + { + this->_transfer_progress = v; } + + void + set_transfer_goal(uint64_t v) + { + this->_transfer_goal = v; + } + +private: + bool _is_transfer_complete = false; + bool _is_reset_complete = false; + uint64_t _transfer_progress = 0; + uint64_t _transfer_goal = UINT64_MAX; }; diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index f931e6451b5..b1de71bc2de 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -77,6 +77,8 @@ QUICStreamIO::read(uint8_t *buf, int64_t len) this->_read_vio->ndone += nread; } + this->_stream->on_read(); + return nread; } @@ -90,6 +92,7 @@ void QUICStreamIO::consume(int64_t len) { this->_read_buffer_reader->consume(len); + this->_stream->on_read(); } bool diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index efc8f417934..82308fcca5c 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -159,12 +159,6 @@ QUICIncomingStreamFrameBuffer::is_transfer_goal_set() const return this->_fin_offset != UINT64_MAX; } -bool -QUICIncomingStreamFrameBuffer::is_transfer_complete() const -{ - return this->is_transfer_goal_set() && this->transfer_progress() == this->transfer_goal(); -} - uint64_t QUICIncomingStreamFrameBuffer::transfer_progress() const { @@ -177,6 +171,12 @@ QUICIncomingStreamFrameBuffer::transfer_goal() const return this->_fin_offset; } +bool +QUICIncomingStreamFrameBuffer::is_cancelled() const +{ + return false; +} + // // QUICIncomingCryptoFrameBuffer // diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index 456ea41dec0..cbca7bb9969 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -62,9 +62,9 @@ class QUICIncomingStreamFrameBuffer : public QUICIncomingFrameBuffer, public QUI // QUICTransferProgressProvider bool is_transfer_goal_set() const override; - bool is_transfer_complete() const override; uint64_t transfer_progress() const override; uint64_t transfer_goal() const override; + bool is_cancelled() const override; private: QUICConnectionErrorUPtr _check_and_set_fin_flag(QUICOffset offset, size_t len = 0, bool fin_flag = false); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index cad165345cc..4d798fdcbb7 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -52,7 +52,7 @@ QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider _local_flow_controller(rtt_provider, recv_max_stream_data, _id), _flow_control_buffer_size(recv_max_stream_data), _received_stream_frame_buffer(), - _state(nullptr, nullptr, &_received_stream_frame_buffer, nullptr) + _state(nullptr, &this->_progress_vio, this, nullptr) { SET_HANDLER(&QUICStream::state_stream_open); mutex = new_ProxyMutex(); @@ -288,6 +288,18 @@ QUICStream::_write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t } } +void +QUICStream::on_read() +{ + this->_state.update_on_read(); +} + +void +QUICStream::on_eos() +{ + this->_state.update_on_eos(); +} + /** * @brief Receive STREAM frame * @detail When receive STREAM frame, reorder frames and write to buffer of read_vio. @@ -377,6 +389,14 @@ QUICStream::recv(const QUICStopSendingFrame &frame) return nullptr; } +QUICConnectionErrorUPtr +QUICStream::recv(const QUICRstStreamFrame &frame) +{ + this->_state.update_with_receiving_frame(frame); + this->_signal_read_eos_event(); + return nullptr; +} + bool QUICStream::will_generate_frame(QUICEncryptionLevel level) { @@ -388,13 +408,16 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit { SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + // RST_STREAM - if (this->_reset_reason) { - return QUICFrameFactory::create_rst_stream_frame(std::move(this->_reset_reason)); + if (this->_reset_reason && !this->_is_reset_sent) { + frame = QUICFrameFactory::create_rst_stream_frame(std::move(this->_reset_reason)); + this->_state.update_with_sending_frame(*frame); + this->_is_reset_sent = true; + return frame; } - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - // MAX_STREAM_DATA frame = this->_local_flow_controller.generate_frame(level, UINT16_MAX, maximum_frame_size); if (frame) { @@ -483,6 +506,34 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit return frame; } +void +QUICStream::_on_frame_acked(QUICFrameInformation info) +{ + if (info.type == QUICFrameType::RST_STREAM) { + this->_is_reset_complete = true; + } else if (info.type == QUICFrameType::STREAM) { + // TODO Check if it received acks for every parts of data + if (false) { + this->_is_transfer_complete = true; + } + } + this->_state.update_on_ack(); +} + +void +QUICStream::_on_frame_lost(QUICFrameInformation info) +{ + if (info.type == QUICFrameType::RST_STREAM) { + // [draft-16] 13.2. Retransmission of Information + // Cancellation of stream transmission, as carried in a RST_STREAM + // frame, is sent until acknowledged or until all stream data is + // acknowledged by the peer (that is, either the "Reset Recvd" or + // "Data Recvd" state is reached on the send stream). The content of + // a RST_STREAM frame MUST NOT change when it is sent again. + this->_is_reset_sent = false; + } +} + /** * Replace existing event only if the new event is different than the inprogress event */ @@ -547,6 +598,28 @@ QUICStream::_signal_write_event() QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); } +/** + * @brief Signal event to this->_write_vio.cont + */ +void +QUICStream::_signal_read_eos_event() +{ + if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { + return; + } + MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread()); + + int event = VC_EVENT_EOS; + + if (lock.is_locked()) { + this->_write_vio.cont->handleEvent(event, &this->_write_vio); + } else { + this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio); + } + + QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); +} + int64_t QUICStream::_process_read_vio() { @@ -599,6 +672,30 @@ QUICStream::largest_offset_sent() const return this->_remote_flow_controller.current_offset(); } +bool +QUICStream::is_transfer_goal_set() const +{ + return this->_received_stream_frame_buffer.is_transfer_goal_set(); +} + +uint64_t +QUICStream::transfer_progress() const +{ + return this->_received_stream_frame_buffer.transfer_progress(); +} + +uint64_t +QUICStream::transfer_goal() const +{ + return this->_received_stream_frame_buffer.transfer_goal(); +} + +bool +QUICStream::is_cancelled() const +{ + return this->_is_reset_complete; +} + // // QUICCryptoStream // diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index c5a7967e507..1fc7e94d50d 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -38,7 +38,7 @@ * @brief QUIC Stream * TODO: This is similar to Http2Stream. Need to think some integration. */ -class QUICStream : public VConnection, public QUICFrameGenerator +class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTransferProgressProvider { public: QUICStream() @@ -67,10 +67,17 @@ class QUICStream : public VConnection, public QUICFrameGenerator void do_io_shutdown(ShutdownHowTo_t howto) override; void reenable(VIO *vio) override; + /* + * QUICApplication need to call one of these functions when it process VC_EVENT_* + */ + void on_read(); + void on_eos(); + QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame); QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame); QUICConnectionErrorUPtr recv(const QUICStreamBlockedFrame &frame); QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame); + QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame); void reset(QUICStreamErrorUPtr error); @@ -84,16 +91,25 @@ class QUICStream : public VConnection, public QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + // QUICTransferProgressProvider + bool is_transfer_goal_set() const override; + uint64_t transfer_progress() const override; + uint64_t transfer_goal() const override; + bool is_cancelled() const override; + protected: virtual int64_t _process_read_vio(); virtual int64_t _process_write_vio(); void _signal_read_event(); void _signal_write_event(); + void _signal_read_eos_event(); Event *_send_tracked_event(Event *, int, VIO *); void _write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin); - QUICStreamErrorUPtr _reset_reason = nullptr; + QUICStreamErrorUPtr _reset_reason = nullptr; + bool _is_reset_sent = false; + QUICConnectionInfoProvider *_connection_info = nullptr; QUICStreamId _id = 0; QUICOffset _send_offset = 0; @@ -106,15 +122,24 @@ class QUICStream : public VConnection, public QUICFrameGenerator VIO _read_vio; VIO _write_vio; + QUICTransferProgressProviderVIO _progress_vio = {this->_read_vio}; + Event *_read_event = nullptr; Event *_write_event = nullptr; + bool _is_transfer_complete = false; + bool _is_reset_complete = false; + // Fragments of received STREAM frame (offset is unmatched) // TODO: Consider to replace with ts/RbTree.h or other data structure QUICIncomingStreamFrameBuffer _received_stream_frame_buffer; // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState QUICBidirectionalStreamState _state; + + // QUICFrameGenerator + void _on_frame_acked(QUICFrameInformation info) override; + void _on_frame_lost(QUICFrameInformation info) override; }; /** diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 9263e7edc30..e58120f4738 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -212,8 +212,7 @@ QUICStreamManager::_handle_frame(const QUICRstStreamFrame &frame) { QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); if (stream) { - // TODO Reset the stream - return nullptr; + return stream->recv(frame); } else { return std::make_unique(QUICTransErrorCode::STREAM_ID_ERROR); } diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index 955fa130052..4621dfa403a 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -168,7 +168,7 @@ QUICReceiveStreamState::update_with_receiving_frame(const QUICFrame &frame) if (frame.type() == QUICFrameType::STREAM) { if (static_cast(frame).has_fin_flag()) { this->_set_state(State::SizeKnown); - if (this->_in_progress->is_transfer_complete()) { + if (this->_in_progress->transfer_progress() == this->_in_progress->transfer_goal()) { this->_set_state(State::DataRecvd); } } @@ -178,7 +178,7 @@ QUICReceiveStreamState::update_with_receiving_frame(const QUICFrame &frame) break; case State::SizeKnown: if (frame.type() == QUICFrameType::STREAM) { - if (this->_in_progress->is_transfer_complete()) { + if (this->_in_progress->transfer_progress() == this->_in_progress->transfer_goal()) { this->_set_state(State::DataRecvd); } } else if (frame.type() == QUICFrameType::RST_STREAM) { @@ -193,6 +193,11 @@ QUICReceiveStreamState::update_with_receiving_frame(const QUICFrame &frame) case State::DataRead: break; case State::ResetRecvd: + if (frame.type() == QUICFrameType::STREAM) { + if (this->_in_progress->transfer_progress() == this->_in_progress->transfer_goal()) { + this->_set_state(State::DataRecvd); + } + } break; case State::ResetRead: break; @@ -219,6 +224,20 @@ QUICReceiveStreamState::update(const QUICStreamState &opposite_side) } } +void +QUICReceiveStreamState::update_on_read() +{ + if (this->_in_progress->is_transfer_complete()) { + this->_set_state(State::DataRead); + } +} + +void +QUICReceiveStreamState::update_on_eos() +{ + this->_set_state(State::ResetRead); +} + // ---------- QUICSendStreamState ------------- bool @@ -341,6 +360,16 @@ QUICSendStreamState::update(const QUICStreamState &opposite_side) } } +void +QUICSendStreamState::update_on_ack() +{ + if (this->_out_progress->is_transfer_complete()) { + this->_set_state(State::DataRecvd); + } else if (this->_out_progress->is_cancelled()) { + this->_set_state(State::ResetRecvd); + } +} + // ---------QUICBidirectionalStreamState ----------- QUICStreamState::State @@ -408,6 +437,24 @@ QUICBidirectionalStreamState::update_with_receiving_frame(const QUICFrame &frame } } +void +QUICBidirectionalStreamState::update_on_ack() +{ + this->_send_stream_state.update_on_ack(); +} + +void +QUICBidirectionalStreamState::update_on_read() +{ + this->_recv_stream_state.update_on_read(); +} + +void +QUICBidirectionalStreamState::update_on_eos() +{ + this->_recv_stream_state.update_on_eos(); +} + bool QUICBidirectionalStreamState::is_allowed_to_send(const QUICFrame &frame) const { diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h index 1179a480924..dab2d8c8ce4 100644 --- a/iocore/net/quic/QUICStreamState.h +++ b/iocore/net/quic/QUICStreamState.h @@ -43,9 +43,9 @@ class QUICStreamState // ReceiveStreamState Recv, SizeKnown, - /* DataRecvd, */ + /* DataRecvd, (dup)*/ DataRead, - /* ResetRecvd, */ + /* ResetRecvd, (dup)*/ ResetRead, // Bidirectional Open, @@ -102,6 +102,7 @@ class QUICSendStreamState : public QUICUnidirectionalStreamState void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; void update(const QUICStreamState &opposite_side) override; + void update_on_ack(); bool is_allowed_to_send(QUICFrameType type) const override; bool is_allowed_to_send(const QUICFrame &frame) const override; @@ -120,6 +121,8 @@ class QUICReceiveStreamState : public QUICUnidirectionalStreamState void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; void update(const QUICStreamState &opposite_side) override; + void update_on_read(); + void update_on_eos(); bool is_allowed_to_send(QUICFrameType type) const override; bool is_allowed_to_send(const QUICFrame &frame) const override; @@ -140,6 +143,9 @@ class QUICBidirectionalStreamState : public QUICStreamState void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; + void update_on_ack(); + void update_on_read(); + void update_on_eos(); bool is_allowed_to_send(QUICFrameType type) const override; bool is_allowed_to_send(const QUICFrame &frame) const override; diff --git a/iocore/net/quic/QUICTransferProgressProvider.h b/iocore/net/quic/QUICTransferProgressProvider.h index e30cc24f4bf..ce798fec954 100644 --- a/iocore/net/quic/QUICTransferProgressProvider.h +++ b/iocore/net/quic/QUICTransferProgressProvider.h @@ -21,13 +21,54 @@ * limitations under the License. */ +#include "I_VIO.h" + #pragma once class QUICTransferProgressProvider { public: virtual bool is_transfer_goal_set() const = 0; - virtual bool is_transfer_complete() const = 0; virtual uint64_t transfer_progress() const = 0; virtual uint64_t transfer_goal() const = 0; + virtual bool is_cancelled() const = 0; + + virtual bool + is_transfer_complete() const + { + return this->transfer_progress() == this->transfer_goal(); + } +}; + +class QUICTransferProgressProviderVIO : public QUICTransferProgressProvider +{ +public: + QUICTransferProgressProviderVIO(VIO &vio) : _vio(vio) {} + + bool + is_transfer_goal_set() const + { + return this->_vio.nbytes != INT64_MAX; + } + + uint64_t + transfer_progress() const + { + return this->_vio.ndone; + } + + uint64_t + transfer_goal() const + { + return this->_vio.nbytes; + } + + bool + is_cancelled() const + { + return false; + } + +private: + VIO &_vio; }; diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index 7c4d1d69beb..bf70f214f7b 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -36,11 +36,12 @@ TEST_CASE("QUICSendStreamState", "[quic]") auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0, 0); + MockQUICTransferProgressProvider pp; - SECTION("Ready -> Send -> Data Sent") + SECTION("Ready -> Send -> Data Sent -> Data Recvd") { // Case1. Create Stream (Sending) - QUICSendStreamState ss(nullptr, nullptr); + QUICSendStreamState ss(nullptr, &pp); CHECK(ss.get() == QUICStreamState::State::Ready); // Case2. Send STREAM @@ -60,18 +61,111 @@ TEST_CASE("QUICSendStreamState", "[quic]") // Case4. STREAM is not allowed to send CHECK(!ss.is_allowed_to_send(QUICFrameType::STREAM)); + + // Case5. Receive all ACKs + pp.set_transfer_complete(true); + ss.update_on_ack(); + CHECK(ss.get() == QUICStreamState::State::DataRecvd); + } + + SECTION("Ready -> Send") + { + // Case1. Create Stream (Sending) + QUICSendStreamState ss(nullptr, &pp); + CHECK(ss.get() == QUICStreamState::State::Ready); + + // Case2. Send STREAM_BLOCKED + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_BLOCKED)); + ss.update_with_sending_frame(*stream_blocked_frame); + CHECK(ss.get() == QUICStreamState::State::Send); } - SECTION("Ready -> Reset Sent") + SECTION("Ready -> Reset Sent -> Reset Recvd") { + MockQUICTransferProgressProvider pp; + // Case1. Create Stream (Sending) - QUICSendStreamState ss(nullptr, nullptr); + QUICSendStreamState ss(nullptr, &pp); CHECK(ss.get() == QUICStreamState::State::Ready); // Case2. Send RST_STREAM CHECK(ss.is_allowed_to_send(QUICFrameType::RST_STREAM)); ss.update_with_sending_frame(*rst_stream_frame); CHECK(ss.get() == QUICStreamState::State::ResetSent); + + // Case3. Receive ACK for STREAM + ss.update_on_ack(); + CHECK(ss.get() == QUICStreamState::State::ResetSent); + + // Case4. Receive ACK for RST_STREAM + pp.set_cancelled(true); + ss.update_on_ack(); + CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + } + + SECTION("Ready -> Send -> Reset Sent -> Reset Recvd") + { + // Case1. Create Stream (Sending) + QUICSendStreamState ss(nullptr, &pp); + CHECK(ss.get() == QUICStreamState::State::Ready); + + // Case2. Send STREAM + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame); + CHECK(ss.get() == QUICStreamState::State::Send); + + // Case3. Send RST_STREAM + CHECK(ss.is_allowed_to_send(QUICFrameType::RST_STREAM)); + ss.update_with_sending_frame(*rst_stream_frame); + CHECK(ss.get() == QUICStreamState::State::ResetSent); + + // Case4. Receive ACK for STREAM + ss.update_on_ack(); + CHECK(ss.get() == QUICStreamState::State::ResetSent); + + // Case5. Receive ACK for RST_STREAM + pp.set_cancelled(true); + ss.update_on_ack(); + CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + } + + SECTION("Ready -> Send -> Data Sent -> Reset Sent -> Reset Recvd") + { + // Case1. Create Stream (Sending) + QUICSendStreamState ss(nullptr, &pp); + CHECK(ss.get() == QUICStreamState::State::Ready); + + // Case2. Send STREAM + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame); + CHECK(ss.get() == QUICStreamState::State::Send); + + // Case3. Send STREAM_BLOCKED + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_BLOCKED)); + ss.update_with_sending_frame(*stream_blocked_frame); + CHECK(ss.get() == QUICStreamState::State::Send); + + // Case3. Send FIN in a STREAM + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICStreamState::State::DataSent); + + // Case4. STREAM is not allowed to send + CHECK(!ss.is_allowed_to_send(QUICFrameType::STREAM)); + + // Case4. Send RST_STREAM + CHECK(ss.is_allowed_to_send(QUICFrameType::RST_STREAM)); + ss.update_with_sending_frame(*rst_stream_frame); + CHECK(ss.get() == QUICStreamState::State::ResetSent); + + // Case5. Receive ACK for STREAM + ss.update_on_ack(); + CHECK(ss.get() == QUICStreamState::State::ResetSent); + + // Case6. Receive ACK for RST_STREAM + pp.set_cancelled(true); + ss.update_on_ack(); + CHECK(ss.get() == QUICStreamState::State::ResetRecvd); } } @@ -79,17 +173,19 @@ TEST_CASE("QUICSendStreamState", "[quic]") TEST_CASE("QUICReceiveStreamState", "[quic]") { auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); - auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); + auto stream_frame_delayed = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 1); + auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("baz"), 4, 1, 2, true); auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0, 0); - SECTION("Recv -> Size Known -> Data Recvd") + SECTION("Recv -> Size Known -> Data Recvd -> Data Read") { MockQUICTransferProgressProvider in_progress; // Case1. Recv STREAM QUICReceiveStreamState ss(&in_progress, nullptr); CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_progress(1); ss.update_with_receiving_frame(*stream_frame); CHECK(ss.get() == QUICStreamState::State::Recv); @@ -100,11 +196,23 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") // Case3. Recv FIN in a STREAM CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_goal(3); ss.update_with_receiving_frame(*stream_frame_with_fin); CHECK(ss.get() == QUICStreamState::State::SizeKnown); + + // Case4. Recv ALL data + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_progress(3); + ss.update_with_receiving_frame(*stream_frame_delayed); + CHECK(ss.get() == QUICStreamState::State::DataRecvd); + + // Case5. Read data + in_progress.set_transfer_complete(true); + ss.update_on_read(); + CHECK(ss.get() == QUICStreamState::State::DataRead); } - SECTION("Recv -> Reset Recvd") + SECTION("Recv -> Reset Recvd -> Reset Read") { MockQUICTransferProgressProvider in_progress; @@ -118,5 +226,88 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") CHECK(ss.is_allowed_to_receive(QUICFrameType::RST_STREAM)); ss.update_with_receiving_frame(*rst_stream_frame); CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + + // Case3. Handle reset + ss.update_on_eos(); + CHECK(ss.get() == QUICStreamState::State::ResetRead); + } + + SECTION("Recv -> Size Known -> Reset Recvd") + { + MockQUICTransferProgressProvider in_progress; + + // Case1. Recv STREAM + QUICReceiveStreamState ss(&in_progress, nullptr); + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + CHECK(ss.get() == QUICStreamState::State::Recv); + + // Case2. Recv FIN in a STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICStreamState::State::SizeKnown); + + // Case3. Recv RST_STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::RST_STREAM)); + ss.update_with_receiving_frame(*rst_stream_frame); + CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + } + + SECTION("Recv -> Size Known -> Data Recvd -> Reset Recvd") + { + MockQUICTransferProgressProvider in_progress; + + // Case1. Recv STREAM + QUICReceiveStreamState ss(&in_progress, nullptr); + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_progress(1); + ss.update_with_receiving_frame(*stream_frame); + CHECK(ss.get() == QUICStreamState::State::Recv); + + // Case2. Recv FIN in a STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_goal(3); + ss.update_with_receiving_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICStreamState::State::SizeKnown); + + // Case3. Recv ALL data + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_progress(3); + ss.update_with_receiving_frame(*stream_frame_delayed); + CHECK(ss.get() == QUICStreamState::State::DataRecvd); + + // Case4. Recv RST_STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::RST_STREAM)); + ss.update_with_receiving_frame(*rst_stream_frame); + CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + } + + SECTION("Recv -> Size Known -> Reset Recvd -> Data Recvd") + { + MockQUICTransferProgressProvider in_progress; + + // Case1. Recv STREAM + QUICReceiveStreamState ss(&in_progress, nullptr); + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_progress(1); + ss.update_with_receiving_frame(*stream_frame); + CHECK(ss.get() == QUICStreamState::State::Recv); + + // Case2. Recv FIN in a STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_goal(3); + ss.update_with_receiving_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICStreamState::State::SizeKnown); + + // Case3. Recv RST_STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::RST_STREAM)); + ss.update_with_receiving_frame(*rst_stream_frame); + CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + + // Case4. Recv ALL data + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_progress(3); + ss.update_with_receiving_frame(*stream_frame_delayed); + CHECK(ss.get() == QUICStreamState::State::DataRecvd); } } From 9dc8b9346c61e0a4baa6fae7d11eae65654a12cb Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 29 Nov 2018 10:16:19 +0900 Subject: [PATCH 0940/1313] Regenerate RST_STREAM with the generateor instead of QUICPacketRetransmitter --- iocore/net/quic/QUICFrame.cc | 4 +- iocore/net/quic/QUICFrame.h | 2 +- iocore/net/quic/QUICPacketRetransmitter.cc | 1 + iocore/net/quic/QUICStream.cc | 5 +- iocore/net/quic/test/test_QUICFrame.cc | 3 +- iocore/net/quic/test/test_QUICStream.cc | 76 ++++++++++++++++++++++ 6 files changed, 84 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index b6ca619a62d..e4f5f2e92b7 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2962,9 +2962,9 @@ QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCo } std::unique_ptr -QUICFrameFactory::create_rst_stream_frame(QUICStreamErrorUPtr error, QUICFrameId id, QUICFrameGenerator *owner) +QUICFrameFactory::create_rst_stream_frame(QUICStreamError &error, QUICFrameId id, QUICFrameGenerator *owner) { - return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->code, error->stream->final_offset(), id, owner); + return QUICFrameFactory::create_rst_stream_frame(error.stream->id(), error.code, error.stream->final_offset(), id, owner); } std::unique_ptr diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index cc73c91db7d..0c52e863dbd 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -1096,7 +1096,7 @@ class QUICFrameFactory QUICOffset final_offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - static std::unique_ptr create_rst_stream_frame(QUICStreamErrorUPtr error, + static std::unique_ptr create_rst_stream_frame(QUICStreamError &error, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 2832fdc1a59..1a527032e21 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -45,6 +45,7 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) case QUICFrameType::ACK: case QUICFrameType::PATH_CHALLENGE: case QUICFrameType::PATH_RESPONSE: + case QUICFrameType::RST_STREAM: break; default: frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 4d798fdcbb7..e80a31b1486 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -412,7 +412,8 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit // RST_STREAM if (this->_reset_reason && !this->_is_reset_sent) { - frame = QUICFrameFactory::create_rst_stream_frame(std::move(this->_reset_reason)); + frame = QUICFrameFactory::create_rst_stream_frame(*this->_reset_reason); + this->_records_frame(frame->id(), {frame->type(), level}); this->_state.update_with_sending_frame(*frame); this->_is_reset_sent = true; return frame; @@ -780,7 +781,7 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ QUICConnectionErrorUPtr error = nullptr; if (this->_reset_reason) { - return QUICFrameFactory::create_rst_stream_frame(std::move(this->_reset_reason)); + return QUICFrameFactory::create_rst_stream_frame(*this->_reset_reason); } QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 8c5a37ee25a..003aa241f4f 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1360,8 +1360,7 @@ TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") QUICStream stream(&mock_rtt, &mock_connection, 0x1234, 0, 0); std::unique_ptr error = std::unique_ptr(new QUICStreamError(&stream, static_cast(0x01))); - std::unique_ptr rst_stream_frame1 = - QUICFrameFactory::create_rst_stream_frame(std::move(error)); + std::unique_ptr rst_stream_frame1 = QUICFrameFactory::create_rst_stream_frame(*error); CHECK(rst_stream_frame1->error_code() == 0x01); CHECK(rst_stream_frame1->stream_id() == 0x1234); CHECK(rst_stream_frame1->final_offset() == 0); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index e1268bd2557..b838e8911c7 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -275,4 +275,80 @@ TEST_CASE("QUICStream", "[quic]") CHECK(frame->type() == QUICFrameType::STREAM); CHECK(stream->will_generate_frame(level) == false); } + + /* + * This test does not pass now + * + SECTION("Retransmit STREAM frame") + { + MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); + IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); + + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); + SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); + + MockContinuation mock_cont(stream->mutex); + stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); + + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + const char data1[] = "this is a test data"; + const char data2[] = "THIS IS ANOTHER TEST DATA"; + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + + QUICFrameUPtr frame1 = QUICFrameFactory::create_null_frame(); + QUICFrameUPtr frame2 = QUICFrameFactory::create_null_frame(); + + // Write data1 + write_buffer->write(data1, 1024); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + // Generate STREAM frame + frame1 = stream->generate_frame(level, 4096, 4096); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->generate_frame(level, 4096, 4096) == nullptr); + // Write data2 + write_buffer->write(data1, 1024); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + // Lost the frame + stream->on_frame_lost(frame->id()); + // Regenerate a frame + frame2 = stream->generate_frame(level, 4096, 4096); + // Lost data should be resent first + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(frame1->offset() == frame2->offset()); + CHECK(frame1->data_length() == frame2->data_length()); + CHECK(memcmp(frame1->data(), frame2->data(), frame1->data_length()); + } + */ + + SECTION("Retransmit RST_STREAM frame") + { + MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); + IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); + + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); + SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); + + MockContinuation mock_cont(stream->mutex); + stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); + + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + + stream->reset(QUICStreamErrorUPtr(new QUICStreamError(stream.get(), QUIC_APP_ERROR_CODE_STOPPING))); + frame = stream->generate_frame(level, 4096, 4096); + REQUIRE(frame); + CHECK(frame->type() == QUICFrameType::RST_STREAM); + // Don't send it again untill it is considers as lost + CHECK(stream->generate_frame(level, 4096, 4096) == nullptr); + // Loss the frame + stream->on_frame_lost(frame->id()); + // After the loss the frame should be regenerated + frame = stream->generate_frame(level, 4096, 4096); + REQUIRE(frame); + CHECK(frame->type() == QUICFrameType::RST_STREAM); + } } From 1a2ceb4b3aaa9f0d2e3cc4ba843c9955d4a2da94 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 29 Nov 2018 10:55:14 +0900 Subject: [PATCH 0941/1313] Fixup for the previous commit It worked only for the unit test because FrameId was not issued and frame generator was not set. --- iocore/net/quic/QUICStream.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index e80a31b1486..3f2ecd79593 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -412,7 +412,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit // RST_STREAM if (this->_reset_reason && !this->_is_reset_sent) { - frame = QUICFrameFactory::create_rst_stream_frame(*this->_reset_reason); + frame = QUICFrameFactory::create_rst_stream_frame(*this->_reset_reason, this->_issue_frame_id(), this); this->_records_frame(frame->id(), {frame->type(), level}); this->_state.update_with_sending_frame(*frame); this->_is_reset_sent = true; From 7a953a5767fc326ae8e5736eb7ec7c7f5b620758 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 30 Nov 2018 12:10:23 +0900 Subject: [PATCH 0942/1313] Retransmit freames genererated by QUICFlowController by itself BLOCKED, STREAM_BLOCKED, MAX_DATA, MAX_STREAM_DATA --- iocore/net/quic/QUICFlowController.cc | 42 ++++++++++++-- iocore/net/quic/QUICFlowController.h | 2 + iocore/net/quic/QUICPacketRetransmitter.cc | 4 ++ .../net/quic/test/test_QUICFlowController.cc | 55 +++++++++++++++++++ 4 files changed, 99 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index b7d738e7cfe..b5ec3c875e6 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -147,6 +147,15 @@ QUICRemoteFlowController::update(QUICOffset offset) return ret; } +void +QUICRemoteFlowController::_on_frame_lost(QUICFrameInformation info) +{ + ink_assert(info.type == QUICFrameType::BLOCKED || info.type == QUICFrameType::STREAM_ID_BLOCKED); + if (this->_offset == reinterpret_cast(info.data)) { + this->_frame = this->_create_frame(); + } +} + // // QUICLocalFlowController // @@ -181,6 +190,15 @@ QUICLocalFlowController::set_limit(QUICOffset limit) QUICFlowController::set_limit(limit); } +void +QUICLocalFlowController::_on_frame_lost(QUICFrameInformation info) +{ + ink_assert(info.type == QUICFrameType::MAX_DATA || info.type == QUICFrameType::MAX_STREAM_DATA); + if (this->_limit == reinterpret_cast(info.data)) { + this->_frame = this->_create_frame(); + } +} + bool QUICLocalFlowController::_need_to_forward_limit() { @@ -198,23 +216,39 @@ QUICLocalFlowController::_need_to_forward_limit() QUICFrameUPtr QUICRemoteConnectionFlowController::_create_frame() { - return QUICFrameFactory::create_blocked_frame(this->_offset); + auto frame = QUICFrameFactory::create_blocked_frame(this->_offset, this->_issue_frame_id(), this); + QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; + *(reinterpret_cast(info.data)) = this->_offset; + this->_records_frame(frame->id(), info); + return frame; } QUICFrameUPtr QUICLocalConnectionFlowController::_create_frame() { - return QUICFrameFactory::create_max_data_frame(this->_limit); + auto frame = QUICFrameFactory::create_max_data_frame(this->_limit, this->_issue_frame_id(), this); + QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; + *(reinterpret_cast(info.data)) = this->_limit; + this->_records_frame(frame->id(), info); + return frame; } QUICFrameUPtr QUICRemoteStreamFlowController::_create_frame() { - return QUICFrameFactory::create_stream_blocked_frame(this->_stream_id, this->_offset); + auto frame = QUICFrameFactory::create_stream_blocked_frame(this->_stream_id, this->_offset, this->_issue_frame_id(), this); + QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; + *(reinterpret_cast(info.data)) = this->_offset; + this->_records_frame(frame->id(), info); + return frame; } QUICFrameUPtr QUICLocalStreamFlowController::_create_frame() { - return QUICFrameFactory::create_max_stream_data_frame(this->_stream_id, this->_limit); + auto frame = QUICFrameFactory::create_max_stream_data_frame(this->_stream_id, this->_limit, this->_issue_frame_id(), this); + QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; + *(reinterpret_cast(info.data)) = this->_limit; + this->_records_frame(frame->id(), info); + return frame; } diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index 4461a73b003..f26c4af5a40 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -80,6 +80,7 @@ class QUICRemoteFlowController : public QUICFlowController void forward_limit(QUICOffset new_limit) override; private: + void _on_frame_lost(QUICFrameInformation info) override; bool _blocked = false; }; @@ -100,6 +101,7 @@ class QUICLocalFlowController : public QUICFlowController void set_limit(QUICOffset limit) override; private: + void _on_frame_lost(QUICFrameInformation info) override; bool _need_to_forward_limit(); QUICRateAnalyzer _analyzer; diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 1a527032e21..1673752196b 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -46,6 +46,10 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) case QUICFrameType::PATH_CHALLENGE: case QUICFrameType::PATH_RESPONSE: case QUICFrameType::RST_STREAM: + case QUICFrameType::BLOCKED: + case QUICFrameType::STREAM_BLOCKED: + case QUICFrameType::MAX_DATA: + case QUICFrameType::MAX_STREAM_DATA: break; default: frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index 951a0e57712..c13b8c2246e 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -308,3 +308,58 @@ TEST_CASE("QUICFlowController_Remote_Stream", "[quic]") CHECK(fc.current_limit() == 2048); CHECK(ret == 0); } + +TEST_CASE("Frame retransmission", "[quic]") +{ + QUICEncryptionLevel level = QUICEncryptionLevel::NONE; + + SECTION("BLOCKED frame") + { + int ret = 0; + QUICRemoteConnectionFlowController fc(1024); + + // Check initial state + auto frame = fc.generate_frame(level, 1024, 1024); + CHECK(!frame); + + ret = fc.update(1024); + CHECK(ret == 0); + frame = fc.generate_frame(level, 1024, 1024); + CHECK(frame); + CHECK(static_cast(frame.get())->offset() == 1024); + + // Don't retransmit unless the frame is lost + frame = fc.generate_frame(level, 1024, 1024); + CHECK(frame); + + // Retransmit + fc.on_frame_lost(frame->id()); + frame = fc.generate_frame(level, 1024, 1024); + CHECK(frame); + CHECK(static_cast(frame.get())->offset() == 1024); + + // Don't send if it was not blocked + fc.on_frame_lost(frame->id()); + fc.forward_limit(1024); + ret = fc.update(512); + frame = fc.generate_frame(level, 1024, 1024); + CHECK(!frame); + + // This should not be retransmition + ret = fc.update(512); + frame = fc.generate_frame(level, 1024, 1024); + CHECK(static_cast(frame.get())->offset() == 2048); + } + + SECTION("STREAM_BLOCKED frame") + { + } + + SECTION("MAX_DATA frame") + { + } + + SECTION("MAX_STREAM_DATA frame") + { + } +} From 5f59304a750104bfd8778a6d0c227556a0a84563 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 30 Nov 2018 14:00:59 +0900 Subject: [PATCH 0943/1313] Remove ../../ from inlcude lines --- iocore/net/quic/QUICApplication.h | 4 ++-- iocore/net/quic/QUICFlowController.h | 2 +- iocore/net/quic/QUICLossDetector.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 649101ddf60..4930eceb144 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -23,8 +23,8 @@ #pragma once -#include "../../eventsystem/I_EventSystem.h" -#include "../../eventsystem/I_IOBuffer.h" +#include "I_EventSystem.h" +#include "I_IOBuffer.h" #include "QUICTypes.h" #include "QUICConnection.h" #include "QUICStream.h" diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index f26c4af5a40..c3eb547a8a3 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -23,7 +23,7 @@ #pragma once -#include "../../eventsystem/I_EventSystem.h" +#include "I_EventSystem.h" #include "QUICTypes.h" #include "QUICFrame.h" #include "QUICFrameGenerator.h" diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 5fa0550a70b..c04c12f7946 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -27,8 +27,8 @@ #include #include -#include "../../eventsystem/I_EventSystem.h" -#include "../../eventsystem/I_Action.h" +#include "I_EventSystem.h" +#include "I_Action.h" #include "tscore/ink_hrtime.h" #include "I_VConnection.h" #include "QUICTypes.h" From 1e94f755fd4ea617435cb406c8ac67e9b7811f5d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 30 Nov 2018 14:55:29 +0900 Subject: [PATCH 0944/1313] Fix tests for QUICFlowController I accidentally pushed WIP branch. This fixes the unit tests but test cases MAX_DATA and MAX_STREAM_DATA are not added. --- iocore/net/quic/QUICFlowController.cc | 23 ++++--- .../net/quic/test/test_QUICFlowController.cc | 68 ++++++++++++++----- 2 files changed, 63 insertions(+), 28 deletions(-) diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index b5ec3c875e6..9fc1ddf91f1 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -130,6 +130,7 @@ QUICRemoteFlowController::forward_limit(QUICOffset new_limit) { QUICFlowController::forward_limit(new_limit); this->_blocked = false; + this->_frame = nullptr; } int @@ -139,7 +140,7 @@ QUICRemoteFlowController::update(QUICOffset offset) // Create BLOCKED(_STREAM) frame // The frame will be sent if stream has something to send. - if (!this->_blocked && offset >= this->_limit) { + if (offset >= this->_limit) { this->_frame = this->_create_frame(); this->_blocked = true; } @@ -151,7 +152,7 @@ void QUICRemoteFlowController::_on_frame_lost(QUICFrameInformation info) { ink_assert(info.type == QUICFrameType::BLOCKED || info.type == QUICFrameType::STREAM_ID_BLOCKED); - if (this->_offset == reinterpret_cast(info.data)) { + if (this->_offset == *reinterpret_cast(info.data)) { this->_frame = this->_create_frame(); } } @@ -194,7 +195,7 @@ void QUICLocalFlowController::_on_frame_lost(QUICFrameInformation info) { ink_assert(info.type == QUICFrameType::MAX_DATA || info.type == QUICFrameType::MAX_STREAM_DATA); - if (this->_limit == reinterpret_cast(info.data)) { + if (this->_limit == *reinterpret_cast(info.data)) { this->_frame = this->_create_frame(); } } @@ -216,9 +217,9 @@ QUICLocalFlowController::_need_to_forward_limit() QUICFrameUPtr QUICRemoteConnectionFlowController::_create_frame() { - auto frame = QUICFrameFactory::create_blocked_frame(this->_offset, this->_issue_frame_id(), this); + auto frame = QUICFrameFactory::create_blocked_frame(this->_offset, this->_issue_frame_id(), this); QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; - *(reinterpret_cast(info.data)) = this->_offset; + *(reinterpret_cast(info.data)) = this->_offset; this->_records_frame(frame->id(), info); return frame; } @@ -226,9 +227,9 @@ QUICRemoteConnectionFlowController::_create_frame() QUICFrameUPtr QUICLocalConnectionFlowController::_create_frame() { - auto frame = QUICFrameFactory::create_max_data_frame(this->_limit, this->_issue_frame_id(), this); + auto frame = QUICFrameFactory::create_max_data_frame(this->_limit, this->_issue_frame_id(), this); QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; - *(reinterpret_cast(info.data)) = this->_limit; + *(reinterpret_cast(info.data)) = this->_limit; this->_records_frame(frame->id(), info); return frame; } @@ -237,8 +238,8 @@ QUICFrameUPtr QUICRemoteStreamFlowController::_create_frame() { auto frame = QUICFrameFactory::create_stream_blocked_frame(this->_stream_id, this->_offset, this->_issue_frame_id(), this); - QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; - *(reinterpret_cast(info.data)) = this->_offset; + QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; + *(reinterpret_cast(info.data)) = this->_offset; this->_records_frame(frame->id(), info); return frame; } @@ -247,8 +248,8 @@ QUICFrameUPtr QUICLocalStreamFlowController::_create_frame() { auto frame = QUICFrameFactory::create_max_stream_data_frame(this->_stream_id, this->_limit, this->_issue_frame_id(), this); - QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; - *(reinterpret_cast(info.data)) = this->_limit; + QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; + *(reinterpret_cast(info.data)) = this->_limit; this->_records_frame(frame->id(), info); return frame; } diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index c13b8c2246e..50a78d714d0 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -311,7 +311,7 @@ TEST_CASE("QUICFlowController_Remote_Stream", "[quic]") TEST_CASE("Frame retransmission", "[quic]") { - QUICEncryptionLevel level = QUICEncryptionLevel::NONE; + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; SECTION("BLOCKED frame") { @@ -325,41 +325,75 @@ TEST_CASE("Frame retransmission", "[quic]") ret = fc.update(1024); CHECK(ret == 0); frame = fc.generate_frame(level, 1024, 1024); - CHECK(frame); - CHECK(static_cast(frame.get())->offset() == 1024); + REQUIRE(frame); + CHECK(static_cast(frame.get())->offset() == 1024); + QUICFrameId id = frame->id(); // Don't retransmit unless the frame is lost frame = fc.generate_frame(level, 1024, 1024); - CHECK(frame); + REQUIRE(!frame); // Retransmit - fc.on_frame_lost(frame->id()); + fc.on_frame_lost(id); frame = fc.generate_frame(level, 1024, 1024); - CHECK(frame); - CHECK(static_cast(frame.get())->offset() == 1024); + REQUIRE(frame); + CHECK(static_cast(frame.get())->offset() == 1024); // Don't send if it was not blocked fc.on_frame_lost(frame->id()); - fc.forward_limit(1024); - ret = fc.update(512); + fc.forward_limit(2048); + ret = fc.update(1536); frame = fc.generate_frame(level, 1024, 1024); CHECK(!frame); // This should not be retransmition - ret = fc.update(512); + ret = fc.update(2048); frame = fc.generate_frame(level, 1024, 1024); - CHECK(static_cast(frame.get())->offset() == 2048); + REQUIRE(frame); + CHECK(static_cast(frame.get())->offset() == 2048); } SECTION("STREAM_BLOCKED frame") { - } + int ret = 0; + QUICRemoteStreamFlowController fc(1024, 0); - SECTION("MAX_DATA frame") - { - } + // Check initial state + auto frame = fc.generate_frame(level, 1024, 1024); + CHECK(!frame); - SECTION("MAX_STREAM_DATA frame") - { + ret = fc.update(1024); + CHECK(ret == 0); + frame = fc.generate_frame(level, 1024, 1024); + REQUIRE(frame); + CHECK(static_cast(frame.get())->offset() == 1024); + QUICFrameId id = frame->id(); + + // Don't retransmit unless the frame is lost + frame = fc.generate_frame(level, 1024, 1024); + REQUIRE(!frame); + + // Retransmit + fc.on_frame_lost(id); + frame = fc.generate_frame(level, 1024, 1024); + REQUIRE(frame); + CHECK(static_cast(frame.get())->offset() == 1024); + + // Don't send if it was not blocked + fc.on_frame_lost(frame->id()); + fc.forward_limit(2048); + ret = fc.update(1536); + frame = fc.generate_frame(level, 1024, 1024); + CHECK(!frame); + + // This should not be retransmition + ret = fc.update(2048); + frame = fc.generate_frame(level, 1024, 1024); + REQUIRE(frame); + CHECK(static_cast(frame.get())->offset() == 2048); } + + SECTION("MAX_DATA frame") {} + + SECTION("MAX_STREAM_DATA frame") {} } From 1105ae453757cab50eb7930c18e42fad252d39ee Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 30 Nov 2018 15:40:46 +0900 Subject: [PATCH 0945/1313] Update tests for QUICFlowController --- iocore/net/quic/QUICFlowController.cc | 2 +- .../net/quic/test/test_QUICFlowController.cc | 78 +++++++++++++++++-- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 9fc1ddf91f1..3ad4546fe93 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -151,7 +151,7 @@ QUICRemoteFlowController::update(QUICOffset offset) void QUICRemoteFlowController::_on_frame_lost(QUICFrameInformation info) { - ink_assert(info.type == QUICFrameType::BLOCKED || info.type == QUICFrameType::STREAM_ID_BLOCKED); + ink_assert(info.type == QUICFrameType::BLOCKED || info.type == QUICFrameType::STREAM_BLOCKED); if (this->_offset == *reinterpret_cast(info.data)) { this->_frame = this->_create_frame(); } diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index 50a78d714d0..c83ca9c783c 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -366,7 +366,7 @@ TEST_CASE("Frame retransmission", "[quic]") CHECK(ret == 0); frame = fc.generate_frame(level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 1024); + CHECK(static_cast(frame.get())->offset() == 1024); QUICFrameId id = frame->id(); // Don't retransmit unless the frame is lost @@ -377,7 +377,7 @@ TEST_CASE("Frame retransmission", "[quic]") fc.on_frame_lost(id); frame = fc.generate_frame(level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 1024); + CHECK(static_cast(frame.get())->offset() == 1024); // Don't send if it was not blocked fc.on_frame_lost(frame->id()); @@ -390,10 +390,78 @@ TEST_CASE("Frame retransmission", "[quic]") ret = fc.update(2048); frame = fc.generate_frame(level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 2048); + CHECK(static_cast(frame.get())->offset() == 2048); } - SECTION("MAX_DATA frame") {} + SECTION("MAX_DATA frame") + { + int ret = 0; + MockRTTProvider rp(DEFAULT_RTT); + QUICLocalConnectionFlowController fc(&rp, 1024); + + // Check initial state + auto frame = fc.generate_frame(level, 1024, 1024); + CHECK(!frame); + + fc.update(1024); + fc.forward_limit(1024); + frame = fc.generate_frame(level, 1024, 1024); + REQUIRE(frame); + CHECK(static_cast(frame.get())->maximum_data() == 1024); + QUICFrameId id = frame->id(); - SECTION("MAX_STREAM_DATA frame") {} + // Don't retransmit unless the frame is lost + frame = fc.generate_frame(level, 1024, 1024); + REQUIRE(!frame); + + // Retransmit + fc.on_frame_lost(id); + frame = fc.generate_frame(level, 1024, 1024); + REQUIRE(frame); + CHECK(static_cast(frame.get())->maximum_data() == 1024); + + // Send new one if it was updated + fc.on_frame_lost(id); + fc.forward_limit(2048); + fc.update(2048); + frame = fc.generate_frame(level, 1024, 1024); + REQUIRE(frame); + CHECK(static_cast(frame.get())->maximum_data() == 2048); + } + + SECTION("MAX_STREAM_DATA frame") + { + int ret = 0; + MockRTTProvider rp(DEFAULT_RTT); + QUICLocalStreamFlowController fc(&rp, 1024, 0); + + // Check initial state + auto frame = fc.generate_frame(level, 1024, 1024); + CHECK(!frame); + + fc.update(1024); + fc.forward_limit(1024); + frame = fc.generate_frame(level, 1024, 1024); + REQUIRE(frame); + CHECK(static_cast(frame.get())->maximum_stream_data() == 1024); + QUICFrameId id = frame->id(); + + // Don't retransmit unless the frame is lost + frame = fc.generate_frame(level, 1024, 1024); + REQUIRE(!frame); + + // Retransmit + fc.on_frame_lost(id); + frame = fc.generate_frame(level, 1024, 1024); + REQUIRE(frame); + CHECK(static_cast(frame.get())->maximum_stream_data() == 1024); + + // Send new one if it was updated + fc.on_frame_lost(id); + fc.forward_limit(2048); + fc.update(2048); + frame = fc.generate_frame(level, 1024, 1024); + REQUIRE(frame); + CHECK(static_cast(frame.get())->maximum_stream_data() == 2048); + } } From 70ef6ad5043693150ea205c282ded0491659101e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 30 Nov 2018 16:21:12 +0900 Subject: [PATCH 0946/1313] Add unit tests for QUICPreferredAddress --- .../test/test_QUICAltConnectionManager.cc | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 iocore/net/quic/test/test_QUICAltConnectionManager.cc diff --git a/iocore/net/quic/test/test_QUICAltConnectionManager.cc b/iocore/net/quic/test/test_QUICAltConnectionManager.cc new file mode 100644 index 00000000000..5c1bdca43fc --- /dev/null +++ b/iocore/net/quic/test/test_QUICAltConnectionManager.cc @@ -0,0 +1,80 @@ +/** @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 "catch.hpp" + +#include "quic/QUICAltConnectionManager.h" +#include "quic/QUICIntUtil.h" +#include + +TEST_CASE("QUICPreferredAddress", "[quic]") +{ + const uint8_t buf[] = { + 0x04, // ipVersion + 0x04, // ipAddress length + 0x01, 0x02, 0x03, 0x04, // ipAddress + 0x11, 0x22, // port + 0x01, // connectionId length + 0x55, // connectionId + 0x10, 0x11, 0x12, 0x13, // statelessResetToken + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + }; + uint8_t cid_buf[] = {0x55}; + QUICConnectionId cid55(cid_buf, sizeof(cid_buf)); + + SECTION("load") + { + auto pref_addr = new QUICPreferredAddress(buf, sizeof(buf)); + CHECK(pref_addr->is_available()); + CHECK(pref_addr->endpoint().isIp4()); + CHECK(pref_addr->endpoint().host_order_port() == 0x1122); + CHECK(pref_addr->endpoint().sin.sin_addr.s_addr == 0x04030201); + CHECK(pref_addr->cid() == cid55); + CHECK(memcmp(pref_addr->token().buf(), buf + 10, 16) == 0); + } + + SECTION("store") + { + IpEndpoint ep; + ats_ip4_set(&ep, 0x04030201, 0x2211); + + auto pref_addr = new QUICPreferredAddress(ep, cid55, {buf + 10}); + CHECK(pref_addr->is_available()); + CHECK(pref_addr->endpoint().isIp4()); + CHECK(pref_addr->endpoint().host_order_port() == 0x1122); + CHECK(pref_addr->endpoint().sin.sin_addr.s_addr == 0x04030201); + CHECK(pref_addr->cid() == cid55); + + uint8_t actual[QUICPreferredAddress::MAX_LEN]; + uint16_t len; + pref_addr->store(actual, len); + CHECK(sizeof(buf) == len); + CHECK(memcmp(buf, actual, sizeof(buf)) == 0); + } + + SECTION("unavailable") + { + auto pref_addr = new QUICPreferredAddress(nullptr, 0); + CHECK(!pref_addr->is_available()); + } +} From 26820f2789eae743f041bafd757b607e4ee9780e Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 29 Nov 2018 09:47:54 +0800 Subject: [PATCH 0947/1313] QUIC: Delay ack support --- iocore/net/P_QUICNetVConnection.h | 4 +- iocore/net/QUICNetVConnection.cc | 12 +- iocore/net/quic/QUICAckFrameCreator.cc | 344 +++++++++++++++++-------- iocore/net/quic/QUICAckFrameCreator.h | 82 ++++-- iocore/net/quic/QUICFrameDispatcher.cc | 8 +- 5 files changed, 309 insertions(+), 141 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 76e5fe965ac..70c41af2943 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -151,7 +151,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub using super = UnixNetVConnection; ///< Parent type. public: - QUICNetVConnection() {} + QUICNetVConnection() : _ack_frame_creator(this) {} void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *, QUICPacketHandler *); void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, QUICConnectionId first_cid, UDPConnection *, QUICPacketHandler *, QUICConnectionTable *ctable); @@ -228,6 +228,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub LINK(QUICNetVConnection, closed_link); SLINK(QUICNetVConnection, closed_alink); + void common_send_packet(); + private: QUICPacketType _last_received_packet_type = QUICPacketType::UNINITIALIZED; std::random_device _rnd; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2a35eaed0c7..5874a222e42 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1431,7 +1431,7 @@ QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_fram QUICPacketNumber packet_num = packet.packet_number(); QUICEncryptionLevel level = QUICTypeUtil::encryption_level(packet.type()); - bool should_send_ack; + bool ack_only; bool is_flow_controlled; QUICConnectionErrorUPtr error = nullptr; @@ -1439,7 +1439,7 @@ QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_fram *has_non_probing_frame = false; } - error = this->_frame_dispatcher->receive_frames(level, payload, size, should_send_ack, is_flow_controlled, has_non_probing_frame); + error = this->_frame_dispatcher->receive_frames(level, payload, size, ack_only, is_flow_controlled, has_non_probing_frame); if (error != nullptr) { return error; } @@ -1458,7 +1458,7 @@ QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_fram this->_local_flow_controller->current_limit()); } - this->_ack_frame_creator.update(level, packet_num, should_send_ack); + this->_ack_frame_creator.update(level, packet_num, size, ack_only); return error; } @@ -2056,3 +2056,9 @@ QUICNetVConnection::_handle_path_validation_timeout(Event *data) this->_switch_to_close_state(); } } + +void +QUICNetVConnection::common_send_packet() +{ + this->_schedule_packet_write_ready(); +} diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 73953ee14ba..5072ef09fd8 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -24,6 +24,14 @@ #include "I_EventSystem.h" #include "QUICAckFrameCreator.h" #include +#include + +QUICAckFrameCreator::QUICAckFrameCreator(QUICNetVConnection *qc) +{ + for (auto i = 0; i < 3; i++) { + this->_packet_numbers[i] = std::make_unique(qc, this); + } +} void QUICAckFrameCreator::set_ack_delay_exponent(uint8_t ack_delay_exponent) @@ -34,28 +42,15 @@ QUICAckFrameCreator::set_ack_delay_exponent(uint8_t ack_delay_exponent) } int -QUICAckFrameCreator::update(QUICEncryptionLevel level, QUICPacketNumber packet_number, bool should_send) +QUICAckFrameCreator::update(QUICEncryptionLevel level, QUICPacketNumber packet_number, size_t size, bool ack_only) { if (!this->_is_level_matched(level)) { return 0; } - int index = QUICTypeUtil::pn_space_index(level); - QUICAckPacketNumbers *packet_numbers = &this->_packet_numbers[index]; - packet_numbers->push_back(packet_number); - - if (packet_numbers->size() == MAXIMUM_PACKET_COUNT) { - return -1; - } - - if (!this->_can_send[index]) { - this->_can_send[index] = true; - } - - if (should_send) { - this->_should_send[index] = true; - } - + int index = QUICTypeUtil::pn_space_index(level); + auto &packet_numbers = this->_packet_numbers[index]; + packet_numbers->push_back(level, packet_number, size, ack_only); return 0; } @@ -68,17 +63,9 @@ QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connecti return ack_frame; } - int index = QUICTypeUtil::pn_space_index(level); - if (this->_can_send[index]) { - ack_frame = this->_create_ack_frame(level); - if (ack_frame && ack_frame->size() > maximum_frame_size) { - // Cancel generating frame - ack_frame = QUICFrameFactory::create_null_ack_frame(); - } else { - this->_can_send[index] = true; - this->_should_send[index] = false; - } - } + int index = QUICTypeUtil::pn_space_index(level); + auto &packet_number = this->_packet_numbers[index]; + ack_frame = packet_number->create_ack_frame(level, maximum_frame_size); if (ack_frame != nullptr) { QUICFrameInformation info; @@ -88,28 +75,204 @@ QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connecti info.level = level; info.type = ack_frame->type(); this->_records_frame(ack_frame->id(), info); + + this->_latest_sent_time = Thread::get_hrtime(); } return ack_frame; } -std::unique_ptr -QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) +bool +QUICAckFrameCreator::will_generate_frame(QUICEncryptionLevel level) { + // No ACK frame on ZERO_RTT level + if (!this->_is_level_matched(level) || level == QUICEncryptionLevel::ZERO_RTT) { + return false; + } + int index = QUICTypeUtil::pn_space_index(level); - this->_packet_numbers[index].sort(); - auto list = this->_packet_numbers[index].list(); + return this->_packet_numbers[index]->should_send(); +} + +void +QUICAckFrameCreator::_on_frame_acked(QUICFrameInformation info) +{ + ink_assert(info.type == QUICFrameType::ACK); + AckFrameInfomation *ack_info = reinterpret_cast(info.data); + int index = QUICTypeUtil::pn_space_index(info.level); + this->_packet_numbers[index]->forget(ack_info->largest_acknowledged); +} +QUICFrameId +QUICAckFrameCreator::issue_frame_id() +{ + return this->_issue_frame_id(); +} + +uint8_t +QUICAckFrameCreator::ack_delay_exponent() const +{ + return this->_ack_delay_exponent; +} + +// +// QUICAckFrameCreator::QUICAckPacketNumbers +// +void +QUICAckFrameCreator::QUICAckPacketNumbers::set_creator(QUICAckFrameCreator *creator) +{ + this->_ack_creator = creator; +} + +void +QUICAckFrameCreator::QUICAckPacketNumbers::forget(QUICPacketNumber largest_acknowledged) +{ + this->_available = false; + this->sort(); + std::list remove_list; + for (auto it = this->_packet_numbers.begin(); it != this->_packet_numbers.end(); it++) { + this->_available |= !(*it).ack_only; + if ((*it).packet_number == largest_acknowledged) { + remove_list.splice(remove_list.begin(), this->_packet_numbers, it, this->_packet_numbers.end()); + break; + } + } + + if (this->_packet_numbers.size() == 0 || !this->_available) { + this->_should_send = false; + this->_cancel_timer(); + } +} + +void +QUICAckFrameCreator::QUICAckPacketNumbers::push_back(QUICEncryptionLevel level, QUICPacketNumber packet_number, size_t size, + bool ack_only) +{ + if (packet_number == 0 || packet_number > this->_largest_ack_number) { + this->_largest_ack_received_time = Thread::get_hrtime(); + this->_largest_ack_number = packet_number; + } + + // delay too much time + if (this->_largest_ack_received_time + QUIC_ACK_CREATOR_MAX_DELAY <= Thread::get_hrtime()) { + this->_should_send = true; + } + + // unorder packet should send ack immediately to accellerate the recovery + if (this->_expect_next != packet_number) { + this->_expect_next = std::max(this->_expect_next, packet_number + 1); + this->_should_send = true; + } + + // every 2 full-packet should send a ack frame like tcp + this->_size_unsend += size; + if (this->_size_unsend > 2 * 1480) { + this->_size_unsend = 0; + this->_should_send = true; + } + + // can not delay handshake packet + if (level == QUICEncryptionLevel::INITIAL || level == QUICEncryptionLevel::HANDSHAKE) { + this->_should_send = true; + } + + if (!ack_only) { + this->_available = true; + } else { + this->_should_send = this->_available ? this->_should_send : false; + } + + if (!this->_should_send && this->_available) { + this->_start_timer(); + } + + this->_packet_numbers.push_back({ack_only, packet_number}); +} + +size_t +QUICAckFrameCreator::QUICAckPacketNumbers::size() +{ + return this->_packet_numbers.size(); +} + +void +QUICAckFrameCreator::QUICAckPacketNumbers::clear() +{ + this->_packet_numbers.clear(); + this->_largest_ack_number = 0; + this->_largest_ack_received_time = 0; +} + +QUICPacketNumber +QUICAckFrameCreator::QUICAckPacketNumbers::largest_ack_number() +{ + return this->_largest_ack_number; +} + +ink_hrtime +QUICAckFrameCreator::QUICAckPacketNumbers::largest_ack_received_time() +{ + return this->_largest_ack_received_time; +} + +void +QUICAckFrameCreator::QUICAckPacketNumbers::sort() +{ + // TODO Find more smart way + this->_packet_numbers.sort([](const RecvdPacket &a, const RecvdPacket &b) -> bool { return a.packet_number > b.packet_number; }); +} + +std::unique_ptr +QUICAckFrameCreator::QUICAckPacketNumbers::create_ack_frame(QUICEncryptionLevel level, uint16_t maximum_frame_size) +{ + auto ack_frame = QUICFrameFactory::create_null_ack_frame(); + if (!this->_available) { + this->_should_send = false; + this->_cancel_timer(); + return ack_frame; + } + + ack_frame = this->_create_ack_frame(level); + if (ack_frame && ack_frame->size() > maximum_frame_size) { + // Cancel generating frame + ack_frame = QUICFrameFactory::create_null_ack_frame(); + } else { + this->_available = false; + this->_should_send = false; + this->_cancel_timer(); + } + + return ack_frame; +} + +std::unique_ptr +QUICAckFrameCreator::QUICAckPacketNumbers::_create_ack_frame(QUICEncryptionLevel level) +{ + ink_assert(this->_packet_numbers.size() > 0); std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); - QUICPacketNumber largest_ack_number = list.front(); - QUICPacketNumber last_ack_number = largest_ack_number; + this->sort(); + std::list &list = this->_packet_numbers; uint8_t gap = 0; uint64_t length = 0; + auto it = list.begin(); + + // skip ack_only packets + for (; it != list.end(); it++) { + if (!(*it).ack_only) { + break; + } + } + + if (it == list.end()) { + return ack_frame; + } + + QUICPacketNumber largest_ack_number = (*it).packet_number; + QUICPacketNumber last_ack_number = largest_ack_number; - auto it = list.begin(); while (it != list.end()) { - QUICPacketNumber pn = *it; + QUICPacketNumber pn = (*it).packet_number; if (pn == last_ack_number) { last_ack_number--; length++; @@ -123,7 +286,8 @@ QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { uint64_t delay = this->_calculate_delay(level); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_issue_frame_id(), this); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_ack_creator->issue_frame_id(), + this->_ack_creator); } gap = last_ack_number - pn; @@ -135,113 +299,71 @@ QUICAckFrameCreator::_create_ack_frame(QUICEncryptionLevel level) ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { uint64_t delay = this->_calculate_delay(level); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_issue_frame_id(), this); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_ack_creator->issue_frame_id(), + this->_ack_creator); } return ack_frame; } -bool -QUICAckFrameCreator::will_generate_frame(QUICEncryptionLevel level) -{ - // No ACK frame on ZERO_RTT level - if (!this->_is_level_matched(level) || level == QUICEncryptionLevel::ZERO_RTT) { - return false; - } - - int index = QUICTypeUtil::pn_space_index(level); - return this->_should_send[index]; -} - uint64_t -QUICAckFrameCreator::_calculate_delay(QUICEncryptionLevel level) +QUICAckFrameCreator::QUICAckPacketNumbers::_calculate_delay(QUICEncryptionLevel level) { // Ack delay is in microseconds and scaled ink_hrtime now = Thread::get_hrtime(); - int index = QUICTypeUtil::pn_space_index(level); - uint64_t delay = (now - this->_packet_numbers[index].largest_ack_received_time()) / 1000; + uint64_t delay = (now - this->_largest_ack_received_time) / 1000; uint8_t ack_delay_exponent = 3; if (level != QUICEncryptionLevel::INITIAL && level != QUICEncryptionLevel::HANDSHAKE) { - ack_delay_exponent = this->_ack_delay_exponent; + ack_delay_exponent = this->_ack_creator->ack_delay_exponent(); } return delay >> ack_delay_exponent; } -void -QUICAckFrameCreator::_on_frame_acked(QUICFrameInformation info) -{ - ink_assert(info.type == QUICFrameType::ACK); - AckFrameInfomation *ack_info = reinterpret_cast(info.data); - int index = QUICTypeUtil::pn_space_index(info.level); - this->_packet_numbers[index].forget(ack_info->largest_acknowledged); - if (this->_packet_numbers[index].size() == 0) { - this->_can_send[index] = false; - this->_should_send[index] = false; - } -} - -// -// QUICAckPacketNumbers -// -void -QUICAckPacketNumbers::forget(QUICPacketNumber largest_acknowledged) -{ - this->sort(); - std::list remove_list; - for (auto it = this->_packet_numbers.begin(); it != this->_packet_numbers.end(); it++) { - if (*it == largest_acknowledged) { - remove_list.splice(remove_list.begin(), this->_packet_numbers, it, this->_packet_numbers.end()); - return; - } - } -} - -void -QUICAckPacketNumbers::push_back(QUICPacketNumber packet_number) +int +QUICAckFrameCreator::QUICAckPacketNumbers::timer_fired(int event, Event *ev) { - if (packet_number == 0 || packet_number > this->_largest_ack_number) { - this->_largest_ack_received_time = Thread::get_hrtime(); - this->_largest_ack_number = packet_number; - } - - this->_packet_numbers.push_back(packet_number); + this->_event = nullptr; + this->_should_send = true; + this->_qc->common_send_packet(); + return 0; } -const std::list -QUICAckPacketNumbers::list() const +bool +QUICAckFrameCreator::QUICAckPacketNumbers::available() const { - return this->_packet_numbers; + return this->_available; } -size_t -QUICAckPacketNumbers::size() +bool +QUICAckFrameCreator::QUICAckPacketNumbers::should_send() const { - return this->_packet_numbers.size(); + return this->_should_send; } void -QUICAckPacketNumbers::clear() +QUICAckFrameCreator::QUICAckPacketNumbers::_start_timer() { - this->_packet_numbers.clear(); - this->_largest_ack_number = 0; - this->_largest_ack_received_time = 0; + if (this->_event == nullptr) { + this->_event = this_ethread()->schedule_at(this, Thread::get_hrtime() + QUIC_ACK_CREATOR_MAX_DELAY); + } } -QUICPacketNumber -QUICAckPacketNumbers::largest_ack_number() +void +QUICAckFrameCreator::QUICAckPacketNumbers::_cancel_timer() { - return this->_largest_ack_number; + if (this->_event) { + this->_event->cancel(); + this->_event = nullptr; + } } -ink_hrtime -QUICAckPacketNumbers::largest_ack_received_time() +QUICAckFrameCreator::QUICAckPacketNumbers::QUICAckPacketNumbers(QUICNetVConnection *qc, QUICAckFrameCreator *ack_creator) + : _qc(qc), _ack_creator(ack_creator) { - return this->_largest_ack_received_time; + SET_HANDLER(&QUICAckFrameCreator::QUICAckPacketNumbers::timer_fired); } -void -QUICAckPacketNumbers::sort() +QUICAckFrameCreator::QUICAckPacketNumbers::~QUICAckPacketNumbers() { - // TODO Find more smart way - this->_packet_numbers.sort([](const QUICPacketNumber a, const QUICPacketNumber b) -> bool { return a > b; }); + this->_cancel_timer(); } diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 166ae5dd1a3..273652ba01f 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -23,6 +23,8 @@ #pragma once +#include "../../eventsystem/I_EventSystem.h" +#include "../../eventsystem/I_Action.h" #include "tscore/ink_hrtime.h" #include "QUICFrameGenerator.h" #include "QUICTypes.h" @@ -30,32 +32,59 @@ #include #include -class QUICAckPacketNumbers -{ -public: - void push_back(QUICPacketNumber packet_number); - size_t size(); - void clear(); - void sort(); - void forget(QUICPacketNumber largest_acknowledged); - - const std::list list() const; - - QUICPacketNumber largest_ack_number(); - ink_hrtime largest_ack_received_time(); +#define QUIC_ACK_CREATOR_MAX_DELAY 25 * HRTIME_MSECOND -private: - QUICPacketNumber _largest_ack_number = 0; - ink_hrtime _largest_ack_received_time = 0; - - std::list _packet_numbers; -}; +class QUICNetVConnection; class QUICAckFrameCreator : public QUICFrameGenerator { public: + class QUICAckPacketNumbers : public Continuation + { + public: + struct RecvdPacket { + bool ack_only = false; + QUICPacketNumber packet_number = 0; + }; + QUICAckPacketNumbers(QUICNetVConnection *qc, QUICAckFrameCreator *ack_creator); + ~QUICAckPacketNumbers(); + + void set_creator(QUICAckFrameCreator *ack_creator); + void push_back(QUICEncryptionLevel level, QUICPacketNumber packet_number, size_t size, bool ack_only); + size_t size(); + void clear(); + void sort(); + void forget(QUICPacketNumber largest_acknowledged); + bool available() const; + bool should_send() const; + std::unique_ptr create_ack_frame(QUICEncryptionLevel level, uint16_t maximum_frame_size); + + QUICPacketNumber largest_ack_number(); + ink_hrtime largest_ack_received_time(); + int timer_fired(int event, Event *edata); + + private: + void _cancel_timer(); + void _start_timer(); + + uint64_t _calculate_delay(QUICEncryptionLevel level); + std::unique_ptr _create_ack_frame(QUICEncryptionLevel level); + + std::list _packet_numbers; + Event *_event = nullptr; + bool _available = false; + bool _should_send = false; + size_t _size_unsend = 0; + QUICPacketNumber _largest_ack_number = 0; + QUICPacketNumber _expect_next = 0; + ink_hrtime _largest_ack_received_time = 0; + + QUICNetVConnection *_qc = nullptr; + QUICAckFrameCreator *_ack_creator = nullptr; + }; + static constexpr int MAXIMUM_PACKET_COUNT = 256; - QUICAckFrameCreator(){}; + QUICAckFrameCreator(QUICNetVConnection *qc); void set_ack_delay_exponent(uint8_t ack_delay_exponent); @@ -63,7 +92,7 @@ class QUICAckFrameCreator : public QUICFrameGenerator * All packet numbers ATS received need to be passed to this method. * Returns 0 if updated successfully. */ - int update(QUICEncryptionLevel level, QUICPacketNumber packet_number, bool should_send); + int update(QUICEncryptionLevel level, QUICPacketNumber packet_number, size_t size, bool akc_only); /* * Returns true only if should send ack. @@ -75,11 +104,16 @@ class QUICAckFrameCreator : public QUICFrameGenerator */ QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrameId issue_frame_id(); + uint8_t ack_delay_exponent() const; + private: struct AckFrameInfomation { QUICPacketNumber largest_acknowledged = 0; }; + Event *_event = nullptr; + virtual void _on_frame_acked(QUICFrameInformation info) override; /* @@ -99,11 +133,13 @@ class QUICAckFrameCreator : public QUICFrameGenerator }; } - bool _can_send[4] = {false}; + bool _available[4] = {false}; bool _should_send[4] = {false}; // Initial, 0/1-RTT, and Handshake - QUICAckPacketNumbers _packet_numbers[3]; + std::unique_ptr _packet_numbers[3]; uint8_t _ack_delay_exponent = 0; + + ink_hrtime _latest_sent_time = 0; }; diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 54b5a4ae637..8b81de22ebf 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -42,12 +42,12 @@ QUICFrameDispatcher::add_handler(QUICFrameHandler *handler) } QUICConnectionErrorUPtr -QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, bool &should_send_ack, +QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *payload, uint16_t size, bool &ack_only, bool &is_flow_controlled, bool *has_non_probing_frame) { std::shared_ptr frame(nullptr); uint16_t cursor = 0; - should_send_ack = false; + ack_only = true; is_flow_controlled = false; QUICConnectionErrorUPtr error = nullptr; @@ -74,7 +74,9 @@ QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *pa QUICDebug("[RX] %s", msg); } - should_send_ack |= (type != QUICFrameType::PADDING && type != QUICFrameType::ACK); + if (type != QUICFrameType::PADDING && type != QUICFrameType::ACK) { + ack_only = false; + } std::vector handlers = this->_handlers[static_cast(type)]; for (auto h : handlers) { From 61693dd6c5a442757f7214d6c09df9cda4e54d3f Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 29 Nov 2018 10:45:32 +0800 Subject: [PATCH 0948/1313] QUIC Sink common_send_packet to QUICConnection --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/quic/QUICAckFrameCreator.cc | 6 +++--- iocore/net/quic/QUICAckFrameCreator.h | 9 +++++---- iocore/net/quic/QUICConnection.h | 1 + 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 70c41af2943..b10f2f88b91 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -228,7 +228,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub LINK(QUICNetVConnection, closed_link); SLINK(QUICNetVConnection, closed_alink); - void common_send_packet(); + void common_send_packet() override; private: QUICPacketType _last_received_packet_type = QUICPacketType::UNINITIALIZED; diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 5072ef09fd8..2c04927a82f 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -24,9 +24,9 @@ #include "I_EventSystem.h" #include "QUICAckFrameCreator.h" #include -#include +#include -QUICAckFrameCreator::QUICAckFrameCreator(QUICNetVConnection *qc) +QUICAckFrameCreator::QUICAckFrameCreator(QUICConnection *qc) { for (auto i = 0; i < 3; i++) { this->_packet_numbers[i] = std::make_unique(qc, this); @@ -357,7 +357,7 @@ QUICAckFrameCreator::QUICAckPacketNumbers::_cancel_timer() } } -QUICAckFrameCreator::QUICAckPacketNumbers::QUICAckPacketNumbers(QUICNetVConnection *qc, QUICAckFrameCreator *ack_creator) +QUICAckFrameCreator::QUICAckPacketNumbers::QUICAckPacketNumbers(QUICConnection *qc, QUICAckFrameCreator *ack_creator) : _qc(qc), _ack_creator(ack_creator) { SET_HANDLER(&QUICAckFrameCreator::QUICAckPacketNumbers::timer_fired); diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 273652ba01f..e86f3e23fde 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -34,7 +34,7 @@ #define QUIC_ACK_CREATOR_MAX_DELAY 25 * HRTIME_MSECOND -class QUICNetVConnection; +class QUICConnection; class QUICAckFrameCreator : public QUICFrameGenerator { @@ -46,7 +46,7 @@ class QUICAckFrameCreator : public QUICFrameGenerator bool ack_only = false; QUICPacketNumber packet_number = 0; }; - QUICAckPacketNumbers(QUICNetVConnection *qc, QUICAckFrameCreator *ack_creator); + QUICAckPacketNumbers(QUICConnection *qc, QUICAckFrameCreator *ack_creator); ~QUICAckPacketNumbers(); void set_creator(QUICAckFrameCreator *ack_creator); @@ -79,12 +79,13 @@ class QUICAckFrameCreator : public QUICFrameGenerator QUICPacketNumber _expect_next = 0; ink_hrtime _largest_ack_received_time = 0; - QUICNetVConnection *_qc = nullptr; + QUICConnection *_qc = nullptr; QUICAckFrameCreator *_ack_creator = nullptr; }; static constexpr int MAXIMUM_PACKET_COUNT = 256; - QUICAckFrameCreator(QUICNetVConnection *qc); + + QUICAckFrameCreator(QUICConnection *qc); void set_ack_delay_exponent(uint8_t ack_delay_exponent); diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index aa67aec7f69..8ca130846fe 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -71,4 +71,5 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler, pu virtual QUICStreamManager *stream_manager() = 0; virtual void close(QUICConnectionErrorUPtr error) = 0; virtual void handle_received_packet(UDPPacket *packeet) = 0; + virtual void common_send_packet() = 0; }; From a732c62a1a84d27ee3a1fc644fa7aa67d0785ce0 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 29 Nov 2018 10:57:14 +0800 Subject: [PATCH 0949/1313] QUIC test_QUICAckFrameCreator --- iocore/net/quic/Mock.h | 5 ++ iocore/net/quic/QUICAckFrameCreator.cc | 2 +- .../net/quic/test/test_QUICAckFrameCreator.cc | 55 +++++++++++-------- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index ac201a87ce0..ca934402c8a 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -276,6 +276,11 @@ class MockQUICConnection : public QUICConnection { } + void + common_send_packet() override + { + } + int _transmit_count = 0; int _retransmit_count = 0; Ptr _mutex; diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 2c04927a82f..d84180b007e 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -131,11 +131,11 @@ QUICAckFrameCreator::QUICAckPacketNumbers::forget(QUICPacketNumber largest_ackno this->sort(); std::list remove_list; for (auto it = this->_packet_numbers.begin(); it != this->_packet_numbers.end(); it++) { - this->_available |= !(*it).ack_only; if ((*it).packet_number == largest_acknowledged) { remove_list.splice(remove_list.begin(), this->_packet_numbers, it, this->_packet_numbers.end()); break; } + this->_available |= !(*it).ack_only; } if (this->_packet_numbers.size() == 0 || !this->_available) { diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 329cef8e4f2..64bfd36e62b 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -25,10 +25,13 @@ #include "I_EventSystem.h" #include "quic/QUICAckFrameCreator.h" +#include "Mock.h" + TEST_CASE("QUICAckFrameCreator", "[quic]") { - QUICAckFrameCreator creator; + MockQUICConnection qc; + QUICAckFrameCreator creator(&qc); QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; // Initial state @@ -37,7 +40,7 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame == nullptr); // One packet - creator.update(level, 1, true); + creator.update(level, 1, 1, false); ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); @@ -49,10 +52,10 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(creator.will_generate_frame(level) == false); // Not sequential - creator.update(level, 2, true); - creator.update(level, 5, true); - creator.update(level, 3, true); - creator.update(level, 4, true); + creator.update(level, 2, 1, false); + creator.update(level, 5, 1, false); + creator.update(level, 3, 1, false); + creator.update(level, 4, 1, false); ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); @@ -61,9 +64,9 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 4); // Loss - creator.update(level, 6, true); - creator.update(level, 7, true); - creator.update(level, 10, true); + creator.update(level, 6, 1, false); + creator.update(level, 7, 1, false); + creator.update(level, 10, 1, false); ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); @@ -79,9 +82,9 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); CHECK(ack_frame == nullptr); - creator.update(level, 11, true); - creator.update(level, 12, true); - creator.update(level, 13, true); + creator.update(level, 11, 1, false); + creator.update(level, 12, 1, false); + creator.update(level, 13, 1, false); ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); @@ -93,7 +96,8 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") { - QUICAckFrameCreator creator; + MockQUICConnection qc; + QUICAckFrameCreator creator(&qc); QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; // Initial state @@ -101,11 +105,11 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") std::shared_ptr frame = std::static_pointer_cast(ack_frame); CHECK(frame == nullptr); - creator.update(level, 2, true); - creator.update(level, 5, true); - creator.update(level, 6, true); - creator.update(level, 8, true); - creator.update(level, 9, true); + creator.update(level, 2, 1, false); + creator.update(level, 5, 1, false); + creator.update(level, 6, 1, false); + creator.update(level, 8, 1, false); + creator.update(level, 9, 1, false); ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); @@ -117,8 +121,8 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") CHECK(creator.will_generate_frame(level) == false); - creator.update(level, 7, true); - creator.update(level, 4, true); + creator.update(level, 7, 1, false); + creator.update(level, 4, 1, false); ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); @@ -130,7 +134,10 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") TEST_CASE("QUICAckFrameCreator_QUICAckPacketNumbers", "[quic]") { - QUICAckPacketNumbers packet_numbers; + MockQUICConnection qc; + QUICAckFrameCreator creator(&qc); + QUICAckFrameCreator::QUICAckPacketNumbers packet_numbers(&qc, &creator); + QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; CHECK(packet_numbers.size() == 0); CHECK(packet_numbers.largest_ack_number() == 0); @@ -138,7 +145,7 @@ TEST_CASE("QUICAckFrameCreator_QUICAckPacketNumbers", "[quic]") Thread::get_hrtime_updated(); - packet_numbers.push_back(3); + packet_numbers.push_back(level, 3, 2, false); CHECK(packet_numbers.size() == 1); CHECK(packet_numbers.largest_ack_number() == 3); @@ -147,14 +154,14 @@ TEST_CASE("QUICAckFrameCreator_QUICAckPacketNumbers", "[quic]") Thread::get_hrtime_updated(); - packet_numbers.push_back(2); + packet_numbers.push_back(level, 2, 2, false); CHECK(packet_numbers.size() == 2); CHECK(packet_numbers.largest_ack_number() == 3); CHECK(packet_numbers.largest_ack_received_time() == ti); Thread::get_hrtime_updated(); - packet_numbers.push_back(10); + packet_numbers.push_back(level, 10, 2, false); CHECK(packet_numbers.size() == 3); CHECK(packet_numbers.largest_ack_number() == 10); CHECK(packet_numbers.largest_ack_received_time() > ti); From dd49e1d69fd14652c17deec590717b2eb4812926 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 29 Nov 2018 11:42:12 +0800 Subject: [PATCH 0950/1313] QUIC: add test for delay ack --- iocore/net/quic/Mock.h | 4 +- iocore/net/quic/QUICAckFrameCreator.cc | 19 +++-- iocore/net/quic/QUICAckFrameCreator.h | 15 ++-- .../net/quic/test/test_QUICAckFrameCreator.cc | 84 ++++++++++++++++++- 4 files changed, 107 insertions(+), 15 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index ca934402c8a..b0e0952c97a 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -276,8 +276,8 @@ class MockQUICConnection : public QUICConnection { } - void - common_send_packet() override + void + common_send_packet() override { } diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index d84180b007e..6fb63950dbd 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -153,14 +153,17 @@ QUICAckFrameCreator::QUICAckPacketNumbers::push_back(QUICEncryptionLevel level, this->_largest_ack_number = packet_number; } + if (!this->_latest_packet_received_time) { + this->_latest_packet_received_time = Thread::get_hrtime(); + } + // delay too much time - if (this->_largest_ack_received_time + QUIC_ACK_CREATOR_MAX_DELAY <= Thread::get_hrtime()) { + if (this->_latest_packet_received_time + QUIC_ACK_CREATOR_MAX_DELAY <= Thread::get_hrtime()) { this->_should_send = true; } // unorder packet should send ack immediately to accellerate the recovery if (this->_expect_next != packet_number) { - this->_expect_next = std::max(this->_expect_next, packet_number + 1); this->_should_send = true; } @@ -186,6 +189,7 @@ QUICAckFrameCreator::QUICAckPacketNumbers::push_back(QUICEncryptionLevel level, this->_start_timer(); } + this->_expect_next = packet_number + 1; this->_packet_numbers.push_back({ack_only, packet_number}); } @@ -237,8 +241,9 @@ QUICAckFrameCreator::QUICAckPacketNumbers::create_ack_frame(QUICEncryptionLevel // Cancel generating frame ack_frame = QUICFrameFactory::create_null_ack_frame(); } else { - this->_available = false; - this->_should_send = false; + this->_available = false; + this->_should_send = false; + this->_latest_packet_received_time = 0; this->_cancel_timer(); } @@ -344,7 +349,11 @@ void QUICAckFrameCreator::QUICAckPacketNumbers::_start_timer() { if (this->_event == nullptr) { - this->_event = this_ethread()->schedule_at(this, Thread::get_hrtime() + QUIC_ACK_CREATOR_MAX_DELAY); + auto ethread = this_ethread(); + // this check for test. + if (ethread) { + this->_event = ethread->schedule_at(this, Thread::get_hrtime() + QUIC_ACK_CREATOR_MAX_DELAY); + } } } diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index e86f3e23fde..f7f758055c1 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -71,13 +71,14 @@ class QUICAckFrameCreator : public QUICFrameGenerator std::unique_ptr _create_ack_frame(QUICEncryptionLevel level); std::list _packet_numbers; - Event *_event = nullptr; - bool _available = false; - bool _should_send = false; - size_t _size_unsend = 0; - QUICPacketNumber _largest_ack_number = 0; - QUICPacketNumber _expect_next = 0; - ink_hrtime _largest_ack_received_time = 0; + Event *_event = nullptr; + bool _available = false; + bool _should_send = false; + size_t _size_unsend = 0; + QUICPacketNumber _largest_ack_number = 0; + QUICPacketNumber _expect_next = 0; + ink_hrtime _largest_ack_received_time = 0; + ink_hrtime _latest_packet_received_time = 0; QUICConnection *_qc = nullptr; QUICAckFrameCreator *_ack_creator = nullptr; diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 64bfd36e62b..8545b1b34f1 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -27,7 +27,6 @@ #include "quic/QUICAckFrameCreator.h" #include "Mock.h" - TEST_CASE("QUICAckFrameCreator", "[quic]") { MockQUICConnection qc; @@ -92,6 +91,89 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame->largest_acknowledged() == 13); CHECK(frame->ack_block_section()->first_ack_block() == 2); CHECK(frame->ack_block_section()->begin()->gap() == 0); + + creator.on_frame_acked(frame->id()); + + // ack-only + creator.update(level, 14, 1, true); + creator.update(level, 15, 1, true); + creator.update(level, 16, 1, true); + CHECK(creator.will_generate_frame(level) == false); + ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + + creator.update(level, 17, 1, false); + ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); + CHECK(frame != nullptr); + CHECK(frame->ack_block_count() == 0); + CHECK(frame->largest_acknowledged() == 17); + CHECK(frame->ack_block_section()->first_ack_block() == 3); + CHECK(frame->ack_block_section()->begin()->gap() == 0); +} + +TEST_CASE("QUICAckFrameCreator should send", "[quic]") +{ + SECTION("QUIC unorder packet", "[quic]") + { + MockQUICConnection qc; + QUICAckFrameCreator creator(&qc); + + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + creator.update(level, 2, 1, false); + CHECK(creator.will_generate_frame(level) == true); + } + + SECTION("QUIC delay ack and unorder packet", "[quic]") + { + MockQUICConnection qc; + QUICAckFrameCreator creator(&qc); + + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + creator.update(level, 0, 1, false); + CHECK(creator.will_generate_frame(level) == false); + + creator.update(level, 1, 1, false); + CHECK(creator.will_generate_frame(level) == false); + + creator.update(level, 3, 1, false); + CHECK(creator.will_generate_frame(level) == true); + } + + SECTION("QUIC delay too much time", "[quic]") + { + Thread::get_hrtime_updated(); + MockQUICConnection qc; + QUICAckFrameCreator creator(&qc); + + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + creator.update(level, 0, 1, false); + CHECK(creator.will_generate_frame(level) == false); + + sleep(1); + Thread::get_hrtime_updated(); + creator.update(level, 1, 1, false); + CHECK(creator.will_generate_frame(level) == true); + } + + SECTION("QUIC intial packet", "[quic]") + { + MockQUICConnection qc; + QUICAckFrameCreator creator(&qc); + + QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; + creator.update(level, 0, 1, false); + CHECK(creator.will_generate_frame(level) == true); + } + + SECTION("QUIC handshake packet", "[quic]") + { + MockQUICConnection qc; + QUICAckFrameCreator creator(&qc); + + QUICEncryptionLevel level = QUICEncryptionLevel::HANDSHAKE; + creator.update(level, 0, 1, false); + CHECK(creator.will_generate_frame(level) == true); + } } TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") From afd9c89872f52a637dde4d23361c57bbb1aea134 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 1 Dec 2018 13:26:33 +0800 Subject: [PATCH 0951/1313] QUIC: Make a periodic event to send ack_frame --- iocore/net/P_QUICNetVConnection.h | 11 +- iocore/net/QUICNetVConnection.cc | 80 +++++++- iocore/net/quic/Mock.h | 5 - iocore/net/quic/QUICAckFrameCreator.cc | 186 ++++++++--------- iocore/net/quic/QUICAckFrameCreator.h | 49 +++-- iocore/net/quic/QUICConnection.h | 1 - iocore/net/quic/QUICDebugNames.cc | 2 + iocore/net/quic/QUICEvents.h | 1 + .../net/quic/test/test_QUICAckFrameCreator.cc | 191 ++++++++++-------- 9 files changed, 303 insertions(+), 223 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index b10f2f88b91..094b7059747 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -151,7 +151,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub using super = UnixNetVConnection; ///< Parent type. public: - QUICNetVConnection() : _ack_frame_creator(this) {} + QUICNetVConnection(); + ~QUICNetVConnection(); void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *, QUICPacketHandler *); void init(QUICConnectionId peer_cid, QUICConnectionId original_cid, QUICConnectionId first_cid, UDPConnection *, QUICPacketHandler *, QUICConnectionTable *ctable); @@ -228,8 +229,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub LINK(QUICNetVConnection, closed_link); SLINK(QUICNetVConnection, closed_alink); - void common_send_packet() override; - private: QUICPacketType _last_received_packet_type = QUICPacketType::UNINITIALIZED; std::random_device _rnd; @@ -249,7 +248,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketHandler *_packet_handler = nullptr; QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; - QUICAckFrameCreator _ack_frame_creator; + QUICAckFrameManager _ack_frame_manager; QUICPacketRetransmitter _packet_retransmitter; QUICPacketNumberProtector _pn_protector; QUICRTTMeasure _rtt_measure; @@ -300,6 +299,10 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _close_path_validation_timeout(Event *data); Event *_path_validation_timeout = nullptr; + void _unschedule_ack_manager_periodic(); + Event *_ack_manager_periodic = nullptr; + bool _refresh_ack_frame_manager(); + uint64_t _maximum_stream_frame_data_size(); void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr &frame, std::vector &frames); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5874a222e42..e6a4eb7a9bb 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -76,6 +76,17 @@ static constexpr uint32_t STATE_CLOSING_MAX_RECV_PKT_WIND = 1 << STATE_CLOSING_M ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); +QUICNetVConnection::QUICNetVConnection() {} + +QUICNetVConnection::~QUICNetVConnection() +{ + this->_unschedule_ack_manager_periodic(); + this->_unschedule_packet_write_ready(); + this->_unschedule_closing_timeout(); + this->_unschedule_closed_event(); + this->_unschedule_path_validation_timeout(); +} + // XXX This might be called on ET_UDP thread void QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *udp_con, @@ -197,6 +208,11 @@ QUICNetVConnection::acceptEvent(int event, Event *e) set_active_timeout(active_timeout_in); } + auto ethread = this_ethread(); + if (ethread != nullptr) { + this->_ack_manager_periodic = ethread->schedule_every(this, HRTIME_MSECONDS(25), QUIC_EVENT_ACK_PERIODIC); + } + action_.continuation->handleEvent(NET_EVENT_ACCEPT, this); this->_schedule_packet_write_ready(); @@ -231,12 +247,12 @@ QUICNetVConnection::start() this->_five_tuple.update(this->local_addr, this->remote_addr, SOCK_DGRAM); // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not if (this->direction() == NET_VCONNECTION_IN) { - this->_ack_frame_creator.set_ack_delay_exponent(params->ack_delay_exponent_in()); + this->_ack_frame_manager.set_ack_delay_exponent(params->ack_delay_exponent_in()); this->_reset_token = QUICStatelessResetToken(this->_quic_connection_id, params->instance_id()); this->_hs_protocol = this->_setup_handshake_protocol(params->server_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol, this->_reset_token, params->stateless_retry()); } else { - this->_ack_frame_creator.set_ack_delay_exponent(params->ack_delay_exponent_out()); + this->_ack_frame_manager.set_ack_delay_exponent(params->ack_delay_exponent_out()); this->_hs_protocol = this->_setup_handshake_protocol(params->client_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol); this->_handshake_handler->start(&this->_packet_factory, params->vn_exercise_enabled()); @@ -599,6 +615,15 @@ QUICNetVConnection::state_handshake(int event, Event *data) } while (error == nullptr && (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::IGNORED)); break; } + case QUIC_EVENT_ACK_PERIODIC: { + if (!this->_refresh_ack_frame_manager()) { + break; + } + } + + // we have ack to send + // FIXME: should sent depend on socket event. + /* fall through */ case QUIC_EVENT_PACKET_WRITE_READY: { this->_close_packet_write_ready(data); @@ -638,6 +663,15 @@ QUICNetVConnection::state_connection_established(int event, Event *data) error = this->_state_connection_established_receive_packet(); break; } + case QUIC_EVENT_ACK_PERIODIC: { + if (!this->_refresh_ack_frame_manager()) { + break; + } + } + // we have ack to send + // FIXME: should sent depend on socket event. + + /* fall through */ case QUIC_EVENT_PACKET_WRITE_READY: { this->_close_packet_write_ready(data); error = this->_state_common_send_packet(); @@ -686,6 +720,7 @@ QUICNetVConnection::state_connection_closing(int event, Event *data) this->_close_closing_timeout(data); this->_switch_to_close_state(); break; + case QUIC_EVENT_ACK_PERIODIC: default: QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); ink_assert(false); @@ -716,6 +751,7 @@ QUICNetVConnection::state_connection_draining(int event, Event *data) this->_close_closing_timeout(data); this->_switch_to_close_state(); break; + case QUIC_EVENT_ACK_PERIODIC: default: QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); ink_assert(false); @@ -730,6 +766,7 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); switch (event) { case QUIC_EVENT_SHUTDOWN: { + this->_unschedule_ack_manager_periodic(); this->_unschedule_packet_write_ready(); this->_unschedule_closing_timeout(); this->_unschedule_path_validation_timeout(); @@ -1350,11 +1387,11 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa // ACK if (frame_count == 0) { - if (this->_ack_frame_creator.will_generate_frame(level)) { - frame = this->_ack_frame_creator.generate_frame(level, UINT16_MAX, max_frame_size); + if (this->_ack_frame_manager.will_generate_frame(level)) { + frame = this->_ack_frame_manager.generate_frame(level, UINT16_MAX, max_frame_size); } } else { - frame = this->_ack_frame_creator.generate_frame(level, UINT16_MAX, max_frame_size); + frame = this->_ack_frame_manager.generate_frame(level, UINT16_MAX, max_frame_size); } bool ack_only = false; @@ -1458,7 +1495,7 @@ QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_fram this->_local_flow_controller->current_limit()); } - this->_ack_frame_creator.update(level, packet_num, size, ack_only); + this->_ack_frame_manager.update(level, packet_num, size, ack_only); return error; } @@ -1666,6 +1703,16 @@ QUICNetVConnection::_unschedule_closing_timeout() } } +void +QUICNetVConnection::_unschedule_ack_manager_periodic() +{ + if (this->_ack_manager_periodic) { + QUICConDebug("Unschedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_ACK_PERIODIC)); + this->_ack_manager_periodic->cancel(); + this->_ack_manager_periodic = nullptr; + } +} + void QUICNetVConnection::_close_closing_timeout(Event *data) { @@ -1824,6 +1871,10 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) QUICConDebug("Reason: %.*s", static_cast(strlen(error->msg)), error->msg); } + // Once we are in closing or draining state, the ack_manager is not needed anymore. Because we don't send + // any frame other than close_frame. + this->_unschedule_ack_manager_periodic(); + this->_connection_error = std::move(error); this->_schedule_packet_write_ready(); @@ -1852,6 +1903,10 @@ QUICNetVConnection::_switch_to_draining_state(QUICConnectionErrorUPtr error) QUICConDebug("Reason: %.*s", static_cast(strlen(error->msg)), error->msg); } + // Once we are in closing or draining state, the ack_manager is not needed anymore. Because we don't send + // any frame other than close_frame. + this->_unschedule_ack_manager_periodic(); + this->remove_from_active_queue(); this->set_inactivity_timeout(0); @@ -2057,8 +2112,15 @@ QUICNetVConnection::_handle_path_validation_timeout(Event *data) } } -void -QUICNetVConnection::common_send_packet() +bool +QUICNetVConnection::_refresh_ack_frame_manager() { - this->_schedule_packet_write_ready(); + this->_ack_frame_manager.timer_fired(); + for (auto level : QUIC_PN_SPACES) { + if (this->_ack_frame_manager.will_generate_frame(level)) { + return true; + } + } + + return false; } diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index b0e0952c97a..ac201a87ce0 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -276,11 +276,6 @@ class MockQUICConnection : public QUICConnection { } - void - common_send_packet() override - { - } - int _transmit_count = 0; int _retransmit_count = 0; Ptr _mutex; diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 6fb63950dbd..674c50d7363 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -26,15 +26,18 @@ #include #include -QUICAckFrameCreator::QUICAckFrameCreator(QUICConnection *qc) +QUICAckFrameManager::QUICAckFrameManager() { - for (auto i = 0; i < 3; i++) { - this->_packet_numbers[i] = std::make_unique(qc, this); + for (auto level : QUIC_PN_SPACES) { + int index = QUICTypeUtil::pn_space_index(level); + this->_ack_creator[index] = std::make_unique(level, this); } } +QUICAckFrameManager::~QUICAckFrameManager() {} + void -QUICAckFrameCreator::set_ack_delay_exponent(uint8_t ack_delay_exponent) +QUICAckFrameManager::set_ack_delay_exponent(uint8_t ack_delay_exponent) { // This function should be called only once ink_assert(this->_ack_delay_exponent == 0); @@ -42,20 +45,20 @@ QUICAckFrameCreator::set_ack_delay_exponent(uint8_t ack_delay_exponent) } int -QUICAckFrameCreator::update(QUICEncryptionLevel level, QUICPacketNumber packet_number, size_t size, bool ack_only) +QUICAckFrameManager::update(QUICEncryptionLevel level, QUICPacketNumber packet_number, size_t size, bool ack_only) { if (!this->_is_level_matched(level)) { return 0; } - int index = QUICTypeUtil::pn_space_index(level); - auto &packet_numbers = this->_packet_numbers[index]; - packet_numbers->push_back(level, packet_number, size, ack_only); + int index = QUICTypeUtil::pn_space_index(level); + auto &ack_creator = this->_ack_creator[index]; + ack_creator->push_back(packet_number, size, ack_only); return 0; } QUICFrameUPtr -QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICAckFrameManager::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); @@ -63,9 +66,9 @@ QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connecti return ack_frame; } - int index = QUICTypeUtil::pn_space_index(level); - auto &packet_number = this->_packet_numbers[index]; - ack_frame = packet_number->create_ack_frame(level, maximum_frame_size); + int index = QUICTypeUtil::pn_space_index(level); + auto &ack_creator = this->_ack_creator[index]; + ack_frame = ack_creator->generate_ack_frame(maximum_frame_size); if (ack_frame != nullptr) { QUICFrameInformation info; @@ -75,15 +78,13 @@ QUICAckFrameCreator::generate_frame(QUICEncryptionLevel level, uint64_t connecti info.level = level; info.type = ack_frame->type(); this->_records_frame(ack_frame->id(), info); - - this->_latest_sent_time = Thread::get_hrtime(); } return ack_frame; } bool -QUICAckFrameCreator::will_generate_frame(QUICEncryptionLevel level) +QUICAckFrameManager::will_generate_frame(QUICEncryptionLevel level) { // No ACK frame on ZERO_RTT level if (!this->_is_level_matched(level) || level == QUICEncryptionLevel::ZERO_RTT) { @@ -91,41 +92,55 @@ QUICAckFrameCreator::will_generate_frame(QUICEncryptionLevel level) } int index = QUICTypeUtil::pn_space_index(level); - return this->_packet_numbers[index]->should_send(); + return this->_ack_creator[index]->is_ack_frame_ready(); } void -QUICAckFrameCreator::_on_frame_acked(QUICFrameInformation info) +QUICAckFrameManager::_on_frame_acked(QUICFrameInformation info) { ink_assert(info.type == QUICFrameType::ACK); AckFrameInfomation *ack_info = reinterpret_cast(info.data); int index = QUICTypeUtil::pn_space_index(info.level); - this->_packet_numbers[index]->forget(ack_info->largest_acknowledged); + this->_ack_creator[index]->forget(ack_info->largest_acknowledged); } QUICFrameId -QUICAckFrameCreator::issue_frame_id() +QUICAckFrameManager::issue_frame_id() { return this->_issue_frame_id(); } uint8_t -QUICAckFrameCreator::ack_delay_exponent() const +QUICAckFrameManager::ack_delay_exponent() const { return this->_ack_delay_exponent; } +int +QUICAckFrameManager::timer_fired() +{ + for (auto level : QUIC_PN_SPACES) { + int index = QUICTypeUtil::pn_space_index(level); + this->_ack_creator[index]->refresh_frame(); + } + + return 0; +} + // -// QUICAckFrameCreator::QUICAckPacketNumbers +// QUICAckFrameManager::QUICAckFrameCreator // void -QUICAckFrameCreator::QUICAckPacketNumbers::set_creator(QUICAckFrameCreator *creator) +QUICAckFrameManager::QUICAckFrameCreator::refresh_frame() { - this->_ack_creator = creator; + if (this->_available) { + // make sure we have the new ack_frame to override the old one. + this->_ack_frame = this->create_ack_frame(); + } } void -QUICAckFrameCreator::QUICAckPacketNumbers::forget(QUICPacketNumber largest_acknowledged) +QUICAckFrameManager::QUICAckFrameCreator::forget(QUICPacketNumber largest_acknowledged) { this->_available = false; this->sort(); @@ -140,13 +155,11 @@ QUICAckFrameCreator::QUICAckPacketNumbers::forget(QUICPacketNumber largest_ackno if (this->_packet_numbers.size() == 0 || !this->_available) { this->_should_send = false; - this->_cancel_timer(); } } void -QUICAckFrameCreator::QUICAckPacketNumbers::push_back(QUICEncryptionLevel level, QUICPacketNumber packet_number, size_t size, - bool ack_only) +QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_number, size_t size, bool ack_only) { if (packet_number == 0 || packet_number > this->_largest_ack_number) { this->_largest_ack_received_time = Thread::get_hrtime(); @@ -175,7 +188,7 @@ QUICAckFrameCreator::QUICAckPacketNumbers::push_back(QUICEncryptionLevel level, } // can not delay handshake packet - if (level == QUICEncryptionLevel::INITIAL || level == QUICEncryptionLevel::HANDSHAKE) { + if (this->_level == QUICEncryptionLevel::INITIAL || this->_level == QUICEncryptionLevel::HANDSHAKE) { this->_should_send = true; } @@ -185,73 +198,84 @@ QUICAckFrameCreator::QUICAckPacketNumbers::push_back(QUICEncryptionLevel level, this->_should_send = this->_available ? this->_should_send : false; } - if (!this->_should_send && this->_available) { - this->_start_timer(); - } - this->_expect_next = packet_number + 1; this->_packet_numbers.push_back({ack_only, packet_number}); + + if (this->_should_send && this->_available) { + this->_ack_frame = this->create_ack_frame(); + } } size_t -QUICAckFrameCreator::QUICAckPacketNumbers::size() +QUICAckFrameManager::QUICAckFrameCreator::size() { return this->_packet_numbers.size(); } void -QUICAckFrameCreator::QUICAckPacketNumbers::clear() +QUICAckFrameManager::QUICAckFrameCreator::clear() { this->_packet_numbers.clear(); - this->_largest_ack_number = 0; - this->_largest_ack_received_time = 0; + this->_largest_ack_number = 0; + this->_largest_ack_received_time = 0; + this->_latest_packet_received_time = 0; + this->_size_unsend = 0; + this->_should_send = false; + this->_available = false; } QUICPacketNumber -QUICAckFrameCreator::QUICAckPacketNumbers::largest_ack_number() +QUICAckFrameManager::QUICAckFrameCreator::largest_ack_number() { return this->_largest_ack_number; } ink_hrtime -QUICAckFrameCreator::QUICAckPacketNumbers::largest_ack_received_time() +QUICAckFrameManager::QUICAckFrameCreator::largest_ack_received_time() { return this->_largest_ack_received_time; } void -QUICAckFrameCreator::QUICAckPacketNumbers::sort() +QUICAckFrameManager::QUICAckFrameCreator::sort() { // TODO Find more smart way this->_packet_numbers.sort([](const RecvdPacket &a, const RecvdPacket &b) -> bool { return a.packet_number > b.packet_number; }); } std::unique_ptr -QUICAckFrameCreator::QUICAckPacketNumbers::create_ack_frame(QUICEncryptionLevel level, uint16_t maximum_frame_size) +QUICAckFrameManager::QUICAckFrameCreator::generate_ack_frame(uint16_t maximum_frame_size) +{ + std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); + if (this->_ack_frame && this->_ack_frame->size() <= maximum_frame_size) { + ack_frame = std::move(this->_ack_frame); + this->_ack_frame = nullptr; + } + + return ack_frame; +} + +std::unique_ptr +QUICAckFrameManager::QUICAckFrameCreator::create_ack_frame() { - auto ack_frame = QUICFrameFactory::create_null_ack_frame(); + std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); if (!this->_available) { this->_should_send = false; - this->_cancel_timer(); return ack_frame; } - ack_frame = this->_create_ack_frame(level); - if (ack_frame && ack_frame->size() > maximum_frame_size) { - // Cancel generating frame - ack_frame = QUICFrameFactory::create_null_ack_frame(); - } else { + ack_frame = this->_create_ack_frame(); + if (ack_frame != nullptr) { this->_available = false; this->_should_send = false; this->_latest_packet_received_time = 0; - this->_cancel_timer(); } return ack_frame; } std::unique_ptr -QUICAckFrameCreator::QUICAckPacketNumbers::_create_ack_frame(QUICEncryptionLevel level) +QUICAckFrameManager::QUICAckFrameCreator::_create_ack_frame() { ink_assert(this->_packet_numbers.size() > 0); std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); @@ -290,9 +314,9 @@ QUICAckFrameCreator::QUICAckPacketNumbers::_create_ack_frame(QUICEncryptionLevel if (ack_frame) { ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { - uint64_t delay = this->_calculate_delay(level); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_ack_creator->issue_frame_id(), - this->_ack_creator); + uint64_t delay = this->_calculate_delay(); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_ack_manager->issue_frame_id(), + this->_ack_manager); } gap = last_ack_number - pn; @@ -303,76 +327,42 @@ QUICAckFrameCreator::QUICAckPacketNumbers::_create_ack_frame(QUICEncryptionLevel if (ack_frame) { ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { - uint64_t delay = this->_calculate_delay(level); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_ack_creator->issue_frame_id(), - this->_ack_creator); + uint64_t delay = this->_calculate_delay(); + ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_ack_manager->issue_frame_id(), + this->_ack_manager); } return ack_frame; } uint64_t -QUICAckFrameCreator::QUICAckPacketNumbers::_calculate_delay(QUICEncryptionLevel level) +QUICAckFrameManager::QUICAckFrameCreator::_calculate_delay() { // Ack delay is in microseconds and scaled ink_hrtime now = Thread::get_hrtime(); uint64_t delay = (now - this->_largest_ack_received_time) / 1000; uint8_t ack_delay_exponent = 3; - if (level != QUICEncryptionLevel::INITIAL && level != QUICEncryptionLevel::HANDSHAKE) { - ack_delay_exponent = this->_ack_creator->ack_delay_exponent(); + if (this->_level != QUICEncryptionLevel::INITIAL && this->_level != QUICEncryptionLevel::HANDSHAKE) { + ack_delay_exponent = this->_ack_manager->ack_delay_exponent(); } return delay >> ack_delay_exponent; } -int -QUICAckFrameCreator::QUICAckPacketNumbers::timer_fired(int event, Event *ev) -{ - this->_event = nullptr; - this->_should_send = true; - this->_qc->common_send_packet(); - return 0; -} - bool -QUICAckFrameCreator::QUICAckPacketNumbers::available() const +QUICAckFrameManager::QUICAckFrameCreator::available() const { return this->_available; } bool -QUICAckFrameCreator::QUICAckPacketNumbers::should_send() const +QUICAckFrameManager::QUICAckFrameCreator::is_ack_frame_ready() const { - return this->_should_send; + return this->_ack_frame != nullptr; } -void -QUICAckFrameCreator::QUICAckPacketNumbers::_start_timer() +QUICAckFrameManager::QUICAckFrameCreator::QUICAckFrameCreator(QUICEncryptionLevel level, QUICAckFrameManager *ack_manager) + : _ack_manager(ack_manager), _level(level) { - if (this->_event == nullptr) { - auto ethread = this_ethread(); - // this check for test. - if (ethread) { - this->_event = ethread->schedule_at(this, Thread::get_hrtime() + QUIC_ACK_CREATOR_MAX_DELAY); - } - } } -void -QUICAckFrameCreator::QUICAckPacketNumbers::_cancel_timer() -{ - if (this->_event) { - this->_event->cancel(); - this->_event = nullptr; - } -} - -QUICAckFrameCreator::QUICAckPacketNumbers::QUICAckPacketNumbers(QUICConnection *qc, QUICAckFrameCreator *ack_creator) - : _qc(qc), _ack_creator(ack_creator) -{ - SET_HANDLER(&QUICAckFrameCreator::QUICAckPacketNumbers::timer_fired); -} - -QUICAckFrameCreator::QUICAckPacketNumbers::~QUICAckPacketNumbers() -{ - this->_cancel_timer(); -} +QUICAckFrameManager::QUICAckFrameCreator::~QUICAckFrameCreator() {} diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index f7f758055c1..770cb6f54eb 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -23,9 +23,6 @@ #pragma once -#include "../../eventsystem/I_EventSystem.h" -#include "../../eventsystem/I_Action.h" -#include "tscore/ink_hrtime.h" #include "QUICFrameGenerator.h" #include "QUICTypes.h" #include "QUICFrame.h" @@ -36,42 +33,42 @@ class QUICConnection; -class QUICAckFrameCreator : public QUICFrameGenerator +class QUICAckFrameManager : public QUICFrameGenerator { public: - class QUICAckPacketNumbers : public Continuation + class QUICAckFrameCreator { public: struct RecvdPacket { bool ack_only = false; QUICPacketNumber packet_number = 0; }; - QUICAckPacketNumbers(QUICConnection *qc, QUICAckFrameCreator *ack_creator); - ~QUICAckPacketNumbers(); + QUICAckFrameCreator(QUICEncryptionLevel level, QUICAckFrameManager *ack_manager); + ~QUICAckFrameCreator(); - void set_creator(QUICAckFrameCreator *ack_creator); - void push_back(QUICEncryptionLevel level, QUICPacketNumber packet_number, size_t size, bool ack_only); + void push_back(QUICPacketNumber packet_number, size_t size, bool ack_only); size_t size(); void clear(); void sort(); void forget(QUICPacketNumber largest_acknowledged); bool available() const; - bool should_send() const; - std::unique_ptr create_ack_frame(QUICEncryptionLevel level, uint16_t maximum_frame_size); + bool is_ack_frame_ready() const; + std::unique_ptr create_ack_frame(); + + // Checks maximum_frame_size and return _ack_frame + std::unique_ptr generate_ack_frame(uint16_t maximum_frame_size); + + // timer event handler, refresh _ack_frame; + void refresh_frame(); QUICPacketNumber largest_ack_number(); ink_hrtime largest_ack_received_time(); - int timer_fired(int event, Event *edata); private: - void _cancel_timer(); - void _start_timer(); - - uint64_t _calculate_delay(QUICEncryptionLevel level); - std::unique_ptr _create_ack_frame(QUICEncryptionLevel level); + uint64_t _calculate_delay(); + std::unique_ptr _create_ack_frame(); std::list _packet_numbers; - Event *_event = nullptr; bool _available = false; bool _should_send = false; size_t _size_unsend = 0; @@ -80,13 +77,16 @@ class QUICAckFrameCreator : public QUICFrameGenerator ink_hrtime _largest_ack_received_time = 0; ink_hrtime _latest_packet_received_time = 0; - QUICConnection *_qc = nullptr; - QUICAckFrameCreator *_ack_creator = nullptr; + std::unique_ptr _ack_frame = QUICFrameFactory::create_null_ack_frame(); + QUICAckFrameManager *_ack_manager = nullptr; + + QUICEncryptionLevel _level = QUICEncryptionLevel::NONE; }; static constexpr int MAXIMUM_PACKET_COUNT = 256; - QUICAckFrameCreator(QUICConnection *qc); + QUICAckFrameManager(); + ~QUICAckFrameManager(); void set_ack_delay_exponent(uint8_t ack_delay_exponent); @@ -106,6 +106,7 @@ class QUICAckFrameCreator : public QUICFrameGenerator */ QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + int timer_fired(); QUICFrameId issue_frame_id(); uint8_t ack_delay_exponent() const; @@ -114,8 +115,6 @@ class QUICAckFrameCreator : public QUICFrameGenerator QUICPacketNumber largest_acknowledged = 0; }; - Event *_event = nullptr; - virtual void _on_frame_acked(QUICFrameInformation info) override; /* @@ -139,9 +138,7 @@ class QUICAckFrameCreator : public QUICFrameGenerator bool _should_send[4] = {false}; // Initial, 0/1-RTT, and Handshake - std::unique_ptr _packet_numbers[3]; + std::unique_ptr _ack_creator[3]; uint8_t _ack_delay_exponent = 0; - - ink_hrtime _latest_sent_time = 0; }; diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 8ca130846fe..aa67aec7f69 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -71,5 +71,4 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler, pu virtual QUICStreamManager *stream_manager() = 0; virtual void close(QUICConnectionErrorUPtr error) = 0; virtual void handle_received_packet(UDPPacket *packeet) = 0; - virtual void common_send_packet() = 0; }; diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 3fc496d959a..492bf5eb838 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -164,6 +164,8 @@ QUICDebugNames::quic_event(int event) return "QUIC_EVENT_SHUTDOWN"; case QUIC_EVENT_LD_SHUTDOWN: return "QUIC_EVENT_LD_SHUTDOWN"; + case QUIC_EVENT_ACK_PERIODIC: + return "QUIC_EVENT_ACK_PERIODIC"; default: return "UNKNOWN"; } diff --git a/iocore/net/quic/QUICEvents.h b/iocore/net/quic/QUICEvents.h index 59e3feb5e97..c758249ee93 100644 --- a/iocore/net/quic/QUICEvents.h +++ b/iocore/net/quic/QUICEvents.h @@ -32,6 +32,7 @@ enum { QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, QUIC_EVENT_CLOSING_TIMEOUT, QUIC_EVENT_PATH_VALIDATION_TIMEOUT, + QUIC_EVENT_ACK_PERIODIC, QUIC_EVENT_SHUTDOWN, QUIC_EVENT_LD_SHUTDOWN, }; diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 8545b1b34f1..3a6121b5d54 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -27,20 +27,19 @@ #include "quic/QUICAckFrameCreator.h" #include "Mock.h" -TEST_CASE("QUICAckFrameCreator", "[quic]") +TEST_CASE("QUICAckFrameManager", "[quic]") { - MockQUICConnection qc; - QUICAckFrameCreator creator(&qc); + QUICAckFrameManager ack_manager; QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; // Initial state - std::shared_ptr ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + std::shared_ptr ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); std::shared_ptr frame = std::static_pointer_cast(ack_frame); CHECK(frame == nullptr); // One packet - creator.update(level, 1, 1, false); - ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + ack_manager.update(level, 1, 1, false); + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -48,14 +47,14 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 0); // retry - CHECK(creator.will_generate_frame(level) == false); + CHECK(ack_manager.will_generate_frame(level) == false); // Not sequential - creator.update(level, 2, 1, false); - creator.update(level, 5, 1, false); - creator.update(level, 3, 1, false); - creator.update(level, 4, 1, false); - ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + ack_manager.update(level, 2, 1, false); + ack_manager.update(level, 5, 1, false); + ack_manager.update(level, 3, 1, false); + ack_manager.update(level, 4, 1, false); + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -63,10 +62,10 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 4); // Loss - creator.update(level, 6, 1, false); - creator.update(level, 7, 1, false); - creator.update(level, 10, 1, false); - ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + ack_manager.update(level, 6, 1, false); + ack_manager.update(level, 7, 1, false); + ack_manager.update(level, 10, 1, false); + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); @@ -75,16 +74,16 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame->ack_block_section()->begin()->gap() == 1); // on frame acked - creator.on_frame_acked(frame->id()); + ack_manager.on_frame_acked(frame->id()); - CHECK(creator.will_generate_frame(level) == false); - ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + CHECK(ack_manager.will_generate_frame(level) == false); + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); CHECK(ack_frame == nullptr); - creator.update(level, 11, 1, false); - creator.update(level, 12, 1, false); - creator.update(level, 13, 1, false); - ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + ack_manager.update(level, 11, 1, false); + ack_manager.update(level, 12, 1, false); + ack_manager.update(level, 13, 1, false); + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -92,17 +91,17 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 2); CHECK(frame->ack_block_section()->begin()->gap() == 0); - creator.on_frame_acked(frame->id()); + ack_manager.on_frame_acked(frame->id()); // ack-only - creator.update(level, 14, 1, true); - creator.update(level, 15, 1, true); - creator.update(level, 16, 1, true); - CHECK(creator.will_generate_frame(level) == false); - ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); - - creator.update(level, 17, 1, false); - ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + ack_manager.update(level, 14, 1, true); + ack_manager.update(level, 15, 1, true); + ack_manager.update(level, 16, 1, true); + CHECK(ack_manager.will_generate_frame(level) == false); + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); + + ack_manager.update(level, 17, 1, false); + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -111,89 +110,122 @@ TEST_CASE("QUICAckFrameCreator", "[quic]") CHECK(frame->ack_block_section()->begin()->gap() == 0); } -TEST_CASE("QUICAckFrameCreator should send", "[quic]") +TEST_CASE("QUICAckFrameManager should send", "[quic]") { SECTION("QUIC unorder packet", "[quic]") { - MockQUICConnection qc; - QUICAckFrameCreator creator(&qc); + QUICAckFrameManager ack_manager; QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; - creator.update(level, 2, 1, false); - CHECK(creator.will_generate_frame(level) == true); + ack_manager.update(level, 2, 1, false); + CHECK(ack_manager.will_generate_frame(level) == true); } SECTION("QUIC delay ack and unorder packet", "[quic]") { - MockQUICConnection qc; - QUICAckFrameCreator creator(&qc); + QUICAckFrameManager ack_manager; QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; - creator.update(level, 0, 1, false); - CHECK(creator.will_generate_frame(level) == false); + ack_manager.update(level, 0, 1, false); + CHECK(ack_manager.will_generate_frame(level) == false); - creator.update(level, 1, 1, false); - CHECK(creator.will_generate_frame(level) == false); + ack_manager.update(level, 1, 1, false); + CHECK(ack_manager.will_generate_frame(level) == false); - creator.update(level, 3, 1, false); - CHECK(creator.will_generate_frame(level) == true); + ack_manager.update(level, 3, 1, false); + CHECK(ack_manager.will_generate_frame(level) == true); } SECTION("QUIC delay too much time", "[quic]") { Thread::get_hrtime_updated(); - MockQUICConnection qc; - QUICAckFrameCreator creator(&qc); + QUICAckFrameManager ack_manager; QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; - creator.update(level, 0, 1, false); - CHECK(creator.will_generate_frame(level) == false); + ack_manager.update(level, 0, 1, false); + CHECK(ack_manager.will_generate_frame(level) == false); sleep(1); Thread::get_hrtime_updated(); - creator.update(level, 1, 1, false); - CHECK(creator.will_generate_frame(level) == true); + ack_manager.update(level, 1, 1, false); + CHECK(ack_manager.will_generate_frame(level) == true); } SECTION("QUIC intial packet", "[quic]") { - MockQUICConnection qc; - QUICAckFrameCreator creator(&qc); + QUICAckFrameManager ack_manager; QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; - creator.update(level, 0, 1, false); - CHECK(creator.will_generate_frame(level) == true); + ack_manager.update(level, 0, 1, false); + CHECK(ack_manager.will_generate_frame(level) == true); } SECTION("QUIC handshake packet", "[quic]") { - MockQUICConnection qc; - QUICAckFrameCreator creator(&qc); + QUICAckFrameManager ack_manager; QUICEncryptionLevel level = QUICEncryptionLevel::HANDSHAKE; - creator.update(level, 0, 1, false); - CHECK(creator.will_generate_frame(level) == true); + ack_manager.update(level, 0, 1, false); + CHECK(ack_manager.will_generate_frame(level) == true); + } + + SECTION("QUIC frame fired", "[quic]") + { + QUICAckFrameManager ack_manager; + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + + ack_manager.update(level, 0, 1, false); + CHECK(ack_manager.will_generate_frame(level) == false); + + ack_manager.timer_fired(0, nullptr); + CHECK(ack_manager.will_generate_frame(level) == true); + } + + SECTION("QUIC refresh frame", "[quic]") + { + QUICAckFrameManager ack_manager; + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + + std::shared_ptr ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); + std::shared_ptr frame = std::static_pointer_cast(ack_frame); + CHECK(frame == nullptr); + + // unorder frame should sent immediately + ack_manager.update(level, 1, 1, false); + CHECK(ack_manager.will_generate_frame(level) == true); + + ack_manager.update(level, 2, 1, false); + + // Delay due to some reason, the frame is not valued any more, but still valued + ack_manager.timer_fired(0, nullptr); + CHECK(ack_manager.will_generate_frame(level) == true); + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); + + CHECK(frame->ack_block_count() == 0); + CHECK(frame->largest_acknowledged() == 2); + CHECK(frame->ack_block_section()->first_ack_block() == 1); + CHECK(frame->ack_block_section()->begin()->gap() == 0); } } -TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") +TEST_CASE("QUICAckFrameManager_loss_recover", "[quic]") { - MockQUICConnection qc; - QUICAckFrameCreator creator(&qc); + QUICAckFrameManager ack_manager; QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; // Initial state - std::shared_ptr ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + std::shared_ptr ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); std::shared_ptr frame = std::static_pointer_cast(ack_frame); CHECK(frame == nullptr); - creator.update(level, 2, 1, false); - creator.update(level, 5, 1, false); - creator.update(level, 6, 1, false); - creator.update(level, 8, 1, false); - creator.update(level, 9, 1, false); + ack_manager.update(level, 2, 1, false); + ack_manager.update(level, 5, 1, false); + ack_manager.update(level, 6, 1, false); + ack_manager.update(level, 8, 1, false); + ack_manager.update(level, 9, 1, false); - ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 2); @@ -201,11 +233,11 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 1); CHECK(frame->ack_block_section()->begin()->gap() == 0); - CHECK(creator.will_generate_frame(level) == false); + CHECK(ack_manager.will_generate_frame(level) == false); - creator.update(level, 7, 1, false); - creator.update(level, 4, 1, false); - ack_frame = creator.generate_frame(level, UINT16_MAX, UINT16_MAX); + ack_manager.update(level, 7, 1, false); + ack_manager.update(level, 4, 1, false); + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); @@ -214,12 +246,11 @@ TEST_CASE("QUICAckFrameCreator_loss_recover", "[quic]") CHECK(frame->ack_block_section()->begin()->gap() == 0); } -TEST_CASE("QUICAckFrameCreator_QUICAckPacketNumbers", "[quic]") +TEST_CASE("QUICAckFrameManager_QUICAckFrameCreator", "[quic]") { - MockQUICConnection qc; - QUICAckFrameCreator creator(&qc); - QUICAckFrameCreator::QUICAckPacketNumbers packet_numbers(&qc, &creator); + QUICAckFrameManager ack_manager; QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; + QUICAckFrameManager::QUICAckFrameCreator packet_numbers(level, &ack_manager); CHECK(packet_numbers.size() == 0); CHECK(packet_numbers.largest_ack_number() == 0); @@ -227,7 +258,7 @@ TEST_CASE("QUICAckFrameCreator_QUICAckPacketNumbers", "[quic]") Thread::get_hrtime_updated(); - packet_numbers.push_back(level, 3, 2, false); + packet_numbers.push_back(3, 2, false); CHECK(packet_numbers.size() == 1); CHECK(packet_numbers.largest_ack_number() == 3); @@ -236,14 +267,14 @@ TEST_CASE("QUICAckFrameCreator_QUICAckPacketNumbers", "[quic]") Thread::get_hrtime_updated(); - packet_numbers.push_back(level, 2, 2, false); + packet_numbers.push_back(2, 2, false); CHECK(packet_numbers.size() == 2); CHECK(packet_numbers.largest_ack_number() == 3); CHECK(packet_numbers.largest_ack_received_time() == ti); Thread::get_hrtime_updated(); - packet_numbers.push_back(level, 10, 2, false); + packet_numbers.push_back(10, 2, false); CHECK(packet_numbers.size() == 3); CHECK(packet_numbers.largest_ack_number() == 10); CHECK(packet_numbers.largest_ack_received_time() > ti); From f313cb52fc6ba1d6ea77ee0ae6091affa9a70a4c Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 3 Dec 2018 09:51:44 +0800 Subject: [PATCH 0952/1313] QUIC: Schedule PACKET_READY_EVENT if ack_frame availiable --- iocore/net/QUICNetVConnection.cc | 23 ++++++++++++++--------- iocore/net/quic/QUICAckFrameCreator.cc | 23 +++++++++++++++++++++-- iocore/net/quic/QUICAckFrameCreator.h | 5 +++-- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e6a4eb7a9bb..43d7ab44d47 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -208,11 +208,6 @@ QUICNetVConnection::acceptEvent(int event, Event *e) set_active_timeout(active_timeout_in); } - auto ethread = this_ethread(); - if (ethread != nullptr) { - this->_ack_manager_periodic = ethread->schedule_every(this, HRTIME_MSECONDS(25), QUIC_EVENT_ACK_PERIODIC); - } - action_.continuation->handleEvent(NET_EVENT_ACCEPT, this); this->_schedule_packet_write_ready(); @@ -282,6 +277,12 @@ 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); + + if (this->thread) { + this->_ack_manager_periodic = this->thread->schedule_every(this, params->max_ack_delay_in(), QUIC_EVENT_ACK_PERIODIC); + } else { + this->_ack_frame_manager.set_force_to_send(); + } } void @@ -619,11 +620,13 @@ QUICNetVConnection::state_handshake(int event, Event *data) if (!this->_refresh_ack_frame_manager()) { break; } - } // we have ack to send // FIXME: should sent depend on socket event. - /* fall through */ + this->_schedule_packet_write_ready(); + break; + } + case QUIC_EVENT_PACKET_WRITE_READY: { this->_close_packet_write_ready(data); @@ -667,11 +670,13 @@ QUICNetVConnection::state_connection_established(int event, Event *data) if (!this->_refresh_ack_frame_manager()) { break; } - } + // we have ack to send // FIXME: should sent depend on socket event. + this->_schedule_packet_write_ready(); + break; + } - /* fall through */ case QUIC_EVENT_PACKET_WRITE_READY: { this->_close_packet_write_ready(data); error = this->_state_common_send_packet(); diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 674c50d7363..cddb65d3520 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -23,8 +23,8 @@ #include "I_EventSystem.h" #include "QUICAckFrameCreator.h" +#include "QUICConfig.h" #include -#include QUICAckFrameManager::QUICAckFrameManager() { @@ -127,6 +127,18 @@ QUICAckFrameManager::timer_fired() return 0; } +void +QUICAckFrameManager::set_force_to_send(bool on) +{ + this->_force_to_send = on; +} + +bool +QUICAckFrameManager::force_to_send() const +{ + return this->_force_to_send; +} + // // QUICAckFrameManager::QUICAckFrameCreator // @@ -161,6 +173,8 @@ QUICAckFrameManager::QUICAckFrameCreator::forget(QUICPacketNumber largest_acknow void QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_number, size_t size, bool ack_only) { + QUICConfig::scoped_config params; + if (packet_number == 0 || packet_number > this->_largest_ack_number) { this->_largest_ack_received_time = Thread::get_hrtime(); this->_largest_ack_number = packet_number; @@ -171,7 +185,7 @@ QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_numb } // delay too much time - if (this->_latest_packet_received_time + QUIC_ACK_CREATOR_MAX_DELAY <= Thread::get_hrtime()) { + if (this->_latest_packet_received_time + params->max_ack_delay_in() <= Thread::get_hrtime()) { this->_should_send = true; } @@ -182,6 +196,7 @@ QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_numb // 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; this->_should_send = true; @@ -192,6 +207,10 @@ QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_numb this->_should_send = true; } + if (this->_ack_manager->force_to_send()) { + this->_should_send = true; + } + if (!ack_only) { this->_available = true; } else { diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 770cb6f54eb..8b841708977 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -29,8 +29,6 @@ #include #include -#define QUIC_ACK_CREATOR_MAX_DELAY 25 * HRTIME_MSECOND - class QUICConnection; class QUICAckFrameManager : public QUICFrameGenerator @@ -89,6 +87,8 @@ class QUICAckFrameManager : public QUICFrameGenerator ~QUICAckFrameManager(); void set_ack_delay_exponent(uint8_t ack_delay_exponent); + void set_force_to_send(bool on = true); + bool force_to_send() const; /* * All packet numbers ATS received need to be passed to this method. @@ -140,5 +140,6 @@ class QUICAckFrameManager : public QUICFrameGenerator // Initial, 0/1-RTT, and Handshake std::unique_ptr _ack_creator[3]; + bool _force_to_send = false; uint8_t _ack_delay_exponent = 0; }; From 1bc29d2627d010f55e9d01bf3b729038bd716077 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 3 Dec 2018 12:21:06 +0800 Subject: [PATCH 0953/1313] QUIC: Add assertion on QUICNetVConnection::thread and fix tests --- iocore/net/QUICNetVConnection.cc | 7 ++----- iocore/net/quic/test/test_QUICAckFrameCreator.cc | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 43d7ab44d47..f441f80a10f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -278,11 +278,8 @@ QUICNetVConnection::start() this->_frame_dispatcher->add_handler(this->_path_validator); this->_frame_dispatcher->add_handler(this->_handshake_handler); - if (this->thread) { - this->_ack_manager_periodic = this->thread->schedule_every(this, params->max_ack_delay_in(), QUIC_EVENT_ACK_PERIODIC); - } else { - this->_ack_frame_manager.set_force_to_send(); - } + ink_release_assert(this->thread != nullptr); + this->_ack_manager_periodic = this->thread->schedule_every(this, params->max_ack_delay_in(), QUIC_EVENT_ACK_PERIODIC); } void diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 3a6121b5d54..a02d0d91df4 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -177,7 +177,7 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") ack_manager.update(level, 0, 1, false); CHECK(ack_manager.will_generate_frame(level) == false); - ack_manager.timer_fired(0, nullptr); + ack_manager.timer_fired(); CHECK(ack_manager.will_generate_frame(level) == true); } @@ -197,7 +197,7 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") ack_manager.update(level, 2, 1, false); // Delay due to some reason, the frame is not valued any more, but still valued - ack_manager.timer_fired(0, nullptr); + ack_manager.timer_fired(); CHECK(ack_manager.will_generate_frame(level) == true); ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); From d0d35fdb93fbe38716cd0784d7519b8a6b8b8d6f Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 4 Dec 2018 11:59:59 +0800 Subject: [PATCH 0954/1313] QUIC: Remove force_to_send api --- iocore/net/quic/QUICAckFrameCreator.cc | 16 ---------------- iocore/net/quic/QUICAckFrameCreator.h | 1 - 2 files changed, 17 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index cddb65d3520..14ae2f78175 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -127,18 +127,6 @@ QUICAckFrameManager::timer_fired() return 0; } -void -QUICAckFrameManager::set_force_to_send(bool on) -{ - this->_force_to_send = on; -} - -bool -QUICAckFrameManager::force_to_send() const -{ - return this->_force_to_send; -} - // // QUICAckFrameManager::QUICAckFrameCreator // @@ -207,10 +195,6 @@ QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_numb this->_should_send = true; } - if (this->_ack_manager->force_to_send()) { - this->_should_send = true; - } - if (!ack_only) { this->_available = true; } else { diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 8b841708977..0e172449aab 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -140,6 +140,5 @@ class QUICAckFrameManager : public QUICFrameGenerator // Initial, 0/1-RTT, and Handshake std::unique_ptr _ack_creator[3]; - bool _force_to_send = false; uint8_t _ack_delay_exponent = 0; }; From 4eb3fbf2280ed5c0d7a5ba9acfecdcb58a8d6944 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 6 Dec 2018 10:56:28 +0800 Subject: [PATCH 0955/1313] QUIC: Send ping frame to force peer send ack --- iocore/net/P_QUICNetVConnection.h | 3 ++- iocore/net/QUICNetVConnection.cc | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 094b7059747..1ad0d486599 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -374,7 +374,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub uint64_t _stream_frames_sent = 0; // TODO: Source addresses verification through an address validation token - bool _src_addr_verified = false; + bool _src_addr_verified = false; + bool _has_ack_only_packet_out = false; }; typedef int (QUICNetVConnection::*QUICNetVConnHandler)(int, void *); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index f441f80a10f..d26f8188145 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1406,6 +1406,27 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa this->_store_frame(buf, len, max_frame_size, frame, frames); } + QUICConfig::scoped_config params; + if (ack_only) { + if (this->_has_ack_only_packet_out) { + // Sent too much ack_only packet. At this moment we need to packetize a ping frame + // to force peer send ack frame. + if (max_frame_size > len) { + this->_has_ack_only_packet_out = false; + // don't care ping frame lost or acked + frame = QUICFrameFactory::create_ping_frame(0, nullptr); + ++frame_count; + ack_only = false; + probing |= frame->is_probing_frame(); + this->_store_frame(buf, len, max_frame_size, frame, frames); + } + } else { + this->_has_ack_only_packet_out = true; + } + } else if (!ack_only) { + this->_has_ack_only_packet_out = false; + } + // Schedule a packet if (len != 0) { if (level == QUICEncryptionLevel::INITIAL && this->netvc_context == NET_VCONNECTION_OUT) { From bc3e89b05ca7f178a55a50826d17b4d7ceac96e1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 10 Dec 2018 16:38:33 +0900 Subject: [PATCH 0956/1313] Fix tests for AckFrameManager --- iocore/net/quic/test/test_QUICLossDetector.cc | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 9e8d99142ac..3722553a22e 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -35,14 +35,14 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") pf.set_hs_protocol(&hs_protocol); QUICRTTMeasure rtt_measure; - QUICAckFrameCreator afc; + QUICAckFrameManager afm; QUICConnectionId connection_id = {reinterpret_cast("\x01"), 1}; MockQUICPacketTransmitter tx; MockQUICConnectionInfoProvider info; MockQUICCongestionController cc(&info); QUICLossDetector detector(&tx, &info, &cc, &rtt_measure, 0); - ats_unique_buf payload = ats_unique_malloc(16); - size_t payload_len = 16; + ats_unique_buf payload = ats_unique_malloc(512); + size_t payload_len = 512; QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); std::shared_ptr frame = QUICFrameFactory::create_null_ack_frame(); std::vector dummy_frames; @@ -84,31 +84,31 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") CHECK(tx.retransmitted.size() == 0); // Send packet (1) to (7) - payload = ats_unique_malloc(16); + payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(16); + payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet2 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(16); + payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet3 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(16); + payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet4 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(16); + payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet5 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(16); + payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet6 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(16); + payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet7 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(16); + payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet8 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(16); + payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet9 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); @@ -135,14 +135,14 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") ink_hrtime_sleep(HRTIME_MSECONDS(1000)); // Receive an ACK for (1) (4) (5) (7) (8) (9) - afc.update(QUICEncryptionLevel::INITIAL, pn1, true); - afc.update(QUICEncryptionLevel::INITIAL, pn4, true); - afc.update(QUICEncryptionLevel::INITIAL, pn5, true); - afc.update(QUICEncryptionLevel::INITIAL, pn7, true); - afc.update(QUICEncryptionLevel::INITIAL, pn8, true); - afc.update(QUICEncryptionLevel::INITIAL, pn9, true); + afm.update(QUICEncryptionLevel::INITIAL, pn1, payload_len, false); + afm.update(QUICEncryptionLevel::INITIAL, pn4, payload_len, false); + afm.update(QUICEncryptionLevel::INITIAL, pn5, payload_len, false); + afm.update(QUICEncryptionLevel::INITIAL, pn7, payload_len, false); + afm.update(QUICEncryptionLevel::INITIAL, pn8, payload_len, false); + afm.update(QUICEncryptionLevel::INITIAL, pn9, payload_len, false); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); - std::shared_ptr x = afc.generate_frame(QUICEncryptionLevel::INITIAL, 2048, 2048); + std::shared_ptr x = afm.generate_frame(QUICEncryptionLevel::INITIAL, 2048, 2048); frame = std::dynamic_pointer_cast(x); detector.handle_frame(QUICEncryptionLevel::INITIAL, *frame.get()); ink_hrtime_sleep(HRTIME_MSECONDS(5000)); From 5d1082ce96dcd4cc9149e55a185763cc6436148d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 3 Dec 2018 18:00:23 +0900 Subject: [PATCH 0957/1313] Add QUICAddressVaridationToken and QUICResumptionToken --- .gitignore | 2 + iocore/net/P_QUICNetVConnection.h | 4 +- iocore/net/QUICNetVConnection.cc | 26 ++++----- iocore/net/QUICPacketHandler.cc | 18 ++++--- iocore/net/quic/Makefile.am | 8 +++ iocore/net/quic/QUICTypes.cc | 70 ++++++++++++++++++++++-- iocore/net/quic/QUICTypes.h | 72 +++++++++++++++++++++++-- iocore/net/quic/test/test_QUICType.cc | 78 +++++++++++++++++++++++++++ 8 files changed, 245 insertions(+), 33 deletions(-) create mode 100644 iocore/net/quic/test/test_QUICType.cc diff --git a/.gitignore b/.gitignore index ca1e46d2f60..8854dae50a2 100644 --- a/.gitignore +++ b/.gitignore @@ -91,6 +91,7 @@ lib/perl/lib/Apache/TS.pm iocore/net/test_certlookup iocore/net/test_UDPNet iocore/net/quic/test_QUICAckFrameCreator +iocore/net/quic/test_QUICAltConnectionManager iocore/net/quic/test_QUICFlowController iocore/net/quic/test_QUICFrame iocore/net/quic/test_QUICFrameDispatcher @@ -106,6 +107,7 @@ iocore/net/quic/test_QUICStream iocore/net/quic/test_QUICStreamManager iocore/net/quic/test_QUICStreamState iocore/net/quic/test_QUICTransportParameters +iocore/net/quic/test_QUICType iocore/net/quic/test_QUICTypeUtil iocore/net/quic/test_QUICVersionNegotiator iocore/aio/test_AIO diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 1ad0d486599..f9d1bcf0da1 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -366,8 +366,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet(); QUICStatelessResetToken _reset_token; - ats_unique_buf _retry_token = {nullptr}; - size_t _retry_token_len = 0; + ats_unique_buf _av_token = {nullptr}; + size_t _av_token_len = 0; // This is for limiting number of packets that a server can send without path validation uint32_t _handshake_packets_sent = 0; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index d26f8188145..af7b4503616 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -989,15 +989,15 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) { ink_assert(this->netvc_context == NET_VCONNECTION_OUT); - if (this->_retry_token) { + if (this->_av_token) { QUICConDebug("Ignore RETRY packet - already processed before"); return nullptr; } - // TODO: move packet->payload to _retry_token - this->_retry_token_len = packet->payload_length(); - this->_retry_token = ats_unique_malloc(this->_retry_token_len); - memcpy(this->_retry_token.get(), packet->payload(), this->_retry_token_len); + // TODO: move packet->payload to _av_token + this->_av_token_len = packet->payload_length(); + this->_av_token = ats_unique_malloc(this->_av_token_len); + memcpy(this->_av_token.get(), packet->payload(), this->_av_token_len); // discard all transport state this->_handshake_handler->reset(); @@ -1293,8 +1293,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa // TODO: adjust MAX_PACKET_OVERHEAD for each encryption level uint64_t max_frame_size = max_packet_size - MAX_PACKET_OVERHEAD; - if (level == QUICEncryptionLevel::INITIAL && this->_retry_token) { - max_frame_size = max_frame_size - (QUICVariableInt::size(this->_retry_token_len) + this->_retry_token_len); + if (level == QUICEncryptionLevel::INITIAL && this->_av_token) { + max_frame_size = max_frame_size - (QUICVariableInt::size(this->_av_token_len) + this->_av_token_len); } max_frame_size = std::min(max_frame_size, this->_maximum_stream_frame_data_size()); @@ -1432,8 +1432,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa if (level == QUICEncryptionLevel::INITIAL && this->netvc_context == NET_VCONNECTION_OUT) { // Pad with PADDING frames uint64_t min_size = this->minimum_quic_packet_size(); - if (this->_retry_token) { - min_size = min_size - this->_retry_token_len; + if (this->_av_token) { + min_size = min_size - this->_av_token_len; } min_size = std::min(min_size, max_packet_size); @@ -1544,10 +1544,10 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi if (this->netvc_context == NET_VCONNECTION_OUT) { // TODO: Add a case of using token which is advertized by NEW_TOKEN frame - if (this->_retry_token) { - token = ats_unique_malloc(this->_retry_token_len); - token_len = this->_retry_token_len; - memcpy(token.get(), this->_retry_token.get(), token_len); + if (this->_av_token) { + token = ats_unique_malloc(this->_av_token_len); + token_len = this->_av_token_len; + memcpy(token.get(), this->_av_token.get(), token_len); } else { dcid = this->_original_quic_connection_id; } diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 55122979dd2..0886b6d75de 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -389,15 +389,17 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC QUICPacketLongHeader::scil(scil, buf, buf_len); const uint8_t *token = buf + LONG_HDR_OFFSET_CONNECTION_ID + dcil + scil + token_length_field_len; - QUICConnectionId attached_cid = QUICTypeUtil::read_QUICConnectionId(token + 20, token_length - 20); - QUICRetryToken token1(token, token_length); - QUICRetryToken token2(from, attached_cid); - if (token1 == token2) { - // Tokein is valid - *original_cid = attached_cid; - return 0; + if (QUICAddressValidationToken::type(token) == QUICAddressValidationToken::Type::RETRY) { + QUICRetryToken token1(token, token_length); + if (token1.is_valid(from)) { + *original_cid = token1.original_dcid(); + return 0; + } else { + return -3; + } } else { - return -3; + // TODO Handle ResumptionToken + return -4; } } diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index f39364cbde3..8fcc90b594a 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -100,6 +100,7 @@ check_PROGRAMS = \ test_QUICStreamManager \ test_QUICStreamState \ test_QUICTransportParameters \ + test_QUICType \ test_QUICTypeUtil \ test_QUICVersionNegotiator @@ -247,6 +248,13 @@ test_QUICTransportParameters_SOURCES = \ $(test_main_SOURCES) \ ./test/test_QUICTransportParameters.cc +test_QUICType_CPPFLAGS = $(test_CPPFLAGS) +test_QUICType_LDFLAGS = @AM_LDFLAGS@ +test_QUICType_LDADD = $(test_LDADD) +test_QUICType_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICType.cc + test_QUICTypeUtil_CPPFLAGS = $(test_CPPFLAGS) test_QUICTypeUtil_LDFLAGS = @AM_LDFLAGS@ test_QUICTypeUtil_LDADD = $(test_LDADD) diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 74c9b95a820..178a055938c 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -25,6 +25,7 @@ #include "QUICTypes.h" #include "QUICIntUtil.h" #include "tscore/CryptoHash.h" +#include "I_EventSystem.h" #include uint8_t QUICConnectionId::SCID_LEN = 0; @@ -277,13 +278,64 @@ QUICStatelessResetToken::QUICStatelessResetToken(QUICConnectionId conn_id, uint3 QUICIntUtil::write_uint_as_nbytes(_hash.u64[1], 8, _token + 8, &dummy); } +QUICResumptionToken::QUICResumptionToken(const IpEndpoint &src, QUICConnectionId cid, ink_hrtime expire_time) +{ + // TODO: read cookie secret from file like SSLTicketKeyConfig + static constexpr char stateless_retry_token_secret[] = "stateless_cookie_secret"; + size_t dummy; + + uint8_t data[1 + INET6_ADDRPORTSTRLEN + QUICConnectionId::MAX_LENGTH + 4] = {0}; + size_t data_len = 0; + ats_ip_nptop(src, reinterpret_cast(data), sizeof(data)); + data_len = strlen(reinterpret_cast(data)); + + size_t cid_len; + QUICTypeUtil::write_QUICConnectionId(cid, data + data_len, &cid_len); + data_len += cid_len; + + QUICIntUtil::write_uint_as_nbytes(expire_time >> 30, 4, data + data_len, &dummy); + data_len += 4; + + this->_token[0] = static_cast(Type::RESUMPTION); + HMAC(EVP_sha1(), stateless_retry_token_secret, sizeof(stateless_retry_token_secret), data, data_len, this->_token + 1, + &this->_token_len); + ink_assert(this->_token_len == 20); + this->_token_len += 1; + + QUICIntUtil::write_uint_as_nbytes(expire_time >> 30, 4, this->_token + this->_token_len, &dummy); + this->_token_len += 4; + + QUICTypeUtil::write_QUICConnectionId(cid, this->_token + this->_token_len, &cid_len); + this->_token_len += cid_len; +} + +bool +QUICResumptionToken::is_valid(const IpEndpoint &src) const +{ + QUICResumptionToken x(src, this->cid(), this->expire_time() << 30); + return *this == x && this->expire_time() >= (Thread::get_hrtime() >> 30); +} + +const QUICConnectionId +QUICResumptionToken::cid() const +{ + // Type uses 1 byte and output of EVP_sha1() should be 160 bits + return QUICTypeUtil::read_QUICConnectionId(this->_token + (1 + 20 + 4), this->_token_len - (1 + 20 + 4)); +} + +const ink_hrtime +QUICResumptionToken::expire_time() const +{ + return QUICIntUtil::read_nbytes_as_uint(this->_token + (1 + 20), 4); +} + QUICRetryToken::QUICRetryToken(const IpEndpoint &src, QUICConnectionId original_dcid) { // TODO: read cookie secret from file like SSLTicketKeyConfig static constexpr char stateless_retry_token_secret[] = "stateless_cookie_secret"; - uint8_t data[INET6_ADDRPORTSTRLEN + QUICConnectionId::MAX_LENGTH] = {0}; - size_t data_len = 0; + uint8_t data[1 + INET6_ADDRPORTSTRLEN + QUICConnectionId::MAX_LENGTH] = {0}; + size_t data_len = 0; ats_ip_nptop(src, reinterpret_cast(data), sizeof(data)); data_len = strlen(reinterpret_cast(data)); @@ -291,19 +343,27 @@ QUICRetryToken::QUICRetryToken(const IpEndpoint &src, QUICConnectionId original_ QUICTypeUtil::write_QUICConnectionId(original_dcid, data + data_len, &cid_len); data_len += cid_len; - HMAC(EVP_sha1(), stateless_retry_token_secret, sizeof(stateless_retry_token_secret), data, data_len, this->_token, + this->_token[0] = static_cast(Type::RETRY); + HMAC(EVP_sha1(), stateless_retry_token_secret, sizeof(stateless_retry_token_secret), data, data_len, this->_token + 1, &this->_token_len); ink_assert(this->_token_len == 20); + this->_token_len += 1; QUICTypeUtil::write_QUICConnectionId(original_dcid, this->_token + this->_token_len, &cid_len); this->_token_len += cid_len; } +bool +QUICRetryToken::is_valid(const IpEndpoint &src) const +{ + return *this == QUICRetryToken(src, this->original_dcid()); +} + const QUICConnectionId QUICRetryToken::original_dcid() const { - // Output of EVP_sha1() should be 160 bits - return QUICTypeUtil::read_QUICConnectionId(this->_token + 20, this->_token_len - 20); + // Type uses 1 byte and output of EVP_sha1() should be 160 bits + return QUICTypeUtil::read_QUICConnectionId(this->_token + (1 + 20), this->_token_len - (1 + 20)); } QUICFrameType diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 43acd9edcb7..7783a713f2b 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -25,6 +25,7 @@ #include #include "tscore/ink_endian.h" +#include "tscore/ink_hrtime.h" #include #include @@ -295,7 +296,66 @@ class QUICStatelessResetToken void _generate(uint64_t data); }; -class QUICRetryToken +class QUICAddressValidationToken +{ +public: + enum class Type : uint8_t { + RESUMPTION, + RETRY, + }; + + virtual ~QUICAddressValidationToken(){}; + + static Type + type(const uint8_t *buf) + { + ink_assert(static_cast(buf[0]) == Type::RESUMPTION || static_cast(buf[0]) == Type::RETRY); + return static_cast(buf[0]) == Type::RESUMPTION ? Type::RESUMPTION : Type::RETRY; + } + + virtual const uint8_t *buf() const = 0; + virtual uint8_t length() const = 0; +}; + +class QUICResumptionToken : public QUICAddressValidationToken +{ +public: + QUICResumptionToken() {} + QUICResumptionToken(const uint8_t *buf, uint8_t len) : _token_len(len) { memcpy(this->_token, buf, len); } + QUICResumptionToken(const IpEndpoint &src, QUICConnectionId cid, ink_hrtime expire_time); + + bool + operator==(const QUICResumptionToken &x) const + { + if (this->_token_len != x._token_len) { + return false; + } + return memcmp(this->_token, x._token, this->_token_len) == 0; + } + + bool is_valid(const IpEndpoint &src) const; + + const QUICConnectionId cid() const; + const ink_hrtime expire_time() const; + + const uint8_t * + buf() const override + { + return this->_token; + } + + uint8_t + length() const override + { + return this->_token_len; + } + +private: + uint8_t _token[1 + EVP_MAX_MD_SIZE + QUICConnectionId::MAX_LENGTH + 4]; + unsigned int _token_len; +}; + +class QUICRetryToken : public QUICAddressValidationToken { public: QUICRetryToken() {} @@ -311,23 +371,25 @@ class QUICRetryToken return memcmp(this->_token, x._token, this->_token_len) == 0; } + bool is_valid(const IpEndpoint &src) const; + const QUICConnectionId original_dcid() const; const uint8_t * - buf() const + buf() const override { return this->_token; } uint8_t - length() const + length() const override { return this->_token_len; } private: - uint8_t _token[EVP_MAX_MD_SIZE + QUICConnectionId::MAX_LENGTH] = {}; - unsigned int _token_len = 0; + uint8_t _token[1 + EVP_MAX_MD_SIZE + QUICConnectionId::MAX_LENGTH] = {}; + unsigned int _token_len = 0; QUICConnectionId _original_dcid; }; diff --git a/iocore/net/quic/test/test_QUICType.cc b/iocore/net/quic/test/test_QUICType.cc new file mode 100644 index 00000000000..aff8247fb4c --- /dev/null +++ b/iocore/net/quic/test/test_QUICType.cc @@ -0,0 +1,78 @@ +/** @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 "catch.hpp" + +#include "quic/QUICTypes.h" +#include "I_EventSystem.h" +#include "tscore/ink_hrtime.h" +#include + +TEST_CASE("QUICType", "[quic]") +{ + SECTION("QUICRetryToken") + { + IpEndpoint ep; + ats_ip4_set(&ep, 0x04030201, 0x2211); + + uint8_t cid_buf[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27}; + QUICConnectionId cid(cid_buf, sizeof(cid_buf)); + + QUICRetryToken token1(ep, cid); + QUICRetryToken token2(token1.buf(), token1.length()); + + CHECK(token1.is_valid(ep)); + CHECK(token2.is_valid(ep)); + CHECK(QUICAddressValidationToken::type(token1.buf()) == QUICAddressValidationToken::Type::RETRY); + CHECK(QUICAddressValidationToken::type(token2.buf()) == QUICAddressValidationToken::Type::RETRY); + CHECK(token1 == token2); + CHECK(token1.length() == token2.length()); + CHECK(memcmp(token1.buf(), token2.buf(), token1.length()) == 0); + CHECK(token1.original_dcid() == token2.original_dcid()); + } + + SECTION("QUICResumptionToken") + { + IpEndpoint ep; + ats_ip4_set(&ep, 0x04030201, 0x2211); + + uint8_t cid_buf[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27}; + QUICConnectionId cid(cid_buf, sizeof(cid_buf)); + + ink_hrtime expire_date = Thread::get_hrtime() + (3 * HRTIME_DAY); + + QUICResumptionToken token1(ep, cid, expire_date); + QUICResumptionToken token2(token1.buf(), token1.length()); + + CHECK(token1.is_valid(ep)); + CHECK(token2.is_valid(ep)); + CHECK(QUICAddressValidationToken::type(token1.buf()) == QUICAddressValidationToken::Type::RESUMPTION); + CHECK(QUICAddressValidationToken::type(token2.buf()) == QUICAddressValidationToken::Type::RESUMPTION); + CHECK(token1 == token2); + CHECK(token1.length() == token2.length()); + CHECK(memcmp(token1.buf(), token2.buf(), token1.length()) == 0); + CHECK(token1.cid() == token2.cid()); + } +} From 7979f0c6f11052c47861a621fec6917023c0337f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 10 Dec 2018 16:14:24 +0900 Subject: [PATCH 0958/1313] Send NEW_TOKEN frame --- iocore/net/P_QUICNetVConnection.h | 23 ++++++--- iocore/net/QUICNetVConnection.cc | 57 ++++++++++++++++++++++ iocore/net/quic/QUICDebugNames.cc | 2 + iocore/net/quic/QUICFrame.cc | 14 +++--- iocore/net/quic/QUICFrame.h | 2 +- iocore/net/quic/QUICPacketRetransmitter.cc | 1 + 6 files changed, 86 insertions(+), 13 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index f9d1bcf0da1..e1e14ff21d8 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -146,7 +146,7 @@ class SSLNextProtocolSet; * WRITE: * Do nothing **/ -class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, public RefCountObj +class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, public QUICFrameGenerator, public RefCountObj { using super = UnixNetVConnection; ///< Parent type. @@ -218,9 +218,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub std::vector interests() override; QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; - // QUICConnection (QUICFrameGenerator) - // bool will_generate_frame(QUICEncryptionLevel level); - // QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint16_t connection_credit, uint16_t maximum_frame_size); + // QUICFrameGenerator + bool will_generate_frame(QUICEncryptionLevel level) override; + QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; int in_closed_queue = 0; @@ -366,8 +366,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet(); QUICStatelessResetToken _reset_token; - ats_unique_buf _av_token = {nullptr}; - size_t _av_token_len = 0; + ats_unique_buf _av_token = {nullptr}; + size_t _av_token_len = 0; + bool _is_resumption_token_sent = false; // This is for limiting number of packets that a server can send without path validation uint32_t _handshake_packets_sent = 0; @@ -376,6 +377,16 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub // TODO: Source addresses verification through an address validation token bool _src_addr_verified = false; bool _has_ack_only_packet_out = false; + + // QUICFrameGenerator + void _on_frame_lost(QUICFrameInformation info) override; + std::vector + _encryption_level_filter() override + { + return { + QUICEncryptionLevel::ONE_RTT, + }; + } }; typedef int (QUICNetVConnection::*QUICNetVConnHandler)(int, void *); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index af7b4503616..370ea77a501 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1190,6 +1190,10 @@ QUICNetVConnection::_state_common_send_packet() uint32_t written = 0; for (auto level : QUIC_ENCRYPTION_LEVELS) { + if (level == QUICEncryptionLevel::ONE_RTT && !this->_handshake_handler->is_completed()) { + continue; + } + if (this->netvc_context == NET_VCONNECTION_IN && !this->_is_src_addr_verified() && this->_handshake_packets_sent >= MAX_PACKETS_WITHOUT_SRC_ADDR_VARIDATION) { error = 1; @@ -1317,6 +1321,14 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); } + // NEW_TOKEN + frame = this->generate_frame(level, UINT16_MAX, max_frame_size); + if (frame) { + ++frame_count; + probing |= frame->is_probing_frame(); + this->_store_frame(buf, len, max_frame_size, frame, frames); + } + // PATH_CHALLENGE, PATH_RESPOSNE frame = this->_path_validator->generate_frame(level, UINT16_MAX, max_frame_size); if (frame) { @@ -2147,3 +2159,48 @@ QUICNetVConnection::_refresh_ack_frame_manager() return false; } + +// QUICFrameGenerator +bool +QUICNetVConnection::will_generate_frame(QUICEncryptionLevel level) +{ + if (!this->_is_level_matched(level)) { + return false; + } + + return !this->_is_resumption_token_sent; +} + +QUICFrameUPtr +QUICNetVConnection::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +{ + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + + if (!this->_is_level_matched(level)) { + return frame; + } + + if (this->_is_resumption_token_sent) { + return frame; + } + + // TODO Make expiration period configurable + QUICResumptionToken token(this->get_remote_endpoint(), this->connection_id(), Thread::get_hrtime() + HRTIME_HOURS(24)); + frame = QUICFrameFactory::create_new_token_frame(token, this->_issue_frame_id(), this); + if (frame) { + if (frame->size() < maximum_frame_size) { + this->_is_resumption_token_sent = true; + } else { + // Cancel generating frame + frame = QUICFrameFactory::create_null_frame(); + } + } + + return frame; +} + +void +QUICNetVConnection::_on_frame_lost(QUICFrameInformation info) +{ + this->_is_resumption_token_sent = false; +} diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 492bf5eb838..7fc32369c39 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -90,6 +90,8 @@ QUICDebugNames::frame_type(QUICFrameType type) return "CRYPTO"; case QUICFrameType::RETIRE_CONNECTION_ID: return "RETIRE_CONNECTION_ID"; + case QUICFrameType::NEW_TOKEN: + return "NEW_TOKEN"; case QUICFrameType::UNKNOWN: default: return "UNKNOWN"; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index e4f5f2e92b7..183f7a90734 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2439,10 +2439,8 @@ QUICPathResponseFrame::_data_offset() const QUICFrameUPtr QUICNewTokenFrame::clone() const { - ats_unique_buf buf = ats_unique_malloc(this->token_length()); - memcpy(buf.get(), this->token(), this->token_length()); - - return QUICFrameFactory::create_new_token_frame(std::move(buf), this->token_length(), this->_id, this->_owner); + // clone() will be removed when all frame generators are responsible for retransmittion + return QUICFrameFactory::create_null_frame(); } QUICFrameType @@ -2987,10 +2985,14 @@ QUICFrameFactory::create_new_connection_id_frame(uint32_t sequence, QUICConnecti } std::unique_ptr -QUICFrameFactory::create_new_token_frame(ats_unique_buf token, uint64_t token_len, QUICFrameId id, QUICFrameGenerator *owner) +QUICFrameFactory::create_new_token_frame(const QUICResumptionToken &token, QUICFrameId id, QUICFrameGenerator *owner) { + uint64_t token_len = token.length(); + ats_unique_buf token_buf = ats_unique_malloc(token_len); + memcpy(token_buf.get(), token.buf(), token_len); + QUICNewTokenFrame *frame = quicNewTokenFrameAllocator.alloc(); - new (frame) QUICNewTokenFrame(std::move(token), token_len, id, owner); + new (frame) QUICNewTokenFrame(std::move(token_buf), token_len, id, owner); return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_token_frame); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 0c52e863dbd..e33c8c481b5 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -1118,7 +1118,7 @@ class QUICFrameFactory /* * Creates a NEW_TOKEN frame */ - static std::unique_ptr create_new_token_frame(ats_unique_buf token, uint64_t token_len, + static std::unique_ptr create_new_token_frame(const QUICResumptionToken &token, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 1673752196b..e332793f321 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -50,6 +50,7 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) case QUICFrameType::STREAM_BLOCKED: case QUICFrameType::MAX_DATA: case QUICFrameType::MAX_STREAM_DATA: + case QUICFrameType::NEW_TOKEN: break; default: frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); From a1467183ccfa2107ed41a4ebd33bfce36a6b6df2 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 10 Dec 2018 17:16:06 +0900 Subject: [PATCH 0959/1313] Fix a file path in Makefile.am --- src/tscore/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tscore/Makefile.am b/src/tscore/Makefile.am index f6acca19a0c..e4929c951f5 100644 --- a/src/tscore/Makefile.am +++ b/src/tscore/Makefile.am @@ -276,7 +276,7 @@ test_tscore_SOURCES = \ if HAS_HKDF test_tscore_SOURCES += \ - unit-tests/test_HKDF.cc + unit_tests/test_HKDF.cc endif CompileParseRules_SOURCES = CompileParseRules.cc From 8f4c036a53c27743bb5aca569409199359f90874 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Dec 2018 09:55:17 +0900 Subject: [PATCH 0960/1313] Fix include line in test_HKDF --- src/tscore/unit_tests/test_HKDF.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tscore/unit_tests/test_HKDF.cc b/src/tscore/unit_tests/test_HKDF.cc index 1c4ab5ce30c..59d2a3540c3 100644 --- a/src/tscore/unit_tests/test_HKDF.cc +++ b/src/tscore/unit_tests/test_HKDF.cc @@ -23,7 +23,7 @@ #include "catch.hpp" #include -#include "ts/HKDF.h" +#include "tscore/HKDF.h" TEST_CASE("HKDF tests", "[hkdf]") { From eb122f585843f655230f513ffe2a267ecb9ceecb Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Dec 2018 10:15:37 +0900 Subject: [PATCH 0961/1313] Add link openssl for test_tscore --- src/tscore/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tscore/Makefile.am b/src/tscore/Makefile.am index e4929c951f5..6722a4cfdd6 100644 --- a/src/tscore/Makefile.am +++ b/src/tscore/Makefile.am @@ -249,7 +249,7 @@ test_tscore_CPPFLAGS = $(AM_CPPFLAGS)\ -I$(abs_top_srcdir)/tests/include test_tscore_CXXFLAGS = -Wno-array-bounds $(AM_CXXFLAGS) -test_tscore_LDADD = libtscore.la $(top_builddir)/src/tscpp/util/libtscpputil.la $(top_builddir)/iocore/eventsystem/libinkevent.a +test_tscore_LDADD = libtscore.la $(top_builddir)/src/tscpp/util/libtscpputil.la $(top_builddir)/iocore/eventsystem/libinkevent.a @OPENSSL_LIBS@ test_tscore_SOURCES = \ unit_tests/unit_test_main.cc \ unit_tests/test_AcidPtr.cc \ From 2197e2935c2ced586f6e7eef144903e0b3337683 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Dec 2018 11:47:52 +0900 Subject: [PATCH 0962/1313] Add Pinger --- iocore/net/P_QUICNetVConnection.h | 2 ++ iocore/net/QUICNetVConnection.cc | 21 ++++++++++++--------- iocore/net/quic/Makefile.am | 1 + 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e1e14ff21d8..994bed9ea54 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -51,6 +51,7 @@ #include "quic/QUICStream.h" #include "quic/QUICHandshakeProtocol.h" #include "quic/QUICAckFrameCreator.h" +#include "quic/QUICPinger.h" #include "quic/QUICPacketRetransmitter.h" #include "quic/QUICLossDetector.h" #include "quic/QUICStreamManager.h" @@ -249,6 +250,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; QUICAckFrameManager _ack_frame_manager; + QUICPinger _pinger; QUICPacketRetransmitter _packet_retransmitter; QUICPacketNumberProtector _pn_protector; QUICRTTMeasure _rtt_measure; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 370ea77a501..1c216af465f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1423,15 +1423,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa if (this->_has_ack_only_packet_out) { // Sent too much ack_only packet. At this moment we need to packetize a ping frame // to force peer send ack frame. - if (max_frame_size > len) { - this->_has_ack_only_packet_out = false; - // don't care ping frame lost or acked - frame = QUICFrameFactory::create_ping_frame(0, nullptr); - ++frame_count; - ack_only = false; - probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, frame, frames); - } + // Just call trigger to not send multiple PING frames, because application could request sending PING. + this->_pinger.trigger(level); } else { this->_has_ack_only_packet_out = true; } @@ -1439,6 +1432,16 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa this->_has_ack_only_packet_out = false; } + // PING + frame = this->_pinger.generate_frame(level, UINT16_MAX, max_frame_size); + if (frame) { + ++frame_count; + ack_only = false; + this->_has_ack_only_packet_out = false; + probing |= frame->is_probing_frame(); + this->_store_frame(buf, len, max_frame_size, frame, frames); + } + // Schedule a packet if (len != 0) { if (level == QUICEncryptionLevel::INITIAL && this->netvc_context == NET_VCONNECTION_OUT) { diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 8fcc90b594a..1520407312e 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -78,6 +78,7 @@ libquic_a_SOURCES = \ QUICPacketReceiveQueue.cc \ QUICPacketRetransmitter.cc \ QUICPathValidator.cc \ + QUICPinger.cc \ QUICFrameGenerator.cc # From c2b548104980d619fd90c5b5b186a5ed55ed1c94 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Dec 2018 11:54:40 +0900 Subject: [PATCH 0963/1313] Provide an inteface for sending PING --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 6 ++++++ iocore/net/quic/Mock.h | 5 +++++ iocore/net/quic/QUICConnection.h | 1 + 4 files changed, 13 insertions(+) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 994bed9ea54..df5ebe692b9 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -195,6 +195,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICStreamManager *stream_manager() override; void close(QUICConnectionErrorUPtr error) override; void handle_received_packet(UDPPacket *packet) override; + void ping() override; // QUICConnection (QUICConnectionInfoProvider) QUICConnectionId peer_connection_id() const override; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 1c216af465f..e81ec96040c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -483,6 +483,12 @@ QUICNetVConnection::handle_received_packet(UDPPacket *packet) this->_packet_recv_queue.enqueue(packet); } +void +QUICNetVConnection::ping() +{ + this->_pinger.trigger(QUICEncryptionLevel::ONE_RTT); +} + void QUICNetVConnection::close(QUICConnectionErrorUPtr error) { diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index ac201a87ce0..c60ef68742a 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -276,6 +276,11 @@ class MockQUICConnection : public QUICConnection { } + void + ping() override + { + } + int _transmit_count = 0; int _retransmit_count = 0; Ptr _mutex; diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index aa67aec7f69..e2e49da8744 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -71,4 +71,5 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler, pu virtual QUICStreamManager *stream_manager() = 0; virtual void close(QUICConnectionErrorUPtr error) = 0; virtual void handle_received_packet(UDPPacket *packeet) = 0; + virtual void ping() = 0; }; From 98f0ca4c627852ad02d3d7213e468ae5d0e89cad Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Dec 2018 11:58:54 +0900 Subject: [PATCH 0964/1313] Don't retransmit PING frame --- iocore/net/quic/QUICPacketRetransmitter.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index e332793f321..6c1adad6bf9 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -51,6 +51,7 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) case QUICFrameType::MAX_DATA: case QUICFrameType::MAX_STREAM_DATA: case QUICFrameType::NEW_TOKEN: + case QUICFrameType::PING: break; default: frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); From cea7468245fd0a10fd03f0c8e1b38cac1704c66b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Dec 2018 14:31:57 +0900 Subject: [PATCH 0965/1313] Add QUICStream::stop_sending() --- iocore/net/quic/QUICPacketRetransmitter.cc | 1 + iocore/net/quic/QUICStream.cc | 18 +++++++++++++ iocore/net/quic/QUICStream.h | 8 ++++-- iocore/net/quic/test/test_QUICStream.cc | 30 ++++++++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 6c1adad6bf9..abb6741d4c0 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -52,6 +52,7 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) case QUICFrameType::MAX_STREAM_DATA: case QUICFrameType::NEW_TOKEN: case QUICFrameType::PING: + case QUICFrameType::STOP_SENDING: break; default: frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 3f2ecd79593..4a4da9b45a1 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -419,6 +419,16 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit return frame; } + // STOP_SENDING + if (this->_stop_sending_reason && !this->_is_stop_sending_sent) { + frame = + QUICFrameFactory::create_stop_sending_frame(this->id(), this->_stop_sending_reason->code, this->_issue_frame_id(), this); + this->_records_frame(frame->id(), {frame->type(), level}); + this->_state.update_with_sending_frame(*frame); + this->_is_stop_sending_sent = true; + return frame; + } + // MAX_STREAM_DATA frame = this->_local_flow_controller.generate_frame(level, UINT16_MAX, maximum_frame_size); if (frame) { @@ -532,6 +542,8 @@ QUICStream::_on_frame_lost(QUICFrameInformation info) // "Data Recvd" state is reached on the send stream). The content of // a RST_STREAM frame MUST NOT change when it is sent again. this->_is_reset_sent = false; + } else if (info.type == QUICFrameType::STOP_SENDING) { + this->_is_stop_sending_sent = false; } } @@ -649,6 +661,12 @@ QUICStream::_process_write_vio() return 0; } +void +QUICStream::stop_sending(QUICStreamErrorUPtr error) +{ + this->_stop_sending_reason = std::move(error); +} + void QUICStream::reset(QUICStreamErrorUPtr error) { diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 1fc7e94d50d..fb6a64c95f6 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -79,6 +79,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame); QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame); + void stop_sending(QUICStreamErrorUPtr error); void reset(QUICStreamErrorUPtr error); QUICOffset reordered_bytes() const; @@ -107,8 +108,10 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra void _write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin); - QUICStreamErrorUPtr _reset_reason = nullptr; - bool _is_reset_sent = false; + QUICStreamErrorUPtr _reset_reason = nullptr; + bool _is_reset_sent = false; + QUICStreamErrorUPtr _stop_sending_reason = nullptr; + bool _is_stop_sending_sent = false; QUICConnectionInfoProvider *_connection_info = nullptr; QUICStreamId _id = 0; @@ -168,6 +171,7 @@ class QUICCryptoStream : public QUICFrameGenerator int64_t read(uint8_t *buf, int64_t len); int64_t write(const uint8_t *buf, int64_t len); + void stop_sending(QUICStreamErrorUPtr error); void reset(QUICStreamErrorUPtr error); QUICOffset largest_offset_received(); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index b838e8911c7..40ad5638005 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -351,4 +351,34 @@ TEST_CASE("QUICStream", "[quic]") REQUIRE(frame); CHECK(frame->type() == QUICFrameType::RST_STREAM); } + + SECTION("Retransmit STOP_SENDING frame") + { + MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); + IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); + + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); + SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); + + MockContinuation mock_cont(stream->mutex); + stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); + + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + + stream->stop_sending(QUICStreamErrorUPtr(new QUICStreamError(stream.get(), QUIC_APP_ERROR_CODE_STOPPING))); + frame = stream->generate_frame(level, 4096, 4096); + REQUIRE(frame); + CHECK(frame->type() == QUICFrameType::STOP_SENDING); + // Don't send it again untill it is considers as lost + CHECK(stream->generate_frame(level, 4096, 4096) == nullptr); + // Loss the frame + stream->on_frame_lost(frame->id()); + // After the loss the frame should be regenerated + frame = stream->generate_frame(level, 4096, 4096); + REQUIRE(frame); + CHECK(frame->type() == QUICFrameType::STOP_SENDING); + } } From c149a0f5985bb59fded4c4874c4f06cc5852e7e9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Dec 2018 16:01:00 +0900 Subject: [PATCH 0966/1313] Pass connection error as a reference to keep it in QNetVC like QUICStream does --- iocore/net/QUICNetVConnection.cc | 8 +++++--- iocore/net/quic/QUICFrame.cc | 21 ++++++++++----------- iocore/net/quic/QUICFrame.h | 4 ++-- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e81ec96040c..96e1a0cf744 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1478,15 +1478,17 @@ QUICNetVConnection::_packetize_closing_frame() SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); - if (this->_connection_error == nullptr) { + if (this->_connection_error == nullptr || this->_the_final_packet) { return; } QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + + // CONNECTION_CLOSE or APPLICATION_CLOSE if (this->_connection_error->cls == QUICErrorClass::APPLICATION) { - frame = QUICFrameFactory::create_application_close_frame(std::move(this->_connection_error)); + frame = QUICFrameFactory::create_application_close_frame(*this->_connection_error); } else { - frame = QUICFrameFactory::create_connection_close_frame(std::move(this->_connection_error)); + frame = QUICFrameFactory::create_connection_close_frame(*this->_connection_error); } uint32_t max_size = this->maximum_quic_packet_size(); diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 183f7a90734..6e391533b85 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2840,14 +2840,13 @@ QUICFrameFactory::create_connection_close_frame(uint16_t error_code, QUICFrameTy } std::unique_ptr -QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error, QUICFrameId id, QUICFrameGenerator *owner) +QUICFrameFactory::create_connection_close_frame(QUICConnectionError &error, QUICFrameId id, QUICFrameGenerator *owner) { - ink_assert(error->cls == QUICErrorClass::TRANSPORT); - if (error->msg) { - return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type(), strlen(error->msg), error->msg, id, - owner); + ink_assert(error.cls == QUICErrorClass::TRANSPORT); + if (error.msg) { + return QUICFrameFactory::create_connection_close_frame(error.code, error.frame_type(), strlen(error.msg), error.msg, id, owner); } else { - return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type(), 0, nullptr, id, owner); + return QUICFrameFactory::create_connection_close_frame(error.code, error.frame_type(), 0, nullptr, id, owner); } } @@ -2861,13 +2860,13 @@ QUICFrameFactory::create_application_close_frame(QUICAppErrorCode error_code, ui } std::unique_ptr -QUICFrameFactory::create_application_close_frame(QUICConnectionErrorUPtr error, QUICFrameId id, QUICFrameGenerator *owner) +QUICFrameFactory::create_application_close_frame(QUICConnectionError &error, QUICFrameId id, QUICFrameGenerator *owner) { - ink_assert(error->cls == QUICErrorClass::APPLICATION); - if (error->msg) { - return QUICFrameFactory::create_application_close_frame(error->code, strlen(error->msg), error->msg, id, owner); + ink_assert(error.cls == QUICErrorClass::APPLICATION); + if (error.msg) { + return QUICFrameFactory::create_application_close_frame(error.code, strlen(error.msg), error.msg, id, owner); } else { - return QUICFrameFactory::create_application_close_frame(error->code, 0, nullptr, id, owner); + return QUICFrameFactory::create_application_close_frame(error.code, 0, nullptr, id, owner); } } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index e33c8c481b5..81a0bb7c132 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -1024,7 +1024,7 @@ class QUICFrameFactory QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); static std::unique_ptr create_connection_close_frame( - QUICConnectionErrorUPtr error, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + QUICConnectionError &error, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a APPLICATION_CLOSE frame. @@ -1033,7 +1033,7 @@ class QUICFrameFactory QUICAppErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); static std::unique_ptr create_application_close_frame( - QUICConnectionErrorUPtr error, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + QUICConnectionError &error, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a MAX_DATA frame. From 61a729bc97496a13560eb70d7a1b70d2f3837231 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 11 Dec 2018 16:12:44 +0900 Subject: [PATCH 0967/1313] Don't retransmit CONNECTION_CLOSE and APPLICATION_CLOSE with QUICPacketRetransmitter --- iocore/net/quic/QUICPacketRetransmitter.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index abb6741d4c0..8b8e40ab312 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -53,6 +53,8 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) case QUICFrameType::NEW_TOKEN: case QUICFrameType::PING: case QUICFrameType::STOP_SENDING: + case QUICFrameType::CONNECTION_CLOSE: + case QUICFrameType::APPLICATION_CLOSE: break; default: frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); From c2af0e5f7870a9bb91b9c8c24a2387015f08fa97 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 13 Dec 2018 13:30:34 +0900 Subject: [PATCH 0968/1313] Revert "Add Pinger" This reverts commit 2197e2935c2ced586f6e7eef144903e0b3337683. --- iocore/net/P_QUICNetVConnection.h | 2 -- iocore/net/QUICNetVConnection.cc | 21 +++++++++------------ iocore/net/quic/Makefile.am | 1 - 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index df5ebe692b9..461de06787e 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -51,7 +51,6 @@ #include "quic/QUICStream.h" #include "quic/QUICHandshakeProtocol.h" #include "quic/QUICAckFrameCreator.h" -#include "quic/QUICPinger.h" #include "quic/QUICPacketRetransmitter.h" #include "quic/QUICLossDetector.h" #include "quic/QUICStreamManager.h" @@ -251,7 +250,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; QUICAckFrameManager _ack_frame_manager; - QUICPinger _pinger; QUICPacketRetransmitter _packet_retransmitter; QUICPacketNumberProtector _pn_protector; QUICRTTMeasure _rtt_measure; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 96e1a0cf744..ba8a2ad9059 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1429,8 +1429,15 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa if (this->_has_ack_only_packet_out) { // Sent too much ack_only packet. At this moment we need to packetize a ping frame // to force peer send ack frame. - // Just call trigger to not send multiple PING frames, because application could request sending PING. - this->_pinger.trigger(level); + if (max_frame_size > len) { + this->_has_ack_only_packet_out = false; + // don't care ping frame lost or acked + frame = QUICFrameFactory::create_ping_frame(0, nullptr); + ++frame_count; + ack_only = false; + probing |= frame->is_probing_frame(); + this->_store_frame(buf, len, max_frame_size, frame, frames); + } } else { this->_has_ack_only_packet_out = true; } @@ -1438,16 +1445,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa this->_has_ack_only_packet_out = false; } - // PING - frame = this->_pinger.generate_frame(level, UINT16_MAX, max_frame_size); - if (frame) { - ++frame_count; - ack_only = false; - this->_has_ack_only_packet_out = false; - probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, frame, frames); - } - // Schedule a packet if (len != 0) { if (level == QUICEncryptionLevel::INITIAL && this->netvc_context == NET_VCONNECTION_OUT) { diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 1520407312e..8fcc90b594a 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -78,7 +78,6 @@ libquic_a_SOURCES = \ QUICPacketReceiveQueue.cc \ QUICPacketRetransmitter.cc \ QUICPathValidator.cc \ - QUICPinger.cc \ QUICFrameGenerator.cc # From 4532046d7fe1a5e811682220dc6ab69667efa572 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 13 Dec 2018 13:30:37 +0900 Subject: [PATCH 0969/1313] Revert "Provide an inteface for sending PING" This reverts commit c2b548104980d619fd90c5b5b186a5ed55ed1c94. --- iocore/net/P_QUICNetVConnection.h | 1 - iocore/net/QUICNetVConnection.cc | 6 ------ iocore/net/quic/Mock.h | 5 ----- iocore/net/quic/QUICConnection.h | 1 - 4 files changed, 13 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 461de06787e..e1e14ff21d8 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -194,7 +194,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICStreamManager *stream_manager() override; void close(QUICConnectionErrorUPtr error) override; void handle_received_packet(UDPPacket *packet) override; - void ping() override; // QUICConnection (QUICConnectionInfoProvider) QUICConnectionId peer_connection_id() const override; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ba8a2ad9059..81dadffa396 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -483,12 +483,6 @@ QUICNetVConnection::handle_received_packet(UDPPacket *packet) this->_packet_recv_queue.enqueue(packet); } -void -QUICNetVConnection::ping() -{ - this->_pinger.trigger(QUICEncryptionLevel::ONE_RTT); -} - void QUICNetVConnection::close(QUICConnectionErrorUPtr error) { diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index c60ef68742a..ac201a87ce0 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -276,11 +276,6 @@ class MockQUICConnection : public QUICConnection { } - void - ping() override - { - } - int _transmit_count = 0; int _retransmit_count = 0; Ptr _mutex; diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index e2e49da8744..aa67aec7f69 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -71,5 +71,4 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler, pu virtual QUICStreamManager *stream_manager() = 0; virtual void close(QUICConnectionErrorUPtr error) = 0; virtual void handle_received_packet(UDPPacket *packeet) = 0; - virtual void ping() = 0; }; From 6c433f5e6336eed64024b22bf5e93d901910127e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 13 Dec 2018 14:22:20 +0900 Subject: [PATCH 0970/1313] Fix unit tests --- iocore/net/quic/test/test_QUICFrame.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 003aa241f4f..ea4b17e2a68 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1340,14 +1340,14 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", std::unique_ptr error = std::unique_ptr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); std::unique_ptr connection_close_frame1 = - QUICFrameFactory::create_connection_close_frame(std::move(error)); + QUICFrameFactory::create_connection_close_frame(*error); CHECK(connection_close_frame1->error_code() == static_cast(QUICTransErrorCode::INTERNAL_ERROR)); CHECK(connection_close_frame1->reason_phrase_length() == 0); CHECK(connection_close_frame1->reason_phrase() == nullptr); error = std::unique_ptr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR, "test")); std::unique_ptr connection_close_frame2 = - QUICFrameFactory::create_connection_close_frame(std::move(error)); + QUICFrameFactory::create_connection_close_frame(*error); CHECK(connection_close_frame2->error_code() == static_cast(QUICTransErrorCode::INTERNAL_ERROR)); CHECK(connection_close_frame2->reason_phrase_length() == 4); CHECK(memcmp(connection_close_frame2->reason_phrase(), "test", 4) == 0); From 272d9513550eb1e4f10ad77456783916e21e6538 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 14 Dec 2018 15:23:39 +0900 Subject: [PATCH 0971/1313] Fix debug log to print error code in hex --- iocore/net/QUICNetVConnection.cc | 6 +++--- iocore/net/quic/QUICFrame.cc | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 81dadffa396..81d31195936 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -694,7 +694,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data) } if (error != nullptr) { - QUICConDebug("QUICError: cls=%u, code=0x%" PRIu16, static_cast(error->cls), error->code); + QUICConDebug("QUICError: cls=%u, code=0x%" PRIx16, static_cast(error->cls), error->code); this->_handle_error(std::move(error)); } @@ -1627,10 +1627,10 @@ void QUICNetVConnection::_handle_error(QUICConnectionErrorUPtr error) { if (error->cls == QUICErrorClass::APPLICATION) { - QUICError("QUICError: %s (%u), APPLICATION ERROR (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls), + QUICError("QUICError: %s (%u), APPLICATION ERROR (0x%" PRIx16 ")", QUICDebugNames::error_class(error->cls), static_cast(error->cls), error->code); } else { - QUICError("QUICError: %s (%u), %s (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls), + QUICError("QUICError: %s (%u), %s (0x%" PRIx16 ")", QUICDebugNames::error_class(error->cls), static_cast(error->cls), QUICDebugNames::error_code(error->code), error->code); } diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 6e391533b85..b705a092ed9 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1378,8 +1378,8 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const int QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const { - int len = snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=%s frame=%s", this->size(), - QUICDebugNames::error_code(this->error_code()), QUICDebugNames::frame_type(this->frame_type())); + int len = snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=%s (0x%" PRIx16 ") frame=%s", this->size(), + QUICDebugNames::error_code(this->error_code()), this->error_code() , QUICDebugNames::frame_type(this->frame_type())); if (this->reason_phrase_length() != 0 && this->reason_phrase() != nullptr) { memcpy(msg + len, " reason=", 8); From 84cb675fe8db5527ff9fee8f214891136e3957ac Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 14 Dec 2018 15:30:21 +0900 Subject: [PATCH 0972/1313] Check TLS version only if content type is HANDSHAKE on msg_cb For "Unsupported TLS version" scenario of QUICTracker --- iocore/net/quic/QUICTLS_openssl.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 92131bd08cb..af841900a15 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -101,7 +101,7 @@ msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, return; } - if (!write_p || !arg || version != TLS1_3_VERSION || (content_type != SSL3_RT_HANDSHAKE && content_type != SSL3_RT_ALERT)) { + if (!write_p || !arg || (content_type != SSL3_RT_HANDSHAKE && content_type != SSL3_RT_ALERT)) { return; } @@ -113,6 +113,10 @@ msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, const uint8_t *msg_buf = reinterpret_cast(buf); if (content_type == SSL3_RT_HANDSHAKE) { + if (version != TLS1_3_VERSION) { + return; + } + int msg_type = msg_buf[0]; QUICEncryptionLevel level = QUICTLS::get_encryption_level(msg_type); From 1041f95901afaf1f57bdc996da8a3ba064f212b5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 18 Dec 2018 11:30:47 +0900 Subject: [PATCH 0973/1313] Add Pinger back with its source files --- iocore/net/P_QUICNetVConnection.h | 3 ++ iocore/net/QUICNetVConnection.cc | 27 ++++++++++----- iocore/net/quic/Makefile.am | 1 + iocore/net/quic/Mock.h | 5 +++ iocore/net/quic/QUICConnection.h | 1 + iocore/net/quic/QUICPinger.cc | 56 ++++++++++++++++++++++++++++++ iocore/net/quic/QUICPinger.h | 57 +++++++++++++++++++++++++++++++ 7 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 iocore/net/quic/QUICPinger.cc create mode 100644 iocore/net/quic/QUICPinger.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e1e14ff21d8..df5ebe692b9 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -51,6 +51,7 @@ #include "quic/QUICStream.h" #include "quic/QUICHandshakeProtocol.h" #include "quic/QUICAckFrameCreator.h" +#include "quic/QUICPinger.h" #include "quic/QUICPacketRetransmitter.h" #include "quic/QUICLossDetector.h" #include "quic/QUICStreamManager.h" @@ -194,6 +195,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICStreamManager *stream_manager() override; void close(QUICConnectionErrorUPtr error) override; void handle_received_packet(UDPPacket *packet) override; + void ping() override; // QUICConnection (QUICConnectionInfoProvider) QUICConnectionId peer_connection_id() const override; @@ -249,6 +251,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; QUICAckFrameManager _ack_frame_manager; + QUICPinger _pinger; QUICPacketRetransmitter _packet_retransmitter; QUICPacketNumberProtector _pn_protector; QUICRTTMeasure _rtt_measure; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 81d31195936..76985deda3d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -483,6 +483,12 @@ QUICNetVConnection::handle_received_packet(UDPPacket *packet) this->_packet_recv_queue.enqueue(packet); } +void +QUICNetVConnection::ping() +{ + this->_pinger.trigger(QUICEncryptionLevel::ONE_RTT); +} + void QUICNetVConnection::close(QUICConnectionErrorUPtr error) { @@ -1423,15 +1429,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa if (this->_has_ack_only_packet_out) { // Sent too much ack_only packet. At this moment we need to packetize a ping frame // to force peer send ack frame. - if (max_frame_size > len) { - this->_has_ack_only_packet_out = false; - // don't care ping frame lost or acked - frame = QUICFrameFactory::create_ping_frame(0, nullptr); - ++frame_count; - ack_only = false; - probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, frame, frames); - } + // Just call trigger to not send multiple PING frames, because application could request sending PING. + this->_pinger.trigger(level); } else { this->_has_ack_only_packet_out = true; } @@ -1439,6 +1438,16 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa this->_has_ack_only_packet_out = false; } + // PING + frame = this->_pinger.generate_frame(level, UINT16_MAX, max_frame_size); + if (frame) { + ++frame_count; + ack_only = false; + this->_has_ack_only_packet_out = false; + probing |= frame->is_probing_frame(); + this->_store_frame(buf, len, max_frame_size, frame, frames); + } + // Schedule a packet if (len != 0) { if (level == QUICEncryptionLevel::INITIAL && this->netvc_context == NET_VCONNECTION_OUT) { diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 8fcc90b594a..1520407312e 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -78,6 +78,7 @@ libquic_a_SOURCES = \ QUICPacketReceiveQueue.cc \ QUICPacketRetransmitter.cc \ QUICPathValidator.cc \ + QUICPinger.cc \ QUICFrameGenerator.cc # diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index ac201a87ce0..c60ef68742a 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -276,6 +276,11 @@ class MockQUICConnection : public QUICConnection { } + void + ping() override + { + } + int _transmit_count = 0; int _retransmit_count = 0; Ptr _mutex; diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index aa67aec7f69..e2e49da8744 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -71,4 +71,5 @@ class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler, pu virtual QUICStreamManager *stream_manager() = 0; virtual void close(QUICConnectionErrorUPtr error) = 0; virtual void handle_received_packet(UDPPacket *packeet) = 0; + virtual void ping() = 0; }; diff --git a/iocore/net/quic/QUICPinger.cc b/iocore/net/quic/QUICPinger.cc new file mode 100644 index 00000000000..1249f1fbee7 --- /dev/null +++ b/iocore/net/quic/QUICPinger.cc @@ -0,0 +1,56 @@ +/** @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 "QUICPinger.h" + +void +QUICPinger::trigger(QUICEncryptionLevel level) +{ + this->_need_to_fire[QUICTypeUtil::pn_space_index(level)] = true; +} + +bool +QUICPinger::will_generate_frame(QUICEncryptionLevel level) +{ + return this->_need_to_fire[QUICTypeUtil::pn_space_index(level)]; +} + +QUICFrameUPtr +QUICPinger::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +{ + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + + if (!this->_is_level_matched(level)) { + return frame; + } + + int index = QUICTypeUtil::pn_space_index(level); + + if (this->_need_to_fire[index] && maximum_frame_size > 0) { + // don't care ping frame lost or acked + frame = QUICFrameFactory::create_ping_frame(0, nullptr); + this->_need_to_fire[index] = false; + } + + return frame; +} diff --git a/iocore/net/quic/QUICPinger.h b/iocore/net/quic/QUICPinger.h new file mode 100644 index 00000000000..547c3d23ac0 --- /dev/null +++ b/iocore/net/quic/QUICPinger.h @@ -0,0 +1,57 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include "QUICTypes.h" +#include "QUICFrameHandler.h" +#include "QUICFrameGenerator.h" + +class QUICPinger : public QUICFrameGenerator +{ +public: + QUICPinger() {} + + void trigger(QUICEncryptionLevel level); + + // QUICFrameGenerator + bool will_generate_frame(QUICEncryptionLevel level) override; + QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + +private: + // Initial, 0/1-RTT, and Handshake + bool _need_to_fire[3] = {false}; + + // QUICFrameGenerator + std::vector + _encryption_level_filter() override + { + return { + QUICEncryptionLevel::INITIAL, + QUICEncryptionLevel::ZERO_RTT, + QUICEncryptionLevel::HANDSHAKE, + QUICEncryptionLevel::ONE_RTT, + }; + } +}; From 205345828a78638f30488829f36f93bc348e42f3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 18 Dec 2018 12:00:37 +0900 Subject: [PATCH 0974/1313] clang-format --- iocore/net/quic/QUICFrame.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index b705a092ed9..26fed5bf89b 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1378,8 +1378,9 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const int QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const { - int len = snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=%s (0x%" PRIx16 ") frame=%s", this->size(), - QUICDebugNames::error_code(this->error_code()), this->error_code() , QUICDebugNames::frame_type(this->frame_type())); + int len = + snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=%s (0x%" PRIx16 ") frame=%s", this->size(), + QUICDebugNames::error_code(this->error_code()), this->error_code(), QUICDebugNames::frame_type(this->frame_type())); if (this->reason_phrase_length() != 0 && this->reason_phrase() != nullptr) { memcpy(msg + len, " reason=", 8); From 0854da0dbb12b125c18f7e5b75fefe2977f024b4 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 18 Dec 2018 11:28:34 +0900 Subject: [PATCH 0975/1313] Fix error of "HTTP GET on stream 2" scenario of QUICTracker QUICStreamManager::_find_or_create_stream() treated stream 0 special for handshake. But it's not required any more, because stream 0 is replaced by crypto stream. --- iocore/net/quic/QUICStreamManager.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index e58120f4738..d34e1c8793f 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -269,7 +269,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) switch (QUICTypeUtil::detect_stream_type(stream_id)) { case QUICStreamType::CLIENT_BIDI: - if (stream_id > this->_local_maximum_stream_id_bidi && this->_local_maximum_stream_id_bidi != 0) { + if (stream_id > this->_local_maximum_stream_id_bidi) { return nullptr; } @@ -285,7 +285,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) break; case QUICStreamType::CLIENT_UNI: - if (stream_id > this->_local_maximum_stream_id_uni && this->_local_maximum_stream_id_uni != 0) { + if (stream_id > this->_local_maximum_stream_id_uni) { return nullptr; } @@ -294,7 +294,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) break; case QUICStreamType::SERVER_BIDI: - if (stream_id > this->_remote_maximum_stream_id_bidi && this->_remote_maximum_stream_id_bidi != 0) { + if (stream_id > this->_remote_maximum_stream_id_bidi) { return nullptr; } @@ -310,7 +310,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) break; case QUICStreamType::SERVER_UNI: - if (stream_id > this->_remote_maximum_stream_id_uni && this->_remote_maximum_stream_id_uni != 0) { + if (stream_id > this->_remote_maximum_stream_id_uni) { return nullptr; } From c97d8c04e0756a91d7c2fb0b530eef7a477dcc9e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 21 Dec 2018 11:45:58 +0900 Subject: [PATCH 0976/1313] Fix unit test of QUICStreamManager Prior this change, the test was broken by 0854da0dbb12b125c18f7e5b75fefe2977f024b4. --- .../net/quic/test/test_QUICStreamManager.cc | 111 ++++++++++++++---- 1 file changed, 85 insertions(+), 26 deletions(-) diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index dcf696d253d..380eeabc229 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -39,42 +39,60 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") MockQUICConnectionInfoProvider cinfo_provider; MockQUICRTTProvider rtt_provider; QUICStreamManager sm(&cinfo_provider, &rtt_provider, &app_map); + + uint8_t local_tp_buf[] = { + 0x00, 0x00, 0x00, 0x00, // initial version + 0x00, // size of supported versions + 0x00, 0x06, // size of parameters + 0x00, 0x02, // parameter id - initial_max_bidi_streams + 0x00, 0x02, // length of value + 0x00, 0x10 // value + }; std::shared_ptr local_tp = - std::make_shared(static_cast(0)); + std::make_shared(local_tp_buf, sizeof(local_tp_buf)); + + uint8_t remote_tp_buf[] = { + 0x00, 0x00, 0x00, 0x00, // initial version + 0x00, 0x06, // size of parameters + 0x00, 0x02, // parameter id - initial_max_bidi_streams + 0x00, 0x02, // length of value + 0x00, 0x10 // value + }; std::shared_ptr remote_tp = - std::make_shared(static_cast(0)); + std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); + sm.init_flow_control_params(local_tp, remote_tp); // STREAM frames create new streams std::shared_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 0); - std::shared_ptr stream_frame_1 = - QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 1, 0); + std::shared_ptr stream_frame_4 = + QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 4, 0); CHECK(sm.stream_count() == 0); sm.handle_frame(level, *stream_frame_0); CHECK(sm.stream_count() == 1); - sm.handle_frame(level, *stream_frame_1); + sm.handle_frame(level, *stream_frame_4); CHECK(sm.stream_count() == 2); // RST_STREAM frames create new streams std::shared_ptr rst_stream_frame = - QUICFrameFactory::create_rst_stream_frame(2, static_cast(0x01), 0); + QUICFrameFactory::create_rst_stream_frame(8, static_cast(0x01), 0); sm.handle_frame(level, *rst_stream_frame); CHECK(sm.stream_count() == 3); // MAX_STREAM_DATA frames create new streams - std::shared_ptr max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(3, 0); + std::shared_ptr max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(0x0c, 0); sm.handle_frame(level, *max_stream_data_frame); CHECK(sm.stream_count() == 4); // STREAM_BLOCKED frames create new streams - std::shared_ptr stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(4, 0); + std::shared_ptr stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0x10, 0); sm.handle_frame(level, *stream_blocked_frame); CHECK(sm.stream_count() == 5); // Set local maximum stream id - sm.set_max_stream_id(5); - std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_blocked_frame(8, 0); + sm.set_max_stream_id(0x14); + std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_blocked_frame(0x18, 0); sm.handle_frame(level, *stream_blocked_frame_x); CHECK(sm.stream_count() == 5); } @@ -111,24 +129,47 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") MockQUICApplication mock_app(&connection); app_map.set_default(&mock_app); QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); + + uint8_t local_tp_buf[] = { + 0x00, 0x00, 0x00, 0x00, // initial version + 0x00, // size of supported versions + 0x00, 0x0c, // size of parameters + 0x00, 0x02, // parameter id - initial_max_bidi_streams + 0x00, 0x02, // length of value + 0x00, 0x10, // value + 0x00, 0x00, // parameter id - initial_max_stream_data_bidi_local + 0x00, 0x02, // length of value + 0xff, 0xff, // value + }; std::shared_ptr local_tp = - std::make_shared(static_cast(0)); - local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, UINT32_C(4096)); + std::make_shared(local_tp_buf, sizeof(local_tp_buf)); + + uint8_t remote_tp_buf[] = { + 0x00, 0x00, 0x00, 0x00, // initial version + 0x00, 0x06, // size of parameters + 0x00, 0x02, // parameter id - initial_max_bidi_streams + 0x00, 0x02, // length of value + 0x00, 0x10, // value + 0x00, 0x0a, // parameter id - initial_max_stream_data_bidi_remote + 0x00, 0x02, // length of value + 0xff, 0xff, // value + }; std::shared_ptr remote_tp = - std::make_shared(static_cast(0)); + std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); + sm.init_flow_control_params(local_tp, remote_tp); uint8_t data[1024] = {0}; // Create a stream with STREAM_BLOCKED (== noop) std::shared_ptr stream_blocked_frame_0 = QUICFrameFactory::create_stream_blocked_frame(0, 0); - std::shared_ptr stream_blocked_frame_1 = QUICFrameFactory::create_stream_blocked_frame(1, 0); + std::shared_ptr stream_blocked_frame_1 = QUICFrameFactory::create_stream_blocked_frame(4, 0); sm.handle_frame(level, *stream_blocked_frame_0); sm.handle_frame(level, *stream_blocked_frame_1); CHECK(sm.stream_count() == 2); CHECK(sm.total_offset_received() == 0); // total_offset should be a integer in unit of 1024 octets - std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); + std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 8, 0); sm.handle_frame(level, *stream_frame_1); CHECK(sm.total_offset_received() == 1024); } @@ -141,34 +182,52 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") MockQUICApplication mock_app(&connection); app_map.set_default(&mock_app); QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); + + uint8_t local_tp_buf[] = { + 0x00, 0x00, 0x00, 0x00, // initial version + 0x00, // size of supported versions + 0x00, 0x06, // size of parameters + 0x00, 0x02, // parameter id - initial_max_bidi_streams + 0x00, 0x02, // length of value + 0x00, 0x10 // value + }; std::shared_ptr local_tp = - std::make_shared(static_cast(0)); - local_tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, UINT32_C(4096)); + std::make_shared(local_tp_buf, sizeof(local_tp_buf)); + + uint8_t remote_tp_buf[] = { + 0x00, 0x00, 0x00, 0x00, // initial version + 0x00, 0x06, // size of parameters + 0x00, 0x02, // parameter id - initial_max_bidi_streams + 0x00, 0x02, // length of value + 0x00, 0x10 // value + }; std::shared_ptr remote_tp = - std::make_shared(static_cast(0)); + std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); + sm.init_flow_control_params(local_tp, remote_tp); uint8_t data[1024] = {0}; // Create a stream with STREAM_BLOCKED (== noop) std::shared_ptr stream_frame_0_r = QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 0); - std::shared_ptr stream_frame_1_r = - QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 1, 0); + std::shared_ptr stream_frame_4_r = + QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 4, 0); sm.handle_frame(level, *stream_frame_0_r); - sm.handle_frame(level, *stream_frame_1_r); + sm.handle_frame(level, *stream_frame_4_r); CHECK(sm.stream_count() == 2); CHECK(sm.total_offset_sent() == 0); - // Stream 0 shoud be out of flow control + // total_offset should be a integer in unit of octets QUICFrameUPtr stream_frame_0 = QUICFrameFactory::create_stream_frame(data, 1024, 0, 0); mock_app.send(data, 1024, 0); + sm.add_total_offset_sent(1024); sleep(2); - CHECK(sm.total_offset_sent() == 0); + CHECK(sm.total_offset_sent() == 1024); // total_offset should be a integer in unit of octets - QUICFrameUPtr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); - mock_app.send(data, 1024, 1); + QUICFrameUPtr stream_frame_4 = QUICFrameFactory::create_stream_frame(data, 1024, 4, 0); + mock_app.send(data, 1024, 4); sm.add_total_offset_sent(1024); sleep(2); - CHECK(sm.total_offset_sent() == 1024); + CHECK(sm.total_offset_sent() == 2048); } From d05b37a695525a7d912753a9963b490573c00bc5 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 21 Dec 2018 11:47:47 +0900 Subject: [PATCH 0977/1313] Prohibit create streams when max stream id is zero --- iocore/net/quic/QUICStreamManager.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index d34e1c8793f..c86ded6616c 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -269,7 +269,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) switch (QUICTypeUtil::detect_stream_type(stream_id)) { case QUICStreamType::CLIENT_BIDI: - if (stream_id > this->_local_maximum_stream_id_bidi) { + if (this->_local_maximum_stream_id_bidi == 0 || stream_id > this->_local_maximum_stream_id_bidi) { return nullptr; } @@ -285,7 +285,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) break; case QUICStreamType::CLIENT_UNI: - if (stream_id > this->_local_maximum_stream_id_uni) { + if (this->_local_maximum_stream_id_uni == 0 || stream_id > this->_local_maximum_stream_id_uni) { return nullptr; } @@ -294,7 +294,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) break; case QUICStreamType::SERVER_BIDI: - if (stream_id > this->_remote_maximum_stream_id_bidi) { + if (this->_remote_maximum_stream_id_bidi == 0 || stream_id > this->_remote_maximum_stream_id_bidi) { return nullptr; } @@ -310,7 +310,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) break; case QUICStreamType::SERVER_UNI: - if (stream_id > this->_remote_maximum_stream_id_uni) { + if (this->_remote_maximum_stream_id_uni == 0 || stream_id > this->_remote_maximum_stream_id_uni) { return nullptr; } From 7c1a1b046dac90bd241cd7d8125aece2f567329a Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 21 Dec 2018 17:06:06 +0800 Subject: [PATCH 0978/1313] QUIC: Rework QUICStreamFrame parsing --- iocore/net/quic/QUICFrame.cc | 245 +++++++++++-------------- iocore/net/quic/QUICFrame.h | 20 +- iocore/net/quic/test/test_QUICFrame.cc | 27 ++- 3 files changed, 144 insertions(+), 148 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 26fed5bf89b..cac19420274 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -52,6 +52,26 @@ ClassAllocator quicNewTokenFrameAllocator("quicNewTokenFrameA ClassAllocator quicRetireConnectionIdFrameAllocator("quicRetireConnectionIdFrameAllocator"); ClassAllocator quicRetransmissionFrameAllocator("quicRetransmissionFrameAllocator"); +#define LEFT_SPACE(pos) ((size_t)(buf + len - pos)) + +// the pos will auto move forward . return true if the data vaild +static bool +read_varint(uint8_t *&pos, size_t len, uint64_t &field, size_t &field_len) +{ + if (len < 1) { + return false; + } + + field_len = QUICVariableInt::size(pos); + if (len < field_len) { + return false; + } + + field = QUICIntUtil::read_QUICVariableInt(pos); + pos += field_len; + return true; +} + QUICFrameType QUICFrame::type() const { @@ -109,32 +129,83 @@ QUICFrame::split(size_t size) return nullptr; } +bool +QUICFrame::valid() const +{ + return this->_valid; +} + // // STREAM Frame // QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, - QUICFrameId id, QUICFrameGenerator *owner) - : QUICFrame(id, owner) + bool has_offset_field, bool has_length_field, QUICFrameId id, QUICFrameGenerator *owner) + : QUICFrame(id, owner), + _data(std::move(data)), + _data_len(data_len), + _stream_id(stream_id), + _offset(offset), + _fin(last), + _has_offset_field(has_offset_field), + _has_length_field(has_length_field) { - this->_data = std::move(data); - this->_data_len = data_len; - this->_stream_id = stream_id; - this->_offset = offset; - this->_fin = last; +} + +QUICStreamFrame::QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +{ + ink_assert(len >= 1); + + uint8_t *pos = const_cast(buf); + this->_has_offset_field = (buf[0] & 0x04) != 0; // "O" of "0b00010OLF" + this->_has_length_field = (buf[0] & 0x02) != 0; // "L" of "0b00010OLF" + this->_fin = (buf[0] & 0x01) != 0; // "F" of "0b00010OLF" + pos += 1; + + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_stream_id, field_len)) { + return; + } + + if (this->_has_offset_field && !read_varint(pos, LEFT_SPACE(pos), this->_offset, field_len)) { + return; + } + + if (this->_has_length_field && !read_varint(pos, LEFT_SPACE(pos), this->_data_len, field_len)) { + return; + } + + if (!this->_has_length_field) { + this->_data_len = LEFT_SPACE(pos); + } else if (LEFT_SPACE(pos) < this->_data_len) { + return; + } + + this->_valid = true; + this->_data = ats_unique_malloc(this->_data_len); + memcpy(this->_data.get(), pos, this->_data_len); + return; } QUICFrame * QUICStreamFrame::split(size_t size) { - if (size <= this->_get_data_field_offset()) { + size_t header_len = 1 + QUICVariableInt::size(this->_stream_id); + if (this->_has_offset_field) { + header_len += QUICVariableInt::size(this->_offset); + } + if (this->_has_length_field) { + header_len += QUICVariableInt::size(this->_data_len); + } + + if (size <= header_len) { return nullptr; } bool fin = this->has_fin_flag(); ink_assert(size < this->size()); - size_t data_len = size - this->_get_data_field_offset(); + size_t data_len = size - header_len; size_t buf2_len = this->data_length() - data_len; ats_unique_buf buf = ats_unique_malloc(data_len); @@ -157,8 +228,8 @@ QUICStreamFrame::split(size_t size) this->reset(nullptr, 0); QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin, this->_id, - this->_owner); + new (frame) QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin, + this->_has_offset_field, this->_has_length_field, this->_id, this->_owner); return frame; } @@ -167,7 +238,8 @@ QUICFrameUPtr QUICStreamFrame::clone() const { return QUICFrameFactory::create_stream_frame(this->data(), this->data_length(), this->stream_id(), this->offset(), - this->has_fin_flag(), this->_id, this->_owner); + this->has_fin_flag(), this->has_offset_field(), this->has_length_field(), this->_id, + this->_owner); } QUICFrameType @@ -179,7 +251,18 @@ QUICStreamFrame::type() const size_t QUICStreamFrame::size() const { - return this->_get_data_field_offset() + this->data_length(); + size_t size = 1; + size += QUICVariableInt::size(this->_stream_id); + if (this->_has_offset_field) { + size += QUICVariableInt::size(this->_offset); + } + + if (this->_has_length_field) { + size += QUICVariableInt::size(this->_data_len); + } + + size += this->_data_len; + return size; } size_t @@ -241,49 +324,29 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, size_t limit, bool include_len QUICStreamId QUICStreamFrame::stream_id() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + _get_stream_id_field_offset()); - } else { - return this->_stream_id; - } + return this->_stream_id; } QUICOffset QUICStreamFrame::offset() const { - if (this->_buf) { - if (this->has_offset_field()) { - return QUICTypeUtil::read_QUICOffset(this->_buf + _get_offset_field_offset()); - } else { - return 0; - } - } else { + if (this->has_offset_field()) { return this->_offset; } + + return 0; } uint64_t QUICStreamFrame::data_length() const { - if (this->_buf) { - if (this->has_length_field()) { - return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_length_field_offset()); - } else { - return this->_len - this->_get_data_field_offset(); - } - } else { - return this->_data_len; - } + return this->_data_len; } const uint8_t * QUICStreamFrame::data() const { - if (this->_buf) { - return this->_buf + this->_get_data_field_offset(); - } else { - return this->_data.get(); - } + return this->_data.get(); } /** @@ -292,11 +355,7 @@ QUICStreamFrame::data() const bool QUICStreamFrame::has_offset_field() const { - if (this->_buf) { - return (this->_buf[0] & 0x04) != 0; - } else { - return this->_offset != 0; - } + return this->_has_offset_field; } /** @@ -305,13 +364,9 @@ QUICStreamFrame::has_offset_field() const bool QUICStreamFrame::has_length_field() const { - if (this->_buf) { - return (this->_buf[0] & 0x02) != 0; - } else { - // This depends on `include_length_field` arg of QUICStreamFrame::store. - // Returning true for just in case. - return true; - } + // This depends on `include_length_field` arg of QUICStreamFrame::store. + // Returning true for just in case. + return this->_has_length_field; } /** @@ -320,89 +375,7 @@ QUICStreamFrame::has_length_field() const bool QUICStreamFrame::has_fin_flag() const { - if (this->_buf) { - return (this->_buf[0] & 0x01) != 0; - } else { - return this->_fin; - } -} - -size_t -QUICStreamFrame::_get_stream_id_field_offset() const -{ - return sizeof(QUICFrameType); -} - -size_t -QUICStreamFrame::_get_offset_field_offset() const -{ - size_t offset_field_offset = this->_get_stream_id_field_offset(); - offset_field_offset += this->_get_stream_id_field_len(); - - return offset_field_offset; -} - -size_t -QUICStreamFrame::_get_length_field_offset() const -{ - size_t length_field_offset = this->_get_stream_id_field_offset(); - length_field_offset += this->_get_stream_id_field_len(); - length_field_offset += this->_get_offset_field_len(); - - return length_field_offset; -} - -size_t -QUICStreamFrame::_get_data_field_offset() const -{ - size_t data_field_offset = this->_get_stream_id_field_offset(); - data_field_offset += this->_get_stream_id_field_len(); - data_field_offset += this->_get_offset_field_len(); - data_field_offset += this->_get_length_field_len(); - - return data_field_offset; -} - -size_t -QUICStreamFrame::_get_stream_id_field_len() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_stream_id_field_offset()); - } else { - return QUICVariableInt::size(this->_stream_id); - } -} - -size_t -QUICStreamFrame::_get_offset_field_len() const -{ - if (this->_buf) { - if (this->has_offset_field()) { - return QUICVariableInt::size(this->_buf + this->_get_offset_field_offset()); - } else { - return 0; - } - } else { - if (this->_offset != 0) { - return QUICVariableInt::size(this->_offset); - } else { - return 0; - } - } -} - -size_t -QUICStreamFrame::_get_length_field_len() const -{ - if (this->_buf) { - if (this->has_length_field()) { - return QUICVariableInt::size(this->_buf + this->_get_length_field_offset()); - } else { - return 0; - } - } else { - return QUICVariableInt::size(this->_data_len); - } + return this->_fin; } // @@ -2789,13 +2762,13 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) QUICStreamFrameUPtr QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, - QUICFrameId id, QUICFrameGenerator *owner) + bool has_offset_field, bool has_length_field, QUICFrameId id, QUICFrameGenerator *owner) { ats_unique_buf buf = ats_unique_malloc(data_len); memcpy(buf.get(), data, data_len); QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last, id, owner); + new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last, has_offset_field, has_length_field, id, owner); return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 81a0bb7c132..b1e91974793 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -66,12 +66,14 @@ class QUICFrame virtual QUICFrame *split(size_t size); virtual int debug_msg(char *msg, size_t msg_len) const; virtual QUICFrameGenerator *generated_by(); + bool valid() const; LINK(QUICFrame, link); protected: QUICFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : _id(id), _owner(owner) {} const uint8_t *_buf = nullptr; size_t _len = 0; + bool _valid = false; const QUICFrameId _id = 0; QUICFrameGenerator *_owner = nullptr; }; @@ -84,8 +86,9 @@ class QUICStreamFrame : public QUICFrame { public: QUICStreamFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} - QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false, QUICFrameId id = 0, + QUICStreamFrame(const uint8_t *buf, size_t len); + QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false, + bool has_offset_field = true, bool has_length_field = true, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrame *split(size_t size) override; @@ -112,14 +115,8 @@ class QUICStreamFrame : public QUICFrame QUICStreamId _stream_id = 0; QUICOffset _offset = 0; bool _fin = false; - size_t _get_stream_id_field_offset() const; - size_t _get_offset_field_offset() const; - size_t _get_length_field_offset() const; - size_t _get_data_field_offset() const; - - size_t _get_stream_id_field_len() const; - size_t _get_offset_field_len() const; - size_t _get_length_field_len() const; + bool _has_offset_field = true; + bool _has_length_field = true; }; // @@ -998,7 +995,8 @@ class QUICFrameFactory * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ static QUICStreamFrameUPtr create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, - bool last = false, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + bool last = false, bool has_offset_field = true, bool has_length_field = true, + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a CRYPTO frame. diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index ea4b17e2a68..2e47cfc354d 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -144,6 +144,31 @@ TEST_CASE("Load STREAM Frame", "[quic]") CHECK(memcmp(stream_frame->data(), "\x01\x02\x03\x04\x05", 5) == 0); CHECK(stream_frame->has_fin_flag() == true); } + + SECTION("BAD DATA") + { + uint8_t buf1[] = { + 0x17, // 0b00010OLF (OLF=110) + 0x01, // Stream ID + 0x02, // Data Length + 0x05, // Data Length + 0x01, 0x02, 0x03, 0x04, // BAD Stream Data + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM); + CHECK(frame1->valid() == false); + } + + SECTION("BAD DATA") + { + uint8_t buf1[] = { + 0x17, // 0b00010OLF (OLF=110) + 0x01, // Stream ID + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM); + CHECK(frame1->valid() == false); + } } TEST_CASE("Store STREAM Frame", "[quic]") @@ -163,7 +188,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") ats_unique_buf payload1 = ats_unique_malloc(5); memcpy(payload1.get(), raw1, 5); - QUICStreamFrame stream_frame(std::move(payload1), 5, 0x01, 0x00); + QUICStreamFrame stream_frame(std::move(payload1), 5, 0x01, 0x00, false, false, true); CHECK(stream_frame.size() == 8); stream_frame.store(buf, &len, 32); From 9843be70033583cdb5c15c8cf9773629c2b6554f Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 21 Dec 2018 20:07:56 +0800 Subject: [PATCH 0979/1313] QUIC: Rework CryptoFrame parsing --- iocore/net/quic/QUICFrame.cc | 95 ++++++++------------------ iocore/net/quic/QUICFrame.h | 9 +-- iocore/net/quic/test/test_QUICFrame.cc | 11 +++ 3 files changed, 40 insertions(+), 75 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index cac19420274..0953c71bb8e 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -383,23 +383,41 @@ QUICStreamFrame::has_fin_flag() const // QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) - : QUICFrame(id, owner) + : QUICFrame(id, owner), _offset(offset), _data_len(data_len), _data(std::move(data)) { - this->_data = std::move(data); - this->_data_len = data_len; - this->_offset = offset; +} + +QUICCryptoFrame::QUICCryptoFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +{ + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; + + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_offset, field_len)) { + return; + } + + if (!read_varint(pos, LEFT_SPACE(pos), this->_data_len, field_len)) { + return; + } + + this->_valid = true; + this->_data = ats_unique_malloc(this->_data_len); + memcpy(this->_data.get(), pos, this->_data_len); + return; } QUICFrame * QUICCryptoFrame::split(size_t size) { - if (size <= this->_get_data_field_offset()) { + size_t header_len = 1 + QUICVariableInt::size(this->_offset) + QUICVariableInt::size(this->_data_len); + if (size <= header_len) { return nullptr; } ink_assert(size < this->size()); - size_t data_len = size - this->_get_data_field_offset(); + size_t data_len = size - header_len; size_t buf2_len = this->data_length() - data_len; ats_unique_buf buf = ats_unique_malloc(data_len); @@ -434,7 +452,7 @@ QUICCryptoFrame::type() const size_t QUICCryptoFrame::size() const { - return this->_get_data_field_offset() + this->data_length(); + return 1 + this->_data_len + QUICVariableInt::size(this->_offset) + QUICVariableInt::size(this->_data_len); } int @@ -475,76 +493,19 @@ QUICCryptoFrame::store(uint8_t *buf, size_t *len, size_t limit) const QUICOffset QUICCryptoFrame::offset() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICOffset(this->_buf + this->_get_offset_field_offset()); - } else { - return this->_offset; - } + return this->_offset; } uint64_t QUICCryptoFrame::data_length() const { - if (this->_buf) { - return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_length_field_offset()); - } else { - return this->_data_len; - } + return this->_data_len; } const uint8_t * QUICCryptoFrame::data() const { - if (this->_buf) { - return this->_buf + this->_get_data_field_offset(); - } else { - return this->_data.get(); - } -} - -size_t -QUICCryptoFrame::_get_offset_field_offset() const -{ - return sizeof(QUICFrameType); -} - -size_t -QUICCryptoFrame::_get_length_field_offset() const -{ - size_t length_field_offset = this->_get_offset_field_offset(); - length_field_offset += this->_get_offset_field_len(); - - return length_field_offset; -} - -size_t -QUICCryptoFrame::_get_data_field_offset() const -{ - size_t data_field_offset = this->_get_offset_field_offset(); - data_field_offset += this->_get_offset_field_len(); - data_field_offset += this->_get_length_field_len(); - - return data_field_offset; -} - -size_t -QUICCryptoFrame::_get_offset_field_len() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_offset_field_offset()); - } else { - return QUICVariableInt::size(this->_offset); - } -} - -size_t -QUICCryptoFrame::_get_length_field_len() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_length_field_offset()); - } else { - return QUICVariableInt::size(this->_data_len); - } + return this->_data.get(); } // diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index b1e91974793..5f43bffa6a0 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -127,7 +127,7 @@ class QUICCryptoFrame : public QUICFrame { public: QUICCryptoFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICCryptoFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICCryptoFrame(const uint8_t *buf, size_t len); QUICCryptoFrame(ats_unique_buf buf, size_t len, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrame *split(size_t size) override; @@ -147,13 +147,6 @@ class QUICCryptoFrame : public QUICFrame QUICOffset _offset = 0; uint64_t _data_len = 0; ats_unique_buf _data = {nullptr}; - - size_t _get_offset_field_offset() const; - size_t _get_length_field_offset() const; - size_t _get_data_field_offset() const; - - size_t _get_offset_field_len() const; - size_t _get_length_field_len() const; }; // diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 2e47cfc354d..b6c34057bf9 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -410,6 +410,17 @@ TEST_CASE("CRYPTO Frame", "[quic]") CHECK(memcmp(crypto_frame->data(), "\x01\x02\x03\x04\x05", 5) == 0); } + SECTION("BAD Loading") + { + uint8_t buf[] = { + 0x18, // Type + 0x80, 0x01, 0x00, 0x00, // Offset + }; + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::CRYPTO); + CHECK(frame->valid() == false); + } + SECTION("Storing") { uint8_t buf[32] = {0}; From a2f7fc15623e19fa6dc494a440d420ba1570a52b Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 21 Dec 2018 21:46:43 +0800 Subject: [PATCH 0980/1313] QUIC: Rework some frames parsing --- iocore/net/quic/QUICFrame.cc | 491 +++++++++++++------------ iocore/net/quic/QUICFrame.h | 56 ++- iocore/net/quic/test/test_QUICFrame.cc | 207 ++++++++--- 3 files changed, 422 insertions(+), 332 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 0953c71bb8e..6ad65728d04 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -153,6 +153,12 @@ QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStrea } QUICStreamFrame::QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +{ + this->parse(buf, len); +} + +void +QUICStreamFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); @@ -177,14 +183,14 @@ QUICStreamFrame::QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(nul if (!this->_has_length_field) { this->_data_len = LEFT_SPACE(pos); - } else if (LEFT_SPACE(pos) < this->_data_len) { + } + if (LEFT_SPACE(pos) < this->_data_len) { return; } this->_valid = true; this->_data = ats_unique_malloc(this->_data_len); memcpy(this->_data.get(), pos, this->_data_len); - return; } QUICFrame * @@ -388,6 +394,12 @@ QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffse } QUICCryptoFrame::QUICCryptoFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +{ + this->parse(buf, len); +} + +void +QUICCryptoFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); uint8_t *pos = const_cast(buf) + 1; @@ -401,6 +413,10 @@ QUICCryptoFrame::QUICCryptoFrame(const uint8_t *buf, size_t len) : QUICFrame(nul return; } + if (LEFT_SPACE(pos) < this->_data_len) { + return; + } + this->_valid = true; this->_data = ats_unique_malloc(this->_data_len); memcpy(this->_data.get(), pos, this->_data_len); @@ -1030,6 +1046,36 @@ QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode { } +QUICRstStreamFrame::QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +{ + this->parse(buf, len); +} + +void +QUICRstStreamFrame::parse(const uint8_t *buf, size_t len) +{ + ink_assert(len >= 1); + uint8_t *pos = 1 + const_cast(buf); + + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_stream_id, field_len)) { + return; + } + + if (LEFT_SPACE(pos) < 2) { + return; + } + + this->_error_code = QUICIntUtil::read_nbytes_as_uint(pos, 2); + pos += 2; + + if (!read_varint(pos, LEFT_SPACE(pos), this->_final_offset, field_len)) { + return; + } + + this->_valid = true; +} + QUICFrameUPtr QUICRstStreamFrame::clone() const { @@ -1046,7 +1092,7 @@ QUICRstStreamFrame::type() const size_t QUICRstStreamFrame::size() const { - return 1 + this->_get_stream_id_field_length() + sizeof(QUICAppErrorCode) + this->_get_final_offset_field_length(); + return 1 + QUICVariableInt::size(this->_stream_id) + sizeof(QUICAppErrorCode) + QUICVariableInt::size(this->_final_offset); } size_t @@ -1080,69 +1126,19 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len, size_t limit) const QUICStreamId QUICRstStreamFrame::stream_id() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + this->_get_stream_id_field_offset()); - } else { - return this->_stream_id; - } + return this->_stream_id; } QUICAppErrorCode QUICRstStreamFrame::error_code() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + this->_get_error_code_field_offset()); - } else { - return this->_error_code; - } + return this->_error_code; } QUICOffset QUICRstStreamFrame::final_offset() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICOffset(this->_buf + this->_get_final_offset_field_offset()); - } else { - return this->_final_offset; - } -} - -size_t -QUICRstStreamFrame::_get_stream_id_field_offset() const -{ - return 1; -} - -size_t -QUICRstStreamFrame::_get_stream_id_field_length() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_stream_id_field_offset()); - } else { - return QUICVariableInt::size(this->_stream_id); - } -} - -size_t -QUICRstStreamFrame::_get_error_code_field_offset() const -{ - return this->_get_stream_id_field_offset() + this->_get_stream_id_field_length(); -} - -size_t -QUICRstStreamFrame::_get_final_offset_field_offset() const -{ - return this->_get_error_code_field_offset() + sizeof(QUICAppErrorCode); -} - -size_t -QUICRstStreamFrame::_get_final_offset_field_length() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_final_offset_field_offset()); - } else { - return QUICVariableInt::size(this->_final_offset); - } + return this->_final_offset; } // @@ -1155,6 +1151,17 @@ QUICPingFrame::clone() const return QUICFrameFactory::create_ping_frame(this->_id, this->_owner); } +QUICPingFrame::QUICPingFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +{ + this->parse(buf, len); +} + +void +QUICPingFrame::parse(const uint8_t *buf, size_t len) +{ + this->_valid = true; +} + QUICFrameType QUICPingFrame::type() const { @@ -1174,20 +1181,25 @@ QUICPingFrame::store(uint8_t *buf, size_t *len, size_t limit) const return 0; } - *len = this->size(); - - if (this->_buf) { - memcpy(buf, this->_buf, *len); - } else { - buf[0] = static_cast(QUICFrameType::PING); - } - + *len = this->size(); + buf[0] = static_cast(QUICFrameType::PING); return *len; } // // PADDING frame // +QUICPaddingFrame::QUICPaddingFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +{ + this->parse(buf, len); +} + +void +QUICPaddingFrame::parse(const uint8_t *buf, size_t len) +{ + ink_assert(len >= 1); + this->_valid = true; +} QUICFrameUPtr QUICPaddingFrame::clone() const @@ -1239,6 +1251,54 @@ QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, QUICFram { } +QUICConnectionCloseFrame::QUICConnectionCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +{ + this->parse(buf, len); +} + +void +QUICConnectionCloseFrame::parse(const uint8_t *buf, size_t len) +{ + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; + + if (LEFT_SPACE(pos) < 2) { + return; + } + + this->_error_code = QUICIntUtil::read_nbytes_as_uint(pos, 2); + pos += 2; + + size_t field_len = 0; + uint64_t field = 0; + if (!read_varint(pos, LEFT_SPACE(pos), field, field_len)) { + return; + } + + this->_frame_type = static_cast(field); + + /** + Frame Type Field Accessor + + PADDING frame in Frame Type field means frame type that triggered the error is unknown. + Return QUICFrameType::UNKNOWN when Frame Type field is PADDING (0x0). + */ + if (this->_frame_type == QUICFrameType::PADDING) { + this->_frame_type = QUICFrameType::UNKNOWN; + } + + if (!read_varint(pos, LEFT_SPACE(pos), this->_reason_phrase_length, field_len)) { + return; + } + + if (LEFT_SPACE(pos) < this->_reason_phrase_length) { + return; + } + + this->_valid = true; + this->_reason_phrase = reinterpret_cast(pos); +} + QUICFrameUPtr QUICConnectionCloseFrame::clone() const { @@ -1255,8 +1315,8 @@ QUICConnectionCloseFrame::type() const size_t QUICConnectionCloseFrame::size() const { - return this->_get_reason_phrase_length_field_offset() + this->_get_reason_phrase_length_field_length() + - this->reason_phrase_length(); + return 1 + sizeof(QUICTransErrorCode) + QUICVariableInt::size(sizeof(QUICFrameType)) + + QUICVariableInt::size(this->_reason_phrase_length) + this->_reason_phrase_length; } /** @@ -1333,90 +1393,25 @@ QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const uint16_t QUICConnectionCloseFrame::error_code() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICTransErrorCode(this->_buf + sizeof(QUICFrameType)); - } else { - return this->_error_code; - } + return this->_error_code; } -/** - Frame Type Field Accessor - - PADDING frame in Frame Type field means frame type that triggered the error is unknown. - Return QUICFrameType::UNKNOWN when Frame Type field is PADDING (0x0). - */ QUICFrameType QUICConnectionCloseFrame::frame_type() const { - if (this->_buf) { - QUICFrameType frame = QUICFrame::type(this->_buf + this->_get_frame_type_field_offset()); - if (frame == QUICFrameType::PADDING) { - frame = QUICFrameType::UNKNOWN; - } - return frame; - } else { - return this->_frame_type; - } + return this->_frame_type; } uint64_t QUICConnectionCloseFrame::reason_phrase_length() const { - if (this->_buf) { - size_t offset = this->_get_reason_phrase_length_field_offset(); - uint64_t reason_phrase_len = QUICIntUtil::read_QUICVariableInt(this->_buf + offset); - if (reason_phrase_len > this->_len - offset) { - reason_phrase_len = this->_len - offset; - } - - return reason_phrase_len; - } else { - return this->_reason_phrase_length; - } + return this->_reason_phrase_length; } const char * QUICConnectionCloseFrame::reason_phrase() const { - if (this->_buf) { - size_t offset = this->_get_reason_phrase_field_offset(); - if (offset > this->_len) { - return nullptr; - } else { - return reinterpret_cast(this->_buf + offset); - } - } else { - return this->_reason_phrase; - } -} - -size_t -QUICConnectionCloseFrame::_get_frame_type_field_offset() const -{ - return sizeof(QUICFrameType) + sizeof(QUICTransErrorCode); -} - -size_t -QUICConnectionCloseFrame::_get_reason_phrase_length_field_offset() const -{ - return this->_get_frame_type_field_offset() + sizeof(QUICFrameType); -} - -size_t -QUICConnectionCloseFrame::_get_reason_phrase_length_field_length() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_reason_phrase_length_field_offset()); - } else { - return QUICVariableInt::size(this->_reason_phrase_length); - } -} - -size_t -QUICConnectionCloseFrame::_get_reason_phrase_field_offset() const -{ - return this->_get_reason_phrase_length_field_offset() + this->_get_reason_phrase_length_field_length(); + return this->_reason_phrase; } // @@ -1431,6 +1426,37 @@ QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code this->_reason_phrase = reason_phrase; } +QUICApplicationCloseFrame::QUICApplicationCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +{ + this->parse(buf, len); +} + +void +QUICApplicationCloseFrame::parse(const uint8_t *buf, size_t len) +{ + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; + + if (LEFT_SPACE(pos) < 2) { + return; + } + + this->_error_code = QUICIntUtil::read_nbytes_as_uint(pos, 2); + pos += 2; + + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_reason_phrase_length, field_len)) { + return; + } + + if (LEFT_SPACE(pos) < this->_reason_phrase_length) { + return; + } + + this->_valid = true; + this->_reason_phrase = reinterpret_cast(pos); +} + QUICFrameUPtr QUICApplicationCloseFrame::clone() const { @@ -1447,8 +1473,7 @@ QUICApplicationCloseFrame::type() const size_t QUICApplicationCloseFrame::size() const { - return sizeof(QUICFrameType) + sizeof(QUICAppErrorCode) + this->_get_reason_phrase_length_field_length() + - this->reason_phrase_length(); + return 1 + sizeof(QUICTransErrorCode) + QUICVariableInt::size(this->_reason_phrase_length) + this->_reason_phrase_length; } size_t @@ -1504,61 +1529,46 @@ QUICApplicationCloseFrame::debug_msg(char *msg, size_t msg_len) const QUICAppErrorCode QUICApplicationCloseFrame::error_code() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + 1); - } else { - return this->_error_code; - } + return this->_error_code; } uint64_t QUICApplicationCloseFrame::reason_phrase_length() const { - if (this->_buf) { - return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_reason_phrase_length_field_offset()); - } else { - return this->_reason_phrase_length; - } + return this->_reason_phrase_length; } const char * QUICApplicationCloseFrame::reason_phrase() const { - if (this->_buf) { - return reinterpret_cast(this->_buf + this->_get_reason_phrase_field_offset()); - } else { - return this->_reason_phrase; - } + return this->_reason_phrase; } -size_t -QUICApplicationCloseFrame::_get_reason_phrase_length_field_offset() const +// +// MAX_DATA frame +// +QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, QUICFrameId id, QUICFrameGenerator *owner) : QUICFrame(id, owner) { - return sizeof(QUICFrameType) + sizeof(QUICTransErrorCode); + this->_maximum_data = maximum_data; } -size_t -QUICApplicationCloseFrame::_get_reason_phrase_length_field_length() const +QUICMaxDataFrame::QUICMaxDataFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) { - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_reason_phrase_length_field_offset()); - } else { - return QUICVariableInt::size(this->_reason_phrase_length); - } + this->parse(buf, len); } -size_t -QUICApplicationCloseFrame::_get_reason_phrase_field_offset() const +void +QUICMaxDataFrame::parse(const uint8_t *buf, size_t len) { - return this->_get_reason_phrase_length_field_offset() + this->_get_reason_phrase_length_field_length(); -} + ink_assert(len >= 1); + uint8_t *pos = 1 + const_cast(buf); -// -// MAX_DATA frame -// -QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, QUICFrameId id, QUICFrameGenerator *owner) : QUICFrame(id, owner) -{ - this->_maximum_data = maximum_data; + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_maximum_data, field_len)) { + return; + } + + this->_valid = true; } QUICFrameUPtr @@ -1576,7 +1586,7 @@ QUICMaxDataFrame::type() const size_t QUICMaxDataFrame::size() const { - return sizeof(QUICFrameType) + this->_get_max_data_field_length(); + return sizeof(QUICFrameType) + QUICVariableInt::size(this->_maximum_data); } size_t @@ -1612,21 +1622,7 @@ QUICMaxDataFrame::debug_msg(char *msg, size_t msg_len) const uint64_t QUICMaxDataFrame::maximum_data() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICMaxData(this->_buf + sizeof(QUICFrameType)); - } else { - return this->_maximum_data; - } -} - -size_t -QUICMaxDataFrame::_get_max_data_field_length() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); - } else { - return QUICVariableInt::size(this->_maximum_data); - } + return this->_maximum_data; } // @@ -1640,6 +1636,29 @@ QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t this->_maximum_stream_data = maximum_stream_data; } +QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +{ + this->parse(buf, len); +} + +void +QUICMaxStreamDataFrame::parse(const uint8_t *buf, size_t len) +{ + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; + + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_stream_id, field_len)) { + return; + } + + if (!read_varint(pos, LEFT_SPACE(pos), this->_maximum_stream_data, field_len)) { + return; + } + + this->_valid = true; +} + QUICFrameUPtr QUICMaxStreamDataFrame::clone() const { @@ -1655,7 +1674,7 @@ QUICMaxStreamDataFrame::type() const size_t QUICMaxStreamDataFrame::size() const { - return sizeof(QUICFrameType) + this->_get_stream_id_field_length() + this->_get_max_stream_data_field_length(); + return sizeof(QUICFrameType) + QUICVariableInt::size(this->_maximum_stream_data) + QUICVariableInt::size(this->_stream_id); } size_t @@ -1691,62 +1710,41 @@ QUICMaxStreamDataFrame::debug_msg(char *msg, size_t msg_len) const QUICStreamId QUICMaxStreamDataFrame::stream_id() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + sizeof(QUICFrameType)); - } else { - return this->_stream_id; - } + return this->_stream_id; } uint64_t QUICMaxStreamDataFrame::maximum_stream_data() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICMaxData(this->_buf + this->_get_max_stream_data_field_offset()); - } else { - return this->_maximum_stream_data; - } + return this->_maximum_stream_data; } -size_t -QUICMaxStreamDataFrame::_get_stream_id_field_offset() const +// +// MAX_STREAM_ID +// +QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICFrameId id, QUICFrameGenerator *owner) + : QUICFrame(id, owner) { - return sizeof(QUICFrameType); + this->_maximum_stream_id = maximum_stream_id; } -size_t -QUICMaxStreamDataFrame::_get_stream_id_field_length() const +QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) { - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_stream_id_field_offset()); - } else { - return QUICVariableInt::size(this->_stream_id); - } + this->parse(buf, len); } -size_t -QUICMaxStreamDataFrame::_get_max_stream_data_field_offset() const +void +QUICMaxStreamIdFrame::parse(const uint8_t *buf, size_t len) { - return sizeof(QUICFrameType) + this->_get_stream_id_field_length(); -} + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; -size_t -QUICMaxStreamDataFrame::_get_max_stream_data_field_length() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_max_stream_data_field_offset()); - } else { - return QUICVariableInt::size(this->_maximum_stream_data); + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_maximum_stream_id, field_len)) { + return; } -} -// -// MAX_STREAM_ID -// -QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICFrameId id, QUICFrameGenerator *owner) - : QUICFrame(id, owner) -{ - this->_maximum_stream_id = maximum_stream_id; + this->_valid = true; } QUICFrameUPtr @@ -1764,7 +1762,7 @@ QUICMaxStreamIdFrame::type() const size_t QUICMaxStreamIdFrame::size() const { - return sizeof(QUICFrameType) + this->_get_max_stream_id_field_length(); + return sizeof(QUICFrameType) + QUICVariableInt::size(this->_maximum_stream_id); } size_t @@ -1793,26 +1791,31 @@ QUICMaxStreamIdFrame::store(uint8_t *buf, size_t *len, size_t limit) const QUICStreamId QUICMaxStreamIdFrame::maximum_stream_id() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + sizeof(QUICFrameType)); - } else { - return this->_maximum_stream_id; - } + return this->_maximum_stream_id; } -size_t -QUICMaxStreamIdFrame::_get_max_stream_id_field_length() const +// +// BLOCKED frame +// +QUICBlockedFrame::QUICBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) { - if (this->_buf) { - return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); - } else { - return QUICVariableInt::size(this->_maximum_stream_id); + this->parse(buf, len); +} + +void +QUICBlockedFrame::parse(const uint8_t *buf, size_t len) +{ + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; + + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_offset, field_len)) { + return; } + + this->_valid = true; } -// -// BLOCKED frame -// QUICFrameUPtr QUICBlockedFrame::clone() const { @@ -2715,7 +2718,7 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) this->_reusable_frames[static_cast(QUICFrame::type(buf))] = frame; } } else { - frame->reset(buf, len); + frame->parse(buf, len); } return frame; diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 5f43bffa6a0..eb500fad95b 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -65,6 +65,11 @@ class QUICFrame virtual void reset(const uint8_t *buf, size_t len); virtual QUICFrame *split(size_t size); virtual int debug_msg(char *msg, size_t msg_len) const; + virtual void + parse(const uint8_t *buf, size_t len) + { + this->reset(buf, len); + } virtual QUICFrameGenerator *generated_by(); bool valid() const; LINK(QUICFrame, link); @@ -97,6 +102,7 @@ class QUICStreamFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, 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) override; size_t store(uint8_t *buf, size_t *len, size_t limit, bool include_length_field) const; QUICStreamId stream_id() const; @@ -136,6 +142,7 @@ class QUICCryptoFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, 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) override; QUICOffset offset() const; uint64_t data_length() const; @@ -299,7 +306,7 @@ class QUICRstStreamFrame : public QUICFrame { public: QUICRstStreamFrame(QUICFrameId id = 0) : QUICFrame(id) {} - QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICRstStreamFrame(const uint8_t *buf, size_t len); QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); @@ -307,18 +314,13 @@ class QUICRstStreamFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void parse(const uint8_t *buf, size_t len) override; QUICStreamId stream_id() const; QUICAppErrorCode error_code() const; QUICOffset final_offset() const; private: - size_t _get_stream_id_field_offset() const; - size_t _get_stream_id_field_length() const; - size_t _get_error_code_field_offset() const; - size_t _get_final_offset_field_offset() const; - size_t _get_final_offset_field_length() const; - QUICStreamId _stream_id = 0; QUICAppErrorCode _error_code = 0; QUICOffset _final_offset = 0; @@ -332,11 +334,12 @@ class QUICPingFrame : public QUICFrame { public: QUICPingFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICPingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICPingFrame(const uint8_t *buf, size_t len); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void parse(const uint8_t *buf, size_t len) override; private: }; @@ -349,12 +352,13 @@ class QUICPaddingFrame : public QUICFrame { public: QUICPaddingFrame() : QUICFrame() {} - QUICPaddingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICPaddingFrame(const uint8_t *buf, size_t len); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual bool is_probing_frame() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void parse(const uint8_t *buf, size_t len) override; }; // @@ -365,7 +369,7 @@ class QUICConnectionCloseFrame : public QUICFrame { public: QUICConnectionCloseFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICConnectionCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICConnectionCloseFrame(const uint8_t *buf, size_t len); QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; @@ -373,6 +377,7 @@ class QUICConnectionCloseFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, 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) override; uint16_t error_code() const; QUICFrameType frame_type() const; @@ -380,11 +385,6 @@ class QUICConnectionCloseFrame : public QUICFrame const char *reason_phrase() const; private: - size_t _get_frame_type_field_offset() const; - size_t _get_reason_phrase_length_field_offset() const; - size_t _get_reason_phrase_length_field_length() const; - size_t _get_reason_phrase_field_offset() const; - uint16_t _error_code; QUICFrameType _frame_type = QUICFrameType::UNKNOWN; uint64_t _reason_phrase_length = 0; @@ -399,7 +399,7 @@ class QUICApplicationCloseFrame : public QUICFrame { public: QUICApplicationCloseFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICApplicationCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICApplicationCloseFrame(const uint8_t *buf, size_t len); QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; @@ -407,16 +407,13 @@ class QUICApplicationCloseFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void parse(const uint8_t *buf, size_t len) override; QUICAppErrorCode error_code() const; uint64_t reason_phrase_length() const; const char *reason_phrase() const; private: - size_t _get_reason_phrase_length_field_offset() const; - size_t _get_reason_phrase_length_field_length() const; - size_t _get_reason_phrase_field_offset() const; - QUICAppErrorCode _error_code = 0; uint64_t _reason_phrase_length = 0; const char *_reason_phrase = nullptr; @@ -430,19 +427,18 @@ class QUICMaxDataFrame : public QUICFrame { public: QUICMaxDataFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICMaxDataFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICMaxDataFrame(const uint8_t *buf, size_t len); QUICMaxDataFrame(uint64_t maximum_data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, 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) override; uint64_t maximum_data() const; private: - size_t _get_max_data_field_length() const; - uint64_t _maximum_data = 0; }; @@ -454,12 +450,13 @@ class QUICMaxStreamDataFrame : public QUICFrame { public: QUICMaxStreamDataFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICMaxStreamDataFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICMaxStreamDataFrame(const uint8_t *buf, size_t len); QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; + virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual int debug_msg(char *msg, size_t msg_len) const override; @@ -467,11 +464,6 @@ class QUICMaxStreamDataFrame : public QUICFrame uint64_t maximum_stream_data() const; private: - size_t _get_stream_id_field_offset() const; - size_t _get_stream_id_field_length() const; - size_t _get_max_stream_data_field_offset() const; - size_t _get_max_stream_data_field_length() const; - QUICStreamId _stream_id = 0; uint64_t _maximum_stream_data = 0; }; @@ -484,12 +476,13 @@ class QUICMaxStreamIdFrame : public QUICFrame { public: QUICMaxStreamIdFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICMaxStreamIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICMaxStreamIdFrame(const uint8_t *buf, size_t len); QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void parse(const uint8_t *buf, size_t len) override; QUICStreamId maximum_stream_id() const; private: @@ -505,13 +498,14 @@ class QUICBlockedFrame : public QUICFrame { public: QUICBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICBlockedFrame(const uint8_t *buf, size_t len); QUICBlockedFrame(QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _offset(offset){}; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; + virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICOffset offset() const; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index b6c34057bf9..3c1c9b7e465 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -635,20 +635,35 @@ TEST_CASE("Store Ack Frame", "[quic]") TEST_CASE("Load RST_STREAM Frame", "[quic]") { - uint8_t buf1[] = { - 0x01, // Type - 0x92, 0x34, 0x56, 0x78, // Stream ID - 0x00, 0x01, // Error Code - 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::RST_STREAM); - CHECK(frame1->size() == 15); - std::shared_ptr rst_stream_frame1 = std::dynamic_pointer_cast(frame1); - CHECK(rst_stream_frame1 != nullptr); - CHECK(rst_stream_frame1->error_code() == 0x0001); - CHECK(rst_stream_frame1->stream_id() == 0x12345678); - CHECK(rst_stream_frame1->final_offset() == 0x1122334455667788); + SECTION("Load") + { + uint8_t buf1[] = { + 0x01, // Type + 0x92, 0x34, 0x56, 0x78, // Stream ID + 0x00, 0x01, // Error Code + 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::RST_STREAM); + CHECK(frame1->size() == 15); + std::shared_ptr rst_stream_frame1 = std::dynamic_pointer_cast(frame1); + CHECK(rst_stream_frame1 != nullptr); + CHECK(rst_stream_frame1->error_code() == 0x0001); + CHECK(rst_stream_frame1->stream_id() == 0x12345678); + CHECK(rst_stream_frame1->final_offset() == 0x1122334455667788); + } + + SECTION("BAD Load") + { + uint8_t buf1[] = { + 0x01, // Type + 0x92, 0x34, 0x56, 0x78, // Stream ID + 0x00, 0x01, // Error Code + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::RST_STREAM); + CHECK(frame1->valid() == false); + } } TEST_CASE("Store RST_STREAM Frame", "[quic]") @@ -754,6 +769,20 @@ TEST_CASE("ConnectionClose Frame", "[quic]") CHECK(memcmp(conn_close_frame->reason_phrase(), reason_phrase, reason_phrase_len) == 0); } + SECTION("Bad loading") + { + uint8_t buf[] = { + 0x02, // Type + 0x00, 0x0A, // Error Code + 0x00, // Frame Type + 0x05, // Reason Phrase Length + }; + + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::CONNECTION_CLOSE); + CHECK(frame->valid() == false); + } + SECTION("loading w/o reason phrase") { uint8_t buf[] = { @@ -836,6 +865,18 @@ TEST_CASE("Load ApplicationClose Frame", "[quic]") CHECK(memcmp(app_close_frame->reason_phrase(), buf1 + 4, 5) == 0); } + SECTION("Bad Loading") + { + uint8_t buf1[] = { + 0x03, // Type + 0x00, 0x01, // Error Code + 0x05, // Reason Phrase Length + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::APPLICATION_CLOSE); + CHECK(frame1->valid() == false); + } + SECTION("w/o reason phrase") { uint8_t buf2[] = { @@ -896,16 +937,29 @@ TEST_CASE("Store ApplicationClose Frame", "[quic]") TEST_CASE("Load MaxData Frame", "[quic]") { - uint8_t buf1[] = { - 0x04, // Type - 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::MAX_DATA); - CHECK(frame1->size() == 9); - std::shared_ptr max_data_frame = std::dynamic_pointer_cast(frame1); - CHECK(max_data_frame != nullptr); - CHECK(max_data_frame->maximum_data() == 0x1122334455667788ULL); + SECTION("Load") + { + uint8_t buf1[] = { + 0x04, // Type + 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::MAX_DATA); + CHECK(frame1->size() == 9); + std::shared_ptr max_data_frame = std::dynamic_pointer_cast(frame1); + CHECK(max_data_frame != nullptr); + CHECK(max_data_frame->maximum_data() == 0x1122334455667788ULL); + } + + SECTION("Bad Load") + { + uint8_t buf1[] = { + 0x04, // Type + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::MAX_DATA); + CHECK(frame1->valid() == false); + } } TEST_CASE("Store MaxData Frame", "[quic]") @@ -927,19 +981,33 @@ TEST_CASE("Store MaxData Frame", "[quic]") TEST_CASE("Load MaxStreamData Frame", "[quic]") { - uint8_t buf1[] = { - 0x05, // Type - 0x81, 0x02, 0x03, 0x04, // Stream ID - 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::MAX_STREAM_DATA); - CHECK(frame1->size() == 13); - std::shared_ptr maxStreamDataFrame1 = - std::dynamic_pointer_cast(frame1); - CHECK(maxStreamDataFrame1 != nullptr); - CHECK(maxStreamDataFrame1->stream_id() == 0x01020304); - CHECK(maxStreamDataFrame1->maximum_stream_data() == 0x1122334455667788ULL); + SECTION("Load") + { + uint8_t buf1[] = { + 0x05, // Type + 0x81, 0x02, 0x03, 0x04, // Stream ID + 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::MAX_STREAM_DATA); + CHECK(frame1->size() == 13); + std::shared_ptr maxStreamDataFrame1 = + std::dynamic_pointer_cast(frame1); + CHECK(maxStreamDataFrame1 != nullptr); + CHECK(maxStreamDataFrame1->stream_id() == 0x01020304); + CHECK(maxStreamDataFrame1->maximum_stream_data() == 0x1122334455667788ULL); + } + + SECTION("Load") + { + uint8_t buf1[] = { + 0x05, // Type + 0x81, 0x02, 0x03, 0x04, // Stream ID + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::MAX_STREAM_DATA); + CHECK(frame1->valid() == false); + } } TEST_CASE("Store MaxStreamData Frame", "[quic]") @@ -962,16 +1030,28 @@ TEST_CASE("Store MaxStreamData Frame", "[quic]") TEST_CASE("Load MaxStreamId Frame", "[quic]") { - uint8_t buf1[] = { - 0x06, // Type - 0x81, 0x02, 0x03, 0x04, // Stream ID - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::MAX_STREAM_ID); - CHECK(frame1->size() == 5); - std::shared_ptr max_stream_id_frame = std::dynamic_pointer_cast(frame1); - CHECK(max_stream_id_frame != nullptr); - CHECK(max_stream_id_frame->maximum_stream_id() == 0x01020304); + SECTION("load") + { + uint8_t buf1[] = { + 0x06, // Type + 0x81, 0x02, 0x03, 0x04, // Stream ID + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::MAX_STREAM_ID); + CHECK(frame1->size() == 5); + std::shared_ptr max_stream_id_frame = std::dynamic_pointer_cast(frame1); + CHECK(max_stream_id_frame != nullptr); + CHECK(max_stream_id_frame->maximum_stream_id() == 0x01020304); + } + SECTION("bad load") + { + uint8_t buf1[] = { + 0x06, // Type + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::MAX_STREAM_ID); + CHECK(frame1->valid() == false); + } } TEST_CASE("Store MaxStreamId Frame", "[quic]") @@ -993,16 +1073,29 @@ TEST_CASE("Store MaxStreamId Frame", "[quic]") TEST_CASE("Load Blocked Frame", "[quic]") { - uint8_t buf1[] = { - 0x08, // Type - 0x07, // Offset - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::BLOCKED); - CHECK(frame1->size() == 2); - std::shared_ptr blocked_stream_frame = std::dynamic_pointer_cast(frame1); - CHECK(blocked_stream_frame != nullptr); - CHECK(blocked_stream_frame->offset() == 0x07); + SECTION("load") + { + uint8_t buf1[] = { + 0x08, // Type + 0x07, // Offset + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::BLOCKED); + CHECK(frame1->size() == 2); + std::shared_ptr blocked_stream_frame = std::dynamic_pointer_cast(frame1); + CHECK(blocked_stream_frame != nullptr); + CHECK(blocked_stream_frame->offset() == 0x07); + } + + SECTION("bad load") + { + uint8_t buf1[] = { + 0x08, // Type + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::BLOCKED); + CHECK(frame1->valid() == false); + } } TEST_CASE("Store Blocked Frame", "[quic]") From d6ccabc7e1e212bba73ddaec7ce57586fe462a67 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 22 Dec 2018 14:25:32 +0800 Subject: [PATCH 0981/1313] QUIC: add left frames --- iocore/net/quic/QUICFrame.cc | 1161 +++++++++++------------- iocore/net/quic/QUICFrame.h | 84 +- iocore/net/quic/test/test_QUICFrame.cc | 299 ++++-- 3 files changed, 786 insertions(+), 758 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 6ad65728d04..737a31b48eb 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -53,6 +53,7 @@ ClassAllocator quicRetireConnectionIdFrameAllocator ClassAllocator quicRetransmissionFrameAllocator("quicRetransmissionFrameAllocator"); #define LEFT_SPACE(pos) ((size_t)(buf + len - pos)) +#define FRAME_SIZE(pos) (pos - buf) // the pos will auto move forward . return true if the data vaild static bool @@ -75,7 +76,8 @@ read_varint(uint8_t *&pos, size_t len, uint64_t &field, size_t &field_len) QUICFrameType QUICFrame::type() const { - return QUICFrame::type(this->_buf); + ink_assert("should no be called"); + return QUICFrameType::UNKNOWN; } bool @@ -113,8 +115,7 @@ QUICFrame::type(const uint8_t *buf) void QUICFrame::reset(const uint8_t *buf, size_t len) { - this->_buf = buf; - this->_len = len; + ink_assert(0); } int @@ -152,7 +153,7 @@ QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStrea { } -QUICStreamFrame::QUICStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +QUICStreamFrame::QUICStreamFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } @@ -191,6 +192,8 @@ QUICStreamFrame::parse(const uint8_t *buf, size_t len) this->_valid = true; this->_data = ats_unique_malloc(this->_data_len); memcpy(this->_data.get(), pos, this->_data_len); + pos += this->_data_len; + this->_size = FRAME_SIZE(pos); } QUICFrame * @@ -231,8 +234,6 @@ QUICStreamFrame::split(size_t size) this->_data = std::move(buf); this->_stream_id = this->stream_id(); - this->reset(nullptr, 0); - QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); new (frame) QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin, this->_has_offset_field, this->_has_length_field, this->_id, this->_owner); @@ -257,6 +258,10 @@ QUICStreamFrame::type() const size_t QUICStreamFrame::size() const { + if (this->_size) { + return this->_size; + } + size_t size = 1; size += QUICVariableInt::size(this->_stream_id); if (this->_has_offset_field) { @@ -393,7 +398,7 @@ QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffse { } -QUICCryptoFrame::QUICCryptoFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +QUICCryptoFrame::QUICCryptoFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } @@ -420,7 +425,7 @@ QUICCryptoFrame::parse(const uint8_t *buf, size_t len) this->_valid = true; this->_data = ats_unique_malloc(this->_data_len); memcpy(this->_data.get(), pos, this->_data_len); - return; + this->_size = FRAME_SIZE(pos); } QUICFrame * @@ -528,9 +533,63 @@ QUICCryptoFrame::data() const // ACK frame // -QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) +QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len) +{ + this->parse(buf, len); +} + +void +QUICAckFrame::parse(const uint8_t *buf, size_t len) { - this->reset(buf, len); + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; + bool has_ecn = (buf[0] == 0x1b); + + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_largest_acknowledged, field_len)) { + return; + } + + if (!read_varint(pos, LEFT_SPACE(pos), this->_ack_delay, field_len)) { + return; + } + + size_t ack_block_count = 0; + if (!read_varint(pos, LEFT_SPACE(pos), ack_block_count, field_len)) { + return; + } + + size_t first_ack_block = 0; + if (!read_varint(pos, LEFT_SPACE(pos), first_ack_block, field_len)) { + return; + } + + this->_ack_block_section = new AckBlockSection(first_ack_block); + for (size_t i = 0; i < ack_block_count; i++) { + size_t gap = 0; + size_t add_ack_block = 0; + + if (!read_varint(pos, LEFT_SPACE(pos), gap, field_len)) { + return; + } + + if (!read_varint(pos, LEFT_SPACE(pos), add_ack_block, field_len)) { + return; + } + + this->_ack_block_section->add_ack_block({gap, add_ack_block}); + } + + if (has_ecn) { + this->_ecn_section = new EcnSection(pos, LEFT_SPACE(pos)); + if (!this->_ecn_section->valid()) { + return; + } + pos += this->_ecn_section->size(); + } + + this->_valid = true; + this->_size = FRAME_SIZE(pos); } QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameId id, @@ -554,23 +613,6 @@ QUICAckFrame::~QUICAckFrame() } } -void -QUICAckFrame::reset(const uint8_t *buf, size_t len) -{ - QUICFrame::reset(buf, len); - if (this->_ack_block_section) { - delete this->_ack_block_section; - } - if (this->_ecn_section) { - delete this->_ecn_section; - } - - this->_ack_block_section = new AckBlockSection(buf + this->_get_ack_block_section_offset(), this->ack_block_count()); - if (buf[0] == static_cast(QUICFrameType::ACK) + 1) { - this->_ecn_section = new EcnSection(buf + this->_get_ack_block_section_offset() + this->_ack_block_section->size()); - } -} - QUICFrameUPtr QUICAckFrame::clone() const { @@ -594,11 +636,21 @@ QUICAckFrame::type() const size_t QUICAckFrame::size() const { + if (this->_size) { + return this->_size; + } + + size_t pre_len = 1 + QUICVariableInt::size(this->_largest_acknowledged) + QUICVariableInt::size(this->_ack_delay) + + QUICVariableInt::size(this->_ack_block_section->count()); + if (this->_ack_block_section) { + pre_len += this->_ack_block_section->size(); + } + if (this->_ecn_section) { - return this->_get_ack_block_section_offset() + this->_ack_block_section->size() + this->_ecn_section->size(); - } else { - return this->_get_ack_block_section_offset() + this->_ack_block_section->size(); + return pre_len + this->_ecn_section->size(); } + + return pre_len; } size_t @@ -647,35 +699,19 @@ QUICAckFrame::debug_msg(char *msg, size_t msg_len) const QUICPacketNumber QUICAckFrame::largest_acknowledged() const { - if (this->_buf) { - uint64_t largest_acknowledged; - size_t encoded_len; - QUICVariableInt::decode(largest_acknowledged, encoded_len, this->_buf + this->_get_largest_acknowledged_offset(), - this->_len - this->_get_largest_acknowledged_offset()); - return largest_acknowledged; - } else { - return this->_largest_acknowledged; - } + return this->_largest_acknowledged; } uint64_t QUICAckFrame::ack_delay() const { - if (this->_buf) { - return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_ack_delay_offset()); - } else { - return this->_ack_delay; - } + return this->_ack_delay; } uint64_t QUICAckFrame::ack_block_count() const { - if (this->_buf) { - return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_ack_block_count_offset()); - } else { - return this->_ack_block_section->count(); - } + return this->_ack_block_section->count(); } QUICAckFrame::AckBlockSection * @@ -702,60 +738,6 @@ QUICAckFrame::ecn_section() const return this->_ecn_section; } -size_t -QUICAckFrame::_get_largest_acknowledged_offset() const -{ - return sizeof(QUICFrameType); -} - -size_t -QUICAckFrame::_get_largest_acknowledged_length() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_largest_acknowledged_offset()); - } else { - return QUICVariableInt::size(this->_largest_acknowledged); - } -} - -size_t -QUICAckFrame::_get_ack_delay_offset() const -{ - return this->_get_largest_acknowledged_offset() + this->_get_largest_acknowledged_length(); -} - -size_t -QUICAckFrame::_get_ack_delay_length() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_ack_delay_offset()); - } else { - return QUICVariableInt::size(this->_ack_delay); - } -} - -size_t -QUICAckFrame::_get_ack_block_count_offset() const -{ - return this->_get_ack_delay_offset() + this->_get_ack_delay_length(); -} - -size_t -QUICAckFrame::_get_ack_block_count_length() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_ack_block_count_offset()); - } else { - return QUICVariableInt::size(this->ack_block_count()); - } -} - -size_t -QUICAckFrame::_get_ack_block_section_offset() const -{ - return this->_get_ack_block_count_offset() + this->_get_ack_block_count_length(); -} - // // QUICAckFrame::PacketNumberRange // @@ -796,53 +778,19 @@ QUICAckFrame::PacketNumberRange::contains(QUICPacketNumber x) const uint64_t QUICAckFrame::AckBlock::gap() const { - if (this->_buf) { - return QUICIntUtil::read_QUICVariableInt(this->_buf); - } else { - return this->_gap; - } + return this->_gap; } uint64_t QUICAckFrame::AckBlock::length() const { - if (this->_buf) { - return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_gap_size()); - } else { - return this->_length; - } + return this->_length; } size_t QUICAckFrame::AckBlock::size() const { - return this->_get_gap_size() + this->_get_length_size(); -} - -const uint8_t * -QUICAckFrame::AckBlock::buf() const -{ - return this->_buf; -} - -size_t -QUICAckFrame::AckBlock::_get_gap_size() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf); - } else { - return QUICVariableInt::size(this->_gap); - } -} - -size_t -QUICAckFrame::AckBlock::_get_length_size() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_gap_size()); - } else { - return QUICVariableInt::size(this->_length); - } + return QUICVariableInt::size(this->_gap) + QUICVariableInt::size(this->_length); } // @@ -851,11 +799,7 @@ QUICAckFrame::AckBlock::_get_length_size() const uint8_t QUICAckFrame::AckBlockSection::count() const { - if (this->_buf) { - return this->_ack_block_count; - } else { - return this->_ack_blocks.size(); - } + return this->_ack_blocks.size(); } size_t @@ -863,7 +807,7 @@ QUICAckFrame::AckBlockSection::size() const { size_t n = 0; - n += this->_get_first_ack_block_size(); + n += QUICVariableInt::size(this->_first_ack_block); for (auto &&block : *this) { n += block.size(); @@ -900,11 +844,7 @@ QUICAckFrame::AckBlockSection::store(uint8_t *buf, size_t *len, size_t limit) co uint64_t QUICAckFrame::AckBlockSection::first_ack_block() const { - if (this->_buf) { - return QUICIntUtil::read_QUICVariableInt(this->_buf); - } else { - return this->_first_ack_block; - } + return this->_first_ack_block; } void @@ -916,46 +856,13 @@ QUICAckFrame::AckBlockSection::add_ack_block(AckBlock block) QUICAckFrame::AckBlockSection::const_iterator QUICAckFrame::AckBlockSection::begin() const { - if (this->_buf) { - return const_iterator(0, this->_buf + this->_get_first_ack_block_size(), this->_ack_block_count); - } else { - return const_iterator(0, &this->_ack_blocks); - } + return const_iterator(0, &this->_ack_blocks); } QUICAckFrame::AckBlockSection::const_iterator QUICAckFrame::AckBlockSection::end() const { - if (this->_buf) { - return const_iterator(this->_ack_block_count, this->_buf, this->_ack_block_count); - } else { - return const_iterator(this->_ack_blocks.size(), &this->_ack_blocks); - } -} - -size_t -QUICAckFrame::AckBlockSection::_get_first_ack_block_size() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf); - } else { - return QUICVariableInt::size(this->_first_ack_block); - } -} - -// -// QUICAckFrame::AckBlockSection::const_iterator -// -QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, const uint8_t *buf, uint8_t ack_block_count) - : _index(index), _buf(buf) -{ - if (index == 0) { - this->_current_block = AckBlock(this->_buf); - } else if (index < ack_block_count) { - this->_current_block = AckBlock(this->_current_block.buf() + this->_current_block.size()); - } else { - this->_current_block = {UINT64_C(0), UINT64_C(0)}; - } + return const_iterator(this->_ack_blocks.size(), &this->_ack_blocks); } QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, const std::vector *ack_blocks) @@ -976,14 +883,10 @@ QUICAckFrame::AckBlockSection::const_iterator::operator++() { ++(this->_index); - if (this->_buf) { - this->_current_block = AckBlock(this->_current_block.buf() + this->_current_block.size()); + if (this->_ack_blocks->size() == this->_index) { + this->_current_block = {UINT64_C(0), UINT64_C(0)}; } else { - if (this->_ack_blocks->size() == this->_index) { - this->_current_block = {UINT64_C(0), UINT64_C(0)}; - } else { - this->_current_block = this->_ack_blocks->at(this->_index); - } + this->_current_block = this->_ack_blocks->at(this->_index); } return this->_current_block; @@ -1001,21 +904,38 @@ QUICAckFrame::AckBlockSection::const_iterator::operator==(const const_iterator & return this->_index == ite._index; } -QUICAckFrame::EcnSection::EcnSection(const uint8_t *buf) +QUICAckFrame::EcnSection::EcnSection(const uint8_t *buf, size_t len) +{ + uint8_t *pos = const_cast(buf); + + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_ect0_count, field_len)) { + return; + } + + if (!read_varint(pos, LEFT_SPACE(pos), this->_ect1_count, field_len)) { + return; + } + + if (!read_varint(pos, LEFT_SPACE(pos), this->_ecn_ce_count, field_len)) { + return; + } + + this->_valid = true; + this->_size = FRAME_SIZE(pos); +} + +bool +QUICAckFrame::EcnSection::valid() const { - size_t ect0_length; - size_t ect1_length; - size_t ecn_ce_length; - QUICVariableInt::decode(this->_ect0_count, ect0_length, buf); - QUICVariableInt::decode(this->_ect1_count, ect1_length, buf + ect0_length); - QUICVariableInt::decode(this->_ecn_ce_count, ecn_ce_length, buf + ect0_length + ect1_length); - this->_section_size = ect0_length + ect1_length + ecn_ce_length; + return this->_valid; } size_t QUICAckFrame::EcnSection::size() const { - return this->_section_size; + return QUICVariableInt::size(this->_ect0_count) + QUICVariableInt::size(this->_ect1_count) + + QUICVariableInt::size(this->_ecn_ce_count); } uint64_t @@ -1046,7 +966,7 @@ QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode { } -QUICRstStreamFrame::QUICRstStreamFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +QUICRstStreamFrame::QUICRstStreamFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } @@ -1074,6 +994,7 @@ QUICRstStreamFrame::parse(const uint8_t *buf, size_t len) } this->_valid = true; + this->_size = FRAME_SIZE(pos); } QUICFrameUPtr @@ -1092,6 +1013,10 @@ QUICRstStreamFrame::type() const size_t QUICRstStreamFrame::size() const { + if (this->_size) { + return this->_size; + } + return 1 + QUICVariableInt::size(this->_stream_id) + sizeof(QUICAppErrorCode) + QUICVariableInt::size(this->_final_offset); } @@ -1102,23 +1027,18 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len, size_t limit) const return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::RST_STREAM); - ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); - p += n; - QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); - p += n; - QUICTypeUtil::write_QUICOffset(this->_final_offset, p, &n); - p += n; + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::RST_STREAM); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); + p += n; + QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); + p += n; + QUICTypeUtil::write_QUICOffset(this->_final_offset, p, &n); + p += n; - *len = p - buf; - } + *len = p - buf; return *len; } @@ -1151,7 +1071,7 @@ QUICPingFrame::clone() const return QUICFrameFactory::create_ping_frame(this->_id, this->_owner); } -QUICPingFrame::QUICPingFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +QUICPingFrame::QUICPingFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } @@ -1160,6 +1080,7 @@ void QUICPingFrame::parse(const uint8_t *buf, size_t len) { this->_valid = true; + this->_size = 1; } QUICFrameType @@ -1189,7 +1110,7 @@ QUICPingFrame::store(uint8_t *buf, size_t *len, size_t limit) const // // PADDING frame // -QUICPaddingFrame::QUICPaddingFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +QUICPaddingFrame::QUICPaddingFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } @@ -1199,6 +1120,7 @@ QUICPaddingFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); this->_valid = true; + this->_size = 1; } QUICFrameUPtr @@ -1251,7 +1173,7 @@ QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, QUICFram { } -QUICConnectionCloseFrame::QUICConnectionCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +QUICConnectionCloseFrame::QUICConnectionCloseFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } @@ -1297,6 +1219,8 @@ QUICConnectionCloseFrame::parse(const uint8_t *buf, size_t len) this->_valid = true; this->_reason_phrase = reinterpret_cast(pos); + pos += this->_reason_phrase_length; + this->_size = FRAME_SIZE(pos); } QUICFrameUPtr @@ -1315,6 +1239,10 @@ QUICConnectionCloseFrame::type() const size_t QUICConnectionCloseFrame::size() const { + if (this->_size) { + return this->_size; + } + return 1 + sizeof(QUICTransErrorCode) + QUICVariableInt::size(sizeof(QUICFrameType)) + QUICVariableInt::size(this->_reason_phrase_length) + this->_reason_phrase_length; } @@ -1332,40 +1260,34 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::CONNECTION_CLOSE); - ++p; - - // Error Code (16) - QUICTypeUtil::write_QUICTransErrorCode(this->_error_code, p, &n); - p += n; + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::CONNECTION_CLOSE); + ++p; - // Frame Type (i) - QUICFrameType frame_type = this->_frame_type; - if (frame_type == QUICFrameType::UNKNOWN) { - frame_type = QUICFrameType::PADDING; - } - *p = static_cast(frame_type); - ++p; + // Error Code (16) + QUICTypeUtil::write_QUICTransErrorCode(this->_error_code, p, &n); + p += n; - // Reason Phrase Length (i) - QUICIntUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); - p += n; + // Frame Type (i) + QUICFrameType frame_type = this->_frame_type; + if (frame_type == QUICFrameType::UNKNOWN) { + frame_type = QUICFrameType::PADDING; + } + *p = static_cast(frame_type); + ++p; - // Reason Phrase (*) - if (this->_reason_phrase_length > 0) { - memcpy(p, this->_reason_phrase, this->_reason_phrase_length); - p += this->_reason_phrase_length; - } + // Reason Phrase Length (i) + QUICIntUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); + p += n; - *len = p - buf; + // Reason Phrase (*) + if (this->_reason_phrase_length > 0) { + memcpy(p, this->_reason_phrase, this->_reason_phrase_length); + p += this->_reason_phrase_length; } + *len = p - buf; return *len; } @@ -1426,7 +1348,7 @@ QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code this->_reason_phrase = reason_phrase; } -QUICApplicationCloseFrame::QUICApplicationCloseFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +QUICApplicationCloseFrame::QUICApplicationCloseFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } @@ -1455,6 +1377,7 @@ QUICApplicationCloseFrame::parse(const uint8_t *buf, size_t len) this->_valid = true; this->_reason_phrase = reinterpret_cast(pos); + this->_size = FRAME_SIZE(pos) + this->_reason_phrase_length; } QUICFrameUPtr @@ -1473,6 +1396,10 @@ QUICApplicationCloseFrame::type() const size_t QUICApplicationCloseFrame::size() const { + if (this->_size) { + return this->_size; + } + return 1 + sizeof(QUICTransErrorCode) + QUICVariableInt::size(this->_reason_phrase_length) + this->_reason_phrase_length; } @@ -1483,26 +1410,20 @@ QUICApplicationCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::APPLICATION_CLOSE); - ++p; - QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); - p += n; - QUICIntUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); - p += n; - if (this->_reason_phrase_length > 0) { - memcpy(p, this->_reason_phrase, this->_reason_phrase_length); - p += this->_reason_phrase_length; - } - - *len = p - buf; + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::APPLICATION_CLOSE); + ++p; + QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); + p += n; + QUICIntUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); + p += n; + if (this->_reason_phrase_length > 0) { + memcpy(p, this->_reason_phrase, this->_reason_phrase_length); + p += this->_reason_phrase_length; } + *len = p - buf; return *len; } @@ -1552,7 +1473,7 @@ QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, QUICFrameId id, QUICFr this->_maximum_data = maximum_data; } -QUICMaxDataFrame::QUICMaxDataFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +QUICMaxDataFrame::QUICMaxDataFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } @@ -1569,6 +1490,7 @@ QUICMaxDataFrame::parse(const uint8_t *buf, size_t len) } this->_valid = true; + this->_size = FRAME_SIZE(pos); } QUICFrameUPtr @@ -1586,6 +1508,10 @@ QUICMaxDataFrame::type() const size_t QUICMaxDataFrame::size() const { + if (this->_size) { + return this->_size; + } + return sizeof(QUICFrameType) + QUICVariableInt::size(this->_maximum_data); } @@ -1596,20 +1522,14 @@ QUICMaxDataFrame::store(uint8_t *buf, size_t *len, size_t limit) const return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::MAX_DATA); - ++p; - QUICTypeUtil::write_QUICMaxData(this->_maximum_data, p, &n); - p += n; - - *len = p - buf; - } + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::MAX_DATA); + ++p; + QUICTypeUtil::write_QUICMaxData(this->_maximum_data, p, &n); + p += n; + *len = p - buf; return *len; } @@ -1636,7 +1556,7 @@ QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t this->_maximum_stream_data = maximum_stream_data; } -QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } @@ -1657,6 +1577,7 @@ QUICMaxStreamDataFrame::parse(const uint8_t *buf, size_t len) } this->_valid = true; + this->_size = FRAME_SIZE(pos); } QUICFrameUPtr @@ -1674,6 +1595,10 @@ QUICMaxStreamDataFrame::type() const size_t QUICMaxStreamDataFrame::size() const { + if (this->_size) { + return this->_size; + } + return sizeof(QUICFrameType) + QUICVariableInt::size(this->_maximum_stream_data) + QUICVariableInt::size(this->_stream_id); } @@ -1683,21 +1608,16 @@ QUICMaxStreamDataFrame::store(uint8_t *buf, size_t *len, size_t limit) const if (limit < this->size()) { return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::MAX_STREAM_DATA); - ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); - p += n; - QUICTypeUtil::write_QUICMaxData(this->_maximum_stream_data, p, &n); - p += n; + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::MAX_STREAM_DATA); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); + p += n; + QUICTypeUtil::write_QUICMaxData(this->_maximum_stream_data, p, &n); + p += n; - *len = p - buf; - } + *len = p - buf; return *len; } @@ -1728,7 +1648,7 @@ QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICF this->_maximum_stream_id = maximum_stream_id; } -QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } @@ -1745,6 +1665,7 @@ QUICMaxStreamIdFrame::parse(const uint8_t *buf, size_t len) } this->_valid = true; + this->_size = FRAME_SIZE(pos); } QUICFrameUPtr @@ -1762,6 +1683,10 @@ QUICMaxStreamIdFrame::type() const size_t QUICMaxStreamIdFrame::size() const { + if (this->_size) { + return this->_size; + } + return sizeof(QUICFrameType) + QUICVariableInt::size(this->_maximum_stream_id); } @@ -1772,19 +1697,14 @@ QUICMaxStreamIdFrame::store(uint8_t *buf, size_t *len, size_t limit) const return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::MAX_STREAM_ID); - ++p; - QUICTypeUtil::write_QUICStreamId(this->_maximum_stream_id, p, &n); - p += n; + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::MAX_STREAM_ID); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_maximum_stream_id, p, &n); + p += n; - *len = p - buf; - } + *len = p - buf; return *len; } @@ -1797,7 +1717,7 @@ QUICMaxStreamIdFrame::maximum_stream_id() const // // BLOCKED frame // -QUICBlockedFrame::QUICBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(nullptr, 0) +QUICBlockedFrame::QUICBlockedFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } @@ -1814,6 +1734,7 @@ QUICBlockedFrame::parse(const uint8_t *buf, size_t len) } this->_valid = true; + this->_size = FRAME_SIZE(pos); } QUICFrameUPtr @@ -1831,7 +1752,11 @@ QUICBlockedFrame::type() const size_t QUICBlockedFrame::size() const { - return sizeof(QUICFrameType) + this->_get_offset_field_length(); + if (this->_size) { + return this->_size; + } + + return sizeof(QUICFrameType) + QUICVariableInt::size(this->offset()); } size_t @@ -1841,20 +1766,15 @@ QUICBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - size_t n; - uint8_t *p = buf; + size_t n; + uint8_t *p = buf; - *p = static_cast(QUICFrameType::BLOCKED); - ++p; - QUICTypeUtil::write_QUICOffset(this->_offset, p, &n); - p += n; + *p = static_cast(QUICFrameType::BLOCKED); + ++p; + QUICTypeUtil::write_QUICOffset(this->_offset, p, &n); + p += n; - *len = p - buf; - } + *len = p - buf; return *len; } @@ -1862,26 +1782,36 @@ QUICBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const QUICOffset QUICBlockedFrame::offset() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICOffset(this->_buf + sizeof(QUICFrameType)); - } else { - return this->_offset; - } -} - -size_t -QUICBlockedFrame::_get_offset_field_length() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); - } else { - return QUICVariableInt::size(this->_offset); - } + return this->_offset; } // // STREAM_BLOCKED frame // +QUICStreamBlockedFrame::QUICStreamBlockedFrame(const uint8_t *buf, size_t len) +{ + this->parse(buf, len); +} + +void +QUICStreamBlockedFrame::parse(const uint8_t *buf, size_t len) +{ + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; + + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_stream_id, field_len)) { + return; + } + + if (!read_varint(pos, LEFT_SPACE(pos), this->_offset, field_len)) { + return; + } + + this->_valid = true; + this->_size = FRAME_SIZE(pos); +} + QUICFrameUPtr QUICStreamBlockedFrame::clone() const { @@ -1897,7 +1827,11 @@ QUICStreamBlockedFrame::type() const size_t QUICStreamBlockedFrame::size() const { - return sizeof(QUICFrameType) + this->_get_stream_id_field_length() + this->_get_offset_field_length(); + if (this->_size) { + return this->_size; + } + + return sizeof(QUICFrameType) + QUICVariableInt::size(this->_offset) + QUICVariableInt::size(this->_stream_id); } size_t @@ -1907,21 +1841,16 @@ QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::STREAM_BLOCKED); - ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); - p += n; - QUICTypeUtil::write_QUICOffset(this->_offset, p, &n); - p += n; + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::STREAM_BLOCKED); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); + p += n; + QUICTypeUtil::write_QUICOffset(this->_offset, p, &n); + p += n; - *len = p - buf; - } + *len = p - buf; return *len; } @@ -1929,52 +1858,38 @@ QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const QUICStreamId QUICStreamBlockedFrame::stream_id() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + sizeof(QUICFrameType)); - } else { - return this->_stream_id; - } + return this->_stream_id; } QUICOffset QUICStreamBlockedFrame::offset() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICOffset(this->_buf + this->_get_offset_field_offset()); - } else { - return this->_offset; - } + return this->_offset; } -size_t -QUICStreamBlockedFrame::_get_stream_id_field_length() const +// +// STREAM_ID_BLOCKED frame +// +QUICStreamIdBlockedFrame::QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len) { - if (this->_buf) { - return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); - } else { - return QUICVariableInt::size(this->_stream_id); - } + this->parse(buf, len); } -size_t -QUICStreamBlockedFrame::_get_offset_field_offset() const +void +QUICStreamIdBlockedFrame::parse(const uint8_t *buf, size_t len) { - return sizeof(QUICFrameType) + this->_get_stream_id_field_length(); -} + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; -size_t -QUICStreamBlockedFrame::_get_offset_field_length() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + this->_get_offset_field_offset()); - } else { - return QUICVariableInt::size(this->_offset); + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_stream_id, field_len)) { + return; } + + this->_valid = true; + this->_size = FRAME_SIZE(pos); } -// -// STREAM_ID_BLOCKED frame -// QUICFrameUPtr QUICStreamIdBlockedFrame::clone() const { @@ -1990,7 +1905,11 @@ QUICStreamIdBlockedFrame::type() const size_t QUICStreamIdBlockedFrame::size() const { - return sizeof(QUICFrameType) + this->_get_stream_id_field_length(); + if (this->_size) { + return this->_size; + } + + return sizeof(QUICFrameType) + QUICVariableInt::size(this->_stream_id); } size_t @@ -2000,47 +1919,66 @@ QUICStreamIdBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - size_t n; - uint8_t *p = buf; - - *p = static_cast(QUICFrameType::STREAM_ID_BLOCKED); - ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); - p += n; + size_t n; + uint8_t *p = buf; - *len = p - buf; - } + *p = static_cast(QUICFrameType::STREAM_ID_BLOCKED); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); + p += n; + *len = p - buf; return *len; } QUICStreamId QUICStreamIdBlockedFrame::stream_id() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + sizeof(QUICFrameType)); - } else { - return this->_stream_id; - } + return this->_stream_id; } -size_t -QUICStreamIdBlockedFrame::_get_stream_id_field_length() const +// +// NEW_CONNECTION_ID frame +// +QUICNewConnectionIdFrame::QUICNewConnectionIdFrame(const uint8_t *buf, size_t len) { - if (this->_buf) { - return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); - } else { - return QUICVariableInt::size(this->_stream_id); + this->parse(buf, len); +} + +void +QUICNewConnectionIdFrame::parse(const uint8_t *buf, size_t len) +{ + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; + + if (LEFT_SPACE(pos) < 1) { + return; + } + + size_t cid_len = *pos; + pos += 1; + + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_sequence, field_len)) { + return; + } + + if (LEFT_SPACE(pos) < cid_len) { + return; } + + this->_connection_id = QUICTypeUtil::read_QUICConnectionId(pos, cid_len); + pos += cid_len; + + if (LEFT_SPACE(pos) < 16) { + return; + } + + this->_stateless_reset_token = QUICStatelessResetToken(pos); + this->_valid = true; + this->_size = FRAME_SIZE(pos) + 16; } -// -// NEW_CONNECTION_ID frame -// QUICFrameUPtr QUICNewConnectionIdFrame::clone() const { @@ -2058,7 +1996,11 @@ QUICNewConnectionIdFrame::type() const size_t QUICNewConnectionIdFrame::size() const { - return sizeof(QUICFrameType) + this->_get_sequence_field_length() + 1 + this->_get_connection_id_length() + 16; + if (this->_size) { + return this->_size; + } + + return sizeof(QUICFrameType) + QUICVariableInt::size(this->_sequence) + 1 + this->_connection_id.length() + 16; } size_t @@ -2068,26 +2010,20 @@ QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len, size_t limit) const return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::NEW_CONNECTION_ID); - ++p; - *p = this->_connection_id.length(); - p += 1; - QUICIntUtil::write_QUICVariableInt(this->_sequence, p, &n); - p += n; - QUICTypeUtil::write_QUICConnectionId(this->_connection_id, p, &n); - p += n; - memcpy(p, this->_stateless_reset_token.buf(), QUICStatelessResetToken::LEN); - p += QUICStatelessResetToken::LEN; - - *len = p - buf; - } + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::NEW_CONNECTION_ID); + ++p; + *p = this->_connection_id.length(); + p += 1; + QUICIntUtil::write_QUICVariableInt(this->_sequence, p, &n); + p += n; + QUICTypeUtil::write_QUICConnectionId(this->_connection_id, p, &n); + p += n; + memcpy(p, this->_stateless_reset_token.buf(), QUICStatelessResetToken::LEN); + p += QUICStatelessResetToken::LEN; + *len = p - buf; return *len; } @@ -2103,68 +2039,54 @@ QUICNewConnectionIdFrame::debug_msg(char *msg, size_t msg_len) const uint64_t QUICNewConnectionIdFrame::sequence() const { - if (this->_buf) { - return QUICIntUtil::read_QUICVariableInt(this->_buf + sizeof(QUICFrameType) + 1); - } else { - return this->_sequence; - } + return this->_sequence; } QUICConnectionId QUICNewConnectionIdFrame::connection_id() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICConnectionId(this->_buf + this->_get_connection_id_field_offset(), - this->_get_connection_id_length()); - } else { - return this->_connection_id; - } + return this->_connection_id; } QUICStatelessResetToken QUICNewConnectionIdFrame::stateless_reset_token() const { - if (this->_buf) { - return QUICStatelessResetToken(this->_buf + this->_get_connection_id_field_offset() + this->_get_connection_id_length()); - } else { - return this->_stateless_reset_token; - } + return this->_stateless_reset_token; } -size_t -QUICNewConnectionIdFrame::_get_sequence_field_length() const +// +// STOP_SENDING frame +// + +QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameId id, + QUICFrameGenerator *owner) + : QUICFrame(id, owner), _stream_id(stream_id), _error_code(error_code) { - if (this->_buf) { - return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType) + 1); - } else { - return QUICVariableInt::size(this->_sequence); - } } -size_t -QUICNewConnectionIdFrame::_get_connection_id_length() const +QUICStopSendingFrame::QUICStopSendingFrame(const uint8_t *buf, size_t len) { - if (this->_buf) { - return this->_buf[sizeof(QUICFrameType)]; - } else { - return this->_connection_id.length(); - } + this->parse(buf, len); } -size_t -QUICNewConnectionIdFrame::_get_connection_id_field_offset() const +void +QUICStopSendingFrame::parse(const uint8_t *buf, size_t len) { - return sizeof(QUICFrameType) + this->_get_sequence_field_length() + 1; -} + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; -// -// STOP_SENDING frame -// + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_stream_id, field_len)) { + return; + } -QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameId id, - QUICFrameGenerator *owner) - : QUICFrame(id, owner), _stream_id(stream_id), _error_code(error_code) -{ + if (LEFT_SPACE(pos) < 2) { + return; + } + + this->_error_code = static_cast(QUICIntUtil::read_nbytes_as_uint(pos, 2)); + this->_valid = true; + this->_size = FRAME_SIZE(pos) + 2; } QUICFrameUPtr @@ -2182,7 +2104,11 @@ QUICStopSendingFrame::type() const size_t QUICStopSendingFrame::size() const { - return sizeof(QUICFrameType) + this->_get_stream_id_field_length() + sizeof(QUICAppErrorCode); + if (this->_size) { + return this->_size; + } + + return sizeof(QUICFrameType) + QUICVariableInt::size(this->_stream_id) + sizeof(QUICAppErrorCode); } size_t @@ -2192,64 +2118,55 @@ QUICStopSendingFrame::store(uint8_t *buf, size_t *len, size_t limit) const return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::STOP_SENDING); - ++p; - QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); - p += n; - QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); - p += n; - - *len = p - buf; - } + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::STOP_SENDING); + ++p; + QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); + p += n; + QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); + p += n; + *len = p - buf; return *len; } QUICAppErrorCode QUICStopSendingFrame::error_code() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICAppErrorCode(this->_buf + this->_get_error_code_field_offset()); - } else { - return this->_error_code; - } + return this->_error_code; } QUICStreamId QUICStopSendingFrame::stream_id() const { - if (this->_buf) { - return QUICTypeUtil::read_QUICStreamId(this->_buf + sizeof(QUICFrameType)); - } else { - return this->_stream_id; - } + return this->_stream_id; } -size_t -QUICStopSendingFrame::_get_stream_id_field_length() const +// +// PATH_CHALLENGE frame +// +QUICPathChallengeFrame::QUICPathChallengeFrame(const uint8_t *buf, size_t len) { - if (this->_buf) { - return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); - } else { - return QUICVariableInt::size(this->_stream_id); - } + this->parse(buf, len); } -size_t -QUICStopSendingFrame::_get_error_code_field_offset() const +void +QUICPathChallengeFrame::parse(const uint8_t *buf, size_t len) { - return sizeof(QUICFrameType) + this->_get_stream_id_field_length(); + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; + + if (LEFT_SPACE(pos) < QUICPathChallengeFrame::DATA_LEN) { + return; + } + + this->_data = ats_unique_malloc(QUICPathChallengeFrame::DATA_LEN); + memcpy(this->_data.get(), pos, QUICPathChallengeFrame::DATA_LEN); + this->_valid = true; + this->_size = FRAME_SIZE(pos) + QUICPathChallengeFrame::DATA_LEN; } -// -// PATH_CHALLENGE frame -// QUICFrameUPtr QUICPathChallengeFrame::clone() const { @@ -2265,7 +2182,11 @@ QUICPathChallengeFrame::type() const size_t QUICPathChallengeFrame::size() const { - return this->_data_offset() + QUICPathChallengeFrame::DATA_LEN; + if (this->_size) { + return this->_size; + } + + return 1 + QUICPathChallengeFrame::DATA_LEN; } bool @@ -2283,12 +2204,8 @@ QUICPathChallengeFrame::store(uint8_t *buf, size_t *len, size_t limit) const *len = this->size(); - if (this->_buf) { - memcpy(buf, this->_buf, *len); - } else { - buf[0] = static_cast(QUICFrameType::PATH_CHALLENGE); - memcpy(buf + this->_data_offset(), this->data(), QUICPathChallengeFrame::DATA_LEN); - } + buf[0] = static_cast(QUICFrameType::PATH_CHALLENGE); + memcpy(buf + 1, this->data(), QUICPathChallengeFrame::DATA_LEN); return *len; } @@ -2296,22 +2213,33 @@ QUICPathChallengeFrame::store(uint8_t *buf, size_t *len, size_t limit) const const uint8_t * QUICPathChallengeFrame::data() const { - if (this->_buf) { - return this->_buf + this->_data_offset(); - } else { - return this->_data.get(); - } -} - -const size_t -QUICPathChallengeFrame::_data_offset() const -{ - return sizeof(QUICFrameType); + return this->_data.get(); } // // PATH_RESPONSE frame // +QUICPathResponseFrame::QUICPathResponseFrame(const uint8_t *buf, size_t len) +{ + this->parse(buf, len); +} + +void +QUICPathResponseFrame::parse(const uint8_t *buf, size_t len) +{ + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; + + if (LEFT_SPACE(pos) < QUICPathChallengeFrame::DATA_LEN) { + return; + } + + this->_data = ats_unique_malloc(QUICPathChallengeFrame::DATA_LEN); + memcpy(this->_data.get(), pos, QUICPathChallengeFrame::DATA_LEN); + this->_valid = true; + this->_size = FRAME_SIZE(pos) + QUICPathChallengeFrame::DATA_LEN; +} + QUICFrameUPtr QUICPathResponseFrame::clone() const { @@ -2327,7 +2255,7 @@ QUICPathResponseFrame::type() const size_t QUICPathResponseFrame::size() const { - return this->_data_offset() + 8; + return 1 + 8; } bool @@ -2345,12 +2273,8 @@ QUICPathResponseFrame::store(uint8_t *buf, size_t *len, size_t limit) const *len = this->size(); - if (this->_buf) { - memcpy(buf, this->_buf, *len); - } else { - buf[0] = static_cast(QUICFrameType::PATH_RESPONSE); - memcpy(buf + this->_data_offset(), this->data(), QUICPathResponseFrame::DATA_LEN); - } + buf[0] = static_cast(QUICFrameType::PATH_RESPONSE); + memcpy(buf + 1, this->data(), QUICPathResponseFrame::DATA_LEN); return *len; } @@ -2358,22 +2282,38 @@ QUICPathResponseFrame::store(uint8_t *buf, size_t *len, size_t limit) const const uint8_t * QUICPathResponseFrame::data() const { - if (this->_buf) { - return this->_buf + this->_data_offset(); - } else { - return this->_data.get(); - } -} - -const size_t -QUICPathResponseFrame::_data_offset() const -{ - return sizeof(QUICFrameType); + return this->_data.get(); } // // QUICNewTokenFrame // +QUICNewTokenFrame::QUICNewTokenFrame(const uint8_t *buf, size_t len) +{ + this->parse(buf, len); +} + +void +QUICNewTokenFrame::parse(const uint8_t *buf, size_t len) +{ + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; + + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_token_length, field_len)) { + return; + } + + if (LEFT_SPACE(pos) < this->_token_length) { + return; + } + + this->_token = ats_unique_malloc(this->_token_length); + memcpy(this->_token.get(), pos, this->_token_length); + this->_valid = true; + this->_size = FRAME_SIZE(pos) + this->_token_length; +} + QUICFrameUPtr QUICNewTokenFrame::clone() const { @@ -2390,7 +2330,11 @@ QUICNewTokenFrame::type() const size_t QUICNewTokenFrame::size() const { - return this->_get_token_field_offset() + this->token_length(); + if (this->_size) { + return this->_size; + } + + return 1 + QUICVariableInt::size(this->_token_length) + this->token_length(); } size_t @@ -2400,76 +2344,60 @@ QUICNewTokenFrame::store(uint8_t *buf, size_t *len, size_t limit) const return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - uint8_t *p = buf; - - // Type (i) - *p = static_cast(QUICFrameType::NEW_TOKEN); - ++p; + uint8_t *p = buf; - // Token Length (i) - size_t n; - QUICIntUtil::write_QUICVariableInt(this->_token_length, p, &n); - p += n; + // Type (i) + *p = static_cast(QUICFrameType::NEW_TOKEN); + ++p; - // Token (*) - memcpy(p, this->token(), this->token_length()); - p += this->token_length(); + // Token Length (i) + size_t n; + QUICIntUtil::write_QUICVariableInt(this->_token_length, p, &n); + p += n; - *len = p - buf; - } + // Token (*) + memcpy(p, this->token(), this->token_length()); + p += this->token_length(); + *len = p - buf; return *len; } uint64_t QUICNewTokenFrame::token_length() const { - if (this->_buf) { - return QUICIntUtil::read_QUICVariableInt(this->_buf + this->_get_token_length_field_offset()); - } else { - return this->_token_length; - } + return this->_token_length; } const uint8_t * QUICNewTokenFrame::token() const { - if (this->_buf) { - return this->_buf + this->_get_token_field_offset(); - } else { - return this->_token.get(); - } + return this->_token.get(); } -size_t -QUICNewTokenFrame::_get_token_length_field_offset() const +// +// RETIRE_CONNECTION_ID frame +// +QUICRetireConnectionIdFrame::QUICRetireConnectionIdFrame(const uint8_t *buf, size_t len) { - return sizeof(QUICFrameType); + this->parse(buf, len); } -size_t -QUICNewTokenFrame::_get_token_length_field_length() const +void +QUICRetireConnectionIdFrame::parse(const uint8_t *buf, size_t len) { - if (this->_buf) { - return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); - } else { - return QUICVariableInt::size(this->_token_length); + ink_assert(len >= 1); + uint8_t *pos = const_cast(buf) + 1; + + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_seq_num, field_len)) { + return; } -} -size_t -QUICNewTokenFrame::_get_token_field_offset() const -{ - return sizeof(QUICFrameType) + this->_get_token_length_field_length(); + this->_valid = true; + this->_size = FRAME_SIZE(pos); } -// -// RETIRE_CONNECTION_ID frame -// QUICFrameUPtr QUICRetireConnectionIdFrame::clone() const { @@ -2485,7 +2413,11 @@ QUICRetireConnectionIdFrame::type() const size_t QUICRetireConnectionIdFrame::size() const { - return sizeof(QUICFrameType) + this->_get_seq_num_field_length(); + if (this->_size) { + return this->_size; + } + + return sizeof(QUICFrameType) + QUICVariableInt::size(this->_seq_num); } size_t @@ -2495,19 +2427,14 @@ QUICRetireConnectionIdFrame::store(uint8_t *buf, size_t *len, size_t limit) cons return 0; } - if (this->_buf) { - *len = this->size(); - memcpy(buf, this->_buf, *len); - } else { - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::RETIRE_CONNECTION_ID); - ++p; - QUICIntUtil::write_QUICVariableInt(this->_seq_num, p, &n); - p += n; + size_t n; + uint8_t *p = buf; + *p = static_cast(QUICFrameType::RETIRE_CONNECTION_ID); + ++p; + QUICIntUtil::write_QUICVariableInt(this->_seq_num, p, &n); + p += n; - *len = p - buf; - } + *len = p - buf; return *len; } @@ -2521,21 +2448,7 @@ QUICRetireConnectionIdFrame::debug_msg(char *msg, size_t msg_len) const uint64_t QUICRetireConnectionIdFrame::seq_num() const { - if (this->_buf) { - return QUICIntUtil::read_QUICVariableInt(this->_buf + sizeof(QUICFrameType)); - } else { - return this->_seq_num; - } -} - -size_t -QUICRetireConnectionIdFrame::_get_seq_num_field_length() const -{ - if (this->_buf) { - return QUICVariableInt::size(this->_buf + sizeof(QUICFrameType)); - } else { - return QUICVariableInt::size(this->_seq_num); - } + return this->_seq_num; } // diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index eb500fad95b..62ed3c291ff 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -51,7 +51,6 @@ using QUICFrameId = uint64_t; class QUICFrame { public: - QUICFrame(const uint8_t *buf, size_t len) : _buf(buf), _len(len) {} virtual ~QUICFrame() {} static QUICFrameType type(const uint8_t *buf); @@ -76,8 +75,7 @@ class QUICFrame protected: QUICFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : _id(id), _owner(owner) {} - const uint8_t *_buf = nullptr; - size_t _len = 0; + size_t _size = 0; bool _valid = false; const QUICFrameId _id = 0; QUICFrameGenerator *_owner = nullptr; @@ -186,22 +184,18 @@ class QUICAckFrame : public QUICFrame class AckBlock { public: - AckBlock(const uint8_t *b) : _buf(b) {} AckBlock(uint64_t g, uint64_t l) : _gap(g), _length(l) {} uint64_t gap() const; uint64_t length() const; size_t size() const; - const uint8_t *buf() const; - LINK(QUICAckFrame::AckBlock, link); private: size_t _get_gap_size() const; size_t _get_length_size() const; - const uint8_t *_buf = nullptr; - uint64_t _gap = 0; - uint64_t _length = 0; + uint64_t _gap = 0; + uint64_t _length = 0; }; class AckBlockSection @@ -210,7 +204,6 @@ class QUICAckFrame : public QUICFrame class const_iterator : public std::iterator { public: - const_iterator(uint8_t index, const uint8_t *buf, uint8_t ack_block_count); const_iterator(uint8_t index, const std::vector *ack_blocks); const QUICAckFrame::AckBlock &operator*() const { return this->_current_block; }; @@ -238,8 +231,6 @@ class QUICAckFrame : public QUICFrame bool has_protected() const; private: - size_t _get_first_ack_block_size() const; - const uint8_t *_buf = nullptr; uint64_t _first_ack_block = 0; uint8_t _ack_block_count = 0; @@ -249,14 +240,16 @@ class QUICAckFrame : public QUICFrame class EcnSection { public: - EcnSection(const uint8_t *buf); + EcnSection(const uint8_t *buf, size_t len); size_t size() const; + bool valid() const; uint64_t ect0_count() const; uint64_t ect1_count() const; uint64_t ecn_ce_count() const; private: - uint64_t _section_size = 0; + bool _valid = false; + size_t _size = 0; uint64_t _ect0_count = 0; uint64_t _ect1_count = 0; uint64_t _ecn_ce_count = 0; @@ -268,11 +261,11 @@ class QUICAckFrame : public QUICFrame QUICFrameGenerator *owner = nullptr); virtual ~QUICAckFrame(); - virtual void reset(const uint8_t *buf, size_t len) override; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void parse(const uint8_t *buf, size_t len) override; virtual int debug_msg(char *msg, size_t msg_len) const override; QUICPacketNumber largest_acknowledged() const; @@ -284,14 +277,6 @@ class QUICAckFrame : public QUICFrame EcnSection *ecn_section(); private: - size_t _get_largest_acknowledged_offset() const; - size_t _get_largest_acknowledged_length() const; - size_t _get_ack_delay_offset() const; - size_t _get_ack_delay_length() const; - size_t _get_ack_block_count_offset() const; - size_t _get_ack_block_count_length() const; - size_t _get_ack_block_section_offset() const; - QUICPacketNumber _largest_acknowledged = 0; uint64_t _ack_delay = 0; AckBlockSection *_ack_block_section = nullptr; @@ -351,7 +336,7 @@ class QUICPingFrame : public QUICFrame class QUICPaddingFrame : public QUICFrame { public: - QUICPaddingFrame() : QUICFrame() {} + QUICPaddingFrame() {} QUICPaddingFrame(const uint8_t *buf, size_t len); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; @@ -486,8 +471,6 @@ class QUICMaxStreamIdFrame : public QUICFrame QUICStreamId maximum_stream_id() const; private: - size_t _get_max_stream_id_field_length() const; - QUICStreamId _maximum_stream_id = 0; }; @@ -511,8 +494,6 @@ class QUICBlockedFrame : public QUICFrame QUICOffset offset() const; private: - size_t _get_offset_field_length() const; - QUICOffset _offset = 0; }; @@ -524,7 +505,7 @@ class QUICStreamBlockedFrame : public QUICFrame { public: QUICStreamBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICStreamBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICStreamBlockedFrame(const uint8_t *buf, size_t len); QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _stream_id(s), _offset(o){}; @@ -532,15 +513,12 @@ class QUICStreamBlockedFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void parse(const uint8_t *buf, size_t len) override; QUICStreamId stream_id() const; QUICOffset offset() const; private: - size_t _get_stream_id_field_length() const; - size_t _get_offset_field_offset() const; - size_t _get_offset_field_length() const; - QUICStreamId _stream_id = 0; QUICOffset _offset = 0; }; @@ -552,7 +530,7 @@ class QUICStreamIdBlockedFrame : public QUICFrame { public: QUICStreamIdBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len); QUICStreamIdBlockedFrame(QUICStreamId s, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _stream_id(s) { @@ -561,12 +539,11 @@ class QUICStreamIdBlockedFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void parse(const uint8_t *buf, size_t len) override; QUICStreamId stream_id() const; private: - size_t _get_stream_id_field_length() const; - QUICStreamId _stream_id = 0; }; @@ -578,7 +555,7 @@ class QUICNewConnectionIdFrame : public QUICFrame { public: QUICNewConnectionIdFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICNewConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICNewConnectionIdFrame(const uint8_t *buf, size_t len); QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId cid, QUICStatelessResetToken token, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _sequence(seq), _connection_id(cid), _stateless_reset_token(token){}; @@ -587,6 +564,7 @@ class QUICNewConnectionIdFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void parse(const uint8_t *buf, size_t len) override; virtual int debug_msg(char *msg, size_t msg_len) const override; uint64_t sequence() const; @@ -594,10 +572,6 @@ class QUICNewConnectionIdFrame : public QUICFrame QUICStatelessResetToken stateless_reset_token() const; private: - size_t _get_sequence_field_length() const; - size_t _get_connection_id_field_offset() const; - size_t _get_connection_id_length() const; - uint64_t _sequence = 0; QUICConnectionId _connection_id = QUICConnectionId::ZERO(); QUICStatelessResetToken _stateless_reset_token; @@ -611,22 +585,20 @@ class QUICStopSendingFrame : public QUICFrame { public: QUICStopSendingFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICStopSendingFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICStopSendingFrame(const uint8_t *buf, size_t len); QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; + virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICStreamId stream_id() const; QUICAppErrorCode error_code() const; private: - size_t _get_stream_id_field_length() const; - size_t _get_error_code_field_offset() const; - QUICStreamId _stream_id = 0; QUICAppErrorCode _error_code = 0; }; @@ -640,7 +612,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) : QUICFrame(buf, len) {} + QUICPathChallengeFrame(const uint8_t *buf, size_t len); QUICPathChallengeFrame(ats_unique_buf data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _data(std::move(data)) { @@ -649,13 +621,12 @@ class QUICPathChallengeFrame : public QUICFrame 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) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; const uint8_t *data() const; private: - const size_t _data_offset() const; - ats_unique_buf _data = {nullptr}; }; @@ -668,7 +639,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) : QUICFrame(buf, len) {} + QUICPathResponseFrame(const uint8_t *buf, size_t len); QUICPathResponseFrame(ats_unique_buf data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _data(std::move(data)) { @@ -677,13 +648,12 @@ class QUICPathResponseFrame : public QUICFrame 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) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; const uint8_t *data() const; private: - const size_t _data_offset() const; - ats_unique_buf _data = {nullptr}; }; @@ -695,7 +665,7 @@ class QUICNewTokenFrame : public QUICFrame { public: QUICNewTokenFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICNewTokenFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICNewTokenFrame(const uint8_t *buf, size_t len); 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)) { @@ -704,15 +674,12 @@ class QUICNewTokenFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void parse(const uint8_t *buf, size_t len) override; uint64_t token_length() const; const uint8_t *token() const; private: - size_t _get_token_length_field_offset() const; - size_t _get_token_length_field_length() const; - size_t _get_token_field_offset() const; - uint64_t _token_length = 0; ats_unique_buf _token = {nullptr}; }; @@ -725,7 +692,7 @@ class QUICRetireConnectionIdFrame : public QUICFrame { public: QUICRetireConnectionIdFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICRetireConnectionIdFrame(const uint8_t *buf, size_t len) : QUICFrame(buf, len) {} + QUICRetireConnectionIdFrame(const uint8_t *buf, size_t len); QUICRetireConnectionIdFrame(uint64_t seq_num, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _seq_num(seq_num) { @@ -734,13 +701,12 @@ class QUICRetireConnectionIdFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void parse(const uint8_t *buf, size_t len) override; virtual int debug_msg(char *msg, size_t msg_len) const override; uint64_t seq_num() const; private: - size_t _get_seq_num_field_length() const; - uint64_t _seq_num = 0; }; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 3c1c9b7e465..b26658f9cf6 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -527,6 +527,36 @@ TEST_CASE("Load Ack Frame 1", "[quic]") CHECK(ite == section->end()); } + SECTION("load bad frame") + { + uint8_t buf1[] = { + 0x1a, // Type + 0x12, // Largest Acknowledged + }; + + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::ACK); + CHECK(frame1->valid() == false); + } + + SECTION("load bad block") + { + uint8_t buf1[] = { + 0x1a, // Type + 0x12, // Largest Acknowledged + 0x74, 0x56, // Ack Delay + 0x02, // Ack Block Count + 0x01, // Ack Block Section (First ACK Block Length) + 0x02, // Ack Block Section (Gap 1) + 0x43, 0x04, // Ack Block Section (ACK Block 1 Length) + 0x85, 0x06, 0x07, 0x08, // Ack Block Section (Gap 2) + }; + + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::ACK); + CHECK(frame1->valid() == false); + } + SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length with ECN section") { uint8_t buf1[] = { @@ -553,6 +583,23 @@ TEST_CASE("Load Ack Frame 1", "[quic]") CHECK(ack_frame1->ecn_section()->ect1_count() == 2); CHECK(ack_frame1->ecn_section()->ecn_ce_count() == 3); } + + SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length with ECN section") + { + uint8_t buf1[] = { + 0x1b, // Type + 0x12, // Largest Acknowledged + 0x74, 0x56, // Ack Delay + 0x00, // Ack Block Count + 0x00, // Ack Block Section + // ECN + 0x01, // ECT0 + 0x02, // ECT1 + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::ACK); + CHECK(frame1->valid() == false); + } } TEST_CASE("Store Ack Frame", "[quic]") @@ -1117,19 +1164,33 @@ TEST_CASE("Store Blocked Frame", "[quic]") TEST_CASE("Load StreamBlocked Frame", "[quic]") { - uint8_t buf1[] = { - 0x09, // Type - 0x81, 0x02, 0x03, 0x04, // Stream ID - 0x07, // Offset - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::STREAM_BLOCKED); - CHECK(frame1->size() == 6); - std::shared_ptr stream_blocked_frame = - std::dynamic_pointer_cast(frame1); - CHECK(stream_blocked_frame != nullptr); - CHECK(stream_blocked_frame->stream_id() == 0x01020304); - CHECK(stream_blocked_frame->offset() == 0x07); + SECTION("Load") + { + uint8_t buf1[] = { + 0x09, // Type + 0x81, 0x02, 0x03, 0x04, // Stream ID + 0x07, // Offset + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM_BLOCKED); + CHECK(frame1->size() == 6); + std::shared_ptr stream_blocked_frame = + std::dynamic_pointer_cast(frame1); + CHECK(stream_blocked_frame != nullptr); + CHECK(stream_blocked_frame->stream_id() == 0x01020304); + CHECK(stream_blocked_frame->offset() == 0x07); + } + + SECTION("Load") + { + uint8_t buf1[] = { + 0x09, // Type + 0x81, 0x02, 0x03, 0x04, // Stream ID + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM_BLOCKED); + CHECK(frame1->valid() == false); + } } TEST_CASE("Store StreamBlocked Frame", "[quic]") @@ -1152,17 +1213,30 @@ TEST_CASE("Store StreamBlocked Frame", "[quic]") TEST_CASE("Load StreamIdBlocked Frame", "[quic]") { - uint8_t buf1[] = { - 0x0a, // Type - 0x41, 0x02, // Stream ID - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::STREAM_ID_BLOCKED); - CHECK(frame1->size() == 3); - std::shared_ptr stream_id_blocked_frame = - std::dynamic_pointer_cast(frame1); - CHECK(stream_id_blocked_frame != nullptr); - CHECK(stream_id_blocked_frame->stream_id() == 0x0102); + SECTION("Load") + { + uint8_t buf1[] = { + 0x0a, // Type + 0x41, 0x02, // Stream ID + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM_ID_BLOCKED); + CHECK(frame1->size() == 3); + std::shared_ptr stream_id_blocked_frame = + std::dynamic_pointer_cast(frame1); + CHECK(stream_id_blocked_frame != nullptr); + CHECK(stream_id_blocked_frame->stream_id() == 0x0102); + } + + SECTION("Load") + { + uint8_t buf1[] = { + 0x0a, // Type + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::STREAM_ID_BLOCKED); + CHECK(frame1->valid() == false); + } } TEST_CASE("Store StreamIdBlocked Frame", "[quic]") @@ -1184,24 +1258,41 @@ TEST_CASE("Store StreamIdBlocked Frame", "[quic]") TEST_CASE("Load NewConnectionId Frame", "[quic]") { - uint8_t buf1[] = { - 0x0b, // Type - 0x08, // Length - 0x41, 0x02, // Sequence - 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID - 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token - 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::NEW_CONNECTION_ID); - CHECK(frame1->size() == 28); - std::shared_ptr new_con_id_frame = - std::dynamic_pointer_cast(frame1); - CHECK(new_con_id_frame != nullptr); - CHECK(new_con_id_frame->sequence() == 0x0102); - CHECK((new_con_id_frame->connection_id() == - QUICConnectionId(reinterpret_cast("\x11\x22\x33\x44\x55\x66\x77\x88"), 8))); - CHECK(memcmp(new_con_id_frame->stateless_reset_token().buf(), buf1 + 12, 16) == 0); + SECTION("load") + { + uint8_t buf1[] = { + 0x0b, // Type + 0x08, // Length + 0x41, 0x02, // Sequence + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token + 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::NEW_CONNECTION_ID); + CHECK(frame1->size() == 28); + std::shared_ptr new_con_id_frame = + std::dynamic_pointer_cast(frame1); + CHECK(new_con_id_frame != nullptr); + CHECK(new_con_id_frame->sequence() == 0x0102); + CHECK((new_con_id_frame->connection_id() == + QUICConnectionId(reinterpret_cast("\x11\x22\x33\x44\x55\x66\x77\x88"), 8))); + CHECK(memcmp(new_con_id_frame->stateless_reset_token().buf(), buf1 + 12, 16) == 0); + } + + SECTION("Bad Load") + { + uint8_t buf1[] = { + 0x0b, // Type + 0x08, // Length + 0x41, 0x02, // Sequence + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token + }; + std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == QUICFrameType::NEW_CONNECTION_ID); + CHECK(frame1->valid() == false); + } } TEST_CASE("Store NewConnectionId Frame", "[quic]") @@ -1228,19 +1319,33 @@ TEST_CASE("Store NewConnectionId Frame", "[quic]") TEST_CASE("Load STOP_SENDING Frame", "[quic]") { - uint8_t buf[] = { - 0x0c, // Type - 0x92, 0x34, 0x56, 0x78, // Stream ID - 0x00, 0x01, // Error Code - }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); - CHECK(frame->type() == QUICFrameType::STOP_SENDING); - CHECK(frame->size() == 7); + SECTION("LOAD") + { + uint8_t buf[] = { + 0x0c, // Type + 0x92, 0x34, 0x56, 0x78, // Stream ID + 0x00, 0x01, // Error Code + }; + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::STOP_SENDING); + CHECK(frame->size() == 7); + + std::shared_ptr stop_sending_frame = std::dynamic_pointer_cast(frame); + CHECK(stop_sending_frame != nullptr); + CHECK(stop_sending_frame->stream_id() == 0x12345678); + CHECK(stop_sending_frame->error_code() == 0x0001); + } - std::shared_ptr stop_sending_frame = std::dynamic_pointer_cast(frame); - CHECK(stop_sending_frame != nullptr); - CHECK(stop_sending_frame->stream_id() == 0x12345678); - CHECK(stop_sending_frame->error_code() == 0x0001); + SECTION("Bad LOAD") + { + uint8_t buf[] = { + 0x0c, // Type + 0x92, 0x34, 0x56, 0x78, // Stream ID + }; + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::STOP_SENDING); + CHECK(frame->valid() == false); + } } TEST_CASE("Store STOP_SENDING Frame", "[quic]") @@ -1263,18 +1368,32 @@ TEST_CASE("Store STOP_SENDING Frame", "[quic]") TEST_CASE("Load PATH_CHALLENGE Frame", "[quic]") { - uint8_t buf[] = { - 0x0e, // Type - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data - }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); - CHECK(frame->type() == QUICFrameType::PATH_CHALLENGE); - CHECK(frame->size() == 9); + SECTION("Load") + { + uint8_t buf[] = { + 0x0e, // Type + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + }; + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::PATH_CHALLENGE); + CHECK(frame->size() == 9); + + std::shared_ptr path_challenge_frame = + std::dynamic_pointer_cast(frame); + CHECK(path_challenge_frame != nullptr); + CHECK(memcmp(path_challenge_frame->data(), "\x01\x23\x45\x67\x89\xab\xcd\xef", QUICPathChallengeFrame::DATA_LEN) == 0); + } - std::shared_ptr path_challenge_frame = - std::dynamic_pointer_cast(frame); - CHECK(path_challenge_frame != nullptr); - CHECK(memcmp(path_challenge_frame->data(), "\x01\x23\x45\x67\x89\xab\xcd\xef", QUICPathChallengeFrame::DATA_LEN) == 0); + SECTION("Load") + { + uint8_t buf[] = { + 0x0e, // Type + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xef, // Data + }; + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::PATH_CHALLENGE); + CHECK(frame->valid() == false); + } } TEST_CASE("Store PATH_CHALLENGE Frame", "[quic]") @@ -1302,17 +1421,32 @@ TEST_CASE("Store PATH_CHALLENGE Frame", "[quic]") TEST_CASE("Load PATH_RESPONSE Frame", "[quic]") { - uint8_t buf[] = { - 0x0f, // Type - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data - }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); - CHECK(frame->type() == QUICFrameType::PATH_RESPONSE); - CHECK(frame->size() == 9); + SECTION("Load") + { + uint8_t buf[] = { + 0x0f, // Type + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + }; + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::PATH_RESPONSE); + CHECK(frame->size() == 9); + + std::shared_ptr path_response_frame = + std::dynamic_pointer_cast(frame); + CHECK(path_response_frame != nullptr); + CHECK(memcmp(path_response_frame->data(), "\x01\x23\x45\x67\x89\xab\xcd\xef", QUICPathResponseFrame::DATA_LEN) == 0); + } - std::shared_ptr path_response_frame = std::dynamic_pointer_cast(frame); - CHECK(path_response_frame != nullptr); - CHECK(memcmp(path_response_frame->data(), "\x01\x23\x45\x67\x89\xab\xcd\xef", QUICPathResponseFrame::DATA_LEN) == 0); + SECTION("Load") + { + uint8_t buf[] = { + 0x0f, // Type + 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data + }; + std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == QUICFrameType::PATH_RESPONSE); + CHECK(frame->valid() == false); + } } TEST_CASE("Store PATH_RESPONSE Frame", "[quic]") @@ -1362,6 +1496,13 @@ TEST_CASE("NEW_TOKEN Frame", "[quic]") CHECK(memcmp(new_token_frame->token(), raw_token, raw_token_len) == 0); } + SECTION("bad load") + { + std::shared_ptr frame = QUICFrameFactory::create(raw_new_token_frame, raw_new_token_frame_len - 5); + CHECK(frame->type() == QUICFrameType::NEW_TOKEN); + CHECK(frame->valid() == false); + } + SECTION("store") { uint8_t buf[32]; @@ -1401,6 +1542,14 @@ TEST_CASE("RETIRE_CONNECTION_ID Frame", "[quic]") CHECK(retire_connection_id_frame->seq_num() == seq_num); } + SECTION("bad load") + { + std::shared_ptr frame = + QUICFrameFactory::create(raw_retire_connection_id_frame, raw_retire_connection_id_frame_len - 1); + CHECK(frame->type() == QUICFrameType::RETIRE_CONNECTION_ID); + CHECK(frame->valid() == false); + } + SECTION("store") { uint8_t buf[32]; From 49c7ac1c5796edbe7fb2a6e55125094cf8a0b05a Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 22 Dec 2018 15:35:22 +0800 Subject: [PATCH 0982/1313] QUIC: reset a frame when fast_create --- iocore/net/quic/QUICFrame.cc | 233 +++++++++++++++++++++++++++++++++-- iocore/net/quic/QUICFrame.h | 28 +++-- 2 files changed, 246 insertions(+), 15 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 737a31b48eb..433e4b10460 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -112,12 +112,6 @@ QUICFrame::type(const uint8_t *buf) } } -void -QUICFrame::reset(const uint8_t *buf, size_t len) -{ - ink_assert(0); -} - int QUICFrame::debug_msg(char *msg, size_t msg_len) const { @@ -196,6 +190,22 @@ QUICStreamFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos); } +void +QUICStreamFrame::reset() +{ + this->_data = nullptr; + this->_fin = false; + this->_has_length_field = true; + this->_has_offset_field = true; + this->_offset = 0; + this->_data_len = 0; + this->_stream_id = 0; + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + QUICFrame * QUICStreamFrame::split(size_t size) { @@ -428,6 +438,17 @@ QUICCryptoFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos); } +void +QUICCryptoFrame::reset() +{ + this->_data = nullptr; + this->_offset = 0; + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + QUICFrame * QUICCryptoFrame::split(size_t size) { @@ -450,8 +471,6 @@ QUICCryptoFrame::split(size_t size) this->_data_len = data_len; this->_data = std::move(buf); - this->reset(nullptr, 0); - QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); new (frame) QUICCryptoFrame(std::move(buf2), buf2_len, this->offset() + this->data_length(), this->_id, this->_owner); @@ -601,6 +620,26 @@ QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_d this->_ack_block_section = new AckBlockSection(first_ack_block); } +void +QUICAckFrame::reset() +{ + if (this->_ack_block_section) { + delete this->_ack_block_section; + this->_ack_block_section = nullptr; + } + if (this->_ecn_section) { + delete this->_ecn_section; + this->_ecn_section = nullptr; + } + + this->_largest_acknowledged = 0; + this->_ack_delay = 0; + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + QUICAckFrame::~QUICAckFrame() { if (this->_ack_block_section) { @@ -997,6 +1036,19 @@ QUICRstStreamFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos); } +void +QUICRstStreamFrame::reset() +{ + this->_stream_id = 0; + this->_error_code = 0; + this->_final_offset = 0; + + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + QUICFrameUPtr QUICRstStreamFrame::clone() const { @@ -1178,6 +1230,20 @@ QUICConnectionCloseFrame::QUICConnectionCloseFrame(const uint8_t *buf, size_t le this->parse(buf, len); } +void +QUICConnectionCloseFrame::reset() +{ + this->_error_code = 0; + this->_reason_phrase_length = 0; + this->_reason_phrase = nullptr; + this->_frame_type = QUICFrameType::UNKNOWN; + + this->_owner = nullptr; + this->_id = 0; + this->_size = 0; + this->_valid = false; +} + void QUICConnectionCloseFrame::parse(const uint8_t *buf, size_t len) { @@ -1353,6 +1419,19 @@ QUICApplicationCloseFrame::QUICApplicationCloseFrame(const uint8_t *buf, size_t this->parse(buf, len); } +void +QUICApplicationCloseFrame::reset() +{ + this->_error_code = 0; + this->_reason_phrase_length = 0; + this->_reason_phrase = nullptr; + + this->_owner = nullptr; + this->_id = 0; + this->_size = 0; + this->_valid = false; +} + void QUICApplicationCloseFrame::parse(const uint8_t *buf, size_t len) { @@ -1473,6 +1552,17 @@ QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, QUICFrameId id, QUICFr this->_maximum_data = maximum_data; } +void +QUICMaxDataFrame::reset() +{ + this->_maximum_data = 0; + + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + QUICMaxDataFrame::QUICMaxDataFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); @@ -1556,6 +1646,18 @@ QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t this->_maximum_stream_data = maximum_stream_data; } +void +QUICMaxStreamDataFrame::reset() +{ + this->_stream_id = 0; + this->_maximum_stream_data = 0; + + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); @@ -1648,6 +1750,17 @@ QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICF this->_maximum_stream_id = maximum_stream_id; } +void +QUICMaxStreamIdFrame::reset() +{ + this->_maximum_stream_id = 0; + + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); @@ -1722,6 +1835,17 @@ QUICBlockedFrame::QUICBlockedFrame(const uint8_t *buf, size_t len) this->parse(buf, len); } +void +QUICBlockedFrame::reset() +{ + this->_offset = 0; + + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + void QUICBlockedFrame::parse(const uint8_t *buf, size_t len) { @@ -1793,6 +1917,18 @@ QUICStreamBlockedFrame::QUICStreamBlockedFrame(const uint8_t *buf, size_t len) this->parse(buf, len); } +void +QUICStreamBlockedFrame::reset() +{ + this->_stream_id = 0; + this->_offset = 0; + + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + void QUICStreamBlockedFrame::parse(const uint8_t *buf, size_t len) { @@ -1875,6 +2011,17 @@ QUICStreamIdBlockedFrame::QUICStreamIdBlockedFrame(const uint8_t *buf, size_t le this->parse(buf, len); } +void +QUICStreamIdBlockedFrame::reset() +{ + this->_stream_id = 0; + + this->_owner = nullptr; + this->_id = 0; + this->_size = 0; + this->_valid = false; +} + void QUICStreamIdBlockedFrame::parse(const uint8_t *buf, size_t len) { @@ -1945,6 +2092,19 @@ QUICNewConnectionIdFrame::QUICNewConnectionIdFrame(const uint8_t *buf, size_t le this->parse(buf, len); } +void +QUICNewConnectionIdFrame::reset() +{ + this->_sequence = 0; + this->_connection_id = QUICConnectionId::ZERO(); + memset(&this->_stateless_reset_token, 0, sizeof(QUICStatelessResetToken)); + + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + void QUICNewConnectionIdFrame::parse(const uint8_t *buf, size_t len) { @@ -2064,6 +2224,18 @@ QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorC { } +void +QUICStopSendingFrame::reset() +{ + this->_stream_id = 0; + this->_error_code = 0; + + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + QUICStopSendingFrame::QUICStopSendingFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); @@ -2151,6 +2323,16 @@ QUICPathChallengeFrame::QUICPathChallengeFrame(const uint8_t *buf, size_t len) this->parse(buf, len); } +void +QUICPathChallengeFrame::reset() +{ + this->_data = nullptr; + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + void QUICPathChallengeFrame::parse(const uint8_t *buf, size_t len) { @@ -2224,6 +2406,16 @@ QUICPathResponseFrame::QUICPathResponseFrame(const uint8_t *buf, size_t len) this->parse(buf, len); } +void +QUICPathResponseFrame::reset() +{ + this->_data = nullptr; + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + void QUICPathResponseFrame::parse(const uint8_t *buf, size_t len) { @@ -2293,6 +2485,18 @@ QUICNewTokenFrame::QUICNewTokenFrame(const uint8_t *buf, size_t len) this->parse(buf, len); } +void +QUICNewTokenFrame::reset() +{ + this->_token = nullptr; + this->_token_length = 0; + + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; +} + void QUICNewTokenFrame::parse(const uint8_t *buf, size_t len) { @@ -2383,6 +2587,18 @@ QUICRetireConnectionIdFrame::QUICRetireConnectionIdFrame(const uint8_t *buf, siz this->parse(buf, len); } +void +QUICRetireConnectionIdFrame::reset() +{ + this->_seq_num = 0; + + this->_owner = nullptr; + this->_id = 0; + this->_valid = false; + this->_size = 0; + this->_size = 0; +} + void QUICRetireConnectionIdFrame::parse(const uint8_t *buf, size_t len) { @@ -2631,6 +2847,7 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) this->_reusable_frames[static_cast(QUICFrame::type(buf))] = frame; } } else { + frame->reset(); frame->parse(buf, len); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 62ed3c291ff..7efa9eea117 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -61,14 +61,10 @@ class QUICFrame virtual size_t size() const = 0; virtual bool is_probing_frame() const; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const = 0; - virtual void reset(const uint8_t *buf, size_t len); + virtual void reset(){}; virtual QUICFrame *split(size_t size); virtual int debug_msg(char *msg, size_t msg_len) const; - virtual void - parse(const uint8_t *buf, size_t len) - { - this->reset(buf, len); - } + virtual void parse(const uint8_t *buf, size_t len){}; virtual QUICFrameGenerator *generated_by(); bool valid() const; LINK(QUICFrame, link); @@ -77,7 +73,7 @@ class QUICFrame QUICFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : _id(id), _owner(owner) {} size_t _size = 0; bool _valid = false; - const QUICFrameId _id = 0; + QUICFrameId _id = 0; QUICFrameGenerator *_owner = nullptr; }; @@ -101,6 +97,7 @@ class QUICStreamFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, 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) override; + virtual void reset() override; size_t store(uint8_t *buf, size_t *len, size_t limit, bool include_length_field) const; QUICStreamId stream_id() const; @@ -141,6 +138,7 @@ class QUICCryptoFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, 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) override; + virtual void reset() override; QUICOffset offset() const; uint64_t data_length() const; @@ -267,6 +265,7 @@ class QUICAckFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual int debug_msg(char *msg, size_t msg_len) const override; + virtual void reset() override; QUICPacketNumber largest_acknowledged() const; uint64_t ack_delay() const; @@ -300,6 +299,7 @@ class QUICRstStreamFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; + virtual void reset() override; QUICStreamId stream_id() const; QUICAppErrorCode error_code() const; @@ -363,6 +363,7 @@ class QUICConnectionCloseFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, 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) override; + virtual void reset() override; uint16_t error_code() const; QUICFrameType frame_type() const; @@ -393,6 +394,7 @@ class QUICApplicationCloseFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; + virtual void reset() override; QUICAppErrorCode error_code() const; uint64_t reason_phrase_length() const; @@ -420,6 +422,7 @@ class QUICMaxDataFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, 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) override; + virtual void reset() override; uint64_t maximum_data() const; @@ -444,6 +447,7 @@ class QUICMaxStreamDataFrame : public QUICFrame virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual int debug_msg(char *msg, size_t msg_len) const override; + virtual void reset() override; QUICStreamId stream_id() const; uint64_t maximum_stream_data() const; @@ -469,6 +473,7 @@ class QUICMaxStreamIdFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; QUICStreamId maximum_stream_id() const; + virtual void reset() override; private: QUICStreamId _maximum_stream_id = 0; @@ -490,6 +495,7 @@ class QUICBlockedFrame : public QUICFrame virtual size_t size() const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void reset() override; QUICOffset offset() const; @@ -514,6 +520,7 @@ class QUICStreamBlockedFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; + virtual void reset() override; QUICStreamId stream_id() const; QUICOffset offset() const; @@ -540,6 +547,7 @@ class QUICStreamIdBlockedFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; + virtual void reset() override; QUICStreamId stream_id() const; @@ -566,6 +574,7 @@ class QUICNewConnectionIdFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual int debug_msg(char *msg, size_t msg_len) const override; + virtual void reset() override; uint64_t sequence() const; QUICConnectionId connection_id() const; @@ -594,6 +603,7 @@ class QUICStopSendingFrame : public QUICFrame virtual size_t size() const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void reset() override; QUICStreamId stream_id() const; QUICAppErrorCode error_code() const; @@ -623,6 +633,7 @@ class QUICPathChallengeFrame : public QUICFrame virtual bool is_probing_frame() const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void reset() override; const uint8_t *data() const; @@ -650,6 +661,7 @@ class QUICPathResponseFrame : public QUICFrame virtual bool is_probing_frame() const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual void reset() override; const uint8_t *data() const; @@ -675,6 +687,7 @@ class QUICNewTokenFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; + virtual void reset() override; uint64_t token_length() const; const uint8_t *token() const; @@ -703,6 +716,7 @@ class QUICRetireConnectionIdFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual int debug_msg(char *msg, size_t msg_len) const override; + virtual void reset() override; uint64_t seq_num() const; From 589eded4360cf4c8ce970e3a34d6aa64327e238b Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 25 Dec 2018 11:36:21 +0800 Subject: [PATCH 0983/1313] QUIC: make reset internal and fix typo --- iocore/net/quic/QUICFrame.cc | 59 ++++++++++++++++++++++++------------ iocore/net/quic/QUICFrame.h | 59 ++++++++++++++++++++++-------------- 2 files changed, 76 insertions(+), 42 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 433e4b10460..3357a4cd082 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -76,7 +76,7 @@ read_varint(uint8_t *&pos, size_t len, uint64_t &field, size_t &field_len) QUICFrameType QUICFrame::type() const { - ink_assert("should no be called"); + ink_assert("should not be called"); return QUICFrameType::UNKNOWN; } @@ -156,6 +156,7 @@ void QUICStreamFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf); this->_has_offset_field = (buf[0] & 0x04) != 0; // "O" of "0b00010OLF" @@ -191,7 +192,7 @@ QUICStreamFrame::parse(const uint8_t *buf, size_t len) } void -QUICStreamFrame::reset() +QUICStreamFrame::_reset() { this->_data = nullptr; this->_fin = false; @@ -417,6 +418,7 @@ void QUICCryptoFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; size_t field_len = 0; @@ -439,7 +441,7 @@ QUICCryptoFrame::parse(const uint8_t *buf, size_t len) } void -QUICCryptoFrame::reset() +QUICCryptoFrame::_reset() { this->_data = nullptr; this->_offset = 0; @@ -561,6 +563,7 @@ void QUICAckFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; bool has_ecn = (buf[0] == 0x1b); @@ -621,7 +624,7 @@ QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_d } void -QUICAckFrame::reset() +QUICAckFrame::_reset() { if (this->_ack_block_section) { delete this->_ack_block_section; @@ -1014,6 +1017,7 @@ void QUICRstStreamFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = 1 + const_cast(buf); size_t field_len = 0; @@ -1037,7 +1041,7 @@ QUICRstStreamFrame::parse(const uint8_t *buf, size_t len) } void -QUICRstStreamFrame::reset() +QUICRstStreamFrame::_reset() { this->_stream_id = 0; this->_error_code = 0; @@ -1131,6 +1135,7 @@ QUICPingFrame::QUICPingFrame(const uint8_t *buf, size_t len) void QUICPingFrame::parse(const uint8_t *buf, size_t len) { + this->_reset(); this->_valid = true; this->_size = 1; } @@ -1171,6 +1176,7 @@ void QUICPaddingFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); this->_valid = true; this->_size = 1; } @@ -1231,7 +1237,7 @@ QUICConnectionCloseFrame::QUICConnectionCloseFrame(const uint8_t *buf, size_t le } void -QUICConnectionCloseFrame::reset() +QUICConnectionCloseFrame::_reset() { this->_error_code = 0; this->_reason_phrase_length = 0; @@ -1248,6 +1254,7 @@ void QUICConnectionCloseFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; if (LEFT_SPACE(pos) < 2) { @@ -1420,7 +1427,7 @@ QUICApplicationCloseFrame::QUICApplicationCloseFrame(const uint8_t *buf, size_t } void -QUICApplicationCloseFrame::reset() +QUICApplicationCloseFrame::_reset() { this->_error_code = 0; this->_reason_phrase_length = 0; @@ -1436,6 +1443,7 @@ void QUICApplicationCloseFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; if (LEFT_SPACE(pos) < 2) { @@ -1553,7 +1561,7 @@ QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, QUICFrameId id, QUICFr } void -QUICMaxDataFrame::reset() +QUICMaxDataFrame::_reset() { this->_maximum_data = 0; @@ -1572,6 +1580,7 @@ void QUICMaxDataFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = 1 + const_cast(buf); size_t field_len = 0; @@ -1647,7 +1656,7 @@ QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t } void -QUICMaxStreamDataFrame::reset() +QUICMaxStreamDataFrame::_reset() { this->_stream_id = 0; this->_maximum_stream_data = 0; @@ -1667,6 +1676,7 @@ void QUICMaxStreamDataFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; size_t field_len = 0; @@ -1751,7 +1761,7 @@ QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICF } void -QUICMaxStreamIdFrame::reset() +QUICMaxStreamIdFrame::_reset() { this->_maximum_stream_id = 0; @@ -1770,6 +1780,7 @@ void QUICMaxStreamIdFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; size_t field_len = 0; @@ -1836,7 +1847,7 @@ QUICBlockedFrame::QUICBlockedFrame(const uint8_t *buf, size_t len) } void -QUICBlockedFrame::reset() +QUICBlockedFrame::_reset() { this->_offset = 0; @@ -1850,6 +1861,7 @@ void QUICBlockedFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; size_t field_len = 0; @@ -1918,7 +1930,7 @@ QUICStreamBlockedFrame::QUICStreamBlockedFrame(const uint8_t *buf, size_t len) } void -QUICStreamBlockedFrame::reset() +QUICStreamBlockedFrame::_reset() { this->_stream_id = 0; this->_offset = 0; @@ -1933,6 +1945,7 @@ void QUICStreamBlockedFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; size_t field_len = 0; @@ -2012,7 +2025,7 @@ QUICStreamIdBlockedFrame::QUICStreamIdBlockedFrame(const uint8_t *buf, size_t le } void -QUICStreamIdBlockedFrame::reset() +QUICStreamIdBlockedFrame::_reset() { this->_stream_id = 0; @@ -2026,6 +2039,7 @@ void QUICStreamIdBlockedFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; size_t field_len = 0; @@ -2093,7 +2107,7 @@ QUICNewConnectionIdFrame::QUICNewConnectionIdFrame(const uint8_t *buf, size_t le } void -QUICNewConnectionIdFrame::reset() +QUICNewConnectionIdFrame::_reset() { this->_sequence = 0; this->_connection_id = QUICConnectionId::ZERO(); @@ -2109,6 +2123,7 @@ void QUICNewConnectionIdFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; if (LEFT_SPACE(pos) < 1) { @@ -2225,7 +2240,7 @@ QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorC } void -QUICStopSendingFrame::reset() +QUICStopSendingFrame::_reset() { this->_stream_id = 0; this->_error_code = 0; @@ -2245,6 +2260,7 @@ void QUICStopSendingFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; size_t field_len = 0; @@ -2324,7 +2340,7 @@ QUICPathChallengeFrame::QUICPathChallengeFrame(const uint8_t *buf, size_t len) } void -QUICPathChallengeFrame::reset() +QUICPathChallengeFrame::_reset() { this->_data = nullptr; this->_owner = nullptr; @@ -2337,6 +2353,7 @@ void QUICPathChallengeFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; if (LEFT_SPACE(pos) < QUICPathChallengeFrame::DATA_LEN) { @@ -2407,7 +2424,7 @@ QUICPathResponseFrame::QUICPathResponseFrame(const uint8_t *buf, size_t len) } void -QUICPathResponseFrame::reset() +QUICPathResponseFrame::_reset() { this->_data = nullptr; this->_owner = nullptr; @@ -2420,6 +2437,7 @@ void QUICPathResponseFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; if (LEFT_SPACE(pos) < QUICPathChallengeFrame::DATA_LEN) { @@ -2486,7 +2504,7 @@ QUICNewTokenFrame::QUICNewTokenFrame(const uint8_t *buf, size_t len) } void -QUICNewTokenFrame::reset() +QUICNewTokenFrame::_reset() { this->_token = nullptr; this->_token_length = 0; @@ -2501,6 +2519,7 @@ void QUICNewTokenFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; size_t field_len = 0; @@ -2588,7 +2607,7 @@ QUICRetireConnectionIdFrame::QUICRetireConnectionIdFrame(const uint8_t *buf, siz } void -QUICRetireConnectionIdFrame::reset() +QUICRetireConnectionIdFrame::_reset() { this->_seq_num = 0; @@ -2603,6 +2622,7 @@ void QUICRetireConnectionIdFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); + this->_reset(); uint8_t *pos = const_cast(buf) + 1; size_t field_len = 0; @@ -2847,7 +2867,6 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) this->_reusable_frames[static_cast(QUICFrame::type(buf))] = frame; } } else { - frame->reset(); frame->parse(buf, len); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 7efa9eea117..e4401070020 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -61,7 +61,6 @@ class QUICFrame virtual size_t size() const = 0; virtual bool is_probing_frame() const; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const = 0; - virtual void reset(){}; virtual QUICFrame *split(size_t size); virtual int debug_msg(char *msg, size_t msg_len) const; virtual void parse(const uint8_t *buf, size_t len){}; @@ -70,6 +69,7 @@ class QUICFrame LINK(QUICFrame, link); protected: + virtual void _reset(){}; QUICFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : _id(id), _owner(owner) {} size_t _size = 0; bool _valid = false; @@ -97,7 +97,6 @@ class QUICStreamFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, 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) override; - virtual void reset() override; size_t store(uint8_t *buf, size_t *len, size_t limit, bool include_length_field) const; QUICStreamId stream_id() const; @@ -111,6 +110,8 @@ class QUICStreamFrame : public QUICFrame LINK(QUICStreamFrame, link); private: + virtual void _reset() override; + ats_unique_buf _data = {nullptr}; size_t _data_len = 0; QUICStreamId _stream_id = 0; @@ -138,7 +139,6 @@ class QUICCryptoFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, 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) override; - virtual void reset() override; QUICOffset offset() const; uint64_t data_length() const; @@ -147,6 +147,8 @@ class QUICCryptoFrame : public QUICFrame LINK(QUICCryptoFrame, link); private: + virtual void _reset() override; + QUICOffset _offset = 0; uint64_t _data_len = 0; ats_unique_buf _data = {nullptr}; @@ -212,13 +214,11 @@ class QUICAckFrame : public QUICFrame private: uint8_t _index = 0; - const uint8_t *_buf = nullptr; QUICAckFrame::AckBlock _current_block = {UINT64_C(0), UINT64_C(0)}; const std::vector *_ack_blocks = nullptr; }; AckBlockSection(uint64_t first_ack_block) : _first_ack_block(first_ack_block) {} - AckBlockSection(const uint8_t *buf, uint8_t ack_block_count) : _buf(buf), _ack_block_count(ack_block_count) {} uint8_t count() const; size_t size() const; size_t store(uint8_t *buf, size_t *len, size_t limit) const; @@ -229,7 +229,6 @@ class QUICAckFrame : public QUICFrame bool has_protected() const; private: - const uint8_t *_buf = nullptr; uint64_t _first_ack_block = 0; uint8_t _ack_block_count = 0; std::vector _ack_blocks; @@ -265,7 +264,6 @@ class QUICAckFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual int debug_msg(char *msg, size_t msg_len) const override; - virtual void reset() override; QUICPacketNumber largest_acknowledged() const; uint64_t ack_delay() const; @@ -276,6 +274,8 @@ class QUICAckFrame : public QUICFrame EcnSection *ecn_section(); private: + virtual void _reset() override; + QUICPacketNumber _largest_acknowledged = 0; uint64_t _ack_delay = 0; AckBlockSection *_ack_block_section = nullptr; @@ -299,13 +299,14 @@ class QUICRstStreamFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; - virtual void reset() override; QUICStreamId stream_id() const; QUICAppErrorCode error_code() const; QUICOffset final_offset() const; private: + virtual void _reset() override; + QUICStreamId _stream_id = 0; QUICAppErrorCode _error_code = 0; QUICOffset _final_offset = 0; @@ -363,7 +364,6 @@ class QUICConnectionCloseFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, 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) override; - virtual void reset() override; uint16_t error_code() const; QUICFrameType frame_type() const; @@ -371,6 +371,8 @@ class QUICConnectionCloseFrame : public QUICFrame const char *reason_phrase() const; private: + virtual void _reset() override; + uint16_t _error_code; QUICFrameType _frame_type = QUICFrameType::UNKNOWN; uint64_t _reason_phrase_length = 0; @@ -394,13 +396,14 @@ class QUICApplicationCloseFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; - virtual void reset() override; QUICAppErrorCode error_code() const; uint64_t reason_phrase_length() const; const char *reason_phrase() const; private: + virtual void _reset() override; + QUICAppErrorCode _error_code = 0; uint64_t _reason_phrase_length = 0; const char *_reason_phrase = nullptr; @@ -422,11 +425,12 @@ class QUICMaxDataFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, 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) override; - virtual void reset() override; uint64_t maximum_data() const; private: + virtual void _reset() override; + uint64_t _maximum_data = 0; }; @@ -447,12 +451,13 @@ class QUICMaxStreamDataFrame : public QUICFrame virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual int debug_msg(char *msg, size_t msg_len) const override; - virtual void reset() override; QUICStreamId stream_id() const; uint64_t maximum_stream_data() const; private: + virtual void _reset() override; + QUICStreamId _stream_id = 0; uint64_t _maximum_stream_data = 0; }; @@ -473,9 +478,10 @@ class QUICMaxStreamIdFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; QUICStreamId maximum_stream_id() const; - virtual void reset() override; private: + virtual void _reset() override; + QUICStreamId _maximum_stream_id = 0; }; @@ -495,11 +501,12 @@ class QUICBlockedFrame : public QUICFrame virtual size_t size() const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - virtual void reset() override; QUICOffset offset() const; private: + virtual void _reset() override; + QUICOffset _offset = 0; }; @@ -520,12 +527,13 @@ class QUICStreamBlockedFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; - virtual void reset() override; QUICStreamId stream_id() const; QUICOffset offset() const; private: + virtual void _reset() override; + QUICStreamId _stream_id = 0; QUICOffset _offset = 0; }; @@ -547,11 +555,12 @@ class QUICStreamIdBlockedFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; - virtual void reset() override; QUICStreamId stream_id() const; private: + virtual void _reset() override; + QUICStreamId _stream_id = 0; }; @@ -574,13 +583,14 @@ class QUICNewConnectionIdFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual int debug_msg(char *msg, size_t msg_len) const override; - virtual void reset() override; uint64_t sequence() const; QUICConnectionId connection_id() const; QUICStatelessResetToken stateless_reset_token() const; private: + virtual void _reset() override; + uint64_t _sequence = 0; QUICConnectionId _connection_id = QUICConnectionId::ZERO(); QUICStatelessResetToken _stateless_reset_token; @@ -603,12 +613,13 @@ class QUICStopSendingFrame : public QUICFrame virtual size_t size() const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - virtual void reset() override; QUICStreamId stream_id() const; QUICAppErrorCode error_code() const; private: + virtual void _reset() override; + QUICStreamId _stream_id = 0; QUICAppErrorCode _error_code = 0; }; @@ -633,11 +644,12 @@ class QUICPathChallengeFrame : public QUICFrame virtual bool is_probing_frame() const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - virtual void reset() override; const uint8_t *data() const; private: + virtual void _reset() override; + ats_unique_buf _data = {nullptr}; }; @@ -661,11 +673,12 @@ class QUICPathResponseFrame : public QUICFrame virtual bool is_probing_frame() const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - virtual void reset() override; const uint8_t *data() const; private: + virtual void _reset() override; + ats_unique_buf _data = {nullptr}; }; @@ -687,12 +700,13 @@ class QUICNewTokenFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; - virtual void reset() override; uint64_t token_length() const; const uint8_t *token() const; private: + virtual void _reset() override; + uint64_t _token_length = 0; ats_unique_buf _token = {nullptr}; }; @@ -716,11 +730,12 @@ class QUICRetireConnectionIdFrame : public QUICFrame virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; virtual int debug_msg(char *msg, size_t msg_len) const override; - virtual void reset() override; uint64_t seq_num() const; private: + virtual void _reset() override; + uint64_t _seq_num = 0; }; From 433b0abceea365dd3abcc54a3a8f4f64c75cc778 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 26 Dec 2018 09:33:36 +0900 Subject: [PATCH 0984/1313] Fix compile errrors because of type difference --- iocore/net/quic/QUICFrame.cc | 8 ++++---- iocore/net/quic/QUICFrame.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 3357a4cd082..072a3cf1092 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -576,20 +576,20 @@ QUICAckFrame::parse(const uint8_t *buf, size_t len) return; } - size_t ack_block_count = 0; + uint64_t ack_block_count = 0; if (!read_varint(pos, LEFT_SPACE(pos), ack_block_count, field_len)) { return; } - size_t first_ack_block = 0; + uint64_t first_ack_block = 0; if (!read_varint(pos, LEFT_SPACE(pos), first_ack_block, field_len)) { return; } this->_ack_block_section = new AckBlockSection(first_ack_block); for (size_t i = 0; i < ack_block_count; i++) { - size_t gap = 0; - size_t add_ack_block = 0; + uint64_t gap = 0; + uint64_t add_ack_block = 0; if (!read_varint(pos, LEFT_SPACE(pos), gap, field_len)) { return; diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index e4401070020..fc604be4cc5 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -113,7 +113,7 @@ class QUICStreamFrame : public QUICFrame virtual void _reset() override; ats_unique_buf _data = {nullptr}; - size_t _data_len = 0; + uint64_t _data_len = 0; QUICStreamId _stream_id = 0; QUICOffset _offset = 0; bool _fin = false; From 80210bca24641f45374d4f28171bb4c6ddefd5c1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 26 Dec 2018 14:30:24 +0900 Subject: [PATCH 0985/1313] Fix tests for QUICStreamManager initial_max_stream_data_bidi_remote and initial_max_stream_data_bidi_local are always 32 bits values. --- iocore/net/quic/test/test_QUICStreamManager.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 380eeabc229..eb9689b3edd 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -133,26 +133,26 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") uint8_t local_tp_buf[] = { 0x00, 0x00, 0x00, 0x00, // initial version 0x00, // size of supported versions - 0x00, 0x0c, // size of parameters + 0x00, 0x0e, // size of parameters 0x00, 0x02, // parameter id - initial_max_bidi_streams 0x00, 0x02, // length of value 0x00, 0x10, // value 0x00, 0x00, // parameter id - initial_max_stream_data_bidi_local - 0x00, 0x02, // length of value - 0xff, 0xff, // value + 0x00, 0x04, // length of value + 0xff, 0xff, 0xff, 0xff // value }; std::shared_ptr local_tp = std::make_shared(local_tp_buf, sizeof(local_tp_buf)); uint8_t remote_tp_buf[] = { 0x00, 0x00, 0x00, 0x00, // initial version - 0x00, 0x06, // size of parameters + 0x00, 0x0e, // size of parameters 0x00, 0x02, // parameter id - initial_max_bidi_streams 0x00, 0x02, // length of value 0x00, 0x10, // value 0x00, 0x0a, // parameter id - initial_max_stream_data_bidi_remote - 0x00, 0x02, // length of value - 0xff, 0xff, // value + 0x00, 0x04, // length of value + 0xff, 0xff, 0xff, 0xff // value }; std::shared_ptr remote_tp = std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); From c832698624e69e8e3d1d577b3234f70e616b3c89 Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 26 Dec 2018 16:17:09 +0800 Subject: [PATCH 0986/1313] QUIC Uses IOBufferBlock instead of ats_unique_malloc --- iocore/net/quic/QUICFrame.cc | 72 +++++++++++----------- iocore/net/quic/QUICFrame.h | 9 +-- iocore/net/quic/QUICStream.cc | 8 ++- iocore/net/quic/test/main.cc | 4 ++ iocore/net/quic/test/test_QUICFrame.cc | 83 ++++++++++++++++---------- 5 files changed, 101 insertions(+), 75 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 072a3cf1092..6b7b879c3dc 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -134,11 +134,10 @@ QUICFrame::valid() const // STREAM Frame // -QUICStreamFrame::QUICStreamFrame(ats_unique_buf data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, +QUICStreamFrame::QUICStreamFrame(Ptr &block, QUICStreamId stream_id, QUICOffset offset, bool last, bool has_offset_field, bool has_length_field, QUICFrameId id, QUICFrameGenerator *owner) : QUICFrame(id, owner), - _data(std::move(data)), - _data_len(data_len), + _block(block), _stream_id(stream_id), _offset(offset), _fin(last), @@ -173,33 +172,36 @@ QUICStreamFrame::parse(const uint8_t *buf, size_t len) return; } - if (this->_has_length_field && !read_varint(pos, LEFT_SPACE(pos), this->_data_len, field_len)) { + uint64_t data_len = 0; + if (this->_has_length_field && !read_varint(pos, LEFT_SPACE(pos), data_len, field_len)) { return; } if (!this->_has_length_field) { - this->_data_len = LEFT_SPACE(pos); + data_len = LEFT_SPACE(pos); } - if (LEFT_SPACE(pos) < this->_data_len) { + if (LEFT_SPACE(pos) < data_len) { return; } this->_valid = true; - this->_data = ats_unique_malloc(this->_data_len); - memcpy(this->_data.get(), pos, this->_data_len); - pos += this->_data_len; + this->_block = make_ptr(new_IOBufferBlock()); + this->_block->alloc(); + ink_assert(static_cast(this->_block->write_avail()) > data_len); + memcpy(this->_block->start(), pos, data_len); + this->_block->fill(data_len); + pos += data_len; this->_size = FRAME_SIZE(pos); } void QUICStreamFrame::_reset() { - this->_data = nullptr; + this->_block = nullptr; this->_fin = false; this->_has_length_field = true; this->_has_offset_field = true; this->_offset = 0; - this->_data_len = 0; this->_stream_id = 0; this->_owner = nullptr; this->_id = 0; @@ -215,7 +217,7 @@ QUICStreamFrame::split(size_t size) header_len += QUICVariableInt::size(this->_offset); } if (this->_has_length_field) { - header_len += QUICVariableInt::size(this->_data_len); + header_len += QUICVariableInt::size(this->_block->read_avail()); } if (size <= header_len) { @@ -224,30 +226,24 @@ QUICStreamFrame::split(size_t size) bool fin = this->has_fin_flag(); ink_assert(size < this->size()); + ink_assert(this->_block.get() != nullptr); size_t data_len = size - header_len; - size_t buf2_len = this->data_length() - data_len; - ats_unique_buf buf = ats_unique_malloc(data_len); - ats_unique_buf buf2 = ats_unique_malloc(buf2_len); - memcpy(buf.get(), this->data(), data_len); - memcpy(buf2.get(), this->data() + data_len, buf2_len); + Ptr new_block = make_ptr(this->_block->clone()); + new_block->consume(data_len); + this->_block->_end = std::min(this->_block->_start + data_len, this->_block->_buf_end); if (this->has_offset_field()) { this->_offset = this->offset(); } - if (this->has_length_field()) { - this->_data_len = data_len; - } - this->_fin = false; - this->_data = std::move(buf); this->_stream_id = this->stream_id(); QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(std::move(buf2), buf2_len, this->stream_id(), this->offset() + this->data_length(), fin, - this->_has_offset_field, this->_has_length_field, this->_id, this->_owner); + new (frame) QUICStreamFrame(new_block, this->stream_id(), this->offset() + this->data_length(), fin, this->_has_offset_field, + this->_has_length_field, this->_id, this->_owner); return frame; } @@ -255,9 +251,9 @@ QUICStreamFrame::split(size_t size) QUICFrameUPtr QUICStreamFrame::clone() const { - return QUICFrameFactory::create_stream_frame(this->data(), this->data_length(), this->stream_id(), this->offset(), - this->has_fin_flag(), this->has_offset_field(), this->has_length_field(), this->_id, - this->_owner); + Ptr new_block = make_ptr(this->_block->clone()); + return QUICFrameFactory::create_stream_frame(new_block, this->stream_id(), this->offset(), this->has_fin_flag(), + this->has_offset_field(), this->has_length_field(), this->_id, this->_owner); } QUICFrameType @@ -273,17 +269,22 @@ QUICStreamFrame::size() const return this->_size; } - size_t size = 1; + size_t size = 1; + size_t data_len = 0; + if (this->_block.get() != nullptr) { + data_len = this->_block->read_avail(); + } + size += QUICVariableInt::size(this->_stream_id); if (this->_has_offset_field) { size += QUICVariableInt::size(this->_offset); } if (this->_has_length_field) { - size += QUICVariableInt::size(this->_data_len); + size += QUICVariableInt::size(data_len); + size += data_len; } - size += this->_data_len; return size; } @@ -362,13 +363,13 @@ QUICStreamFrame::offset() const uint64_t QUICStreamFrame::data_length() const { - return this->_data_len; + return this->_block->read_avail(); } const uint8_t * QUICStreamFrame::data() const { - return this->_data.get(); + return reinterpret_cast(this->_block->start()); } /** @@ -2874,14 +2875,11 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) } QUICStreamFrameUPtr -QUICFrameFactory::create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, bool last, +QUICFrameFactory::create_stream_frame(Ptr &block, QUICStreamId stream_id, QUICOffset offset, bool last, bool has_offset_field, bool has_length_field, QUICFrameId id, QUICFrameGenerator *owner) { - ats_unique_buf buf = ats_unique_malloc(data_len); - memcpy(buf.get(), data, data_len); - QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(std::move(buf), data_len, stream_id, offset, last, has_offset_field, has_length_field, id, owner); + new (frame) QUICStreamFrame(block, stream_id, offset, last, has_offset_field, has_length_field, id, owner); return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index fc604be4cc5..84714de1684 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -26,6 +26,8 @@ #include #include "tscore/Allocator.h" #include "tscore/List.h" +#include "tscore/Ptr.h" +#include "I_IOBuffer.h" #include #include @@ -86,7 +88,7 @@ class QUICStreamFrame : public QUICFrame public: QUICStreamFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICStreamFrame(const uint8_t *buf, size_t len); - QUICStreamFrame(ats_unique_buf buf, size_t len, QUICStreamId streamid, QUICOffset offset, bool last = false, + QUICStreamFrame(Ptr &block, QUICStreamId streamid, QUICOffset offset, bool last = false, bool has_offset_field = true, bool has_length_field = true, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); @@ -112,8 +114,7 @@ class QUICStreamFrame : public QUICFrame private: virtual void _reset() override; - ats_unique_buf _data = {nullptr}; - uint64_t _data_len = 0; + Ptr _block; QUICStreamId _stream_id = 0; QUICOffset _offset = 0; bool _fin = false; @@ -976,7 +977,7 @@ class QUICFrameFactory * Creates a STREAM frame. * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ - static QUICStreamFrameUPtr create_stream_frame(const uint8_t *data, size_t data_len, QUICStreamId stream_id, QUICOffset offset, + static QUICStreamFrameUPtr create_stream_frame(Ptr &block, QUICStreamId stream_id, QUICOffset offset, bool last = false, bool has_offset_field = true, bool has_length_field = true, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 4a4da9b45a1..46c74c7c50e 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -485,9 +485,13 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit } } + Ptr block = make_ptr(reader->get_current_block()->clone()); + block->consume(reader->start_offset); + block->_end = std::min(block->start() + len, block->_buf_end); + ink_assert(static_cast(block->read_avail()) == len); + // STREAM - Pure FIN or data length is lager than 0 - frame = QUICFrameFactory::create_stream_frame(reinterpret_cast(reader->start()), len, this->_id, - this->_send_offset, fin); + frame = QUICFrameFactory::create_stream_frame(block, this->_id, this->_send_offset, fin); if (!this->_state.is_allowed_to_send(*frame)) { QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); return frame; diff --git a/iocore/net/quic/test/main.cc b/iocore/net/quic/test/main.cc index 3b3af1d081c..fe4783cc916 100644 --- a/iocore/net/quic/test/main.cc +++ b/iocore/net/quic/test/main.cc @@ -49,6 +49,10 @@ struct EventProcessorListener : Catch::TestEventListenerBase { LibRecordsConfigInit(); QUICConfig::startup(); + + EThread *thread = new EThread(); + thread->set_specific(); + init_buffer_allocators(0); } }; CATCH_REGISTER_LISTENER(EventProcessorListener); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index b26658f9cf6..9c060d8beec 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -27,6 +27,9 @@ #include "quic/QUICFrame.h" #include "quic/QUICStream.h" +extern const ink_freelist_ops *freelist_global_ops; +extern const ink_freelist_ops *freelist_class_ops; + TEST_CASE("QUICFrame Type", "[quic]") { CHECK(QUICFrame::type(reinterpret_cast("\x00")) == QUICFrameType::PADDING); @@ -184,11 +187,13 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - uint8_t raw1[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload1 = ats_unique_malloc(5); - memcpy(payload1.get(), raw1, 5); + uint8_t raw1[] = "\x01\x02\x03\x04\x05"; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), raw1, 5); + block->fill(5); - QUICStreamFrame stream_frame(std::move(payload1), 5, 0x01, 0x00, false, false, true); + QUICStreamFrame stream_frame(block, 0x01, 0x00, false, false, true); CHECK(stream_frame.size() == 8); stream_frame.store(buf, &len, 32); @@ -207,11 +212,13 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - uint8_t raw2[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload2 = ats_unique_malloc(5); - memcpy(payload2.get(), raw2, 5); + uint8_t raw2[] = "\x01\x02\x03\x04\x05"; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), raw2, 5); + block->fill(5); - QUICStreamFrame stream_frame(std::move(payload2), 5, 0x01, 0x01); + QUICStreamFrame stream_frame(block, 0x01, 0x01); CHECK(stream_frame.size() == 9); stream_frame.store(buf, &len, 32); @@ -230,11 +237,13 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - uint8_t raw3[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload3 = ats_unique_malloc(5); - memcpy(payload3.get(), raw3, 5); + uint8_t raw3[] = "\x01\x02\x03\x04\x05"; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), raw3, 5); + block->fill(5); - QUICStreamFrame stream_frame(std::move(payload3), 5, 0x01, 0x010000); + QUICStreamFrame stream_frame(block, 0x01, 0x010000); CHECK(stream_frame.size() == 12); stream_frame.store(buf, &len, 32); @@ -253,11 +262,13 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - uint8_t raw4[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload4 = ats_unique_malloc(5); - memcpy(payload4.get(), raw4, 5); + uint8_t raw4[] = "\x01\x02\x03\x04\x05"; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), raw4, 5); + block->fill(5); - QUICStreamFrame stream_frame(std::move(payload4), 5, 0x01, 0x0100000000); + QUICStreamFrame stream_frame(block, 0x01, 0x0100000000); CHECK(stream_frame.size() == 16); stream_frame.store(buf, &len, 32); @@ -276,11 +287,13 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - uint8_t raw5[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload5 = ats_unique_malloc(5); - memcpy(payload5.get(), raw5, 5); + uint8_t raw5[] = "\x01\x02\x03\x04\x05"; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), raw5, 5); + block->fill(5); - QUICStreamFrame stream_frame(std::move(payload5), 5, 0x0100, 0x0100000000); + QUICStreamFrame stream_frame(block, 0x0100, 0x0100000000); CHECK(stream_frame.size() == 17); stream_frame.store(buf, &len, 32); @@ -299,11 +312,13 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - uint8_t raw6[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload6 = ats_unique_malloc(5); - memcpy(payload6.get(), raw6, 5); + uint8_t raw6[] = "\x01\x02\x03\x04\x05"; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), raw6, 5); + block->fill(5); - QUICStreamFrame stream_frame(std::move(payload6), 5, 0x010000, 0x0100000000); + QUICStreamFrame stream_frame(block, 0x010000, 0x0100000000); CHECK(stream_frame.size() == 19); stream_frame.store(buf, &len, 32); @@ -322,11 +337,13 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - uint8_t raw7[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload7 = ats_unique_malloc(5); - memcpy(payload7.get(), raw7, 5); + uint8_t raw7[] = "\x01\x02\x03\x04\x05"; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), raw7, 5); + block->fill(5); - QUICStreamFrame stream_frame(std::move(payload7), 5, 0x01000000, 0x0100000000); + QUICStreamFrame stream_frame(block, 0x01000000, 0x0100000000); CHECK(stream_frame.size() == 19); stream_frame.store(buf, &len, 32); @@ -345,11 +362,13 @@ TEST_CASE("Store STREAM Frame", "[quic]") 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - uint8_t raw[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload = ats_unique_malloc(5); - memcpy(payload.get(), raw, 5); + uint8_t raw[] = "\x01\x02\x03\x04\x05"; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), raw, 5); + block->fill(5); - QUICStreamFrame stream_frame(std::move(payload), 5, 0x01000000, 0x0100000000, true); + QUICStreamFrame stream_frame(block, 0x01000000, 0x0100000000, true); CHECK(stream_frame.size() == 19); stream_frame.store(buf, &len, 32); From f7fcbb5dbe82c82720e78eb7ce354fd7c879b3b5 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 27 Dec 2018 10:34:28 +0800 Subject: [PATCH 0987/1313] QUIC: update crypto data buffer with IOBufferBlock --- iocore/net/quic/QUICFrame.cc | 59 ++++++++++++++------------ iocore/net/quic/QUICFrame.h | 9 ++-- iocore/net/quic/QUICStream.cc | 8 +++- iocore/net/quic/test/test_QUICFrame.cc | 10 +++-- 4 files changed, 48 insertions(+), 38 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 6b7b879c3dc..0eff6abd6ea 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -405,8 +405,8 @@ QUICStreamFrame::has_fin_flag() const // CRYPTO frame // -QUICCryptoFrame::QUICCryptoFrame(ats_unique_buf data, size_t data_len, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) - : QUICFrame(id, owner), _offset(offset), _data_len(data_len), _data(std::move(data)) +QUICCryptoFrame::QUICCryptoFrame(Ptr &block, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) + : QUICFrame(id, owner), _offset(offset), _block(block) { } @@ -427,24 +427,29 @@ QUICCryptoFrame::parse(const uint8_t *buf, size_t len) return; } - if (!read_varint(pos, LEFT_SPACE(pos), this->_data_len, field_len)) { + uint64_t data_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), data_len, field_len)) { return; } - if (LEFT_SPACE(pos) < this->_data_len) { + if (LEFT_SPACE(pos) < data_len) { return; } this->_valid = true; - this->_data = ats_unique_malloc(this->_data_len); - memcpy(this->_data.get(), pos, this->_data_len); + this->_block = make_ptr(new_IOBufferBlock()); + this->_block->alloc(); + ink_assert(static_cast(this->_block->write_avail()) > data_len); + memcpy(this->_block->start(), pos, data_len); + this->_block->fill(data_len); + pos += data_len; this->_size = FRAME_SIZE(pos); } void QUICCryptoFrame::_reset() { - this->_data = nullptr; + this->_block = nullptr; this->_offset = 0; this->_owner = nullptr; this->_id = 0; @@ -455,7 +460,7 @@ QUICCryptoFrame::_reset() QUICFrame * QUICCryptoFrame::split(size_t size) { - size_t header_len = 1 + QUICVariableInt::size(this->_offset) + QUICVariableInt::size(this->_data_len); + size_t header_len = 1 + QUICVariableInt::size(this->_offset) + QUICVariableInt::size(this->_block->read_avail()); if (size <= header_len) { return nullptr; } @@ -463,19 +468,18 @@ QUICCryptoFrame::split(size_t size) ink_assert(size < this->size()); size_t data_len = size - header_len; - size_t buf2_len = this->data_length() - data_len; - ats_unique_buf buf = ats_unique_malloc(data_len); - ats_unique_buf buf2 = ats_unique_malloc(buf2_len); - memcpy(buf.get(), this->data(), data_len); - memcpy(buf2.get(), this->data() + data_len, buf2_len); + ink_assert(size < this->size()); + ink_assert(this->_block.get() != nullptr); + + Ptr new_block = make_ptr(this->_block->clone()); + new_block->consume(data_len); + this->_block->_end = std::min(this->_block->_start + data_len, this->_block->_buf_end); - this->_offset = this->offset(); - this->_data_len = data_len; - this->_data = std::move(buf); + this->_offset = this->offset(); QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); - new (frame) QUICCryptoFrame(std::move(buf2), buf2_len, this->offset() + this->data_length(), this->_id, this->_owner); + new (frame) QUICCryptoFrame(this->_block, this->offset() + data_len, this->_id, this->_owner); return frame; } @@ -483,7 +487,8 @@ QUICCryptoFrame::split(size_t size) QUICFrameUPtr QUICCryptoFrame::clone() const { - return QUICFrameFactory::create_crypto_frame(this->data(), this->data_length(), this->offset(), this->_id, this->_owner); + Ptr block = make_ptr(this->_block->clone()); + return QUICFrameFactory::create_crypto_frame(block, this->offset(), this->_id, this->_owner); } QUICFrameType @@ -495,7 +500,11 @@ QUICCryptoFrame::type() const size_t QUICCryptoFrame::size() const { - return 1 + this->_data_len + QUICVariableInt::size(this->_offset) + QUICVariableInt::size(this->_data_len); + if (this->_size) { + return this->_size; + } + + return 1 + this->_block->read_avail() + QUICVariableInt::size(this->_offset) + QUICVariableInt::size(this->_block->read_avail()); } int @@ -542,13 +551,13 @@ QUICCryptoFrame::offset() const uint64_t QUICCryptoFrame::data_length() const { - return this->_data_len; + return this->_block->read_avail(); } const uint8_t * QUICCryptoFrame::data() const { - return this->_data.get(); + return reinterpret_cast(this->_block->start()); } // @@ -2884,14 +2893,10 @@ QUICFrameFactory::create_stream_frame(Ptr &block, QUICStreamId st } QUICCryptoFrameUPtr -QUICFrameFactory::create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, QUICFrameId id, - QUICFrameGenerator *owner) +QUICFrameFactory::create_crypto_frame(Ptr &block, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) { - ats_unique_buf buf = ats_unique_malloc(data_len); - memcpy(buf.get(), data, data_len); - QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); - new (frame) QUICCryptoFrame(std::move(buf), data_len, offset, id, owner); + new (frame) QUICCryptoFrame(block, offset, id, owner); return QUICCryptoFrameUPtr(frame, &QUICFrameDeleter::delete_crypto_frame); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 84714de1684..2236fe04372 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -131,7 +131,7 @@ class QUICCryptoFrame : public QUICFrame public: QUICCryptoFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICCryptoFrame(const uint8_t *buf, size_t len); - QUICCryptoFrame(ats_unique_buf buf, size_t len, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + QUICCryptoFrame(Ptr &block, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrame *split(size_t size) override; QUICFrameUPtr clone() const override; @@ -150,9 +150,8 @@ class QUICCryptoFrame : public QUICFrame private: virtual void _reset() override; - QUICOffset _offset = 0; - uint64_t _data_len = 0; - ats_unique_buf _data = {nullptr}; + QUICOffset _offset = 0; + Ptr _block; }; // @@ -985,7 +984,7 @@ class QUICFrameFactory * Creates a CRYPTO frame. * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ - static QUICCryptoFrameUPtr create_crypto_frame(const uint8_t *data, uint64_t data_len, QUICOffset offset, QUICFrameId id = 0, + static QUICCryptoFrameUPtr create_crypto_frame(Ptr &block, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 46c74c7c50e..c2412ab1fe0 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -819,8 +819,12 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ return frame; } - frame = QUICFrameFactory::create_crypto_frame(reinterpret_cast(this->_write_buffer_reader->start()), - frame_payload_size, this->_send_offset); + Ptr block = make_ptr(this->_write_buffer_reader->get_current_block()->clone()); + block->consume(this->_write_buffer_reader->start_offset); + block->_end = std::min(block->start() + frame_payload_size, block->_buf_end); + ink_assert(static_cast(block->read_avail()) == frame_payload_size); + + frame = QUICFrameFactory::create_crypto_frame(block, this->_send_offset); this->_send_offset += frame_payload_size; this->_write_buffer_reader->consume(frame_payload_size); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 9c060d8beec..7903eeccd7b 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -450,11 +450,13 @@ TEST_CASE("CRYPTO Frame", "[quic]") 0x05, // Length 0x01, 0x02, 0x03, 0x04, 0x05, // Crypto Data }; - uint8_t raw_data[] = "\x01\x02\x03\x04\x05"; - ats_unique_buf payload = ats_unique_malloc(5); - memcpy(payload.get(), raw_data, 5); + uint8_t raw_data[] = "\x01\x02\x03\x04\x05"; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), raw_data, 5); + block->fill(5); - QUICCryptoFrame crypto_frame(std::move(payload), 5, 0x010000); + QUICCryptoFrame crypto_frame(block, 0x010000); CHECK(crypto_frame.size() == sizeof(expected)); crypto_frame.store(buf, &len, 32); From 6e3d31a3a9e4909f5c392fcb5f243fd4fd36b842 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 28 Dec 2018 15:33:36 +0800 Subject: [PATCH 0988/1313] QUIC: Fixes Stream test case --- iocore/net/quic/test/test_QUICStream.cc | 98 ++++++++++++++----------- 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 40ad5638005..776b78625ba 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -29,40 +29,52 @@ TEST_CASE("QUICStream", "[quic]") { // Test Data - uint8_t payload[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; - uint32_t stream_id = 0x03; - - ats_unique_buf payload1 = ats_unique_malloc(2); - memcpy(payload1.get(), payload, 2); - std::shared_ptr frame_1 = std::make_shared(std::move(payload1), 2, stream_id, 0); - - ats_unique_buf payload2 = ats_unique_malloc(2); - memcpy(payload2.get(), payload + 2, 2); - std::shared_ptr frame_2 = std::make_shared(std::move(payload2), 2, stream_id, 2); - - ats_unique_buf payload3 = ats_unique_malloc(2); - memcpy(payload3.get(), payload + 4, 2); - std::shared_ptr frame_3 = std::make_shared(std::move(payload3), 2, stream_id, 4); - - ats_unique_buf payload4 = ats_unique_malloc(2); - memcpy(payload4.get(), payload + 6, 2); - std::shared_ptr frame_4 = std::make_shared(std::move(payload4), 2, stream_id, 6); - - ats_unique_buf payload5 = ats_unique_malloc(2); - memcpy(payload5.get(), payload + 8, 2); - std::shared_ptr frame_5 = std::make_shared(std::move(payload5), 2, stream_id, 8); - - ats_unique_buf payload6 = ats_unique_malloc(2); - memcpy(payload6.get(), payload + 10, 2); - std::shared_ptr frame_6 = std::make_shared(std::move(payload6), 2, stream_id, 10); - - ats_unique_buf payload7 = ats_unique_malloc(2); - memcpy(payload7.get(), payload + 12, 2); - std::shared_ptr frame_7 = std::make_shared(std::move(payload7), 2, stream_id, 12); - - ats_unique_buf payload8 = ats_unique_malloc(2); - memcpy(payload8.get(), payload + 14, 2); - std::shared_ptr frame_8 = std::make_shared(std::move(payload8), 2, stream_id, 14); + uint8_t payload[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; + uint32_t stream_id = 0x03; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), payload, sizeof(payload)); + block->fill(sizeof(payload)); + + Ptr new_block = make_ptr(block->clone()); + new_block->_end = new_block->_start + 2; + std::shared_ptr frame_1 = std::make_shared(new_block, stream_id, 0); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + std::shared_ptr frame_2 = std::make_shared(new_block, stream_id, 2); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + std::shared_ptr frame_3 = std::make_shared(new_block, stream_id, 4); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + std::shared_ptr frame_4 = std::make_shared(new_block, stream_id, 6); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + std::shared_ptr frame_5 = std::make_shared(new_block, stream_id, 8); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + std::shared_ptr frame_6 = std::make_shared(new_block, stream_id, 10); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + std::shared_ptr frame_7 = std::make_shared(new_block, stream_id, 12); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + std::shared_ptr frame_8 = std::make_shared(new_block, stream_id, 14); + block->consume(2); SECTION("QUICStream_assembling_byte_stream_1") { @@ -158,25 +170,29 @@ TEST_CASE("QUICStream", "[quic]") std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, 4096, 4096)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + block->fill(1024); + // Start with 1024 but not 0 so received frames won't be processed - error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 1024)); + error = stream->recv(*std::make_shared(block, stream_id, 1024)); CHECK(error == nullptr); // duplicate - error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 1024)); + error = stream->recv(*std::make_shared(block, stream_id, 1024)); CHECK(error == nullptr); - error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 3072)); + error = stream->recv(*std::make_shared(block, stream_id, 3072)); CHECK(error == nullptr); // delay - error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 2048)); + error = stream->recv(*std::make_shared(block, stream_id, 2048)); CHECK(error == nullptr); // all frames should be processed - error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 0)); + error = stream->recv(*std::make_shared(block, stream_id, 0)); CHECK(error == nullptr); // start again without the first block - error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 5120)); + error = stream->recv(*std::make_shared(block, stream_id, 5120)); CHECK(error == nullptr); // this should exceed the limit - error = stream->recv(*std::make_shared(ats_unique_malloc(1024), 1024, stream_id, 8192)); + error = stream->recv(*std::make_shared(block, stream_id, 8192)); CHECK(error->cls == QUICErrorClass::TRANSPORT); CHECK(error->code == static_cast(QUICTransErrorCode::FLOW_CONTROL_ERROR)); } From 63e24156283048d1bb837f5971eb0511a9c65d06 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 28 Dec 2018 15:13:04 +0800 Subject: [PATCH 0989/1313] QUIC: Records STREAM frame, RST frame, STOP_SENDING frame and MAX_STREAM_DATA frame --- iocore/net/quic/QUICStream.cc | 110 +++++++++++++++++++++++++++++++--- iocore/net/quic/QUICStream.h | 31 ++++++++++ 2 files changed, 132 insertions(+), 9 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index c2412ab1fe0..b0928c2ae5c 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -413,7 +413,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit // RST_STREAM if (this->_reset_reason && !this->_is_reset_sent) { frame = QUICFrameFactory::create_rst_stream_frame(*this->_reset_reason, this->_issue_frame_id(), this); - this->_records_frame(frame->id(), {frame->type(), level}); + this->_records_rst_stream_frame(*static_cast(frame.get())); this->_state.update_with_sending_frame(*frame); this->_is_reset_sent = true; return frame; @@ -423,7 +423,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit if (this->_stop_sending_reason && !this->_is_stop_sending_sent) { frame = QUICFrameFactory::create_stop_sending_frame(this->id(), this->_stop_sending_reason->code, this->_issue_frame_id(), this); - this->_records_frame(frame->id(), {frame->type(), level}); + this->_records_stop_sending_frame(*static_cast(frame.get())); this->_state.update_with_sending_frame(*frame); this->_is_stop_sending_sent = true; return frame; @@ -432,6 +432,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit // MAX_STREAM_DATA frame = this->_local_flow_controller.generate_frame(level, UINT16_MAX, maximum_frame_size); if (frame) { + this->_records_max_stream_data_frame(*static_cast(frame.get())); return frame; } @@ -491,7 +492,9 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit ink_assert(static_cast(block->read_avail()) == len); // STREAM - Pure FIN or data length is lager than 0 - frame = QUICFrameFactory::create_stream_frame(block, this->_id, this->_send_offset, fin); + // FIXME has_length_flag and has_offset_flag should be configurable + frame = + QUICFrameFactory::create_stream_frame(block, this->_id, this->_send_offset, fin, true, true, this->_issue_frame_id(), this); if (!this->_state.is_allowed_to_send(*frame)) { QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); return frame; @@ -514,6 +517,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit this->_send_offset += len; this->_write_vio.ndone += len; } + this->_records_stream_frame(*static_cast(frame.get()), block); this->_signal_write_event(); this->_state.update_with_sending_frame(*frame); @@ -521,24 +525,79 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit return frame; } +void +QUICStream::_records_stream_frame(const QUICStreamFrame &frame, Ptr &block) +{ + QUICFrameInformation info; + info.type = frame.type(); + StreamFrameInfo *frame_info = reinterpret_cast(info.data); + frame_info->offset = frame.offset(); + frame_info->has_fin = frame.has_fin_flag(); + frame_info->block = block; + this->_records_frame(frame.id(), info); +} + +void +QUICStream::_records_rst_stream_frame(const QUICRstStreamFrame &frame) +{ + QUICFrameInformation info; + info.type = frame.type(); + RstStreamFrameInfo *frame_info = reinterpret_cast(info.data); + frame_info->error_code = frame.error_code(); + frame_info->final_offset = frame.final_offset(); + this->_records_frame(frame.id(), info); +} + +void +QUICStream::_records_stop_sending_frame(const QUICStopSendingFrame &frame) +{ + QUICFrameInformation info; + info.type = frame.type(); + StopSendingFrameInfo *frame_info = reinterpret_cast(info.data); + frame_info->error_code = frame.error_code(); + this->_records_frame(frame.id(), info); +} + +void +QUICStream::_records_max_stream_data_frame(const QUICMaxStreamDataFrame &frame) +{ + QUICFrameInformation info; + info.type = frame.type(); + MaxStreamDataInfo *frame_info = reinterpret_cast(info.data); + frame_info->maximum_stream_data = frame.maximum_stream_data(); + this->_records_frame(frame.id(), info); +} + void QUICStream::_on_frame_acked(QUICFrameInformation info) { - if (info.type == QUICFrameType::RST_STREAM) { + StreamFrameInfo *frame_info = nullptr; + switch (info.type) { + case QUICFrameType::RST_STREAM: this->_is_reset_complete = true; - } else if (info.type == QUICFrameType::STREAM) { - // TODO Check if it received acks for every parts of data + break; + case QUICFrameType::STREAM: + frame_info = reinterpret_cast(info.data); + frame_info->block = nullptr; if (false) { this->_is_transfer_complete = true; } + break; + case QUICFrameType::STOP_SENDING: + case QUICFrameType::MAX_STREAM_DATA: + default: + break; } + this->_state.update_on_ack(); } void QUICStream::_on_frame_lost(QUICFrameInformation info) { - if (info.type == QUICFrameType::RST_STREAM) { + StreamFrameInfo *frame_info = nullptr; + switch (info.type) { + case QUICFrameType::RST_STREAM: // [draft-16] 13.2. Retransmission of Information // Cancellation of stream transmission, as carried in a RST_STREAM // frame, is sent until acknowledged or until all stream data is @@ -546,8 +605,17 @@ QUICStream::_on_frame_lost(QUICFrameInformation info) // "Data Recvd" state is reached on the send stream). The content of // a RST_STREAM frame MUST NOT change when it is sent again. this->_is_reset_sent = false; - } else if (info.type == QUICFrameType::STOP_SENDING) { + break; + case QUICFrameType::STREAM: + frame_info = reinterpret_cast(info.data); + frame_info->block = nullptr; + break; + case QUICFrameType::STOP_SENDING: this->_is_stop_sending_sent = false; + break; + case QUICFrameType::MAX_STREAM_DATA: + default: + break; } } @@ -824,9 +892,33 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ block->_end = std::min(block->start() + frame_payload_size, block->_buf_end); ink_assert(static_cast(block->read_avail()) == frame_payload_size); - frame = QUICFrameFactory::create_crypto_frame(block, this->_send_offset); + QUICFrameInformation info; + info.type = QUICFrameType::CRYPTO; + QUICFrameId frame_id = this->_issue_frame_id(); + CryptoFrameInformation *crypto_frame_info = reinterpret_cast(info.data); + crypto_frame_info->offset = this->_send_offset; + crypto_frame_info->block = block; + this->_records_frame(frame_id, info); + + frame = QUICFrameFactory::create_crypto_frame(block, this->_send_offset, frame_id, this); this->_send_offset += frame_payload_size; this->_write_buffer_reader->consume(frame_payload_size); return frame; } + +void +QUICCryptoStream::_on_frame_acked(QUICFrameInformation info) +{ + ink_assert(info.type == QUICFrameType::CRYPTO); + CryptoFrameInformation *crypto_frame_info = reinterpret_cast(info.data); + crypto_frame_info->block = nullptr; +} + +void +QUICCryptoStream::_on_frame_lost(QUICFrameInformation info) +{ + ink_assert(info.type == QUICFrameType::CRYPTO); + CryptoFrameInformation *crypto_frame_info = reinterpret_cast(info.data); + crypto_frame_info->block = nullptr; +} diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index fb6a64c95f6..0078460e092 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -99,6 +99,25 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra bool is_cancelled() const override; protected: + struct StreamFrameInfo { + QUICOffset offset; + bool has_fin; + Ptr block; + } stream_frame_info; + + struct MaxStreamDataInfo { + uint64_t maximum_stream_data; + }; + + struct RstStreamFrameInfo { + QUICAppErrorCode error_code; + QUICOffset final_offset; + }; + + struct StopSendingFrameInfo { + QUICAppErrorCode error_code; + }; + virtual int64_t _process_read_vio(); virtual int64_t _process_write_vio(); void _signal_read_event(); @@ -107,6 +126,10 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra Event *_send_tracked_event(Event *, int, VIO *); void _write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin); + void _records_max_stream_data_frame(const QUICMaxStreamDataFrame &frame); + void _records_rst_stream_frame(const QUICRstStreamFrame &frame); + void _records_stream_frame(const QUICStreamFrame &frame, Ptr &block); + void _records_stop_sending_frame(const QUICStopSendingFrame &frame); QUICStreamErrorUPtr _reset_reason = nullptr; bool _is_reset_sent = false; @@ -184,6 +207,14 @@ class QUICCryptoStream : public QUICFrameGenerator QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; private: + struct CryptoFrameInformation { + QUICOffset offset; + Ptr block; + }; + + void _on_frame_acked(QUICFrameInformation info) override; + void _on_frame_lost(QUICFrameInformation info) override; + QUICStreamErrorUPtr _reset_reason = nullptr; QUICOffset _send_offset = 0; From 0d463a6f69367231fb7b5dd0729f11232e45b905 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 8 Jan 2019 16:20:26 +0800 Subject: [PATCH 0990/1313] QUIC: Uses reference to the callback QUICFrameInformation --- iocore/net/quic/QUICAckFrameCreator.cc | 2 +- iocore/net/quic/QUICAckFrameCreator.h | 2 +- iocore/net/quic/QUICFlowController.cc | 4 ++-- iocore/net/quic/QUICFlowController.h | 4 ++-- iocore/net/quic/QUICFrameGenerator.h | 4 ++-- iocore/net/quic/QUICStream.cc | 8 ++++---- iocore/net/quic/QUICStream.h | 8 ++++---- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 14ae2f78175..3f6fbc738d7 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -96,7 +96,7 @@ QUICAckFrameManager::will_generate_frame(QUICEncryptionLevel level) } void -QUICAckFrameManager::_on_frame_acked(QUICFrameInformation info) +QUICAckFrameManager::_on_frame_acked(QUICFrameInformation &info) { ink_assert(info.type == QUICFrameType::ACK); AckFrameInfomation *ack_info = reinterpret_cast(info.data); diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 0e172449aab..19a9d5491f9 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -115,7 +115,7 @@ class QUICAckFrameManager : public QUICFrameGenerator QUICPacketNumber largest_acknowledged = 0; }; - virtual void _on_frame_acked(QUICFrameInformation info) override; + virtual void _on_frame_acked(QUICFrameInformation &info) override; /* * Returns QUICAckFrame only if ACK frame is able to be sent. diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 3ad4546fe93..738e076b9ef 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -149,7 +149,7 @@ QUICRemoteFlowController::update(QUICOffset offset) } void -QUICRemoteFlowController::_on_frame_lost(QUICFrameInformation info) +QUICRemoteFlowController::_on_frame_lost(QUICFrameInformation &info) { ink_assert(info.type == QUICFrameType::BLOCKED || info.type == QUICFrameType::STREAM_BLOCKED); if (this->_offset == *reinterpret_cast(info.data)) { @@ -192,7 +192,7 @@ QUICLocalFlowController::set_limit(QUICOffset limit) } void -QUICLocalFlowController::_on_frame_lost(QUICFrameInformation info) +QUICLocalFlowController::_on_frame_lost(QUICFrameInformation &info) { ink_assert(info.type == QUICFrameType::MAX_DATA || info.type == QUICFrameType::MAX_STREAM_DATA); if (this->_limit == *reinterpret_cast(info.data)) { diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index c3eb547a8a3..72d6095aa83 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -80,7 +80,7 @@ class QUICRemoteFlowController : public QUICFlowController void forward_limit(QUICOffset new_limit) override; private: - void _on_frame_lost(QUICFrameInformation info) override; + void _on_frame_lost(QUICFrameInformation &info) override; bool _blocked = false; }; @@ -101,7 +101,7 @@ class QUICLocalFlowController : public QUICFlowController void set_limit(QUICOffset limit) override; private: - void _on_frame_lost(QUICFrameInformation info) override; + void _on_frame_lost(QUICFrameInformation &info) override; bool _need_to_forward_limit(); QUICRateAnalyzer _analyzer; diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index c75d7489ab9..2b35062890d 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -50,12 +50,12 @@ class QUICFrameGenerator } virtual void - _on_frame_acked(QUICFrameInformation info) + _on_frame_acked(QUICFrameInformation &info) { } virtual void - _on_frame_lost(QUICFrameInformation info) + _on_frame_lost(QUICFrameInformation &info) { } diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index b0928c2ae5c..f7c3de18086 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -569,7 +569,7 @@ QUICStream::_records_max_stream_data_frame(const QUICMaxStreamDataFrame &frame) } void -QUICStream::_on_frame_acked(QUICFrameInformation info) +QUICStream::_on_frame_acked(QUICFrameInformation &info) { StreamFrameInfo *frame_info = nullptr; switch (info.type) { @@ -593,7 +593,7 @@ QUICStream::_on_frame_acked(QUICFrameInformation info) } void -QUICStream::_on_frame_lost(QUICFrameInformation info) +QUICStream::_on_frame_lost(QUICFrameInformation &info) { StreamFrameInfo *frame_info = nullptr; switch (info.type) { @@ -908,7 +908,7 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ } void -QUICCryptoStream::_on_frame_acked(QUICFrameInformation info) +QUICCryptoStream::_on_frame_acked(QUICFrameInformation &info) { ink_assert(info.type == QUICFrameType::CRYPTO); CryptoFrameInformation *crypto_frame_info = reinterpret_cast(info.data); @@ -916,7 +916,7 @@ QUICCryptoStream::_on_frame_acked(QUICFrameInformation info) } void -QUICCryptoStream::_on_frame_lost(QUICFrameInformation info) +QUICCryptoStream::_on_frame_lost(QUICFrameInformation &info) { ink_assert(info.type == QUICFrameType::CRYPTO); CryptoFrameInformation *crypto_frame_info = reinterpret_cast(info.data); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 0078460e092..001c110263d 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -164,8 +164,8 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra QUICBidirectionalStreamState _state; // QUICFrameGenerator - void _on_frame_acked(QUICFrameInformation info) override; - void _on_frame_lost(QUICFrameInformation info) override; + void _on_frame_acked(QUICFrameInformation &info) override; + void _on_frame_lost(QUICFrameInformation &info) override; }; /** @@ -212,8 +212,8 @@ class QUICCryptoStream : public QUICFrameGenerator Ptr block; }; - void _on_frame_acked(QUICFrameInformation info) override; - void _on_frame_lost(QUICFrameInformation info) override; + void _on_frame_acked(QUICFrameInformation &info) override; + void _on_frame_lost(QUICFrameInformation &info) override; QUICStreamErrorUPtr _reset_reason = nullptr; QUICOffset _send_offset = 0; From 285d910a5344b1935e65bcd166542cc2888b0eb2 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 8 Jan 2019 16:26:31 +0800 Subject: [PATCH 0991/1313] QUIC: Missed QUICNetVConnection _on_frame_lost --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index df5ebe692b9..eabc7713318 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -382,7 +382,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub bool _has_ack_only_packet_out = false; // QUICFrameGenerator - void _on_frame_lost(QUICFrameInformation info) override; + void _on_frame_lost(QUICFrameInformation &info) override; std::vector _encryption_level_filter() override { diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 76985deda3d..df65064ab00 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -2211,7 +2211,7 @@ QUICNetVConnection::generate_frame(QUICEncryptionLevel level, uint64_t connectio } void -QUICNetVConnection::_on_frame_lost(QUICFrameInformation info) +QUICNetVConnection::_on_frame_lost(QUICFrameInformation &info) { this->_is_resumption_token_sent = false; } From 2c81f2b647bc4b24ae0459388ede28f826fed93b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 11 Jan 2019 11:58:52 +0900 Subject: [PATCH 0992/1313] Start QUICNetVConnection after thread is assigned --- iocore/net/QUICNetProcessor.cc | 2 -- iocore/net/QUICNetVConnection.cc | 6 +++++- iocore/net/QUICPacketHandler.cc | 2 -- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index a3df3f114f3..eec45f15ff2 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -154,8 +154,6 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne SET_CONTINUATION_HANDLER(vc, &QUICNetVConnection::startEvent); - vc->start(); - if (t->is_event_type(opt->etype)) { MUTEX_TRY_LOCK(lock, cont->mutex, t); if (lock.is_locked()) { diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index df65064ab00..2c4fe4d9d4a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -208,6 +208,8 @@ QUICNetVConnection::acceptEvent(int event, Event *e) set_active_timeout(active_timeout_in); } + this->start(); + action_.continuation->handleEvent(NET_EVENT_ACCEPT, this); this->_schedule_packet_write_ready(); @@ -368,6 +370,8 @@ QUICNetVConnection::connectUp(EThread *t, int fd) // FIXME: complete do_io_xxxx instead this->read.enabled = 1; + this->start(); + // start QUIC handshake this->_schedule_packet_write_ready(); @@ -554,7 +558,7 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra } // XXX Setup QUICNetVConnection on regular EThread. -// QUICNetVConnection::init() and QUICNetVConnection::start() might be called on ET_UDP EThread. +// QUICNetVConnection::init() might be called on ET_UDP EThread. int QUICNetVConnection::state_pre_handshake(int event, Event *data) { diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 0886b6d75de..05d20b83975 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -321,12 +321,10 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) vc->id = net_next_connection_number(); vc->con.move(con); vc->submit_time = Thread::get_hrtime(); - vc->thread = eth; vc->mutex = new_ProxyMutex(); vc->action_ = *this->action_; vc->set_is_transparent(this->opt.f_inbound_transparent); vc->set_context(NET_VCONNECTION_IN); - vc->start(); vc->options.ip_proto = NetVCOptions::USE_UDP; vc->options.ip_family = udp_packet->from.sa.sa_family; From f848582a3d16c2bef08f11f8a557da0ddc47c07f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 11 Jan 2019 14:49:46 +0900 Subject: [PATCH 0993/1313] Set vc hander startEvent on out going QUICNetVC initialization --- iocore/net/QUICNetProcessor.cc | 5 +---- iocore/net/QUICNetVConnection.cc | 5 ++++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index eec45f15ff2..8c63668ffe7 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -141,6 +141,7 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne // Setup QUICNetVConnection 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); packet_handler->init(vc); @@ -152,8 +153,6 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne vc->mutex = cont->mutex; vc->action_ = cont; - SET_CONTINUATION_HANDLER(vc, &QUICNetVConnection::startEvent); - if (t->is_event_type(opt->etype)) { MUTEX_TRY_LOCK(lock, cont->mutex, t); if (lock.is_locked()) { @@ -172,8 +171,6 @@ QUICNetProcessor::connect_re(Continuation *cont, sockaddr const *remote_addr, Ne eventProcessor.schedule_imm(vc, opt->etype); } - // vc->connectUp(t, NO_FD); - return ACTION_RESULT_DONE; } diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2c4fe4d9d4a..5cba303016e 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -88,11 +88,12 @@ QUICNetVConnection::~QUICNetVConnection() } // XXX This might be called on ET_UDP thread +// Initialize QUICNetVC for out going connection (NET_VCONNECTION_OUT) void QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_cid, UDPConnection *udp_con, QUICPacketHandler *packet_handler) { - SET_HANDLER((NetVConnHandler)&QUICNetVConnection::acceptEvent); + SET_HANDLER((NetVConnHandler)&QUICNetVConnection::startEvent); this->_packet_transmitter_mutex = new_ProxyMutex(); this->_frame_transmitter_mutex = new_ProxyMutex(); this->_udp_con = udp_con; @@ -112,6 +113,8 @@ QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_ci QUICConDebug("dcid=%s scid=%s", dcid_hex_str, scid_hex_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) From feccf53db09466acdba8fd7f4c82dd88466d0a7a Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 10 Jan 2019 17:17:49 +0800 Subject: [PATCH 0994/1313] QUIC: Introduces QUICFrameRetranmsitter to retransmit frame --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/Makefile.am | 13 +- iocore/net/quic/QUICAckFrameCreator.cc | 18 +- iocore/net/quic/QUICAckFrameCreator.h | 6 +- iocore/net/quic/QUICFlowController.cc | 68 ++++-- iocore/net/quic/QUICFlowController.h | 4 +- iocore/net/quic/QUICFrame.cc | 5 +- iocore/net/quic/QUICFrameGenerator.cc | 4 +- iocore/net/quic/QUICFrameGenerator.h | 16 +- iocore/net/quic/QUICFrameRetransmitter.cc | 197 ++++++++++++++++++ iocore/net/quic/QUICFrameRetransmitter.h | 114 ++++++++++ iocore/net/quic/QUICStream.cc | 85 ++++---- iocore/net/quic/QUICStream.h | 36 +--- .../quic/test/test_QUICFrameRetransmitter.cc | 163 +++++++++++++++ 15 files changed, 599 insertions(+), 134 deletions(-) create mode 100644 iocore/net/quic/QUICFrameRetransmitter.cc create mode 100644 iocore/net/quic/QUICFrameRetransmitter.h create mode 100644 iocore/net/quic/test/test_QUICFrameRetransmitter.cc diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index eabc7713318..da5f732709d 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -382,7 +382,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub bool _has_ack_only_packet_out = false; // QUICFrameGenerator - void _on_frame_lost(QUICFrameInformation &info) override; + void _on_frame_lost(QUICFrameInformationUPtr &info) override; std::vector _encryption_level_filter() override { diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5cba303016e..2305c1f8959 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -2218,7 +2218,7 @@ QUICNetVConnection::generate_frame(QUICEncryptionLevel level, uint64_t connectio } void -QUICNetVConnection::_on_frame_lost(QUICFrameInformation &info) +QUICNetVConnection::_on_frame_lost(QUICFrameInformationUPtr &info) { this->_is_resumption_token_sent = false; } diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 1520407312e..6744958f633 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -79,7 +79,8 @@ libquic_a_SOURCES = \ QUICPacketRetransmitter.cc \ QUICPathValidator.cc \ QUICPinger.cc \ - QUICFrameGenerator.cc + QUICFrameGenerator.cc \ + QUICFrameRetransmitter.cc # # Check Programs @@ -103,7 +104,8 @@ check_PROGRAMS = \ test_QUICTransportParameters \ test_QUICType \ test_QUICTypeUtil \ - test_QUICVersionNegotiator + test_QUICVersionNegotiator \ + test_QUICFrameRetransmitter TESTS = $(check_PROGRAMS) @@ -270,6 +272,13 @@ test_QUICVersionNegotiator_SOURCES = \ $(test_main_SOURCES) \ ./test/test_QUICVersionNegotiator.cc +test_QUICFrameRetransmitter_CPPFLAGS = $(test_CPPFLAGS) +test_QUICFrameRetransmitter_LDFLAGS = @AM_LDFLAGS@ +test_QUICFrameRetransmitter_LDADD = $(test_LDADD) +test_QUICFrameRetransmitter_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICFrameRetransmitter.cc + # # clang-tidy # diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 3f6fbc738d7..08a046c967c 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -71,13 +71,13 @@ QUICAckFrameManager::generate_frame(QUICEncryptionLevel level, uint64_t connecti ack_frame = ack_creator->generate_ack_frame(maximum_frame_size); if (ack_frame != nullptr) { - QUICFrameInformation info; - AckFrameInfomation *ack_info = reinterpret_cast(info.data); + QUICFrameInformationUPtr info = std::make_unique(); + AckFrameInfo *ack_info = reinterpret_cast(info->data); ack_info->largest_acknowledged = ack_frame->largest_acknowledged(); - info.level = level; - info.type = ack_frame->type(); - this->_records_frame(ack_frame->id(), info); + info->level = level; + info->type = ack_frame->type(); + this->_records_frame(ack_frame->id(), std::move(info)); } return ack_frame; @@ -96,11 +96,11 @@ QUICAckFrameManager::will_generate_frame(QUICEncryptionLevel level) } void -QUICAckFrameManager::_on_frame_acked(QUICFrameInformation &info) +QUICAckFrameManager::_on_frame_acked(QUICFrameInformationUPtr &info) { - ink_assert(info.type == QUICFrameType::ACK); - AckFrameInfomation *ack_info = reinterpret_cast(info.data); - int index = QUICTypeUtil::pn_space_index(info.level); + ink_assert(info->type == QUICFrameType::ACK); + AckFrameInfo *ack_info = reinterpret_cast(info->data); + int index = QUICTypeUtil::pn_space_index(info->level); this->_ack_creator[index]->forget(ack_info->largest_acknowledged); } diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 19a9d5491f9..91e77f5cf43 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -111,11 +111,7 @@ class QUICAckFrameManager : public QUICFrameGenerator uint8_t ack_delay_exponent() const; private: - struct AckFrameInfomation { - QUICPacketNumber largest_acknowledged = 0; - }; - - virtual void _on_frame_acked(QUICFrameInformation &info) override; + virtual void _on_frame_acked(QUICFrameInformationUPtr &info) override; /* * Returns QUICAckFrame only if ACK frame is able to be sent. diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 738e076b9ef..e30e5f35379 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -149,10 +149,17 @@ QUICRemoteFlowController::update(QUICOffset offset) } void -QUICRemoteFlowController::_on_frame_lost(QUICFrameInformation &info) +QUICRemoteFlowController::_on_frame_lost(QUICFrameInformationUPtr &info) { - ink_assert(info.type == QUICFrameType::BLOCKED || info.type == QUICFrameType::STREAM_BLOCKED); - if (this->_offset == *reinterpret_cast(info.data)) { + ink_assert(info->type == QUICFrameType::BLOCKED || info->type == QUICFrameType::STREAM_BLOCKED); + QUICOffset offset = UINT64_MAX; + if (info->type == QUICFrameType::BLOCKED) { + offset = reinterpret_cast(info->data)->offset; + } else { + offset = reinterpret_cast(info->data)->offset; + } + + if (this->_offset == offset) { this->_frame = this->_create_frame(); } } @@ -192,10 +199,17 @@ QUICLocalFlowController::set_limit(QUICOffset limit) } void -QUICLocalFlowController::_on_frame_lost(QUICFrameInformation &info) +QUICLocalFlowController::_on_frame_lost(QUICFrameInformationUPtr &info) { - ink_assert(info.type == QUICFrameType::MAX_DATA || info.type == QUICFrameType::MAX_STREAM_DATA); - if (this->_limit == *reinterpret_cast(info.data)) { + ink_assert(info->type == QUICFrameType::MAX_DATA || info->type == QUICFrameType::MAX_STREAM_DATA); + uint64_t limit = UINT64_MAX; + if (info->type == QUICFrameType::MAX_DATA) { + limit = reinterpret_cast(info->data)->maximum_data; + } else { + limit = reinterpret_cast(info->data)->maximum_stream_data; + } + + if (this->_limit == limit) { this->_frame = this->_create_frame(); } } @@ -217,20 +231,26 @@ QUICLocalFlowController::_need_to_forward_limit() QUICFrameUPtr QUICRemoteConnectionFlowController::_create_frame() { - auto frame = QUICFrameFactory::create_blocked_frame(this->_offset, this->_issue_frame_id(), this); - QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; - *(reinterpret_cast(info.data)) = this->_offset; - this->_records_frame(frame->id(), info); + auto frame = QUICFrameFactory::create_blocked_frame(this->_offset, this->_issue_frame_id(), this); + QUICFrameInformationUPtr info = std::make_unique(); + BlockedFrameInfo *frame_info = reinterpret_cast(info->data); + info->type = frame->type(); + info->level = QUICEncryptionLevel::NONE; + frame_info->offset = this->_offset; + this->_records_frame(frame->id(), std::move(info)); return frame; } QUICFrameUPtr QUICLocalConnectionFlowController::_create_frame() { - auto frame = QUICFrameFactory::create_max_data_frame(this->_limit, this->_issue_frame_id(), this); - QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; - *(reinterpret_cast(info.data)) = this->_limit; - this->_records_frame(frame->id(), info); + auto frame = QUICFrameFactory::create_max_data_frame(this->_limit, this->_issue_frame_id(), this); + QUICFrameInformationUPtr info = std::make_unique(); + MaxDataFrameInfo *frame_info = reinterpret_cast(info->data); + info->type = frame->type(); + info->level = QUICEncryptionLevel::NONE; + frame_info->maximum_data = this->_limit; + this->_records_frame(frame->id(), std::move(info)); return frame; } @@ -238,9 +258,13 @@ QUICFrameUPtr QUICRemoteStreamFlowController::_create_frame() { auto frame = QUICFrameFactory::create_stream_blocked_frame(this->_stream_id, this->_offset, this->_issue_frame_id(), this); - QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; - *(reinterpret_cast(info.data)) = this->_offset; - this->_records_frame(frame->id(), info); + QUICFrameInformationUPtr info = std::make_unique(); + StreamBlockedFrameInfo *frame_info = reinterpret_cast(info->data); + info->type = frame->type(); + info->level = QUICEncryptionLevel::NONE; + frame_info->stream_id = this->_stream_id; + frame_info->offset = this->_offset; + this->_records_frame(frame->id(), std::move(info)); return frame; } @@ -248,8 +272,12 @@ QUICFrameUPtr QUICLocalStreamFlowController::_create_frame() { auto frame = QUICFrameFactory::create_max_stream_data_frame(this->_stream_id, this->_limit, this->_issue_frame_id(), this); - QUICFrameInformation info = {frame->type(), QUICEncryptionLevel::NONE}; - *(reinterpret_cast(info.data)) = this->_limit; - this->_records_frame(frame->id(), info); + QUICFrameInformationUPtr info = std::make_unique(); + MaxStreamDataFrameInfo *frame_info = reinterpret_cast(info->data); + info->type = frame->type(); + info->level = QUICEncryptionLevel::NONE; + frame_info->stream_id = this->_stream_id; + frame_info->maximum_stream_data = this->_limit; + this->_records_frame(frame->id(), std::move(info)); return frame; } diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index 72d6095aa83..b10daad9d29 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -80,7 +80,7 @@ class QUICRemoteFlowController : public QUICFlowController void forward_limit(QUICOffset new_limit) override; private: - void _on_frame_lost(QUICFrameInformation &info) override; + void _on_frame_lost(QUICFrameInformationUPtr &info) override; bool _blocked = false; }; @@ -101,7 +101,7 @@ class QUICLocalFlowController : public QUICFlowController void set_limit(QUICOffset limit) override; private: - void _on_frame_lost(QUICFrameInformation &info) override; + void _on_frame_lost(QUICFrameInformationUPtr &info) override; bool _need_to_forward_limit(); QUICRateAnalyzer _analyzer; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 0eff6abd6ea..8eda35a3b6e 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2887,8 +2887,9 @@ QUICStreamFrameUPtr QUICFrameFactory::create_stream_frame(Ptr &block, QUICStreamId stream_id, QUICOffset offset, bool last, bool has_offset_field, bool has_length_field, QUICFrameId id, QUICFrameGenerator *owner) { - QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(block, stream_id, offset, last, has_offset_field, has_length_field, id, owner); + Ptr new_block = make_ptr(block->clone()); + QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); + new (frame) QUICStreamFrame(new_block, stream_id, offset, last, has_offset_field, has_length_field, id, owner); return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); } diff --git a/iocore/net/quic/QUICFrameGenerator.cc b/iocore/net/quic/QUICFrameGenerator.cc index 96aa0587d82..0969445639a 100644 --- a/iocore/net/quic/QUICFrameGenerator.cc +++ b/iocore/net/quic/QUICFrameGenerator.cc @@ -24,9 +24,9 @@ #include "QUICFrameGenerator.h" void -QUICFrameGenerator::_records_frame(QUICFrameId id, QUICFrameInformation info) +QUICFrameGenerator::_records_frame(QUICFrameId id, QUICFrameInformationUPtr info) { - this->_info.insert(std::make_pair(id, info)); + this->_info.insert(std::make_pair(id, std::move(info))); } std::vector diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index 2b35062890d..0f1c50f1713 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -24,13 +24,7 @@ #pragma once #include "QUICFrame.h" - -struct QUICFrameInformation { - QUICFrameType type; - QUICEncryptionLevel level; - - uint8_t data[1024] = {}; -}; +#include "QUICFrameRetransmitter.h" class QUICFrameGenerator { @@ -50,20 +44,20 @@ class QUICFrameGenerator } virtual void - _on_frame_acked(QUICFrameInformation &info) + _on_frame_acked(QUICFrameInformationUPtr &info) { } virtual void - _on_frame_lost(QUICFrameInformation &info) + _on_frame_lost(QUICFrameInformationUPtr &info) { } virtual std::vector _encryption_level_filter(); virtual bool _is_level_matched(QUICEncryptionLevel level); - void _records_frame(QUICFrameId id, QUICFrameInformation info); + void _records_frame(QUICFrameId id, QUICFrameInformationUPtr info); private: QUICFrameId _latest_frame_Id = 0; - std::map _info; + std::map _info; }; diff --git a/iocore/net/quic/QUICFrameRetransmitter.cc b/iocore/net/quic/QUICFrameRetransmitter.cc new file mode 100644 index 00000000000..ad9fd8dee0a --- /dev/null +++ b/iocore/net/quic/QUICFrameRetransmitter.cc @@ -0,0 +1,197 @@ +/** @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 "tscore/Diags.h" + +#include "QUICFrameRetransmitter.h" +#include "QUICFrameGenerator.h" +#include "QUICDebugNames.h" + +QUICFrameUPtr +QUICFrameRetransmitter::create_retransmitted_frame(QUICEncryptionLevel level, uint16_t maximum_frame_size, QUICFrameId id, + QUICFrameGenerator *owner) +{ + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + if (this->_lost_frame_info_queue.empty()) { + return frame; + } + + std::deque tmp_queue; + for (auto it = this->_lost_frame_info_queue.begin(); it != this->_lost_frame_info_queue.end(); + it = this->_lost_frame_info_queue.begin()) { + QUICFrameInformationUPtr &info = *it; + + if (info->level != QUICEncryptionLevel::NONE && info->level != level) { + // skip unmapped info. + tmp_queue.push_back(std::move(info)); + this->_lost_frame_info_queue.pop_front(); + continue; + } + + switch (info->type) { + case QUICFrameType::STREAM: + frame = this->_create_stream_frame(info, maximum_frame_size, tmp_queue, id, owner); + break; + case QUICFrameType::RST_STREAM: + frame = this->_create_reset_stream_frame(info, maximum_frame_size, tmp_queue, id, owner); + break; + case QUICFrameType::STOP_SENDING: + frame = this->_create_stop_sending_frame(info, maximum_frame_size, tmp_queue, id, owner); + break; + case QUICFrameType::MAX_STREAM_DATA: + frame = this->_create_max_stream_data_frame(info, maximum_frame_size, tmp_queue, id, owner); + break; + case QUICFrameType::MAX_DATA: + frame = this->_create_max_data_frame(info, maximum_frame_size, tmp_queue, id, owner); + break; + default: + ink_assert("unknown frame type"); + Error("unknown frame type: %s", QUICDebugNames::frame_type(info->type)); + } + + this->_lost_frame_info_queue.pop_front(); + if (frame != nullptr) { + break; + } + } + + this->_append_info_queue(tmp_queue); + return frame; +} + +void +QUICFrameRetransmitter::save_frame_info(QUICFrameInformationUPtr &info) +{ + for (auto type : RETRANSMITTED_FRAME_TYPE) { + if (type == info->type) { + this->_lost_frame_info_queue.push_back(std::move(info)); + break; + } + } +} + +void +QUICFrameRetransmitter::_append_info_queue(std::deque &tmp_queue) +{ + auto it = tmp_queue.begin(); + while (it != tmp_queue.end()) { + this->_lost_frame_info_queue.push_back(std::move(*it)); + tmp_queue.pop_front(); + it = tmp_queue.begin(); + } +} + +QUICFrameUPtr +QUICFrameRetransmitter::_create_stream_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, + QUICFrameGenerator *owner) +{ + StreamFrameInfo *stream_info = reinterpret_cast(info->data); + // FIXME: has_offset and has_length should be configurable. + auto frame = QUICFrameFactory::create_stream_frame(stream_info->block, stream_info->stream_id, stream_info->offset, + stream_info->has_fin, true, true, id, owner); + if (frame->size() > maximum_frame_size) { + auto new_frame = QUICFrameFactory::split_frame(frame.get(), maximum_frame_size); + if (new_frame == nullptr) { + // can not split stream frame. Because of too small maximum_frame_size. + tmp_queue.push_back(std::move(info)); + return QUICFrameFactory::create_null_frame(); + } else { + QUICStreamFrame *stream_frame = static_cast(frame.get()); + stream_info->block->consume(stream_frame->data_length()); + stream_info->offset += stream_frame->data_length(); + ink_assert(frame->size() <= maximum_frame_size); + tmp_queue.push_back(std::move(info)); + return frame; + } + } + + stream_info->block = nullptr; + ink_assert(frame != nullptr); + return frame; +} + +QUICFrameUPtr +QUICFrameRetransmitter::_create_reset_stream_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, + QUICFrameGenerator *owner) +{ + RstStreamFrameInfo *rst_info = reinterpret_cast(info->data); + auto frame = + QUICFrameFactory::create_rst_stream_frame(rst_info->stream_id, rst_info->error_code, rst_info->final_offset, id, owner); + if (frame->size() > maximum_frame_size) { + tmp_queue.push_back(std::move(info)); + return QUICFrameFactory::create_null_frame(); + } + + ink_assert(frame != nullptr); + return frame; +} + +QUICFrameUPtr +QUICFrameRetransmitter::_create_max_stream_data_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, + QUICFrameGenerator *owner) +{ + MaxStreamDataFrameInfo *frame_info = reinterpret_cast(info->data); + auto frame = QUICFrameFactory::create_max_stream_data_frame(frame_info->stream_id, frame_info->maximum_stream_data, id, owner); + if (frame->size() > maximum_frame_size) { + tmp_queue.push_back(std::move(info)); + return QUICFrameFactory::create_null_frame(); + } + + ink_assert(frame != nullptr); + return frame; +} + +QUICFrameUPtr +QUICFrameRetransmitter::_create_max_data_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, + QUICFrameGenerator *owner) +{ + MaxDataFrameInfo *frame_info = reinterpret_cast(info->data); + auto frame = QUICFrameFactory::create_max_data_frame(frame_info->maximum_data, id, owner); + if (frame->size() > maximum_frame_size) { + tmp_queue.push_back(std::move(info)); + return QUICFrameFactory::create_null_frame(); + } + + ink_assert(frame != nullptr); + return frame; +} + +QUICFrameUPtr +QUICFrameRetransmitter::_create_stop_sending_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, + QUICFrameGenerator *owner) +{ + StopSendingFrameInfo *frame_info = reinterpret_cast(info->data); + auto frame = QUICFrameFactory::create_stop_sending_frame(frame_info->stream_id, frame_info->error_code, id, owner); + if (frame->size() > maximum_frame_size) { + tmp_queue.push_back(std::move(info)); + return QUICFrameFactory::create_null_frame(); + } + + ink_assert(frame != nullptr); + return frame; +} diff --git a/iocore/net/quic/QUICFrameRetransmitter.h b/iocore/net/quic/QUICFrameRetransmitter.h new file mode 100644 index 00000000000..8da30cee6a2 --- /dev/null +++ b/iocore/net/quic/QUICFrameRetransmitter.h @@ -0,0 +1,114 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include "QUICFrame.h" + +class QUICFrameGenerator; + +struct QUICFrameInformation { + QUICFrameType type; + QUICEncryptionLevel level; + + uint8_t data[1024] = {}; +}; + +typedef std::unique_ptr QUICFrameInformationUPtr; + +constexpr QUICFrameType RETRANSMITTED_FRAME_TYPE[] = {QUICFrameType::STREAM, QUICFrameType::STOP_SENDING, + QUICFrameType::MAX_STREAM_DATA, QUICFrameType::RST_STREAM, + QUICFrameType::MAX_DATA}; + +struct StreamFrameInfo { + QUICStreamId stream_id; + QUICOffset offset; + bool has_fin; + Ptr block; +}; + +struct MaxStreamDataFrameInfo { + QUICStreamId stream_id; + uint64_t maximum_stream_data; +}; + +struct RstStreamFrameInfo { + QUICStreamId stream_id; + QUICAppErrorCode error_code; + QUICOffset final_offset; +}; + +struct StopSendingFrameInfo { + QUICStreamId stream_id; + QUICAppErrorCode error_code; +}; + +struct MaxDataFrameInfo { + uint64_t maximum_data; +}; + +struct BlockedFrameInfo { + QUICOffset offset; +}; + +struct StreamBlockedFrameInfo { + QUICStreamId stream_id; + QUICOffset offset; +}; + +struct CryptoFrameInfo { + QUICOffset offset; + Ptr block; +}; + +struct AckFrameInfo { + QUICPacketNumber largest_acknowledged; +}; + +class QUICFrameRetransmitter +{ +public: + virtual QUICFrameUPtr create_retransmitted_frame(QUICEncryptionLevel level, uint16_t maximum_frame_size, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); + virtual void save_frame_info(QUICFrameInformationUPtr &info); + +private: + QUICFrameUPtr _create_stream_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner); + QUICFrameUPtr _create_reset_stream_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, + QUICFrameGenerator *owner); + QUICFrameUPtr _create_max_stream_data_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, + QUICFrameGenerator *owner); + QUICFrameUPtr _create_stop_sending_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, + QUICFrameGenerator *owner); + QUICFrameUPtr _create_max_data_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner); + + void _append_info_queue(std::deque &tmp_queue); + + std::deque _lost_frame_info_queue; +}; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index f7c3de18086..ed9bf321592 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -432,7 +432,6 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit // MAX_STREAM_DATA frame = this->_local_flow_controller.generate_frame(level, UINT16_MAX, maximum_frame_size); if (frame) { - this->_records_max_stream_data_frame(*static_cast(frame.get())); return frame; } @@ -528,63 +527,52 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit void QUICStream::_records_stream_frame(const QUICStreamFrame &frame, Ptr &block) { - QUICFrameInformation info; - info.type = frame.type(); - StreamFrameInfo *frame_info = reinterpret_cast(info.data); - frame_info->offset = frame.offset(); - frame_info->has_fin = frame.has_fin_flag(); - frame_info->block = block; - this->_records_frame(frame.id(), info); + QUICFrameInformationUPtr info = std::make_unique(); + info->type = frame.type(); + StreamFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->offset = frame.offset(); + frame_info->has_fin = frame.has_fin_flag(); + frame_info->block = block; + this->_records_frame(frame.id(), std::move(info)); } void QUICStream::_records_rst_stream_frame(const QUICRstStreamFrame &frame) { - QUICFrameInformation info; - info.type = frame.type(); - RstStreamFrameInfo *frame_info = reinterpret_cast(info.data); + QUICFrameInformationUPtr info = std::make_unique(); + info->type = frame.type(); + RstStreamFrameInfo *frame_info = reinterpret_cast(info->data); frame_info->error_code = frame.error_code(); frame_info->final_offset = frame.final_offset(); - this->_records_frame(frame.id(), info); + this->_records_frame(frame.id(), std::move(info)); } void QUICStream::_records_stop_sending_frame(const QUICStopSendingFrame &frame) { - QUICFrameInformation info; - info.type = frame.type(); - StopSendingFrameInfo *frame_info = reinterpret_cast(info.data); + QUICFrameInformationUPtr info = std::make_unique(); + info->type = frame.type(); + StopSendingFrameInfo *frame_info = reinterpret_cast(info->data); frame_info->error_code = frame.error_code(); - this->_records_frame(frame.id(), info); + this->_records_frame(frame.id(), std::move(info)); } void -QUICStream::_records_max_stream_data_frame(const QUICMaxStreamDataFrame &frame) -{ - QUICFrameInformation info; - info.type = frame.type(); - MaxStreamDataInfo *frame_info = reinterpret_cast(info.data); - frame_info->maximum_stream_data = frame.maximum_stream_data(); - this->_records_frame(frame.id(), info); -} - -void -QUICStream::_on_frame_acked(QUICFrameInformation &info) +QUICStream::_on_frame_acked(QUICFrameInformationUPtr &info) { StreamFrameInfo *frame_info = nullptr; - switch (info.type) { + switch (info->type) { case QUICFrameType::RST_STREAM: this->_is_reset_complete = true; break; case QUICFrameType::STREAM: - frame_info = reinterpret_cast(info.data); + frame_info = reinterpret_cast(info->data); frame_info->block = nullptr; if (false) { this->_is_transfer_complete = true; } break; case QUICFrameType::STOP_SENDING: - case QUICFrameType::MAX_STREAM_DATA: default: break; } @@ -593,10 +581,10 @@ QUICStream::_on_frame_acked(QUICFrameInformation &info) } void -QUICStream::_on_frame_lost(QUICFrameInformation &info) +QUICStream::_on_frame_lost(QUICFrameInformationUPtr &info) { StreamFrameInfo *frame_info = nullptr; - switch (info.type) { + switch (info->type) { case QUICFrameType::RST_STREAM: // [draft-16] 13.2. Retransmission of Information // Cancellation of stream transmission, as carried in a RST_STREAM @@ -607,13 +595,12 @@ QUICStream::_on_frame_lost(QUICFrameInformation &info) this->_is_reset_sent = false; break; case QUICFrameType::STREAM: - frame_info = reinterpret_cast(info.data); + frame_info = reinterpret_cast(info->data); frame_info->block = nullptr; break; case QUICFrameType::STOP_SENDING: this->_is_stop_sending_sent = false; break; - case QUICFrameType::MAX_STREAM_DATA: default: break; } @@ -892,13 +879,13 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ block->_end = std::min(block->start() + frame_payload_size, block->_buf_end); ink_assert(static_cast(block->read_avail()) == frame_payload_size); - QUICFrameInformation info; - info.type = QUICFrameType::CRYPTO; - QUICFrameId frame_id = this->_issue_frame_id(); - CryptoFrameInformation *crypto_frame_info = reinterpret_cast(info.data); - crypto_frame_info->offset = this->_send_offset; - crypto_frame_info->block = block; - this->_records_frame(frame_id, info); + QUICFrameInformationUPtr info = std::make_unique(); + info->type = QUICFrameType::CRYPTO; + QUICFrameId frame_id = this->_issue_frame_id(); + CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); + crypto_frame_info->offset = this->_send_offset; + crypto_frame_info->block = block; + this->_records_frame(frame_id, std::move(info)); frame = QUICFrameFactory::create_crypto_frame(block, this->_send_offset, frame_id, this); this->_send_offset += frame_payload_size; @@ -908,17 +895,17 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ } void -QUICCryptoStream::_on_frame_acked(QUICFrameInformation &info) +QUICCryptoStream::_on_frame_acked(QUICFrameInformationUPtr &info) { - ink_assert(info.type == QUICFrameType::CRYPTO); - CryptoFrameInformation *crypto_frame_info = reinterpret_cast(info.data); - crypto_frame_info->block = nullptr; + ink_assert(info->type == QUICFrameType::CRYPTO); + CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); + crypto_frame_info->block = nullptr; } void -QUICCryptoStream::_on_frame_lost(QUICFrameInformation &info) +QUICCryptoStream::_on_frame_lost(QUICFrameInformationUPtr &info) { - ink_assert(info.type == QUICFrameType::CRYPTO); - CryptoFrameInformation *crypto_frame_info = reinterpret_cast(info.data); - crypto_frame_info->block = nullptr; + ink_assert(info->type == QUICFrameType::CRYPTO); + CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); + crypto_frame_info->block = nullptr; } diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 001c110263d..c0aec9dff93 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -33,12 +33,13 @@ #include "QUICIncomingFrameBuffer.h" #include "QUICFrameGenerator.h" #include "QUICConnection.h" +#include "QUICFrameRetransmitter.h" /** * @brief QUIC Stream * TODO: This is similar to Http2Stream. Need to think some integration. */ -class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTransferProgressProvider +class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTransferProgressProvider, public QUICFrameRetransmitter { public: QUICStream() @@ -99,25 +100,6 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra bool is_cancelled() const override; protected: - struct StreamFrameInfo { - QUICOffset offset; - bool has_fin; - Ptr block; - } stream_frame_info; - - struct MaxStreamDataInfo { - uint64_t maximum_stream_data; - }; - - struct RstStreamFrameInfo { - QUICAppErrorCode error_code; - QUICOffset final_offset; - }; - - struct StopSendingFrameInfo { - QUICAppErrorCode error_code; - }; - virtual int64_t _process_read_vio(); virtual int64_t _process_write_vio(); void _signal_read_event(); @@ -126,7 +108,6 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra Event *_send_tracked_event(Event *, int, VIO *); void _write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin); - void _records_max_stream_data_frame(const QUICMaxStreamDataFrame &frame); void _records_rst_stream_frame(const QUICRstStreamFrame &frame); void _records_stream_frame(const QUICStreamFrame &frame, Ptr &block); void _records_stop_sending_frame(const QUICStopSendingFrame &frame); @@ -164,8 +145,8 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra QUICBidirectionalStreamState _state; // QUICFrameGenerator - void _on_frame_acked(QUICFrameInformation &info) override; - void _on_frame_lost(QUICFrameInformation &info) override; + void _on_frame_acked(QUICFrameInformationUPtr &info) override; + void _on_frame_lost(QUICFrameInformationUPtr &info) override; }; /** @@ -207,13 +188,8 @@ class QUICCryptoStream : public QUICFrameGenerator QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; private: - struct CryptoFrameInformation { - QUICOffset offset; - Ptr block; - }; - - void _on_frame_acked(QUICFrameInformation &info) override; - void _on_frame_lost(QUICFrameInformation &info) override; + void _on_frame_acked(QUICFrameInformationUPtr &info) override; + void _on_frame_lost(QUICFrameInformationUPtr &info) override; QUICStreamErrorUPtr _reset_reason = nullptr; QUICOffset _send_offset = 0; diff --git a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc new file mode 100644 index 00000000000..5f246fdfc89 --- /dev/null +++ b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc @@ -0,0 +1,163 @@ +/** @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 "catch.hpp" + +#include "QUICFrameRetransmitter.h" + +constexpr static uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}; + +TEST_CASE("QUICFrameRetransmitter ignore frame which can not be retranmistted", "[quic]") +{ + QUICFrameRetransmitter retransmitter; + QUICFrameInformationUPtr info = std::make_unique(); + info->type = QUICFrameType::PING; + info->level = QUICEncryptionLevel::NONE; + + retransmitter.save_frame_info(info); + CHECK(retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX) == nullptr); +} + +TEST_CASE("QUICFrameRetransmitter ignore frame which can not be split", "[quic]") +{ + QUICFrameRetransmitter retransmitter; + QUICFrameInformationUPtr info = std::make_unique(); + info->type = QUICFrameType::STOP_SENDING; + info->level = QUICEncryptionLevel::NONE; + + retransmitter.save_frame_info(info); + CHECK(retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 0) == nullptr); +} + +TEST_CASE("QUICFrameRetransmitter ignore frame which has wrong level", "[quic]") +{ + QUICFrameRetransmitter retransmitter; + QUICFrameInformationUPtr info = std::make_unique(); + info->type = QUICFrameType::STOP_SENDING; + info->level = QUICEncryptionLevel::HANDSHAKE; + + retransmitter.save_frame_info(info); + CHECK(retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX) == nullptr); +} + +TEST_CASE("QUICFrameRetransmitter successfully create retransmitted frame", "[quic]") +{ + QUICFrameRetransmitter retransmitter; + QUICFrameInformationUPtr info = std::make_unique(); + info->type = QUICFrameType::STOP_SENDING; + info->level = QUICEncryptionLevel::INITIAL; + + retransmitter.save_frame_info(info); + + auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); + CHECK(frame != nullptr); + CHECK(frame->type() == QUICFrameType::STOP_SENDING); +} + +TEST_CASE("QUICFrameRetransmitter successfully create stream frame", "[quic]") +{ + QUICFrameRetransmitter retransmitter; + QUICFrameInformationUPtr info = std::make_unique(); + info->type = QUICFrameType::STREAM; + info->level = QUICEncryptionLevel::INITIAL; + + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), data, sizeof(data)); + block->fill(sizeof(data)); + + StreamFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->stream_id = 0x12345; + frame_info->offset = 0x67890; + frame_info->block = block; + + CHECK(block->refcount() == 2); + retransmitter.save_frame_info(info); + CHECK(block->refcount() == 2); // block's refcount doesn't change + + auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); + CHECK(frame != nullptr); + CHECK(frame->type() == QUICFrameType::STREAM); + auto stream_frame = static_cast(frame.get()); + CHECK(stream_frame->stream_id() == 0x12345); + CHECK(stream_frame->offset() == 0x67890); + CHECK(stream_frame->data_length() == sizeof(data)); + CHECK(memcmp(stream_frame->data(), data, sizeof(data)) == 0); + frame = QUICFrameFactory::create_null_frame(); + // Becasue the info has been released, the refcount should be 1 (var block). + CHECK(block->refcount() == 1); +} + +TEST_CASE("QUICFrameRetransmitter successfully split stream frame", "[quic]") +{ + QUICFrameRetransmitter retransmitter; + QUICFrameInformationUPtr info = std::make_unique(); + info->type = QUICFrameType::STREAM; + info->level = QUICEncryptionLevel::INITIAL; + + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), data, sizeof(data)); + block->fill(sizeof(data)); + + StreamFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->stream_id = 0x12345; + frame_info->offset = 0x67890; + frame_info->block = block; + CHECK(block->refcount() == 2); + + retransmitter.save_frame_info(info); + + auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 15); + CHECK(frame != nullptr); + CHECK(frame->type() == QUICFrameType::STREAM); + auto stream_frame = static_cast(frame.get()); + CHECK(stream_frame->stream_id() == 0x12345); + CHECK(stream_frame->offset() == 0x67890); + CHECK(stream_frame->size() <= 15); + + auto size = stream_frame->data_length(); + CHECK(memcmp(stream_frame->data(), data, stream_frame->data_length()) == 0); + // one for var block, one for the left data which saved in retransmitter + CHECK(block->data->refcount() == 2); + // one for var block, one for the left data which saved in retransmitter, one for var frame + CHECK(block->refcount() == 2); + frame = QUICFrameFactory::create_null_frame(); + // one for var block, one for var info + CHECK(block->refcount() == 2); + CHECK(block->data->refcount() == 1); + + frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); + CHECK(frame != nullptr); + CHECK(frame->type() == QUICFrameType::STREAM); + stream_frame = static_cast(frame.get()); + CHECK(stream_frame->stream_id() == 0x12345); + CHECK(stream_frame->offset() == 0x67890 + size); + CHECK(stream_frame->data_length() == sizeof(data) - size); + CHECK(memcmp(stream_frame->data(), data + size, stream_frame->data_length()) == 0); + CHECK(block->refcount() == 1); // one for var block + + frame = QUICFrameFactory::create_null_frame(); + CHECK(block->refcount() == 1); + CHECK(block->data->refcount() == 1); +} From 3e4ac8eff5531a8b212eb92f604c3a248d8127b1 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 11 Jan 2019 10:07:24 +0800 Subject: [PATCH 0995/1313] QUIC: Uses Allocator to alloc QUICFrameInformation --- iocore/net/quic/QUICAckFrameCreator.cc | 2 +- iocore/net/quic/QUICFlowController.cc | 8 ++++---- iocore/net/quic/QUICFrameRetransmitter.cc | 2 ++ iocore/net/quic/QUICFrameRetransmitter.h | 16 ++++++++++++++-- iocore/net/quic/QUICStream.cc | 8 ++++---- .../net/quic/test/test_QUICFrameRetransmitter.cc | 12 ++++++------ 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 08a046c967c..5f6df9a8205 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -71,7 +71,7 @@ QUICAckFrameManager::generate_frame(QUICEncryptionLevel level, uint64_t connecti ack_frame = ack_creator->generate_ack_frame(maximum_frame_size); if (ack_frame != nullptr) { - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); AckFrameInfo *ack_info = reinterpret_cast(info->data); ack_info->largest_acknowledged = ack_frame->largest_acknowledged(); diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index e30e5f35379..2f9c12e3a28 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -232,7 +232,7 @@ QUICFrameUPtr QUICRemoteConnectionFlowController::_create_frame() { auto frame = QUICFrameFactory::create_blocked_frame(this->_offset, this->_issue_frame_id(), this); - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); BlockedFrameInfo *frame_info = reinterpret_cast(info->data); info->type = frame->type(); info->level = QUICEncryptionLevel::NONE; @@ -245,7 +245,7 @@ QUICFrameUPtr QUICLocalConnectionFlowController::_create_frame() { auto frame = QUICFrameFactory::create_max_data_frame(this->_limit, this->_issue_frame_id(), this); - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); MaxDataFrameInfo *frame_info = reinterpret_cast(info->data); info->type = frame->type(); info->level = QUICEncryptionLevel::NONE; @@ -258,7 +258,7 @@ QUICFrameUPtr QUICRemoteStreamFlowController::_create_frame() { auto frame = QUICFrameFactory::create_stream_blocked_frame(this->_stream_id, this->_offset, this->_issue_frame_id(), this); - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); StreamBlockedFrameInfo *frame_info = reinterpret_cast(info->data); info->type = frame->type(); info->level = QUICEncryptionLevel::NONE; @@ -272,7 +272,7 @@ QUICFrameUPtr QUICLocalStreamFlowController::_create_frame() { auto frame = QUICFrameFactory::create_max_stream_data_frame(this->_stream_id, this->_limit, this->_issue_frame_id(), this); - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); MaxStreamDataFrameInfo *frame_info = reinterpret_cast(info->data); info->type = frame->type(); info->level = QUICEncryptionLevel::NONE; diff --git a/iocore/net/quic/QUICFrameRetransmitter.cc b/iocore/net/quic/QUICFrameRetransmitter.cc index ad9fd8dee0a..80655be9e1f 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.cc +++ b/iocore/net/quic/QUICFrameRetransmitter.cc @@ -27,6 +27,8 @@ #include "QUICFrameGenerator.h" #include "QUICDebugNames.h" +ClassAllocator quicFrameInformationAllocator("quicFrameInformationAllocator"); + QUICFrameUPtr QUICFrameRetransmitter::create_retransmitted_frame(QUICEncryptionLevel level, uint16_t maximum_frame_size, QUICFrameId id, QUICFrameGenerator *owner) diff --git a/iocore/net/quic/QUICFrameRetransmitter.h b/iocore/net/quic/QUICFrameRetransmitter.h index 8da30cee6a2..6eb259a83a2 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.h +++ b/iocore/net/quic/QUICFrameRetransmitter.h @@ -32,10 +32,14 @@ struct QUICFrameInformation { QUICFrameType type; QUICEncryptionLevel level; - uint8_t data[1024] = {}; + uint8_t data[128] = {}; }; -typedef std::unique_ptr QUICFrameInformationUPtr; +struct QUICFrameInformationDeleter { + void operator()(QUICFrameInformation *p); +}; + +using QUICFrameInformationUPtr = std::unique_ptr; constexpr QUICFrameType RETRANSMITTED_FRAME_TYPE[] = {QUICFrameType::STREAM, QUICFrameType::STOP_SENDING, QUICFrameType::MAX_STREAM_DATA, QUICFrameType::RST_STREAM, @@ -112,3 +116,11 @@ class QUICFrameRetransmitter std::deque _lost_frame_info_queue; }; + +extern ClassAllocator quicFrameInformationAllocator; + +inline void +QUICFrameInformationDeleter::operator()(QUICFrameInformation *p) +{ + quicFrameInformationAllocator.free(p); +} diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index ed9bf321592..ac781e6f55a 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -527,7 +527,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit void QUICStream::_records_stream_frame(const QUICStreamFrame &frame, Ptr &block) { - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = frame.type(); StreamFrameInfo *frame_info = reinterpret_cast(info->data); frame_info->offset = frame.offset(); @@ -539,7 +539,7 @@ QUICStream::_records_stream_frame(const QUICStreamFrame &frame, Ptr(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = frame.type(); RstStreamFrameInfo *frame_info = reinterpret_cast(info->data); frame_info->error_code = frame.error_code(); @@ -550,7 +550,7 @@ QUICStream::_records_rst_stream_frame(const QUICRstStreamFrame &frame) void QUICStream::_records_stop_sending_frame(const QUICStopSendingFrame &frame) { - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = frame.type(); StopSendingFrameInfo *frame_info = reinterpret_cast(info->data); frame_info->error_code = frame.error_code(); @@ -879,7 +879,7 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ block->_end = std::min(block->start() + frame_payload_size, block->_buf_end); ink_assert(static_cast(block->read_avail()) == frame_payload_size); - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = QUICFrameType::CRYPTO; QUICFrameId frame_id = this->_issue_frame_id(); CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); diff --git a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc index 5f246fdfc89..6c30c28fc55 100644 --- a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc +++ b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc @@ -30,7 +30,7 @@ constexpr static uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x0 TEST_CASE("QUICFrameRetransmitter ignore frame which can not be retranmistted", "[quic]") { QUICFrameRetransmitter retransmitter; - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = QUICFrameType::PING; info->level = QUICEncryptionLevel::NONE; @@ -41,7 +41,7 @@ TEST_CASE("QUICFrameRetransmitter ignore frame which can not be retranmistted", TEST_CASE("QUICFrameRetransmitter ignore frame which can not be split", "[quic]") { QUICFrameRetransmitter retransmitter; - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = QUICFrameType::STOP_SENDING; info->level = QUICEncryptionLevel::NONE; @@ -52,7 +52,7 @@ TEST_CASE("QUICFrameRetransmitter ignore frame which can not be split", "[quic]" TEST_CASE("QUICFrameRetransmitter ignore frame which has wrong level", "[quic]") { QUICFrameRetransmitter retransmitter; - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = QUICFrameType::STOP_SENDING; info->level = QUICEncryptionLevel::HANDSHAKE; @@ -63,7 +63,7 @@ TEST_CASE("QUICFrameRetransmitter ignore frame which has wrong level", "[quic]") TEST_CASE("QUICFrameRetransmitter successfully create retransmitted frame", "[quic]") { QUICFrameRetransmitter retransmitter; - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = QUICFrameType::STOP_SENDING; info->level = QUICEncryptionLevel::INITIAL; @@ -77,7 +77,7 @@ TEST_CASE("QUICFrameRetransmitter successfully create retransmitted frame", "[qu TEST_CASE("QUICFrameRetransmitter successfully create stream frame", "[quic]") { QUICFrameRetransmitter retransmitter; - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = QUICFrameType::STREAM; info->level = QUICEncryptionLevel::INITIAL; @@ -111,7 +111,7 @@ TEST_CASE("QUICFrameRetransmitter successfully create stream frame", "[quic]") TEST_CASE("QUICFrameRetransmitter successfully split stream frame", "[quic]") { QUICFrameRetransmitter retransmitter; - QUICFrameInformationUPtr info = std::make_unique(); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = QUICFrameType::STREAM; info->level = QUICEncryptionLevel::INITIAL; From 6c2e2f17e8d649eb25c02d906637cc918f5507f7 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 11 Jan 2019 10:14:45 +0800 Subject: [PATCH 0996/1313] QUIC: Remove useless MAX_XX_DATA, STOP_SENDING, RESET retransmition --- iocore/net/quic/QUICFlowController.cc | 44 +++-------- iocore/net/quic/QUICFrameRetransmitter.cc | 77 ------------------- iocore/net/quic/QUICFrameRetransmitter.h | 41 +--------- .../quic/test/test_QUICFrameRetransmitter.cc | 36 +++++---- 4 files changed, 39 insertions(+), 159 deletions(-) diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 2f9c12e3a28..ae88d815356 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -152,14 +152,7 @@ void QUICRemoteFlowController::_on_frame_lost(QUICFrameInformationUPtr &info) { ink_assert(info->type == QUICFrameType::BLOCKED || info->type == QUICFrameType::STREAM_BLOCKED); - QUICOffset offset = UINT64_MAX; - if (info->type == QUICFrameType::BLOCKED) { - offset = reinterpret_cast(info->data)->offset; - } else { - offset = reinterpret_cast(info->data)->offset; - } - - if (this->_offset == offset) { + if (this->_offset == *reinterpret_cast(info->data)) { this->_frame = this->_create_frame(); } } @@ -202,14 +195,7 @@ void QUICLocalFlowController::_on_frame_lost(QUICFrameInformationUPtr &info) { ink_assert(info->type == QUICFrameType::MAX_DATA || info->type == QUICFrameType::MAX_STREAM_DATA); - uint64_t limit = UINT64_MAX; - if (info->type == QUICFrameType::MAX_DATA) { - limit = reinterpret_cast(info->data)->maximum_data; - } else { - limit = reinterpret_cast(info->data)->maximum_stream_data; - } - - if (this->_limit == limit) { + if (this->_limit == *reinterpret_cast(info->data)) { this->_frame = this->_create_frame(); } } @@ -233,10 +219,9 @@ QUICRemoteConnectionFlowController::_create_frame() { auto frame = QUICFrameFactory::create_blocked_frame(this->_offset, this->_issue_frame_id(), this); QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - BlockedFrameInfo *frame_info = reinterpret_cast(info->data); info->type = frame->type(); info->level = QUICEncryptionLevel::NONE; - frame_info->offset = this->_offset; + *(reinterpret_cast(info->data)) = this->_offset; this->_records_frame(frame->id(), std::move(info)); return frame; } @@ -246,10 +231,9 @@ QUICLocalConnectionFlowController::_create_frame() { auto frame = QUICFrameFactory::create_max_data_frame(this->_limit, this->_issue_frame_id(), this); QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - MaxDataFrameInfo *frame_info = reinterpret_cast(info->data); info->type = frame->type(); info->level = QUICEncryptionLevel::NONE; - frame_info->maximum_data = this->_limit; + *(reinterpret_cast(info->data)) = this->_limit; this->_records_frame(frame->id(), std::move(info)); return frame; } @@ -258,12 +242,10 @@ QUICFrameUPtr QUICRemoteStreamFlowController::_create_frame() { auto frame = QUICFrameFactory::create_stream_blocked_frame(this->_stream_id, this->_offset, this->_issue_frame_id(), this); - QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - StreamBlockedFrameInfo *frame_info = reinterpret_cast(info->data); - info->type = frame->type(); - info->level = QUICEncryptionLevel::NONE; - frame_info->stream_id = this->_stream_id; - frame_info->offset = this->_offset; + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = frame->type(); + info->level = QUICEncryptionLevel::NONE; + *(reinterpret_cast(info->data)) = this->_offset; this->_records_frame(frame->id(), std::move(info)); return frame; } @@ -272,12 +254,10 @@ QUICFrameUPtr QUICLocalStreamFlowController::_create_frame() { auto frame = QUICFrameFactory::create_max_stream_data_frame(this->_stream_id, this->_limit, this->_issue_frame_id(), this); - QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - MaxStreamDataFrameInfo *frame_info = reinterpret_cast(info->data); - info->type = frame->type(); - info->level = QUICEncryptionLevel::NONE; - frame_info->stream_id = this->_stream_id; - frame_info->maximum_stream_data = this->_limit; + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = frame->type(); + info->level = QUICEncryptionLevel::NONE; + *(reinterpret_cast(info->data)) = this->_limit; this->_records_frame(frame->id(), std::move(info)); return frame; } diff --git a/iocore/net/quic/QUICFrameRetransmitter.cc b/iocore/net/quic/QUICFrameRetransmitter.cc index 80655be9e1f..21e1faa2054 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.cc +++ b/iocore/net/quic/QUICFrameRetransmitter.cc @@ -54,18 +54,6 @@ QUICFrameRetransmitter::create_retransmitted_frame(QUICEncryptionLevel level, ui case QUICFrameType::STREAM: frame = this->_create_stream_frame(info, maximum_frame_size, tmp_queue, id, owner); break; - case QUICFrameType::RST_STREAM: - frame = this->_create_reset_stream_frame(info, maximum_frame_size, tmp_queue, id, owner); - break; - case QUICFrameType::STOP_SENDING: - frame = this->_create_stop_sending_frame(info, maximum_frame_size, tmp_queue, id, owner); - break; - case QUICFrameType::MAX_STREAM_DATA: - frame = this->_create_max_stream_data_frame(info, maximum_frame_size, tmp_queue, id, owner); - break; - case QUICFrameType::MAX_DATA: - frame = this->_create_max_data_frame(info, maximum_frame_size, tmp_queue, id, owner); - break; default: ink_assert("unknown frame type"); Error("unknown frame type: %s", QUICDebugNames::frame_type(info->type)); @@ -132,68 +120,3 @@ QUICFrameRetransmitter::_create_stream_frame(QUICFrameInformationUPtr &info, uin ink_assert(frame != nullptr); return frame; } - -QUICFrameUPtr -QUICFrameRetransmitter::_create_reset_stream_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, - std::deque &tmp_queue, QUICFrameId id, - QUICFrameGenerator *owner) -{ - RstStreamFrameInfo *rst_info = reinterpret_cast(info->data); - auto frame = - QUICFrameFactory::create_rst_stream_frame(rst_info->stream_id, rst_info->error_code, rst_info->final_offset, id, owner); - if (frame->size() > maximum_frame_size) { - tmp_queue.push_back(std::move(info)); - return QUICFrameFactory::create_null_frame(); - } - - ink_assert(frame != nullptr); - return frame; -} - -QUICFrameUPtr -QUICFrameRetransmitter::_create_max_stream_data_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, - std::deque &tmp_queue, QUICFrameId id, - QUICFrameGenerator *owner) -{ - MaxStreamDataFrameInfo *frame_info = reinterpret_cast(info->data); - auto frame = QUICFrameFactory::create_max_stream_data_frame(frame_info->stream_id, frame_info->maximum_stream_data, id, owner); - if (frame->size() > maximum_frame_size) { - tmp_queue.push_back(std::move(info)); - return QUICFrameFactory::create_null_frame(); - } - - ink_assert(frame != nullptr); - return frame; -} - -QUICFrameUPtr -QUICFrameRetransmitter::_create_max_data_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, - std::deque &tmp_queue, QUICFrameId id, - QUICFrameGenerator *owner) -{ - MaxDataFrameInfo *frame_info = reinterpret_cast(info->data); - auto frame = QUICFrameFactory::create_max_data_frame(frame_info->maximum_data, id, owner); - if (frame->size() > maximum_frame_size) { - tmp_queue.push_back(std::move(info)); - return QUICFrameFactory::create_null_frame(); - } - - ink_assert(frame != nullptr); - return frame; -} - -QUICFrameUPtr -QUICFrameRetransmitter::_create_stop_sending_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, - std::deque &tmp_queue, QUICFrameId id, - QUICFrameGenerator *owner) -{ - StopSendingFrameInfo *frame_info = reinterpret_cast(info->data); - auto frame = QUICFrameFactory::create_stop_sending_frame(frame_info->stream_id, frame_info->error_code, id, owner); - if (frame->size() > maximum_frame_size) { - tmp_queue.push_back(std::move(info)); - return QUICFrameFactory::create_null_frame(); - } - - ink_assert(frame != nullptr); - return frame; -} diff --git a/iocore/net/quic/QUICFrameRetransmitter.h b/iocore/net/quic/QUICFrameRetransmitter.h index 6eb259a83a2..a9ac6fc555b 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.h +++ b/iocore/net/quic/QUICFrameRetransmitter.h @@ -41,9 +41,7 @@ struct QUICFrameInformationDeleter { using QUICFrameInformationUPtr = std::unique_ptr; -constexpr QUICFrameType RETRANSMITTED_FRAME_TYPE[] = {QUICFrameType::STREAM, QUICFrameType::STOP_SENDING, - QUICFrameType::MAX_STREAM_DATA, QUICFrameType::RST_STREAM, - QUICFrameType::MAX_DATA}; +constexpr QUICFrameType RETRANSMITTED_FRAME_TYPE[] = {QUICFrameType::STREAM}; struct StreamFrameInfo { QUICStreamId stream_id; @@ -52,40 +50,20 @@ struct StreamFrameInfo { Ptr block; }; -struct MaxStreamDataFrameInfo { - QUICStreamId stream_id; - uint64_t maximum_stream_data; +struct CryptoFrameInfo { + QUICOffset offset; + Ptr block; }; struct RstStreamFrameInfo { - QUICStreamId stream_id; QUICAppErrorCode error_code; QUICOffset final_offset; }; struct StopSendingFrameInfo { - QUICStreamId stream_id; QUICAppErrorCode error_code; }; -struct MaxDataFrameInfo { - uint64_t maximum_data; -}; - -struct BlockedFrameInfo { - QUICOffset offset; -}; - -struct StreamBlockedFrameInfo { - QUICStreamId stream_id; - QUICOffset offset; -}; - -struct CryptoFrameInfo { - QUICOffset offset; - Ptr block; -}; - struct AckFrameInfo { QUICPacketNumber largest_acknowledged; }; @@ -100,17 +78,6 @@ class QUICFrameRetransmitter private: QUICFrameUPtr _create_stream_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner); - QUICFrameUPtr _create_reset_stream_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, - std::deque &tmp_queue, QUICFrameId id, - QUICFrameGenerator *owner); - QUICFrameUPtr _create_max_stream_data_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, - std::deque &tmp_queue, QUICFrameId id, - QUICFrameGenerator *owner); - QUICFrameUPtr _create_stop_sending_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, - std::deque &tmp_queue, QUICFrameId id, - QUICFrameGenerator *owner); - QUICFrameUPtr _create_max_data_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, - std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner); void _append_info_queue(std::deque &tmp_queue); diff --git a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc index 6c30c28fc55..a3e5f29ed26 100644 --- a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc +++ b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc @@ -38,22 +38,22 @@ TEST_CASE("QUICFrameRetransmitter ignore frame which can not be retranmistted", CHECK(retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX) == nullptr); } -TEST_CASE("QUICFrameRetransmitter ignore frame which can not be split", "[quic]") -{ - QUICFrameRetransmitter retransmitter; - QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - info->type = QUICFrameType::STOP_SENDING; - info->level = QUICEncryptionLevel::NONE; - - retransmitter.save_frame_info(info); - CHECK(retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 0) == nullptr); -} +// TEST_CASE("QUICFrameRetransmitter ignore frame which can not be split", "[quic]") +// { +// QUICFrameRetransmitter retransmitter; +// QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); +// info->type = QUICFrameType::STOP_SENDING; +// info->level = QUICEncryptionLevel::NONE; +// +// retransmitter.save_frame_info(info); +// CHECK(retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 0) == nullptr); +// } TEST_CASE("QUICFrameRetransmitter ignore frame which has wrong level", "[quic]") { QUICFrameRetransmitter retransmitter; QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - info->type = QUICFrameType::STOP_SENDING; + info->type = QUICFrameType::STREAM; info->level = QUICEncryptionLevel::HANDSHAKE; retransmitter.save_frame_info(info); @@ -64,14 +64,24 @@ TEST_CASE("QUICFrameRetransmitter successfully create retransmitted frame", "[qu { QUICFrameRetransmitter retransmitter; QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - info->type = QUICFrameType::STOP_SENDING; + info->type = QUICFrameType::STREAM; info->level = QUICEncryptionLevel::INITIAL; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), data, sizeof(data)); + block->fill(sizeof(data)); + + StreamFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->stream_id = 0x12345; + frame_info->offset = 0x67890; + frame_info->block = block; + retransmitter.save_frame_info(info); auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); CHECK(frame != nullptr); - CHECK(frame->type() == QUICFrameType::STOP_SENDING); + CHECK(frame->type() == QUICFrameType::STREAM); } TEST_CASE("QUICFrameRetransmitter successfully create stream frame", "[quic]") From b61748cfb9de25751a19d17599f5649e2711eb31 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 11 Jan 2019 13:44:12 +0800 Subject: [PATCH 0997/1313] Uses IOBufferBlock::consume instead of split_frame --- iocore/net/quic/QUICFrame.cc | 6 ++--- iocore/net/quic/QUICFrame.h | 2 +- iocore/net/quic/QUICFrameRetransmitter.cc | 26 ++++++++++++------- iocore/net/quic/QUICStream.cc | 4 +-- iocore/net/quic/test/test_QUICFrame.cc | 12 ++++----- .../quic/test/test_QUICFrameRetransmitter.cc | 6 ++--- 6 files changed, 32 insertions(+), 24 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 8eda35a3b6e..83054bf5019 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -338,7 +338,7 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, size_t limit, bool include_len } // Stream Data (*) - memcpy(buf + *len, this->data(), this->data_length()); + memcpy(buf + *len, this->data()->start(), this->data_length()); *len += this->data_length(); return *len; @@ -366,10 +366,10 @@ QUICStreamFrame::data_length() const return this->_block->read_avail(); } -const uint8_t * +IOBufferBlock * QUICStreamFrame::data() const { - return reinterpret_cast(this->_block->start()); + return this->_block.get(); } /** diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 2236fe04372..0f8a435ee22 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -103,7 +103,7 @@ class QUICStreamFrame : public QUICFrame size_t store(uint8_t *buf, size_t *len, size_t limit, bool include_length_field) const; QUICStreamId stream_id() const; QUICOffset offset() const; - const uint8_t *data() const; + IOBufferBlock *data() const; uint64_t data_length() const; bool has_offset_field() const; bool has_length_field() const; diff --git a/iocore/net/quic/QUICFrameRetransmitter.cc b/iocore/net/quic/QUICFrameRetransmitter.cc index 21e1faa2054..dfa6352659a 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.cc +++ b/iocore/net/quic/QUICFrameRetransmitter.cc @@ -101,19 +101,27 @@ QUICFrameRetransmitter::_create_stream_frame(QUICFrameInformationUPtr &info, uin auto frame = QUICFrameFactory::create_stream_frame(stream_info->block, stream_info->stream_id, stream_info->offset, stream_info->has_fin, true, true, id, owner); if (frame->size() > maximum_frame_size) { - auto new_frame = QUICFrameFactory::split_frame(frame.get(), maximum_frame_size); - if (new_frame == nullptr) { - // can not split stream frame. Because of too small maximum_frame_size. + QUICStreamFrame *stream_frame = static_cast(frame.get()); + if (stream_frame->size() - stream_frame->data_length() > maximum_frame_size) { + // header length is larger than maximum_frame_size. tmp_queue.push_back(std::move(info)); return QUICFrameFactory::create_null_frame(); - } else { - QUICStreamFrame *stream_frame = static_cast(frame.get()); - stream_info->block->consume(stream_frame->data_length()); - stream_info->offset += stream_frame->data_length(); - ink_assert(frame->size() <= maximum_frame_size); + } + + IOBufferBlock *block = stream_frame->data(); + size_t over_length = stream_frame->size() - maximum_frame_size; + block->_end = std::max(block->start(), block->_end - over_length); + if (block->read_avail() == 0) { + // no payload tmp_queue.push_back(std::move(info)); - return frame; + return QUICFrameFactory::create_null_frame(); } + + stream_info->block->consume(stream_frame->data_length()); + stream_info->offset += stream_frame->data_length(); + ink_assert(frame->size() <= maximum_frame_size); + tmp_queue.push_back(std::move(info)); + return frame; } stream_info->block = nullptr; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index ac781e6f55a..48af1ccfc00 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -338,8 +338,8 @@ QUICStream::recv(const QUICStreamFrame &frame) while (new_frame != nullptr) { stream_frame = std::static_pointer_cast(new_frame); - this->_write_to_read_vio(stream_frame->offset(), stream_frame->data(), stream_frame->data_length(), - stream_frame->has_fin_flag()); + this->_write_to_read_vio(stream_frame->offset(), reinterpret_cast(stream_frame->data()->start()), + stream_frame->data_length(), stream_frame->has_fin_flag()); this->_state.update_with_receiving_frame(*new_frame); new_frame = this->_received_stream_frame_buffer.pop(); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 7903eeccd7b..327d89d6724 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -83,7 +83,7 @@ TEST_CASE("Load STREAM Frame", "[quic]") CHECK(stream_frame->stream_id() == 0x01); CHECK(stream_frame->offset() == 0x00); CHECK(stream_frame->data_length() == 4); - CHECK(memcmp(stream_frame->data(), "\x01\x02\x03\x04", 4) == 0); + CHECK(memcmp(stream_frame->data()->start(), "\x01\x02\x03\x04", 4) == 0); CHECK(stream_frame->has_fin_flag() == false); } @@ -102,7 +102,7 @@ TEST_CASE("Load STREAM Frame", "[quic]") CHECK(stream_frame->stream_id() == 0x01); CHECK(stream_frame->offset() == 0x00); CHECK(stream_frame->data_length() == 5); - CHECK(memcmp(stream_frame->data(), "\x01\x02\x03\x04\x05", 5) == 0); + CHECK(memcmp(stream_frame->data()->start(), "\x01\x02\x03\x04\x05", 5) == 0); CHECK(stream_frame->has_fin_flag() == false); } @@ -123,7 +123,7 @@ TEST_CASE("Load STREAM Frame", "[quic]") CHECK(stream_frame->stream_id() == 0x01); CHECK(stream_frame->offset() == 0x02); CHECK(stream_frame->data_length() == 5); - CHECK(memcmp(stream_frame->data(), "\x01\x02\x03\x04\x05", 5) == 0); + CHECK(memcmp(stream_frame->data()->start(), "\x01\x02\x03\x04\x05", 5) == 0); CHECK(stream_frame->has_fin_flag() == false); } @@ -144,7 +144,7 @@ TEST_CASE("Load STREAM Frame", "[quic]") CHECK(stream_frame->stream_id() == 0x01); CHECK(stream_frame->offset() == 0x02); CHECK(stream_frame->data_length() == 5); - CHECK(memcmp(stream_frame->data(), "\x01\x02\x03\x04\x05", 5) == 0); + CHECK(memcmp(stream_frame->data()->start(), "\x01\x02\x03\x04\x05", 5) == 0); CHECK(stream_frame->has_fin_flag() == true); } @@ -397,11 +397,11 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame *stream_frame2 = dynamic_cast(stream_frame->split(16)); CHECK(stream_frame->stream_id() == 0x01); CHECK(stream_frame->data_length() == 5); - CHECK(memcmp(stream_frame->data(), "\x01\x02\x03\x04\x05", stream_frame->data_length()) == 0); + CHECK(memcmp(stream_frame->data()->start(), "\x01\x02\x03\x04\x05", stream_frame->data_length()) == 0); CHECK(stream_frame->offset() == 0x100000000); CHECK(stream_frame2->data_length() == 5); - CHECK(memcmp(stream_frame2->data(), "\x11\x22\x33\x44\x55", stream_frame2->data_length()) == 0); + CHECK(memcmp(stream_frame2->data()->start(), "\x11\x22\x33\x44\x55", stream_frame2->data_length()) == 0); CHECK(stream_frame2->offset() == 0x100000000 + 5); CHECK(stream_frame2->stream_id() == 0x01); diff --git a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc index a3e5f29ed26..5c8557baee6 100644 --- a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc +++ b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc @@ -112,7 +112,7 @@ TEST_CASE("QUICFrameRetransmitter successfully create stream frame", "[quic]") CHECK(stream_frame->stream_id() == 0x12345); CHECK(stream_frame->offset() == 0x67890); CHECK(stream_frame->data_length() == sizeof(data)); - CHECK(memcmp(stream_frame->data(), data, sizeof(data)) == 0); + CHECK(memcmp(stream_frame->data()->start(), data, sizeof(data)) == 0); frame = QUICFrameFactory::create_null_frame(); // Becasue the info has been released, the refcount should be 1 (var block). CHECK(block->refcount() == 1); @@ -147,7 +147,7 @@ TEST_CASE("QUICFrameRetransmitter successfully split stream frame", "[quic]") CHECK(stream_frame->size() <= 15); auto size = stream_frame->data_length(); - CHECK(memcmp(stream_frame->data(), data, stream_frame->data_length()) == 0); + CHECK(memcmp(stream_frame->data()->start(), data, stream_frame->data_length()) == 0); // one for var block, one for the left data which saved in retransmitter CHECK(block->data->refcount() == 2); // one for var block, one for the left data which saved in retransmitter, one for var frame @@ -164,7 +164,7 @@ TEST_CASE("QUICFrameRetransmitter successfully split stream frame", "[quic]") CHECK(stream_frame->stream_id() == 0x12345); CHECK(stream_frame->offset() == 0x67890 + size); CHECK(stream_frame->data_length() == sizeof(data) - size); - CHECK(memcmp(stream_frame->data(), data + size, stream_frame->data_length()) == 0); + CHECK(memcmp(stream_frame->data()->start(), data + size, stream_frame->data_length()) == 0); CHECK(block->refcount() == 1); // one for var block frame = QUICFrameFactory::create_null_frame(); From 79ff56862137051abcb77853dfb318daa90269ae Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 11 Jan 2019 15:33:58 +0900 Subject: [PATCH 0998/1313] Abort traffic_quic if it could not create stream --- src/traffic_quic/quic_client.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc index 547240e428e..80680462757 100644 --- a/src/traffic_quic/quic_client.cc +++ b/src/traffic_quic/quic_client.cc @@ -133,7 +133,7 @@ QUICClientApp::start(const char *path) if (error != nullptr) { Error("%s", error->msg); - ink_assert(!error->msg); + ink_abort("Could not create bidi stream : %s", error->msg); } // TODO: move to transaction From 850f2762c3c587c4727ca0ed80cf0f5e41f45fbc Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 11 Jan 2019 15:49:30 +0900 Subject: [PATCH 0999/1313] Increment _next_stream_id_(uni|bidi) correctly --- iocore/net/quic/QUICStreamManager.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index c86ded6616c..3cc9b6649a7 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -26,7 +26,8 @@ #include "QUICApplication.h" #include "QUICTransportParameters.h" -static constexpr char tag[] = "quic_stream_manager"; +static constexpr char tag[] = "quic_stream_manager"; +static constexpr QUICStreamId QUIC_STREAM_TYPES = 4; ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); ClassAllocator quicStreamAllocator("quicStreamAllocator"); @@ -109,7 +110,7 @@ QUICStreamManager::create_uni_stream(QUICStreamId &new_stream_id) QUICConnectionErrorUPtr error = this->create_stream(this->_next_stream_id_uni); if (error == nullptr) { new_stream_id = this->_next_stream_id_uni; - this->_next_stream_id_uni += 2; + this->_next_stream_id_uni += QUIC_STREAM_TYPES; } return error; @@ -121,7 +122,7 @@ QUICStreamManager::create_bidi_stream(QUICStreamId &new_stream_id) QUICConnectionErrorUPtr error = this->create_stream(this->_next_stream_id_bidi); if (error == nullptr) { new_stream_id = this->_next_stream_id_bidi; - this->_next_stream_id_bidi += 2; + this->_next_stream_id_bidi += QUIC_STREAM_TYPES; } return error; From b223484721089ca00566cedfe1323e984bd5e60c Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 11 Jan 2019 15:23:03 +0800 Subject: [PATCH 1000/1313] QUIC: Fixes test cases broken due to (ats_unique_buf -> IOBufferBlock) --- .../net/quic/test/test_QUICFrameDispatcher.cc | 9 ++- .../quic/test/test_QUICIncomingFrameBuffer.cc | 73 ++++++++++++------- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 781eb40c7e8..5c9f9ccbefb 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -29,11 +29,12 @@ TEST_CASE("QUICFrameHandler", "[quic]") { - uint8_t raw[] = {0x01}; - ats_unique_buf payload = ats_unique_malloc(1); - memcpy(payload.get(), raw, 1); + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + block->fill(1); + CHECK(block->read_avail() == 1); - QUICStreamFrame streamFrame(std::move(payload), 1, 0x03, 0); + QUICStreamFrame streamFrame(block, 0x03, 0); MockQUICConnection connection; MockQUICStreamManager streamManager; diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 64325a0e543..90e3680305a 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -33,11 +33,18 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") QUICIncomingStreamFrameBuffer buffer; QUICErrorUPtr err = nullptr; - uint8_t data[1024] = {0}; + Ptr block_1024 = make_ptr(new_IOBufferBlock()); + block_1024->alloc(); + block_1024->fill(1024); + CHECK(block_1024->read_avail() == 1024); + + Ptr block_0 = make_ptr(new_IOBufferBlock()); + block_0->alloc(); + CHECK(block_0->read_avail() == 0); SECTION("single frame") { - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0, true); + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 0, true); err = buffer.insert(*stream1_frame_0_r); CHECK(err == nullptr); @@ -45,11 +52,11 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") SECTION("multiple frames") { - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); - std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); - std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); - std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 3072, true); - std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 4096); + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 0); + std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 1024); + std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 2048, true); + std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 3072, true); + std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 4096); buffer.insert(*stream1_frame_0_r); buffer.insert(*stream1_frame_1_r); @@ -77,9 +84,9 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") SECTION("Pure FIN") { - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); - std::shared_ptr stream1_frame_empty = QUICFrameFactory::create_stream_frame(data, 0, 1, 1024); - std::shared_ptr stream1_frame_pure_fin = QUICFrameFactory::create_stream_frame(data, 0, 1, 1024, true); + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 0); + std::shared_ptr stream1_frame_empty = QUICFrameFactory::create_stream_frame(block_0, 1, 1024); + std::shared_ptr stream1_frame_pure_fin = QUICFrameFactory::create_stream_frame(block_0, 1, 1024, true); err = buffer.insert(*stream1_frame_0_r); CHECK(err == nullptr); @@ -100,14 +107,21 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") QUICIncomingStreamFrameBuffer buffer; QUICErrorUPtr err = nullptr; - uint8_t data[1024] = {0}; + Ptr block_1024 = make_ptr(new_IOBufferBlock()); + block_1024->alloc(); + block_1024->fill(1024); + CHECK(block_1024->read_avail() == 1024); + + Ptr block_0 = make_ptr(new_IOBufferBlock()); + block_0->alloc(); + CHECK(block_0->read_avail() == 0); - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); - std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); - std::shared_ptr stream1_frame_empty = QUICFrameFactory::create_stream_frame(data, 0, 1, 2048); - std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048); - std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 3072); - std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 4096, true); + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 0); + std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 1024); + std::shared_ptr stream1_frame_empty = QUICFrameFactory::create_stream_frame(block_0, 1, 2048); + std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 2048); + std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 3072); + std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 4096, true); buffer.insert(*stream1_frame_0_r); buffer.insert(*stream1_frame_1_r); @@ -159,12 +173,19 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") QUICIncomingStreamFrameBuffer buffer; QUICErrorUPtr err = nullptr; - uint8_t data[1024] = {0}; + Ptr block_1024 = make_ptr(new_IOBufferBlock()); + block_1024->alloc(); + block_1024->fill(1024); + CHECK(block_1024->read_avail() == 1024); + + Ptr block_0 = make_ptr(new_IOBufferBlock()); + block_0->alloc(); + CHECK(block_0->read_avail() == 0); - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); - std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); - std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); - std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); + std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 0); + std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 1024); + std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 2048, true); + std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 2048, true); buffer.insert(*stream1_frame_0_r); buffer.insert(*stream1_frame_1_r); @@ -184,10 +205,10 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") buffer.clear(); - std::shared_ptr stream2_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0); - std::shared_ptr stream2_frame_1_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); - std::shared_ptr stream2_frame_2_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 1024); - std::shared_ptr stream2_frame_3_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 2048, true); + std::shared_ptr stream2_frame_0_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 0); + std::shared_ptr stream2_frame_1_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 1024); + std::shared_ptr stream2_frame_2_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 1024); + std::shared_ptr stream2_frame_3_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 2048, true); buffer.insert(*stream2_frame_0_r); buffer.insert(*stream2_frame_1_r); From f2cb7b6335f281bd5816da13acfc2c058665ec0e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 15 Jan 2019 09:32:19 +0900 Subject: [PATCH 1001/1313] Add test_QUICFrameRetransmitter to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8854dae50a2..c23af7ee444 100644 --- a/.gitignore +++ b/.gitignore @@ -95,6 +95,7 @@ iocore/net/quic/test_QUICAltConnectionManager iocore/net/quic/test_QUICFlowController iocore/net/quic/test_QUICFrame iocore/net/quic/test_QUICFrameDispatcher +iocore/net/quic/test_QUICFrameRetransmitter iocore/net/quic/test_QUICHandshake iocore/net/quic/test_QUICHandshakeProtocol iocore/net/quic/test_QUICIncomingFrameBuffer From 72d2a70ee2f8a00c4eed95280b11cc5482c0fe41 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 15 Jan 2019 09:33:06 +0900 Subject: [PATCH 1002/1313] More fixes test cases broken due to (ats_unique_buf -> IOBufferBlock) --- .../net/quic/test/test_QUICStreamManager.cc | 52 +++++++++++++------ iocore/net/quic/test/test_QUICStreamState.cc | 20 +++++-- 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index eb9689b3edd..c5a72b3cf0e 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -64,10 +64,13 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") sm.init_flow_control_params(local_tp, remote_tp); // STREAM frames create new streams - std::shared_ptr stream_frame_0 = - QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 0); - std::shared_ptr stream_frame_4 = - QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 4, 0); + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + block->fill(4); + CHECK(block->read_avail() == 4); + + std::shared_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(block, 0, 0); + std::shared_ptr stream_frame_4 = QUICFrameFactory::create_stream_frame(block, 4, 0); CHECK(sm.stream_count() == 0); sm.handle_frame(level, *stream_frame_0); CHECK(sm.stream_count() == 1); @@ -114,8 +117,12 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") sm.init_flow_control_params(local_tp, remote_tp); // STREAM frames create new streams - std::shared_ptr stream_frame_0 = - QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 7); + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + block->fill(4); + CHECK(block->read_avail() == 4); + + std::shared_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(block, 0, 7); sm.handle_frame(level, *stream_frame_0); CHECK("succeed"); @@ -158,7 +165,6 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); sm.init_flow_control_params(local_tp, remote_tp); - uint8_t data[1024] = {0}; // Create a stream with STREAM_BLOCKED (== noop) std::shared_ptr stream_blocked_frame_0 = QUICFrameFactory::create_stream_blocked_frame(0, 0); @@ -169,7 +175,12 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") CHECK(sm.total_offset_received() == 0); // total_offset should be a integer in unit of 1024 octets - std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(data, 1024, 8, 0); + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + block->fill(1024); + CHECK(block->read_avail() == 1024); + + std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(block, 8, 0); sm.handle_frame(level, *stream_frame_1); CHECK(sm.total_offset_received() == 1024); } @@ -205,28 +216,35 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); sm.init_flow_control_params(local_tp, remote_tp); - uint8_t data[1024] = {0}; // Create a stream with STREAM_BLOCKED (== noop) - std::shared_ptr stream_frame_0_r = - QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 0, 0); - std::shared_ptr stream_frame_4_r = - QUICFrameFactory::create_stream_frame(reinterpret_cast("abc"), 3, 4, 0); + Ptr block_3 = make_ptr(new_IOBufferBlock()); + block_3->alloc(); + block_3->fill(3); + CHECK(block_3->read_avail() == 3); + + std::shared_ptr stream_frame_0_r = QUICFrameFactory::create_stream_frame(block_3, 0, 0); + std::shared_ptr stream_frame_4_r = QUICFrameFactory::create_stream_frame(block_3, 4, 0); sm.handle_frame(level, *stream_frame_0_r); sm.handle_frame(level, *stream_frame_4_r); CHECK(sm.stream_count() == 2); CHECK(sm.total_offset_sent() == 0); + Ptr block_1024 = make_ptr(new_IOBufferBlock()); + block_1024->alloc(); + block_1024->fill(1024); + CHECK(block_1024->read_avail() == 1024); + // total_offset should be a integer in unit of octets - QUICFrameUPtr stream_frame_0 = QUICFrameFactory::create_stream_frame(data, 1024, 0, 0); - mock_app.send(data, 1024, 0); + QUICFrameUPtr stream_frame_0 = QUICFrameFactory::create_stream_frame(block_1024, 0, 0); + mock_app.send(reinterpret_cast(block_1024->buf()), 1024, 0); sm.add_total_offset_sent(1024); sleep(2); CHECK(sm.total_offset_sent() == 1024); // total_offset should be a integer in unit of octets - QUICFrameUPtr stream_frame_4 = QUICFrameFactory::create_stream_frame(data, 1024, 4, 0); - mock_app.send(data, 1024, 4); + QUICFrameUPtr stream_frame_4 = QUICFrameFactory::create_stream_frame(block_1024, 4, 0); + mock_app.send(reinterpret_cast(block_1024->buf()), 1024, 4); sm.add_total_offset_sent(1024); sleep(2); CHECK(sm.total_offset_sent() == 2048); diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index bf70f214f7b..79a22d70407 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -32,8 +32,13 @@ // Unidirectional (sending) TEST_CASE("QUICSendStreamState", "[quic]") { - auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); - auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 0, true); + Ptr block_4 = make_ptr(new_IOBufferBlock()); + block_4->alloc(); + block_4->fill(4); + CHECK(block_4->read_avail() == 4); + + auto stream_frame = QUICFrameFactory::create_stream_frame(block_4, 1, 0); + auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(block_4, 1, 0, true); auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0, 0); MockQUICTransferProgressProvider pp; @@ -172,9 +177,14 @@ TEST_CASE("QUICSendStreamState", "[quic]") // Unidirectional (receiving) TEST_CASE("QUICReceiveStreamState", "[quic]") { - auto stream_frame = QUICFrameFactory::create_stream_frame(reinterpret_cast("foo"), 4, 1, 0); - auto stream_frame_delayed = QUICFrameFactory::create_stream_frame(reinterpret_cast("bar"), 4, 1, 1); - auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(reinterpret_cast("baz"), 4, 1, 2, true); + Ptr block_4 = make_ptr(new_IOBufferBlock()); + block_4->alloc(); + block_4->fill(4); + CHECK(block_4->read_avail() == 4); + + auto stream_frame = QUICFrameFactory::create_stream_frame(block_4, 1, 0); + auto stream_frame_delayed = QUICFrameFactory::create_stream_frame(block_4, 1, 1); + auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(block_4, 1, 2, true); auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0, 0); From 06b3b2d0d0131ff21ad27dabcd794961f58f6713 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 15 Jan 2019 12:00:58 +0900 Subject: [PATCH 1003/1313] Assign thread for QUICNetVC at QUICPacketHandlerIn::_recv_packet Partically, revert 2c81f2b647bc4b24ae0459388ede28f826fed93b. On incoming side, vc->thread have to be assigned before enqueue. --- iocore/net/QUICNetVConnection.cc | 8 ++++---- iocore/net/QUICPacketHandler.cc | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2305c1f8959..2a2b953bb3f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -184,7 +184,8 @@ QUICNetVConnection::acceptEvent(int event, Event *e) } } - thread = t; + // this->thread is already assigned by QUICPacketHandlerIn::_recv_packet + ink_assert(this->thread == this_ethread()); // Send this NetVC to NetHandler and start to polling read & write event. if (h->startIO(this) < 0) { @@ -567,9 +568,8 @@ QUICNetVConnection::state_pre_handshake(int event, Event *data) { SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - if (!this->thread) { - this->thread = this_ethread(); - } + // this->thread should be assigned on any direction + ink_assert(this->thread == this_ethread()); if (!this->nh) { this->nh = get_NetHandler(this_ethread()); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 05d20b83975..25476c52e8f 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -321,6 +321,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) vc->id = net_next_connection_number(); vc->con.move(con); vc->submit_time = Thread::get_hrtime(); + vc->thread = eth; vc->mutex = new_ProxyMutex(); vc->action_ = *this->action_; vc->set_is_transparent(this->opt.f_inbound_transparent); @@ -338,6 +339,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // Push the packet into QUICPollCont get_QUICPollCont(eth)->inQueue.push(qe); get_NetHandler(eth)->signalActivity(); + return; } From 7c2b65a43c1e51366ffcbeeff736b94023df63ef Mon Sep 17 00:00:00 2001 From: scw00 Date: Sun, 13 Jan 2019 17:19:16 +0800 Subject: [PATCH 1004/1313] QUIC: Refactor crypto and stream frame retrasmission --- iocore/net/quic/QUICFrame.cc | 11 ++-- iocore/net/quic/QUICFrame.h | 2 +- iocore/net/quic/QUICFrameRetransmitter.cc | 42 ++++++++++++- iocore/net/quic/QUICFrameRetransmitter.h | 6 +- iocore/net/quic/QUICPacketRetransmitter.cc | 2 + iocore/net/quic/QUICStream.cc | 49 +++++++++------ iocore/net/quic/QUICStream.h | 6 +- iocore/net/quic/test/test_QUICFrame.cc | 3 +- .../quic/test/test_QUICFrameRetransmitter.cc | 61 +++++++++++++++++-- 9 files changed, 146 insertions(+), 36 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 83054bf5019..be365e1bca7 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -536,7 +536,7 @@ QUICCryptoFrame::store(uint8_t *buf, size_t *len, size_t limit) const *len += n; // Crypto Data (*) - memcpy(buf + *len, this->data(), this->data_length()); + memcpy(buf + *len, this->data()->start(), this->data_length()); *len += this->data_length(); return *len; @@ -554,10 +554,10 @@ QUICCryptoFrame::data_length() const return this->_block->read_avail(); } -const uint8_t * +IOBufferBlock * QUICCryptoFrame::data() const { - return reinterpret_cast(this->_block->start()); + return this->_block.get(); } // @@ -2896,8 +2896,9 @@ QUICFrameFactory::create_stream_frame(Ptr &block, QUICStreamId st QUICCryptoFrameUPtr QUICFrameFactory::create_crypto_frame(Ptr &block, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) { - QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); - new (frame) QUICCryptoFrame(block, offset, id, owner); + Ptr new_block = make_ptr(block->clone()); + QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); + new (frame) QUICCryptoFrame(new_block, offset, id, owner); return QUICCryptoFrameUPtr(frame, &QUICFrameDeleter::delete_crypto_frame); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 0f8a435ee22..3291a6606a0 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -143,7 +143,7 @@ class QUICCryptoFrame : public QUICFrame QUICOffset offset() const; uint64_t data_length() const; - const uint8_t *data() const; + IOBufferBlock *data() const; LINK(QUICCryptoFrame, link); diff --git a/iocore/net/quic/QUICFrameRetransmitter.cc b/iocore/net/quic/QUICFrameRetransmitter.cc index dfa6352659a..485e13d5d4d 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.cc +++ b/iocore/net/quic/QUICFrameRetransmitter.cc @@ -54,6 +54,9 @@ QUICFrameRetransmitter::create_retransmitted_frame(QUICEncryptionLevel level, ui case QUICFrameType::STREAM: frame = this->_create_stream_frame(info, maximum_frame_size, tmp_queue, id, owner); break; + case QUICFrameType::CRYPTO: + frame = this->_create_crypto_frame(info, maximum_frame_size, tmp_queue, id, owner); + break; default: ink_assert("unknown frame type"); Error("unknown frame type: %s", QUICDebugNames::frame_type(info->type)); @@ -70,7 +73,7 @@ QUICFrameRetransmitter::create_retransmitted_frame(QUICEncryptionLevel level, ui } void -QUICFrameRetransmitter::save_frame_info(QUICFrameInformationUPtr &info) +QUICFrameRetransmitter::save_frame_info(QUICFrameInformationUPtr info) { for (auto type : RETRANSMITTED_FRAME_TYPE) { if (type == info->type) { @@ -128,3 +131,40 @@ QUICFrameRetransmitter::_create_stream_frame(QUICFrameInformationUPtr &info, uin ink_assert(frame != nullptr); return frame; } + +QUICFrameUPtr +QUICFrameRetransmitter::_create_crypto_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, + QUICFrameGenerator *owner) +{ + CryptoFrameInfo *crypto_info = reinterpret_cast(info->data); + // FIXME: has_offset and has_length should be configurable. + auto frame = QUICFrameFactory::create_crypto_frame(crypto_info->block, crypto_info->offset, id, owner); + if (frame->size() > maximum_frame_size) { + QUICCryptoFrame *crypto_frame = static_cast(frame.get()); + if (crypto_frame->size() - crypto_frame->data_length() > maximum_frame_size) { + // header length is larger than maximum_frame_size. + tmp_queue.push_back(std::move(info)); + return QUICFrameFactory::create_null_frame(); + } + + IOBufferBlock *block = crypto_frame->data(); + size_t over_length = crypto_frame->size() - maximum_frame_size; + block->_end = std::max(block->start(), block->_end - over_length); + if (block->read_avail() == 0) { + // no payload + tmp_queue.push_back(std::move(info)); + return QUICFrameFactory::create_null_frame(); + } + + crypto_info->block->consume(crypto_frame->data_length()); + crypto_info->offset += crypto_frame->data_length(); + ink_assert(frame->size() <= maximum_frame_size); + tmp_queue.push_back(std::move(info)); + return frame; + } + + crypto_info->block = nullptr; + ink_assert(frame != nullptr); + return frame; +} diff --git a/iocore/net/quic/QUICFrameRetransmitter.h b/iocore/net/quic/QUICFrameRetransmitter.h index a9ac6fc555b..f64d71fe5b5 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.h +++ b/iocore/net/quic/QUICFrameRetransmitter.h @@ -41,7 +41,7 @@ struct QUICFrameInformationDeleter { using QUICFrameInformationUPtr = std::unique_ptr; -constexpr QUICFrameType RETRANSMITTED_FRAME_TYPE[] = {QUICFrameType::STREAM}; +constexpr QUICFrameType RETRANSMITTED_FRAME_TYPE[] = {QUICFrameType::STREAM, QUICFrameType::CRYPTO}; struct StreamFrameInfo { QUICStreamId stream_id; @@ -73,11 +73,13 @@ class QUICFrameRetransmitter public: virtual QUICFrameUPtr create_retransmitted_frame(QUICEncryptionLevel level, uint16_t maximum_frame_size, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - virtual void save_frame_info(QUICFrameInformationUPtr &info); + virtual void save_frame_info(QUICFrameInformationUPtr info); private: QUICFrameUPtr _create_stream_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner); + QUICFrameUPtr _create_crypto_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner); void _append_info_queue(std::deque &tmp_queue); diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 8b8e40ab312..44f4ff60c35 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -55,6 +55,8 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) case QUICFrameType::STOP_SENDING: case QUICFrameType::CONNECTION_CLOSE: case QUICFrameType::APPLICATION_CLOSE: + case QUICFrameType::STREAM: + case QUICFrameType::CRYPTO: break; default: frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 48af1ccfc00..9edb646b8e1 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -408,7 +408,12 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit { SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrameUPtr frame = this->create_retransmitted_frame(level, maximum_frame_size, this->_issue_frame_id(), this); + if (frame != nullptr) { + ink_assert(frame->type() == QUICFrameType::STREAM); + this->_records_stream_frame(*static_cast(frame.get())); + return frame; + } // RST_STREAM if (this->_reset_reason && !this->_is_reset_sent) { @@ -516,7 +521,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit this->_send_offset += len; this->_write_vio.ndone += len; } - this->_records_stream_frame(*static_cast(frame.get()), block); + this->_records_stream_frame(*static_cast(frame.get())); this->_signal_write_event(); this->_state.update_with_sending_frame(*frame); @@ -525,14 +530,14 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit } void -QUICStream::_records_stream_frame(const QUICStreamFrame &frame, Ptr &block) +QUICStream::_records_stream_frame(const QUICStreamFrame &frame) { QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = frame.type(); StreamFrameInfo *frame_info = reinterpret_cast(info->data); frame_info->offset = frame.offset(); frame_info->has_fin = frame.has_fin_flag(); - frame_info->block = block; + frame_info->block = frame.data(); this->_records_frame(frame.id(), std::move(info)); } @@ -583,7 +588,6 @@ QUICStream::_on_frame_acked(QUICFrameInformationUPtr &info) void QUICStream::_on_frame_lost(QUICFrameInformationUPtr &info) { - StreamFrameInfo *frame_info = nullptr; switch (info->type) { case QUICFrameType::RST_STREAM: // [draft-16] 13.2. Retransmission of Information @@ -595,8 +599,7 @@ QUICStream::_on_frame_lost(QUICFrameInformationUPtr &info) this->_is_reset_sent = false; break; case QUICFrameType::STREAM: - frame_info = reinterpret_cast(info->data); - frame_info->block = nullptr; + this->save_frame_info(std::move(info)); break; case QUICFrameType::STOP_SENDING: this->_is_stop_sending_sent = false; @@ -821,7 +824,7 @@ QUICCryptoStream::recv(const QUICCryptoFrame &frame) while (new_frame != nullptr) { QUICCryptoFrameSPtr crypto_frame = std::static_pointer_cast(new_frame); - this->_read_buffer->write(crypto_frame->data(), crypto_frame->data_length()); + this->_read_buffer->write(reinterpret_cast(crypto_frame->data()->start()), crypto_frame->data_length()); new_frame = this->_received_stream_frame_buffer.pop(); } @@ -861,7 +864,12 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ return QUICFrameFactory::create_rst_stream_frame(*this->_reset_reason); } - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrameUPtr frame = this->create_retransmitted_frame(level, maximum_frame_size, this->_issue_frame_id(), this); + if (frame != nullptr) { + ink_assert(frame->type() == QUICFrameType::CRYPTO); + this->_records_crypto_frame(*static_cast(frame.get())); + return frame; + } if (maximum_frame_size <= MAX_CRYPTO_FRAME_OVERHEAD) { return frame; @@ -879,17 +887,10 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ block->_end = std::min(block->start() + frame_payload_size, block->_buf_end); ink_assert(static_cast(block->read_avail()) == frame_payload_size); - QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - info->type = QUICFrameType::CRYPTO; - QUICFrameId frame_id = this->_issue_frame_id(); - CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); - crypto_frame_info->offset = this->_send_offset; - crypto_frame_info->block = block; - this->_records_frame(frame_id, std::move(info)); - - frame = QUICFrameFactory::create_crypto_frame(block, this->_send_offset, frame_id, this); + frame = QUICFrameFactory::create_crypto_frame(block, this->_send_offset, this->_issue_frame_id(), this); this->_send_offset += frame_payload_size; this->_write_buffer_reader->consume(frame_payload_size); + this->_records_crypto_frame(*static_cast(frame.get())); return frame; } @@ -906,6 +907,16 @@ void QUICCryptoStream::_on_frame_lost(QUICFrameInformationUPtr &info) { ink_assert(info->type == QUICFrameType::CRYPTO); + this->save_frame_info(std::move(info)); +} + +void +QUICCryptoStream::_records_crypto_frame(const QUICCryptoFrame &frame) +{ + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = QUICFrameType::CRYPTO; CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); - crypto_frame_info->block = nullptr; + crypto_frame_info->offset = frame.offset(); + crypto_frame_info->block = frame.data(); + this->_records_frame(frame.id(), std::move(info)); } diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index c0aec9dff93..6f486d4fafa 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -109,7 +109,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra void _write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin); void _records_rst_stream_frame(const QUICRstStreamFrame &frame); - void _records_stream_frame(const QUICStreamFrame &frame, Ptr &block); + void _records_stream_frame(const QUICStreamFrame &frame); void _records_stop_sending_frame(const QUICStopSendingFrame &frame); QUICStreamErrorUPtr _reset_reason = nullptr; @@ -157,7 +157,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra * - no flow control * - no state (never closed) */ -class QUICCryptoStream : public QUICFrameGenerator +class QUICCryptoStream : public QUICFrameGenerator, public QUICFrameRetransmitter { public: QUICCryptoStream(); @@ -191,6 +191,8 @@ class QUICCryptoStream : public QUICFrameGenerator void _on_frame_acked(QUICFrameInformationUPtr &info) override; void _on_frame_lost(QUICFrameInformationUPtr &info) override; + void _records_crypto_frame(const QUICCryptoFrame &frame); + QUICStreamErrorUPtr _reset_reason = nullptr; QUICOffset _send_offset = 0; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 327d89d6724..408c41a485e 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -400,6 +400,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") CHECK(memcmp(stream_frame->data()->start(), "\x01\x02\x03\x04\x05", stream_frame->data_length()) == 0); CHECK(stream_frame->offset() == 0x100000000); + frame1 = QUICFrameFactory::create_null_frame(); CHECK(stream_frame2->data_length() == 5); CHECK(memcmp(stream_frame2->data()->start(), "\x11\x22\x33\x44\x55", stream_frame2->data_length()) == 0); CHECK(stream_frame2->offset() == 0x100000000 + 5); @@ -426,7 +427,7 @@ TEST_CASE("CRYPTO Frame", "[quic]") std::shared_ptr crypto_frame = std::dynamic_pointer_cast(frame); CHECK(crypto_frame->offset() == 0x010000); CHECK(crypto_frame->data_length() == 5); - CHECK(memcmp(crypto_frame->data(), "\x01\x02\x03\x04\x05", 5) == 0); + CHECK(memcmp(crypto_frame->data()->start(), "\x01\x02\x03\x04\x05", 5) == 0); } SECTION("BAD Loading") diff --git a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc index 5c8557baee6..6ea6b11ab12 100644 --- a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc +++ b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc @@ -34,7 +34,7 @@ TEST_CASE("QUICFrameRetransmitter ignore frame which can not be retranmistted", info->type = QUICFrameType::PING; info->level = QUICEncryptionLevel::NONE; - retransmitter.save_frame_info(info); + retransmitter.save_frame_info(std::move(info)); CHECK(retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX) == nullptr); } @@ -56,7 +56,7 @@ TEST_CASE("QUICFrameRetransmitter ignore frame which has wrong level", "[quic]") info->type = QUICFrameType::STREAM; info->level = QUICEncryptionLevel::HANDSHAKE; - retransmitter.save_frame_info(info); + retransmitter.save_frame_info(std::move(info)); CHECK(retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX) == nullptr); } @@ -77,7 +77,7 @@ TEST_CASE("QUICFrameRetransmitter successfully create retransmitted frame", "[qu frame_info->offset = 0x67890; frame_info->block = block; - retransmitter.save_frame_info(info); + retransmitter.save_frame_info(std::move(info)); auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); CHECK(frame != nullptr); @@ -102,7 +102,7 @@ TEST_CASE("QUICFrameRetransmitter successfully create stream frame", "[quic]") frame_info->block = block; CHECK(block->refcount() == 2); - retransmitter.save_frame_info(info); + retransmitter.save_frame_info(std::move(info)); CHECK(block->refcount() == 2); // block's refcount doesn't change auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); @@ -136,7 +136,7 @@ TEST_CASE("QUICFrameRetransmitter successfully split stream frame", "[quic]") frame_info->block = block; CHECK(block->refcount() == 2); - retransmitter.save_frame_info(info); + retransmitter.save_frame_info(std::move(info)); auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 15); CHECK(frame != nullptr); @@ -171,3 +171,54 @@ TEST_CASE("QUICFrameRetransmitter successfully split stream frame", "[quic]") CHECK(block->refcount() == 1); CHECK(block->data->refcount() == 1); } + +TEST_CASE("QUICFrameRetransmitter successfully split crypto frame", "[quic]") +{ + QUICFrameRetransmitter retransmitter; + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = QUICFrameType::CRYPTO; + info->level = QUICEncryptionLevel::INITIAL; + + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), data, sizeof(data)); + block->fill(sizeof(data)); + + CryptoFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->offset = 0x67890; + frame_info->block = block; + CHECK(block->refcount() == 2); + + retransmitter.save_frame_info(std::move(info)); + + auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 15); + CHECK(frame != nullptr); + CHECK(frame->type() == QUICFrameType::CRYPTO); + auto crypto_frame = static_cast(frame.get()); + CHECK(crypto_frame->offset() == 0x67890); + CHECK(crypto_frame->size() <= 15); + + auto size = crypto_frame->data_length(); + CHECK(memcmp(crypto_frame->data()->start(), data, crypto_frame->data_length()) == 0); + // one for var block, one for the left data which saved in retransmitter + CHECK(block->data->refcount() == 2); + // one for var block, one for the left data which saved in retransmitter, one for var frame + CHECK(block->refcount() == 2); + frame = QUICFrameFactory::create_null_frame(); + // one for var block, one for var info + CHECK(block->refcount() == 2); + CHECK(block->data->refcount() == 1); + + frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); + CHECK(frame != nullptr); + CHECK(frame->type() == QUICFrameType::CRYPTO); + crypto_frame = static_cast(frame.get()); + CHECK(crypto_frame->offset() == 0x67890 + size); + CHECK(crypto_frame->data_length() == sizeof(data) - size); + CHECK(memcmp(crypto_frame->data()->start(), data + size, crypto_frame->data_length()) == 0); + CHECK(block->refcount() == 1); // one for var block + + frame = QUICFrameFactory::create_null_frame(); + CHECK(block->refcount() == 1); + CHECK(block->data->refcount() == 1); +} From d1f3ca0d324ca42e15138b0d35a70a03ce860221 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 26 Dec 2018 12:03:30 +0900 Subject: [PATCH 1005/1313] Make it compilable with OpenSSL for draft-17 (probably broken) --- iocore/net/quic/QUICKeyGenerator.cc | 16 +++- iocore/net/quic/QUICKeyGenerator.h | 6 +- iocore/net/quic/QUICKeyGenerator_openssl.cc | 17 ---- iocore/net/quic/QUICTLS.cc | 41 +++++----- iocore/net/quic/QUICTLS.h | 4 +- iocore/net/quic/QUICTLS_boringssl.cc | 7 ++ iocore/net/quic/QUICTLS_openssl.cc | 90 +++++++++++++-------- 7 files changed, 103 insertions(+), 78 deletions(-) diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 3c99e573be1..d88cf533d6e 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -81,6 +81,16 @@ QUICKeyGenerator::generate(QUICConnectionId cid) return km; } +std::unique_ptr +QUICKeyGenerator::regenerate(const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher, QUICHKDF &hkdf) +{ + std::unique_ptr km = std::make_unique(); + + this->_generate(*km, hkdf, secret, secret_len, cipher); + + return km; +} + int QUICKeyGenerator::_generate(KeyMaterial &km, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher) @@ -91,7 +101,7 @@ QUICKeyGenerator::_generate(KeyMaterial &km, QUICHKDF &hkdf, const uint8_t *secr // pn_key = HKDF-Expand-Label(S, "pn", "", pn_key_length) this->_generate_key(km.key, &km.key_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); this->_generate_iv(km.iv, &km.iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher)); - QUICKeyGenerator::generate_pn(km.pn, &km.pn_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); + this->_generate_pn(km.pn, &km.pn_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); return 0; } @@ -137,8 +147,8 @@ QUICKeyGenerator::_generate_iv(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, co } int -QUICKeyGenerator::generate_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, - size_t pn_length) +QUICKeyGenerator::_generate_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, + size_t pn_length) const { return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_PN.data(), LABEL_FOR_PN.length(), pn_length); } diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index fdc5765f2c2..1d3a062e8c6 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -51,15 +51,14 @@ class QUICKeyGenerator QUICKeyGenerator(Context ctx) : _ctx(ctx) {} - static int generate_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t pn_length); - static const EVP_MD *get_handshake_digest(const SSL *ssl); - /** * Generate keys for Initial encryption level * The keys for the remaining encryption level are derived by TLS stack with "quic " prefix */ std::unique_ptr generate(QUICConnectionId cid); + std::unique_ptr regenerate(const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher, QUICHKDF &hkdf); + private: Context _ctx = Context::SERVER; @@ -72,6 +71,7 @@ class QUICKeyGenerator 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_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t pn_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; diff --git a/iocore/net/quic/QUICKeyGenerator_openssl.cc b/iocore/net/quic/QUICKeyGenerator_openssl.cc index e843c82e8f4..5d9d0294e0f 100644 --- a/iocore/net/quic/QUICKeyGenerator_openssl.cc +++ b/iocore/net/quic/QUICKeyGenerator_openssl.cc @@ -61,20 +61,3 @@ QUICKeyGenerator::_get_cipher_for_protected_packet(const SSL *ssl) const return nullptr; } } - -const EVP_MD * -QUICKeyGenerator::get_handshake_digest(const SSL *ssl) -{ - switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) { - case TLS1_3_CK_AES_128_GCM_SHA256: - case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - case TLS1_3_CK_AES_128_CCM_SHA256: - case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_sha256(); - case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_sha384(); - default: - ink_assert(false); - return nullptr; - } -} diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 8eb81b39f38..dc6e11e7104 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -109,29 +109,11 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) std::unique_ptr km; km = this->_keygen_for_client.generate(cid); - - if (is_debug_tag_set("vv_quic_crypto")) { - uint8_t print_buf[512]; - QUICDebug::to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "key=%s", print_buf); - QUICDebug::to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "iv=%s", print_buf); - QUICDebug::to_hex(print_buf, km->pn, km->pn_len); - Debug("vv_quic_crypto", "pn=%s", print_buf); - } + this->_print_km("initial - client", *km); this->_client_pp->set_key(std::move(km), QUICKeyPhase::INITIAL); km = this->_keygen_for_server.generate(cid); - - if (is_debug_tag_set("vv_quic_crypto")) { - uint8_t print_buf[512]; - QUICDebug::to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "key=%s", print_buf); - QUICDebug::to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "iv=%s", print_buf); - QUICDebug::to_hex(print_buf, km->pn, km->pn_len); - Debug("vv_quic_crypto", "pn=%s", print_buf); - } + this->_print_km("initial - server", *km); this->_server_pp->set_key(std::move(km), QUICKeyPhase::INITIAL); return 1; @@ -277,3 +259,22 @@ QUICTLS::_get_km(QUICKeyPhase phase, bool for_encryption) const return pp->get_key(phase); } + +void +QUICTLS::_print_km(const char *header, KeyMaterial &km, const uint8_t *secret, size_t secret_len) +{ + if (is_debug_tag_set("vv_quic_crypto")) { + Debug("vv_quic_crypto", "%s", header); + uint8_t print_buf[128]; + if (secret) { + QUICDebug::to_hex(print_buf, static_cast(secret), secret_len); + Debug("vv_quic_crypto", "secret=%s", print_buf); + } + QUICDebug::to_hex(print_buf, km.key, km.key_len); + Debug("vv_quic_crypto", "key=%s", print_buf); + QUICDebug::to_hex(print_buf, km.iv, km.iv_len); + Debug("vv_quic_crypto", "iv=%s", print_buf); + QUICDebug::to_hex(print_buf, km.pn, km.pn_len); + Debug("vv_quic_crypto", "pn=%s", print_buf); + } +} diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 32498fc03e8..b3830b6779b 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -67,7 +67,7 @@ class QUICTLS : public QUICHandshakeProtocol bool is_ready_to_derive() const override; bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const override; int initialize_key_materials(QUICConnectionId cid) override; - void update_key_materials_on_key_cb(std::unique_ptr km, int name); + void update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t secret_len); const char *negotiated_cipher_suite() const override; void negotiated_application_name(const uint8_t **name, unsigned int *len) const override; const KeyMaterial *key_material_for_encryption(QUICKeyPhase phase) const override; @@ -86,6 +86,7 @@ class QUICTLS : public QUICHandshakeProtocol QUICKeyGenerator _keygen_for_server = QUICKeyGenerator(QUICKeyGenerator::Context::SERVER); void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; const QUIC_EVP_CIPHER *_get_evp_aead(QUICKeyPhase phase) const; + const EVP_MD *_get_handshake_digest() const; size_t _get_aead_tag_len(QUICKeyPhase phase) const; const KeyMaterial *_get_km(QUICKeyPhase phase, bool for_encryption) const; @@ -100,6 +101,7 @@ class QUICTLS : public QUICHandshakeProtocol int _process_post_handshake_messages(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in); void _generate_0rtt_key(); void _update_encryption_level(QUICEncryptionLevel level); + void _print_km(const char *header, KeyMaterial &km, const uint8_t *secret = nullptr, size_t secret_len = 0); SSL *_ssl = nullptr; QUICPacketProtection *_client_pp = nullptr; diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc index f80c80e3a84..159d0df2f1b 100644 --- a/iocore/net/quic/QUICTLS_boringssl.cc +++ b/iocore/net/quic/QUICTLS_boringssl.cc @@ -120,6 +120,13 @@ QUICTLS::_get_aead_tag_len(QUICKeyPhase phase) const } } +const EVP_MD * +QUICKeyGenerator::_get_handshake_digest() +{ + // TODO not implemented + return nullptr; +} + bool QUICTLS::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const EVP_AEAD *aead, diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index af841900a15..428d666dab6 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -139,24 +139,21 @@ msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, } static int -key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, const unsigned char *key, size_t key_len, - const unsigned char *iv, size_t iv_len, void *arg) +key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, void *arg) { - QUICTLS *qtls = reinterpret_cast(arg); - if (qtls == nullptr) { + if (arg == nullptr) { return 0; } - std::unique_ptr km = std::make_unique(); - memcpy(km->key, key, key_len); - km->key_len = key_len; - memcpy(km->iv, iv, iv_len); - km->iv_len = iv_len; + QUICTLS *qtls = reinterpret_cast(arg); + qtls->update_key_materials_on_key_cb(name, secret, secret_len); - const EVP_MD *md = QUICKeyGenerator::get_handshake_digest(ssl); - QUICHKDF hkdf(md); - QUICKeyGenerator::generate_pn(km->pn, &km->pn_len, hkdf, secret, secret_len, key_len); + return 1; +} +void +QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t secret_len) +{ if (is_debug_tag_set("vv_quic_crypto")) { switch (name) { case SSL_KEY_CLIENT_EARLY_TRAFFIC: @@ -177,50 +174,58 @@ key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, const default: break; } - - uint8_t print_buf[128]; - QUICDebug::to_hex(print_buf, static_cast(secret), secret_len); - Debug("vv_quic_crypto", "secret=%s", print_buf); - QUICDebug::to_hex(print_buf, km->key, km->key_len); - Debug("vv_quic_crypto", "key=%s", print_buf); - QUICDebug::to_hex(print_buf, km->iv, km->iv_len); - Debug("vv_quic_crypto", "iv=%s", print_buf); - QUICDebug::to_hex(print_buf, km->pn, km->pn_len); - Debug("vv_quic_crypto", "pn=%s", print_buf); } - qtls->update_key_materials_on_key_cb(std::move(km), name); - - return 1; -} -void -QUICTLS::update_key_materials_on_key_cb(std::unique_ptr km, int name) -{ if (this->_state == HandshakeState::ABORTED) { return; } + QUICKeyPhase phase; + const QUIC_EVP_CIPHER *cipher; + QUICHKDF hkdf(this->_get_handshake_digest()); + std::unique_ptr km = nullptr; + switch (name) { case SSL_KEY_CLIENT_EARLY_TRAFFIC: // this->_update_encryption_level(QUICEncryptionLevel::ZERO_RTT); - this->_client_pp->set_key(std::move(km), QUICKeyPhase::ZERO_RTT); + phase = QUICKeyPhase::ZERO_RTT; + cipher = this->_get_evp_aead(phase); + km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); + this->_print_km("update - client", *km, secret, secret_len); + this->_client_pp->set_key(std::move(km), phase); break; case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); - this->_client_pp->set_key(std::move(km), QUICKeyPhase::HANDSHAKE); + phase = QUICKeyPhase::HANDSHAKE; + cipher = this->_get_evp_aead(phase); + km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); + this->_print_km("update - client", *km, secret, secret_len); + this->_client_pp->set_key(std::move(km), phase); break; case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); - this->_client_pp->set_key(std::move(km), QUICKeyPhase::PHASE_0); + phase = QUICKeyPhase::PHASE_0; + cipher = this->_get_evp_aead(phase); + km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); + this->_print_km("update - client", *km, secret, secret_len); + this->_client_pp->set_key(std::move(km), phase); break; case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); - this->_server_pp->set_key(std::move(km), QUICKeyPhase::HANDSHAKE); + phase = QUICKeyPhase::HANDSHAKE; + cipher = this->_get_evp_aead(phase); + km = this->_keygen_for_server.regenerate(secret, secret_len, cipher, hkdf); + this->_print_km("update - server", *km, secret, secret_len); + this->_server_pp->set_key(std::move(km), phase); break; case SSL_KEY_SERVER_APPLICATION_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); - this->_server_pp->set_key(std::move(km), QUICKeyPhase::PHASE_0); + phase = QUICKeyPhase::PHASE_0; + cipher = this->_get_evp_aead(phase); + km = this->_keygen_for_server.regenerate(secret, secret_len, cipher, hkdf); + this->_print_km("update - server", *km, secret, secret_len); + this->_server_pp->set_key(std::move(km), phase); break; default: break; @@ -532,6 +537,23 @@ QUICTLS::_get_aead_tag_len(QUICKeyPhase phase) const } } +const EVP_MD * +QUICTLS::_get_handshake_digest() const +{ + switch (SSL_CIPHER_get_id(SSL_get_current_cipher(this->_ssl))) { + case TLS1_3_CK_AES_128_GCM_SHA256: + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + case TLS1_3_CK_AES_128_CCM_SHA256: + case TLS1_3_CK_AES_128_CCM_8_SHA256: + return EVP_sha256(); + case TLS1_3_CK_AES_256_GCM_SHA384: + return EVP_sha384(); + default: + ink_assert(false); + return nullptr; + } +} + bool QUICTLS::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const EVP_CIPHER *aead, From cd8347a7d2202733ad1644aa384e725cd2d941b5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 26 Dec 2018 14:35:32 +0900 Subject: [PATCH 1006/1313] Update version numbers to draft-17 and h3-17 --- iocore/net/quic/QUICConfig.cc | 2 +- iocore/net/quic/QUICTypes.h | 2 +- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 3b0c8798174..8e8ccf5d1bb 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -36,7 +36,7 @@ // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html // Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? using namespace std::literals; -static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-14"sv); +static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5h3-17"sv); int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 7783a713f2b..714d85093b3 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -50,7 +50,7 @@ using QUICOffset = uint64_t; // Note: Fix QUIC_ALPN_PROTO_LIST in QUICConfig.cc // Note: Change ExtensionType (QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID) if it's changed constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff00000f, + 0xff000011, }; constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 65e0d5e867d..7f2535f1aad 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -53,7 +53,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x55, // DCIL/SCIL 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Destination Connection ID 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection ID - 0xff, 0x00, 0x00, 0x0f, // Supported Version + 0xff, 0x00, 0x00, 0x11, // Supported Version }; uint8_t buf[1024] = {0}; size_t buf_len; From bc7fe3cb2c18925c8ce3e3393caf33c80c9cb7ef Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 27 Dec 2018 17:30:55 +0900 Subject: [PATCH 1007/1313] Unprotect packet headers --- iocore/net/P_QUICNetVConnection.h | 4 +- iocore/net/P_QUICPacketHandler.h | 10 +- iocore/net/QUICNetVConnection.cc | 8 +- iocore/net/QUICPacketHandler.cc | 14 +- iocore/net/quic/Makefile.am | 7 +- iocore/net/quic/QUICHKDF.cc | 2 +- iocore/net/quic/QUICHandshakeProtocol.cc | 57 ------ iocore/net/quic/QUICHandshakeProtocol.h | 23 +-- iocore/net/quic/QUICKeyGenerator.cc | 24 +-- iocore/net/quic/QUICKeyGenerator.h | 6 +- iocore/net/quic/QUICPacket.cc | 107 +++--------- iocore/net/quic/QUICPacket.h | 17 +- iocore/net/quic/QUICPacketHeaderProtector.cc | 162 ++++++++++++++++++ iocore/net/quic/QUICPacketHeaderProtector.h | 53 ++++++ ...c => QUICPacketHeaderProtector_openssl.cc} | 32 ++-- iocore/net/quic/QUICPacketReceiveQueue.cc | 19 +- iocore/net/quic/QUICPacketReceiveQueue.h | 4 +- iocore/net/quic/QUICTLS.cc | 4 +- iocore/net/quic/QUICTLS.h | 2 +- iocore/net/quic/QUICTLS_openssl.cc | 31 ++-- iocore/net/quic/QUICTypes.cc | 13 +- iocore/net/quic/QUICTypes.h | 18 +- .../quic/test/test_QUICHandshakeProtocol.cc | 24 +-- iocore/net/quic/test/test_QUICKeyGenerator.cc | 86 ++-------- 24 files changed, 370 insertions(+), 357 deletions(-) create mode 100644 iocore/net/quic/QUICPacketHeaderProtector.cc create mode 100644 iocore/net/quic/QUICPacketHeaderProtector.h rename iocore/net/quic/{QUICHandshakeProtocol_openssl.cc => QUICPacketHeaderProtector_openssl.cc} (67%) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index da5f732709d..5ff0961f934 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -253,7 +253,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICAckFrameManager _ack_frame_manager; QUICPinger _pinger; QUICPacketRetransmitter _packet_retransmitter; - QUICPacketNumberProtector _pn_protector; + QUICPacketHeaderProtector _ph_protector; QUICRTTMeasure _rtt_measure; QUICApplicationMap *_application_map = nullptr; @@ -275,7 +275,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICAltConnectionManager *_alt_con_manager = nullptr; QUICPathValidator *_path_validator = nullptr; - QUICPacketReceiveQueue _packet_recv_queue = {this->_packet_factory, this->_pn_protector}; + QUICPacketReceiveQueue _packet_recv_queue = {this->_packet_factory, this->_ph_protector}; QUICConnectionErrorUPtr _connection_error = nullptr; uint32_t _state_closing_recv_packet_count = 0; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index c475e9f206d..b24808ff55c 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -32,7 +32,7 @@ class QUICClosedConCollector; class QUICNetVConnection; class QUICPacket; -class QUICPacketNumberProtector; +class QUICPacketHeaderProtector; class QUICPacketHandler { @@ -40,14 +40,14 @@ class QUICPacketHandler QUICPacketHandler(); ~QUICPacketHandler(); - virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketNumberProtector &pn_protector) = 0; + virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketHeaderProtector &pn_protector) = 0; virtual void send_packet(QUICNetVConnection *vc, Ptr udp_payload) = 0; virtual void close_conenction(QUICNetVConnection *conn); protected: static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu, - const QUICPacketNumberProtector *pn_protector, int dcil); + const QUICPacketHeaderProtector *ph_protector, int dcil); static void _send_packet(Continuation *c, QUICNetVConnection *vc, Ptr udp_payload); Event *_collector_event = nullptr; @@ -74,7 +74,7 @@ class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler // QUICPacketHandler virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, - const QUICPacketNumberProtector &pn_protector) override; + const QUICPacketHeaderProtector &ph_protector) override; virtual void send_packet(QUICNetVConnection *vc, Ptr udp_payload) override; private: @@ -100,7 +100,7 @@ class QUICPacketHandlerOut : public Continuation, public QUICPacketHandler // QUICPacketHandler virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, - const QUICPacketNumberProtector &pn_protector) override; + const QUICPacketHeaderProtector &pn_protector) override; virtual void send_packet(QUICNetVConnection *vc, Ptr udp_payload) override; private: diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2a2b953bb3f..9c10de9f3b1 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -264,7 +264,7 @@ QUICNetVConnection::start() this->_frame_dispatcher = new QUICFrameDispatcher(this); this->_packet_factory.set_hs_protocol(this->_hs_protocol); - this->_pn_protector.set_hs_protocol(this->_hs_protocol); + this->_ph_protector.set_hs_protocol(this->_hs_protocol); // Create frame handlers this->_congestion_controller = new QUICCongestionController(this); @@ -1230,8 +1230,8 @@ QUICNetVConnection::_state_common_send_packet() written += len; // TODO: Avoid static function. We don't need to parse buffer again. Get packet number offset from packet. - QUICPacket::protect_packet_number( - buf, len, &this->_pn_protector, + QUICPacket::protect_packet_header( + buf, len, &this->_ph_protector, (this->_peer_quic_connection_id == QUICConnectionId::ZERO()) ? 0 : this->_peer_quic_connection_id.length()); QUICConDebug("[TX] %s packet #%" PRIu64 " size=%zu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), @@ -1272,7 +1272,7 @@ QUICNetVConnection::_state_closing_send_packet() // that an endpoint maintains for a closing connection, endpoints MAY // send the exact same packet. if (this->_the_final_packet) { - this->_packet_handler->send_packet(*this->_the_final_packet, this, this->_pn_protector); + this->_packet_handler->send_packet(*this->_the_final_packet, this, this->_ph_protector); } return nullptr; diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 25476c52e8f..4153fabe215 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -72,7 +72,7 @@ QUICPacketHandler::close_conenction(QUICNetVConnection *conn) void QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu, - const QUICPacketNumberProtector *pn_protector, int dcil) + const QUICPacketHeaderProtector *ph_protector, int dcil) { size_t udp_len; Ptr udp_payload(new_IOBufferBlock()); @@ -80,8 +80,8 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo packet.store(reinterpret_cast(udp_payload->end()), &udp_len); udp_payload->fill(udp_len); - if (pn_protector) { - QUICPacket::protect_packet_number(reinterpret_cast(udp_payload->start()), udp_len, pn_protector, dcil); + if (ph_protector) { + QUICPacket::protect_packet_header(reinterpret_cast(udp_payload->start()), udp_len, ph_protector, dcil); } UDPPacket *udp_packet = new_UDPPacket(addr, 0, udp_payload); @@ -345,9 +345,9 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // TODO: Should be called via eventProcessor? void -QUICPacketHandlerIn::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketNumberProtector &pn_protector) +QUICPacketHandlerIn::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketHeaderProtector &ph_protector) { - this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &pn_protector, vc->peer_connection_id().length()); + this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &ph_protector, vc->peer_connection_id().length()); } void @@ -446,9 +446,9 @@ QUICPacketHandlerOut::event_handler(int event, Event *data) } void -QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketNumberProtector &pn_protector) +QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketHeaderProtector &ph_protector) { - this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &pn_protector, vc->peer_connection_id().length()); + this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &ph_protector, vc->peer_connection_id().length()); } void diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 6744958f633..e24293317ea 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -34,11 +34,11 @@ AM_CPPFLAGS += \ noinst_LIBRARIES = libquic.a if OPENSSL_IS_BORINGSSL -QUICHSProtocol_impl = QUICHandshakeProtocol_boringssl.cc +QUICPHProtector_impl = QUICPacketHeaderProtector_boringssl.cc QUICTLS_impl = QUICTLS_boringssl.cc QUICKeyGenerator_impl = QUICKeyGenerator_boringssl.cc else -QUICHSProtocol_impl = QUICHandshakeProtocol_openssl.cc +QUICPHProtector_impl = QUICPacketHeaderProtector_openssl.cc QUICTLS_impl = QUICTLS_openssl.cc QUICKeyGenerator_impl = QUICKeyGenerator_openssl.cc endif @@ -59,7 +59,8 @@ libquic_a_SOURCES = \ QUICStream.cc \ QUICHandshake.cc \ QUICHandshakeProtocol.cc \ - $(QUICHSProtocol_impl) \ + QUICPacketHeaderProtector.cc \ + $(QUICPHProtector_impl) \ QUICTLS.cc \ $(QUICTLS_impl) \ QUICKeyGenerator.cc \ diff --git a/iocore/net/quic/QUICHKDF.cc b/iocore/net/quic/QUICHKDF.cc index 08cc8cd9428..778eac50b85 100644 --- a/iocore/net/quic/QUICHKDF.cc +++ b/iocore/net/quic/QUICHKDF.cc @@ -45,7 +45,7 @@ QUICHKDF::expand(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t se hkdf_label_len += 2; // label (prefix + Label) field - hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%cquic %.*s", static_cast(5 + label_len), + hkdf_label_len += sprintf(reinterpret_cast(hkdf_label + hkdf_label_len), "%ctls13 %.*s", static_cast(6 + label_len), static_cast(label_len), label); // context field diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index 50711ff3d35..8fa07012819 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -20,17 +20,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "QUICGlobals.h" #include "QUICHandshakeProtocol.h" -#include "QUICDebugNames.h" - -#include "tscore/Diags.h" #include "QUICTypes.h" -#include "QUICHKDF.h" - -// -// QUICPacketProtection -// QUICPacketProtection::~QUICPacketProtection() {} @@ -51,51 +42,3 @@ QUICPacketProtection::key_phase() const { return this->_key_phase; } - -// -// QUICPacketNumberProtector -// - -bool -QUICPacketNumberProtector::protect(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, - uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const -{ - const KeyMaterial *km = this->_hs_protocol->key_material_for_encryption(phase); - if (!km) { - Debug("quic_pne", "Failed to encrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); - return false; - } - - const QUIC_EVP_CIPHER *aead = this->_hs_protocol->cipher_for_pne(phase); - - bool ret = this->_encrypt_pn(protected_pn, protected_pn_len, unprotected_pn, unprotected_pn_len, sample, *km, aead); - if (!ret) { - Debug("quic_pne", "Failed to encrypt a packet number"); - } - return ret; -} - -bool -QUICPacketNumberProtector::unprotect(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, - uint8_t protected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const -{ - const KeyMaterial *km = this->_hs_protocol->key_material_for_decryption(phase); - if (!km) { - Debug("quic_pne", "Failed to decrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); - return false; - } - - const QUIC_EVP_CIPHER *aead = this->_hs_protocol->cipher_for_pne(phase); - - bool ret = this->_decrypt_pn(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, *km, aead); - if (!ret) { - Debug("quic_pne", "Failed to decrypt a packet number"); - } - return ret; -} - -void -QUICPacketNumberProtector::set_hs_protocol(const QUICHandshakeProtocol *hs_protocol) -{ - this->_hs_protocol = hs_protocol; -} diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 5bd77b41f17..f2d37c01430 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -44,27 +44,6 @@ class QUICPacketProtection QUICKeyPhase _key_phase = QUICKeyPhase::INITIAL; }; -class QUICPacketNumberProtector -{ -public: - bool protect(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, - const uint8_t *sample, QUICKeyPhase phase) const; - bool unprotect(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, - const uint8_t *sample, QUICKeyPhase phase) const; - - // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICCryptoInfoProvider or somethign instead. - // For now it receives a CONST pointer so PacketNubmerProtector cannot bother handshake. - void set_hs_protocol(const QUICHandshakeProtocol *hs_protocol); - -private: - const QUICHandshakeProtocol *_hs_protocol = nullptr; - - bool _encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, - const uint8_t *sample, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead) const; - bool _decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, uint8_t protected_pn_len, - const uint8_t *sample, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead) const; -}; - struct QUICHandshakeMsgs { uint8_t *buf = nullptr; //< pointer to the buffer size_t max_buf_len = 0; //< size of buffer @@ -88,7 +67,7 @@ class QUICHandshakeProtocol virtual void negotiated_application_name(const uint8_t **name, unsigned int *len) const = 0; virtual const KeyMaterial *key_material_for_encryption(QUICKeyPhase phase) const = 0; virtual const KeyMaterial *key_material_for_decryption(QUICKeyPhase phase) const = 0; - virtual const QUIC_EVP_CIPHER *cipher_for_pne(QUICKeyPhase phase) const = 0; + virtual const QUIC_EVP_CIPHER *cipher_for_hp(QUICKeyPhase phase) const = 0; virtual std::shared_ptr local_transport_parameters() = 0; virtual std::shared_ptr remote_transport_parameters() = 0; diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index d88cf533d6e..d37234aa94d 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -34,13 +34,13 @@ using namespace std::literals; constexpr static uint8_t QUIC_VERSION_1_SALT[] = { - 0x9c, 0x10, 0x8f, 0x98, 0x52, 0x0a, 0x5c, 0x5c, 0x32, 0x96, 0x8e, 0x95, 0x0e, 0x8a, 0x2c, 0x5f, 0xe0, 0x6d, 0x6c, 0x38, + 0xef, 0x4f, 0xb0, 0xab, 0xb4, 0x74, 0x70, 0xc4, 0x1b, 0xef, 0xcf, 0x80, 0x31, 0x33, 0x4f, 0xae, 0x48, 0x5e, 0x09, 0xa0, }; constexpr static std::string_view LABEL_FOR_CLIENT_INITIAL_SECRET("client in"sv); constexpr static std::string_view LABEL_FOR_SERVER_INITIAL_SECRET("server in"sv); -constexpr static std::string_view LABEL_FOR_KEY("key"sv); -constexpr static std::string_view LABEL_FOR_IV("iv"sv); -constexpr static std::string_view LABEL_FOR_PN("pn"sv); +constexpr static std::string_view LABEL_FOR_KEY("quic key"sv); +constexpr static std::string_view LABEL_FOR_IV("quic iv"sv); +constexpr static std::string_view LABEL_FOR_HP("quic hp"sv); std::unique_ptr QUICKeyGenerator::generate(QUICConnectionId cid) @@ -95,13 +95,13 @@ int QUICKeyGenerator::_generate(KeyMaterial &km, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher) { - // Generate key, iv, and pn_key - // key = HKDF-Expand-Label(S, "key", "", key_length) - // iv = HKDF-Expand-Label(S, "iv", "", iv_length) - // pn_key = HKDF-Expand-Label(S, "pn", "", pn_key_length) + // Generate key, iv, and hp_key + // key = HKDF-Expand-Label(S, "quic key", "", key_length) + // iv = HKDF-Expand-Label(S, "quic iv", "", iv_length) + // hp_key = HKDF-Expand-Label(S, "quic hp", "", hp_key_length) this->_generate_key(km.key, &km.key_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); this->_generate_iv(km.iv, &km.iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher)); - this->_generate_pn(km.pn, &km.pn_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); + this->_generate_hp(km.hp, &km.hp_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); return 0; } @@ -147,8 +147,8 @@ QUICKeyGenerator::_generate_iv(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, co } int -QUICKeyGenerator::_generate_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, - size_t pn_length) const +QUICKeyGenerator::_generate_hp(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, + size_t hp_length) const { - return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_PN.data(), LABEL_FOR_PN.length(), pn_length); + return hkdf.expand(out, out_len, secret, secret_len, LABEL_FOR_HP.data(), LABEL_FOR_HP.length(), hp_length); } diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index 1d3a062e8c6..4d9bf2d426c 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -38,10 +38,10 @@ struct KeyMaterial { // uint8_t iv[EVP_MAX_IV_LENGTH] = {0}; uint8_t key[512] = {0}; uint8_t iv[512] = {0}; - uint8_t pn[512] = {0}; + uint8_t hp[512] = {0}; size_t key_len = 512; size_t iv_len = 512; - size_t pn_len = 512; + size_t hp_len = 512; }; class QUICKeyGenerator @@ -71,7 +71,7 @@ class QUICKeyGenerator 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_pn(uint8_t *out, size_t *out_len, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t pn_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; diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 670bceeb2cf..26b2acba26c 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -194,8 +194,8 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf offset += QUICVariableInt::size(raw_buf + offset); // PN Field - int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf + offset); - QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset), pn_len, + 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; } @@ -268,12 +268,12 @@ QUICPacketLongHeader::type(QUICPacketType &type, const uint8_t *packet, size_t p return false; } - uint8_t raw_type = packet[0] & 0x7F; QUICVersion version; if (QUICPacketLongHeader::version(version, packet, packet_len) && version == 0x00) { type = QUICPacketType::VERSION_NEGOTIATION; } else { - type = static_cast(raw_type); + uint8_t raw_type = (packet[0] & 0x30) >> 4; + type = static_cast(raw_type); } return true; } @@ -377,7 +377,7 @@ QUICPacketLongHeader::length(size_t &length, uint8_t *field_len, const uint8_t * } bool -QUICPacketLongHeader::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len) +QUICPacketLongHeader::packet_number_offset(uint8_t &pn_offset, const uint8_t *packet, size_t packet_len) { QUICPacketType type; QUICPacketLongHeader::type(type, packet, packet_len); @@ -397,6 +397,15 @@ QUICPacketLongHeader::packet_number_offset(size_t &pn_offset, const uint8_t *pac return true; } +bool +QUICPacketLongHeader::key_phase(QUICKeyPhase &phase, const uint8_t *packet, size_t packet_len) +{ + QUICPacketType type; + QUICPacketLongHeader::type(type, packet, packet_len); + phase = QUICTypeUtil::key_phase(type); + return true; +} + QUICConnectionId QUICPacketLongHeader::destination_cid() const { @@ -489,12 +498,6 @@ QUICPacketLongHeader::token_len() const return this->_token_len; } -bool -QUICPacketLongHeader::has_key_phase() const -{ - return false; -} - QUICKeyPhase QUICPacketLongHeader::key_phase() const { @@ -610,8 +613,8 @@ QUICPacketShortHeader::QUICPacketShortHeader(const IpEndpoint from, ats_unique_b 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() + offset); - QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(this->_buf.get() + offset); + 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); } @@ -620,7 +623,6 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase k QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len) { this->_type = type; - this->_has_key_phase = true; this->_key_phase = key_phase; this->_packet_number = packet_number; this->_base_packet_number = base_packet_number; @@ -634,7 +636,6 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase k ats_unique_buf buf, size_t len) { this->_type = type; - this->_has_key_phase = true; this->_key_phase = key_phase; this->_connection_id = connection_id; this->_packet_number = packet_number; @@ -707,12 +708,6 @@ QUICPacketShortHeader::payload() const } } -bool -QUICPacketShortHeader::has_key_phase() const -{ - return true; -} - QUICKeyPhase QUICPacketShortHeader::key_phase() const { @@ -740,7 +735,7 @@ QUICPacketShortHeader::key_phase(QUICKeyPhase &phase, const uint8_t *packet, siz } bool -QUICPacketShortHeader::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len, int dcil) +QUICPacketShortHeader::packet_number_offset(uint8_t &pn_offset, const uint8_t *packet, size_t packet_len, int dcil) { pn_offset = 1 + dcil; return true; @@ -991,7 +986,7 @@ QUICPacket::encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si bool QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, QUICPacketNumber largest_acked) { - ink_assert(len == 1 || len == 2 || len == 4); + ink_assert(len == 1 || len == 2 || len == 3 || len == 4); uint64_t maximum_diff = 0; switch (len) { @@ -1001,11 +996,14 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si case 2: maximum_diff = 0x4000; break; + case 3: + maximum_diff = 0x400000; + break; case 4: maximum_diff = 0x40000000; break; default: - ink_assert(!"len must be 1, 2 or 4"); + ink_assert(!"len must be 1, 2, 3 or 4"); } QUICPacketNumber base = largest_acked & (~(maximum_diff - 1)); QUICPacketNumber candidate1 = base + src; @@ -1023,9 +1021,9 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si } bool -QUICPacket::protect_packet_number(uint8_t *packet, size_t packet_len, const QUICPacketNumberProtector *pn_protector, int dcil) +QUICPacket::protect_packet_header(uint8_t *packet, size_t packet_len, const QUICPacketHeaderProtector *ph_protector, int dcil) { - size_t pn_offset = 0; + uint8_t pn_offset = 0; uint8_t pn_len = 4; size_t sample_offset = 0; constexpr int aead_expansion = 16; // Currently, AEAD expansion (which is probably AEAD tag) length is always 16 @@ -1040,71 +1038,18 @@ QUICPacket::protect_packet_number(uint8_t *packet, size_t packet_len, const QUIC QUICPacketShortHeader::key_phase(phase, packet, packet_len); QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, dcil); } - sample_offset = std::min(pn_offset + 4, packet_len - aead_expansion); + sample_offset = std::min(static_cast(pn_offset) + 4, packet_len - aead_expansion); uint8_t protected_pn[4] = {0}; uint8_t protected_pn_len = 0; pn_len = QUICTypeUtil::read_QUICPacketNumberLen(packet + pn_offset); - if (!pn_protector->protect(protected_pn, protected_pn_len, packet + pn_offset, pn_len, packet + sample_offset, phase)) { + if (!ph_protector->protect(protected_pn, protected_pn_len, packet + pn_offset, pn_len, packet + sample_offset, phase)) { return false; } memcpy(packet + pn_offset, protected_pn, pn_len); return true; } -bool -QUICPacket::unprotect_packet_number(uint8_t *packet, size_t packet_len, const QUICPacketNumberProtector *pn_protector) -{ - size_t pn_offset = 0; - uint8_t pn_len = 4; - size_t sample_offset = 0; - constexpr int aead_expansion = 16; // Currently, AEAD expansion (which is probably AEAD tag) length is always 16 - QUICKeyPhase phase; - - if (QUICInvariants::is_long_header(packet)) { -#ifdef DEBUG - QUICVersion version; - QUICPacketLongHeader::version(version, packet, packet_len); - ink_assert(version != 0x0); -#endif - - QUICPacketType type; - QUICPacketLongHeader::type(type, packet, packet_len); - phase = QUICTypeUtil::key_phase(type); - - if (!QUICPacketLongHeader::packet_number_offset(pn_offset, packet, packet_len)) { - Debug(tag.data(), "Failed to calculate packet number offset"); - return false; - } - - Debug("v_quic_crypto", "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), - QUICDebugNames::key_phase(phase)); - - } else { - QUICPacketShortHeader::key_phase(phase, packet, packet_len); - if (!QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, QUICConnectionId::SCID_LEN)) { - Debug(tag.data(), "Failed to calculate packet number offset"); - return false; - } - } - sample_offset = std::min(pn_offset + 4, packet_len - aead_expansion); - - uint8_t unprotected_pn[4] = {0}; - uint8_t unprotected_pn_len = 0; - if (!pn_protector->unprotect(unprotected_pn, unprotected_pn_len, packet + pn_offset, pn_len, packet + sample_offset, phase)) { - return false; - } - unprotected_pn_len = QUICTypeUtil::read_QUICPacketNumberLen(unprotected_pn); - - if (pn_offset + unprotected_pn_len > packet_len) { - Debug(tag.data(), "Malformed header: pn_offset=%zu, pn_len=%d", pn_offset, unprotected_pn_len); - return false; - } - - memcpy(packet + pn_offset, unprotected_pn, unprotected_pn_len); - return true; -} - // // QUICPacketFactory // diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 63ccbdf48f5..45fb79e49ce 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -32,6 +32,7 @@ #include "QUICTypes.h" #include "QUICHandshakeProtocol.h" +#include "QUICPacketHeaderProtector.h" #include "QUICFrame.h" #define QUIC_FIELD_OFFSET_CONNECTION_ID 1 @@ -119,9 +120,8 @@ class QUICPacketHeader QUICPacketHeaderUPtr clone() const; - virtual bool has_key_phase() const = 0; - virtual bool has_version() const = 0; - virtual bool is_valid() const = 0; + virtual bool has_version() const = 0; + virtual bool is_valid() const = 0; /***** STATIC members *****/ @@ -197,7 +197,6 @@ class QUICPacketHeader QUICPacketNumber _base_packet_number = 0; QUICVersion _version = 0; size_t _payload_length = 0; - bool _has_key_phase = false; bool _has_version = false; }; @@ -226,7 +225,6 @@ class QUICPacketLongHeader : public QUICPacketHeader const uint8_t *token() const; size_t token_len() const; QUICKeyPhase key_phase() const; - bool has_key_phase() const; uint16_t size() const; void store(uint8_t *buf, size_t *len) const; @@ -242,7 +240,8 @@ class QUICPacketLongHeader : public QUICPacketHeader 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, const uint8_t *packet, size_t packet_len); static bool length(size_t &length, uint8_t *field_len, 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); + static bool key_phase(QUICKeyPhase &key_phase, const uint8_t *packet, size_t packet_len); + static bool packet_number_offset(uint8_t &pn_offset, const uint8_t *packet, size_t packet_len); private: bool _odcil(uint8_t &odcil, const uint8_t *buf, size_t buf_len); @@ -280,12 +279,11 @@ class QUICPacketShortHeader : public QUICPacketHeader QUICVersion version() const; const uint8_t *payload() const; QUICKeyPhase key_phase() const; - bool has_key_phase() const; uint16_t size() const; void store(uint8_t *buf, size_t *len) const; 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); + static bool packet_number_offset(uint8_t &pn_offset, const uint8_t *packet, size_t packet_len, int dcil); private: int _packet_number_len; @@ -383,8 +381,7 @@ class QUICPacket : public QUICTrackablePacket 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); - static bool protect_packet_number(uint8_t *packet, size_t packet_len, const QUICPacketNumberProtector *pn_protector, int dcil); - static bool unprotect_packet_number(uint8_t *packet, size_t packet_len, const QUICPacketNumberProtector *pn_protector); + static bool protect_packet_header(uint8_t *packet, size_t packet_len, const QUICPacketHeaderProtector *ph_protector, int dcil); LINK(QUICPacket, link); diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc new file mode 100644 index 00000000000..7bc8e839139 --- /dev/null +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -0,0 +1,162 @@ +/** @file + * + * QUIC Packet Header Protector + * + * @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 "QUICPacketHeaderProtector.h" +#include "QUICDebugNames.h" +#include "QUICPacket.h" + +#include "tscore/Diags.h" + +bool +QUICPacketHeaderProtector::protect(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, + uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const +{ + const QUIC_EVP_CIPHER *aead = this->_hs_protocol->cipher_for_hp(phase); + + const KeyMaterial *km = this->_hs_protocol->key_material_for_encryption(phase); + if (!km) { + return false; + } + + bool ret = + this->_encrypt_pn(protected_pn, protected_pn_len, unprotected_pn, unprotected_pn_len, sample, km->hp, km->hp_len, aead); + if (!ret) { + Debug("quic_pne", "Failed to encrypt a packet number"); + } + return ret; +} + +bool +QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected_packet_len) +{ + // Do nothing if the packet is VN + if (QUICInvariants::is_long_header(protected_packet)) { + QUICVersion version; + QUICPacketLongHeader::version(version, protected_packet, protected_packet_len); + if (version == 0x0) { + 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); + } else { + QUICPacketShortHeader::key_phase(phase, protected_packet, protected_packet_len); + type = QUICPacketType::PROTECTED; + } + + Debug("v_quic_pne", "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), + QUICDebugNames::key_phase(phase)); + + const QUIC_EVP_CIPHER *aead = this->_hs_protocol->cipher_for_hp(phase); + if (!aead) { + Debug("quic_pne", "Failed to decrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); + return false; + } + + const KeyMaterial *km = this->_hs_protocol->key_material_for_decryption(phase); + if (!km) { + Debug("quic_pne", "Failed to decrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); + return false; + } + + uint8_t sample_offset; + if (!this->_calc_sample_offset(&sample_offset, protected_packet, protected_packet_len)) { + Debug("v_quic_pne", "Failed to calculate a sample offset"); + return false; + } + + uint8_t mask[EVP_MAX_BLOCK_LENGTH]; + if (!this->_generate_mask(mask, protected_packet + sample_offset, km->hp, aead)) { + Debug("v_quic_pne", "Failed to generate a mask"); + return false; + } + + if (!this->_unprotect(protected_packet, protected_packet_len, mask)) { + Debug("quic_pne", "Failed to decrypt a packet number"); + } + + return true; +} + +void +QUICPacketHeaderProtector::set_hs_protocol(const QUICHandshakeProtocol *hs_protocol) +{ + this->_hs_protocol = hs_protocol; +} + +bool +QUICPacketHeaderProtector::_calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len) +{ + uint8_t pn_offset = 0; + uint8_t aead_expansion = 16; + QUICKeyPhase phase; + + if (QUICInvariants::is_long_header(protected_packet)) { + uint8_t dcil; + uint8_t scil; + size_t dummy; + uint8_t length_len; + QUICPacketLongHeader::dcil(dcil, protected_packet, protected_packet_len); + QUICPacketLongHeader::scil(scil, protected_packet, protected_packet_len); + QUICPacketLongHeader::length(dummy, &length_len, protected_packet, protected_packet_len); + *sample_offset = 6 + dcil + scil + length_len + 4; + + QUICPacketType type; + QUICPacketLongHeader::type(type, protected_packet, protected_packet_len); + if (type == QUICPacketType::INITIAL) { + size_t token_len; + uint8_t token_length_len; + QUICPacketLongHeader::token_length(token_len, &token_length_len, protected_packet, protected_packet_len); + *sample_offset += token_len + token_length_len; + } + } else { + QUICPacketShortHeader::key_phase(phase, protected_packet, protected_packet_len); + } + return std::min(static_cast(pn_offset) + 4, protected_packet_len - aead_expansion); +} + +bool +QUICPacketHeaderProtector::_unprotect(uint8_t *protected_packet, size_t protected_packet_len, const uint8_t *mask) +{ + uint8_t pn_offset; + + // 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); + } else { + protected_packet[0] ^= mask[0] & 0x1f; + QUICPacketShortHeader::packet_number_offset(pn_offset, protected_packet, protected_packet_len, QUICConnectionId::SCID_LEN); + } + uint8_t pn_length = QUICTypeUtil::read_QUICPacketNumberLen(protected_packet); + + for (int i = 0; i < pn_length; ++i) { + protected_packet[pn_offset + i] ^= mask[1 + i]; + } + + return true; +} diff --git a/iocore/net/quic/QUICPacketHeaderProtector.h b/iocore/net/quic/QUICPacketHeaderProtector.h new file mode 100644 index 00000000000..1f388af1c31 --- /dev/null +++ b/iocore/net/quic/QUICPacketHeaderProtector.h @@ -0,0 +1,53 @@ +/** @file + * + * QUIC Packet Header Protector + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICTypes.h" +#include "QUICKeyGenerator.h" +#include "QUICHandshakeProtocol.h" + +class QUICPacketHeaderProtector +{ +public: + bool unprotect(uint8_t *protected_packet, size_t protected_packet_len); + + bool protect(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, + const uint8_t *sample, QUICKeyPhase phase) const; + + // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICCryptoInfoProvider or somethign instead. + // For now it receives a CONST pointer so PacketNubmerProtector cannot bother handshake. + void set_hs_protocol(const QUICHandshakeProtocol *hs_protocol); + +private: + const QUICHandshakeProtocol *_hs_protocol = nullptr; + + bool _calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len); + + bool _generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *aead); + + bool _unprotect(uint8_t *packet, size_t packet_len, const uint8_t *mask); + + bool _encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, + const uint8_t *sample, const uint8_t *key, size_t key_len, const QUIC_EVP_CIPHER *aead) const; +}; diff --git a/iocore/net/quic/QUICHandshakeProtocol_openssl.cc b/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc similarity index 67% rename from iocore/net/quic/QUICHandshakeProtocol_openssl.cc rename to iocore/net/quic/QUICPacketHeaderProtector_openssl.cc index 77f82c51dea..d88ede04c2d 100644 --- a/iocore/net/quic/QUICHandshakeProtocol_openssl.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc @@ -21,51 +21,49 @@ * limitations under the License. */ -#include "QUICHandshakeProtocol.h" +#include "QUICPacketHeaderProtector.h" bool -QUICPacketNumberProtector::_encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, - uint8_t unprotected_pn_len, const uint8_t *sample, const KeyMaterial &km, - const EVP_CIPHER *aead) const +QUICPacketHeaderProtector::_generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *aead) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); - int len = 0; - if (!ctx || !EVP_EncryptInit_ex(ctx, aead, nullptr, km.pn, sample)) { + if (!ctx || !EVP_EncryptInit_ex(ctx, aead, nullptr, key, sample)) { return false; } - if (!EVP_EncryptUpdate(ctx, protected_pn, &len, unprotected_pn, unprotected_pn_len)) { + + int len = 0; + if (!EVP_EncryptUpdate(ctx, mask, &len, sample, 16)) { return false; } - protected_pn_len = len; - if (!EVP_EncryptFinal_ex(ctx, protected_pn + len, &len)) { + if (!EVP_EncryptFinal_ex(ctx, mask + len, &len)) { return false; } - protected_pn_len += len; + EVP_CIPHER_CTX_free(ctx); return true; } bool -QUICPacketNumberProtector::_decrypt_pn(uint8_t *unprotected_pn, uint8_t &unprotected_pn_len, const uint8_t *protected_pn, - uint8_t protected_pn_len, const uint8_t *sample, const KeyMaterial &km, +QUICPacketHeaderProtector::_encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, + uint8_t unprotected_pn_len, const uint8_t *sample, const uint8_t *key, size_t key_len, const EVP_CIPHER *aead) const { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); int len = 0; - if (!ctx || !EVP_DecryptInit_ex(ctx, aead, nullptr, km.pn, sample)) { + if (!ctx || !EVP_EncryptInit_ex(ctx, aead, nullptr, key, sample)) { return false; } - if (!EVP_DecryptUpdate(ctx, unprotected_pn, &len, protected_pn, protected_pn_len)) { + if (!EVP_EncryptUpdate(ctx, protected_pn, &len, unprotected_pn, unprotected_pn_len)) { return false; } - unprotected_pn_len = len; - if (!EVP_DecryptFinal_ex(ctx, unprotected_pn, &len)) { + protected_pn_len = len; + if (!EVP_EncryptFinal_ex(ctx, protected_pn + len, &len)) { return false; } - unprotected_pn_len += len; + protected_pn_len += len; EVP_CIPHER_CTX_free(ctx); return true; diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 0fb445c2dfe..ae6b5344c6d 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -61,8 +61,8 @@ long_hdr_pkt_len(size_t &pkt_len, uint8_t *buf, size_t len) return true; } -QUICPacketReceiveQueue::QUICPacketReceiveQueue(QUICPacketFactory &packet_factory, QUICPacketNumberProtector &pn_protector) - : _packet_factory(packet_factory), _pn_protector(pn_protector) +QUICPacketReceiveQueue::QUICPacketReceiveQueue(QUICPacketFactory &packet_factory, QUICPacketHeaderProtector &ph_protector) + : _packet_factory(packet_factory), _ph_protector(ph_protector) { } @@ -100,10 +100,9 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) } } - ats_unique_buf pkt = {nullptr}; - size_t pkt_len = 0; - bool has_packet_number = true; - QUICPacketType type = QUICPacketType::UNINITIALIZED; + ats_unique_buf pkt = {nullptr}; + size_t pkt_len = 0; + QUICPacketType type = QUICPacketType::UNINITIALIZED; if (QUICInvariants::is_long_header(this->_payload.get())) { uint8_t *buf = this->_payload.get() + this->_offset; @@ -113,9 +112,8 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) QUICVersion version; QUICPacketLongHeader::version(version, buf, remaining_len); if (is_vn(version)) { - has_packet_number = false; - pkt_len = remaining_len; - type = QUICPacketType::VERSION_NEGOTIATION; + pkt_len = remaining_len; + type = QUICPacketType::VERSION_NEGOTIATION; } else if (!QUICTypeUtil::is_supported_version(version)) { result = QUICPacketCreationResult::UNSUPPORTED; pkt_len = remaining_len; @@ -176,8 +174,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) type = QUICPacketType::PROTECTED; } - // VN doesn't have Packet Number field - if (!has_packet_number || QUICPacket::unprotect_packet_number(pkt.get(), pkt_len, &this->_pn_protector)) { + if (this->_ph_protector.unprotect(pkt.get(), pkt_len)) { quic_packet = this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->_largest_received_packet_number, result); } else { // ZERO_RTT might be rejected diff --git a/iocore/net/quic/QUICPacketReceiveQueue.h b/iocore/net/quic/QUICPacketReceiveQueue.h index 8473ab76630..a3518ff883a 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.h +++ b/iocore/net/quic/QUICPacketReceiveQueue.h @@ -31,7 +31,7 @@ class QUICPacketReceiveQueue { public: - QUICPacketReceiveQueue(QUICPacketFactory &packet_factory, QUICPacketNumberProtector &pn_protector); + QUICPacketReceiveQueue(QUICPacketFactory &packet_factory, QUICPacketHeaderProtector &ph_protector); void enqueue(UDPPacket *packet); QUICPacketUPtr dequeue(QUICPacketCreationResult &result); @@ -41,7 +41,7 @@ class QUICPacketReceiveQueue private: CountQueue _queue; QUICPacketFactory &_packet_factory; - QUICPacketNumberProtector &_pn_protector; + QUICPacketHeaderProtector &_ph_protector; QUICPacketNumber _largest_received_packet_number = 0; // FIXME: workaround code for coalescing packets ats_unique_buf _payload = {nullptr}; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index dc6e11e7104..06bf7dc3a5b 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -274,7 +274,7 @@ QUICTLS::_print_km(const char *header, KeyMaterial &km, const uint8_t *secret, s Debug("vv_quic_crypto", "key=%s", print_buf); QUICDebug::to_hex(print_buf, km.iv, km.iv_len); Debug("vv_quic_crypto", "iv=%s", print_buf); - QUICDebug::to_hex(print_buf, km.pn, km.pn_len); - Debug("vv_quic_crypto", "pn=%s", print_buf); + QUICDebug::to_hex(print_buf, km.hp, km.hp_len); + Debug("vv_quic_crypto", "hp=%s", print_buf); } } diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index b3830b6779b..e523e0e72b4 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -72,7 +72,7 @@ class QUICTLS : public QUICHandshakeProtocol void negotiated_application_name(const uint8_t **name, unsigned int *len) const override; const KeyMaterial *key_material_for_encryption(QUICKeyPhase phase) const override; const KeyMaterial *key_material_for_decryption(QUICKeyPhase phase) const override; - const QUIC_EVP_CIPHER *cipher_for_pne(QUICKeyPhase phase) const override; + const QUIC_EVP_CIPHER *cipher_for_hp(QUICKeyPhase phase) const override; bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 428d666dab6..46f958dfee5 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -176,7 +176,6 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t } } - if (this->_state == HandshakeState::ABORTED) { return; } @@ -189,41 +188,41 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t switch (name) { case SSL_KEY_CLIENT_EARLY_TRAFFIC: // this->_update_encryption_level(QUICEncryptionLevel::ZERO_RTT); - phase = QUICKeyPhase::ZERO_RTT; + phase = QUICKeyPhase::ZERO_RTT; cipher = this->_get_evp_aead(phase); - km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); + km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); this->_print_km("update - client", *km, secret, secret_len); this->_client_pp->set_key(std::move(km), phase); break; case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); - phase = QUICKeyPhase::HANDSHAKE; + phase = QUICKeyPhase::HANDSHAKE; cipher = this->_get_evp_aead(phase); - km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); + km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); this->_print_km("update - client", *km, secret, secret_len); this->_client_pp->set_key(std::move(km), phase); break; case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); - phase = QUICKeyPhase::PHASE_0; + phase = QUICKeyPhase::PHASE_0; cipher = this->_get_evp_aead(phase); - km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); + km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); this->_print_km("update - client", *km, secret, secret_len); this->_client_pp->set_key(std::move(km), phase); break; case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); - phase = QUICKeyPhase::HANDSHAKE; + phase = QUICKeyPhase::HANDSHAKE; cipher = this->_get_evp_aead(phase); - km = this->_keygen_for_server.regenerate(secret, secret_len, cipher, hkdf); + km = this->_keygen_for_server.regenerate(secret, secret_len, cipher, hkdf); this->_print_km("update - server", *km, secret, secret_len); this->_server_pp->set_key(std::move(km), phase); break; case SSL_KEY_SERVER_APPLICATION_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); - phase = QUICKeyPhase::PHASE_0; + phase = QUICKeyPhase::PHASE_0; cipher = this->_get_evp_aead(phase); - km = this->_keygen_for_server.regenerate(secret, secret_len, cipher, hkdf); + km = this->_keygen_for_server.regenerate(secret, secret_len, cipher, hkdf); this->_print_km("update - server", *km, secret, secret_len); this->_server_pp->set_key(std::move(km), phase); break; @@ -426,23 +425,23 @@ QUICTLS::reset() } const EVP_CIPHER * -QUICTLS::cipher_for_pne(QUICKeyPhase phase) const +QUICTLS::cipher_for_hp(QUICKeyPhase phase) const { if (phase == QUICKeyPhase::INITIAL) { - return EVP_aes_128_ctr(); + return EVP_aes_128_ecb(); } else { const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); if (cipher) { switch (SSL_CIPHER_get_id(cipher)) { case TLS1_3_CK_AES_128_GCM_SHA256: - return EVP_aes_128_ctr(); + return EVP_aes_128_ecb(); case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_aes_256_ctr(); + return EVP_aes_256_ecb(); case TLS1_3_CK_CHACHA20_POLY1305_SHA256: return EVP_chacha20(); case TLS1_3_CK_AES_128_CCM_SHA256: case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_aes_128_ctr(); + return EVP_aes_128_ecb(); default: ink_assert(false); return nullptr; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 178a055938c..5c76a02455d 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -143,20 +143,13 @@ QUICTypeUtil::read_QUICConnectionId(const uint8_t *buf, uint8_t len) int QUICTypeUtil::read_QUICPacketNumberLen(const uint8_t *buf) { - if ((buf[0] & 0xC0) == 0xC0) { - return 4; - } else if ((buf[0] & 0x80) == 0x80) { - return 2; - } else { - return 1; - } + return (buf[0] & 0x03) + 1; } QUICPacketNumber -QUICTypeUtil::read_QUICPacketNumber(const uint8_t *buf) +QUICTypeUtil::read_QUICPacketNumber(const uint8_t *buf, int encoded_length) { - int encoded_length = QUICTypeUtil::read_QUICPacketNumberLen(buf); - uint64_t pn = QUICIntUtil::read_nbytes_as_uint(buf, encoded_length); + uint64_t pn = QUICIntUtil::read_nbytes_as_uint(buf, encoded_length); // Remove length indicator if (encoded_length == 1) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 714d85093b3..c8e03c42dfe 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -81,14 +81,14 @@ constexpr QUICEncryptionLevel QUIC_PN_SPACES[] = { // Devide to QUICPacketType and QUICPacketLongHeaderType ? enum class QUICPacketType : uint8_t { - VERSION_NEGOTIATION = 0, - PROTECTED, // Not on the spec. but just for convenience // should be short header - STATELESS_RESET, // Not on the spec. but just for convenience - INITIAL = 0x7F, // draft-08 version-specific type - RETRY = 0x7E, // draft-08 version-specific type - HANDSHAKE = 0x7D, // draft-08 version-specific type - ZERO_RTT_PROTECTED = 0x7C, // draft-08 version-specific type - UNINITIALIZED = 0xFF, // Not on the spec. but just for convenience + INITIAL = 0x00, // draft-17 version-specific type + ZERO_RTT_PROTECTED = 0x01, // draft-17 version-specific type + HANDSHAKE = 0x02, // draft-17 version-specific type + RETRY = 0x03, // draft-17 version-specific type + VERSION_NEGOTIATION = 0xF0, // Not on the spec. but just for convenience + PROTECTED, // Not on the spec. but just for convenience + STATELESS_RESET, // Not on the spec. but just for convenience + UNINITIALIZED = 0xFF, // Not on the spec. but just for convenience }; // XXX If you add or remove QUICFrameType, you might also need to change QUICFrame::type(const uint8_t *) @@ -456,7 +456,7 @@ class QUICTypeUtil static QUICConnectionId read_QUICConnectionId(const uint8_t *buf, uint8_t n); static int read_QUICPacketNumberLen(const uint8_t *buf); - static QUICPacketNumber read_QUICPacketNumber(const uint8_t *buf); + static QUICPacketNumber read_QUICPacketNumber(const uint8_t *buf, int len); static QUICVersion read_QUICVersion(const uint8_t *buf); static QUICStreamId read_QUICStreamId(const uint8_t *buf); static QUICOffset read_QUICOffset(const uint8_t *buf); diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 7a4e1cd4cc4..0c32eb8a82d 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -389,11 +389,11 @@ TEST_CASE("QUICHandshakeProtocol") CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - QUICPacketNumberProtector client_pn_protector; - QUICPacketNumberProtector server_pn_protector; + QUICPacketHeaderProtector client_ph_protector; + QUICPacketHeaderProtector server_ph_protector; - client_pn_protector.set_hs_protocol(client); - server_pn_protector.set_hs_protocol(server); + client_ph_protector.set_hs_protocol(client); + server_ph_protector.set_hs_protocol(server); uint8_t expected[] = {0x01, 0x02, 0x03, 0x04, 0x05}; uint8_t sample[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; @@ -401,14 +401,14 @@ TEST_CASE("QUICHandshakeProtocol") uint8_t protected_pn_len = 0, unprotected_pn_len = 0; // ## Client -> Server - client_pn_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); - server_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, + client_ph_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); + server_ph_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::INITIAL); CHECK(unprotected_pn_len == sizeof(expected)); CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); // ## Server -> Client - server_pn_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); - client_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, + server_ph_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); + client_ph_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::INITIAL); CHECK(unprotected_pn_len == sizeof(expected)); CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); @@ -489,14 +489,14 @@ TEST_CASE("QUICHandshakeProtocol") // # End Handshake // ## Client -> Server - client_pn_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); - server_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, + client_ph_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); + server_ph_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); CHECK(unprotected_pn_len == sizeof(expected)); CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); // ## Server -> Client - server_pn_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); - client_pn_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, + server_ph_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); + client_ph_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, QUICKeyPhase::PHASE_0); CHECK(unprotected_pn_len == sizeof(expected)); CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index d0a2ec0461d..73ea2440335 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -34,78 +34,24 @@ #include "QUICKeyGenerator.h" -TEST_CASE("QUICKeyGenerator", "[quic]") +// https://github.com/quicwg/base-drafts/wiki/Test-Vector-for-the-Clear-Text-AEAD-key-derivation +TEST_CASE("draft-17 Test Vectors", "[quic]") { SECTION("CLIENT Initial") { QUICKeyGenerator keygen(QUICKeyGenerator::Context::CLIENT); - QUICConnectionId cid = {reinterpret_cast("\x06\xb8\x58\xec\x6f\x80\x45\x2b"), 8}; + QUICConnectionId cid = {reinterpret_cast("\xc6\x54\xef\xd8\xa3\x1b\x47\x92"), 8}; uint8_t expected_client_key[] = { - 0xa7, 0x99, 0x43, 0x56, 0x6c, 0x41, 0x34, 0x2f, 0x2b, 0xc3, 0xde, 0x6b, 0x7c, 0x15, 0x39, 0xdf, - }; - uint8_t expected_client_iv[] = { - 0x84, 0xeb, 0x95, 0x4f, 0xfe, 0x16, 0x1c, 0x38, 0x75, 0x91, 0x9f, 0x5f, - }; - uint8_t expected_client_pn[] = { - 0x5c, 0x0f, 0x64, 0x72, 0xa1, 0x56, 0x58, 0x04, 0x7a, 0x3c, 0xc1, 0xf1, 0x54, 0x78, 0xdc, 0xf4, - }; - - std::unique_ptr actual_km = keygen.generate(cid); - - CHECK(actual_km->key_len == sizeof(expected_client_key)); - CHECK(memcmp(actual_km->key, expected_client_key, sizeof(expected_client_key)) == 0); - CHECK(actual_km->iv_len == sizeof(expected_client_iv)); - CHECK(memcmp(actual_km->iv, expected_client_iv, sizeof(expected_client_iv)) == 0); - CHECK(actual_km->pn_len == sizeof(expected_client_pn)); - CHECK(memcmp(actual_km->pn, expected_client_pn, sizeof(expected_client_pn)) == 0); - } - - SECTION("SERVER Initial") - { - QUICKeyGenerator keygen(QUICKeyGenerator::Context::SERVER); - - QUICConnectionId cid = {reinterpret_cast("\x06\xb8\x58\xec\x6f\x80\x45\x2b"), 8}; + 0x86, 0xd1, 0x83, 0x04, 0x80, 0xb4, 0x0f, 0x86, 0xcf, 0x9d, 0x68, 0xdc, 0xad, 0xf3, 0x5d, 0xfe, - uint8_t expected_server_key[] = { - 0x26, 0x08, 0x0e, 0x60, 0xd2, 0x88, 0xdb, 0x7d, 0xf8, 0x16, 0xa1, 0xcb, 0x0b, 0xc6, 0xc7, 0xf4, - }; - uint8_t expected_server_iv[] = { - 0xb9, 0xfd, 0xc5, 0xb4, 0x48, 0xaf, 0x3e, 0x02, 0x34, 0x22, 0x44, 0x3b, - }; - uint8_t expected_server_pn[] = { - 0x00, 0xba, 0xbb, 0xe1, 0xbe, 0x0f, 0x0c, 0x66, 0x18, 0x18, 0x8b, 0x4f, 0xcc, 0xa5, 0x7a, 0x96, - }; - - std::unique_ptr actual_km = keygen.generate(cid); - - CHECK(actual_km->key_len == sizeof(expected_server_key)); - CHECK(memcmp(actual_km->key, expected_server_key, sizeof(expected_server_key)) == 0); - CHECK(actual_km->iv_len == sizeof(expected_server_iv)); - CHECK(memcmp(actual_km->iv, expected_server_iv, sizeof(expected_server_iv)) == 0); - CHECK(actual_km->pn_len == sizeof(expected_server_pn)); - CHECK(memcmp(actual_km->pn, expected_server_pn, sizeof(expected_server_pn)) == 0); - } -} - -// https://github.com/quicwg/base-drafts/wiki/Test-Vector-for-the-Clear-Text-AEAD-key-derivation#draft-14-test-vectors -TEST_CASE("draft-14 Test Vectors", "[quic]") -{ - SECTION("CLIENT Initial") - { - QUICKeyGenerator keygen(QUICKeyGenerator::Context::CLIENT); - - QUICConnectionId cid = {reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x08"), 8}; - - uint8_t expected_client_key[] = { - 0xf2, 0x92, 0x8f, 0x26, 0x14, 0xad, 0x6c, 0x20, 0xb9, 0xbd, 0x00, 0x8e, 0x9c, 0x89, 0x63, 0x1c, }; uint8_t expected_client_iv[] = { - 0xab, 0x95, 0x0b, 0x01, 0x98, 0x63, 0x79, 0x78, 0xcf, 0x44, 0xaa, 0xb9, + 0x12, 0xf3, 0x93, 0x8a, 0xca, 0x34, 0xaa, 0x02, 0x54, 0x31, 0x63, 0xd4, }; - uint8_t expected_client_pn[] = { - 0x68, 0xc3, 0xf6, 0x4e, 0x2d, 0x66, 0x34, 0x41, 0x2b, 0x8e, 0x32, 0x94, 0x62, 0x8d, 0x76, 0xf1, + uint8_t expected_client_hp[] = { + 0xcd, 0x25, 0x3a, 0x36, 0xff, 0x93, 0x93, 0x7c, 0x46, 0x93, 0x84, 0xa8, 0x23, 0xaf, 0x6c, 0x56, }; std::unique_ptr actual_km = keygen.generate(cid); @@ -114,24 +60,24 @@ TEST_CASE("draft-14 Test Vectors", "[quic]") CHECK(memcmp(actual_km->key, expected_client_key, sizeof(expected_client_key)) == 0); CHECK(actual_km->iv_len == sizeof(expected_client_iv)); CHECK(memcmp(actual_km->iv, expected_client_iv, sizeof(expected_client_iv)) == 0); - CHECK(actual_km->pn_len == sizeof(expected_client_pn)); - CHECK(memcmp(actual_km->pn, expected_client_pn, sizeof(expected_client_pn)) == 0); + CHECK(actual_km->hp_len == sizeof(expected_client_hp)); + CHECK(memcmp(actual_km->hp, expected_client_hp, sizeof(expected_client_hp)) == 0); } SECTION("SERVER Initial") { QUICKeyGenerator keygen(QUICKeyGenerator::Context::SERVER); - QUICConnectionId cid = {reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x08"), 8}; + QUICConnectionId cid = {reinterpret_cast("\xc6\x54\xef\xd8\xa3\x1b\x47\x92"), 8}; uint8_t expected_server_key[] = { - 0xf5, 0x68, 0x17, 0xd0, 0xfc, 0x59, 0x5c, 0xfc, 0x0a, 0x2b, 0x0b, 0xcf, 0xb1, 0x87, 0x35, 0xec, + 0x2c, 0x78, 0x63, 0x3e, 0x20, 0x6e, 0x99, 0xad, 0x25, 0x19, 0x64, 0xf1, 0x9f, 0x6d, 0xcd, 0x6d, }; uint8_t expected_server_iv[] = { - 0x32, 0x05, 0x03, 0x5a, 0x3c, 0x93, 0x7c, 0x90, 0x2e, 0xe4, 0xf4, 0xd6, + 0x7b, 0x50, 0xbf, 0x36, 0x98, 0xa0, 0x6d, 0xfa, 0xbf, 0x75, 0xf2, 0x87, }; - uint8_t expected_server_pn[] = { - 0xa3, 0x13, 0xc8, 0x6d, 0x13, 0x73, 0xec, 0xbc, 0xcb, 0x32, 0x94, 0xb1, 0x49, 0x74, 0x22, 0x6c, + uint8_t expected_server_hp[] = { + 0x25, 0x79, 0xd8, 0x69, 0x6f, 0x85, 0xed, 0xa6, 0x8d, 0x35, 0x02, 0xb6, 0x55, 0x96, 0x58, 0x6b, }; std::unique_ptr actual_km = keygen.generate(cid); @@ -140,7 +86,7 @@ TEST_CASE("draft-14 Test Vectors", "[quic]") CHECK(memcmp(actual_km->key, expected_server_key, sizeof(expected_server_key)) == 0); CHECK(actual_km->iv_len == sizeof(expected_server_iv)); CHECK(memcmp(actual_km->iv, expected_server_iv, sizeof(expected_server_iv)) == 0); - CHECK(actual_km->pn_len == sizeof(expected_server_pn)); - CHECK(memcmp(actual_km->pn, expected_server_pn, sizeof(expected_server_pn)) == 0); + CHECK(actual_km->hp_len == sizeof(expected_server_hp)); + CHECK(memcmp(actual_km->hp, expected_server_hp, sizeof(expected_server_hp)) == 0); } } From 2f3b3c213b52b5d4a890540461fec5d3bbf44149 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 7 Jan 2019 11:33:59 +0900 Subject: [PATCH 1008/1313] Update frame types and names --- iocore/net/QUICNetVConnection.cc | 33 +--- iocore/net/quic/QUICDebugNames.cc | 22 +-- iocore/net/quic/QUICFlowController.cc | 2 +- iocore/net/quic/QUICFrame.cc | 218 +++------------------ iocore/net/quic/QUICFrame.h | 63 +----- iocore/net/quic/QUICIncomingFrameBuffer.cc | 2 +- iocore/net/quic/QUICPacketRetransmitter.cc | 7 +- iocore/net/quic/QUICStream.cc | 14 +- iocore/net/quic/QUICStreamManager.cc | 12 +- iocore/net/quic/QUICStreamState.cc | 38 ++-- iocore/net/quic/QUICTypes.h | 29 ++- 11 files changed, 107 insertions(+), 333 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 9c10de9f3b1..9cd1809090c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -511,7 +511,7 @@ QUICNetVConnection::close(QUICConnectionErrorUPtr error) std::vector QUICNetVConnection::interests() { - return {QUICFrameType::APPLICATION_CLOSE, QUICFrameType::CONNECTION_CLOSE, QUICFrameType::BLOCKED, QUICFrameType::MAX_DATA}; + return {QUICFrameType::CONNECTION_CLOSE, QUICFrameType::DATA_BLOCKED, QUICFrameType::MAX_DATA}; } QUICConnectionErrorUPtr @@ -530,10 +530,9 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra case QUICFrameType::PING: // Nothing to do break; - case QUICFrameType::BLOCKED: - // BLOCKED frame is for debugging. Nothing to do here. + case QUICFrameType::DATA_BLOCKED: + // DATA_BLOCKED frame is for debugging. Nothing to do here. break; - case QUICFrameType::APPLICATION_CLOSE: case QUICFrameType::CONNECTION_CLOSE: if (this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_closed) || this->handler == reinterpret_cast(&QUICNetVConnection::state_connection_draining)) { @@ -543,10 +542,7 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra // 7.9.1. Closing and Draining Connection States // An endpoint MAY transition from the closing period to the draining period if it can confirm that its peer is also closing or // draining. Receiving a closing frame is sufficient confirmation, as is receiving a stateless reset. - if (frame.type() == QUICFrameType::APPLICATION_CLOSE) { - this->_switch_to_draining_state(QUICConnectionErrorUPtr(std::make_unique( - QUICErrorClass::APPLICATION, static_cast(frame).error_code()))); - } else { + { uint16_t error_code = static_cast(frame).error_code(); this->_switch_to_draining_state( QUICConnectionErrorUPtr(std::make_unique(static_cast(error_code)))); @@ -1380,7 +1376,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa this->_store_frame(buf, len, max_frame_size, frame, frames); } - // BLOCKED + // DATA_BLOCKED if (this->_remote_flow_controller->credit() == 0 && this->_stream_manager->will_generate_frame(level)) { frame = this->_remote_flow_controller->generate_frame(level, UINT16_MAX, max_frame_size); if (frame) { @@ -1390,7 +1386,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } } - // STREAM, MAX_STREAM_DATA, STREAM_BLOCKED + // STREAM, MAX_STREAM_DATA, STREAM_DATA_BLOCKED if (!this->_path_validator->is_validating()) { frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); while (frame) { @@ -1491,12 +1487,8 @@ QUICNetVConnection::_packetize_closing_frame() QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - // CONNECTION_CLOSE or APPLICATION_CLOSE - if (this->_connection_error->cls == QUICErrorClass::APPLICATION) { - frame = QUICFrameFactory::create_application_close_frame(*this->_connection_error); - } else { - frame = QUICFrameFactory::create_connection_close_frame(*this->_connection_error); - } + // CONNECTION_CLOSE + frame = QUICFrameFactory::create_connection_close_frame(*this->_connection_error); uint32_t max_size = this->maximum_quic_packet_size(); ats_unique_buf buf = ats_unique_malloc(max_size); @@ -1642,13 +1634,8 @@ QUICNetVConnection::_init_flow_control_params(const std::shared_ptrcls == QUICErrorClass::APPLICATION) { - QUICError("QUICError: %s (%u), APPLICATION ERROR (0x%" PRIx16 ")", QUICDebugNames::error_class(error->cls), - static_cast(error->cls), error->code); - } else { - QUICError("QUICError: %s (%u), %s (0x%" PRIx16 ")", QUICDebugNames::error_class(error->cls), - static_cast(error->cls), QUICDebugNames::error_code(error->code), error->code); - } + QUICError("QUICError: %s (%u), %s (0x%" PRIx16 ")", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), QUICDebugNames::error_code(error->code), error->code); // Connection Error this->close(std::move(error)); diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 7fc32369c39..9f0cc702639 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -54,26 +54,24 @@ QUICDebugNames::frame_type(QUICFrameType type) switch (type) { case QUICFrameType::PADDING: return "PADDING"; - case QUICFrameType::RST_STREAM: - return "RST_STREAM"; + case QUICFrameType::RESET_STREAM: + return "RESET_STREAM"; case QUICFrameType::CONNECTION_CLOSE: return "CONNECTION_CLOSE"; - case QUICFrameType::APPLICATION_CLOSE: - return "APPLICATION_CLOSE"; case QUICFrameType::MAX_DATA: return "MAX_DATA"; case QUICFrameType::MAX_STREAM_DATA: return "MAX_STREAM_DATA"; - case QUICFrameType::MAX_STREAM_ID: - return "MAX_STREAM_ID"; + case QUICFrameType::MAX_STREAMS: + return "MAX_STREAMS"; case QUICFrameType::PING: return "PING"; - case QUICFrameType::BLOCKED: - return "BLOCKED"; - case QUICFrameType::STREAM_BLOCKED: - return "STREAM_BLOCKED"; - case QUICFrameType::STREAM_ID_BLOCKED: - return "STREAM_ID_BLOCKED"; + case QUICFrameType::DATA_BLOCKED: + return "DATA_BLOCKED"; + case QUICFrameType::STREAM_DATA_BLOCKED: + return "STREAM_DATA_BLOCKED"; + case QUICFrameType::STREAMS_BLOCKED: + return "STREAMS_BLOCKED"; case QUICFrameType::NEW_CONNECTION_ID: return "NEW_CONNECTION_ID"; case QUICFrameType::STOP_SENDING: diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index ae88d815356..a973543d52f 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -151,7 +151,7 @@ QUICRemoteFlowController::update(QUICOffset offset) void QUICRemoteFlowController::_on_frame_lost(QUICFrameInformationUPtr &info) { - ink_assert(info->type == QUICFrameType::BLOCKED || info->type == QUICFrameType::STREAM_BLOCKED); + ink_assert(info->type == QUICFrameType::DATA_BLOCKED || info->type == QUICFrameType::STREAM_DATA_BLOCKED); if (this->_offset == *reinterpret_cast(info->data)) { this->_frame = this->_create_frame(); } diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index be365e1bca7..9f546eff37a 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -36,7 +36,6 @@ ClassAllocator quicAckFrameAllocator("quicAckFrameAllocator"); ClassAllocator quicPaddingFrameAllocator("quicPaddingFrameAllocator"); ClassAllocator quicRstStreamFrameAllocator("quicRstStreamFrameAllocator"); ClassAllocator quicConnectionCloseFrameAllocator("quicConnectionCloseFrameAllocator"); -ClassAllocator quicApplicationCloseFrameAllocator("quicApplicationCloseFrameAllocator"); ClassAllocator quicMaxDataFrameAllocator("quicMaxDataFrameAllocator"); ClassAllocator quicMaxStreamDataFrameAllocator("quicMaxStreamDataFrameAllocator"); ClassAllocator quicMaxStreamIdFrameAllocator("quicMaxStreamDataIdAllocator"); @@ -103,10 +102,16 @@ QUICFrame::type(const uint8_t *buf) { if (buf[0] >= static_cast(QUICFrameType::UNKNOWN)) { return QUICFrameType::UNKNOWN; - } else if (static_cast(QUICFrameType::STREAM) <= buf[0] && buf[0] < static_cast(QUICFrameType::CRYPTO)) { - return QUICFrameType::STREAM; - } else if (static_cast(QUICFrameType::ACK) <= buf[0] && buf[0] < static_cast(QUICFrameType::UNKNOWN)) { + } else if (static_cast(QUICFrameType::ACK) <= buf[0] && buf[0] < static_cast(QUICFrameType::RESET_STREAM)) { return QUICFrameType::ACK; + } else if (static_cast(QUICFrameType::STREAM) <= buf[0] && buf[0] < static_cast(QUICFrameType::MAX_DATA)) { + return QUICFrameType::STREAM; + } else if (static_cast(QUICFrameType::MAX_STREAMS) <= buf[0] && buf[0] < static_cast(QUICFrameType::DATA_BLOCKED)) { + return QUICFrameType::MAX_STREAMS; + } else if (static_cast(QUICFrameType::STREAMS_BLOCKED) <= buf[0] && buf[0] < static_cast(QUICFrameType::NEW_CONNECTION_ID)) { + return QUICFrameType::STREAMS_BLOCKED; + } else if (static_cast(QUICFrameType::CONNECTION_CLOSE) <= buf[0] && buf[0] < static_cast(QUICFrameType::UNKNOWN)) { + return QUICFrameType::CONNECTION_CLOSE; } else { return static_cast(buf[0]); } @@ -1009,7 +1014,7 @@ QUICAckFrame::EcnSection::ecn_ce_count() const } // -// RST_STREAM frame +// RESET_STREAM frame // QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameId id, @@ -1073,7 +1078,7 @@ QUICRstStreamFrame::clone() const QUICFrameType QUICRstStreamFrame::type() const { - return QUICFrameType::RST_STREAM; + return QUICFrameType::RESET_STREAM; } size_t @@ -1095,7 +1100,7 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len, size_t limit) const size_t n; uint8_t *p = buf; - *p = static_cast(QUICFrameType::RST_STREAM); + *p = static_cast(QUICFrameType::RESET_STREAM); ++p; QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); p += n; @@ -1419,149 +1424,6 @@ QUICConnectionCloseFrame::reason_phrase() const return this->_reason_phrase; } -// -// APPLICATION_CLOSE frame -// -QUICApplicationCloseFrame::QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, - const char *reason_phrase, QUICFrameId id, QUICFrameGenerator *owner) - : QUICFrame(id, owner) -{ - this->_error_code = error_code; - this->_reason_phrase_length = reason_phrase_length; - this->_reason_phrase = reason_phrase; -} - -QUICApplicationCloseFrame::QUICApplicationCloseFrame(const uint8_t *buf, size_t len) -{ - this->parse(buf, len); -} - -void -QUICApplicationCloseFrame::_reset() -{ - this->_error_code = 0; - this->_reason_phrase_length = 0; - this->_reason_phrase = nullptr; - - this->_owner = nullptr; - this->_id = 0; - this->_size = 0; - this->_valid = false; -} - -void -QUICApplicationCloseFrame::parse(const uint8_t *buf, size_t len) -{ - ink_assert(len >= 1); - this->_reset(); - uint8_t *pos = const_cast(buf) + 1; - - if (LEFT_SPACE(pos) < 2) { - return; - } - - this->_error_code = QUICIntUtil::read_nbytes_as_uint(pos, 2); - pos += 2; - - size_t field_len = 0; - if (!read_varint(pos, LEFT_SPACE(pos), this->_reason_phrase_length, field_len)) { - return; - } - - if (LEFT_SPACE(pos) < this->_reason_phrase_length) { - return; - } - - this->_valid = true; - this->_reason_phrase = reinterpret_cast(pos); - this->_size = FRAME_SIZE(pos) + this->_reason_phrase_length; -} - -QUICFrameUPtr -QUICApplicationCloseFrame::clone() const -{ - return QUICFrameFactory::create_application_close_frame(this->error_code(), this->reason_phrase_length(), this->reason_phrase(), - this->_id, this->_owner); -} - -QUICFrameType -QUICApplicationCloseFrame::type() const -{ - return QUICFrameType::APPLICATION_CLOSE; -} - -size_t -QUICApplicationCloseFrame::size() const -{ - if (this->_size) { - return this->_size; - } - - return 1 + sizeof(QUICTransErrorCode) + QUICVariableInt::size(this->_reason_phrase_length) + this->_reason_phrase_length; -} - -size_t -QUICApplicationCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const -{ - if (limit < this->size()) { - return 0; - } - - size_t n; - uint8_t *p = buf; - *p = static_cast(QUICFrameType::APPLICATION_CLOSE); - ++p; - QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, p, &n); - p += n; - QUICIntUtil::write_QUICVariableInt(this->_reason_phrase_length, p, &n); - p += n; - if (this->_reason_phrase_length > 0) { - memcpy(p, this->_reason_phrase, this->_reason_phrase_length); - p += this->_reason_phrase_length; - } - - *len = p - buf; - return *len; -} - -int -QUICApplicationCloseFrame::debug_msg(char *msg, size_t msg_len) const -{ - int len = - snprintf(msg, msg_len, "| APPLICATION_CLOSE size=%zu code=%s", this->size(), QUICDebugNames::error_code(this->error_code())); - - if (this->reason_phrase_length() != 0 && this->reason_phrase() != nullptr) { - memcpy(msg + len, " reason=", 8); - len += 8; - - int phrase_len = std::min(msg_len - len, static_cast(this->reason_phrase_length())); - memcpy(msg + len, this->reason_phrase(), phrase_len); - len += phrase_len; - msg[len] = '\0'; - ++len; - } - - return len; -} - -QUICAppErrorCode -QUICApplicationCloseFrame::error_code() const -{ - return this->_error_code; -} - -uint64_t -QUICApplicationCloseFrame::reason_phrase_length() const -{ - return this->_reason_phrase_length; -} - -const char * -QUICApplicationCloseFrame::reason_phrase() const -{ - return this->_reason_phrase; -} - // // MAX_DATA frame // @@ -1762,7 +1624,7 @@ QUICMaxStreamDataFrame::maximum_stream_data() const } // -// MAX_STREAM_ID +// MAX_STREAMS // QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICFrameId id, QUICFrameGenerator *owner) : QUICFrame(id, owner) @@ -1811,7 +1673,7 @@ QUICMaxStreamIdFrame::clone() const QUICFrameType QUICMaxStreamIdFrame::type() const { - return QUICFrameType::MAX_STREAM_ID; + return QUICFrameType::MAX_STREAMS; } size_t @@ -1833,7 +1695,7 @@ QUICMaxStreamIdFrame::store(uint8_t *buf, size_t *len, size_t limit) const size_t n; uint8_t *p = buf; - *p = static_cast(QUICFrameType::MAX_STREAM_ID); + *p = static_cast(QUICFrameType::MAX_STREAMS); ++p; QUICTypeUtil::write_QUICStreamId(this->_maximum_stream_id, p, &n); p += n; @@ -1892,7 +1754,7 @@ QUICBlockedFrame::clone() const QUICFrameType QUICBlockedFrame::type() const { - return QUICFrameType::BLOCKED; + return QUICFrameType::DATA_BLOCKED; } size_t @@ -1915,7 +1777,7 @@ QUICBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const size_t n; uint8_t *p = buf; - *p = static_cast(QUICFrameType::BLOCKED); + *p = static_cast(QUICFrameType::DATA_BLOCKED); ++p; QUICTypeUtil::write_QUICOffset(this->_offset, p, &n); p += n; @@ -1932,7 +1794,7 @@ QUICBlockedFrame::offset() const } // -// STREAM_BLOCKED frame +// STREAM_DATA_BLOCKED frame // QUICStreamBlockedFrame::QUICStreamBlockedFrame(const uint8_t *buf, size_t len) { @@ -1980,7 +1842,7 @@ QUICStreamBlockedFrame::clone() const QUICFrameType QUICStreamBlockedFrame::type() const { - return QUICFrameType::STREAM_BLOCKED; + return QUICFrameType::STREAM_DATA_BLOCKED; } size_t @@ -2002,7 +1864,7 @@ QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const size_t n; uint8_t *p = buf; - *p = static_cast(QUICFrameType::STREAM_BLOCKED); + *p = static_cast(QUICFrameType::STREAM_DATA_BLOCKED); ++p; QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); p += n; @@ -2027,7 +1889,7 @@ QUICStreamBlockedFrame::offset() const } // -// STREAM_ID_BLOCKED frame +// STREAMS_BLOCKED frame // QUICStreamIdBlockedFrame::QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len) { @@ -2070,7 +1932,7 @@ QUICStreamIdBlockedFrame::clone() const QUICFrameType QUICStreamIdBlockedFrame::type() const { - return QUICFrameType::STREAM_ID_BLOCKED; + return QUICFrameType::STREAMS_BLOCKED; } size_t @@ -2093,7 +1955,7 @@ QUICStreamIdBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const size_t n; uint8_t *p = buf; - *p = static_cast(QUICFrameType::STREAM_ID_BLOCKED); + *p = static_cast(QUICFrameType::STREAMS_BLOCKED); ++p; QUICTypeUtil::write_QUICStreamId(this->_stream_id, p, &n); p += n; @@ -2791,7 +2653,7 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicPaddingFrameAllocator.alloc(); new (frame) QUICPaddingFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_padding_frame); - case QUICFrameType::RST_STREAM: + case QUICFrameType::RESET_STREAM: frame = quicRstStreamFrameAllocator.alloc(); new (frame) QUICRstStreamFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_rst_stream_frame); @@ -2799,10 +2661,6 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicConnectionCloseFrameAllocator.alloc(); new (frame) QUICConnectionCloseFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_connection_close_frame); - case QUICFrameType::APPLICATION_CLOSE: - frame = quicApplicationCloseFrameAllocator.alloc(); - new (frame) QUICApplicationCloseFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_application_close_frame); case QUICFrameType::MAX_DATA: frame = quicMaxDataFrameAllocator.alloc(); new (frame) QUICMaxDataFrame(buf, len); @@ -2811,7 +2669,7 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicMaxStreamDataFrameAllocator.alloc(); new (frame) QUICMaxStreamDataFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); - case QUICFrameType::MAX_STREAM_ID: + case QUICFrameType::MAX_STREAMS: frame = quicMaxStreamIdFrameAllocator.alloc(); new (frame) QUICMaxStreamIdFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_max_stream_id_frame); @@ -2819,15 +2677,15 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) frame = quicPingFrameAllocator.alloc(); new (frame) QUICPingFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_ping_frame); - case QUICFrameType::BLOCKED: + case QUICFrameType::DATA_BLOCKED: frame = quicBlockedFrameAllocator.alloc(); new (frame) QUICBlockedFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_blocked_frame); - case QUICFrameType::STREAM_BLOCKED: + case QUICFrameType::STREAM_DATA_BLOCKED: frame = quicStreamBlockedFrameAllocator.alloc(); new (frame) QUICStreamBlockedFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); - case QUICFrameType::STREAM_ID_BLOCKED: + case QUICFrameType::STREAMS_BLOCKED: frame = quicStreamIdBlockedFrameAllocator.alloc(); new (frame) QUICStreamIdBlockedFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_id_blocked_frame); @@ -2942,26 +2800,6 @@ QUICFrameFactory::create_connection_close_frame(QUICConnectionError &error, QUIC } } -std::unique_ptr -QUICFrameFactory::create_application_close_frame(QUICAppErrorCode error_code, uint16_t reason_phrase_length, - const char *reason_phrase, QUICFrameId id, QUICFrameGenerator *owner) -{ - QUICApplicationCloseFrame *frame = quicApplicationCloseFrameAllocator.alloc(); - new (frame) QUICApplicationCloseFrame(error_code, reason_phrase_length, reason_phrase, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); -} - -std::unique_ptr -QUICFrameFactory::create_application_close_frame(QUICConnectionError &error, QUICFrameId id, QUICFrameGenerator *owner) -{ - ink_assert(error.cls == QUICErrorClass::APPLICATION); - if (error.msg) { - return QUICFrameFactory::create_application_close_frame(error.code, strlen(error.msg), error.msg, id, owner); - } else { - return QUICFrameFactory::create_application_close_frame(error.code, 0, nullptr, id, owner); - } -} - std::unique_ptr QUICFrameFactory::create_max_data_frame(uint64_t maximum_data, QUICFrameId id, QUICFrameGenerator *owner) { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 3291a6606a0..59af88e9759 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -283,7 +283,7 @@ class QUICAckFrame : public QUICFrame }; // -// RST_STREAM +// RESET_STREAM // class QUICRstStreamFrame : public QUICFrame @@ -379,36 +379,6 @@ class QUICConnectionCloseFrame : public QUICFrame const char *_reason_phrase = nullptr; }; -// -// APPLICATION_CLOSE -// - -class QUICApplicationCloseFrame : public QUICFrame -{ -public: - QUICApplicationCloseFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICApplicationCloseFrame(const uint8_t *buf, size_t len); - QUICApplicationCloseFrame(QUICAppErrorCode error_code, uint64_t reason_phrase_length, const char *reason_phrase, - QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - QUICFrameUPtr clone() const override; - virtual int debug_msg(char *msg, size_t msg_len) const override; - virtual QUICFrameType type() const override; - virtual size_t size() const override; - virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - virtual void parse(const uint8_t *buf, size_t len) override; - - QUICAppErrorCode error_code() const; - uint64_t reason_phrase_length() const; - const char *reason_phrase() const; - -private: - virtual void _reset() override; - - QUICAppErrorCode _error_code = 0; - uint64_t _reason_phrase_length = 0; - const char *_reason_phrase = nullptr; -}; - // // MAX_DATA // @@ -463,7 +433,7 @@ class QUICMaxStreamDataFrame : public QUICFrame }; // -// MAX_STREAM_ID +// MAX_STREAMS // class QUICMaxStreamIdFrame : public QUICFrame @@ -511,7 +481,7 @@ class QUICBlockedFrame : public QUICFrame }; // -// STREAM_BLOCKED +// STREAM_DATA_BLOCKED // class QUICStreamBlockedFrame : public QUICFrame @@ -539,7 +509,7 @@ class QUICStreamBlockedFrame : public QUICFrame }; // -// STREAM_ID_BLOCKED +// STREAMS_BLOCKED // class QUICStreamIdBlockedFrame : public QUICFrame { @@ -768,7 +738,6 @@ extern ClassAllocator quicAckFrameAllocator; extern ClassAllocator quicPaddingFrameAllocator; extern ClassAllocator quicRstStreamFrameAllocator; extern ClassAllocator quicConnectionCloseFrameAllocator; -extern ClassAllocator quicApplicationCloseFrameAllocator; extern ClassAllocator quicMaxDataFrameAllocator; extern ClassAllocator quicMaxStreamDataFrameAllocator; extern ClassAllocator quicMaxStreamIdFrameAllocator; @@ -836,13 +805,6 @@ class QUICFrameDeleter quicConnectionCloseFrameAllocator.free(static_cast(frame)); } - static void - delete_application_close_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicApplicationCloseFrameAllocator.free(static_cast(frame)); - } - static void delete_max_data_frame(QUICFrame *frame) { @@ -1006,15 +968,6 @@ class QUICFrameFactory static std::unique_ptr create_connection_close_frame( QUICConnectionError &error, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - /* - * Creates a APPLICATION_CLOSE frame. - */ - static std::unique_ptr create_application_close_frame( - QUICAppErrorCode error_code, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr, QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); - static std::unique_ptr create_application_close_frame( - QUICConnectionError &error, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - /* * Creates a MAX_DATA frame. */ @@ -1027,7 +980,7 @@ class QUICFrameFactory static std::unique_ptr create_max_stream_data_frame( QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* - * Creates a MAX_STREAM_ID frame. + * Creates a MAX_STREAMS frame. */ static std::unique_ptr create_max_stream_id_frame( QUICStreamId maximum_stream_id, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); @@ -1057,19 +1010,19 @@ class QUICFrameFactory QUICFrameGenerator *owner = nullptr); /* - * Creates a STREAM_BLOCKED frame. + * Creates a STREAM_DATA_BLOCKED frame. */ static std::unique_ptr create_stream_blocked_frame( QUICStreamId stream_id, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* - * Creates a STREAM_ID_BLOCKED frame. + * Creates a STREAMS_BLOCKED frame. */ static std::unique_ptr create_stream_id_blocked_frame( QUICStreamId stream_id, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* - * Creates a RST_STREAM frame. + * Creates a RESET_STREAM frame. */ static std::unique_ptr create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index 82308fcca5c..09c870e2383 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -122,7 +122,7 @@ QUICIncomingStreamFrameBuffer::_check_and_set_fin_flag(QUICOffset offset, size_t { // stream with fin flag {11.3. Stream Final Offset} // Once a final offset for a stream is known, it cannot change. - // If a RST_STREAM or STREAM frame causes the final offset to change for a stream, + // If a RESET_STREAM or STREAM frame causes the final offset to change for a stream, // an endpoint SHOULD respond with a FINAL_OFFSET_ERROR error (see Section 12). // A receiver SHOULD treat receipt of data at or beyond the final offset as a // FINAL_OFFSET_ERROR error, even after a stream is closed. diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 44f4ff60c35..79173eb3b25 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -45,16 +45,15 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) case QUICFrameType::ACK: case QUICFrameType::PATH_CHALLENGE: case QUICFrameType::PATH_RESPONSE: - case QUICFrameType::RST_STREAM: - case QUICFrameType::BLOCKED: - case QUICFrameType::STREAM_BLOCKED: + case QUICFrameType::RESET_STREAM: + case QUICFrameType::DATA_BLOCKED: + case QUICFrameType::STREAM_DATA_BLOCKED: case QUICFrameType::MAX_DATA: case QUICFrameType::MAX_STREAM_DATA: case QUICFrameType::NEW_TOKEN: case QUICFrameType::PING: case QUICFrameType::STOP_SENDING: case QUICFrameType::CONNECTION_CLOSE: - case QUICFrameType::APPLICATION_CLOSE: case QUICFrameType::STREAM: case QUICFrameType::CRYPTO: break; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 9edb646b8e1..0677c18173f 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -376,7 +376,7 @@ QUICStream::recv(const QUICMaxStreamDataFrame &frame) QUICConnectionErrorUPtr QUICStream::recv(const QUICStreamBlockedFrame &frame) { - // STREAM_BLOCKED frames are for debugging. Nothing to do here. + // STREAM_DATA_BLOCKED frames are for debugging. Nothing to do here. return nullptr; } @@ -415,7 +415,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit return frame; } - // RST_STREAM + // RESET_STREAM if (this->_reset_reason && !this->_is_reset_sent) { frame = QUICFrameFactory::create_rst_stream_frame(*this->_reset_reason, this->_issue_frame_id(), this); this->_records_rst_stream_frame(*static_cast(frame.get())); @@ -470,7 +470,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit // Check Connection/Stream level credit only if the generating STREAM frame is not pure fin uint64_t stream_credit = this->_remote_flow_controller.credit(); if (stream_credit == 0) { - // STREAM_BLOCKED + // STREAM_DATA_BLOCKED frame = this->_remote_flow_controller.generate_frame(level, UINT16_MAX, maximum_frame_size); return frame; } @@ -567,7 +567,7 @@ QUICStream::_on_frame_acked(QUICFrameInformationUPtr &info) { StreamFrameInfo *frame_info = nullptr; switch (info->type) { - case QUICFrameType::RST_STREAM: + case QUICFrameType::RESET_STREAM: this->_is_reset_complete = true; break; case QUICFrameType::STREAM: @@ -589,13 +589,13 @@ void QUICStream::_on_frame_lost(QUICFrameInformationUPtr &info) { switch (info->type) { - case QUICFrameType::RST_STREAM: + case QUICFrameType::RESET_STREAM: // [draft-16] 13.2. Retransmission of Information - // Cancellation of stream transmission, as carried in a RST_STREAM + // Cancellation of stream transmission, as carried in a RESET_STREAM // frame, is sent until acknowledged or until all stream data is // acknowledged by the peer (that is, either the "Reset Recvd" or // "Data Recvd" state is reached on the send stream). The content of - // a RST_STREAM frame MUST NOT change when it is sent again. + // a RESET_STREAM frame MUST NOT change when it is sent again. this->_is_reset_sent = false; break; case QUICFrameType::STREAM: diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 3cc9b6649a7..b12bf0aa355 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -48,8 +48,8 @@ std::vector QUICStreamManager::interests() { return { - QUICFrameType::STREAM, QUICFrameType::RST_STREAM, QUICFrameType::STOP_SENDING, - QUICFrameType::MAX_STREAM_DATA, QUICFrameType::MAX_STREAM_ID, + QUICFrameType::STREAM, QUICFrameType::RESET_STREAM, QUICFrameType::STOP_SENDING, + QUICFrameType::MAX_STREAM_DATA, QUICFrameType::MAX_STREAMS, }; } @@ -144,8 +144,8 @@ QUICStreamManager::handle_frame(QUICEncryptionLevel level, const QUICFrame &fram case QUICFrameType::MAX_STREAM_DATA: error = this->_handle_frame(static_cast(frame)); break; - case QUICFrameType::STREAM_BLOCKED: - // STREAM_BLOCKED frame is for debugging. Just propagate to streams + case QUICFrameType::STREAM_DATA_BLOCKED: + // STREAM_DATA_BLOCKED frame is for debugging. Just propagate to streams error = this->_handle_frame(static_cast(frame)); break; case QUICFrameType::STREAM: @@ -154,10 +154,10 @@ QUICStreamManager::handle_frame(QUICEncryptionLevel level, const QUICFrame &fram case QUICFrameType::STOP_SENDING: error = this->_handle_frame(static_cast(frame)); break; - case QUICFrameType::RST_STREAM: + case QUICFrameType::RESET_STREAM: error = this->_handle_frame(static_cast(frame)); break; - case QUICFrameType::MAX_STREAM_ID: + case QUICFrameType::MAX_STREAMS: error = this->_handle_frame(static_cast(frame)); break; default: diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index 4621dfa403a..a91e9f45323 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -46,8 +46,8 @@ QUICReceiveStreamState::is_allowed_to_send(QUICFrameType type) const // Return true or break out the switch to return false switch (this->get()) { case State::_Init: - if (type == QUICFrameType::STREAM || type == QUICFrameType::RST_STREAM || type == QUICFrameType::MAX_STREAM_DATA || - type == QUICFrameType::STREAM_BLOCKED) { + if (type == QUICFrameType::STREAM || type == QUICFrameType::RESET_STREAM || type == QUICFrameType::MAX_STREAM_DATA || + type == QUICFrameType::STREAM_DATA_BLOCKED) { return true; } break; @@ -74,7 +74,7 @@ QUICReceiveStreamState::is_allowed_to_send(QUICFrameType type) const } break; case State::DataRecvd: - if (type != QUICFrameType::STREAM && type != QUICFrameType::RST_STREAM && type != QUICFrameType::STREAM_BLOCKED) { + if (type != QUICFrameType::STREAM && type != QUICFrameType::RESET_STREAM && type != QUICFrameType::STREAM_DATA_BLOCKED) { return true; } break; @@ -84,10 +84,10 @@ QUICReceiveStreamState::is_allowed_to_send(QUICFrameType type) const } break; case State::ResetRecvd: - // It should not send any frame after receiving RST_STREAM + // It should not send any frame after receiving RESET_STREAM break; case State::ResetRead: - // It should not send any frame after receiving RST_STREAM + // It should not send any frame after receiving RESET_STREAM break; default: ink_assert(!"Unknown state"); @@ -109,8 +109,8 @@ QUICReceiveStreamState::is_allowed_to_receive(QUICFrameType type) const // Return true or break out the switch to return false switch (this->get()) { case State::_Init: - if (type == QUICFrameType::STREAM || type == QUICFrameType::RST_STREAM || type == QUICFrameType::MAX_STREAM_DATA || - type == QUICFrameType::STREAM_BLOCKED) { + if (type == QUICFrameType::STREAM || type == QUICFrameType::RESET_STREAM || type == QUICFrameType::MAX_STREAM_DATA || + type == QUICFrameType::STREAM_DATA_BLOCKED) { return true; } break; @@ -155,10 +155,10 @@ QUICReceiveStreamState::update_with_receiving_frame(const QUICFrame &frame) this->_set_state(State::DataRecvd); } } - } else if (frame.type() == QUICFrameType::RST_STREAM) { + } else if (frame.type() == QUICFrameType::RESET_STREAM) { this->_set_state(State::Recv); this->_set_state(State::ResetRecvd); - } else if (frame.type() == QUICFrameType::MAX_STREAM_DATA || frame.type() == QUICFrameType::STREAM_BLOCKED) { + } else if (frame.type() == QUICFrameType::MAX_STREAM_DATA || frame.type() == QUICFrameType::STREAM_DATA_BLOCKED) { this->_set_state(State::Recv); } else { this->_set_state(State::_Invalid); @@ -172,7 +172,7 @@ QUICReceiveStreamState::update_with_receiving_frame(const QUICFrame &frame) this->_set_state(State::DataRecvd); } } - } else if (frame.type() == QUICFrameType::RST_STREAM) { + } else if (frame.type() == QUICFrameType::RESET_STREAM) { this->_set_state(State::ResetRecvd); } break; @@ -181,12 +181,12 @@ QUICReceiveStreamState::update_with_receiving_frame(const QUICFrame &frame) if (this->_in_progress->transfer_progress() == this->_in_progress->transfer_goal()) { this->_set_state(State::DataRecvd); } - } else if (frame.type() == QUICFrameType::RST_STREAM) { + } else if (frame.type() == QUICFrameType::RESET_STREAM) { this->_set_state(State::ResetRecvd); } break; case State::DataRecvd: - if (frame.type() == QUICFrameType::RST_STREAM) { + if (frame.type() == QUICFrameType::RESET_STREAM) { this->_set_state(State::ResetRecvd); } break; @@ -253,17 +253,17 @@ QUICSendStreamState::is_allowed_to_send(QUICFrameType type) const case State::_Init: break; case State::Ready: - if (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_BLOCKED || type == QUICFrameType::RST_STREAM) { + if (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM) { return true; } break; case State::Send: - if (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_BLOCKED || type == QUICFrameType::RST_STREAM) { + if (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM) { return true; } break; case State::DataSent: - if (type == QUICFrameType::RST_STREAM) { + if (type == QUICFrameType::RESET_STREAM) { return true; } break; @@ -307,9 +307,9 @@ QUICSendStreamState::update_with_sending_frame(const QUICFrame &frame) if (static_cast(frame).has_fin_flag()) { this->_set_state(State::DataSent); } - } else if (frame.type() == QUICFrameType::STREAM_BLOCKED) { + } else if (frame.type() == QUICFrameType::STREAM_DATA_BLOCKED) { this->_set_state(State::Send); - } else if (frame.type() == QUICFrameType::RST_STREAM) { + } else if (frame.type() == QUICFrameType::RESET_STREAM) { this->_set_state(State::ResetSent); } break; @@ -318,12 +318,12 @@ QUICSendStreamState::update_with_sending_frame(const QUICFrame &frame) if (static_cast(frame).has_fin_flag()) { this->_set_state(State::DataSent); } - } else if (frame.type() == QUICFrameType::RST_STREAM) { + } else if (frame.type() == QUICFrameType::RESET_STREAM) { this->_set_state(State::ResetSent); } break; case State::DataSent: - if (frame.type() == QUICFrameType::RST_STREAM) { + if (frame.type() == QUICFrameType::RESET_STREAM) { this->_set_state(State::ResetSent); } break; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index c8e03c42dfe..c79bbebad43 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -94,26 +94,25 @@ enum class QUICPacketType : uint8_t { // XXX If you add or remove QUICFrameType, you might also need to change QUICFrame::type(const uint8_t *) enum class QUICFrameType : uint8_t { PADDING = 0x00, - RST_STREAM, - CONNECTION_CLOSE, - APPLICATION_CLOSE, - MAX_DATA, - MAX_STREAM_DATA, - MAX_STREAM_ID, PING, - BLOCKED, - STREAM_BLOCKED, - STREAM_ID_BLOCKED, - NEW_CONNECTION_ID, + ACK, // 0x02 - 0x03 + RESET_STREAM = 0x04, STOP_SENDING, + CRYPTO, + NEW_TOKEN, + STREAM, // 0x08 - 0x0f + MAX_DATA = 0x10, + MAX_STREAM_DATA, + MAX_STREAMS, // 0x12 - 0x13 + DATA_BLOCKED = 0x14, + STREAM_DATA_BLOCKED, + STREAMS_BLOCKED, // 0x16 - 0x17 + NEW_CONNECTION_ID = 0x18, RETIRE_CONNECTION_ID, PATH_CHALLENGE, PATH_RESPONSE, - STREAM = 0x10, // 0x10 - 0x17 - CRYPTO = 0x18, - NEW_TOKEN, - ACK, // 0x1a - 0x1b - UNKNOWN = 0x1c, + CONNECTION_CLOSE, // 0x1c - 0x1d + UNKNOWN = 0x1e, }; enum class QUICVersionNegotiationStatus { From b022e04949a3abe7f9ef498d8df5ed5562eecf05 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 7 Jan 2019 12:07:36 +0900 Subject: [PATCH 1009/1313] Update TP IDs and names --- iocore/net/quic/QUICDebugNames.cc | 8 ++++---- iocore/net/quic/QUICHandshake.cc | 8 ++++---- iocore/net/quic/QUICStreamManager.cc | 8 ++++---- iocore/net/quic/QUICTransportParameters.cc | 8 ++++---- iocore/net/quic/QUICTransportParameters.h | 18 +++++++++--------- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 9f0cc702639..cfeed61c04d 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -179,8 +179,8 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) return "INITIAL_MAX_STREAM_DATA_BIDI_LOCAL"; case QUICTransportParameterId::INITIAL_MAX_DATA: return "INITIAL_MAX_DATA"; - case QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS: - return "INITIAL_MAX_BIDI_STREAMS"; + case QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI: + return "INITIAL_MAX_STREAMS_BIDI"; case QUICTransportParameterId::IDLE_TIMEOUT: return "IDLE_TIMEOUT"; case QUICTransportParameterId::PREFERRED_ADDRESS: @@ -191,8 +191,8 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) return "STATELESS_RESET_TOKEN"; case QUICTransportParameterId::ACK_DELAY_EXPONENT: return "ACK_DELAY_EXPONENT"; - case QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS: - return "INITIAL_MAX_UNI_STREAMS"; + case QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI: + return "INITIAL_MAX_STREAMS_UNI"; case QUICTransportParameterId::DISABLE_MIGRATION: return "DISABLE_MIGRATION"; case QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE: diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 5912a7aae65..b3c96a87f80 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -377,10 +377,10 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data_in()); } if (params->initial_max_bidi_streams_in() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_in()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, params->initial_max_bidi_streams_in()); } if (params->initial_max_uni_streams_in() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_in()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, params->initial_max_uni_streams_in()); } if (params->initial_max_stream_data_bidi_local_in() != 0) { tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, params->initial_max_stream_data_bidi_local_in()); @@ -423,10 +423,10 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data_out()); } if (params->initial_max_bidi_streams_out() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, params->initial_max_bidi_streams_out()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, params->initial_max_bidi_streams_out()); } if (params->initial_max_uni_streams_out() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS, params->initial_max_uni_streams_out()); + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, params->initial_max_uni_streams_out()); } if (params->initial_max_stream_data_bidi_local_out() != 0) { tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, params->initial_max_stream_data_bidi_local_out()); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index b12bf0aa355..bf4186dfa12 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -61,12 +61,12 @@ QUICStreamManager::init_flow_control_params(const std::shared_ptr_remote_tp = remote_tp; if (this->_local_tp) { - this->_local_maximum_stream_id_bidi = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS); - this->_local_maximum_stream_id_uni = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS); + this->_local_maximum_stream_id_bidi = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI); + this->_local_maximum_stream_id_uni = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI); } if (this->_remote_tp) { - this->_remote_maximum_stream_id_bidi = this->_remote_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS); - this->_remote_maximum_stream_id_uni = this->_remote_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS); + this->_remote_maximum_stream_id_bidi = this->_remote_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI); + this->_remote_maximum_stream_id_uni = this->_remote_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI); } } diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index d2a713717b8..23e73b05b4d 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -156,15 +156,15 @@ QUICTransportParameters::_validate_parameters() const } } - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS)) != this->_parameters.end()) { + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI)) != this->_parameters.end()) { if (ite->second->len() != 2) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS); + return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI); } } - if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS)) != this->_parameters.end()) { + if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI)) != this->_parameters.end()) { if (ite->second->len() != 2) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_UNI_STREAMS); + return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI); } } diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index a9b4dcd719d..2ceef221b11 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -34,20 +34,20 @@ class QUICTransportParameterId { public: enum { - INITIAL_MAX_STREAM_DATA_BIDI_LOCAL = 0, - INITIAL_MAX_DATA, - INITIAL_MAX_BIDI_STREAMS, + ORIGINAL_CONNECTION_ID, IDLE_TIMEOUT, - PREFERRED_ADDRESS, - MAX_PACKET_SIZE, STATELESS_RESET_TOKEN, - ACK_DELAY_EXPONENT, - INITIAL_MAX_UNI_STREAMS, - DISABLE_MIGRATION, + MAX_PACKET_SIZE, + INITIAL_MAX_DATA, + INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, INITIAL_MAX_STREAM_DATA_UNI, + INITIAL_MAX_STREAMS_BIDI, + INITIAL_MAX_STREAMS_UNI, + ACK_DELAY_EXPONENT, MAX_ACK_DELAY, - ORIGINAL_CONNECTION_ID, + DISABLE_MIGRATION, + PREFERRED_ADDRESS, }; explicit operator bool() const { return true; } From 3761592bac1de213a1d5567400742bb91595819f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 7 Jan 2019 12:39:38 +0900 Subject: [PATCH 1010/1313] Read and write integer TPs as variable integers but not fixed size integers --- iocore/net/quic/QUICStreamManager.cc | 32 +++--- iocore/net/quic/QUICTransportParameters.cc | 108 ++++----------------- iocore/net/quic/QUICTransportParameters.h | 8 +- 3 files changed, 36 insertions(+), 112 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index bf4186dfa12..73becc3fff2 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -61,12 +61,12 @@ QUICStreamManager::init_flow_control_params(const std::shared_ptr_remote_tp = remote_tp; if (this->_local_tp) { - this->_local_maximum_stream_id_bidi = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI); - this->_local_maximum_stream_id_uni = this->_local_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI); + this->_local_maximum_stream_id_bidi = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI); + this->_local_maximum_stream_id_uni = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI); } if (this->_remote_tp) { - this->_remote_maximum_stream_id_bidi = this->_remote_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI); - this->_remote_maximum_stream_id_uni = this->_remote_tp->getAsUInt16(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI); + this->_remote_maximum_stream_id_bidi = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI); + this->_remote_maximum_stream_id_uni = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI); } } @@ -276,12 +276,12 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) if (this->_info->direction() == NET_VCONNECTION_OUT) { // client - local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); - remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); + local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); + remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); } else { // server - local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); - remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); + local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); + remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); } break; @@ -290,8 +290,8 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) return nullptr; } - local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); - remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); + local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); + remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); break; case QUICStreamType::SERVER_BIDI: @@ -301,12 +301,12 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) if (this->_info->direction() == NET_VCONNECTION_OUT) { // client - local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); - remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); + local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); + remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); } else { // server - local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); - remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); + local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); + remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); } break; @@ -315,8 +315,8 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) return nullptr; } - local_max_stream_data = this->_local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); - remote_max_stream_data = this->_remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); + local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); + remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); break; } diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 23e73b05b4d..75be850c1f7 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -35,8 +35,8 @@ static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; static constexpr char tag[] = "quic_handshake"; -static constexpr uint32_t TP_ERROR_LENGTH = 0x010000; -// static constexpr uint32_t TP_ERROR_VALUE = 0x020000; +static constexpr uint32_t TP_ERROR_LENGTH = 0x010000; +static constexpr uint32_t TP_ERROR_VALUE = 0x020000; // static constexpr uint32_t TP_ERROR_MUST_EXIST = 0x030000; static constexpr uint32_t TP_ERROR_MUST_NOT_EXIST = 0x040000; @@ -151,76 +151,43 @@ QUICTransportParameters::_validate_parameters() const // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_DATA)) != this->_parameters.end()) { - if (ite->second->len() != 4) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_DATA); - } } if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI)) != this->_parameters.end()) { - if (ite->second->len() != 2) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI); - } } if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI)) != this->_parameters.end()) { - if (ite->second->len() != 2) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI); - } } if ((ite = this->_parameters.find(QUICTransportParameterId::IDLE_TIMEOUT)) != this->_parameters.end()) { - if (ite->second->len() != 2) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::IDLE_TIMEOUT); - } } if ((ite = this->_parameters.find(QUICTransportParameterId::MAX_PACKET_SIZE)) != this->_parameters.end()) { - if (ite->second->len() != 2) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::MAX_PACKET_SIZE); - } if (QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) < 1200) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::MAX_PACKET_SIZE); + return -(TP_ERROR_VALUE | QUICTransportParameterId::MAX_PACKET_SIZE); } } if ((ite = this->_parameters.find(QUICTransportParameterId::ACK_DELAY_EXPONENT)) != this->_parameters.end()) { - if (ite->second->len() != 1) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::ACK_DELAY_EXPONENT); - } if (QUICIntUtil::read_nbytes_as_uint(ite->second->data(), ite->second->len()) > 20) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::ACK_DELAY_EXPONENT); + return -(TP_ERROR_VALUE | QUICTransportParameterId::ACK_DELAY_EXPONENT); } } // MAYs (initial values for the flow control on each type of stream) if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL)) != this->_parameters.end()) { - if (ite->second->len() != 4) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); - } } if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE)) != this->_parameters.end()) { - if (ite->second->len() != 4) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); - } } if ((ite = this->_parameters.find(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI)) != this->_parameters.end()) { - if (ite->second->len() != 4) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); - } } if ((ite = this->_parameters.find(QUICTransportParameterId::DISABLE_MIGRATION)) != this->_parameters.end()) { - if (ite->second->len() != 0) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::DISABLE_MIGRATION); - } } if ((ite = this->_parameters.find(QUICTransportParameterId::MAX_ACK_DELAY)) != this->_parameters.end()) { - if (ite->second->len() != 1) { - return -(TP_ERROR_LENGTH | QUICTransportParameterId::MAX_ACK_DELAY); - } } return 0; @@ -239,37 +206,16 @@ QUICTransportParameters::getAsBytes(QUICTransportParameterId tpid, uint16_t &len return nullptr; } -uint8_t -QUICTransportParameters::getAsUInt8(QUICTransportParameterId tpid) const -{ - uint16_t len = 0; - const uint8_t *value = this->getAsBytes(tpid, len); - if (value) { - return QUICIntUtil::read_nbytes_as_uint(value, 1); - } else { - return 0; - } -} - -uint16_t -QUICTransportParameters::getAsUInt16(QUICTransportParameterId tpid) const +uint64_t +QUICTransportParameters::getAsUInt(QUICTransportParameterId tpid) const { - uint16_t len = 0; - const uint8_t *value = this->getAsBytes(tpid, len); - if (value) { - return QUICIntUtil::read_nbytes_as_uint(value, 2); - } else { - return 0; - } -} - -uint32_t -QUICTransportParameters::getAsUInt32(QUICTransportParameterId tpid) const -{ - uint16_t len = 0; - const uint8_t *value = this->getAsBytes(tpid, len); - if (value) { - return QUICIntUtil::read_nbytes_as_uint(value, 4); + uint64_t int_value = 0; + size_t int_value_len = 0; + uint16_t raw_value_len = 0; + const uint8_t *raw_value = this->getAsBytes(tpid, raw_value_len); + if (raw_value) { + QUICVariableInt::decode(int_value, int_value_len, raw_value, raw_value_len); + return int_value; } else { return 0; } @@ -293,30 +239,12 @@ QUICTransportParameters::set(QUICTransportParameterId id, const uint8_t *value, } void -QUICTransportParameters::set(QUICTransportParameterId id, uint8_t value) -{ - uint8_t v[1]; - size_t n; - QUICIntUtil::write_uint_as_nbytes(value, 1, v, &n); - this->set(id, v, 1); -} - -void -QUICTransportParameters::set(QUICTransportParameterId id, uint16_t value) -{ - uint8_t v[2]; - size_t n; - QUICIntUtil::write_uint_as_nbytes(value, 2, v, &n); - this->set(id, v, 2); -} - -void -QUICTransportParameters::set(QUICTransportParameterId id, uint32_t value) +QUICTransportParameters::set(QUICTransportParameterId id, uint64_t value) { - uint8_t v[4]; + uint8_t v[8]; size_t n; - QUICIntUtil::write_uint_as_nbytes(value, 4, v, &n); - this->set(id, v, 4); + QUICIntUtil::write_QUICVariableInt(value, v, &n); + this->set(id, v, n); } void @@ -526,7 +454,7 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const // MAYs if ((ite = this->_parameters.find(QUICTransportParameterId::STATELESS_RESET_TOKEN)) != this->_parameters.end()) { - if (ite->second->len() != QUICStatelessResetToken::LEN) { + if (ite->second->len() != 16) { return -(TP_ERROR_LENGTH | QUICTransportParameterId::STATELESS_RESET_TOKEN); } } diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index 2ceef221b11..f9e2722866a 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -80,15 +80,11 @@ class QUICTransportParameters bool is_valid() const; const uint8_t *getAsBytes(QUICTransportParameterId id, uint16_t &len) const; - uint8_t getAsUInt8(QUICTransportParameterId id) const; - uint16_t getAsUInt16(QUICTransportParameterId id) const; - uint32_t getAsUInt32(QUICTransportParameterId id) const; + uint64_t getAsUInt(QUICTransportParameterId id) const; bool contains(QUICTransportParameterId id) const; void set(QUICTransportParameterId id, const uint8_t *value, uint16_t value_len); - void set(QUICTransportParameterId id, uint8_t value); - void set(QUICTransportParameterId id, uint16_t value); - void set(QUICTransportParameterId id, uint32_t value); + void set(QUICTransportParameterId id, uint64_t value); void store(uint8_t *buf, uint16_t *len) const; From 585c1e8b26f4af6fb43aeab93738c0f46a5a1a61 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 7 Jan 2019 18:07:15 +0900 Subject: [PATCH 1011/1313] Protect packet headers --- iocore/net/QUICNetVConnection.cc | 18 ++--- iocore/net/QUICPacketHandler.cc | 2 +- iocore/net/quic/QUICPacket.cc | 37 ++------- iocore/net/quic/QUICPacket.h | 2 - iocore/net/quic/QUICPacketHeaderProtector.cc | 78 ++++++++++++++++--- iocore/net/quic/QUICPacketHeaderProtector.h | 16 ++-- .../quic/QUICPacketHeaderProtector_openssl.cc | 26 +------ iocore/net/quic/QUICTLS_boringssl.cc | 17 ---- iocore/net/quic/QUICTypes.cc | 6 ++ iocore/net/quic/QUICTypes.h | 1 + 10 files changed, 97 insertions(+), 106 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 9cd1809090c..709c827a022 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1225,10 +1225,8 @@ QUICNetVConnection::_state_common_send_packet() udp_payload->fill(len); written += len; - // TODO: Avoid static function. We don't need to parse buffer again. Get packet number offset from packet. - QUICPacket::protect_packet_header( - buf, len, &this->_ph_protector, - (this->_peer_quic_connection_id == QUICConnectionId::ZERO()) ? 0 : this->_peer_quic_connection_id.length()); + int dcil = (this->_peer_quic_connection_id == QUICConnectionId::ZERO()) ? 0 : this->_peer_quic_connection_id.length(); + this->_ph_protector.protect(buf, len, dcil); QUICConDebug("[TX] %s packet #%" PRIu64 " size=%zu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), len); @@ -1613,14 +1611,14 @@ QUICNetVConnection::_init_flow_control_params(const std::shared_ptr_stream_manager->init_flow_control_params(local_tp, remote_tp); - uint32_t local_initial_max_data = 0; - uint32_t remote_initial_max_data = 0; + uint64_t local_initial_max_data = 0; + uint64_t remote_initial_max_data = 0; if (local_tp) { - local_initial_max_data = local_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_DATA); + local_initial_max_data = local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_DATA); this->_flow_control_buffer_size = local_initial_max_data; } if (remote_tp) { - remote_initial_max_data = remote_tp->getAsUInt32(QUICTransportParameterId::INITIAL_MAX_DATA); + remote_initial_max_data = remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_DATA); } this->_local_flow_controller->set_limit(local_initial_max_data); @@ -1806,8 +1804,8 @@ QUICNetVConnection::_complete_handshake_if_possible() // PN space doesn't matter but seems like this is the way to pick the LossDetector for 0-RTT and Short packet int index_for_1rtt = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ONE_RTT); - uint8_t ack_delay_exponent = - this->_handshake_handler->remote_transport_parameters()->getAsUInt8(QUICTransportParameterId::ACK_DELAY_EXPONENT); + uint64_t ack_delay_exponent = + this->_handshake_handler->remote_transport_parameters()->getAsUInt(QUICTransportParameterId::ACK_DELAY_EXPONENT); this->_loss_detector[index_for_1rtt]->update_ack_delay_exponent(ack_delay_exponent); this->_start_application(); diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 4153fabe215..32781913d17 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -81,7 +81,7 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo udp_payload->fill(udp_len); if (ph_protector) { - QUICPacket::protect_packet_header(reinterpret_cast(udp_payload->start()), udp_len, ph_protector, dcil); + ph_protector->protect(reinterpret_cast(udp_payload->start()), udp_len, dcil); } UDPPacket *udp_packet = new_UDPPacket(addr, 0, udp_payload); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 26b2acba26c..d4e36e2e9e3 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -515,8 +515,8 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const { size_t n; *len = 0; - buf[0] = 0x80; - buf[0] += static_cast(this->_type); + buf[0] = 0xC0; + buf[0] += static_cast(this->_type) << 4; if (this->_type == QUICPacketType::VERSION_NEGOTIATION) { buf[0] |= rand(); } @@ -573,6 +573,9 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const pn_len = 1; } + // 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; @@ -1020,36 +1023,6 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si return true; } -bool -QUICPacket::protect_packet_header(uint8_t *packet, size_t packet_len, const QUICPacketHeaderProtector *ph_protector, int dcil) -{ - uint8_t pn_offset = 0; - uint8_t pn_len = 4; - size_t sample_offset = 0; - constexpr int aead_expansion = 16; // Currently, AEAD expansion (which is probably AEAD tag) length is always 16 - QUICKeyPhase phase; - - if (QUICInvariants::is_long_header(packet)) { - QUICPacketType type; - QUICPacketLongHeader::type(type, packet, packet_len); - phase = QUICTypeUtil::key_phase(type); - QUICPacketLongHeader::packet_number_offset(pn_offset, packet, packet_len); - } else { - QUICPacketShortHeader::key_phase(phase, packet, packet_len); - QUICPacketShortHeader::packet_number_offset(pn_offset, packet, packet_len, dcil); - } - sample_offset = std::min(static_cast(pn_offset) + 4, packet_len - aead_expansion); - - uint8_t protected_pn[4] = {0}; - uint8_t protected_pn_len = 0; - pn_len = QUICTypeUtil::read_QUICPacketNumberLen(packet + pn_offset); - if (!ph_protector->protect(protected_pn, protected_pn_len, packet + pn_offset, pn_len, packet + sample_offset, phase)) { - return false; - } - memcpy(packet + pn_offset, protected_pn, pn_len); - return true; -} - // // QUICPacketFactory // diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 45fb79e49ce..82acf4b83d1 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -381,8 +381,6 @@ class QUICPacket : public QUICTrackablePacket 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); - static bool protect_packet_header(uint8_t *packet, size_t packet_len, const QUICPacketHeaderProtector *ph_protector, int dcil); - LINK(QUICPacket, link); private: diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc index 7bc8e839139..a7813685a49 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -28,26 +28,63 @@ #include "tscore/Diags.h" bool -QUICPacketHeaderProtector::protect(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, - uint8_t unprotected_pn_len, const uint8_t *sample, QUICKeyPhase phase) const +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; + } + } + + 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); + } else { + QUICPacketShortHeader::key_phase(phase, unprotected_packet, unprotected_packet_len); + type = QUICPacketType::PROTECTED; + } + + Debug("v_quic_pne", "Protecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), + QUICDebugNames::key_phase(phase)); + const QUIC_EVP_CIPHER *aead = this->_hs_protocol->cipher_for_hp(phase); + if (!aead) { + Debug("quic_pne", "Failed to encrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); + return false; + } const KeyMaterial *km = this->_hs_protocol->key_material_for_encryption(phase); if (!km) { + Debug("quic_pne", "Failed to encrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } - bool ret = - this->_encrypt_pn(protected_pn, protected_pn_len, unprotected_pn, unprotected_pn_len, sample, km->hp, km->hp_len, aead); - if (!ret) { + uint8_t sample_offset; + if (!this->_calc_sample_offset(&sample_offset, unprotected_packet, unprotected_packet_len)) { + Debug("v_quic_pne", "Failed to calculate a sample offset"); + return false; + } + + uint8_t mask[EVP_MAX_BLOCK_LENGTH]; + if (!this->_generate_mask(mask, unprotected_packet + sample_offset, km->hp, aead)) { + Debug("v_quic_pne", "Failed to generate a mask"); + return false; + } + + if (!this->_protect(unprotected_packet, unprotected_packet_len, mask)) { Debug("quic_pne", "Failed to encrypt a packet number"); } - return ret; + + return true; } bool -QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected_packet_len) +QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected_packet_len) const { // Do nothing if the packet is VN if (QUICInvariants::is_long_header(protected_packet)) { @@ -109,7 +146,7 @@ QUICPacketHeaderProtector::set_hs_protocol(const QUICHandshakeProtocol *hs_proto } bool -QUICPacketHeaderProtector::_calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len) +QUICPacketHeaderProtector::_calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len) const { uint8_t pn_offset = 0; uint8_t aead_expansion = 16; @@ -140,7 +177,7 @@ QUICPacketHeaderProtector::_calc_sample_offset(uint8_t *sample_offset, const uin } bool -QUICPacketHeaderProtector::_unprotect(uint8_t *protected_packet, size_t protected_packet_len, const uint8_t *mask) +QUICPacketHeaderProtector::_unprotect(uint8_t *protected_packet, size_t protected_packet_len, const uint8_t *mask) const { uint8_t pn_offset; @@ -160,3 +197,26 @@ QUICPacketHeaderProtector::_unprotect(uint8_t *protected_packet, size_t protecte return true; } + +bool +QUICPacketHeaderProtector::_protect(uint8_t *protected_packet, size_t protected_packet_len, const uint8_t *mask) const +{ + uint8_t pn_offset; + + uint8_t pn_length = QUICTypeUtil::read_QUICPacketNumberLen(protected_packet); + + // 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); + } else { + protected_packet[0] ^= mask[0] & 0x1f; + QUICPacketShortHeader::packet_number_offset(pn_offset, protected_packet, protected_packet_len, QUICConnectionId::SCID_LEN); + } + + for (int i = 0; i < pn_length; ++i) { + protected_packet[pn_offset + i] ^= mask[1 + i]; + } + + return true; +} diff --git a/iocore/net/quic/QUICPacketHeaderProtector.h b/iocore/net/quic/QUICPacketHeaderProtector.h index 1f388af1c31..d635418b912 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.h +++ b/iocore/net/quic/QUICPacketHeaderProtector.h @@ -30,10 +30,8 @@ class QUICPacketHeaderProtector { public: - bool unprotect(uint8_t *protected_packet, size_t protected_packet_len); - - bool protect(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, - const uint8_t *sample, QUICKeyPhase phase) const; + bool unprotect(uint8_t *protected_packet, size_t protected_packet_len) const; + bool protect(uint8_t *unprotected_packet, size_t unprotected_packet_len, int dcil) const; // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICCryptoInfoProvider or somethign instead. // For now it receives a CONST pointer so PacketNubmerProtector cannot bother handshake. @@ -42,12 +40,10 @@ class QUICPacketHeaderProtector private: const QUICHandshakeProtocol *_hs_protocol = nullptr; - bool _calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len); - - bool _generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *aead); + bool _calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len) const; - bool _unprotect(uint8_t *packet, size_t packet_len, const uint8_t *mask); + bool _generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *aead) const; - bool _encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, uint8_t unprotected_pn_len, - const uint8_t *sample, const uint8_t *key, size_t key_len, const QUIC_EVP_CIPHER *aead) const; + bool _unprotect(uint8_t *packet, size_t packet_len, const uint8_t *mask) const; + bool _protect(uint8_t *packet, size_t packet_len, const uint8_t *mask) const; }; diff --git a/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc b/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc index d88ede04c2d..13c318fa2d5 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc @@ -24,7 +24,7 @@ #include "QUICPacketHeaderProtector.h" bool -QUICPacketHeaderProtector::_generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *aead) +QUICPacketHeaderProtector::_generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *aead) const { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); @@ -44,27 +44,3 @@ QUICPacketHeaderProtector::_generate_mask(uint8_t *mask, const uint8_t *sample, return true; } - -bool -QUICPacketHeaderProtector::_encrypt_pn(uint8_t *protected_pn, uint8_t &protected_pn_len, const uint8_t *unprotected_pn, - uint8_t unprotected_pn_len, const uint8_t *sample, const uint8_t *key, size_t key_len, - const EVP_CIPHER *aead) const -{ - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); - int len = 0; - - if (!ctx || !EVP_EncryptInit_ex(ctx, aead, nullptr, key, sample)) { - return false; - } - if (!EVP_EncryptUpdate(ctx, protected_pn, &len, unprotected_pn, unprotected_pn_len)) { - return false; - } - protected_pn_len = len; - if (!EVP_EncryptFinal_ex(ctx, protected_pn + len, &len)) { - return false; - } - protected_pn_len += len; - EVP_CIPHER_CTX_free(ctx); - - return true; -} diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc index 159d0df2f1b..935ef4c7e7d 100644 --- a/iocore/net/quic/QUICTLS_boringssl.cc +++ b/iocore/net/quic/QUICTLS_boringssl.cc @@ -176,20 +176,3 @@ QUICTLS::_decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const return true; } - -bool -QUICTLS::_encrypt_pn(uint8_t *protected_pn, size_t &protected_pn_len, const uint8_t *unprotected_pn, size_t unprotected_pn_len, - const uint8_t *sample, const KeyMaterial &km, const EVP_AEAD *aead) -{ - { - ink_assert(!"not implemented"); - return false; - } - - bool QUICTLS::_decrypt_pn(uint8_t * protected_pn, size_t & protected_pn_len, const uint8_t *unprotected_pn, - size_t unprotected_pn_len, const uint8_t *sample, const KeyMaterial &km, const EVP_AEAD *aead) - { - { - ink_assert(!"not implemented"); - return false; - } diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 5c76a02455d..c5cabfb4a35 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -146,6 +146,12 @@ QUICTypeUtil::read_QUICPacketNumberLen(const uint8_t *buf) return (buf[0] & 0x03) + 1; } +void +QUICTypeUtil::write_QUICPacketNumberLen(int len, uint8_t *buf) +{ + buf[0] |= len - 1; +} + QUICPacketNumber QUICTypeUtil::read_QUICPacketNumber(const uint8_t *buf, int encoded_length) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index c79bbebad43..5894b1abce3 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -464,6 +464,7 @@ class QUICTypeUtil static uint64_t read_QUICMaxData(const uint8_t *buf); static void write_QUICConnectionId(QUICConnectionId connection_id, uint8_t *buf, size_t *len); + static void write_QUICPacketNumberLen(int len, uint8_t *buf); static void write_QUICPacketNumber(QUICPacketNumber packet_number, uint8_t n, uint8_t *buf, size_t *len); static void write_QUICVersion(QUICVersion version, uint8_t *buf, size_t *len); static void write_QUICStreamId(QUICStreamId stream_id, uint8_t *buf, size_t *len); From 702e3e8f26e9eb7c147cfaae8dfa22a9e3d385f5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 8 Jan 2019 16:12:00 +0900 Subject: [PATCH 1012/1313] Update short header and header protection --- iocore/net/quic/QUICPacket.cc | 10 ++++---- iocore/net/quic/QUICPacketHeaderProtector.cc | 27 ++++++++++---------- iocore/net/quic/QUICPacketHeaderProtector.h | 4 +-- iocore/net/quic/QUICTLS_openssl.cc | 10 ++++---- iocore/net/quic/QUICTypes.cc | 20 +-------------- 5 files changed, 26 insertions(+), 45 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index d4e36e2e9e3..170d485a60b 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -729,7 +729,7 @@ QUICPacketShortHeader::key_phase(QUICKeyPhase &phase, const uint8_t *packet, siz if (packet_len < 1) { return false; } - if (packet[0] & 0x40) { + if (packet[0] & 0x04) { phase = QUICKeyPhase::PHASE_1; } else { phase = QUICKeyPhase::PHASE_0; @@ -764,11 +764,10 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const { size_t n; *len = 0; - buf[0] = 0x00; + buf[0] = 0x40; if (this->_key_phase == QUICKeyPhase::PHASE_1) { - buf[0] += 0x40; + buf[0] |= 0x04; } - buf[0] += 0x30; *len += 1; if (this->_connection_id != QUICConnectionId::ZERO()) { @@ -780,8 +779,9 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const 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; + + QUICTypeUtil::write_QUICPacketNumberLen(n, buf); } // diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc index a7813685a49..20a278e63c1 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -45,7 +45,8 @@ QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotect QUICPacketLongHeader::key_phase(phase, unprotected_packet, unprotected_packet_len); QUICPacketLongHeader::type(type, unprotected_packet, unprotected_packet_len); } else { - QUICPacketShortHeader::key_phase(phase, unprotected_packet, unprotected_packet_len); + // 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; type = QUICPacketType::PROTECTED; } @@ -65,7 +66,7 @@ QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotect } uint8_t sample_offset; - if (!this->_calc_sample_offset(&sample_offset, unprotected_packet, unprotected_packet_len)) { + if (!this->_calc_sample_offset(&sample_offset, unprotected_packet, unprotected_packet_len, dcil)) { Debug("v_quic_pne", "Failed to calculate a sample offset"); return false; } @@ -76,7 +77,7 @@ QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotect return false; } - if (!this->_protect(unprotected_packet, unprotected_packet_len, mask)) { + if (!this->_protect(unprotected_packet, unprotected_packet_len, mask, dcil)) { Debug("quic_pne", "Failed to encrypt a packet number"); } @@ -101,7 +102,8 @@ QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected QUICPacketLongHeader::key_phase(phase, protected_packet, protected_packet_len); QUICPacketLongHeader::type(type, protected_packet, protected_packet_len); } else { - QUICPacketShortHeader::key_phase(phase, protected_packet, protected_packet_len); + // 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; type = QUICPacketType::PROTECTED; } @@ -121,7 +123,7 @@ QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected } uint8_t sample_offset; - if (!this->_calc_sample_offset(&sample_offset, protected_packet, protected_packet_len)) { + if (!this->_calc_sample_offset(&sample_offset, protected_packet, protected_packet_len, QUICConnectionId::SCID_LEN)) { Debug("v_quic_pne", "Failed to calculate a sample offset"); return false; } @@ -146,12 +148,9 @@ QUICPacketHeaderProtector::set_hs_protocol(const QUICHandshakeProtocol *hs_proto } bool -QUICPacketHeaderProtector::_calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len) const +QUICPacketHeaderProtector::_calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len, +int dcil) const { - uint8_t pn_offset = 0; - uint8_t aead_expansion = 16; - QUICKeyPhase phase; - if (QUICInvariants::is_long_header(protected_packet)) { uint8_t dcil; uint8_t scil; @@ -171,9 +170,9 @@ QUICPacketHeaderProtector::_calc_sample_offset(uint8_t *sample_offset, const uin *sample_offset += token_len + token_length_len; } } else { - QUICPacketShortHeader::key_phase(phase, protected_packet, protected_packet_len); + *sample_offset = 1 + dcil + 4; } - return std::min(static_cast(pn_offset) + 4, protected_packet_len - aead_expansion); + return sample_offset + 16 < protected_packet + protected_packet_len; } bool @@ -199,7 +198,7 @@ QUICPacketHeaderProtector::_unprotect(uint8_t *protected_packet, size_t protecte } bool -QUICPacketHeaderProtector::_protect(uint8_t *protected_packet, size_t protected_packet_len, const uint8_t *mask) const +QUICPacketHeaderProtector::_protect(uint8_t *protected_packet, size_t protected_packet_len, const uint8_t *mask, int dcil) const { uint8_t pn_offset; @@ -211,7 +210,7 @@ QUICPacketHeaderProtector::_protect(uint8_t *protected_packet, size_t protected_ QUICPacketLongHeader::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); + QUICPacketShortHeader::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.h b/iocore/net/quic/QUICPacketHeaderProtector.h index d635418b912..f98a2e65f3c 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.h +++ b/iocore/net/quic/QUICPacketHeaderProtector.h @@ -40,10 +40,10 @@ class QUICPacketHeaderProtector private: const QUICHandshakeProtocol *_hs_protocol = nullptr; - bool _calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len) const; + bool _calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len, int dcil) const; bool _generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *aead) const; bool _unprotect(uint8_t *packet, size_t packet_len, const uint8_t *mask) const; - bool _protect(uint8_t *packet, size_t packet_len, const uint8_t *mask) const; + bool _protect(uint8_t *packet, size_t packet_len, const uint8_t *mask, int dcil) const; }; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 46f958dfee5..bda64d92289 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -191,7 +191,7 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t phase = QUICKeyPhase::ZERO_RTT; cipher = this->_get_evp_aead(phase); km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); - this->_print_km("update - client", *km, secret, secret_len); + this->_print_km("update - client - 0rtt", *km, secret, secret_len); this->_client_pp->set_key(std::move(km), phase); break; case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: @@ -199,7 +199,7 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t phase = QUICKeyPhase::HANDSHAKE; cipher = this->_get_evp_aead(phase); km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); - this->_print_km("update - client", *km, secret, secret_len); + this->_print_km("update - client - handshake", *km, secret, secret_len); this->_client_pp->set_key(std::move(km), phase); break; case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: @@ -207,7 +207,7 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t phase = QUICKeyPhase::PHASE_0; cipher = this->_get_evp_aead(phase); km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); - this->_print_km("update - client", *km, secret, secret_len); + this->_print_km("update - client - 1rtt", *km, secret, secret_len); this->_client_pp->set_key(std::move(km), phase); break; case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC: @@ -215,7 +215,7 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t phase = QUICKeyPhase::HANDSHAKE; cipher = this->_get_evp_aead(phase); km = this->_keygen_for_server.regenerate(secret, secret_len, cipher, hkdf); - this->_print_km("update - server", *km, secret, secret_len); + this->_print_km("update - server - handshake", *km, secret, secret_len); this->_server_pp->set_key(std::move(km), phase); break; case SSL_KEY_SERVER_APPLICATION_TRAFFIC: @@ -223,7 +223,7 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t phase = QUICKeyPhase::PHASE_0; cipher = this->_get_evp_aead(phase); km = this->_keygen_for_server.regenerate(secret, secret_len, cipher, hkdf); - this->_print_km("update - server", *km, secret, secret_len); + this->_print_km("update - server - 1rtt", *km, secret, secret_len); this->_server_pp->set_key(std::move(km), phase); break; default: diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index c5cabfb4a35..a826f47c96d 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -155,16 +155,7 @@ QUICTypeUtil::write_QUICPacketNumberLen(int len, uint8_t *buf) QUICPacketNumber QUICTypeUtil::read_QUICPacketNumber(const uint8_t *buf, int encoded_length) { - uint64_t pn = QUICIntUtil::read_nbytes_as_uint(buf, encoded_length); - - // Remove length indicator - if (encoded_length == 1) { - pn &= 0x7F; - } else { - pn &= (0x3FFFFFFF >> ((4 - encoded_length) * 8)); - } - - return static_cast(pn); + return QUICIntUtil::read_nbytes_as_uint(buf, encoded_length); } QUICVersion @@ -214,15 +205,6 @@ void QUICTypeUtil::write_QUICPacketNumber(QUICPacketNumber packet_number, uint8_t n, uint8_t *buf, size_t *len) { uint64_t pn = static_cast(packet_number); - if (n == 1) { - // Do nothing - } else if (n == 2) { - pn |= 0x8000; - } else if (n == 4) { - pn |= 0xC0000000; - } else { - ink_assert(!"Encoded length must be 1, 2 or 4"); - } QUICIntUtil::write_uint_as_nbytes(static_cast(pn), n, buf, len); } From 0fbdd31904d50a90b053d4197ba6b5a284467add Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 8 Jan 2019 16:14:45 +0900 Subject: [PATCH 1013/1313] Update NEW_CONNECTION_ID frame --- iocore/net/quic/QUICFrame.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 9f546eff37a..8a5c4c217be 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1998,6 +1998,11 @@ QUICNewConnectionIdFrame::parse(const uint8_t *buf, size_t len) this->_reset(); uint8_t *pos = const_cast(buf) + 1; + size_t field_len = 0; + if (!read_varint(pos, LEFT_SPACE(pos), this->_sequence, field_len)) { + return; + } + if (LEFT_SPACE(pos) < 1) { return; } @@ -2005,11 +2010,6 @@ QUICNewConnectionIdFrame::parse(const uint8_t *buf, size_t len) size_t cid_len = *pos; pos += 1; - size_t field_len = 0; - if (!read_varint(pos, LEFT_SPACE(pos), this->_sequence, field_len)) { - return; - } - if (LEFT_SPACE(pos) < cid_len) { return; } @@ -2061,10 +2061,10 @@ QUICNewConnectionIdFrame::store(uint8_t *buf, size_t *len, size_t limit) const uint8_t *p = buf; *p = static_cast(QUICFrameType::NEW_CONNECTION_ID); ++p; - *p = this->_connection_id.length(); - p += 1; QUICIntUtil::write_QUICVariableInt(this->_sequence, p, &n); p += n; + *p = this->_connection_id.length(); + p += 1; QUICTypeUtil::write_QUICConnectionId(this->_connection_id, p, &n); p += n; memcpy(p, this->_stateless_reset_token.buf(), QUICStatelessResetToken::LEN); From 56d0e1d80ccc3e5a27dcfad257898cb52ee5c019 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 8 Jan 2019 16:36:17 +0900 Subject: [PATCH 1014/1313] Update ACK frame --- iocore/net/quic/QUICFrame.cc | 2 +- iocore/net/quic/QUICTypes.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 8a5c4c217be..17ab821838e 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -580,7 +580,7 @@ QUICAckFrame::parse(const uint8_t *buf, size_t len) ink_assert(len >= 1); this->_reset(); uint8_t *pos = const_cast(buf) + 1; - bool has_ecn = (buf[0] == 0x1b); + bool has_ecn = (buf[0] == ACK_WITH_ECN); size_t field_len = 0; if (!read_varint(pos, LEFT_SPACE(pos), this->_largest_acknowledged, field_len)) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 5894b1abce3..31fe659b5d2 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -95,7 +95,8 @@ enum class QUICPacketType : uint8_t { enum class QUICFrameType : uint8_t { PADDING = 0x00, PING, - ACK, // 0x02 - 0x03 + ACK, + ACK_WITH_ECN, RESET_STREAM = 0x04, STOP_SENDING, CRYPTO, From e9c299f63d19fc5638acf197c194fb67c2e526ab Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 9 Jan 2019 15:04:40 +0900 Subject: [PATCH 1015/1313] Fix a compile error on ACK frame --- iocore/net/quic/QUICFrame.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 17ab821838e..945d5c0956c 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -580,7 +580,7 @@ QUICAckFrame::parse(const uint8_t *buf, size_t len) ink_assert(len >= 1); this->_reset(); uint8_t *pos = const_cast(buf) + 1; - bool has_ecn = (buf[0] == ACK_WITH_ECN); + bool has_ecn = (buf[0] == static_cast(QUICFrameType::ACK_WITH_ECN)); size_t field_len = 0; if (!read_varint(pos, LEFT_SPACE(pos), this->_largest_acknowledged, field_len)) { From c4dda17c6e4076a39d361d7cb29263be2a20f591 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 9 Jan 2019 15:28:49 +0900 Subject: [PATCH 1016/1313] Probably fix packet number decoding issue --- iocore/net/quic/QUICPacket.cc | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 170d485a60b..7809e179b76 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -565,8 +565,10 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const size_t pn_len = 4; QUICPacket::encode_packet_number(pn, this->_packet_number, pn_len); - if (pn > 0x3FFF) { + if (pn > 0x7FFFFF) { pn_len = 4; + } else if (pn > 0x7FFF) { + pn_len = 3; } else if (pn > 0x7F) { pn_len = 2; } else { @@ -951,9 +953,11 @@ QUICPacket::calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base) uint64_t d = (num - base) * 2; uint8_t len = 0; - if (d > 0x3FFF) { + if (d > 0xFFFFFF) { len = 4; - } else if (d > 0x7F) { + } else if (d > 0xFFFF) { + len = 3; + } else if (d > 0xFF) { len = 2; } else { len = 1; @@ -970,19 +974,23 @@ QUICPacket::encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si uint64_t mask = 0; switch (len) { case 1: - mask = 0x7F; + mask = 0xFF; break; case 2: - mask = 0x3FFF; + mask = 0xFFFF; + break; + case 3: + mask = 0xFFFFFF; break; case 4: - mask = 0x3FFFFFFF; + mask = 0xFFFFFFFF; break; default: ink_assert(!"len must be 1, 2, or 4"); return false; } dst = src & mask; + return true; } @@ -994,16 +1002,16 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si uint64_t maximum_diff = 0; switch (len) { case 1: - maximum_diff = 0x80; + maximum_diff = 0x100; break; case 2: - maximum_diff = 0x4000; + maximum_diff = 0x10000; break; case 3: - maximum_diff = 0x400000; + maximum_diff = 0x1000000; break; case 4: - maximum_diff = 0x40000000; + maximum_diff = 0x100000000; break; default: ink_assert(!"len must be 1, 2, 3 or 4"); From dca4f5a84c03706e0e0b08f65d2199b4bbaa94f0 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 9 Jan 2019 16:04:37 +0900 Subject: [PATCH 1017/1313] Update CONNECTION_CLOSE frame --- iocore/net/quic/QUICFrame.cc | 48 +++++++++++++++++++++++++----------- iocore/net/quic/QUICFrame.h | 5 ++++ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 945d5c0956c..c78e8b6fcc4 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1239,6 +1239,7 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len, size_t limit) const QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase, QUICFrameId id, QUICFrameGenerator *owner) : QUICFrame(id, owner), + _type(0x1c), _error_code(error_code), _frame_type(frame_type), _reason_phrase_length(reason_phrase_length), @@ -1246,6 +1247,16 @@ QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, QUICFram { } +QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, uint64_t reason_phrase_length, + const char *reason_phrase, QUICFrameId id, QUICFrameGenerator *owner) + : QUICFrame(id, owner), + _type(0x1d), + _error_code(error_code), + _reason_phrase_length(reason_phrase_length), + _reason_phrase(reason_phrase) +{ +} + QUICConnectionCloseFrame::QUICConnectionCloseFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); @@ -1270,6 +1281,7 @@ QUICConnectionCloseFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); this->_reset(); + this->_type = buf[0]; uint8_t *pos = const_cast(buf) + 1; if (LEFT_SPACE(pos) < 2) { @@ -1281,20 +1293,23 @@ QUICConnectionCloseFrame::parse(const uint8_t *buf, size_t len) size_t field_len = 0; uint64_t field = 0; - if (!read_varint(pos, LEFT_SPACE(pos), field, field_len)) { - return; - } - this->_frame_type = static_cast(field); + if (this->_type == 0x1c) { + if (!read_varint(pos, LEFT_SPACE(pos), field, field_len)) { + return; + } + + this->_frame_type = static_cast(field); - /** - Frame Type Field Accessor + /** + Frame Type Field Accessor - PADDING frame in Frame Type field means frame type that triggered the error is unknown. - Return QUICFrameType::UNKNOWN when Frame Type field is PADDING (0x0). - */ - if (this->_frame_type == QUICFrameType::PADDING) { - this->_frame_type = QUICFrameType::UNKNOWN; + PADDING frame in Frame Type field means frame type that triggered the error is unknown. + Return QUICFrameType::UNKNOWN when Frame Type field is PADDING (0x0). + */ + if (this->_frame_type == QUICFrameType::PADDING) { + this->_frame_type = QUICFrameType::UNKNOWN; + } } if (!read_varint(pos, LEFT_SPACE(pos), this->_reason_phrase_length, field_len)) { @@ -1350,7 +1365,7 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const size_t n; uint8_t *p = buf; - *p = static_cast(QUICFrameType::CONNECTION_CLOSE); + *p = this->_type; ++p; // Error Code (16) @@ -1382,9 +1397,14 @@ QUICConnectionCloseFrame::store(uint8_t *buf, size_t *len, size_t limit) const int QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const { - int len = - snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=%s (0x%" PRIx16 ") frame=%s", this->size(), + int len; + if (this->_type == 0x1c) { + len = snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=%s (0x%" PRIx16 ") frame=%s", this->size(), QUICDebugNames::error_code(this->error_code()), this->error_code(), QUICDebugNames::frame_type(this->frame_type())); + } else { + // Application-specific error. It doesn't have a frame type and we don't know string representations of error codes. + len = snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=0x%" PRIx16 " ", this->size(), this->error_code()); + } if (this->reason_phrase_length() != 0 && this->reason_phrase() != nullptr) { memcpy(msg + len, " reason=", 8); diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 59af88e9759..c52687435e9 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -356,8 +356,12 @@ class QUICConnectionCloseFrame : public QUICFrame public: QUICConnectionCloseFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICConnectionCloseFrame(const uint8_t *buf, size_t len); + // Constructor for transport error codes QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + // Constructor for application protocol error codes + QUICConnectionCloseFrame(uint16_t error_code, uint64_t reason_phrase_length, const char *reason_phrase, + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -373,6 +377,7 @@ class QUICConnectionCloseFrame : public QUICFrame private: virtual void _reset() override; + uint8_t _type = 0; uint16_t _error_code; QUICFrameType _frame_type = QUICFrameType::UNKNOWN; uint64_t _reason_phrase_length = 0; From b8089ccd8ec623598426094882d94bd920f06e68 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 11 Jan 2019 17:27:52 +0900 Subject: [PATCH 1018/1313] Make unit tests compilable --- iocore/net/quic/Makefile.am | 8 + iocore/net/quic/Mock.h | 2 +- .../net/quic/test/test_QUICFlowController.cc | 6 +- iocore/net/quic/test/test_QUICFrame.cc | 139 ++---------- .../quic/test/test_QUICHandshakeProtocol.cc | 38 +--- iocore/net/quic/test/test_QUICPacket.cc | 7 - .../test/test_QUICPacketHeaderProtector.cc | 207 ++++++++++++++++++ iocore/net/quic/test/test_QUICStream.cc | 10 +- .../net/quic/test/test_QUICStreamManager.cc | 8 +- iocore/net/quic/test/test_QUICStreamState.cc | 50 ++--- .../quic/test/test_QUICTransportParameters.cc | 2 +- 11 files changed, 278 insertions(+), 199 deletions(-) create mode 100644 iocore/net/quic/test/test_QUICPacketHeaderProtector.cc diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index e24293317ea..268208fbcbb 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -98,6 +98,7 @@ check_PROGRAMS = \ test_QUICInvariants \ test_QUICKeyGenerator \ test_QUICPacket \ + test_QUICPacketHeaderProtector \ test_QUICPacketFactory \ test_QUICStream \ test_QUICStreamManager \ @@ -224,6 +225,13 @@ test_QUICPacketFactory_SOURCES = \ $(test_main_SOURCES) \ ./test/test_QUICPacketFactory.cc +test_QUICPacketHeaderProtector_CPPFLAGS = $(test_CPPFLAGS) +test_QUICPacketHeaderProtector_LDFLAGS = @AM_LDFLAGS@ +test_QUICPacketHeaderProtector_LDADD = $(test_LDADD) +test_QUICPacketHeaderProtector_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICPacketHeaderProtector.cc + test_QUICStream_CPPFLAGS = $(test_CPPFLAGS) test_QUICStream_LDFLAGS = @AM_LDFLAGS@ test_QUICStream_LDADD = $(test_LDADD) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index c60ef68742a..7037431d9cc 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -599,7 +599,7 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol } const QUIC_EVP_CIPHER * - cipher_for_pne(QUICKeyPhase phase) const override + cipher_for_hp(QUICKeyPhase phase) const override { return nullptr; } diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index c83ca9c783c..e84d2380043 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -150,7 +150,7 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") CHECK(ret != 0); QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024); CHECK(frame); - CHECK(frame->type() == QUICFrameType::BLOCKED); + CHECK(frame->type() == QUICFrameType::DATA_BLOCKED); // MAX_STREAM_DATA fc.forward_limit(2048); @@ -182,7 +182,7 @@ TEST_CASE("QUICFlowController_Remote_Connection_ZERO_Credit", "[quic]") // if there're anything to send QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024); CHECK(frame); - CHECK(frame->type() == QUICFrameType::BLOCKED); + CHECK(frame->type() == QUICFrameType::DATA_BLOCKED); // MAX_STREAM_DATA fc.forward_limit(2048); @@ -353,7 +353,7 @@ TEST_CASE("Frame retransmission", "[quic]") CHECK(static_cast(frame.get())->offset() == 2048); } - SECTION("STREAM_BLOCKED frame") + SECTION("STREAM_DATA_BLOCKED frame") { int ret = 0; QUICRemoteStreamFlowController fc(1024, 0); diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 408c41a485e..01f0d72c359 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -33,16 +33,15 @@ extern const ink_freelist_ops *freelist_class_ops; TEST_CASE("QUICFrame Type", "[quic]") { CHECK(QUICFrame::type(reinterpret_cast("\x00")) == QUICFrameType::PADDING); - CHECK(QUICFrame::type(reinterpret_cast("\x01")) == QUICFrameType::RST_STREAM); + CHECK(QUICFrame::type(reinterpret_cast("\x01")) == QUICFrameType::RESET_STREAM); CHECK(QUICFrame::type(reinterpret_cast("\x02")) == QUICFrameType::CONNECTION_CLOSE); - CHECK(QUICFrame::type(reinterpret_cast("\x03")) == QUICFrameType::APPLICATION_CLOSE); CHECK(QUICFrame::type(reinterpret_cast("\x04")) == QUICFrameType::MAX_DATA); CHECK(QUICFrame::type(reinterpret_cast("\x05")) == QUICFrameType::MAX_STREAM_DATA); - CHECK(QUICFrame::type(reinterpret_cast("\x06")) == QUICFrameType::MAX_STREAM_ID); + CHECK(QUICFrame::type(reinterpret_cast("\x06")) == QUICFrameType::MAX_STREAMS); CHECK(QUICFrame::type(reinterpret_cast("\x07")) == QUICFrameType::PING); - CHECK(QUICFrame::type(reinterpret_cast("\x08")) == QUICFrameType::BLOCKED); - CHECK(QUICFrame::type(reinterpret_cast("\x09")) == QUICFrameType::STREAM_BLOCKED); - CHECK(QUICFrame::type(reinterpret_cast("\x0a")) == QUICFrameType::STREAM_ID_BLOCKED); + CHECK(QUICFrame::type(reinterpret_cast("\x08")) == QUICFrameType::DATA_BLOCKED); + CHECK(QUICFrame::type(reinterpret_cast("\x09")) == QUICFrameType::STREAM_DATA_BLOCKED); + CHECK(QUICFrame::type(reinterpret_cast("\x0a")) == QUICFrameType::STREAMS_BLOCKED); CHECK(QUICFrame::type(reinterpret_cast("\x0b")) == QUICFrameType::NEW_CONNECTION_ID); CHECK(QUICFrame::type(reinterpret_cast("\x0c")) == QUICFrameType::STOP_SENDING); CHECK(QUICFrame::type(reinterpret_cast("\x0d")) == QUICFrameType::RETIRE_CONNECTION_ID); @@ -702,7 +701,7 @@ TEST_CASE("Store Ack Frame", "[quic]") } } -TEST_CASE("Load RST_STREAM Frame", "[quic]") +TEST_CASE("Load RESET_STREAM Frame", "[quic]") { SECTION("Load") { @@ -713,7 +712,7 @@ TEST_CASE("Load RST_STREAM Frame", "[quic]") 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::RST_STREAM); + CHECK(frame1->type() == QUICFrameType::RESET_STREAM); CHECK(frame1->size() == 15); std::shared_ptr rst_stream_frame1 = std::dynamic_pointer_cast(frame1); CHECK(rst_stream_frame1 != nullptr); @@ -730,12 +729,12 @@ TEST_CASE("Load RST_STREAM Frame", "[quic]") 0x00, 0x01, // Error Code }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::RST_STREAM); + CHECK(frame1->type() == QUICFrameType::RESET_STREAM); CHECK(frame1->valid() == false); } } -TEST_CASE("Store RST_STREAM Frame", "[quic]") +TEST_CASE("Store RESET_STREAM Frame", "[quic]") { uint8_t buf[65535]; size_t len; @@ -868,7 +867,7 @@ TEST_CASE("ConnectionClose Frame", "[quic]") std::dynamic_pointer_cast(frame); CHECK(conn_close_frame != nullptr); CHECK(conn_close_frame->error_code() == static_cast(QUICTransErrorCode::PROTOCOL_VIOLATION)); - CHECK(conn_close_frame->frame_type() == QUICFrameType::RST_STREAM); + CHECK(conn_close_frame->frame_type() == QUICFrameType::RESET_STREAM); CHECK(conn_close_frame->reason_phrase_length() == 0); } @@ -912,98 +911,6 @@ TEST_CASE("ConnectionClose Frame", "[quic]") } } -TEST_CASE("Load ApplicationClose Frame", "[quic]") -{ - SECTION("w/ reason phrase") - { - uint8_t buf1[] = { - 0x03, // Type - 0x00, 0x01, // Error Code - 0x05, // Reason Phrase Length - 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::APPLICATION_CLOSE); - CHECK(frame1->size() == 9); - - std::shared_ptr app_close_frame = - std::dynamic_pointer_cast(frame1); - CHECK(app_close_frame != nullptr); - CHECK(app_close_frame->error_code() == static_cast(0x01)); - CHECK(app_close_frame->reason_phrase_length() == 5); - CHECK(memcmp(app_close_frame->reason_phrase(), buf1 + 4, 5) == 0); - } - - SECTION("Bad Loading") - { - uint8_t buf1[] = { - 0x03, // Type - 0x00, 0x01, // Error Code - 0x05, // Reason Phrase Length - }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::APPLICATION_CLOSE); - CHECK(frame1->valid() == false); - } - - SECTION("w/o reason phrase") - { - uint8_t buf2[] = { - 0x03, // Type - 0x00, 0x01, // Error Code - 0x00, // Reason Phrase Length - }; - std::shared_ptr frame2 = QUICFrameFactory::create(buf2, sizeof(buf2)); - CHECK(frame2->type() == QUICFrameType::APPLICATION_CLOSE); - CHECK(frame2->size() == 4); - - std::shared_ptr app_close_frame = - std::dynamic_pointer_cast(frame2); - CHECK(app_close_frame != nullptr); - CHECK(app_close_frame->error_code() == static_cast(0x01)); - CHECK(app_close_frame->reason_phrase_length() == 0); - } -} - -TEST_CASE("Store ApplicationClose Frame", "[quic]") -{ - SECTION("w/ reason phrase") - { - uint8_t buf[32]; - size_t len; - - uint8_t expected1[] = { - 0x03, // Type - 0x00, 0x01, // Error Code - 0x05, // Reason Phrase Length - 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); - }; - QUICApplicationCloseFrame app_close_frame(static_cast(0x01), 5, "ABCDE"); - CHECK(app_close_frame.size() == 9); - - app_close_frame.store(buf, &len, 32); - CHECK(len == 9); - CHECK(memcmp(buf, expected1, len) == 0); - } - SECTION("w/o reason phrase") - { - uint8_t buf[32]; - size_t len; - - uint8_t expected2[] = { - 0x03, // Type - 0x00, 0x01, // Error Code - 0x00, // Reason Phrase Length - }; - QUICApplicationCloseFrame app_close_frame(static_cast(0x01), 0, nullptr); - CHECK(app_close_frame.size() == 4); - - app_close_frame.store(buf, &len, 32); - CHECK(len == 4); - CHECK(memcmp(buf, expected2, len) == 0); - } -} - TEST_CASE("Load MaxData Frame", "[quic]") { SECTION("Load") @@ -1106,7 +1013,7 @@ TEST_CASE("Load MaxStreamId Frame", "[quic]") 0x81, 0x02, 0x03, 0x04, // Stream ID }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::MAX_STREAM_ID); + CHECK(frame1->type() == QUICFrameType::MAX_STREAMS); CHECK(frame1->size() == 5); std::shared_ptr max_stream_id_frame = std::dynamic_pointer_cast(frame1); CHECK(max_stream_id_frame != nullptr); @@ -1118,7 +1025,7 @@ TEST_CASE("Load MaxStreamId Frame", "[quic]") 0x06, // Type }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::MAX_STREAM_ID); + CHECK(frame1->type() == QUICFrameType::MAX_STREAMS); CHECK(frame1->valid() == false); } } @@ -1149,7 +1056,7 @@ TEST_CASE("Load Blocked Frame", "[quic]") 0x07, // Offset }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::BLOCKED); + CHECK(frame1->type() == QUICFrameType::DATA_BLOCKED); CHECK(frame1->size() == 2); std::shared_ptr blocked_stream_frame = std::dynamic_pointer_cast(frame1); CHECK(blocked_stream_frame != nullptr); @@ -1162,7 +1069,7 @@ TEST_CASE("Load Blocked Frame", "[quic]") 0x08, // Type }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::BLOCKED); + CHECK(frame1->type() == QUICFrameType::DATA_BLOCKED); CHECK(frame1->valid() == false); } } @@ -1194,7 +1101,7 @@ TEST_CASE("Load StreamBlocked Frame", "[quic]") 0x07, // Offset }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::STREAM_BLOCKED); + CHECK(frame1->type() == QUICFrameType::STREAM_DATA_BLOCKED); CHECK(frame1->size() == 6); std::shared_ptr stream_blocked_frame = std::dynamic_pointer_cast(frame1); @@ -1210,7 +1117,7 @@ TEST_CASE("Load StreamBlocked Frame", "[quic]") 0x81, 0x02, 0x03, 0x04, // Stream ID }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::STREAM_BLOCKED); + CHECK(frame1->type() == QUICFrameType::STREAM_DATA_BLOCKED); CHECK(frame1->valid() == false); } } @@ -1242,7 +1149,7 @@ TEST_CASE("Load StreamIdBlocked Frame", "[quic]") 0x41, 0x02, // Stream ID }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::STREAM_ID_BLOCKED); + CHECK(frame1->type() == QUICFrameType::STREAMS_BLOCKED); CHECK(frame1->size() == 3); std::shared_ptr stream_id_blocked_frame = std::dynamic_pointer_cast(frame1); @@ -1256,7 +1163,7 @@ TEST_CASE("Load StreamIdBlocked Frame", "[quic]") 0x0a, // Type }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::STREAM_ID_BLOCKED); + CHECK(frame1->type() == QUICFrameType::STREAMS_BLOCKED); CHECK(frame1->valid() == false); } } @@ -1653,7 +1560,7 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", CHECK(memcmp(connection_close_frame2->reason_phrase(), "test", 4) == 0); } -TEST_CASE("QUICFrameFactory Create RST_STREAM with a QUICStreamError", "[quic]") +TEST_CASE("QUICFrameFactory Create RESET_STREAM with a QUICStreamError", "[quic]") { MockQUICRTTProvider mock_rtt; MockQUICConnection mock_connection; @@ -1758,7 +1665,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") CHECK(memcmp(buf, frame_buf, len) == 0); } - SECTION("RST_STREAM frame") + SECTION("RESET_STREAM frame") { uint8_t frame_buf[] = { 0x01, // Type @@ -1856,7 +1763,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") CHECK(memcmp(buf, frame_buf, len) == 0); } - SECTION("MAX_STREAM_ID frame") + SECTION("MAX_STREAMS frame") { uint8_t frame_buf[] = { 0x06, // Type @@ -1909,7 +1816,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") CHECK(memcmp(buf, frame_buf, len) == 0); } - SECTION("STREAM_BLOCKED frame") + SECTION("STREAM_DATA_BLOCKED frame") { uint8_t frame_buf[] = { 0x09, // Type @@ -1928,7 +1835,7 @@ TEST_CASE("Retransmit", "[quic][frame][retransmit]") CHECK(memcmp(buf, frame_buf, len) == 0); } - SECTION("STREAM_ID_BLOCKED frame") + SECTION("STREAMS_BLOCKED frame") { uint8_t frame_buf[] = { 0x0a, // Type diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 0c32eb8a82d..a4f51101ad7 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -34,6 +34,7 @@ #include // #include "Mock.h" +#include "QUICPacketHeaderProtector.h" #include "QUICTLS.h" // depends on size of cert @@ -389,30 +390,6 @@ TEST_CASE("QUICHandshakeProtocol") CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - QUICPacketHeaderProtector client_ph_protector; - QUICPacketHeaderProtector server_ph_protector; - - client_ph_protector.set_hs_protocol(client); - server_ph_protector.set_hs_protocol(server); - - uint8_t expected[] = {0x01, 0x02, 0x03, 0x04, 0x05}; - uint8_t sample[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; - uint8_t protected_pn[18], unprotected_pn[18]; - uint8_t protected_pn_len = 0, unprotected_pn_len = 0; - - // ## Client -> Server - client_ph_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); - server_ph_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, - QUICKeyPhase::INITIAL); - CHECK(unprotected_pn_len == sizeof(expected)); - CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); - // ## Server -> Client - server_ph_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::INITIAL); - client_ph_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, - QUICKeyPhase::INITIAL); - CHECK(unprotected_pn_len == sizeof(expected)); - CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); - // # Start Handshake // CH @@ -488,19 +465,6 @@ TEST_CASE("QUICHandshakeProtocol") // # End Handshake - // ## Client -> Server - client_ph_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); - server_ph_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, - QUICKeyPhase::PHASE_0); - CHECK(unprotected_pn_len == sizeof(expected)); - CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); - // ## Server -> Client - server_ph_protector.protect(protected_pn, protected_pn_len, expected, sizeof(expected), sample, QUICKeyPhase::PHASE_0); - client_ph_protector.unprotect(unprotected_pn, unprotected_pn_len, protected_pn, protected_pn_len, sample, - QUICKeyPhase::PHASE_0); - CHECK(unprotected_pn_len == sizeof(expected)); - CHECK(memcmp(unprotected_pn, expected, sizeof(expected)) == 0); - // Teardown delete client; delete server; diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index f6e1c1f9f89..143e96f756b 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -50,7 +50,6 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") CHECK((header->source_cid() == QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8))); CHECK(header->has_version() == true); CHECK(header->version() == 0x00000000); - CHECK(header->has_key_phase() == false); } SECTION("Long Header (load) INITIAL Packet") @@ -79,7 +78,6 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") CHECK(header->packet_number() == 0x01234567); CHECK(header->has_version() == true); CHECK(header->version() == 0x11223344); - CHECK(header->has_key_phase() == false); } SECTION("Long Header (load) RETRY Packet") @@ -115,7 +113,6 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") CHECK(memcmp(header->payload(), retry_token, 16) == 0); CHECK(header->has_version() == true); CHECK(header->version() == 0x11223344); - CHECK(header->has_key_phase() == false); } SECTION("Long Header (store) INITIAL Packet") @@ -142,7 +139,6 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x01234567, 0, 0x11223344, std::move(payload), 5); CHECK(header->size() == sizeof(expected) - 5); - CHECK(header->has_key_phase() == false); CHECK(header->packet_size() == sizeof(expected)); CHECK(header->type() == QUICPacketType::INITIAL); CHECK( @@ -183,7 +179,6 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") {reinterpret_cast("\x08\x07\x06\x05\x04\x03\x02\x01"), 8}, std::move(payload), 16); CHECK(header->size() == sizeof(expected) - 16); - CHECK(header->has_key_phase() == false); CHECK(header->packet_size() == sizeof(expected)); CHECK(header->type() == QUICPacketType::RETRY); CHECK( @@ -228,7 +223,6 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") QUICPacketHeaderUPtr header = QUICPacketHeader::load({}, std::move(uinput), sizeof(input), 0); CHECK(header->size() == 23); CHECK(header->packet_size() == 25); - CHECK(header->has_key_phase() == true); CHECK(header->key_phase() == QUICKeyPhase::PHASE_0); CHECK(header->destination_cid() == dcid); CHECK(header->packet_number() == 0x01234567); @@ -259,7 +253,6 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") CHECK(header->size() == 23); CHECK(header->packet_size() == 0); - CHECK(header->has_key_phase() == true); CHECK(header->key_phase() == QUICKeyPhase::PHASE_0); CHECK(header->type() == QUICPacketType::PROTECTED); CHECK(header->destination_cid() == dcid); diff --git a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc new file mode 100644 index 00000000000..e479c48f3e1 --- /dev/null +++ b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc @@ -0,0 +1,207 @@ +/** @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 "catch.hpp" + +#include "QUICPacketHeaderProtector.h" +#include "QUICTLS.h" + +// depends on size of cert +static constexpr uint32_t MAX_HANDSHAKE_MSG_LEN = 8192; + +#include "./server_cert.h" + +TEST_CASE("QUICPacketHeaderProtector") +{ + // Client + SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +#ifdef SSL_MODE_QUIC_HACK + SSL_CTX_set_mode(client_ssl_ctx, SSL_MODE_QUIC_HACK); +#endif + + // Server + SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); + SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); + SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +#ifdef SSL_MODE_QUIC_HACK + SSL_CTX_set_mode(server_ssl_ctx, SSL_MODE_QUIC_HACK); +#endif + BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); + X509 *x509 = PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr); + SSL_CTX_use_certificate(server_ssl_ctx, x509); + BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); + EVP_PKEY *pkey = PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr); + SSL_CTX_use_PrivateKey(server_ssl_ctx, pkey); + + SECTION("Long header", "[quic]") + { + uint8_t original[] = { + 0xC0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + }; + uint8_t tmp[48]; + memcpy(tmp, original, sizeof(tmp)); + + QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); + QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); + + CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + + QUICPacketHeaderProtector client_ph_protector; + QUICPacketHeaderProtector server_ph_protector; + + client_ph_protector.set_hs_protocol(client); + server_ph_protector.set_hs_protocol(server); + + // ## Client -> Server + client_ph_protector.protect(tmp, sizeof(tmp), 18); + CHECK(memcmp(original, tmp, sizeof(original)) != 0); + server_ph_protector.unprotect(tmp, sizeof(tmp)); + CHECK(memcmp(original, tmp, sizeof(original)) == 0); + // ## Server -> Client + server_ph_protector.protect(tmp, sizeof(tmp), 18); + CHECK(memcmp(original, tmp, sizeof(original)) != 0); + client_ph_protector.unprotect(tmp, sizeof(tmp)); + CHECK(memcmp(original, tmp, sizeof(original)) == 0); + } + + SECTION("Short header", "[quic]") + { + uint8_t original[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + }; + uint8_t tmp[48]; + memcpy(tmp, original, sizeof(tmp)); + + QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); + QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); + + CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); + + QUICPacketHeaderProtector client_ph_protector; + QUICPacketHeaderProtector server_ph_protector; + + client_ph_protector.set_hs_protocol(client); + server_ph_protector.set_hs_protocol(server); + + + // Handshake + // CH + QUICHandshakeMsgs msg1; + uint8_t msg1_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg1.buf = msg1_buf; + msg1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + REQUIRE(client->handshake(&msg1, nullptr) == 1); + + // SH, EE, CERT, CV, FIN + QUICHandshakeMsgs msg2; + uint8_t msg2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2.buf = msg2_buf; + msg2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + REQUIRE(server->handshake(&msg2, &msg1) == 1); + + // FIN + QUICHandshakeMsgs msg3; + uint8_t msg3_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg3.buf = msg3_buf; + msg3.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + +#ifdef SSL_MODE_QUIC_HACK + // -- Hacks for OpenSSL with SSL_MODE_QUIC_HACK -- + // SH + QUICHandshakeMsgs msg2_1; + uint8_t msg2_1_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2_1.buf = msg2_1_buf; + msg2_1.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + memcpy(msg2_1.buf, msg2.buf, msg2.offsets[1]); + msg2_1.offsets[0] = 0; + msg2_1.offsets[1] = msg2.offsets[1]; + msg2_1.offsets[2] = msg2.offsets[1]; + msg2_1.offsets[3] = msg2.offsets[1]; + msg2_1.offsets[4] = msg2.offsets[1]; + + // EE - FIN + QUICHandshakeMsgs msg2_2; + uint8_t msg2_2_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg2_2.buf = msg2_2_buf; + msg2_2.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + size_t len = msg2.offsets[3] - msg2.offsets[2]; + memcpy(msg2_2.buf, msg2.buf + msg2.offsets[1], len); + msg2_2.offsets[0] = 0; + msg2_2.offsets[1] = 0; + msg2_2.offsets[2] = 0; + msg2_2.offsets[3] = len; + msg2_2.offsets[4] = len; + + REQUIRE(client->handshake(&msg3, &msg2_1) == 1); + REQUIRE(client->handshake(&msg3, &msg2_2) == 1); +#else + REQUIRE(client->handshake(&msg3, &msg2) == 1); +#endif + + // NS + QUICHandshakeMsgs msg4; + uint8_t msg4_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg4.buf = msg4_buf; + msg4.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + + REQUIRE(server->handshake(&msg4, &msg3) == 1); + + QUICHandshakeMsgs msg5; + uint8_t msg5_buf[MAX_HANDSHAKE_MSG_LEN] = {0}; + msg5.buf = msg5_buf; + msg5.max_buf_len = MAX_HANDSHAKE_MSG_LEN; + REQUIRE(client->handshake(&msg5, &msg4) == 1); + + + // ## Client -> Server + client_ph_protector.protect(tmp, sizeof(tmp), 18); + CHECK(memcmp(original, tmp, sizeof(original)) != 0); + server_ph_protector.unprotect(tmp, sizeof(tmp)); + CHECK(memcmp(original, tmp, sizeof(original)) == 0); + // ## Server -> Client + server_ph_protector.protect(tmp, sizeof(tmp), 18); + CHECK(memcmp(original, tmp, sizeof(original)) != 0); + client_ph_protector.unprotect(tmp, sizeof(tmp)); + CHECK(memcmp(original, tmp, sizeof(original)) == 0); + } +} diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 776b78625ba..c36e460cddc 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -253,7 +253,7 @@ TEST_CASE("QUICStream", "[quic]") CHECK(stream->will_generate_frame(level) == true); frame = stream->generate_frame(level, 4096, 4096); CHECK(frame); - CHECK(frame->type() == QUICFrameType::STREAM_BLOCKED); + CHECK(frame->type() == QUICFrameType::STREAM_DATA_BLOCKED); CHECK(stream->will_generate_frame(level) == true); // Update window @@ -280,7 +280,7 @@ TEST_CASE("QUICStream", "[quic]") stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame(level) == true); frame = stream->generate_frame(level, 4096, 4096); - CHECK(frame->type() == QUICFrameType::STREAM_BLOCKED); + CHECK(frame->type() == QUICFrameType::STREAM_DATA_BLOCKED); // Update window stream->recv(*std::make_shared(stream_id, 6144)); @@ -338,7 +338,7 @@ TEST_CASE("QUICStream", "[quic]") } */ - SECTION("Retransmit RST_STREAM frame") + SECTION("Retransmit RESET_STREAM frame") { MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); @@ -357,7 +357,7 @@ TEST_CASE("QUICStream", "[quic]") stream->reset(QUICStreamErrorUPtr(new QUICStreamError(stream.get(), QUIC_APP_ERROR_CODE_STOPPING))); frame = stream->generate_frame(level, 4096, 4096); REQUIRE(frame); - CHECK(frame->type() == QUICFrameType::RST_STREAM); + CHECK(frame->type() == QUICFrameType::RESET_STREAM); // Don't send it again untill it is considers as lost CHECK(stream->generate_frame(level, 4096, 4096) == nullptr); // Loss the frame @@ -365,7 +365,7 @@ TEST_CASE("QUICStream", "[quic]") // After the loss the frame should be regenerated frame = stream->generate_frame(level, 4096, 4096); REQUIRE(frame); - CHECK(frame->type() == QUICFrameType::RST_STREAM); + CHECK(frame->type() == QUICFrameType::RESET_STREAM); } SECTION("Retransmit STOP_SENDING frame") diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index c5a72b3cf0e..e355cbce60c 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -77,7 +77,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") sm.handle_frame(level, *stream_frame_4); CHECK(sm.stream_count() == 2); - // RST_STREAM frames create new streams + // RESET_STREAM frames create new streams std::shared_ptr rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(8, static_cast(0x01), 0); sm.handle_frame(level, *rst_stream_frame); @@ -88,7 +88,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") sm.handle_frame(level, *max_stream_data_frame); CHECK(sm.stream_count() == 4); - // STREAM_BLOCKED frames create new streams + // STREAM_DATA_BLOCKED frames create new streams std::shared_ptr stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0x10, 0); sm.handle_frame(level, *stream_blocked_frame); CHECK(sm.stream_count() == 5); @@ -166,7 +166,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") sm.init_flow_control_params(local_tp, remote_tp); - // Create a stream with STREAM_BLOCKED (== noop) + // Create a stream with STREAM_DATA_BLOCKED (== noop) std::shared_ptr stream_blocked_frame_0 = QUICFrameFactory::create_stream_blocked_frame(0, 0); std::shared_ptr stream_blocked_frame_1 = QUICFrameFactory::create_stream_blocked_frame(4, 0); sm.handle_frame(level, *stream_blocked_frame_0); @@ -217,7 +217,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") sm.init_flow_control_params(local_tp, remote_tp); - // Create a stream with STREAM_BLOCKED (== noop) + // Create a stream with STREAM_DATA_BLOCKED (== noop) Ptr block_3 = make_ptr(new_IOBufferBlock()); block_3->alloc(); block_3->fill(3); diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index 79a22d70407..985d7e7ba70 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -54,8 +54,8 @@ TEST_CASE("QUICSendStreamState", "[quic]") ss.update_with_sending_frame(*stream_frame); CHECK(ss.get() == QUICStreamState::State::Send); - // Case3. Send STREAM_BLOCKED - CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_BLOCKED)); + // Case3. Send STREAM_DATA_BLOCKED + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_DATA_BLOCKED)); ss.update_with_sending_frame(*stream_blocked_frame); CHECK(ss.get() == QUICStreamState::State::Send); @@ -79,8 +79,8 @@ TEST_CASE("QUICSendStreamState", "[quic]") QUICSendStreamState ss(nullptr, &pp); CHECK(ss.get() == QUICStreamState::State::Ready); - // Case2. Send STREAM_BLOCKED - CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_BLOCKED)); + // Case2. Send STREAM_DATA_BLOCKED + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_DATA_BLOCKED)); ss.update_with_sending_frame(*stream_blocked_frame); CHECK(ss.get() == QUICStreamState::State::Send); } @@ -93,8 +93,8 @@ TEST_CASE("QUICSendStreamState", "[quic]") QUICSendStreamState ss(nullptr, &pp); CHECK(ss.get() == QUICStreamState::State::Ready); - // Case2. Send RST_STREAM - CHECK(ss.is_allowed_to_send(QUICFrameType::RST_STREAM)); + // Case2. Send RESET_STREAM + CHECK(ss.is_allowed_to_send(QUICFrameType::RESET_STREAM)); ss.update_with_sending_frame(*rst_stream_frame); CHECK(ss.get() == QUICStreamState::State::ResetSent); @@ -102,7 +102,7 @@ TEST_CASE("QUICSendStreamState", "[quic]") ss.update_on_ack(); CHECK(ss.get() == QUICStreamState::State::ResetSent); - // Case4. Receive ACK for RST_STREAM + // Case4. Receive ACK for RESET_STREAM pp.set_cancelled(true); ss.update_on_ack(); CHECK(ss.get() == QUICStreamState::State::ResetRecvd); @@ -119,8 +119,8 @@ TEST_CASE("QUICSendStreamState", "[quic]") ss.update_with_sending_frame(*stream_frame); CHECK(ss.get() == QUICStreamState::State::Send); - // Case3. Send RST_STREAM - CHECK(ss.is_allowed_to_send(QUICFrameType::RST_STREAM)); + // Case3. Send RESET_STREAM + CHECK(ss.is_allowed_to_send(QUICFrameType::RESET_STREAM)); ss.update_with_sending_frame(*rst_stream_frame); CHECK(ss.get() == QUICStreamState::State::ResetSent); @@ -128,7 +128,7 @@ TEST_CASE("QUICSendStreamState", "[quic]") ss.update_on_ack(); CHECK(ss.get() == QUICStreamState::State::ResetSent); - // Case5. Receive ACK for RST_STREAM + // Case5. Receive ACK for RESET_STREAM pp.set_cancelled(true); ss.update_on_ack(); CHECK(ss.get() == QUICStreamState::State::ResetRecvd); @@ -145,8 +145,8 @@ TEST_CASE("QUICSendStreamState", "[quic]") ss.update_with_sending_frame(*stream_frame); CHECK(ss.get() == QUICStreamState::State::Send); - // Case3. Send STREAM_BLOCKED - CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_BLOCKED)); + // Case3. Send STREAM_DATA_BLOCKED + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_DATA_BLOCKED)); ss.update_with_sending_frame(*stream_blocked_frame); CHECK(ss.get() == QUICStreamState::State::Send); @@ -158,8 +158,8 @@ TEST_CASE("QUICSendStreamState", "[quic]") // Case4. STREAM is not allowed to send CHECK(!ss.is_allowed_to_send(QUICFrameType::STREAM)); - // Case4. Send RST_STREAM - CHECK(ss.is_allowed_to_send(QUICFrameType::RST_STREAM)); + // Case4. Send RESET_STREAM + CHECK(ss.is_allowed_to_send(QUICFrameType::RESET_STREAM)); ss.update_with_sending_frame(*rst_stream_frame); CHECK(ss.get() == QUICStreamState::State::ResetSent); @@ -167,7 +167,7 @@ TEST_CASE("QUICSendStreamState", "[quic]") ss.update_on_ack(); CHECK(ss.get() == QUICStreamState::State::ResetSent); - // Case6. Receive ACK for RST_STREAM + // Case6. Receive ACK for RESET_STREAM pp.set_cancelled(true); ss.update_on_ack(); CHECK(ss.get() == QUICStreamState::State::ResetRecvd); @@ -199,8 +199,8 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") ss.update_with_receiving_frame(*stream_frame); CHECK(ss.get() == QUICStreamState::State::Recv); - // Case2. Recv STREAM_BLOCKED - CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM_BLOCKED)); + // Case2. Recv STREAM_DATA_BLOCKED + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM_DATA_BLOCKED)); ss.update_with_receiving_frame(*stream_blocked_frame); CHECK(ss.get() == QUICStreamState::State::Recv); @@ -232,8 +232,8 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") ss.update_with_receiving_frame(*stream_frame); CHECK(ss.get() == QUICStreamState::State::Recv); - // Case2. Recv RST_STREAM - CHECK(ss.is_allowed_to_receive(QUICFrameType::RST_STREAM)); + // Case2. Recv RESET_STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); ss.update_with_receiving_frame(*rst_stream_frame); CHECK(ss.get() == QUICStreamState::State::ResetRecvd); @@ -257,8 +257,8 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") ss.update_with_receiving_frame(*stream_frame_with_fin); CHECK(ss.get() == QUICStreamState::State::SizeKnown); - // Case3. Recv RST_STREAM - CHECK(ss.is_allowed_to_receive(QUICFrameType::RST_STREAM)); + // Case3. Recv RESET_STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); ss.update_with_receiving_frame(*rst_stream_frame); CHECK(ss.get() == QUICStreamState::State::ResetRecvd); } @@ -286,8 +286,8 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") ss.update_with_receiving_frame(*stream_frame_delayed); CHECK(ss.get() == QUICStreamState::State::DataRecvd); - // Case4. Recv RST_STREAM - CHECK(ss.is_allowed_to_receive(QUICFrameType::RST_STREAM)); + // Case4. Recv RESET_STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); ss.update_with_receiving_frame(*rst_stream_frame); CHECK(ss.get() == QUICStreamState::State::ResetRecvd); } @@ -309,8 +309,8 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") ss.update_with_receiving_frame(*stream_frame_with_fin); CHECK(ss.get() == QUICStreamState::State::SizeKnown); - // Case3. Recv RST_STREAM - CHECK(ss.is_allowed_to_receive(QUICFrameType::RST_STREAM)); + // Case3. Recv RESET_STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); ss.update_with_receiving_frame(*rst_stream_frame); CHECK(ss.get() == QUICStreamState::State::ResetRecvd); diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index 43d66675c87..f993b4ead96 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -61,7 +61,7 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") CHECK(len == 4); CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); - data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_BIDI_STREAMS, len); + data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, len); CHECK(len == 2); CHECK(memcmp(data, "\x0a\x0b", 2) == 0); From f88932a0f9847f8a8e306d47115a5e7f2b57d9f5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 Jan 2019 12:49:22 +0900 Subject: [PATCH 1019/1313] Fix a packet type check in QUICPollCont --- iocore/net/QUICNet.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/QUICNet.cc b/iocore/net/QUICNet.cc index 9a4b649c0f0..d3df166be11 100644 --- a/iocore/net/QUICNet.cc +++ b/iocore/net/QUICNet.cc @@ -67,7 +67,8 @@ QUICPollCont::_process_long_header_packet(QUICPollEvent *e, NetHandler *nh) QUICNetVConnection *vc = static_cast(e->con); uint8_t *buf = (uint8_t *)p->getIOBlockChain()->buf(); - QUICPacketType ptype = static_cast(buf[0] & 0x7f); + QUICPacketType ptype; + QUICPacketLongHeader::type(ptype, buf, 1); if (ptype == QUICPacketType::INITIAL && !vc->read.triggered) { SCOPED_MUTEX_LOCK(lock, vc->mutex, this_ethread()); vc->read.triggered = 1; From 0a685ab2b04a9b811d6f9b5562a624501cd34b88 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 Jan 2019 15:25:32 +0900 Subject: [PATCH 1020/1313] Update names around max_streams --- iocore/net/quic/QUICConfig.cc | 32 ++++++------ iocore/net/quic/QUICConfig.h | 16 +++--- iocore/net/quic/QUICFrame.cc | 50 +++++++++---------- iocore/net/quic/QUICFrame.h | 22 ++++---- iocore/net/quic/QUICHandshake.cc | 16 +++--- iocore/net/quic/QUICStreamManager.cc | 34 ++++++------- iocore/net/quic/QUICStreamManager.h | 10 ++-- iocore/net/quic/test/test_QUICFrame.cc | 24 ++++----- .../net/quic/test/test_QUICStreamManager.cc | 12 ++--- mgmt/RecordsConfig.cc | 8 +-- 10 files changed, 112 insertions(+), 112 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 8e8ccf5d1bb..eaab96a3dc6 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -162,10 +162,10 @@ QUICConfigParams::initialize() "proxy.config.quic.initial_max_stream_data_bidi_remote_out"); REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data_uni_in, "proxy.config.quic.initial_max_stream_data_uni_in"); REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data_uni_out, "proxy.config.quic.initial_max_stream_data_uni_out"); - REC_EstablishStaticConfigInt32U(this->_initial_max_bidi_streams_in, "proxy.config.quic.initial_max_bidi_streams_in"); - REC_EstablishStaticConfigInt32U(this->_initial_max_bidi_streams_out, "proxy.config.quic.initial_max_bidi_streams_out"); - REC_EstablishStaticConfigInt32U(this->_initial_max_uni_streams_in, "proxy.config.quic.initial_max_uni_streams_in"); - REC_EstablishStaticConfigInt32U(this->_initial_max_uni_streams_out, "proxy.config.quic.initial_max_uni_streams_out"); + REC_EstablishStaticConfigInt32U(this->_initial_max_streams_bidi_in, "proxy.config.quic.initial_max_streams_bidi_in"); + REC_EstablishStaticConfigInt32U(this->_initial_max_streams_bidi_out, "proxy.config.quic.initial_max_streams_bidi_out"); + REC_EstablishStaticConfigInt32U(this->_initial_max_streams_uni_in, "proxy.config.quic.initial_max_streams_uni_in"); + REC_EstablishStaticConfigInt32U(this->_initial_max_streams_uni_out, "proxy.config.quic.initial_max_streams_uni_out"); REC_EstablishStaticConfigInt32U(this->_ack_delay_exponent_in, "proxy.config.quic.ack_delay_exponent_in"); REC_EstablishStaticConfigInt32U(this->_ack_delay_exponent_out, "proxy.config.quic.ack_delay_exponent_out"); REC_EstablishStaticConfigInt32U(this->_max_ack_delay_in, "proxy.config.quic.max_ack_delay_in"); @@ -306,28 +306,28 @@ QUICConfigParams::initial_max_stream_data_uni_out() const return this->_initial_max_stream_data_uni_out; } -uint16_t -QUICConfigParams::initial_max_bidi_streams_in() const +uint64_t +QUICConfigParams::initial_max_streams_bidi_in() const { - return this->_initial_max_bidi_streams_in; + return this->_initial_max_streams_bidi_in; } -uint16_t -QUICConfigParams::initial_max_bidi_streams_out() const +uint64_t +QUICConfigParams::initial_max_streams_bidi_out() const { - return this->_initial_max_bidi_streams_out; + return this->_initial_max_streams_bidi_out; } -uint16_t -QUICConfigParams::initial_max_uni_streams_in() const +uint64_t +QUICConfigParams::initial_max_streams_uni_in() const { - return this->_initial_max_uni_streams_in; + return this->_initial_max_streams_uni_in; } -uint16_t -QUICConfigParams::initial_max_uni_streams_out() const +uint64_t +QUICConfigParams::initial_max_streams_uni_out() const { - return this->_initial_max_uni_streams_out; + return this->_initial_max_streams_uni_out; } uint8_t diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index f33b793fd51..cd182b2c105 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -60,10 +60,10 @@ class QUICConfigParams : public ConfigInfo uint32_t initial_max_stream_data_bidi_remote_out() const; uint32_t initial_max_stream_data_uni_in() const; uint32_t initial_max_stream_data_uni_out() const; - uint16_t initial_max_bidi_streams_in() const; - uint16_t initial_max_bidi_streams_out() const; - uint16_t initial_max_uni_streams_in() const; - uint16_t initial_max_uni_streams_out() const; + uint64_t initial_max_streams_bidi_in() const; + uint64_t initial_max_streams_bidi_out() const; + uint64_t initial_max_streams_uni_in() const; + uint64_t initial_max_streams_uni_out() const; uint8_t ack_delay_exponent_in() const; uint8_t ack_delay_exponent_out() const; uint8_t max_ack_delay_in() const; @@ -120,10 +120,10 @@ class QUICConfigParams : public ConfigInfo uint32_t _initial_max_stream_data_bidi_remote_out = 0; uint32_t _initial_max_stream_data_uni_in = 0; uint32_t _initial_max_stream_data_uni_out = 0; - uint32_t _initial_max_bidi_streams_in = 0; - uint32_t _initial_max_bidi_streams_out = 0; - uint32_t _initial_max_uni_streams_in = 0; - uint32_t _initial_max_uni_streams_out = 0; + uint32_t _initial_max_streams_bidi_in = 0; + uint32_t _initial_max_streams_bidi_out = 0; + uint32_t _initial_max_streams_uni_in = 0; + uint32_t _initial_max_streams_uni_out = 0; uint32_t _ack_delay_exponent_in = 0; uint32_t _ack_delay_exponent_out = 0; uint32_t _max_ack_delay_in = 0; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index c78e8b6fcc4..3719cdb7375 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -38,7 +38,7 @@ ClassAllocator quicRstStreamFrameAllocator("quicRstStreamFra ClassAllocator quicConnectionCloseFrameAllocator("quicConnectionCloseFrameAllocator"); ClassAllocator quicMaxDataFrameAllocator("quicMaxDataFrameAllocator"); ClassAllocator quicMaxStreamDataFrameAllocator("quicMaxStreamDataFrameAllocator"); -ClassAllocator quicMaxStreamIdFrameAllocator("quicMaxStreamDataIdAllocator"); +ClassAllocator quicMaxStreamIdFrameAllocator("quicMaxStreamDataIdAllocator"); ClassAllocator quicPingFrameAllocator("quicPingFrameAllocator"); ClassAllocator quicBlockedFrameAllocator("quicBlockedFrameAllocator"); ClassAllocator quicStreamBlockedFrameAllocator("quicStreamBlockedFrameAllocator"); @@ -1646,16 +1646,16 @@ QUICMaxStreamDataFrame::maximum_stream_data() const // // MAX_STREAMS // -QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICFrameId id, QUICFrameGenerator *owner) +QUICMaxStreamsFrame::QUICMaxStreamsFrame(QUICStreamId maximum_streams, QUICFrameId id, QUICFrameGenerator *owner) : QUICFrame(id, owner) { - this->_maximum_stream_id = maximum_stream_id; + this->_maximum_streams = maximum_streams; } void -QUICMaxStreamIdFrame::_reset() +QUICMaxStreamsFrame::_reset() { - this->_maximum_stream_id = 0; + this->_maximum_streams = 0; this->_owner = nullptr; this->_id = 0; @@ -1663,20 +1663,20 @@ QUICMaxStreamIdFrame::_reset() this->_size = 0; } -QUICMaxStreamIdFrame::QUICMaxStreamIdFrame(const uint8_t *buf, size_t len) +QUICMaxStreamsFrame::QUICMaxStreamsFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } void -QUICMaxStreamIdFrame::parse(const uint8_t *buf, size_t len) +QUICMaxStreamsFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); this->_reset(); uint8_t *pos = const_cast(buf) + 1; size_t field_len = 0; - if (!read_varint(pos, LEFT_SPACE(pos), this->_maximum_stream_id, field_len)) { + if (!read_varint(pos, LEFT_SPACE(pos), this->_maximum_streams, field_len)) { return; } @@ -1685,29 +1685,29 @@ QUICMaxStreamIdFrame::parse(const uint8_t *buf, size_t len) } QUICFrameUPtr -QUICMaxStreamIdFrame::clone() const +QUICMaxStreamsFrame::clone() const { - return QUICFrameFactory::create_max_stream_id_frame(this->maximum_stream_id(), this->_id, this->_owner); + return QUICFrameFactory::create_max_streams_frame(this->maximum_streams(), this->_id, this->_owner); } QUICFrameType -QUICMaxStreamIdFrame::type() const +QUICMaxStreamsFrame::type() const { return QUICFrameType::MAX_STREAMS; } size_t -QUICMaxStreamIdFrame::size() const +QUICMaxStreamsFrame::size() const { if (this->_size) { return this->_size; } - return sizeof(QUICFrameType) + QUICVariableInt::size(this->_maximum_stream_id); + return sizeof(QUICFrameType) + QUICVariableInt::size(this->_maximum_streams); } size_t -QUICMaxStreamIdFrame::store(uint8_t *buf, size_t *len, size_t limit) const +QUICMaxStreamsFrame::store(uint8_t *buf, size_t *len, size_t limit) const { if (limit < this->size()) { return 0; @@ -1717,17 +1717,17 @@ QUICMaxStreamIdFrame::store(uint8_t *buf, size_t *len, size_t limit) const uint8_t *p = buf; *p = static_cast(QUICFrameType::MAX_STREAMS); ++p; - QUICTypeUtil::write_QUICStreamId(this->_maximum_stream_id, p, &n); + QUICTypeUtil::write_QUICStreamId(this->_maximum_streams, p, &n); p += n; *len = p - buf; return *len; } -QUICStreamId -QUICMaxStreamIdFrame::maximum_stream_id() const +uint64_t +QUICMaxStreamsFrame::maximum_streams() const { - return this->_maximum_stream_id; + return this->_maximum_streams; } // @@ -2691,8 +2691,8 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); case QUICFrameType::MAX_STREAMS: frame = quicMaxStreamIdFrameAllocator.alloc(); - new (frame) QUICMaxStreamIdFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_max_stream_id_frame); + new (frame) QUICMaxStreamsFrame(buf, len); + return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_max_streams_frame); case QUICFrameType::PING: frame = quicPingFrameAllocator.alloc(); new (frame) QUICPingFrame(buf, len); @@ -2837,12 +2837,12 @@ QUICFrameFactory::create_max_stream_data_frame(QUICStreamId stream_id, uint64_t return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); } -std::unique_ptr -QUICFrameFactory::create_max_stream_id_frame(QUICStreamId maximum_stream_id, QUICFrameId id, QUICFrameGenerator *owner) +std::unique_ptr +QUICFrameFactory::create_max_streams_frame(QUICStreamId maximum_streams, QUICFrameId id, QUICFrameGenerator *owner) { - QUICMaxStreamIdFrame *frame = quicMaxStreamIdFrameAllocator.alloc(); - new (frame) QUICMaxStreamIdFrame(maximum_stream_id, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_id_frame); + QUICMaxStreamsFrame *frame = quicMaxStreamIdFrameAllocator.alloc(); + new (frame) QUICMaxStreamsFrame(maximum_streams, id, owner); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_streams_frame); } std::unique_ptr diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index c52687435e9..46ee9c4fc03 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -441,23 +441,23 @@ class QUICMaxStreamDataFrame : public QUICFrame // MAX_STREAMS // -class QUICMaxStreamIdFrame : public QUICFrame +class QUICMaxStreamsFrame : public QUICFrame { public: - QUICMaxStreamIdFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICMaxStreamIdFrame(const uint8_t *buf, size_t len); - QUICMaxStreamIdFrame(QUICStreamId maximum_stream_id, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + QUICMaxStreamsFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} + QUICMaxStreamsFrame(const uint8_t *buf, size_t len); + QUICMaxStreamsFrame(QUICStreamId maximum_streams, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; - QUICStreamId maximum_stream_id() const; + uint64_t maximum_streams() const; private: virtual void _reset() override; - QUICStreamId _maximum_stream_id = 0; + uint64_t _maximum_streams = 0; }; // @@ -745,7 +745,7 @@ extern ClassAllocator quicRstStreamFrameAllocator; extern ClassAllocator quicConnectionCloseFrameAllocator; extern ClassAllocator quicMaxDataFrameAllocator; extern ClassAllocator quicMaxStreamDataFrameAllocator; -extern ClassAllocator quicMaxStreamIdFrameAllocator; +extern ClassAllocator quicMaxStreamIdFrameAllocator; extern ClassAllocator quicPingFrameAllocator; extern ClassAllocator quicBlockedFrameAllocator; extern ClassAllocator quicStreamBlockedFrameAllocator; @@ -825,10 +825,10 @@ class QUICFrameDeleter } static void - delete_max_stream_id_frame(QUICFrame *frame) + delete_max_streams_frame(QUICFrame *frame) { frame->~QUICFrame(); - quicMaxStreamIdFrameAllocator.free(static_cast(frame)); + quicMaxStreamIdFrameAllocator.free(static_cast(frame)); } static void @@ -987,8 +987,8 @@ class QUICFrameFactory /* * Creates a MAX_STREAMS frame. */ - static std::unique_ptr create_max_stream_id_frame( - QUICStreamId maximum_stream_id, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_max_streams_frame( + QUICStreamId maximum_streams, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a PING frame diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index b3c96a87f80..d8b5752ffca 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -376,11 +376,11 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve if (params->initial_max_data_in() != 0) { tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data_in()); } - if (params->initial_max_bidi_streams_in() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, params->initial_max_bidi_streams_in()); + if (params->initial_max_streams_bidi_in() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, params->initial_max_streams_bidi_in()); } - if (params->initial_max_uni_streams_in() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, params->initial_max_uni_streams_in()); + if (params->initial_max_streams_uni_in() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, params->initial_max_streams_uni_in()); } if (params->initial_max_stream_data_bidi_local_in() != 0) { tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, params->initial_max_stream_data_bidi_local_in()); @@ -422,11 +422,11 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi if (params->initial_max_data_out() != 0) { tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data_out()); } - if (params->initial_max_bidi_streams_out() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, params->initial_max_bidi_streams_out()); + if (params->initial_max_streams_bidi_out() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, params->initial_max_streams_bidi_out()); } - if (params->initial_max_uni_streams_out() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, params->initial_max_uni_streams_out()); + if (params->initial_max_streams_uni_out() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, params->initial_max_streams_uni_out()); } if (params->initial_max_stream_data_bidi_local_out() != 0) { tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, params->initial_max_stream_data_bidi_local_out()); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 73becc3fff2..6ce9056a96b 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -61,12 +61,12 @@ QUICStreamManager::init_flow_control_params(const std::shared_ptr_remote_tp = remote_tp; if (this->_local_tp) { - this->_local_maximum_stream_id_bidi = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI); - this->_local_maximum_stream_id_uni = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI); + this->_local_max_streams_bidi = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI); + this->_local_max_streams_uni = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI); } if (this->_remote_tp) { - this->_remote_maximum_stream_id_bidi = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI); - this->_remote_maximum_stream_id_uni = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI); + this->_remote_max_streams_bidi = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI); + this->_remote_max_streams_uni = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI); } } @@ -75,12 +75,12 @@ QUICStreamManager::set_max_stream_id(QUICStreamId id) { QUICStreamType type = QUICTypeUtil::detect_stream_type(id); if (type == QUICStreamType::SERVER_BIDI || type == QUICStreamType::CLIENT_BIDI) { - if (this->_local_maximum_stream_id_bidi <= id) { - this->_local_maximum_stream_id_bidi = id; + if (this->_local_max_streams_bidi <= id) { + this->_local_max_streams_bidi = id; } } else { - if (this->_local_maximum_stream_id_uni <= id) { - this->_local_maximum_stream_id_uni = id; + if (this->_local_max_streams_uni <= id) { + this->_local_max_streams_uni = id; } } } @@ -158,7 +158,7 @@ QUICStreamManager::handle_frame(QUICEncryptionLevel level, const QUICFrame &fram error = this->_handle_frame(static_cast(frame)); break; case QUICFrameType::MAX_STREAMS: - error = this->_handle_frame(static_cast(frame)); + error = this->_handle_frame(static_cast(frame)); break; default: Debug(tag, "Unexpected frame type: %02x", static_cast(frame.type())); @@ -231,13 +231,13 @@ QUICStreamManager::_handle_frame(const QUICStopSendingFrame &frame) } QUICConnectionErrorUPtr -QUICStreamManager::_handle_frame(const QUICMaxStreamIdFrame &frame) +QUICStreamManager::_handle_frame(const QUICMaxStreamsFrame &frame) { - QUICStreamType type = QUICTypeUtil::detect_stream_type(frame.maximum_stream_id()); + QUICStreamType type = QUICTypeUtil::detect_stream_type(frame.maximum_streams()); if (type == QUICStreamType::SERVER_BIDI || type == QUICStreamType::CLIENT_BIDI) { - this->_remote_maximum_stream_id_bidi = frame.maximum_stream_id(); + this->_remote_max_streams_bidi = frame.maximum_streams(); } else { - this->_remote_maximum_stream_id_uni = frame.maximum_stream_id(); + this->_remote_max_streams_uni = frame.maximum_streams(); } return nullptr; } @@ -270,7 +270,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) switch (QUICTypeUtil::detect_stream_type(stream_id)) { case QUICStreamType::CLIENT_BIDI: - if (this->_local_maximum_stream_id_bidi == 0 || stream_id > this->_local_maximum_stream_id_bidi) { + if (this->_local_max_streams_bidi == 0 || stream_id > this->_local_max_streams_bidi) { return nullptr; } @@ -286,7 +286,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) break; case QUICStreamType::CLIENT_UNI: - if (this->_local_maximum_stream_id_uni == 0 || stream_id > this->_local_maximum_stream_id_uni) { + if (this->_local_max_streams_uni == 0 || stream_id > this->_local_max_streams_uni) { return nullptr; } @@ -295,7 +295,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) break; case QUICStreamType::SERVER_BIDI: - if (this->_remote_maximum_stream_id_bidi == 0 || stream_id > this->_remote_maximum_stream_id_bidi) { + if (this->_remote_max_streams_bidi == 0 || stream_id > this->_remote_max_streams_bidi) { return nullptr; } @@ -311,7 +311,7 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) break; case QUICStreamType::SERVER_UNI: - if (this->_remote_maximum_stream_id_uni == 0 || stream_id > this->_remote_maximum_stream_id_uni) { + if (this->_remote_max_streams_uni == 0 || stream_id > this->_remote_max_streams_uni) { return nullptr; } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 3f5d563a324..fce8ef39696 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -74,7 +74,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICConnectionErrorUPtr _handle_frame(const QUICStopSendingFrame &frame); QUICConnectionErrorUPtr _handle_frame(const QUICMaxStreamDataFrame &frame); QUICConnectionErrorUPtr _handle_frame(const QUICStreamBlockedFrame &frame); - QUICConnectionErrorUPtr _handle_frame(const QUICMaxStreamIdFrame &frame); + QUICConnectionErrorUPtr _handle_frame(const QUICMaxStreamsFrame &frame); std::vector _encryption_level_filter() override { @@ -89,10 +89,10 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICApplicationMap *_app_map = nullptr; std::shared_ptr _local_tp = nullptr; std::shared_ptr _remote_tp = nullptr; - QUICStreamId _local_maximum_stream_id_bidi = 0; - QUICStreamId _local_maximum_stream_id_uni = 0; - QUICStreamId _remote_maximum_stream_id_bidi = 0; - QUICStreamId _remote_maximum_stream_id_uni = 0; + QUICStreamId _local_max_streams_bidi = 0; + QUICStreamId _local_max_streams_uni = 0; + QUICStreamId _remote_max_streams_bidi = 0; + QUICStreamId _remote_max_streams_uni = 0; QUICStreamId _next_stream_id_uni = 0; QUICStreamId _next_stream_id_bidi = 0; uint64_t _total_offset_sent = 0; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 01f0d72c359..85a6d94469a 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1015,9 +1015,9 @@ TEST_CASE("Load MaxStreamId Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_STREAMS); CHECK(frame1->size() == 5); - std::shared_ptr max_stream_id_frame = std::dynamic_pointer_cast(frame1); - CHECK(max_stream_id_frame != nullptr); - CHECK(max_stream_id_frame->maximum_stream_id() == 0x01020304); + std::shared_ptr max_streams_frame = std::dynamic_pointer_cast(frame1); + CHECK(max_streams_frame != nullptr); + CHECK(max_streams_frame->maximum_streams() == 0x01020304); } SECTION("bad load") { @@ -1039,10 +1039,10 @@ TEST_CASE("Store MaxStreamId Frame", "[quic]") 0x06, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID }; - QUICMaxStreamIdFrame max_stream_id_frame(0x01020304, 0, nullptr); - CHECK(max_stream_id_frame.size() == 5); + QUICMaxStreamsFrame max_streams_frame(0x01020304, 0, nullptr); + CHECK(max_streams_frame.size() == 5); - max_stream_id_frame.store(buf, &len, 65535); + max_streams_frame.store(buf, &len, 65535); CHECK(len == 5); CHECK(memcmp(buf, expected, len) == 0); } @@ -1517,16 +1517,16 @@ TEST_CASE("QUICFrameFactory Fast Create Frame", "[quic]") std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); CHECK(frame1 != nullptr); - std::shared_ptr max_stream_id_frame1 = std::dynamic_pointer_cast(frame1); - CHECK(max_stream_id_frame1 != nullptr); - CHECK(max_stream_id_frame1->maximum_stream_id() == 0x01020304); + std::shared_ptr max_streams_frame1 = std::dynamic_pointer_cast(frame1); + CHECK(max_streams_frame1 != nullptr); + CHECK(max_streams_frame1->maximum_streams() == 0x01020304); std::shared_ptr frame2 = factory.fast_create(buf2, sizeof(buf2)); CHECK(frame2 != nullptr); - std::shared_ptr max_stream_id_frame2 = std::dynamic_pointer_cast(frame2); - CHECK(max_stream_id_frame2 != nullptr); - CHECK(max_stream_id_frame2->maximum_stream_id() == 0x05060708); + std::shared_ptr max_streams_frame2 = std::dynamic_pointer_cast(frame2); + CHECK(max_streams_frame2 != nullptr); + CHECK(max_streams_frame2->maximum_streams() == 0x05060708); CHECK(frame1 == frame2); } diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index e355cbce60c..54a4ee8d19c 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -44,7 +44,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") 0x00, 0x00, 0x00, 0x00, // initial version 0x00, // size of supported versions 0x00, 0x06, // size of parameters - 0x00, 0x02, // parameter id - initial_max_bidi_streams + 0x00, 0x02, // parameter id - initial_max_streams_bidi 0x00, 0x02, // length of value 0x00, 0x10 // value }; @@ -54,7 +54,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") uint8_t remote_tp_buf[] = { 0x00, 0x00, 0x00, 0x00, // initial version 0x00, 0x06, // size of parameters - 0x00, 0x02, // parameter id - initial_max_bidi_streams + 0x00, 0x02, // parameter id - initial_max_streams_bidi 0x00, 0x02, // length of value 0x00, 0x10 // value }; @@ -141,7 +141,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") 0x00, 0x00, 0x00, 0x00, // initial version 0x00, // size of supported versions 0x00, 0x0e, // size of parameters - 0x00, 0x02, // parameter id - initial_max_bidi_streams + 0x00, 0x02, // parameter id - initial_max_streams_bidi 0x00, 0x02, // length of value 0x00, 0x10, // value 0x00, 0x00, // parameter id - initial_max_stream_data_bidi_local @@ -154,7 +154,7 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") uint8_t remote_tp_buf[] = { 0x00, 0x00, 0x00, 0x00, // initial version 0x00, 0x0e, // size of parameters - 0x00, 0x02, // parameter id - initial_max_bidi_streams + 0x00, 0x02, // parameter id - initial_max_streams_bidi 0x00, 0x02, // length of value 0x00, 0x10, // value 0x00, 0x0a, // parameter id - initial_max_stream_data_bidi_remote @@ -198,7 +198,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") 0x00, 0x00, 0x00, 0x00, // initial version 0x00, // size of supported versions 0x00, 0x06, // size of parameters - 0x00, 0x02, // parameter id - initial_max_bidi_streams + 0x00, 0x02, // parameter id - initial_max_streams_bidi 0x00, 0x02, // length of value 0x00, 0x10 // value }; @@ -208,7 +208,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") uint8_t remote_tp_buf[] = { 0x00, 0x00, 0x00, 0x00, // initial version 0x00, 0x06, // size of parameters - 0x00, 0x02, // parameter id - initial_max_bidi_streams + 0x00, 0x02, // parameter id - initial_max_streams_bidi 0x00, 0x02, // length of value 0x00, 0x10 // value }; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 6a185a224b4..7c66eb29b17 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1380,13 +1380,13 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_uni_out", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.initial_max_bidi_streams_in", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.initial_max_streams_bidi_in", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.initial_max_bidi_streams_out", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.initial_max_streams_bidi_out", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.initial_max_uni_streams_in", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.initial_max_streams_uni_in", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.initial_max_uni_streams_out", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.initial_max_streams_uni_out", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.ack_delay_exponent_in", RECD_INT, "3", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , From 3a993f9a7c8799577e4fa4f712041ba9e2726734 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 15 Jan 2019 15:58:49 +0900 Subject: [PATCH 1021/1313] Change set_max_stream_id to set_max_streams_(bidi|uni) --- iocore/net/quic/QUICStreamManager.cc | 21 ++++++++++--------- iocore/net/quic/QUICStreamManager.h | 3 ++- .../net/quic/test/test_QUICStreamManager.cc | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 6ce9056a96b..643471b3d7f 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -71,17 +71,18 @@ QUICStreamManager::init_flow_control_params(const std::shared_ptr_local_max_streams_bidi <= id) { - this->_local_max_streams_bidi = id; - } - } else { - if (this->_local_max_streams_uni <= id) { - this->_local_max_streams_uni = id; - } + if (this->_local_max_streams_bidi <= max_streams) { + this->_local_max_streams_bidi = max_streams; + } +} + +void +QUICStreamManager::set_max_streams_uni(uint64_t max_streams) +{ + if (this->_local_max_streams_uni <= max_streams) { + this->_local_max_streams_uni = max_streams; } } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index fce8ef39696..a382c17a92e 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -42,7 +42,8 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator void init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); - void set_max_stream_id(QUICStreamId id); + void set_max_streams_bidi(uint64_t max_streams); + void set_max_streams_uni(uint64_t max_streams); uint64_t total_reordered_bytes() const; uint64_t total_offset_received() const; uint64_t total_offset_sent() const; diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 54a4ee8d19c..8188d223af7 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -94,7 +94,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") CHECK(sm.stream_count() == 5); // Set local maximum stream id - sm.set_max_stream_id(0x14); + sm.set_max_streams_bidi(100); std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_blocked_frame(0x18, 0); sm.handle_frame(level, *stream_blocked_frame_x); CHECK(sm.stream_count() == 5); From cb13e7dddce53f4224c69ef5a2359f0cc1b424fe Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 16 Jan 2019 08:08:17 +0900 Subject: [PATCH 1022/1313] Fix sample offset boundary check --- iocore/net/quic/QUICPacketHeaderProtector.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc index 20a278e63c1..6d06b5b88d1 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -172,7 +172,8 @@ int dcil) const } else { *sample_offset = 1 + dcil + 4; } - return sample_offset + 16 < protected_packet + protected_packet_len; + + return *sample_offset + 16 < protected_packet_len; } bool From e1438d0d72431ce12a6566ad8dad72e63a9ea7cc Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 16 Jan 2019 08:12:02 +0900 Subject: [PATCH 1023/1313] clang-formant --- iocore/net/quic/QUICFrame.cc | 22 +++++++++++-------- iocore/net/quic/QUICFrame.h | 11 +++++----- iocore/net/quic/QUICPacketHeaderProtector.cc | 6 ++--- iocore/net/quic/QUICStreamManager.cc | 2 +- iocore/net/quic/QUICStreamManager.h | 8 +++---- iocore/net/quic/QUICTransportParameters.cc | 4 ++-- .../test/test_QUICPacketHeaderProtector.cc | 20 +++++------------ 7 files changed, 35 insertions(+), 38 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 3719cdb7375..b2d66dd92d9 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -106,11 +106,14 @@ QUICFrame::type(const uint8_t *buf) return QUICFrameType::ACK; } else if (static_cast(QUICFrameType::STREAM) <= buf[0] && buf[0] < static_cast(QUICFrameType::MAX_DATA)) { return QUICFrameType::STREAM; - } else if (static_cast(QUICFrameType::MAX_STREAMS) <= buf[0] && buf[0] < static_cast(QUICFrameType::DATA_BLOCKED)) { + } else if (static_cast(QUICFrameType::MAX_STREAMS) <= buf[0] && + buf[0] < static_cast(QUICFrameType::DATA_BLOCKED)) { return QUICFrameType::MAX_STREAMS; - } else if (static_cast(QUICFrameType::STREAMS_BLOCKED) <= buf[0] && buf[0] < static_cast(QUICFrameType::NEW_CONNECTION_ID)) { + } else if (static_cast(QUICFrameType::STREAMS_BLOCKED) <= buf[0] && + buf[0] < static_cast(QUICFrameType::NEW_CONNECTION_ID)) { return QUICFrameType::STREAMS_BLOCKED; - } else if (static_cast(QUICFrameType::CONNECTION_CLOSE) <= buf[0] && buf[0] < static_cast(QUICFrameType::UNKNOWN)) { + } else if (static_cast(QUICFrameType::CONNECTION_CLOSE) <= buf[0] && + buf[0] < static_cast(QUICFrameType::UNKNOWN)) { return QUICFrameType::CONNECTION_CLOSE; } else { return static_cast(buf[0]); @@ -1247,8 +1250,8 @@ QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, QUICFram { } -QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, uint64_t reason_phrase_length, - const char *reason_phrase, QUICFrameId id, QUICFrameGenerator *owner) +QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, uint64_t reason_phrase_length, const char *reason_phrase, + QUICFrameId id, QUICFrameGenerator *owner) : QUICFrame(id, owner), _type(0x1d), _error_code(error_code), @@ -1281,7 +1284,7 @@ QUICConnectionCloseFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); this->_reset(); - this->_type = buf[0]; + this->_type = buf[0]; uint8_t *pos = const_cast(buf) + 1; if (LEFT_SPACE(pos) < 2) { @@ -1399,10 +1402,11 @@ QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const { int len; if (this->_type == 0x1c) { - len = snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=%s (0x%" PRIx16 ") frame=%s", this->size(), - QUICDebugNames::error_code(this->error_code()), this->error_code(), QUICDebugNames::frame_type(this->frame_type())); + len = + snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=%s (0x%" PRIx16 ") frame=%s", this->size(), + QUICDebugNames::error_code(this->error_code()), this->error_code(), QUICDebugNames::frame_type(this->frame_type())); } else { - // Application-specific error. It doesn't have a frame type and we don't know string representations of error codes. + // Application-specific error. It doesn't have a frame type and we don't know string representations of error codes. len = snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=0x%" PRIx16 " ", this->size(), this->error_code()); } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 46ee9c4fc03..549db76938b 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -360,8 +360,8 @@ class QUICConnectionCloseFrame : public QUICFrame QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); // Constructor for application protocol error codes - QUICConnectionCloseFrame(uint16_t error_code, uint64_t reason_phrase_length, const char *reason_phrase, - QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + QUICConnectionCloseFrame(uint16_t error_code, uint64_t reason_phrase_length, const char *reason_phrase, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -377,7 +377,7 @@ class QUICConnectionCloseFrame : public QUICFrame private: virtual void _reset() override; - uint8_t _type = 0; + uint8_t _type = 0; uint16_t _error_code; QUICFrameType _frame_type = QUICFrameType::UNKNOWN; uint64_t _reason_phrase_length = 0; @@ -987,8 +987,9 @@ class QUICFrameFactory /* * Creates a MAX_STREAMS frame. */ - static std::unique_ptr create_max_streams_frame( - QUICStreamId maximum_streams, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_max_streams_frame(QUICStreamId maximum_streams, + QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a PING frame diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc index 6d06b5b88d1..64682238eee 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -47,7 +47,7 @@ QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotect } 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; - type = QUICPacketType::PROTECTED; + type = QUICPacketType::PROTECTED; } Debug("v_quic_pne", "Protecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), @@ -104,7 +104,7 @@ QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected } 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; - type = QUICPacketType::PROTECTED; + type = QUICPacketType::PROTECTED; } Debug("v_quic_pne", "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), @@ -149,7 +149,7 @@ QUICPacketHeaderProtector::set_hs_protocol(const QUICHandshakeProtocol *hs_proto bool QUICPacketHeaderProtector::_calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len, -int dcil) const + int dcil) const { if (QUICInvariants::is_long_header(protected_packet)) { uint8_t dcil; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 643471b3d7f..30e38168f46 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -48,7 +48,7 @@ std::vector QUICStreamManager::interests() { return { - QUICFrameType::STREAM, QUICFrameType::RESET_STREAM, QUICFrameType::STOP_SENDING, + QUICFrameType::STREAM, QUICFrameType::RESET_STREAM, QUICFrameType::STOP_SENDING, QUICFrameType::MAX_STREAM_DATA, QUICFrameType::MAX_STREAMS, }; } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index a382c17a92e..86fd94ffc99 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -90,10 +90,10 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICApplicationMap *_app_map = nullptr; std::shared_ptr _local_tp = nullptr; std::shared_ptr _remote_tp = nullptr; - QUICStreamId _local_max_streams_bidi = 0; - QUICStreamId _local_max_streams_uni = 0; - QUICStreamId _remote_max_streams_bidi = 0; - QUICStreamId _remote_max_streams_uni = 0; + QUICStreamId _local_max_streams_bidi = 0; + QUICStreamId _local_max_streams_uni = 0; + QUICStreamId _remote_max_streams_bidi = 0; + QUICStreamId _remote_max_streams_uni = 0; QUICStreamId _next_stream_id_uni = 0; QUICStreamId _next_stream_id_bidi = 0; uint64_t _total_offset_sent = 0; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 75be850c1f7..175e9c03fa9 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -35,8 +35,8 @@ static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; static constexpr char tag[] = "quic_handshake"; -static constexpr uint32_t TP_ERROR_LENGTH = 0x010000; -static constexpr uint32_t TP_ERROR_VALUE = 0x020000; +static constexpr uint32_t TP_ERROR_LENGTH = 0x010000; +static constexpr uint32_t TP_ERROR_VALUE = 0x020000; // static constexpr uint32_t TP_ERROR_MUST_EXIST = 0x030000; static constexpr uint32_t TP_ERROR_MUST_NOT_EXIST = 0x040000; diff --git a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc index e479c48f3e1..818a64fdd58 100644 --- a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc @@ -60,12 +60,9 @@ TEST_CASE("QUICPacketHeaderProtector") SECTION("Long header", "[quic]") { uint8_t original[] = { - 0xC0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0xC0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, }; uint8_t tmp[48]; memcpy(tmp, original, sizeof(tmp)); @@ -97,12 +94,9 @@ TEST_CASE("QUICPacketHeaderProtector") SECTION("Short header", "[quic]") { uint8_t original[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, }; uint8_t tmp[48]; memcpy(tmp, original, sizeof(tmp)); @@ -119,7 +113,6 @@ TEST_CASE("QUICPacketHeaderProtector") client_ph_protector.set_hs_protocol(client); server_ph_protector.set_hs_protocol(server); - // Handshake // CH QUICHandshakeMsgs msg1; @@ -192,7 +185,6 @@ TEST_CASE("QUICPacketHeaderProtector") msg5.max_buf_len = MAX_HANDSHAKE_MSG_LEN; REQUIRE(client->handshake(&msg5, &msg4) == 1); - // ## Client -> Server client_ph_protector.protect(tmp, sizeof(tmp), 18); CHECK(memcmp(original, tmp, sizeof(original)) != 0); From bfda9e0f62dcd9e4504aa60e6527e2e35e303c5c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 16 Jan 2019 14:30:30 +0900 Subject: [PATCH 1024/1313] Rename HQ to HTTP3 --- .gitignore | 4 +- configure.ac | 2 +- iocore/eventsystem/I_Event.h | 2 +- iocore/net/quic/Makefile.am | 2 +- iocore/net/quic/Mock.h | 2 +- proxy/Makefile.am | 4 +- proxy/hq/HQFrame.cc | 324 ------------------ proxy/http/HttpProxyServerMain.cc | 4 +- proxy/http/Makefile.am | 2 +- proxy/{hq/HQ.cc => http3/Http3.cc} | 8 +- proxy/{hq/HQ.h => http3/Http3.h} | 11 +- .../Http3ClientSession.cc} | 48 +-- .../Http3ClientSession.h} | 16 +- .../Http3ClientTransaction.cc} | 100 +++--- .../Http3ClientTransaction.h} | 32 +- .../Http3DataFramer.cc} | 20 +- .../Http3DataFramer.h} | 16 +- .../Http3DebugNames.h} | 4 +- proxy/http3/Http3Frame.cc | 324 ++++++++++++++++++ proxy/{hq/HQFrame.h => http3/Http3Frame.h} | 100 +++--- .../Http3FrameCollector.cc} | 12 +- .../Http3FrameCollector.h} | 12 +- .../Http3FrameDispatcher.cc} | 24 +- .../Http3FrameDispatcher.h} | 14 +- .../Http3FrameGenerator.h} | 6 +- .../Http3FrameHandler.h} | 12 +- .../Http3HeaderFramer.cc} | 22 +- .../Http3HeaderFramer.h} | 16 +- .../Http3HeaderVIOAdaptor.cc} | 20 +- .../Http3HeaderVIOAdaptor.h} | 12 +- .../Http3SessionAccept.cc} | 16 +- .../Http3SessionAccept.h} | 10 +- .../Http3StreamDataVIOAdaptor.cc} | 20 +- .../Http3StreamDataVIOAdaptor.h} | 12 +- proxy/{hq/HQTypes.h => http3/Http3Types.h} | 50 +-- proxy/{hq => http3}/Makefile.am | 50 +-- proxy/{hq => http3}/QPACK.cc | 0 proxy/{hq => http3}/QPACK.h | 2 +- proxy/{hq => http3}/QUICSimpleApp.cc | 10 +- proxy/{hq => http3}/QUICSimpleApp.h | 4 +- proxy/{hq => http3}/test/Mock.h | 16 +- proxy/{hq => http3}/test/main.cc | 0 proxy/{hq => http3}/test/main_qpack.cc | 0 proxy/{hq => http3}/test/stub.cc | 0 .../test/test_Http3Frame.cc} | 54 +-- .../test/test_Http3FrameDispatcher.cc} | 12 +- proxy/{hq => http3}/test/test_QPACK.cc | 0 src/traffic_server/Makefile.inc | 4 +- src/traffic_server/traffic_server.cc | 4 +- src/tscore/ink_inet.cc | 2 +- 50 files changed, 719 insertions(+), 722 deletions(-) delete mode 100644 proxy/hq/HQFrame.cc rename proxy/{hq/HQ.cc => http3/Http3.cc} (87%) rename proxy/{hq/HQ.h => http3/Http3.h} (84%) rename proxy/{hq/HQClientSession.cc => http3/Http3ClientSession.cc} (57%) rename proxy/{hq/HQClientSession.h => http3/Http3ClientSession.h} (85%) rename proxy/{hq/HQClientTransaction.cc => http3/Http3ClientTransaction.cc} (79%) rename proxy/{hq/HQClientTransaction.h => http3/Http3ClientTransaction.h} (80%) rename proxy/{hq/HQDataFramer.cc => http3/Http3DataFramer.cc} (69%) rename proxy/{hq/HQDataFramer.h => http3/Http3DataFramer.h} (74%) rename proxy/{hq/HQDebugNames.h => http3/Http3DebugNames.h} (92%) create mode 100644 proxy/http3/Http3Frame.cc rename proxy/{hq/HQFrame.h => http3/Http3Frame.h} (52%) rename proxy/{hq/HQFrameCollector.cc => http3/Http3FrameCollector.cc} (82%) rename proxy/{hq/HQFrameCollector.h => http3/Http3FrameCollector.h} (79%) rename proxy/{hq/HQFrameDispatcher.cc => http3/Http3FrameDispatcher.cc} (77%) rename proxy/{hq/HQFrameDispatcher.h => http3/Http3FrameDispatcher.h} (80%) rename proxy/{hq/HQFrameGenerator.h => http3/Http3FrameGenerator.h} (88%) rename proxy/{hq/HQFrameHandler.h => http3/Http3FrameHandler.h} (77%) rename proxy/{hq/HQHeaderFramer.cc => http3/Http3HeaderFramer.cc} (82%) rename proxy/{hq/HQHeaderFramer.h => http3/Http3HeaderFramer.h} (78%) rename proxy/{hq/HQHeaderVIOAdaptor.cc => http3/Http3HeaderVIOAdaptor.cc} (69%) rename proxy/{hq/HQHeaderVIOAdaptor.h => http3/Http3HeaderVIOAdaptor.h} (77%) rename proxy/{hq/HQSessionAccept.cc => http3/Http3SessionAccept.cc} (80%) rename proxy/{hq/HQSessionAccept.h => http3/Http3SessionAccept.h} (86%) rename proxy/{hq/HQStreamDataVIOAdaptor.cc => http3/Http3StreamDataVIOAdaptor.cc} (68%) rename proxy/{hq/HQStreamDataVIOAdaptor.h => http3/Http3StreamDataVIOAdaptor.h} (76%) rename proxy/{hq/HQTypes.h => http3/Http3Types.h} (53%) rename proxy/{hq => http3}/Makefile.am (77%) rename proxy/{hq => http3}/QPACK.cc (100%) rename proxy/{hq => http3}/QPACK.h (99%) rename proxy/{hq => http3}/QUICSimpleApp.cc (90%) rename proxy/{hq => http3}/QUICSimpleApp.h (94%) rename proxy/{hq => http3}/test/Mock.h (77%) rename proxy/{hq => http3}/test/main.cc (100%) rename proxy/{hq => http3}/test/main_qpack.cc (100%) rename proxy/{hq => http3}/test/stub.cc (100%) rename proxy/{hq/test/test_HQFrame.cc => http3/test/test_Http3Frame.cc} (62%) rename proxy/{hq/test/test_HQFrameDispatcher.cc => http3/test/test_Http3FrameDispatcher.cc} (83%) rename proxy/{hq => http3}/test/test_QPACK.cc (100%) diff --git a/.gitignore b/.gitignore index f4c8848cdce..ed79285ad81 100644 --- a/.gitignore +++ b/.gitignore @@ -124,8 +124,8 @@ proxy/http/test_proxy_http proxy/http2/test_Http2DependencyTree proxy/http2/test_HPACK proxy/http2/hpack-tests/results -proxy/hq/test_libhq -proxy/hq/test_qpack +proxy/http3/test_libhttp3 +proxy/http3/test_qpack proxy/logging/test_LogUtils plugins/header_rewrite/header_rewrite_test diff --git a/configure.ac b/configure.ac index 46b82a97e33..f87252e8742 100644 --- a/configure.ac +++ b/configure.ac @@ -2104,7 +2104,7 @@ AC_CONFIG_FILES([ proxy/http/Makefile proxy/http/remap/Makefile proxy/http2/Makefile - proxy/hq/Makefile + proxy/http3/Makefile proxy/logging/Makefile proxy/shared/Makefile rc/Makefile diff --git a/iocore/eventsystem/I_Event.h b/iocore/eventsystem/I_Event.h index 6beab953f98..52fa67da4f8 100644 --- a/iocore/eventsystem/I_Event.h +++ b/iocore/eventsystem/I_Event.h @@ -74,7 +74,7 @@ #define HTTP_TUNNEL_EVENTS_START 2300 #define HTTP_SCH_UPDATE_EVENTS_START 2400 #define QUIC_EVENT_EVENTS_START 2500 -#define HQ_SESSION_EVENTS_START 2600 +#define HTTP3_SESSION_EVENTS_START 2600 #define QPACK_EVENT_EVENTS_START 2700 #define NT_ASYNC_CONNECT_EVENT_EVENTS_START 3000 #define NT_ASYNC_IO_EVENT_EVENTS_START 3100 diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 268208fbcbb..ba7568318d6 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -25,7 +25,7 @@ AM_CPPFLAGS += \ -I$(abs_top_srcdir)/proxy/shared \ -I$(abs_top_srcdir)/proxy/logging \ -I$(abs_top_srcdir)/proxy/http \ - -I$(abs_top_srcdir)/proxy/hq \ + -I$(abs_top_srcdir)/proxy/http3 \ -I$(abs_top_srcdir)/mgmt \ -I$(abs_top_srcdir)/mgmt/utils \ $(TS_INCLUDES) \ diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 7037431d9cc..e6d3bba0b85 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -582,7 +582,7 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol void negotiated_application_name(const uint8_t **name, unsigned int *len) const override { - *name = reinterpret_cast("hq"); + *name = reinterpret_cast("h3"); *len = 2; } diff --git a/proxy/Makefile.am b/proxy/Makefile.am index 902bc81ccf6..0ac0de5c91e 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -20,7 +20,7 @@ include $(top_srcdir)/build/tidy.mk SUBDIRS = hdrs shared http http2 logging if ENABLE_QUIC -SUBDIRS += hq +SUBDIRS += http3 endif noinst_LIBRARIES = libproxy.a @@ -31,7 +31,7 @@ AM_CPPFLAGS += \ -I$(abs_top_srcdir)/lib \ -I$(abs_srcdir)/http \ -I$(abs_srcdir)/http2 \ - -I$(abs_srcdir)/hq \ + -I$(abs_srcdir)/http3 \ -I$(abs_srcdir)/logging \ -I$(abs_srcdir)/http/remap \ -I$(abs_srcdir)/hdrs \ diff --git a/proxy/hq/HQFrame.cc b/proxy/hq/HQFrame.cc deleted file mode 100644 index 6ab87d7b390..00000000000 --- a/proxy/hq/HQFrame.cc +++ /dev/null @@ -1,324 +0,0 @@ -/** @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 "tscore/Diags.h" -#include "quic/QUICIntUtil.h" -#include "HQFrame.h" - -ClassAllocator hqFrameAllocator("hqFrameAllocator"); -ClassAllocator hqDataFrameAllocator("hqDataFrameAllocator"); -ClassAllocator hqHeadersFrameAllocator("hqHeadersFrameAllocator"); - -// -// Static functions -// - -int -HQFrame::length(const uint8_t *buf, size_t buf_len, uint64_t &length) -{ - size_t length_field_length = 0; - return QUICVariableInt::decode(length, length_field_length, buf, buf_len); -} - -HQFrameType -HQFrame::type(const uint8_t *buf, size_t buf_len) -{ - uint64_t length = 0; - size_t length_field_length = 0; - int ret = QUICVariableInt::decode(length, length_field_length, buf, buf_len); - ink_assert(ret != 1); - if (buf[length_field_length] <= static_cast(HQFrameType::X_MAX_DEFINED)) { - return static_cast(buf[length_field_length]); - } else { - return HQFrameType::UNKNOWN; - } -} - -// -// Generic Frame -// - -HQFrame::HQFrame(const uint8_t *buf, size_t buf_len) -{ - // Length - size_t length_field_length = 0; - int ret = QUICVariableInt::decode(this->_length, length_field_length, buf, buf_len); - ink_assert(ret != 1); - - // Type - this->_type = HQFrameType(buf[length_field_length]); - - // Flags - this->_flags = buf[length_field_length + 1]; - - // Payload offset - this->_payload_offset = length_field_length + 2; -} - -HQFrame::HQFrame(HQFrameType type) : _type(type) {} - -uint64_t -HQFrame::total_length() const -{ - return this->_payload_offset + this->length(); -} - -uint64_t -HQFrame::length() const -{ - return this->_length; -} - -HQFrameType -HQFrame::type() const -{ - return this->_type; -} - -uint8_t -HQFrame::flags() const -{ - return this->_flags; -} - -void -HQFrame::store(uint8_t *buf, size_t *len) const -{ - // If you really need this, you should keep the data passed to its constructor - ink_assert(!"Not supported"); -} - -void -HQFrame::reset(const uint8_t *buf, size_t len) -{ - this->~HQFrame(); - new (this) HQFrame(buf, len); -} - -// -// UNKNOWN Frame -// -HQUnknownFrame::HQUnknownFrame(const uint8_t *buf, size_t buf_len) : HQFrame(buf, buf_len), _buf(buf), _buf_len(buf_len) {} - -void -HQUnknownFrame::store(uint8_t *buf, size_t *len) const -{ - memcpy(buf, this->_buf, this->_buf_len); - *len = this->_buf_len; -} - -// -// DATA Frame -// -HQDataFrame::HQDataFrame(const uint8_t *buf, size_t buf_len) : HQFrame(buf, buf_len) -{ - this->_payload = buf + this->_payload_offset; - this->_payload_len = buf_len - this->_payload_offset; -} - -HQDataFrame::HQDataFrame(ats_unique_buf payload, size_t payload_len) - : HQFrame(HQFrameType::DATA), _payload_uptr(std::move(payload)), _payload_len(payload_len) -{ - this->_length = this->_payload_len; - this->_payload = this->_payload_uptr.get(); -} - -void -HQDataFrame::store(uint8_t *buf, size_t *len) const -{ - size_t written = 0; - QUICVariableInt::encode(buf, UINT64_MAX, written, this->_length); - buf[written++] = static_cast(this->_type); - buf[written++] = this->_flags; - memcpy(buf + written, this->_payload, this->_payload_len); - written += this->_payload_len; - *len = written; -} - -void -HQDataFrame::reset(const uint8_t *buf, size_t len) -{ - this->~HQDataFrame(); - new (this) HQDataFrame(buf, len); -} - -const uint8_t * -HQDataFrame::payload() const -{ - return this->_payload; -} - -uint64_t -HQDataFrame::payload_length() const -{ - return this->_payload_len; -} - -// -// HEADERS Frame -// -HQHeadersFrame::HQHeadersFrame(const uint8_t *buf, size_t buf_len) : HQFrame(buf, buf_len) -{ - this->_header_block = buf + this->_payload_offset; - this->_header_block_len = buf_len - this->_payload_offset; -} - -HQHeadersFrame::HQHeadersFrame(ats_unique_buf header_block, size_t header_block_len) - : HQFrame(HQFrameType::HEADERS), _header_block_uptr(std::move(header_block)), _header_block_len(header_block_len) -{ - this->_length = header_block_len; - this->_header_block = this->_header_block_uptr.get(); -} - -void -HQHeadersFrame::store(uint8_t *buf, size_t *len) const -{ - size_t written = 0; - QUICVariableInt::encode(buf, UINT64_MAX, written, this->_length); - buf[written++] = static_cast(this->_type); - buf[written++] = this->_flags; - memcpy(buf + written, this->_header_block, this->_header_block_len); - written += this->_header_block_len; - *len = written; -} - -void -HQHeadersFrame::reset(const uint8_t *buf, size_t len) -{ - this->~HQHeadersFrame(); - new (this) HQHeadersFrame(buf, len); -} - -const uint8_t * -HQHeadersFrame::header_block() const -{ - return this->_header_block; -} - -uint64_t -HQHeadersFrame::header_block_length() const -{ - return this->_header_block_len; -} - -// -// HQFrameFactory -// -HQFrameUPtr -HQFrameFactory::create_null_frame() -{ - return {nullptr, &HQFrameDeleter::delete_null_frame}; -} - -HQFrameUPtr -HQFrameFactory::create(const uint8_t *buf, size_t len) -{ - HQFrame *frame = nullptr; - HQFrameType type = HQFrame::type(buf, len); - - switch (type) { - case HQFrameType::HEADERS: - frame = hqHeadersFrameAllocator.alloc(); - new (frame) HQHeadersFrame(buf, len); - return HQFrameUPtr(frame, &HQFrameDeleter::delete_headers_frame); - case HQFrameType::DATA: - frame = hqDataFrameAllocator.alloc(); - new (frame) HQDataFrame(buf, len); - return HQFrameUPtr(frame, &HQFrameDeleter::delete_data_frame); - default: - // Unknown frame - Debug("hq_frame_factory", "Unknown frame type %hhx", static_cast(type)); - frame = hqFrameAllocator.alloc(); - new (frame) HQFrame(buf, len); - return HQFrameUPtr(frame, &HQFrameDeleter::delete_frame); - } -} - -std::shared_ptr -HQFrameFactory::fast_create(const uint8_t *buf, size_t len) -{ - uint64_t frame_length = 0; - if (HQFrame::length(buf, len, frame_length) == -1 || frame_length > len) { - return nullptr; - } - HQFrameType type = HQFrame::type(buf, len); - if (type == HQFrameType::UNKNOWN) { - if (!this->_unknown_frame) { - this->_unknown_frame = HQFrameFactory::create(buf, len); - } else { - this->_unknown_frame->reset(buf, len); - } - return _unknown_frame; - } - - std::shared_ptr frame = this->_reusable_frames[static_cast(type)]; - - if (frame == nullptr) { - frame = HQFrameFactory::create(buf, len); - if (frame != nullptr) { - this->_reusable_frames[static_cast(type)] = frame; - } - } else { - frame->reset(buf, len); - } - fprintf(stderr, "%p\n", frame.get()); - - return frame; -} - -std::shared_ptr -HQFrameFactory::fast_create(QUICStreamIO &stream_io, size_t len) -{ - uint8_t buf[65536]; - - // FIXME DATA frames can be giga bytes - ink_assert(sizeof(buf) > len); - - if (stream_io.peek(buf, sizeof(buf) < len)) { - // Return if whole frame data is not available - return nullptr; - } - return this->fast_create(buf, len); -} - -HQHeadersFrameUPtr -HQFrameFactory::create_headers_frame(const uint8_t *header_block, size_t header_block_len) -{ - ats_unique_buf buf = ats_unique_malloc(header_block_len); - memcpy(buf.get(), header_block, header_block_len); - - HQHeadersFrame *frame = hqHeadersFrameAllocator.alloc(); - new (frame) HQHeadersFrame(std::move(buf), header_block_len); - return HQHeadersFrameUPtr(frame, &HQFrameDeleter::delete_headers_frame); -} - -HQDataFrameUPtr -HQFrameFactory::create_data_frame(const uint8_t *payload, size_t payload_len) -{ - ats_unique_buf buf = ats_unique_malloc(payload_len); - memcpy(buf.get(), payload, payload_len); - - HQDataFrame *frame = hqDataFrameAllocator.alloc(); - new (frame) HQDataFrame(std::move(buf), payload_len); - return HQDataFrameUPtr(frame, &HQFrameDeleter::delete_data_frame); -} diff --git a/proxy/http/HttpProxyServerMain.cc b/proxy/http/HttpProxyServerMain.cc index 856e3725e37..ac5e6bbbde2 100644 --- a/proxy/http/HttpProxyServerMain.cc +++ b/proxy/http/HttpProxyServerMain.cc @@ -41,7 +41,7 @@ #include "HttpProxyServerMain.h" #if TS_USE_QUIC == 1 #include "P_QUICNextProtocolAccept.h" -#include "hq/HQSessionAccept.h" +#include "http3/Http3SessionAccept.h" #endif #include @@ -260,7 +260,7 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned // HTTP/QUIC if (port.m_session_protocol_preference.contains(TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC)) { - quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC, new HQSessionAccept(accept_opt)); + quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC, new Http3SessionAccept(accept_opt)); } quic->proxyPort = &port; diff --git a/proxy/http/Makefile.am b/proxy/http/Makefile.am index 7b8492d83d5..b86e3a2f77a 100644 --- a/proxy/http/Makefile.am +++ b/proxy/http/Makefile.am @@ -32,7 +32,7 @@ AM_CPPFLAGS += \ -I$(abs_top_srcdir)/proxy/http/remap \ -I$(abs_top_srcdir)/proxy/logging \ -I$(abs_top_srcdir)/proxy/http2 \ - -I$(abs_top_srcdir)/proxy/hq \ + -I$(abs_top_srcdir)/proxy/http3 \ $(TS_INCLUDES) noinst_HEADERS = HttpProxyServerMain.h diff --git a/proxy/hq/HQ.cc b/proxy/http3/Http3.cc similarity index 87% rename from proxy/hq/HQ.cc rename to proxy/http3/Http3.cc index 1282a1ad824..74f811b2549 100644 --- a/proxy/hq/HQ.cc +++ b/proxy/http3/Http3.cc @@ -21,12 +21,12 @@ * limitations under the License. */ -#include "HQ.h" +#include "Http3.h" -RecRawStatBlock *hq_rsb; +RecRawStatBlock *http3_rsb; void -HQ::init() +Http3::init() { - hq_rsb = RecAllocateRawStatBlock(static_cast(HQ_N_STATS)); + http3_rsb = RecAllocateRawStatBlock(static_cast(HTTP3_N_STATS)); } diff --git a/proxy/hq/HQ.h b/proxy/http3/Http3.h similarity index 84% rename from proxy/hq/HQ.h rename to proxy/http3/Http3.h index 78c3c7560fd..b3da732d105 100644 --- a/proxy/hq/HQ.h +++ b/proxy/http3/Http3.h @@ -21,16 +21,15 @@ * limitations under the License. */ -#ifndef __HTTP_QUIC_H__ -#define __HTTP_QUIC_H__ +#pragma once #include "tscore/ink_defs.h" #include "records/I_RecDefs.h" #include "records/I_RecProcess.h" -extern RecRawStatBlock *hq_rsb; // Container for statistics. +extern RecRawStatBlock *http3_rsb; // Container for statistics. -class HQ +class Http3 { public: static void init(); @@ -38,7 +37,5 @@ class HQ // Statistics enum { - HQ_N_STATS // Terminal counter, NOT A STAT INDEX. + HTTP3_N_STATS // Terminal counter, NOT A STAT INDEX. }; - -#endif // __HTTP_QUIC_H__ diff --git a/proxy/hq/HQClientSession.cc b/proxy/http3/Http3ClientSession.cc similarity index 57% rename from proxy/hq/HQClientSession.cc rename to proxy/http3/Http3ClientSession.cc index b0c49a64fe3..d87125afd41 100644 --- a/proxy/hq/HQClientSession.cc +++ b/proxy/http3/Http3ClientSession.cc @@ -21,69 +21,69 @@ limitations under the License. */ -#include "HQClientSession.h" +#include "Http3ClientSession.h" -HQClientSession::HQClientSession(NetVConnection *vc) : _client_vc(vc) {} +Http3ClientSession::Http3ClientSession(NetVConnection *vc) : _client_vc(vc) {} -HQClientSession::~HQClientSession() +Http3ClientSession::~Http3ClientSession() { this->_client_vc = nullptr; - for (HQClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { + for (Http3ClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { delete t; } } VIO * -HQClientSession::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +Http3ClientSession::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) { ink_assert(false); return nullptr; } VIO * -HQClientSession::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +Http3ClientSession::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) { ink_assert(false); return nullptr; } void -HQClientSession::do_io_close(int lerrno) +Http3ClientSession::do_io_close(int lerrno) { // TODO return; } void -HQClientSession::do_io_shutdown(ShutdownHowTo_t howto) +Http3ClientSession::do_io_shutdown(ShutdownHowTo_t howto) { ink_assert(false); return; } void -HQClientSession::reenable(VIO *vio) +Http3ClientSession::reenable(VIO *vio) { ink_assert(false); return; } void -HQClientSession::destroy() +Http3ClientSession::destroy() { ink_assert(false); return; } void -HQClientSession::start() +Http3ClientSession::start() { ink_assert(false); return; } void -HQClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader, bool backdoor) +Http3ClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader, bool backdoor) { this->con_id = static_cast(reinterpret_cast(new_vc))->connection_id(); @@ -91,32 +91,32 @@ HQClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBuff } NetVConnection * -HQClientSession::get_netvc() const +Http3ClientSession::get_netvc() const { return this->_client_vc; } int -HQClientSession::get_transact_count() const +Http3ClientSession::get_transact_count() const { return 0; } const char * -HQClientSession::get_protocol_string() const +Http3ClientSession::get_protocol_string() const { - return "hq"; + return "h3-17"; } void -HQClientSession::release(ProxyClientTransaction *trans) +Http3ClientSession::release(ProxyClientTransaction *trans) { ink_assert(false); return; } int -HQClientSession::populate_protocol(std::string_view *result, int size) const +Http3ClientSession::populate_protocol(std::string_view *result, int size) const { int retval = 0; if (size > retval) { @@ -129,29 +129,29 @@ HQClientSession::populate_protocol(std::string_view *result, int size) const } void -HQClientSession::increment_current_active_client_connections_stat() +Http3ClientSession::increment_current_active_client_connections_stat() { // TODO Implement stats } void -HQClientSession::decrement_current_active_client_connections_stat() +Http3ClientSession::decrement_current_active_client_connections_stat() { // TODO Implement stats } void -HQClientSession::add_transaction(HQClientTransaction *trans) +Http3ClientSession::add_transaction(Http3ClientTransaction *trans) { this->_transaction_list.enqueue(trans); return; } // this->_transaction_list should be map? -HQClientTransaction * -HQClientSession::get_transaction(QUICStreamId id) +Http3ClientTransaction * +Http3ClientSession::get_transaction(QUICStreamId id) { - for (HQClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { + for (Http3ClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { if (t->get_transaction_id() == static_cast(id)) { return t; } diff --git a/proxy/hq/HQClientSession.h b/proxy/http3/Http3ClientSession.h similarity index 85% rename from proxy/hq/HQClientSession.h rename to proxy/http3/Http3ClientSession.h index 40578bc0a13..7f2240c4259 100644 --- a/proxy/hq/HQClientSession.h +++ b/proxy/http3/Http3ClientSession.h @@ -24,15 +24,15 @@ #pragma once #include "ProxyClientSession.h" -#include "HQClientTransaction.h" +#include "Http3ClientTransaction.h" -class HQClientSession : public ProxyClientSession +class Http3ClientSession : public ProxyClientSession { public: typedef ProxyClientSession super; ///< Parent type. - HQClientSession(NetVConnection *vc); - ~HQClientSession(); + Http3ClientSession(NetVConnection *vc); + ~Http3ClientSession(); // Implement VConnection interface VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) override; @@ -53,11 +53,11 @@ class HQClientSession : public ProxyClientSession void increment_current_active_client_connections_stat() override; void decrement_current_active_client_connections_stat() override; - // HQClientSession specific methods - void add_transaction(HQClientTransaction *); - HQClientTransaction *get_transaction(QUICStreamId); + // Http3ClientSession specific methods + void add_transaction(Http3ClientTransaction *); + Http3ClientTransaction *get_transaction(QUICStreamId); private: NetVConnection *_client_vc = nullptr; - Queue _transaction_list; + Queue _transaction_list; }; diff --git a/proxy/hq/HQClientTransaction.cc b/proxy/http3/Http3ClientTransaction.cc similarity index 79% rename from proxy/hq/HQClientTransaction.cc rename to proxy/http3/Http3ClientTransaction.cc index 16f1f13b98b..4eaa7e270d2 100644 --- a/proxy/hq/HQClientTransaction.cc +++ b/proxy/http3/Http3ClientTransaction.cc @@ -21,24 +21,24 @@ limitations under the License. */ -#include "HQClientTransaction.h" +#include "Http3ClientTransaction.h" #include "QUICDebugNames.h" -#include "HQClientSession.h" -#include "HQStreamDataVIOAdaptor.h" -#include "HQHeaderVIOAdaptor.h" -#include "HQHeaderFramer.h" -#include "HQDataFramer.h" +#include "Http3ClientSession.h" +#include "Http3StreamDataVIOAdaptor.h" +#include "Http3HeaderVIOAdaptor.h" +#include "Http3HeaderFramer.h" +#include "Http3DataFramer.h" #include "HttpSM.h" -#define HQTransDebug(fmt, ...) \ - Debug("hq_trans", "[%s] [%" PRIx32 "] " fmt, \ +#define Http3TransDebug(fmt, ...) \ + Debug("http3_trans", "[%s] [%" PRIx32 "] " fmt, \ static_cast(reinterpret_cast(this->parent->get_netvc()))->cids().data(), \ this->get_transaction_id(), ##__VA_ARGS__) -#define HQTransVDebug(fmt, ...) \ - Debug("v_hq_trans", "[%s] [%" PRIx32 "] " fmt, \ +#define Http3TransVDebug(fmt, ...) \ + Debug("v_http3_trans", "[%s] [%" PRIx32 "] " fmt, \ static_cast(reinterpret_cast(this->parent->get_netvc()))->cids().data(), \ this->get_transaction_id(), ##__VA_ARGS__) @@ -49,33 +49,33 @@ // uint8_t msg[1024] = {0}; // int64_t msg_len = 1024; // int64_t read_len = debug_reader->read(msg, msg_len); -// Debug("v_hq_trans", "len=%" PRId64 "\n%s\n", read_len, msg); +// Debug("v_http3_trans", "len=%" PRId64 "\n%s\n", read_len, msg); // } -HQClientTransaction::HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) +Http3ClientTransaction::Http3ClientTransaction(Http3ClientSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) { this->mutex = new_ProxyMutex(); this->_thread = this_ethread(); this->set_parent(session); this->sm_reader = this->_read_vio_buf.alloc_reader(); - static_cast(this->parent)->add_transaction(this); + static_cast(this->parent)->add_transaction(this); - this->_header_framer = new HQHeaderFramer(this, &this->_write_vio); - this->_data_framer = new HQDataFramer(this, &this->_write_vio); + this->_header_framer = new Http3HeaderFramer(this, &this->_write_vio); + this->_data_framer = new Http3DataFramer(this, &this->_write_vio); this->_frame_collector.add_generator(this->_header_framer); this->_frame_collector.add_generator(this->_data_framer); // this->_frame_collector.add_generator(this->_push_controller); - this->_header_handler = new HQHeaderVIOAdaptor(&this->_read_vio); - this->_data_handler = new HQStreamDataVIOAdaptor(&this->_read_vio); + this->_header_handler = new Http3HeaderVIOAdaptor(&this->_read_vio); + this->_data_handler = new Http3StreamDataVIOAdaptor(&this->_read_vio); this->_frame_dispatcher.add_handler(this->_header_handler); this->_frame_dispatcher.add_handler(this->_data_handler); - SET_HANDLER(&HQClientTransaction::state_stream_open); + SET_HANDLER(&Http3ClientTransaction::state_stream_open); } -HQClientTransaction::~HQClientTransaction() +Http3ClientTransaction::~Http3ClientTransaction() { delete this->_header_framer; delete this->_data_framer; @@ -84,7 +84,7 @@ HQClientTransaction::~HQClientTransaction() } void -HQClientTransaction::set_active_timeout(ink_hrtime timeout_in) +Http3ClientTransaction::set_active_timeout(ink_hrtime timeout_in) { if (parent) { parent->set_active_timeout(timeout_in); @@ -92,7 +92,7 @@ HQClientTransaction::set_active_timeout(ink_hrtime timeout_in) } void -HQClientTransaction::set_inactivity_timeout(ink_hrtime timeout_in) +Http3ClientTransaction::set_inactivity_timeout(ink_hrtime timeout_in) { if (parent) { parent->set_inactivity_timeout(timeout_in); @@ -100,7 +100,7 @@ HQClientTransaction::set_inactivity_timeout(ink_hrtime timeout_in) } void -HQClientTransaction::cancel_inactivity_timeout() +Http3ClientTransaction::cancel_inactivity_timeout() { if (parent) { parent->cancel_inactivity_timeout(); @@ -108,23 +108,23 @@ HQClientTransaction::cancel_inactivity_timeout() } void -HQClientTransaction::release(IOBufferReader *r) +Http3ClientTransaction::release(IOBufferReader *r) { super::release(r); this->current_reader = nullptr; } bool -HQClientTransaction::allow_half_open() const +Http3ClientTransaction::allow_half_open() const { return false; } int -HQClientTransaction::state_stream_open(int event, void *edata) +Http3ClientTransaction::state_stream_open(int event, void *edata) { // TODO: should check recursive call? - HQTransVDebug("%s (%d)", get_vc_event_name(event), event); + Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); if (this->_thread != this_ethread()) { // Send on to the owning thread @@ -171,7 +171,7 @@ HQClientTransaction::state_stream_open(int event, void *edata) break; } default: - HQTransDebug("Unknown event %d", event); + Http3TransDebug("Unknown event %d", event); ink_assert(false); } @@ -179,9 +179,9 @@ HQClientTransaction::state_stream_open(int event, void *edata) } int -HQClientTransaction::state_stream_closed(int event, void *data) +Http3ClientTransaction::state_stream_closed(int event, void *data) { - HQTransVDebug("%s (%d)", get_vc_event_name(event), event); + Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); switch (event) { case VC_EVENT_READ_READY: @@ -210,7 +210,7 @@ HQClientTransaction::state_stream_closed(int event, void *data) } VIO * -HQClientTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +Http3ClientTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) { if (buf) { this->_read_vio.buffer.writer_for(buf); @@ -232,7 +232,7 @@ HQClientTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) } VIO * -HQClientTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +Http3ClientTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) { if (buf) { this->_write_vio.buffer.reader_for(buf); @@ -254,9 +254,9 @@ HQClientTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader } void -HQClientTransaction::do_io_close(int lerrno) +Http3ClientTransaction::do_io_close(int lerrno) { - SET_HANDLER(&HQClientTransaction::state_stream_closed); + SET_HANDLER(&Http3ClientTransaction::state_stream_closed); if (this->_read_event) { this->_read_event->cancel(); @@ -282,13 +282,13 @@ HQClientTransaction::do_io_close(int lerrno) } void -HQClientTransaction::do_io_shutdown(ShutdownHowTo_t howto) +Http3ClientTransaction::do_io_shutdown(ShutdownHowTo_t howto) { return; } void -HQClientTransaction::reenable(VIO *vio) +Http3ClientTransaction::reenable(VIO *vio) { if (vio->op == VIO::READ) { int64_t len = this->_process_read_vio(); @@ -311,7 +311,7 @@ HQClientTransaction::reenable(VIO *vio) * @brief Replace existing event only if the new event is different than the inprogress event */ Event * -HQClientTransaction::_send_tracked_event(Event *event, int send_event, VIO *vio) +Http3ClientTransaction::_send_tracked_event(Event *event, int send_event, VIO *vio) { if (event != nullptr) { if (event->callback_event != send_event) { @@ -328,19 +328,19 @@ HQClientTransaction::_send_tracked_event(Event *event, int send_event, VIO *vio) } void -HQClientTransaction::set_read_vio_nbytes(int64_t nbytes) +Http3ClientTransaction::set_read_vio_nbytes(int64_t nbytes) { this->_read_vio.nbytes = nbytes; } void -HQClientTransaction::set_write_vio_nbytes(int64_t nbytes) +Http3ClientTransaction::set_write_vio_nbytes(int64_t nbytes) { this->_write_vio.nbytes = nbytes; } void -HQClientTransaction::destroy() +Http3ClientTransaction::destroy() { current_reader = nullptr; } @@ -349,7 +349,7 @@ HQClientTransaction::destroy() * @brief Signal event to this->_read_vio.cont */ void -HQClientTransaction::_signal_read_event() +Http3ClientTransaction::_signal_read_event() { if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return; @@ -363,14 +363,14 @@ HQClientTransaction::_signal_read_event() this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio); } - HQTransVDebug("%s (%d)", get_vc_event_name(event), event); + Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); } /** * @brief Signal event to this->_write_vio.cont */ void -HQClientTransaction::_signal_write_event() +Http3ClientTransaction::_signal_write_event() { if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { return; @@ -384,12 +384,12 @@ HQClientTransaction::_signal_write_event() this_ethread()->schedule_imm(this->_write_vio.cont, event, &this->_write_vio); } - HQTransVDebug("%s (%d)", get_vc_event_name(event), event); + Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); } // Convert HTTP/0.9 to HTTP/1.1 int64_t -HQClientTransaction::_process_read_vio() +Http3ClientTransaction::_process_read_vio() { if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return 0; @@ -459,7 +459,7 @@ HQClientTransaction::_process_read_vio() return nread; // End of code for HTTP/0.9 } else { - // This branch is for HQ + // This branch is for HTTP/3 uint64_t nread = 0; this->_frame_dispatcher.on_read_ready(*this->_stream_io, nread); return nread; @@ -471,7 +471,7 @@ static constexpr char http_1_1_version[] = "HTTP/1.1"; // Convert HTTP/1.1 to HTTP/0.9 int64_t -HQClientTransaction::_process_write_vio() +Http3ClientTransaction::_process_write_vio() { if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { return 0; @@ -535,26 +535,26 @@ HQClientTransaction::_process_write_vio() } void -HQClientTransaction::transaction_done() +Http3ClientTransaction::transaction_done() { // TODO: start closing transaction return; } int -HQClientTransaction::get_transaction_id() const +Http3ClientTransaction::get_transaction_id() const { return this->_stream_io->stream_id(); } bool -HQClientTransaction::is_response_header_sent() const +Http3ClientTransaction::is_response_header_sent() const { return this->_header_framer->is_done(); } bool -HQClientTransaction::is_response_body_sent() const +Http3ClientTransaction::is_response_body_sent() const { return this->_data_framer->is_done(); } diff --git a/proxy/hq/HQClientTransaction.h b/proxy/http3/Http3ClientTransaction.h similarity index 80% rename from proxy/hq/HQClientTransaction.h rename to proxy/http3/Http3ClientTransaction.h index d24c3bf744c..b778c203264 100644 --- a/proxy/hq/HQClientTransaction.h +++ b/proxy/http3/Http3ClientTransaction.h @@ -25,21 +25,21 @@ #include "I_VConnection.h" #include "ProxyClientTransaction.h" -#include "HQFrameDispatcher.h" -#include "HQFrameCollector.h" +#include "Http3FrameDispatcher.h" +#include "Http3FrameCollector.h" class QUICStreamIO; -class HQClientSession; -class HQHeaderFramer; -class HQDataFramer; +class Http3ClientSession; +class Http3HeaderFramer; +class Http3DataFramer; -class HQClientTransaction : public ProxyClientTransaction +class Http3ClientTransaction : public ProxyClientTransaction { public: using super = ProxyClientTransaction; - HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io); - ~HQClientTransaction(); + Http3ClientTransaction(Http3ClientSession *session, QUICStreamIO *stream_io); + ~Http3ClientTransaction(); // Implement ProxyClienTransaction interface void set_active_timeout(ink_hrtime timeout_in) override; @@ -61,7 +61,7 @@ class HQClientTransaction : public ProxyClientTransaction void set_read_vio_nbytes(int64_t nbytes); void set_write_vio_nbytes(int64_t nbytes); - // HQClientTransaction specific methods + // Http3ClientTransaction specific methods int state_stream_open(int, void *); int state_stream_closed(int event, void *data); bool is_response_header_sent() const; @@ -85,13 +85,13 @@ class HQClientTransaction : public ProxyClientTransaction Event *_read_event = nullptr; Event *_write_event = nullptr; - // These are for HQ - HQFrameDispatcher _frame_dispatcher; - HQFrameCollector _frame_collector; - HQFrameGenerator *_header_framer = nullptr; - HQFrameGenerator *_data_framer = nullptr; - HQFrameHandler *_header_handler = nullptr; - HQFrameHandler *_data_handler = nullptr; + // These are for Http3 + Http3FrameDispatcher _frame_dispatcher; + Http3FrameCollector _frame_collector; + Http3FrameGenerator *_header_framer = nullptr; + Http3FrameGenerator *_data_framer = nullptr; + Http3FrameHandler *_header_handler = nullptr; + Http3FrameHandler *_data_handler = nullptr; // These are for 0.9 support bool _protocol_detected = false; diff --git a/proxy/hq/HQDataFramer.cc b/proxy/http3/Http3DataFramer.cc similarity index 69% rename from proxy/hq/HQDataFramer.cc rename to proxy/http3/Http3DataFramer.cc index d074a27d8ee..3f4b6b3b8d5 100644 --- a/proxy/hq/HQDataFramer.cc +++ b/proxy/http3/Http3DataFramer.cc @@ -21,24 +21,24 @@ * limitations under the License. */ -#include "HQFrame.h" -#include "HQDataFramer.h" -#include "HQClientTransaction.h" +#include "Http3Frame.h" +#include "Http3DataFramer.h" +#include "Http3ClientTransaction.h" -HQDataFramer::HQDataFramer(HQClientTransaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) {} +Http3DataFramer::Http3DataFramer(Http3ClientTransaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) {} -HQFrameUPtr -HQDataFramer::generate_frame(uint16_t max_size) +Http3FrameUPtr +Http3DataFramer::generate_frame(uint16_t max_size) { if (!this->_transaction->is_response_header_sent()) { - return HQFrameFactory::create_null_frame(); + return Http3FrameFactory::create_null_frame(); } - HQFrameUPtr frame = HQFrameFactory::create_null_frame(); + Http3FrameUPtr frame = Http3FrameFactory::create_null_frame(); IOBufferReader *reader = this->_source_vio->get_reader(); size_t len = std::min(reader->read_avail(), static_cast(max_size)); if (len) { - frame = HQFrameFactory::create_data_frame(reinterpret_cast(reader->start()), len); + frame = Http3FrameFactory::create_data_frame(reinterpret_cast(reader->start()), len); reader->consume(len); this->_source_vio->ndone += len; } @@ -47,7 +47,7 @@ HQDataFramer::generate_frame(uint16_t max_size) } bool -HQDataFramer::is_done() const +Http3DataFramer::is_done() const { return this->_source_vio->ntodo() == 0; } diff --git a/proxy/hq/HQDataFramer.h b/proxy/http3/Http3DataFramer.h similarity index 74% rename from proxy/hq/HQDataFramer.h rename to proxy/http3/Http3DataFramer.h index af6fe8d09b4..8d288192617 100644 --- a/proxy/hq/HQDataFramer.h +++ b/proxy/http3/Http3DataFramer.h @@ -23,22 +23,22 @@ #pragma once -#include "HQFrameGenerator.h" -#include "HQFrame.h" +#include "Http3FrameGenerator.h" +#include "Http3Frame.h" -class HQClientTransaction; +class Http3ClientTransaction; class VIO; -class HQDataFramer : public HQFrameGenerator +class Http3DataFramer : public Http3FrameGenerator { public: - HQDataFramer(HQClientTransaction *transaction, VIO *source); + Http3DataFramer(Http3ClientTransaction *transaction, VIO *source); - // HQFrameGenerator - HQFrameUPtr generate_frame(uint16_t max_size) override; + // Http3FrameGenerator + Http3FrameUPtr generate_frame(uint16_t max_size) override; bool is_done() const override; private: - HQClientTransaction *_transaction = nullptr; + Http3ClientTransaction *_transaction = nullptr; VIO *_source_vio = nullptr; }; diff --git a/proxy/hq/HQDebugNames.h b/proxy/http3/Http3DebugNames.h similarity index 92% rename from proxy/hq/HQDebugNames.h rename to proxy/http3/Http3DebugNames.h index f1aa81da4be..4a0977d71d3 100644 --- a/proxy/hq/HQDebugNames.h +++ b/proxy/http3/Http3DebugNames.h @@ -23,7 +23,7 @@ #pragma once -class HQDebugNames +class Http3DebugNames { - static const char *frame_type(HQFrameType type); + static const char *frame_type(Http3FrameType type); }; diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc new file mode 100644 index 00000000000..2dd2e1a4d11 --- /dev/null +++ b/proxy/http3/Http3Frame.cc @@ -0,0 +1,324 @@ +/** @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 "tscore/Diags.h" +#include "quic/QUICIntUtil.h" +#include "Http3Frame.h" + +ClassAllocator http3FrameAllocator("http3FrameAllocator"); +ClassAllocator http3DataFrameAllocator("http3DataFrameAllocator"); +ClassAllocator http3HeadersFrameAllocator("http3HeadersFrameAllocator"); + +// +// Static functions +// + +int +Http3Frame::length(const uint8_t *buf, size_t buf_len, uint64_t &length) +{ + size_t length_field_length = 0; + return QUICVariableInt::decode(length, length_field_length, buf, buf_len); +} + +Http3FrameType +Http3Frame::type(const uint8_t *buf, size_t buf_len) +{ + uint64_t length = 0; + size_t length_field_length = 0; + int ret = QUICVariableInt::decode(length, length_field_length, buf, buf_len); + ink_assert(ret != 1); + if (buf[length_field_length] <= static_cast(Http3FrameType::X_MAX_DEFINED)) { + return static_cast(buf[length_field_length]); + } else { + return Http3FrameType::UNKNOWN; + } +} + +// +// Generic Frame +// + +Http3Frame::Http3Frame(const uint8_t *buf, size_t buf_len) +{ + // Length + size_t length_field_length = 0; + int ret = QUICVariableInt::decode(this->_length, length_field_length, buf, buf_len); + ink_assert(ret != 1); + + // Type + this->_type = Http3FrameType(buf[length_field_length]); + + // Flags + this->_flags = buf[length_field_length + 1]; + + // Payload offset + this->_payload_offset = length_field_length + 2; +} + +Http3Frame::Http3Frame(Http3FrameType type) : _type(type) {} + +uint64_t +Http3Frame::total_length() const +{ + return this->_payload_offset + this->length(); +} + +uint64_t +Http3Frame::length() const +{ + return this->_length; +} + +Http3FrameType +Http3Frame::type() const +{ + return this->_type; +} + +uint8_t +Http3Frame::flags() const +{ + return this->_flags; +} + +void +Http3Frame::store(uint8_t *buf, size_t *len) const +{ + // If you really need this, you should keep the data passed to its constructor + ink_assert(!"Not supported"); +} + +void +Http3Frame::reset(const uint8_t *buf, size_t len) +{ + this->~Http3Frame(); + new (this) Http3Frame(buf, len); +} + +// +// UNKNOWN Frame +// +Http3UnknownFrame::Http3UnknownFrame(const uint8_t *buf, size_t buf_len) : Http3Frame(buf, buf_len), _buf(buf), _buf_len(buf_len) {} + +void +Http3UnknownFrame::store(uint8_t *buf, size_t *len) const +{ + memcpy(buf, this->_buf, this->_buf_len); + *len = this->_buf_len; +} + +// +// DATA Frame +// +Http3DataFrame::Http3DataFrame(const uint8_t *buf, size_t buf_len) : Http3Frame(buf, buf_len) +{ + this->_payload = buf + this->_payload_offset; + this->_payload_len = buf_len - this->_payload_offset; +} + +Http3DataFrame::Http3DataFrame(ats_unique_buf payload, size_t payload_len) + : Http3Frame(Http3FrameType::DATA), _payload_uptr(std::move(payload)), _payload_len(payload_len) +{ + this->_length = this->_payload_len; + this->_payload = this->_payload_uptr.get(); +} + +void +Http3DataFrame::store(uint8_t *buf, size_t *len) const +{ + size_t written = 0; + QUICVariableInt::encode(buf, UINT64_MAX, written, this->_length); + buf[written++] = static_cast(this->_type); + buf[written++] = this->_flags; + memcpy(buf + written, this->_payload, this->_payload_len); + written += this->_payload_len; + *len = written; +} + +void +Http3DataFrame::reset(const uint8_t *buf, size_t len) +{ + this->~Http3DataFrame(); + new (this) Http3DataFrame(buf, len); +} + +const uint8_t * +Http3DataFrame::payload() const +{ + return this->_payload; +} + +uint64_t +Http3DataFrame::payload_length() const +{ + return this->_payload_len; +} + +// +// HEADERS Frame +// +Http3HeadersFrame::Http3HeadersFrame(const uint8_t *buf, size_t buf_len) : Http3Frame(buf, buf_len) +{ + this->_header_block = buf + this->_payload_offset; + this->_header_block_len = buf_len - this->_payload_offset; +} + +Http3HeadersFrame::Http3HeadersFrame(ats_unique_buf header_block, size_t header_block_len) + : Http3Frame(Http3FrameType::HEADERS), _header_block_uptr(std::move(header_block)), _header_block_len(header_block_len) +{ + this->_length = header_block_len; + this->_header_block = this->_header_block_uptr.get(); +} + +void +Http3HeadersFrame::store(uint8_t *buf, size_t *len) const +{ + size_t written = 0; + QUICVariableInt::encode(buf, UINT64_MAX, written, this->_length); + buf[written++] = static_cast(this->_type); + buf[written++] = this->_flags; + memcpy(buf + written, this->_header_block, this->_header_block_len); + written += this->_header_block_len; + *len = written; +} + +void +Http3HeadersFrame::reset(const uint8_t *buf, size_t len) +{ + this->~Http3HeadersFrame(); + new (this) Http3HeadersFrame(buf, len); +} + +const uint8_t * +Http3HeadersFrame::header_block() const +{ + return this->_header_block; +} + +uint64_t +Http3HeadersFrame::header_block_length() const +{ + return this->_header_block_len; +} + +// +// Http3FrameFactory +// +Http3FrameUPtr +Http3FrameFactory::create_null_frame() +{ + return {nullptr, &Http3FrameDeleter::delete_null_frame}; +} + +Http3FrameUPtr +Http3FrameFactory::create(const uint8_t *buf, size_t len) +{ + Http3Frame *frame = nullptr; + Http3FrameType type = Http3Frame::type(buf, len); + + switch (type) { + case Http3FrameType::HEADERS: + frame = http3HeadersFrameAllocator.alloc(); + new (frame) Http3HeadersFrame(buf, len); + return Http3FrameUPtr(frame, &Http3FrameDeleter::delete_headers_frame); + case Http3FrameType::DATA: + frame = http3DataFrameAllocator.alloc(); + new (frame) Http3DataFrame(buf, len); + return Http3FrameUPtr(frame, &Http3FrameDeleter::delete_data_frame); + default: + // Unknown frame + Debug("http3_frame_factory", "Unknown frame type %hhx", static_cast(type)); + frame = http3FrameAllocator.alloc(); + new (frame) Http3Frame(buf, len); + return Http3FrameUPtr(frame, &Http3FrameDeleter::delete_frame); + } +} + +std::shared_ptr +Http3FrameFactory::fast_create(const uint8_t *buf, size_t len) +{ + uint64_t frame_length = 0; + if (Http3Frame::length(buf, len, frame_length) == -1 || frame_length > len) { + return nullptr; + } + Http3FrameType type = Http3Frame::type(buf, len); + if (type == Http3FrameType::UNKNOWN) { + if (!this->_unknown_frame) { + this->_unknown_frame = Http3FrameFactory::create(buf, len); + } else { + this->_unknown_frame->reset(buf, len); + } + return _unknown_frame; + } + + std::shared_ptr frame = this->_reusable_frames[static_cast(type)]; + + if (frame == nullptr) { + frame = Http3FrameFactory::create(buf, len); + if (frame != nullptr) { + this->_reusable_frames[static_cast(type)] = frame; + } + } else { + frame->reset(buf, len); + } + fprintf(stderr, "%p\n", frame.get()); + + return frame; +} + +std::shared_ptr +Http3FrameFactory::fast_create(QUICStreamIO &stream_io, size_t len) +{ + uint8_t buf[65536]; + + // FIXME DATA frames can be giga bytes + ink_assert(sizeof(buf) > len); + + if (stream_io.peek(buf, sizeof(buf) < len)) { + // Return if whole frame data is not available + return nullptr; + } + return this->fast_create(buf, len); +} + +Http3HeadersFrameUPtr +Http3FrameFactory::create_headers_frame(const uint8_t *header_block, size_t header_block_len) +{ + ats_unique_buf buf = ats_unique_malloc(header_block_len); + memcpy(buf.get(), header_block, header_block_len); + + Http3HeadersFrame *frame = http3HeadersFrameAllocator.alloc(); + new (frame) Http3HeadersFrame(std::move(buf), header_block_len); + return Http3HeadersFrameUPtr(frame, &Http3FrameDeleter::delete_headers_frame); +} + +Http3DataFrameUPtr +Http3FrameFactory::create_data_frame(const uint8_t *payload, size_t payload_len) +{ + ats_unique_buf buf = ats_unique_malloc(payload_len); + memcpy(buf.get(), payload, payload_len); + + Http3DataFrame *frame = http3DataFrameAllocator.alloc(); + new (frame) Http3DataFrame(std::move(buf), payload_len); + return Http3DataFrameUPtr(frame, &Http3FrameDeleter::delete_data_frame); +} diff --git a/proxy/hq/HQFrame.h b/proxy/http3/Http3Frame.h similarity index 52% rename from proxy/hq/HQFrame.h rename to proxy/http3/Http3Frame.h index 6edd2074e85..43c21336ee0 100644 --- a/proxy/hq/HQFrame.h +++ b/proxy/http3/Http3Frame.h @@ -27,37 +27,37 @@ #include "tscore/ink_memory.h" #include "tscore/ink_assert.h" #include "QUICApplication.h" -#include "HQTypes.h" +#include "Http3Types.h" -class HQFrame +class Http3Frame { public: - HQFrame() {} - HQFrame(const uint8_t *buf, size_t len); - HQFrame(HQFrameType type); - virtual ~HQFrame() {} + Http3Frame() {} + Http3Frame(const uint8_t *buf, size_t len); + Http3Frame(Http3FrameType type); + virtual ~Http3Frame() {} uint64_t total_length() const; uint64_t length() const; - HQFrameType type() const; + Http3FrameType type() const; uint8_t flags() const; virtual void store(uint8_t *buf, size_t *len) const; virtual void reset(const uint8_t *buf, size_t len); static int length(const uint8_t *buf, size_t buf_len, uint64_t &length); - static HQFrameType type(const uint8_t *buf, size_t buf_len); + static Http3FrameType type(const uint8_t *buf, size_t buf_len); protected: uint64_t _length = 0; - HQFrameType _type = HQFrameType::UNKNOWN; + Http3FrameType _type = Http3FrameType::UNKNOWN; uint8_t _flags = 0; size_t _payload_offset = 0; }; -class HQUnknownFrame : public HQFrame +class Http3UnknownFrame : public Http3Frame { public: - HQUnknownFrame() : HQFrame() {} - HQUnknownFrame(const uint8_t *buf, size_t len); + Http3UnknownFrame() : Http3Frame() {} + Http3UnknownFrame(const uint8_t *buf, size_t len); void store(uint8_t *buf, size_t *len) const override; @@ -70,12 +70,12 @@ class HQUnknownFrame : public HQFrame // DATA Frame // -class HQDataFrame : public HQFrame +class Http3DataFrame : public Http3Frame { public: - HQDataFrame() : HQFrame() {} - HQDataFrame(const uint8_t *buf, size_t len); - HQDataFrame(ats_unique_buf payload, size_t payload_len); + Http3DataFrame() : Http3Frame() {} + Http3DataFrame(const uint8_t *buf, size_t len); + Http3DataFrame(ats_unique_buf payload, size_t payload_len); void store(uint8_t *buf, size_t *len) const override; void reset(const uint8_t *buf, size_t len) override; @@ -93,12 +93,12 @@ class HQDataFrame : public HQFrame // HEADERS Frame // -class HQHeadersFrame : public HQFrame +class Http3HeadersFrame : public Http3Frame { public: - HQHeadersFrame() : HQFrame() {} - HQHeadersFrame(const uint8_t *buf, size_t len); - HQHeadersFrame(ats_unique_buf header_block, size_t header_block_len); + Http3HeadersFrame() : Http3Frame() {} + Http3HeadersFrame(const uint8_t *buf, size_t len); + Http3HeadersFrame(ats_unique_buf header_block, size_t header_block_len); void store(uint8_t *buf, size_t *len) const override; void reset(const uint8_t *buf, size_t len) override; @@ -112,81 +112,81 @@ class HQHeadersFrame : public HQFrame size_t _header_block_len = 0; }; -using HQFrameDeleterFunc = void (*)(HQFrame *p); -using HQFrameUPtr = std::unique_ptr; -using HQDataFrameUPtr = std::unique_ptr; -using HQHeadersFrameUPtr = std::unique_ptr; +using Http3FrameDeleterFunc = void (*)(Http3Frame *p); +using Http3FrameUPtr = std::unique_ptr; +using Http3DataFrameUPtr = std::unique_ptr; +using Http3HeadersFrameUPtr = std::unique_ptr; -extern ClassAllocator hqFrameAllocator; -extern ClassAllocator hqDataFrameAllocator; -extern ClassAllocator hqHeadersFrameAllocator; +extern ClassAllocator http3FrameAllocator; +extern ClassAllocator http3DataFrameAllocator; +extern ClassAllocator http3HeadersFrameAllocator; -class HQFrameDeleter +class Http3FrameDeleter { public: static void - delete_null_frame(HQFrame *frame) + delete_null_frame(Http3Frame *frame) { ink_assert(frame == nullptr); } static void - delete_frame(HQFrame *frame) + delete_frame(Http3Frame *frame) { - frame->~HQFrame(); - hqFrameAllocator.free(static_cast(frame)); + frame->~Http3Frame(); + http3FrameAllocator.free(static_cast(frame)); } static void - delete_data_frame(HQFrame *frame) + delete_data_frame(Http3Frame *frame) { - frame->~HQFrame(); - hqDataFrameAllocator.free(static_cast(frame)); + frame->~Http3Frame(); + http3DataFrameAllocator.free(static_cast(frame)); } static void - delete_headers_frame(HQFrame *frame) + delete_headers_frame(Http3Frame *frame) { - frame->~HQFrame(); - hqHeadersFrameAllocator.free(static_cast(frame)); + frame->~Http3Frame(); + http3HeadersFrameAllocator.free(static_cast(frame)); } }; // -// HQFrameFactory +// Http3FrameFactory // -class HQFrameFactory +class Http3FrameFactory { public: /* - * This is for an empty HQFrameUPtr. + * This is for an empty Http3FrameUPtr. * Empty frames are used for variable initialization and return value of frame creation failure */ - static HQFrameUPtr create_null_frame(); + static Http3FrameUPtr create_null_frame(); /* - * This is used for creating a HQFrame object based on received data. + * This is used for creating a Http3Frame object based on received data. */ - static HQFrameUPtr create(const uint8_t *buf, size_t len); + static Http3FrameUPtr create(const uint8_t *buf, size_t len); /* * 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. */ - std::shared_ptr fast_create(QUICStreamIO &stream_io, size_t len); - std::shared_ptr fast_create(const uint8_t *buf, size_t len); + std::shared_ptr fast_create(QUICStreamIO &stream_io, size_t len); + std::shared_ptr fast_create(const uint8_t *buf, size_t len); /* * Creates a HEADERS frame. */ - static HQHeadersFrameUPtr create_headers_frame(const uint8_t *header_block, size_t header_block_len); + static Http3HeadersFrameUPtr create_headers_frame(const uint8_t *header_block, size_t header_block_len); /* * Creates a DATA frame. */ - static HQDataFrameUPtr create_data_frame(const uint8_t *data, size_t data_len); + static Http3DataFrameUPtr create_data_frame(const uint8_t *data, size_t data_len); private: - std::shared_ptr _unknown_frame = nullptr; - std::shared_ptr _reusable_frames[256] = {nullptr}; + std::shared_ptr _unknown_frame = nullptr; + std::shared_ptr _reusable_frames[256] = {nullptr}; }; diff --git a/proxy/hq/HQFrameCollector.cc b/proxy/http3/Http3FrameCollector.cc similarity index 82% rename from proxy/hq/HQFrameCollector.cc rename to proxy/http3/Http3FrameCollector.cc index c19ca194e77..9a5cda00e9e 100644 --- a/proxy/hq/HQFrameCollector.cc +++ b/proxy/http3/Http3FrameCollector.cc @@ -21,10 +21,10 @@ * limitations under the License. */ -#include "HQFrameCollector.h" +#include "Http3FrameCollector.h" -HQErrorUPtr -HQFrameCollector::on_write_ready(QUICStreamIO *stream_io, size_t &nwritten) +Http3ErrorUPtr +Http3FrameCollector::on_write_ready(QUICStreamIO *stream_io, size_t &nwritten) { bool all_done = true; uint8_t tmp[32768]; @@ -35,7 +35,7 @@ HQFrameCollector::on_write_ready(QUICStreamIO *stream_io, size_t &nwritten) continue; } size_t len = 0; - HQFrameUPtr frame = g->generate_frame(sizeof(tmp) - nwritten); + Http3FrameUPtr frame = g->generate_frame(sizeof(tmp) - nwritten); if (frame) { frame->store(tmp + nwritten, &len); nwritten += len; @@ -52,11 +52,11 @@ HQFrameCollector::on_write_ready(QUICStreamIO *stream_io, size_t &nwritten) stream_io->write_done(); } - return HQErrorUPtr(new HQNoError()); + return Http3ErrorUPtr(new Http3NoError()); } void -HQFrameCollector::add_generator(HQFrameGenerator *generator) +Http3FrameCollector::add_generator(Http3FrameGenerator *generator) { this->_generators.push_back(generator); } diff --git a/proxy/hq/HQFrameCollector.h b/proxy/http3/Http3FrameCollector.h similarity index 79% rename from proxy/hq/HQFrameCollector.h rename to proxy/http3/Http3FrameCollector.h index 8542a0a20b7..73b7c5c5ab2 100644 --- a/proxy/hq/HQFrameCollector.h +++ b/proxy/http3/Http3FrameCollector.h @@ -24,17 +24,17 @@ #pragma once #include "QUICApplication.h" -#include "HQFrame.h" -#include "HQFrameGenerator.h" +#include "Http3Frame.h" +#include "Http3FrameGenerator.h" #include -class HQFrameCollector +class Http3FrameCollector { public: - HQErrorUPtr on_write_ready(QUICStreamIO *stream_io, size_t &nread); + Http3ErrorUPtr on_write_ready(QUICStreamIO *stream_io, size_t &nread); - void add_generator(HQFrameGenerator *generator); + void add_generator(Http3FrameGenerator *generator); private: - std::vector _generators; + std::vector _generators; }; diff --git a/proxy/hq/HQFrameDispatcher.cc b/proxy/http3/Http3FrameDispatcher.cc similarity index 77% rename from proxy/hq/HQFrameDispatcher.cc rename to proxy/http3/Http3FrameDispatcher.cc index 59a393fa3de..cfbfbca2fea 100644 --- a/proxy/hq/HQFrameDispatcher.cc +++ b/proxy/http3/Http3FrameDispatcher.cc @@ -22,8 +22,8 @@ */ #include "QUICIntUtil.h" -#include "HQFrameDispatcher.h" -#include "HQDebugNames.h" +#include "Http3FrameDispatcher.h" +#include "Http3DebugNames.h" #include "tscore/Diags.h" // @@ -31,18 +31,18 @@ // void -HQFrameDispatcher::add_handler(HQFrameHandler *handler) +Http3FrameDispatcher::add_handler(Http3FrameHandler *handler) { - for (HQFrameType t : handler->interests()) { + for (Http3FrameType t : handler->interests()) { this->_handlers[static_cast(t)].push_back(handler); } } -HQErrorUPtr -HQFrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) +Http3ErrorUPtr +Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) { - std::shared_ptr frame(nullptr); - HQErrorUPtr error = HQErrorUPtr(new HQNoError()); + std::shared_ptr frame(nullptr); + Http3ErrorUPtr error = Http3ErrorUPtr(new Http3NoError()); nread = 0; while (true) { @@ -65,7 +65,7 @@ HQFrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) nread += _reading_frame_length_len; size_t dummy; if (QUICVariableInt::decode(_reading_frame_payload_len, dummy, length_buf, sizeof(length_buf)) < 0) { - error = HQErrorUPtr(new HQStreamError()); + error = Http3ErrorUPtr(new Http3StreamError()); } _reading_state = READING_PAYLOAD; } @@ -78,11 +78,11 @@ HQFrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) nread += 1 + _reading_frame_payload_len; // Type field length (1) + Payload length // Dispatch - HQFrameType type = frame->type(); - std::vector handlers = this->_handlers[static_cast(type)]; + Http3FrameType type = frame->type(); + std::vector handlers = this->_handlers[static_cast(type)]; for (auto h : handlers) { error = h->handle_frame(frame); - if (error->cls != HQErrorClass::NONE) { + if (error->cls != Http3ErrorClass::NONE) { return error; } } diff --git a/proxy/hq/HQFrameDispatcher.h b/proxy/http3/Http3FrameDispatcher.h similarity index 80% rename from proxy/hq/HQFrameDispatcher.h rename to proxy/http3/Http3FrameDispatcher.h index ced9ca65234..beaad0de543 100644 --- a/proxy/hq/HQFrameDispatcher.h +++ b/proxy/http3/Http3FrameDispatcher.h @@ -24,16 +24,16 @@ #pragma once #include "QUICApplication.h" -#include "HQFrame.h" -#include "HQFrameHandler.h" +#include "Http3Frame.h" +#include "Http3FrameHandler.h" #include -class HQFrameDispatcher +class Http3FrameDispatcher { public: - HQErrorUPtr on_read_ready(QUICStreamIO &stream_io, uint64_t &nread); + Http3ErrorUPtr on_read_ready(QUICStreamIO &stream_io, uint64_t &nread); - void add_handler(HQFrameHandler *handler); + void add_handler(Http3FrameHandler *handler); private: enum READING_STATE { @@ -43,6 +43,6 @@ class HQFrameDispatcher } _reading_state = READING_LENGTH_LEN; int64_t _reading_frame_length_len; uint64_t _reading_frame_payload_len; - HQFrameFactory _frame_factory; - std::vector _handlers[256]; + Http3FrameFactory _frame_factory; + std::vector _handlers[256]; }; diff --git a/proxy/hq/HQFrameGenerator.h b/proxy/http3/Http3FrameGenerator.h similarity index 88% rename from proxy/hq/HQFrameGenerator.h rename to proxy/http3/Http3FrameGenerator.h index 680a9ed74d1..1108d36242e 100644 --- a/proxy/hq/HQFrameGenerator.h +++ b/proxy/http3/Http3FrameGenerator.h @@ -23,10 +23,10 @@ #pragma once -class HQFrameGenerator +class Http3FrameGenerator { public: - virtual ~HQFrameGenerator(){}; - virtual HQFrameUPtr generate_frame(uint16_t max_size) = 0; + virtual ~Http3FrameGenerator(){}; + virtual Http3FrameUPtr generate_frame(uint16_t max_size) = 0; virtual bool is_done() const = 0; }; diff --git a/proxy/hq/HQFrameHandler.h b/proxy/http3/Http3FrameHandler.h similarity index 77% rename from proxy/hq/HQFrameHandler.h rename to proxy/http3/Http3FrameHandler.h index 486c3de0599..26eb6477361 100644 --- a/proxy/hq/HQFrameHandler.h +++ b/proxy/http3/Http3FrameHandler.h @@ -24,13 +24,13 @@ #pragma once #include -#include -#include +#include +#include -class HQFrameHandler +class Http3FrameHandler { public: - virtual ~HQFrameHandler(){}; - virtual std::vector interests() = 0; - virtual HQErrorUPtr handle_frame(std::shared_ptr frame) = 0; + virtual ~Http3FrameHandler(){}; + virtual std::vector interests() = 0; + virtual Http3ErrorUPtr handle_frame(std::shared_ptr frame) = 0; }; diff --git a/proxy/hq/HQHeaderFramer.cc b/proxy/http3/Http3HeaderFramer.cc similarity index 82% rename from proxy/hq/HQHeaderFramer.cc rename to proxy/http3/Http3HeaderFramer.cc index f8bf717fc99..7555fcbfeb0 100644 --- a/proxy/hq/HQHeaderFramer.cc +++ b/proxy/http3/Http3HeaderFramer.cc @@ -21,19 +21,19 @@ * limitations under the License. */ -#include "HQFrame.h" -#include "HQHeaderFramer.h" -#include "HQClientTransaction.h" +#include "Http3Frame.h" +#include "Http3HeaderFramer.h" +#include "Http3ClientTransaction.h" #include "HTTP.h" #include "I_VIO.h" -HQHeaderFramer::HQHeaderFramer(HQClientTransaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) +Http3HeaderFramer::Http3HeaderFramer(Http3ClientTransaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) { http_parser_init(&this->_http_parser); } -HQFrameUPtr -HQHeaderFramer::generate_frame(uint16_t max_size) +Http3FrameUPtr +Http3HeaderFramer::generate_frame(uint16_t max_size) { ink_assert(!this->_transaction->is_response_header_sent()); @@ -46,25 +46,25 @@ HQHeaderFramer::generate_frame(uint16_t max_size) // Create frames on demand base on max_size since we don't know how much we can write now const uint8_t *start = this->_header_block + this->_header_block_wrote; size_t len = std::min(this->_header_block_len - this->_header_block_wrote, static_cast(max_size)); - HQFrameUPtr frame = HQFrameFactory::create_headers_frame(start, len); + Http3FrameUPtr frame = Http3FrameFactory::create_headers_frame(start, len); this->_header_block_wrote += len; if (this->_header_block_len == this->_header_block_wrote) { this->_sent_all_data = true; } return frame; } else { - return HQFrameFactory::create_null_frame(); + return Http3FrameFactory::create_null_frame(); } } bool -HQHeaderFramer::is_done() const +Http3HeaderFramer::is_done() const { return this->_sent_all_data; } void -HQHeaderFramer::_generate_header_block() +Http3HeaderFramer::_generate_header_block() { // Prase response header and generate header block int bytes_used = 0; @@ -85,7 +85,7 @@ HQHeaderFramer::_generate_header_block() } void -HQHeaderFramer::_compress_header() +Http3HeaderFramer::_compress_header() { // TODO Compress the header data // Just copy the header data for now. diff --git a/proxy/hq/HQHeaderFramer.h b/proxy/http3/Http3HeaderFramer.h similarity index 78% rename from proxy/hq/HQHeaderFramer.h rename to proxy/http3/Http3HeaderFramer.h index b719efa3e06..5df85bac6bf 100644 --- a/proxy/hq/HQHeaderFramer.h +++ b/proxy/http3/Http3HeaderFramer.h @@ -23,24 +23,24 @@ #pragma once -#include "HQFrameGenerator.h" -#include "HQFrame.h" +#include "Http3FrameGenerator.h" +#include "Http3Frame.h" #include "hdrs/HTTP.h" -class HQClientTransaction; +class Http3ClientTransaction; class VIO; -class HQHeaderFramer : public HQFrameGenerator +class Http3HeaderFramer : public Http3FrameGenerator { public: - HQHeaderFramer(HQClientTransaction *transaction, VIO *source); + Http3HeaderFramer(Http3ClientTransaction *transaction, VIO *source); - // HQFrameGenerator - HQFrameUPtr generate_frame(uint16_t max_size) override; + // Http3FrameGenerator + Http3FrameUPtr generate_frame(uint16_t max_size) override; bool is_done() const override; private: - HQClientTransaction *_transaction = nullptr; + Http3ClientTransaction *_transaction = nullptr; VIO *_source_vio = nullptr; HTTPParser _http_parser; HTTPHdr _header; diff --git a/proxy/hq/HQHeaderVIOAdaptor.cc b/proxy/http3/Http3HeaderVIOAdaptor.cc similarity index 69% rename from proxy/hq/HQHeaderVIOAdaptor.cc rename to proxy/http3/Http3HeaderVIOAdaptor.cc index 0c44d81f8fa..db7de9cca95 100644 --- a/proxy/hq/HQHeaderVIOAdaptor.cc +++ b/proxy/http3/Http3HeaderVIOAdaptor.cc @@ -21,22 +21,22 @@ limitations under the License. */ -#include "HQHeaderVIOAdaptor.h" +#include "Http3HeaderVIOAdaptor.h" #include "I_VIO.h" -HQHeaderVIOAdaptor::HQHeaderVIOAdaptor(VIO *sink) : _sink_vio(sink) {} +Http3HeaderVIOAdaptor::Http3HeaderVIOAdaptor(VIO *sink) : _sink_vio(sink) {} -std::vector -HQHeaderVIOAdaptor::interests() +std::vector +Http3HeaderVIOAdaptor::interests() { - return {HQFrameType::HEADERS}; + return {Http3FrameType::HEADERS}; } -HQErrorUPtr -HQHeaderVIOAdaptor::handle_frame(std::shared_ptr frame) +Http3ErrorUPtr +Http3HeaderVIOAdaptor::handle_frame(std::shared_ptr frame) { - ink_assert(frame->type() == HQFrameType::HEADERS); - const HQHeadersFrame *hframe = dynamic_cast(frame.get()); + ink_assert(frame->type() == Http3FrameType::HEADERS); + const Http3HeadersFrame *hframe = dynamic_cast(frame.get()); SCOPED_MUTEX_LOCK(lock, this->_sink_vio->mutex, this_ethread()); @@ -44,5 +44,5 @@ HQHeaderVIOAdaptor::handle_frame(std::shared_ptr frame) // TODO Uncompress header block writer->write(hframe->header_block(), hframe->header_block_length()); - return HQErrorUPtr(new HQNoError()); + return Http3ErrorUPtr(new Http3NoError()); } diff --git a/proxy/hq/HQHeaderVIOAdaptor.h b/proxy/http3/Http3HeaderVIOAdaptor.h similarity index 77% rename from proxy/hq/HQHeaderVIOAdaptor.h rename to proxy/http3/Http3HeaderVIOAdaptor.h index 0ec8c79d346..0a497feefe7 100644 --- a/proxy/hq/HQHeaderVIOAdaptor.h +++ b/proxy/http3/Http3HeaderVIOAdaptor.h @@ -23,18 +23,18 @@ #pragma once -#include "HQFrameHandler.h" +#include "Http3FrameHandler.h" class VIO; -class HQHeaderVIOAdaptor : public HQFrameHandler +class Http3HeaderVIOAdaptor : public Http3FrameHandler { public: - HQHeaderVIOAdaptor(VIO *sink); + Http3HeaderVIOAdaptor(VIO *sink); - // HQFrameHandler - std::vector interests() override; - HQErrorUPtr handle_frame(std::shared_ptr frame) override; + // Http3FrameHandler + std::vector interests() override; + Http3ErrorUPtr handle_frame(std::shared_ptr frame) override; private: VIO *_sink_vio = nullptr; diff --git a/proxy/hq/HQSessionAccept.cc b/proxy/http3/Http3SessionAccept.cc similarity index 80% rename from proxy/hq/HQSessionAccept.cc rename to proxy/http3/Http3SessionAccept.cc index e16b6c5304c..5db8abb08ef 100644 --- a/proxy/hq/HQSessionAccept.cc +++ b/proxy/http3/Http3SessionAccept.cc @@ -21,22 +21,22 @@ limitations under the License. */ -#include "HQSessionAccept.h" +#include "Http3SessionAccept.h" #include "P_Net.h" #include "I_Machine.h" #include "IPAllow.h" #include "QUICSimpleApp.h" -HQSessionAccept::HQSessionAccept(const HttpSessionAccept::Options &_o) : SessionAccept(nullptr), options(_o) +Http3SessionAccept::Http3SessionAccept(const HttpSessionAccept::Options &_o) : SessionAccept(nullptr), options(_o) { - SET_HANDLER(&HQSessionAccept::mainEvent); + SET_HANDLER(&Http3SessionAccept::mainEvent); } -HQSessionAccept::~HQSessionAccept() {} +Http3SessionAccept::~Http3SessionAccept() {} bool -HQSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader *reader) +Http3SessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader *reader) { sockaddr const *client_ip = netvc->get_remote_addr(); IpAllow::ACL session_acl = IpAllow::match(client_ip, IpAllow::SRC_ADDR); @@ -48,10 +48,10 @@ HQSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader netvc->attributes = this->options.transport_type; - if (is_debug_tag_set("hq")) { + if (is_debug_tag_set("http3")) { ip_port_text_buffer ipb; - Debug("hq", "[%s] accepted connection from %s transport type = %d", + Debug("http3", "[%s] accepted connection from %s transport type = %d", static_cast(static_cast(netvc))->cids().data(), ats_ip_nptop(client_ip, ipb, sizeof(ipb)), netvc->attributes); } @@ -62,7 +62,7 @@ HQSessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferReader } int -HQSessionAccept::mainEvent(int event, void *data) +Http3SessionAccept::mainEvent(int event, void *data) { NetVConnection *netvc; ink_release_assert(event == NET_EVENT_ACCEPT || event == EVENT_ERROR); diff --git a/proxy/hq/HQSessionAccept.h b/proxy/http3/Http3SessionAccept.h similarity index 86% rename from proxy/hq/HQSessionAccept.h rename to proxy/http3/Http3SessionAccept.h index d17aa5e76d0..8bb388e3daf 100644 --- a/proxy/hq/HQSessionAccept.h +++ b/proxy/http3/Http3SessionAccept.h @@ -38,18 +38,18 @@ // // CONFIG proxy.config.http.server_ports STRING 443:quic -class HQSessionAccept : public SessionAccept +class Http3SessionAccept : public SessionAccept { public: - explicit HQSessionAccept(const HttpSessionAccept::Options &); - ~HQSessionAccept(); + explicit Http3SessionAccept(const HttpSessionAccept::Options &); + ~Http3SessionAccept(); bool accept(NetVConnection *, MIOBuffer *, IOBufferReader *); int mainEvent(int event, void *netvc); private: - HQSessionAccept(const HQSessionAccept &); - HQSessionAccept &operator=(const HQSessionAccept &); + Http3SessionAccept(const Http3SessionAccept &); + Http3SessionAccept &operator=(const Http3SessionAccept &); HttpSessionAccept::Options options; }; diff --git a/proxy/hq/HQStreamDataVIOAdaptor.cc b/proxy/http3/Http3StreamDataVIOAdaptor.cc similarity index 68% rename from proxy/hq/HQStreamDataVIOAdaptor.cc rename to proxy/http3/Http3StreamDataVIOAdaptor.cc index 675b3c3ceed..e5b6875c209 100644 --- a/proxy/hq/HQStreamDataVIOAdaptor.cc +++ b/proxy/http3/Http3StreamDataVIOAdaptor.cc @@ -21,27 +21,27 @@ limitations under the License. */ -#include "HQStreamDataVIOAdaptor.h" +#include "Http3StreamDataVIOAdaptor.h" #include "I_VIO.h" -HQStreamDataVIOAdaptor::HQStreamDataVIOAdaptor(VIO *sink) : _sink_vio(sink) {} +Http3StreamDataVIOAdaptor::Http3StreamDataVIOAdaptor(VIO *sink) : _sink_vio(sink) {} -std::vector -HQStreamDataVIOAdaptor::interests() +std::vector +Http3StreamDataVIOAdaptor::interests() { - return {HQFrameType::DATA}; + return {Http3FrameType::DATA}; } -HQErrorUPtr -HQStreamDataVIOAdaptor::handle_frame(std::shared_ptr frame) +Http3ErrorUPtr +Http3StreamDataVIOAdaptor::handle_frame(std::shared_ptr frame) { - ink_assert(frame->type() == HQFrameType::DATA); - const HQDataFrame *dframe = dynamic_cast(frame.get()); + ink_assert(frame->type() == Http3FrameType::DATA); + const Http3DataFrame *dframe = dynamic_cast(frame.get()); SCOPED_MUTEX_LOCK(lock, this->_sink_vio->mutex, this_ethread()); MIOBuffer *writer = this->_sink_vio->get_writer(); writer->write(dframe->payload(), dframe->payload_length()); - return HQErrorUPtr(new HQNoError()); + return Http3ErrorUPtr(new Http3NoError()); } diff --git a/proxy/hq/HQStreamDataVIOAdaptor.h b/proxy/http3/Http3StreamDataVIOAdaptor.h similarity index 76% rename from proxy/hq/HQStreamDataVIOAdaptor.h rename to proxy/http3/Http3StreamDataVIOAdaptor.h index d3f79684c6a..f62fd319c64 100644 --- a/proxy/hq/HQStreamDataVIOAdaptor.h +++ b/proxy/http3/Http3StreamDataVIOAdaptor.h @@ -23,18 +23,18 @@ #pragma once -#include "HQFrameHandler.h" +#include "Http3FrameHandler.h" class VIO; -class HQStreamDataVIOAdaptor : public HQFrameHandler +class Http3StreamDataVIOAdaptor : public Http3FrameHandler { public: - HQStreamDataVIOAdaptor(VIO *sink); + Http3StreamDataVIOAdaptor(VIO *sink); - // HQFrameHandler - std::vector interests() override; - HQErrorUPtr handle_frame(std::shared_ptr frame) override; + // Http3FrameHandler + std::vector interests() override; + Http3ErrorUPtr handle_frame(std::shared_ptr frame) override; private: VIO *_sink_vio = nullptr; diff --git a/proxy/hq/HQTypes.h b/proxy/http3/Http3Types.h similarity index 53% rename from proxy/hq/HQTypes.h rename to proxy/http3/Http3Types.h index 9b9d12b8596..e48ab599325 100644 --- a/proxy/hq/HQTypes.h +++ b/proxy/http3/Http3Types.h @@ -27,8 +27,8 @@ #include -// Update HQFrame::type(const uint8_t *) too when you modify this list -enum class HQFrameType : uint8_t { +// Update Http3Frame::type(const uint8_t *) too when you modify this list +enum class Http3FrameType : uint8_t { DATA = 0x00, HEADERS = 0x01, PRIORITY = 0x02, @@ -44,56 +44,56 @@ enum class HQFrameType : uint8_t { UNKNOWN = 0xFF, }; -enum class HQErrorClass { +enum class Http3ErrorClass { NONE, APPLICATION, }; -using HQAppErrorCode = uint16_t; +using Http3AppErrorCode = uint16_t; -class HQError +class Http3Error { public: - virtual ~HQError() {} + virtual ~Http3Error() {} uint16_t code(); - HQErrorClass cls = HQErrorClass::NONE; + Http3ErrorClass cls = Http3ErrorClass::NONE; union { - HQAppErrorCode app_error_code; + Http3AppErrorCode app_error_code; }; const char *msg = nullptr; protected: - HQError(){}; - HQError(const HQAppErrorCode error_code, const char *error_msg = nullptr) - : cls(HQErrorClass::APPLICATION), app_error_code(error_code), msg(error_msg){}; + Http3Error(){}; + Http3Error(const Http3AppErrorCode error_code, const char *error_msg = nullptr) + : cls(Http3ErrorClass::APPLICATION), app_error_code(error_code), msg(error_msg){}; }; -class HQNoError : public HQError +class Http3NoError : public Http3Error { public: - HQNoError() : HQError() {} + Http3NoError() : Http3Error() {} }; -class HQConnectionError : public HQError +class Http3ConnectionError : public Http3Error { public: - HQConnectionError() : HQError() {} - HQConnectionError(const HQAppErrorCode error_code, const char *error_msg = nullptr) : HQError(error_code, error_msg){}; + Http3ConnectionError() : Http3Error() {} + Http3ConnectionError(const Http3AppErrorCode error_code, const char *error_msg = nullptr) : Http3Error(error_code, error_msg){}; }; -class HQStream; +class Http3Stream; -class HQStreamError : public HQError +class Http3StreamError : public Http3Error { public: - HQStreamError() : HQError() {} - HQStreamError(HQStream *s, const HQAppErrorCode error_code, const char *error_msg = nullptr) - : HQError(error_code, error_msg), stream(s){}; + Http3StreamError() : Http3Error() {} + Http3StreamError(Http3Stream *s, const Http3AppErrorCode error_code, const char *error_msg = nullptr) + : Http3Error(error_code, error_msg), stream(s){}; - HQStream *stream; + Http3Stream *stream; }; -using HQErrorUPtr = std::unique_ptr; -using HQConnectionErrorUPtr = std::unique_ptr; -using HQStreamErrorUPtr = std::unique_ptr; +using Http3ErrorUPtr = std::unique_ptr; +using Http3ConnectionErrorUPtr = std::unique_ptr; +using Http3StreamErrorUPtr = std::unique_ptr; diff --git a/proxy/hq/Makefile.am b/proxy/http3/Makefile.am similarity index 77% rename from proxy/hq/Makefile.am rename to proxy/http3/Makefile.am index ce785ad7f40..8c2b3adc8f7 100644 --- a/proxy/hq/Makefile.am +++ b/proxy/http3/Makefile.am @@ -31,20 +31,20 @@ AM_CPPFLAGS += \ -I$(abs_top_srcdir)/proxy/http/remap \ $(TS_INCLUDES) -noinst_LIBRARIES = libhq.a +noinst_LIBRARIES = libhttp3.a -libhq_a_SOURCES = \ - HQ.cc \ - HQSessionAccept.cc \ - HQClientSession.cc \ - HQClientTransaction.cc \ - HQFrame.cc \ - HQFrameCollector.cc \ - HQFrameDispatcher.cc \ - HQHeaderFramer.cc \ - HQDataFramer.cc \ - HQHeaderVIOAdaptor.cc \ - HQStreamDataVIOAdaptor.cc \ +libhttp3_a_SOURCES = \ + Http3.cc \ + Http3SessionAccept.cc \ + Http3ClientSession.cc \ + Http3ClientTransaction.cc \ + Http3Frame.cc \ + Http3FrameCollector.cc \ + Http3FrameDispatcher.cc \ + Http3HeaderFramer.cc \ + Http3DataFramer.cc \ + Http3HeaderVIOAdaptor.cc \ + Http3StreamDataVIOAdaptor.cc \ QPACK.cc \ QUICSimpleApp.cc @@ -52,25 +52,25 @@ libhq_a_SOURCES = \ # Check Programs # check_PROGRAMS = \ - test_libhq \ + test_libhttp3 \ test_qpack TESTS = $(check_PROGRAMS) -test_libhq_CPPFLAGS = \ +test_libhttp3_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(abs_top_srcdir)/tests/include -test_libhq_LDFLAGS = \ +test_libhttp3_LDFLAGS = \ @AM_LDFLAGS@ -test_libhq_SOURCES = \ +test_libhttp3_SOURCES = \ ./test/main.cc \ - ./test/test_HQFrame.cc \ - ./test/test_HQFrameDispatcher.cc + ./test/test_Http3Frame.cc \ + ./test/test_Http3FrameDispatcher.cc -test_libhq_LDADD = \ - libhq.a \ +test_libhttp3_LDADD = \ + libhttp3.a \ $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/src/tscore/libtscore.la @@ -83,8 +83,8 @@ test_qpack_LDFLAGS = \ test_qpack_SOURCES = \ ./test/main_qpack.cc \ - ./test/test_HQFrame.cc \ - ./test/test_HQFrameDispatcher.cc \ + ./test/test_Http3Frame.cc \ + ./test/test_Http3FrameDispatcher.cc \ ./test/test_QPACK.cc \ ../http/HttpConfig.cc \ ../http/HttpConnectionCount.cc \ @@ -92,7 +92,7 @@ test_qpack_SOURCES = \ ./test/stub.cc test_qpack_LDADD = \ - libhq.a \ + libhttp3.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ @@ -107,5 +107,5 @@ test_qpack_LDADD = \ # include $(top_srcdir)/build/tidy.mk -tidy-local: $(libhq_a_SOURCES) \ +tidy-local: $(libhttp3_a_SOURCES) \ $(CXX_Clang_Tidy) diff --git a/proxy/hq/QPACK.cc b/proxy/http3/QPACK.cc similarity index 100% rename from proxy/hq/QPACK.cc rename to proxy/http3/QPACK.cc diff --git a/proxy/hq/QPACK.h b/proxy/http3/QPACK.h similarity index 99% rename from proxy/hq/QPACK.h rename to proxy/http3/QPACK.h index dc255408f3c..82a65874d8c 100644 --- a/proxy/hq/QPACK.h +++ b/proxy/http3/QPACK.h @@ -36,7 +36,7 @@ enum { QPACK_EVENT_DECODE_FAILED, }; -// FIXME This setting should be passed by HQ +// FIXME This setting should be passed by HTTP/3 constexpr int SETTINGS_HEADER_TABLE_SIZE = 4096; constexpr int SETTINGS_QPACK_BLOCKED_STREAMS = 100; diff --git a/proxy/hq/QUICSimpleApp.cc b/proxy/http3/QUICSimpleApp.cc similarity index 90% rename from proxy/hq/QUICSimpleApp.cc rename to proxy/http3/QUICSimpleApp.cc index d2f20e33a03..1a46fd4f85e 100644 --- a/proxy/hq/QUICSimpleApp.cc +++ b/proxy/http3/QUICSimpleApp.cc @@ -27,15 +27,15 @@ #include "P_VConnection.h" #include "QUICDebugNames.h" -#include "HQClientSession.h" -#include "HQClientTransaction.h" +#include "Http3ClientSession.h" +#include "Http3ClientTransaction.h" static constexpr char tag[] = "quic_simple_app"; static constexpr char tag_v[] = "v_quic_simple_app"; QUICSimpleApp::QUICSimpleApp(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QUICApplication(client_vc) { - this->_client_session = new HQClientSession(client_vc); + this->_client_session = new Http3ClientSession(client_vc); this->_client_session->acl = std::move(session_acl); this->_client_session->new_connection(client_vc, nullptr, nullptr, false); @@ -63,7 +63,7 @@ QUICSimpleApp::main_event_handler(int event, Event *data) } QUICStreamId stream_id = stream_io->stream_id(); - HQClientTransaction *txn = this->_client_session->get_transaction(stream_id); + Http3ClientTransaction *txn = this->_client_session->get_transaction(stream_id); uint8_t dummy; switch (event) { @@ -71,7 +71,7 @@ QUICSimpleApp::main_event_handler(int event, Event *data) case VC_EVENT_READ_COMPLETE: if (stream_io->peek(&dummy, 1)) { if (txn == nullptr) { - txn = new HQClientTransaction(this->_client_session, stream_io); + txn = new Http3ClientTransaction(this->_client_session, stream_io); SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); txn->new_transaction(); diff --git a/proxy/hq/QUICSimpleApp.h b/proxy/http3/QUICSimpleApp.h similarity index 94% rename from proxy/hq/QUICSimpleApp.h rename to proxy/http3/QUICSimpleApp.h index 492aed30781..fcb9c9a131f 100644 --- a/proxy/hq/QUICSimpleApp.h +++ b/proxy/http3/QUICSimpleApp.h @@ -28,7 +28,7 @@ #include "QUICApplication.h" class QUICNetVConnection; -class HQClientSession; +class Http3ClientSession; /** * @brief A simple multi-streamed application. @@ -44,5 +44,5 @@ class QUICSimpleApp : public QUICApplication int main_event_handler(int event, Event *data); private: - HQClientSession *_client_session = nullptr; + Http3ClientSession *_client_session = nullptr; }; diff --git a/proxy/hq/test/Mock.h b/proxy/http3/test/Mock.h similarity index 77% rename from proxy/hq/test/Mock.h rename to proxy/http3/test/Mock.h index 3e7090e9797..2b02ed014c2 100644 --- a/proxy/hq/test/Mock.h +++ b/proxy/http3/test/Mock.h @@ -23,25 +23,25 @@ #include "catch.hpp" -#include "HQFrameHandler.h" +#include "Http3FrameHandler.h" -class HQMockFrameHandler : public HQFrameHandler +class Http3MockFrameHandler : public Http3FrameHandler { public: int total_frame_received = 0; - // HQFrameHandler + // Http3FrameHandler - std::vector + std::vector interests() override { - return {HQFrameType::DATA}; + return {Http3FrameType::DATA}; } - HQErrorUPtr - handle_frame(std::shared_ptr frame) override + Http3ErrorUPtr + handle_frame(std::shared_ptr frame) override { this->total_frame_received++; - return HQErrorUPtr(new HQNoError()); + return Http3ErrorUPtr(new Http3NoError()); } }; diff --git a/proxy/hq/test/main.cc b/proxy/http3/test/main.cc similarity index 100% rename from proxy/hq/test/main.cc rename to proxy/http3/test/main.cc diff --git a/proxy/hq/test/main_qpack.cc b/proxy/http3/test/main_qpack.cc similarity index 100% rename from proxy/hq/test/main_qpack.cc rename to proxy/http3/test/main_qpack.cc diff --git a/proxy/hq/test/stub.cc b/proxy/http3/test/stub.cc similarity index 100% rename from proxy/hq/test/stub.cc rename to proxy/http3/test/stub.cc diff --git a/proxy/hq/test/test_HQFrame.cc b/proxy/http3/test/test_Http3Frame.cc similarity index 62% rename from proxy/hq/test/test_HQFrame.cc rename to proxy/http3/test/test_Http3Frame.cc index 061061b8063..b7aeccd3f16 100644 --- a/proxy/hq/test/test_HQFrame.cc +++ b/proxy/http3/test/test_Http3Frame.cc @@ -23,18 +23,18 @@ #include "catch.hpp" #include -#include "HQFrame.h" -#include "HQFrameDispatcher.h" +#include "Http3Frame.h" +#include "Http3FrameDispatcher.h" -TEST_CASE("HQFrame Type", "[hq]") +TEST_CASE("Http3Frame Type", "[http3]") { - CHECK(HQFrame::type(reinterpret_cast("\x00\x00"), 2) == HQFrameType::DATA); + CHECK(Http3Frame::type(reinterpret_cast("\x00\x00"), 2) == Http3FrameType::DATA); // Undefined ragne - CHECK(HQFrame::type(reinterpret_cast("\x00\x0e"), 2) == HQFrameType::UNKNOWN); - CHECK(HQFrame::type(reinterpret_cast("\x00\xff"), 2) == HQFrameType::UNKNOWN); + CHECK(Http3Frame::type(reinterpret_cast("\x00\x0e"), 2) == Http3FrameType::UNKNOWN); + CHECK(Http3Frame::type(reinterpret_cast("\x00\xff"), 2) == Http3FrameType::UNKNOWN); } -TEST_CASE("Load DATA Frame", "[hq]") +TEST_CASE("Load DATA Frame", "[http3]") { SECTION("No flags") { @@ -44,10 +44,10 @@ TEST_CASE("Load DATA Frame", "[hq]") 0x00, // Flags 0x11, 0x22, 0x33, 0x44, // Payload }; - std::shared_ptr frame1 = HQFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == HQFrameType::DATA); + std::shared_ptr frame1 = Http3FrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == Http3FrameType::DATA); CHECK(frame1->length() == 4); - std::shared_ptr data_frame = std::dynamic_pointer_cast(frame1); + std::shared_ptr data_frame = std::dynamic_pointer_cast(frame1); CHECK(data_frame); CHECK(data_frame->payload_length() == 4); CHECK(memcmp(data_frame->payload(), "\x11\x22\x33\x44", 4) == 0); @@ -61,17 +61,17 @@ TEST_CASE("Load DATA Frame", "[hq]") 0xff, // Flags 0x11, 0x22, 0x33, 0x44, // Payload }; - std::shared_ptr frame1 = HQFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == HQFrameType::DATA); + std::shared_ptr frame1 = Http3FrameFactory::create(buf1, sizeof(buf1)); + CHECK(frame1->type() == Http3FrameType::DATA); CHECK(frame1->length() == 4); - std::shared_ptr data_frame = std::dynamic_pointer_cast(frame1); + std::shared_ptr data_frame = std::dynamic_pointer_cast(frame1); CHECK(data_frame); CHECK(data_frame->payload_length() == 4); CHECK(memcmp(data_frame->payload(), "\x11\x22\x33\x44", 4) == 0); } } -TEST_CASE("Store DATA Frame", "[hq]") +TEST_CASE("Store DATA Frame", "[http3]") { SECTION("Normal") { @@ -88,7 +88,7 @@ TEST_CASE("Store DATA Frame", "[hq]") ats_unique_buf payload1 = ats_unique_malloc(4); memcpy(payload1.get(), raw1, 4); - HQDataFrame data_frame(std::move(payload1), 4); + Http3DataFrame data_frame(std::move(payload1), 4); CHECK(data_frame.length() == 4); data_frame.store(buf, &len); @@ -97,22 +97,22 @@ TEST_CASE("Store DATA Frame", "[hq]") } } -TEST_CASE("HQFrameFactory Create Unknown Frame", "[hq]") +TEST_CASE("Http3FrameFactory Create Unknown Frame", "[http3]") { uint8_t buf1[] = { 0x00, // Length 0xff, // Type 0x00, // Flags }; - std::shared_ptr frame1 = HQFrameFactory::create(buf1, sizeof(buf1)); + std::shared_ptr frame1 = Http3FrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1); - CHECK(frame1->type() == HQFrameType::UNKNOWN); + CHECK(frame1->type() == Http3FrameType::UNKNOWN); CHECK(frame1->length() == 0); } -TEST_CASE("HQFrameFactory Fast Create Frame", "[hq]") +TEST_CASE("Http3FrameFactory Fast Create Frame", "[http3]") { - HQFrameFactory factory; + Http3FrameFactory factory; uint8_t buf1[] = { 0x04, // Length @@ -126,30 +126,30 @@ TEST_CASE("HQFrameFactory Fast Create Frame", "[hq]") 0x00, // Flags 0xaa, 0xbb, 0xcc, 0xdd, // Payload }; - std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); + std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); CHECK(frame1 != nullptr); - std::shared_ptr data_frame1 = std::dynamic_pointer_cast(frame1); + std::shared_ptr data_frame1 = std::dynamic_pointer_cast(frame1); CHECK(data_frame1 != nullptr); CHECK(memcmp(data_frame1->payload(), buf1 + 3, 4) == 0); - std::shared_ptr frame2 = factory.fast_create(buf2, sizeof(buf2)); + std::shared_ptr frame2 = factory.fast_create(buf2, sizeof(buf2)); CHECK(frame2 != nullptr); - std::shared_ptr data_frame2 = std::dynamic_pointer_cast(frame2); + std::shared_ptr data_frame2 = std::dynamic_pointer_cast(frame2); CHECK(data_frame2 != nullptr); CHECK(memcmp(data_frame2->payload(), buf2 + 3, 4) == 0); CHECK(frame1 == frame2); } -TEST_CASE("HQFrameFactory Fast Create Unknown Frame", "[hq]") +TEST_CASE("Http3FrameFactory Fast Create Unknown Frame", "[http3]") { - HQFrameFactory factory; + Http3FrameFactory factory; uint8_t buf1[] = { 0x0f, // Type }; - std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); + std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); CHECK(frame1 == nullptr); } diff --git a/proxy/hq/test/test_HQFrameDispatcher.cc b/proxy/http3/test/test_Http3FrameDispatcher.cc similarity index 83% rename from proxy/hq/test/test_HQFrameDispatcher.cc rename to proxy/http3/test/test_Http3FrameDispatcher.cc index caf40ee21c0..3e8a1ae4966 100644 --- a/proxy/hq/test/test_HQFrameDispatcher.cc +++ b/proxy/http3/test/test_Http3FrameDispatcher.cc @@ -23,10 +23,10 @@ #include "catch.hpp" -#include "HQFrameDispatcher.h" +#include "Http3FrameDispatcher.h" #include "Mock.h" -TEST_CASE("HQFrameHandler dispatch", "[hq]") +TEST_CASE("Http3FrameHandler dispatch", "[http3]") { uint8_t input[] = {// 1st frame (HEADERS) 0x02, 0x01, 0x00, 0x01, 0x23, @@ -35,16 +35,16 @@ TEST_CASE("HQFrameHandler dispatch", "[hq]") // 3rd frame (incomplete) 0xff}; - HQFrameDispatcher hqFrameDispatcher; - HQMockFrameHandler handler; - hqFrameDispatcher.add_handler(&handler); + Http3FrameDispatcher http3FrameDispatcher; + Http3MockFrameHandler handler; + http3FrameDispatcher.add_handler(&handler); uint16_t nread = 0; // Initial state CHECK(handler.total_frame_received == 0); CHECK(nread == 0); - hqFrameDispatcher.on_read_ready(input, sizeof(input), nread); + http3FrameDispatcher.on_read_ready(input, sizeof(input), nread); CHECK(handler.total_frame_received == 1); CHECK(nread == 12); } diff --git a/proxy/hq/test/test_QPACK.cc b/proxy/http3/test/test_QPACK.cc similarity index 100% rename from proxy/hq/test/test_QPACK.cc rename to proxy/http3/test/test_QPACK.cc diff --git a/src/traffic_server/Makefile.inc b/src/traffic_server/Makefile.inc index ee6da81d876..34efa160c02 100644 --- a/src/traffic_server/Makefile.inc +++ b/src/traffic_server/Makefile.inc @@ -27,7 +27,7 @@ traffic_server_traffic_server_CPPFLAGS = \ -I$(abs_top_srcdir)/proxy \ -I$(abs_top_srcdir)/proxy/http \ -I$(abs_top_srcdir)/proxy/http2 \ - -I$(abs_top_srcdir)/proxy/hq \ + -I$(abs_top_srcdir)/proxy/http3 \ -I$(abs_top_srcdir)/proxy/logging \ -I$(abs_top_srcdir)/proxy/http/remap \ -I$(abs_top_srcdir)/proxy/hdrs \ @@ -98,6 +98,6 @@ endif if ENABLE_QUIC traffic_server_traffic_server_LDADD += \ - $(top_builddir)/proxy/hq/libhq.a \ + $(top_builddir)/proxy/http3/libhttp3.a \ $(top_builddir)/iocore/net/quic/libquic.a endif diff --git a/src/traffic_server/traffic_server.cc b/src/traffic_server/traffic_server.cc index ec22ef14760..5e124c8a33b 100644 --- a/src/traffic_server/traffic_server.cc +++ b/src/traffic_server/traffic_server.cc @@ -98,7 +98,7 @@ extern "C" int plock(int); #include "P_SSLSNI.h" #if TS_USE_QUIC == 1 -#include "HQ.h" +#include "Http3.h" #endif #include "tscore/ink_cap.h" @@ -1892,7 +1892,7 @@ main(int /* argc ATS_UNUSED */, const char **argv) Http2::init(); #if TS_USE_QUIC == 1 // Initialize HTTP/QUIC - HQ::init(); + Http3::init(); #endif if (!HttpProxyPort::loadValue(http_accept_port_descriptor)) { diff --git a/src/tscore/ink_inet.cc b/src/tscore/ink_inet.cc index 7f4fcaeb726..8a279cf2840 100644 --- a/src/tscore/ink_inet.cc +++ b/src/tscore/ink_inet.cc @@ -50,7 +50,7 @@ const std::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"sv); const std::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"sv); const std::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"sv); const std::string_view IP_PROTO_TAG_HTTP_2_0("h2"sv); // HTTP/2 over TLS -const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-12"sv); // HTTP over QUIC +const std::string_view IP_PROTO_TAG_HTTP_QUIC("h3-17"sv); // HTTP/3 over QUIC const std::string_view UNIX_PROTO_TAG{"unix"sv}; From 4f7f8586bea2e88fa651dd59b584071eba58f32b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 16 Jan 2019 16:17:16 +0900 Subject: [PATCH 1025/1313] Don't crash when H3 requests come --- iocore/net/quic/QUICApplication.cc | 6 ++++++ iocore/net/quic/QUICApplication.h | 1 + iocore/net/quic/QUICStream.cc | 6 ++++++ iocore/net/quic/QUICStream.h | 1 + proxy/http3/Http3FrameDispatcher.cc | 22 +++++++++++----------- proxy/http3/QUICSimpleApp.cc | 4 ++++ 6 files changed, 29 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index b1de71bc2de..2248361734d 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -59,6 +59,12 @@ QUICStreamIO::stream_id() const return this->_stream->id(); } +bool +QUICStreamIO::is_bidirectional() const +{ + return this->_stream->is_bidirectional(); +} + int64_t QUICStreamIO::read(uint8_t *buf, int64_t len) { diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 4930eceb144..00f75626e45 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -41,6 +41,7 @@ class QUICStreamIO virtual ~QUICStreamIO(); uint32_t stream_id() const; + bool is_bidirectional() const; int64_t read(uint8_t *buf, int64_t len); int64_t peek(uint8_t *buf, int64_t len); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 0677c18173f..fd46d4a63b2 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -88,6 +88,12 @@ QUICStream::connection_info() const return this->_connection_info; } +bool +QUICStream::is_bidirectional() const +{ + return this->_id < 0x02; +} + QUICOffset QUICStream::final_offset() const { diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 6f486d4fafa..be61d2bcc4f 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -59,6 +59,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra QUICStreamId id() const; const QUICConnectionInfoProvider *connection_info() const; + bool is_bidirectional() const; QUICOffset final_offset() const; // Implement VConnection Interface. diff --git a/proxy/http3/Http3FrameDispatcher.cc b/proxy/http3/Http3FrameDispatcher.cc index cfbfbca2fea..af8c91a0b88 100644 --- a/proxy/http3/Http3FrameDispatcher.cc +++ b/proxy/http3/Http3FrameDispatcher.cc @@ -46,36 +46,36 @@ Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) nread = 0; while (true) { - if (_reading_state == READING_LENGTH_LEN) { + if (this->_reading_state == READING_LENGTH_LEN) { // Read a length of Length field uint8_t head; if (stream_io.peek(&head, 1) <= 0) { break; } - _reading_frame_length_len = QUICVariableInt::size(&head); - _reading_state = READING_PAYLOAD_LEN; + this->_reading_frame_length_len = QUICVariableInt::size(&head); + this->_reading_state = READING_PAYLOAD_LEN; } - if (_reading_state < READING_PAYLOAD_LEN) { + if (this->_reading_state == READING_PAYLOAD_LEN) { // Read a payload length uint8_t length_buf[8]; - if (stream_io.read(length_buf, _reading_frame_length_len) != _reading_frame_length_len) { + if (stream_io.read(length_buf, this->_reading_frame_length_len) != this->_reading_frame_length_len) { break; } - nread += _reading_frame_length_len; + nread += this->_reading_frame_length_len; size_t dummy; - if (QUICVariableInt::decode(_reading_frame_payload_len, dummy, length_buf, sizeof(length_buf)) < 0) { + if (QUICVariableInt::decode(this->_reading_frame_payload_len, dummy, length_buf, sizeof(length_buf)) < 0) { error = Http3ErrorUPtr(new Http3StreamError()); } - _reading_state = READING_PAYLOAD; + this->_reading_state = READING_PAYLOAD; } // Create a frame - frame = this->_frame_factory.fast_create(stream_io, _reading_frame_payload_len); + frame = this->_frame_factory.fast_create(stream_io, this->_reading_frame_payload_len); if (frame == nullptr) { break; } - nread += 1 + _reading_frame_payload_len; // Type field length (1) + Payload length + nread += 1 + this->_reading_frame_payload_len; // Type field length (1) + Payload length // Dispatch Http3FrameType type = frame->type(); @@ -86,7 +86,7 @@ Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) return error; } } - _reading_state = READING_LENGTH_LEN; + this->_reading_state = READING_LENGTH_LEN; } return error; diff --git a/proxy/http3/QUICSimpleApp.cc b/proxy/http3/QUICSimpleApp.cc index 1a46fd4f85e..6b343452cc0 100644 --- a/proxy/http3/QUICSimpleApp.cc +++ b/proxy/http3/QUICSimpleApp.cc @@ -69,6 +69,10 @@ QUICSimpleApp::main_event_handler(int event, Event *data) switch (event) { case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: + if (!stream_io->is_bidirectional()) { + // FIXME Ignore unidirectional streams for now + break; + } if (stream_io->peek(&dummy, 1)) { if (txn == nullptr) { txn = new Http3ClientTransaction(this->_client_session, stream_io); From 8697d161d6e9ec18c9ce8b9f68ba52834968b431 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 16 Jan 2019 17:33:06 +0900 Subject: [PATCH 1026/1313] Send INITIAL_MAX_STREAM_DATA_UNI --- iocore/net/quic/QUICHandshake.cc | 4 ++-- mgmt/RecordsConfig.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index d8b5752ffca..b1254d27470 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -388,8 +388,8 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve if (params->initial_max_stream_data_bidi_remote_in() != 0) { tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, params->initial_max_stream_data_bidi_remote_in()); } - if (params->initial_max_stream_data_uni_out() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, params->initial_max_stream_data_uni_out()); + if (params->initial_max_stream_data_uni_in() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, params->initial_max_stream_data_uni_in()); } if (pref_addr != nullptr) { uint8_t pref_addr_buf[QUICPreferredAddress::MAX_LEN]; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 7c66eb29b17..571f4b70cb9 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1376,7 +1376,7 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_bidi_remote_out", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_uni_in", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_uni_in", RECD_INT, "4096", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_uni_out", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , From a693553e129fe412f3904d9ed4a107bc35992ef3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 17 Jan 2019 16:29:08 +0900 Subject: [PATCH 1027/1313] Remove an unreasonable ink_assert --- proxy/http3/Http3ClientSession.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3ClientSession.cc index d87125afd41..e6e595e2d28 100644 --- a/proxy/http3/Http3ClientSession.cc +++ b/proxy/http3/Http3ClientSession.cc @@ -111,7 +111,6 @@ Http3ClientSession::get_protocol_string() const void Http3ClientSession::release(ProxyClientTransaction *trans) { - ink_assert(false); return; } From 43f8c7d3694f57b466f38b4711066ee3cb5643f4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 17 Jan 2019 16:29:47 +0900 Subject: [PATCH 1028/1313] Acquire a lock before touching NetHandler --- iocore/net/QUICNetVConnection.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 709c827a022..34eaaa4473d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -796,6 +796,8 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) ld->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); } + // FIXME I'm not sure whether we can block here, but it's needed to not crash. + SCOPED_MUTEX_LOCK(lock, this->nh->mutex, this_ethread()); if (this->nh) { this->nh->free_netvc(this); } else { From 2afb62121d27f96b65e23f34539221170376c8a4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 17 Jan 2019 16:57:13 +0900 Subject: [PATCH 1029/1313] Ignore decryption failure This closes #4134. --- iocore/net/QUICNetVConnection.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 34eaaa4473d..f1775638492 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -608,7 +608,11 @@ QUICNetVConnection::state_handshake(int event, Event *data) if (result == QUICPacketCreationResult::NOT_READY) { error = nullptr; } else if (result == QUICPacketCreationResult::FAILED) { - error = std::make_unique(QUICTransErrorCode::INTERNAL_ERROR); + // Don't make this error, and discard the packet. + // Because: + // - Attacker can terminate connections + // - It could be just an errora on lower layer + error = nullptr; } else if (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::UNSUPPORTED) { error = this->_state_handshake_process_packet(std::move(packet)); } @@ -1098,7 +1102,11 @@ QUICNetVConnection::_state_connection_established_receive_packet() do { QUICPacketUPtr p = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::FAILED) { - return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); + // Don't make this error, and discard the packet. + // Because: + // - Attacker can terminate connections + // - It could be just an errora on lower layer + continue; } else if (result == QUICPacketCreationResult::NO_PACKET) { return error; } else if (result == QUICPacketCreationResult::NOT_READY) { From ef7a22835860c0a0393790b50d1c8d55da95c32f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 17 Jan 2019 17:22:57 +0900 Subject: [PATCH 1030/1313] Print H3 frame types received --- proxy/http3/Http3DebugNames.cc | 52 +++++++++++++++++++++++++++++ proxy/http3/Http3DebugNames.h | 3 ++ proxy/http3/Http3FrameDispatcher.cc | 1 + proxy/http3/Http3Types.h | 27 +++++++-------- proxy/http3/Makefile.am | 1 + 5 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 proxy/http3/Http3DebugNames.cc diff --git a/proxy/http3/Http3DebugNames.cc b/proxy/http3/Http3DebugNames.cc new file mode 100644 index 00000000000..47eb99b60d9 --- /dev/null +++ b/proxy/http3/Http3DebugNames.cc @@ -0,0 +1,52 @@ +/** @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 "Http3DebugNames.h" +#include "Http3Types.h" + +const char * +Http3DebugNames::frame_type(Http3FrameType type) +{ + switch (type) { + case Http3FrameType::DATA: + return "DATA"; + case Http3FrameType::HEADERS: + return "HEADERS"; + case Http3FrameType::PRIORITY: + return "PRIORITY"; + case Http3FrameType::CANCEL_PUSH: + return "CANCEL_PUSH"; + case Http3FrameType::SETTINGS: + return "SETTINGS"; + case Http3FrameType::PUSH_PROMISE: + return "PUSH_PROMISE"; + case Http3FrameType::GOAWAY: + return "GOAWAY"; + case Http3FrameType::DUPLICATE_PUSH_ID: + return "DUPLICATE_PUSH_ID"; + case Http3FrameType::UNKNOWN: + default: + return "UNKNOWN"; + } +} + diff --git a/proxy/http3/Http3DebugNames.h b/proxy/http3/Http3DebugNames.h index 4a0977d71d3..558dccbb36f 100644 --- a/proxy/http3/Http3DebugNames.h +++ b/proxy/http3/Http3DebugNames.h @@ -23,7 +23,10 @@ #pragma once +#include "Http3Types.h" + class Http3DebugNames { +public: static const char *frame_type(Http3FrameType type); }; diff --git a/proxy/http3/Http3FrameDispatcher.cc b/proxy/http3/Http3FrameDispatcher.cc index af8c91a0b88..c4a305fa879 100644 --- a/proxy/http3/Http3FrameDispatcher.cc +++ b/proxy/http3/Http3FrameDispatcher.cc @@ -79,6 +79,7 @@ Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) // Dispatch Http3FrameType type = frame->type(); + Debug("http3", "[RX] | %s", Http3DebugNames::frame_type(type)); std::vector handlers = this->_handlers[static_cast(type)]; for (auto h : handlers) { error = h->handle_frame(frame); diff --git a/proxy/http3/Http3Types.h b/proxy/http3/Http3Types.h index e48ab599325..4d427794659 100644 --- a/proxy/http3/Http3Types.h +++ b/proxy/http3/Http3Types.h @@ -29,19 +29,20 @@ // Update Http3Frame::type(const uint8_t *) too when you modify this list enum class Http3FrameType : uint8_t { - DATA = 0x00, - HEADERS = 0x01, - PRIORITY = 0x02, - CANCEL_PUSH = 0x03, - SETTINGS = 0x04, - PUSH_PROMISE = 0x05, - X_RESERVED_1 = 0x06, - GOAWAY = 0x07, - HEADER_ACK = 0x08, - X_RESERVED_2 = 0x09, - MAX_PUSH_ID = 0x0D, - X_MAX_DEFINED = 0x0D, - UNKNOWN = 0xFF, + DATA = 0x00, + HEADERS = 0x01, + PRIORITY = 0x02, + CANCEL_PUSH = 0x03, + SETTINGS = 0x04, + PUSH_PROMISE = 0x05, + X_RESERVED_1 = 0x06, + GOAWAY = 0x07, + X_RESERVED_2 = 0x08, + X_RESERVED_3 = 0x09, + MAX_PUSH_ID = 0x0D, + DUPLICATE_PUSH_ID = 0x0E, + X_MAX_DEFINED = 0x0E, + UNKNOWN = 0xFF, }; enum class Http3ErrorClass { diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index 8c2b3adc8f7..2a5b89d481c 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -38,6 +38,7 @@ libhttp3_a_SOURCES = \ Http3SessionAccept.cc \ Http3ClientSession.cc \ Http3ClientTransaction.cc \ + Http3DebugNames.cc \ Http3Frame.cc \ Http3FrameCollector.cc \ Http3FrameDispatcher.cc \ From ccf5a07c2eefa8ad03b188497e2aa42eca89aacf Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 17 Jan 2019 17:24:02 +0900 Subject: [PATCH 1031/1313] Revmoed useless debug print --- proxy/http3/Http3Frame.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc index 2dd2e1a4d11..59c6b1d548d 100644 --- a/proxy/http3/Http3Frame.cc +++ b/proxy/http3/Http3Frame.cc @@ -281,7 +281,6 @@ Http3FrameFactory::fast_create(const uint8_t *buf, size_t len) } else { frame->reset(buf, len); } - fprintf(stderr, "%p\n", frame.get()); return frame; } From c27906e5806e79e96d59ba0caebcf9889f553458 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 18 Jan 2019 13:11:13 +0900 Subject: [PATCH 1032/1313] Fix building unit tests of HTTP/3 and QPACK - Remove test for libhttp3 from test_qpack - Disabled test_Http3FrameDispatcher temporally due to Http3FrameDispatcher::on_read_ready() is changed --- proxy/http3/Makefile.am | 15 +++++++++++---- proxy/http3/test/main_qpack.cc | 2 +- proxy/http3/test/stub.cc | 6 ++++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index 2a5b89d481c..aa6219dad37 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -68,12 +68,21 @@ test_libhttp3_LDFLAGS = \ test_libhttp3_SOURCES = \ ./test/main.cc \ ./test/test_Http3Frame.cc \ - ./test/test_Http3FrameDispatcher.cc + ../http/HttpConfig.cc \ + ../http/HttpConnectionCount.cc \ + ../http/ForwardedConfig.cc \ + ./test/stub.cc test_libhttp3_LDADD = \ libhttp3.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/src/tscore/libtscore.la + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/src/tscore/libtscore.la \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/proxy/libproxy.a \ + $(top_builddir)/proxy/hdrs/libhdrs.a \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a test_qpack_CPPFLAGS = \ $(AM_CPPFLAGS) \ @@ -84,8 +93,6 @@ test_qpack_LDFLAGS = \ test_qpack_SOURCES = \ ./test/main_qpack.cc \ - ./test/test_Http3Frame.cc \ - ./test/test_Http3FrameDispatcher.cc \ ./test/test_QPACK.cc \ ../http/HttpConfig.cc \ ../http/HttpConnectionCount.cc \ diff --git a/proxy/http3/test/main_qpack.cc b/proxy/http3/test/main_qpack.cc index 68d77334f51..a53b20df860 100644 --- a/proxy/http3/test/main_qpack.cc +++ b/proxy/http3/test/main_qpack.cc @@ -67,7 +67,7 @@ struct EventProcessorListener : Catch::TestEventListenerBase { QUICConfig::startup(); - ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + ink_event_system_init(EVENT_SYSTEM_MODULE_PUBLIC_VERSION); eventProcessor.start(TEST_THREADS); Thread *main_thread = new EThread; diff --git a/proxy/http3/test/stub.cc b/proxy/http3/test/stub.cc index fa860af998d..6e821003a93 100644 --- a/proxy/http3/test/stub.cc +++ b/proxy/http3/test/stub.cc @@ -24,6 +24,12 @@ #include "P_SSLConfig.h" +void +SSLConfigInit(IpMap *) +{ + return; +} + bool SSLParseCertificateConfiguration(const SSLConfigParams *, SSL_CTX *) { From 0608ab3c642874b62d81d0dc72eaeda36f115fc4 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 18 Jan 2019 13:19:16 +0900 Subject: [PATCH 1033/1313] Fix test_Http3Frame - checking frame type --- proxy/http3/test/test_Http3Frame.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/http3/test/test_Http3Frame.cc b/proxy/http3/test/test_Http3Frame.cc index b7aeccd3f16..94f8e9b3e8d 100644 --- a/proxy/http3/test/test_Http3Frame.cc +++ b/proxy/http3/test/test_Http3Frame.cc @@ -30,7 +30,7 @@ TEST_CASE("Http3Frame Type", "[http3]") { CHECK(Http3Frame::type(reinterpret_cast("\x00\x00"), 2) == Http3FrameType::DATA); // Undefined ragne - CHECK(Http3Frame::type(reinterpret_cast("\x00\x0e"), 2) == Http3FrameType::UNKNOWN); + CHECK(Http3Frame::type(reinterpret_cast("\x00\x0f"), 2) == Http3FrameType::UNKNOWN); CHECK(Http3Frame::type(reinterpret_cast("\x00\xff"), 2) == Http3FrameType::UNKNOWN); } From f846f919ed5472a36735face4e41375524227695 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 18 Jan 2019 14:16:35 +0900 Subject: [PATCH 1034/1313] draft-13: Remove flags from HTTP/3 frames --- proxy/http3/Http3Frame.cc | 13 +------------ proxy/http3/Http3Frame.h | 4 +--- proxy/http3/test/test_Http3Frame.cc | 14 +++++--------- 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc index 59c6b1d548d..5817a294669 100644 --- a/proxy/http3/Http3Frame.cc +++ b/proxy/http3/Http3Frame.cc @@ -68,11 +68,8 @@ Http3Frame::Http3Frame(const uint8_t *buf, size_t buf_len) // Type this->_type = Http3FrameType(buf[length_field_length]); - // Flags - this->_flags = buf[length_field_length + 1]; - // Payload offset - this->_payload_offset = length_field_length + 2; + this->_payload_offset = length_field_length + 1; } Http3Frame::Http3Frame(Http3FrameType type) : _type(type) {} @@ -95,12 +92,6 @@ Http3Frame::type() const return this->_type; } -uint8_t -Http3Frame::flags() const -{ - return this->_flags; -} - void Http3Frame::store(uint8_t *buf, size_t *len) const { @@ -149,7 +140,6 @@ Http3DataFrame::store(uint8_t *buf, size_t *len) const size_t written = 0; QUICVariableInt::encode(buf, UINT64_MAX, written, this->_length); buf[written++] = static_cast(this->_type); - buf[written++] = this->_flags; memcpy(buf + written, this->_payload, this->_payload_len); written += this->_payload_len; *len = written; @@ -196,7 +186,6 @@ Http3HeadersFrame::store(uint8_t *buf, size_t *len) const size_t written = 0; QUICVariableInt::encode(buf, UINT64_MAX, written, this->_length); buf[written++] = static_cast(this->_type); - buf[written++] = this->_flags; memcpy(buf + written, this->_header_block, this->_header_block_len); written += this->_header_block_len; *len = written; diff --git a/proxy/http3/Http3Frame.h b/proxy/http3/Http3Frame.h index 43c21336ee0..bd001ecf2dd 100644 --- a/proxy/http3/Http3Frame.h +++ b/proxy/http3/Http3Frame.h @@ -40,7 +40,6 @@ class Http3Frame uint64_t total_length() const; uint64_t length() const; Http3FrameType type() const; - uint8_t flags() const; virtual void store(uint8_t *buf, size_t *len) const; virtual void reset(const uint8_t *buf, size_t len); static int length(const uint8_t *buf, size_t buf_len, uint64_t &length); @@ -48,8 +47,7 @@ class Http3Frame protected: uint64_t _length = 0; - Http3FrameType _type = Http3FrameType::UNKNOWN; - uint8_t _flags = 0; + Http3FrameType _type = Http3FrameType::UNKNOWN; size_t _payload_offset = 0; }; diff --git a/proxy/http3/test/test_Http3Frame.cc b/proxy/http3/test/test_Http3Frame.cc index 94f8e9b3e8d..807f49939da 100644 --- a/proxy/http3/test/test_Http3Frame.cc +++ b/proxy/http3/test/test_Http3Frame.cc @@ -41,12 +41,12 @@ TEST_CASE("Load DATA Frame", "[http3]") uint8_t buf1[] = { 0x04, // Length 0x00, // Type - 0x00, // Flags 0x11, 0x22, 0x33, 0x44, // Payload }; std::shared_ptr frame1 = Http3FrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == Http3FrameType::DATA); CHECK(frame1->length() == 4); + std::shared_ptr data_frame = std::dynamic_pointer_cast(frame1); CHECK(data_frame); CHECK(data_frame->payload_length() == 4); @@ -58,12 +58,12 @@ TEST_CASE("Load DATA Frame", "[http3]") uint8_t buf1[] = { 0x04, // Length 0x00, // Type - 0xff, // Flags 0x11, 0x22, 0x33, 0x44, // Payload }; std::shared_ptr frame1 = Http3FrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == Http3FrameType::DATA); CHECK(frame1->length() == 4); + std::shared_ptr data_frame = std::dynamic_pointer_cast(frame1); CHECK(data_frame); CHECK(data_frame->payload_length() == 4); @@ -80,7 +80,6 @@ TEST_CASE("Store DATA Frame", "[http3]") uint8_t expected1[] = { 0x04, // Length 0x00, // Type - 0x00, // Flags 0x11, 0x22, 0x33, 0x44, // Payload }; @@ -92,7 +91,7 @@ TEST_CASE("Store DATA Frame", "[http3]") CHECK(data_frame.length() == 4); data_frame.store(buf, &len); - CHECK(len == 7); + CHECK(len == 6); CHECK(memcmp(buf, expected1, len) == 0); } } @@ -102,7 +101,6 @@ TEST_CASE("Http3FrameFactory Create Unknown Frame", "[http3]") uint8_t buf1[] = { 0x00, // Length 0xff, // Type - 0x00, // Flags }; std::shared_ptr frame1 = Http3FrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1); @@ -117,13 +115,11 @@ TEST_CASE("Http3FrameFactory Fast Create Frame", "[http3]") uint8_t buf1[] = { 0x04, // Length 0x00, // Type - 0x00, // Flags 0x11, 0x22, 0x33, 0x44, // Payload }; uint8_t buf2[] = { 0x04, // Length 0x00, // Type - 0x00, // Flags 0xaa, 0xbb, 0xcc, 0xdd, // Payload }; std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); @@ -131,14 +127,14 @@ TEST_CASE("Http3FrameFactory Fast Create Frame", "[http3]") std::shared_ptr data_frame1 = std::dynamic_pointer_cast(frame1); CHECK(data_frame1 != nullptr); - CHECK(memcmp(data_frame1->payload(), buf1 + 3, 4) == 0); + CHECK(memcmp(data_frame1->payload(), buf1 + 2, 4) == 0); std::shared_ptr frame2 = factory.fast_create(buf2, sizeof(buf2)); CHECK(frame2 != nullptr); std::shared_ptr data_frame2 = std::dynamic_pointer_cast(frame2); CHECK(data_frame2 != nullptr); - CHECK(memcmp(data_frame2->payload(), buf2 + 3, 4) == 0); + CHECK(memcmp(data_frame2->payload(), buf2 + 2, 4) == 0); CHECK(frame1 == frame2); } From 38439c9064a942905fa210a8c2ddf630eb5a203a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 18 Jan 2019 17:32:10 +0900 Subject: [PATCH 1035/1313] Support NAT rebinding scenario on connection migration --- iocore/net/QUICNetVConnection.cc | 58 +++++++++++++++++++------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index f1775638492..d16e3fc55b3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1072,13 +1072,15 @@ QUICNetVConnection::_state_connection_established_process_protected_packet(QUICP // 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) { - if (this->_alt_con_manager != nullptr && packet->destination_cid() != this->_quic_connection_id) { - if (!has_non_probing_frame) { - QUICConDebug("FIXME: Connection migration has been initiated without non-probing frames"); - } - error = this->_state_connection_established_migrate_connection(*packet); - if (error != nullptr) { - return error; + 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"); + } + error = this->_state_connection_established_migrate_connection(*packet); + if (error != nullptr) { + return error; + } } } @@ -2097,23 +2099,33 @@ QUICNetVConnection::_state_connection_established_migrate_connection(const QUICP QUICConDebug("Connection migration is initiated by remote"); } - if (this->_alt_con_manager->migrate_to(dcid, this->_reset_token)) { - // DCID of received packet is local cid - this->_update_local_cid(dcid); - - // On client side (NET_VCONNECTION_OUT), nothing to do any more - if (this->netvc_context == NET_VCONNECTION_IN) { - Connection con; - con.setRemote(&(p.from().sa)); - this->con.move(con); - - this->_update_peer_cid(this->_alt_con_manager->migrate_to_alt_cid()); - this->_validate_new_path(); - } + if (this->connection_id() == dcid) { + // On client side (NET_VCONNECTION_OUT), nothing to do any more + if (this->netvc_context == NET_VCONNECTION_IN) { + Connection con; + con.setRemote(&(p.from().sa)); + this->con.move(con); + this->_validate_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); + if (this->_alt_con_manager->migrate_to(dcid, this->_reset_token)) { + // DCID of received packet is local cid + this->_update_local_cid(dcid); + + // On client side (NET_VCONNECTION_OUT), nothing to do any more + if (this->netvc_context == NET_VCONNECTION_IN) { + Connection con; + con.setRemote(&(p.from().sa)); + this->con.move(con); + + this->_update_peer_cid(this->_alt_con_manager->migrate_to_alt_cid()); + this->_validate_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); + } } return error; From 3be7a1566a2a2633683713cfbbbe01bf89604754 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 21 Jan 2019 10:03:18 +0900 Subject: [PATCH 1036/1313] clang-format proxy/http3/ --- proxy/http3/Http3ClientTransaction.cc | 11 ++++++----- proxy/http3/Http3DataFramer.cc | 6 ++++-- proxy/http3/Http3DataFramer.h | 2 +- proxy/http3/Http3DebugNames.cc | 1 - proxy/http3/Http3FrameCollector.cc | 2 +- proxy/http3/Http3FrameDispatcher.cc | 4 ++-- proxy/http3/Http3FrameGenerator.h | 2 +- proxy/http3/Http3FrameHandler.h | 2 +- proxy/http3/Http3HeaderFramer.cc | 5 +++-- proxy/http3/Http3HeaderFramer.h | 2 +- proxy/http3/QUICSimpleApp.cc | 2 +- 11 files changed, 21 insertions(+), 18 deletions(-) diff --git a/proxy/http3/Http3ClientTransaction.cc b/proxy/http3/Http3ClientTransaction.cc index 4eaa7e270d2..009c0c62284 100644 --- a/proxy/http3/Http3ClientTransaction.cc +++ b/proxy/http3/Http3ClientTransaction.cc @@ -32,13 +32,13 @@ #include "Http3DataFramer.h" #include "HttpSM.h" -#define Http3TransDebug(fmt, ...) \ - Debug("http3_trans", "[%s] [%" PRIx32 "] " fmt, \ +#define Http3TransDebug(fmt, ...) \ + Debug("http3_trans", "[%s] [%" PRIx32 "] " fmt, \ static_cast(reinterpret_cast(this->parent->get_netvc()))->cids().data(), \ this->get_transaction_id(), ##__VA_ARGS__) -#define Http3TransVDebug(fmt, ...) \ - Debug("v_http3_trans", "[%s] [%" PRIx32 "] " fmt, \ +#define Http3TransVDebug(fmt, ...) \ + Debug("v_http3_trans", "[%s] [%" PRIx32 "] " fmt, \ static_cast(reinterpret_cast(this->parent->get_netvc()))->cids().data(), \ this->get_transaction_id(), ##__VA_ARGS__) @@ -52,7 +52,8 @@ // Debug("v_http3_trans", "len=%" PRId64 "\n%s\n", read_len, msg); // } -Http3ClientTransaction::Http3ClientTransaction(Http3ClientSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) +Http3ClientTransaction::Http3ClientTransaction(Http3ClientSession *session, QUICStreamIO *stream_io) + : super(), _stream_io(stream_io) { this->mutex = new_ProxyMutex(); this->_thread = this_ethread(); diff --git a/proxy/http3/Http3DataFramer.cc b/proxy/http3/Http3DataFramer.cc index 3f4b6b3b8d5..5f58e9297e9 100644 --- a/proxy/http3/Http3DataFramer.cc +++ b/proxy/http3/Http3DataFramer.cc @@ -25,7 +25,9 @@ #include "Http3DataFramer.h" #include "Http3ClientTransaction.h" -Http3DataFramer::Http3DataFramer(Http3ClientTransaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) {} +Http3DataFramer::Http3DataFramer(Http3ClientTransaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) +{ +} Http3FrameUPtr Http3DataFramer::generate_frame(uint16_t max_size) @@ -34,7 +36,7 @@ Http3DataFramer::generate_frame(uint16_t max_size) return Http3FrameFactory::create_null_frame(); } - Http3FrameUPtr frame = Http3FrameFactory::create_null_frame(); + Http3FrameUPtr frame = Http3FrameFactory::create_null_frame(); IOBufferReader *reader = this->_source_vio->get_reader(); size_t len = std::min(reader->read_avail(), static_cast(max_size)); if (len) { diff --git a/proxy/http3/Http3DataFramer.h b/proxy/http3/Http3DataFramer.h index 8d288192617..ded46293d02 100644 --- a/proxy/http3/Http3DataFramer.h +++ b/proxy/http3/Http3DataFramer.h @@ -40,5 +40,5 @@ class Http3DataFramer : public Http3FrameGenerator private: Http3ClientTransaction *_transaction = nullptr; - VIO *_source_vio = nullptr; + VIO *_source_vio = nullptr; }; diff --git a/proxy/http3/Http3DebugNames.cc b/proxy/http3/Http3DebugNames.cc index 47eb99b60d9..07b7d75eaa6 100644 --- a/proxy/http3/Http3DebugNames.cc +++ b/proxy/http3/Http3DebugNames.cc @@ -49,4 +49,3 @@ Http3DebugNames::frame_type(Http3FrameType type) return "UNKNOWN"; } } - diff --git a/proxy/http3/Http3FrameCollector.cc b/proxy/http3/Http3FrameCollector.cc index 9a5cda00e9e..7409bc15a5b 100644 --- a/proxy/http3/Http3FrameCollector.cc +++ b/proxy/http3/Http3FrameCollector.cc @@ -34,7 +34,7 @@ Http3FrameCollector::on_write_ready(QUICStreamIO *stream_io, size_t &nwritten) if (g->is_done()) { continue; } - size_t len = 0; + size_t len = 0; Http3FrameUPtr frame = g->generate_frame(sizeof(tmp) - nwritten); if (frame) { frame->store(tmp + nwritten, &len); diff --git a/proxy/http3/Http3FrameDispatcher.cc b/proxy/http3/Http3FrameDispatcher.cc index c4a305fa879..3c4a156f6da 100644 --- a/proxy/http3/Http3FrameDispatcher.cc +++ b/proxy/http3/Http3FrameDispatcher.cc @@ -43,7 +43,7 @@ Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) { std::shared_ptr frame(nullptr); Http3ErrorUPtr error = Http3ErrorUPtr(new Http3NoError()); - nread = 0; + nread = 0; while (true) { if (this->_reading_state == READING_LENGTH_LEN) { @@ -78,7 +78,7 @@ Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) nread += 1 + this->_reading_frame_payload_len; // Type field length (1) + Payload length // Dispatch - Http3FrameType type = frame->type(); + Http3FrameType type = frame->type(); Debug("http3", "[RX] | %s", Http3DebugNames::frame_type(type)); std::vector handlers = this->_handlers[static_cast(type)]; for (auto h : handlers) { diff --git a/proxy/http3/Http3FrameGenerator.h b/proxy/http3/Http3FrameGenerator.h index 1108d36242e..a3633d14402 100644 --- a/proxy/http3/Http3FrameGenerator.h +++ b/proxy/http3/Http3FrameGenerator.h @@ -28,5 +28,5 @@ class Http3FrameGenerator public: virtual ~Http3FrameGenerator(){}; virtual Http3FrameUPtr generate_frame(uint16_t max_size) = 0; - virtual bool is_done() const = 0; + virtual bool is_done() const = 0; }; diff --git a/proxy/http3/Http3FrameHandler.h b/proxy/http3/Http3FrameHandler.h index 26eb6477361..e3c1f97bf1a 100644 --- a/proxy/http3/Http3FrameHandler.h +++ b/proxy/http3/Http3FrameHandler.h @@ -31,6 +31,6 @@ class Http3FrameHandler { public: virtual ~Http3FrameHandler(){}; - virtual std::vector interests() = 0; + virtual std::vector interests() = 0; virtual Http3ErrorUPtr handle_frame(std::shared_ptr frame) = 0; }; diff --git a/proxy/http3/Http3HeaderFramer.cc b/proxy/http3/Http3HeaderFramer.cc index 7555fcbfeb0..f437cbe0174 100644 --- a/proxy/http3/Http3HeaderFramer.cc +++ b/proxy/http3/Http3HeaderFramer.cc @@ -27,7 +27,8 @@ #include "HTTP.h" #include "I_VIO.h" -Http3HeaderFramer::Http3HeaderFramer(Http3ClientTransaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) +Http3HeaderFramer::Http3HeaderFramer(Http3ClientTransaction *transaction, VIO *source) + : _transaction(transaction), _source_vio(source) { http_parser_init(&this->_http_parser); } @@ -46,7 +47,7 @@ Http3HeaderFramer::generate_frame(uint16_t max_size) // Create frames on demand base on max_size since we don't know how much we can write now const uint8_t *start = this->_header_block + this->_header_block_wrote; size_t len = std::min(this->_header_block_len - this->_header_block_wrote, static_cast(max_size)); - Http3FrameUPtr frame = Http3FrameFactory::create_headers_frame(start, len); + Http3FrameUPtr frame = Http3FrameFactory::create_headers_frame(start, len); this->_header_block_wrote += len; if (this->_header_block_len == this->_header_block_wrote) { this->_sent_all_data = true; diff --git a/proxy/http3/Http3HeaderFramer.h b/proxy/http3/Http3HeaderFramer.h index 5df85bac6bf..0311a2f72b1 100644 --- a/proxy/http3/Http3HeaderFramer.h +++ b/proxy/http3/Http3HeaderFramer.h @@ -41,7 +41,7 @@ class Http3HeaderFramer : public Http3FrameGenerator private: Http3ClientTransaction *_transaction = nullptr; - VIO *_source_vio = nullptr; + VIO *_source_vio = nullptr; HTTPParser _http_parser; HTTPHdr _header; uint8_t *_header_block = nullptr; diff --git a/proxy/http3/QUICSimpleApp.cc b/proxy/http3/QUICSimpleApp.cc index 6b343452cc0..fee0899075a 100644 --- a/proxy/http3/QUICSimpleApp.cc +++ b/proxy/http3/QUICSimpleApp.cc @@ -62,7 +62,7 @@ QUICSimpleApp::main_event_handler(int event, Event *data) return -1; } - QUICStreamId stream_id = stream_io->stream_id(); + QUICStreamId stream_id = stream_io->stream_id(); Http3ClientTransaction *txn = this->_client_session->get_transaction(stream_id); uint8_t dummy; From 92bf49d1e0794c2558dc683b66058dc6640bf194 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 18 Jan 2019 13:57:01 +0900 Subject: [PATCH 1037/1313] HTTP/3: Add SETTINGS frame --- proxy/http3/Http3Frame.cc | 115 ++++++++++++++++++++++++++++ proxy/http3/Http3Frame.h | 49 ++++++++++++ proxy/http3/Http3Types.h | 5 ++ proxy/http3/test/test_Http3Frame.cc | 54 +++++++++++++ 4 files changed, 223 insertions(+) diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc index 5817a294669..aa51a553048 100644 --- a/proxy/http3/Http3Frame.cc +++ b/proxy/http3/Http3Frame.cc @@ -28,6 +28,7 @@ ClassAllocator http3FrameAllocator("http3FrameAllocator"); ClassAllocator http3DataFrameAllocator("http3DataFrameAllocator"); ClassAllocator http3HeadersFrameAllocator("http3HeadersFrameAllocator"); +ClassAllocator http3SettingsFrameAllocator("http3SettingsFrameAllocator"); // // Static functions @@ -210,6 +211,116 @@ Http3HeadersFrame::header_block_length() const return this->_header_block_len; } +// +// SETTINGS Frame +// + +Http3SettingsFrame::Http3SettingsFrame(const uint8_t *buf, size_t buf_len) : Http3Frame(buf, buf_len) +{ + size_t len = this->_payload_offset; + + while (len < buf_len) { + uint16_t id = QUICIntUtil::read_nbytes_as_uint(buf + len, 2); + len += 2; + + size_t value_len = QUICVariableInt::size(buf + len); + uint64_t value = QUICIntUtil::read_QUICVariableInt(buf + len); + len += value_len; + + // Ignore any SETTINGS identifier it does not understand. + bool ignore = true; + for (const auto &known_id : Http3SettingsFrame::VALID_SETTINGS_IDS) { + if (id == static_cast(known_id)) { + ignore = false; + break; + } + } + + if (ignore) { + continue; + } + + this->_settings.insert(std::make_pair(static_cast(id), value)); + } + + if (len == buf_len) { + this->_valid = true; + } +} + +void +Http3SettingsFrame::store(uint8_t *buf, size_t *len) const +{ + uint8_t payload[Http3SettingsFrame::MAX_PAYLOAD_SIZE] = {0}; + uint8_t *p = payload; + size_t l = 0; + + for (auto &it : this->_settings) { + QUICIntUtil::write_uint_as_nbytes(static_cast(it.first), sizeof(uint16_t), p, &l); + p += l; + QUICIntUtil::write_QUICVariableInt(it.second, p, &l); + p += l; + } + + // Exercise the requirement that unknown identifiers be ignored. - 4.2.5.1. + QUICIntUtil::write_uint_as_nbytes(static_cast(Http3SettingsId::UNKNOWN), sizeof(uint16_t), p, &l); + p += l; + QUICIntUtil::write_QUICVariableInt(0, p, &l); + p += l; + + size_t written = 0; + size_t payload_len = p - payload; + + // Length + QUICVariableInt::encode(buf, UINT64_MAX, written, payload_len); + + // Type + buf[written++] = static_cast(this->_type); + + // Payload + memcpy(buf + written, payload, payload_len); + written += payload_len; + + *len = written; +} + +void +Http3SettingsFrame::reset(const uint8_t *buf, size_t len) +{ + this->~Http3SettingsFrame(); + new (this) Http3SettingsFrame(buf, len); +} + +bool +Http3SettingsFrame::is_valid() const +{ + return this->_valid; +} + +bool +Http3SettingsFrame::contains(Http3SettingsId id) const +{ + auto p = this->_settings.find(id); + return (p != this->_settings.end()); +} + +uint64_t +Http3SettingsFrame::get(Http3SettingsId id) const +{ + auto p = this->_settings.find(id); + if (p != this->_settings.end()) { + return p->second; + } + + return 0; +} + +void +Http3SettingsFrame::set(Http3SettingsId id, uint64_t value) +{ + this->_settings[id] = value; +} + // // Http3FrameFactory // @@ -234,6 +345,10 @@ Http3FrameFactory::create(const uint8_t *buf, size_t len) frame = http3DataFrameAllocator.alloc(); new (frame) Http3DataFrame(buf, len); return Http3FrameUPtr(frame, &Http3FrameDeleter::delete_data_frame); + case Http3FrameType::SETTINGS: + frame = http3SettingsFrameAllocator.alloc(); + new (frame) Http3SettingsFrame(buf, len); + return Http3FrameUPtr(frame, &Http3FrameDeleter::delete_settings_frame); default: // Unknown frame Debug("http3_frame_factory", "Unknown frame type %hhx", static_cast(type)); diff --git a/proxy/http3/Http3Frame.h b/proxy/http3/Http3Frame.h index bd001ecf2dd..36143bfe0ca 100644 --- a/proxy/http3/Http3Frame.h +++ b/proxy/http3/Http3Frame.h @@ -110,6 +110,47 @@ class Http3HeadersFrame : public Http3Frame size_t _header_block_len = 0; }; +// +// SETTINGS Frame +// + +enum class Http3SettingsId : uint16_t { + MAX_HEADER_LIST_SIZE = 0x06, + NUM_PLACEHOLDERS = 0x08, + UNKNOWN = 0x0a0a, +}; + +class Http3SettingsFrame : public Http3Frame +{ +public: + Http3SettingsFrame() : Http3Frame(Http3FrameType::SETTINGS) {} + Http3SettingsFrame(const uint8_t *buf, size_t len); + + static constexpr size_t MAX_PAYLOAD_SIZE = 60; + static constexpr std::array VALID_SETTINGS_IDS{Http3SettingsId::MAX_HEADER_LIST_SIZE, + Http3SettingsId::NUM_PLACEHOLDERS}; + + void store(uint8_t *buf, size_t *len) const override; + void reset(const uint8_t *buf, size_t len) override; + + bool is_valid() const; + + bool contains(Http3SettingsId id) const; + uint64_t get(Http3SettingsId id) const; + void set(Http3SettingsId id, uint64_t value); + +private: + std::map _settings; + // TODO: make connection error with HTTP_MALFORMED_FRAME + bool _valid = false; +}; + +using Http3FrameDeleterFunc = void (*)(Http3Frame *p); +using Http3FrameUPtr = std::unique_ptr; +using Http3DataFrameUPtr = std::unique_ptr; +using Http3HeadersFrameUPtr = std::unique_ptr; +using Http3SettingsFrameUPtr = std::unique_ptr; + using Http3FrameDeleterFunc = void (*)(Http3Frame *p); using Http3FrameUPtr = std::unique_ptr; using Http3DataFrameUPtr = std::unique_ptr; @@ -118,6 +159,7 @@ using Http3HeadersFrameUPtr = std::unique_ptr http3FrameAllocator; extern ClassAllocator http3DataFrameAllocator; extern ClassAllocator http3HeadersFrameAllocator; +extern ClassAllocator http3SettingsFrameAllocator; class Http3FrameDeleter { @@ -148,6 +190,13 @@ class Http3FrameDeleter frame->~Http3Frame(); http3HeadersFrameAllocator.free(static_cast(frame)); } + + static void + delete_settings_frame(Http3Frame *frame) + { + frame->~Http3Frame(); + http3SettingsFrameAllocator.free(static_cast(frame)); + } }; // diff --git a/proxy/http3/Http3Types.h b/proxy/http3/Http3Types.h index 4d427794659..cdd2ae0f353 100644 --- a/proxy/http3/Http3Types.h +++ b/proxy/http3/Http3Types.h @@ -27,6 +27,11 @@ #include +enum class Http3StreamType : uint8_t { + CONTROL = 0x43, + PUSH = 0x50, +}; + // Update Http3Frame::type(const uint8_t *) too when you modify this list enum class Http3FrameType : uint8_t { DATA = 0x00, diff --git a/proxy/http3/test/test_Http3Frame.cc b/proxy/http3/test/test_Http3Frame.cc index 807f49939da..38dcc17e5db 100644 --- a/proxy/http3/test/test_Http3Frame.cc +++ b/proxy/http3/test/test_Http3Frame.cc @@ -96,6 +96,60 @@ TEST_CASE("Store DATA Frame", "[http3]") } } +TEST_CASE("Load SETTINGS Frame", "[http3]") +{ + SECTION("Normal") + { + uint8_t buf[] = { + 0x0a, // Length + 0x04, // Type + 0x00, 0x06, // Identifier + 0x44, 0x00, // Value + 0x00, 0x08, // Identifier + 0x0f, // Value + 0xba, 0xba, // Identifier + 0x00, // Value + }; + + std::shared_ptr frame = Http3FrameFactory::create(buf, sizeof(buf)); + CHECK(frame->type() == Http3FrameType::SETTINGS); + CHECK(frame->length() == sizeof(buf) - 2); + + std::shared_ptr settings_frame = std::dynamic_pointer_cast(frame); + CHECK(settings_frame); + CHECK(settings_frame->is_valid()); + CHECK(settings_frame->get(Http3SettingsId::MAX_HEADER_LIST_SIZE) == 0x0400); + CHECK(settings_frame->get(Http3SettingsId::NUM_PLACEHOLDERS) == 0x0f); + } +} + +TEST_CASE("Store SETTINGS Frame", "[http3]") +{ + SECTION("Normal") + { + uint8_t expected[] = { + 0x0a, // Length + 0x04, // Type + 0x00, 0x06, // Identifier + 0x44, 0x00, // Value + 0x00, 0x08, // Identifier + 0x0f, // Value + 0x0a, 0x0a, // Identifier + 0x00, // Value + }; + + Http3SettingsFrame settings_frame; + settings_frame.set(Http3SettingsId::MAX_HEADER_LIST_SIZE, 0x0400); + settings_frame.set(Http3SettingsId::NUM_PLACEHOLDERS, 0x0f); + + uint8_t buf[32] = {0}; + size_t len; + settings_frame.store(buf, &len); + CHECK(len == sizeof(expected)); + CHECK(memcmp(buf, expected, len) == 0); + } +} + TEST_CASE("Http3FrameFactory Create Unknown Frame", "[http3]") { uint8_t buf1[] = { From ed906430e2c127ad5576377d28d47f472de66780 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 21 Jan 2019 10:19:59 +0900 Subject: [PATCH 1038/1313] Update Retry packet format --- iocore/net/QUICNetVConnection.cc | 16 +++++++------- iocore/net/quic/QUICPacket.cc | 36 +++++++------------------------- iocore/net/quic/QUICPacket.h | 2 -- 3 files changed, 16 insertions(+), 38 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index d16e3fc55b3..def4e0017bb 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1073,7 +1073,7 @@ QUICNetVConnection::_state_connection_established_process_protected_packet(QUICP // on the old path until they initiate migration. // if (packet.destination_cid() == this->_quic_connection_id && has_non_probing_frame) { 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 (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"); } @@ -2100,13 +2100,13 @@ QUICNetVConnection::_state_connection_established_migrate_connection(const QUICP } if (this->connection_id() == dcid) { - // On client side (NET_VCONNECTION_OUT), nothing to do any more - if (this->netvc_context == NET_VCONNECTION_IN) { - Connection con; - con.setRemote(&(p.from().sa)); - this->con.move(con); - this->_validate_new_path(); - } + // On client side (NET_VCONNECTION_OUT), nothing to do any more + if (this->netvc_context == NET_VCONNECTION_IN) { + Connection con; + con.setRemote(&(p.from().sa)); + this->con.move(con); + this->_validate_new_path(); + } } else { if (this->_alt_con_manager->migrate_to(dcid, this->_reset_token)) { // DCID of received packet is local cid diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 7809e179b76..817c0ca7848 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -175,9 +175,7 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf if (this->type() != QUICPacketType::VERSION_NEGOTIATION) { if (this->type() == QUICPacketType::RETRY) { - uint8_t odcil = 0; - this->_odcil(odcil, raw_buf + offset, len - offset); - ++offset; + uint8_t odcil = (raw_buf[0] & 0x0f) + 3; this->_original_dcid = {raw_buf + offset, odcil}; offset += odcil; } else { @@ -540,16 +538,13 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const if (this->_type != QUICPacketType::VERSION_NEGOTIATION) { if (this->_type == QUICPacketType::RETRY) { - std::random_device rnd; - - buf[*len] += rnd() & 0xF0; - buf[*len] = this->_original_dcid == QUICConnectionId::ZERO() ? 0 : (this->_original_dcid.length() - 3); - *len += 1; - + // Original Destination Connection ID if (this->_original_dcid != QUICConnectionId::ZERO()) { QUICTypeUtil::write_QUICConnectionId(this->_original_dcid, buf + *len, &n); *len += n; } + // ODCIL + buf[0] |= this->_original_dcid.length() - 3; } else { if (this->_type == QUICPacketType::INITIAL) { // Token Length Field @@ -575,8 +570,10 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const pn_len = 1; } - // PN Len field - QUICTypeUtil::write_QUICPacketNumberLen(pn_len, buf); + 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); @@ -591,23 +588,6 @@ QUICPacketLongHeader::store(uint8_t *buf, size_t *len) const } } -bool -QUICPacketLongHeader::_odcil(uint8_t &odcil, const uint8_t *buf, size_t buf_len) -{ - if (buf_len <= 0) { - return false; - } - - // the least significant 4 bits are odcil and the most significant 4 bits are random - odcil = buf[0]; - - if (odcil != 0) { - odcil += 3; - } - - return true; -} - // // QUICPacketShortHeader // diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 82acf4b83d1..cf30c8ca621 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -244,8 +244,6 @@ class QUICPacketLongHeader : public QUICPacketHeader static bool packet_number_offset(uint8_t &pn_offset, const uint8_t *packet, size_t packet_len); private: - bool _odcil(uint8_t &odcil, const uint8_t *buf, size_t buf_len); - QUICPacketNumber _packet_number; QUICConnectionId _destination_cid = QUICConnectionId::ZERO(); QUICConnectionId _source_cid = QUICConnectionId::ZERO(); From 0bec142021f0731fb3193f4099af9714d9b4d80a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 21 Jan 2019 14:14:08 +0900 Subject: [PATCH 1039/1313] Don't unprotect RETRY packet's header --- iocore/net/quic/QUICPacketHeaderProtector.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc index 64682238eee..7e6f9392ab5 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -87,13 +87,18 @@ QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotect bool QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected_packet_len) const { - // Do nothing if the packet is VN + // 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; + } } QUICKeyPhase phase; From 17736660076f686f6870520bcaf9dae10d5714f9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 21 Jan 2019 14:29:27 +0900 Subject: [PATCH 1040/1313] Log TPs correctly --- iocore/net/quic/QUICTransportParameters.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 175e9c03fa9..0362c3f4c5a 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -288,9 +288,10 @@ QUICTransportParameters::_print() const if (p.second->len() == 0) { Debug(tag, "%s: (no value)", QUICDebugNames::transport_parameter_id(p.first)); } else if (p.second->len() <= 8) { - Debug(tag, "%s: 0x%" PRIx64 " (%" PRIu64 ")", QUICDebugNames::transport_parameter_id(p.first), - QUICIntUtil::read_nbytes_as_uint(p.second->data(), p.second->len()), - QUICIntUtil::read_nbytes_as_uint(p.second->data(), p.second->len())); + uint64_t int_value; + size_t int_value_len; + QUICVariableInt::decode(int_value, int_value_len, p.second->data(), p.second->len()); + Debug(tag, "%s: 0x%" PRIx64 " (%" PRIu64 ")", QUICDebugNames::transport_parameter_id(p.first), int_value, int_value); } else if (p.second->len() <= 24) { char hex_str[65]; to_hex_str(hex_str, sizeof(hex_str), p.second->data(), p.second->len()); From 3f8d224220516d1570ab6acc5a205bc0dcf43057 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 21 Jan 2019 16:43:05 +0900 Subject: [PATCH 1041/1313] Fix a length check in packet protection --- iocore/net/quic/QUICPacketHeaderProtector.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc index 7e6f9392ab5..b6260bed930 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -178,7 +178,7 @@ QUICPacketHeaderProtector::_calc_sample_offset(uint8_t *sample_offset, const uin *sample_offset = 1 + dcil + 4; } - return *sample_offset + 16 < protected_packet_len; + return *sample_offset + 16 <= protected_packet_len; } bool From d18ea13a1bab7eb9935ce9f7cba29b544f793a73 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 22 Jan 2019 09:13:46 +0900 Subject: [PATCH 1042/1313] HTTP/3: Add settings id and stream type for QPACK --- proxy/http3/Http3Frame.h | 14 ++++++-------- proxy/http3/Http3Types.h | 20 ++++++++++++++++++-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/proxy/http3/Http3Frame.h b/proxy/http3/Http3Frame.h index 36143bfe0ca..1f9082dd1cf 100644 --- a/proxy/http3/Http3Frame.h +++ b/proxy/http3/Http3Frame.h @@ -114,12 +114,6 @@ class Http3HeadersFrame : public Http3Frame // SETTINGS Frame // -enum class Http3SettingsId : uint16_t { - MAX_HEADER_LIST_SIZE = 0x06, - NUM_PLACEHOLDERS = 0x08, - UNKNOWN = 0x0a0a, -}; - class Http3SettingsFrame : public Http3Frame { public: @@ -127,8 +121,12 @@ class Http3SettingsFrame : public Http3Frame Http3SettingsFrame(const uint8_t *buf, size_t len); static constexpr size_t MAX_PAYLOAD_SIZE = 60; - static constexpr std::array VALID_SETTINGS_IDS{Http3SettingsId::MAX_HEADER_LIST_SIZE, - Http3SettingsId::NUM_PLACEHOLDERS}; + static constexpr std::array VALID_SETTINGS_IDS{ + Http3SettingsId::HEADER_TABLE_SIZE, + Http3SettingsId::MAX_HEADER_LIST_SIZE, + Http3SettingsId::QPACK_BLOCKED_STREAMS, + Http3SettingsId::NUM_PLACEHOLDERS, + }; void store(uint8_t *buf, size_t *len) const override; void reset(const uint8_t *buf, size_t len) override; diff --git a/proxy/http3/Http3Types.h b/proxy/http3/Http3Types.h index cdd2ae0f353..988e94e6792 100644 --- a/proxy/http3/Http3Types.h +++ b/proxy/http3/Http3Types.h @@ -28,8 +28,24 @@ #include enum class Http3StreamType : uint8_t { - CONTROL = 0x43, - PUSH = 0x50, + CONTROL = 0x43, ///< HTTP/3 + QPACK_ENCODER = 0x48, ///< QPACK + PUSH = 0x50, ///< HTTP/3 + QPACK_DECODER = 0x68, ///< QPACK + RESERVED = 0x1F, + UNKOWN = 0xFF, +}; + +enum class Http3SettingsId : uint16_t { + HEADER_TABLE_SIZE = 0x01, ///< QPACK Settings + RESERVED_1 = 0x02, ///< HTTP/3 Settings + RESERVED_2 = 0x03, ///< HTTP/3 Settings + RESERVED_3 = 0x04, ///< HTTP/3 Settings + RESERVED_4 = 0x05, ///< HTTP/3 Settings + MAX_HEADER_LIST_SIZE = 0x06, ///< HTTP/3 Settings + QPACK_BLOCKED_STREAMS = 0x07, ///< QPACK Settings + NUM_PLACEHOLDERS = 0x08, ///< HTTP/3 Settings + UNKNOWN = 0x0A0A, }; // Update Http3Frame::type(const uint8_t *) too when you modify this list From 3bd51f16ed893687eec4827f8f5e3757f4b8de5b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 22 Jan 2019 09:18:01 +0900 Subject: [PATCH 1043/1313] HTTP/3: Add error codes --- proxy/http3/Http3Types.h | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/proxy/http3/Http3Types.h b/proxy/http3/Http3Types.h index 988e94e6792..142418fff3a 100644 --- a/proxy/http3/Http3Types.h +++ b/proxy/http3/Http3Types.h @@ -71,7 +71,34 @@ enum class Http3ErrorClass { APPLICATION, }; -using Http3AppErrorCode = uint16_t; +// Actual error code of QPACK is not decided yet on qpack-05. It will be changed. +enum class Http3ErrorCode : uint16_t { + NO_ERROR = 0x00, + WRONG_SETTING_DIRECTION = 0x01, + PUSH_REFUSED = 0x02, + INTERNAL_ERROR = 0x03, + PUSH_ALREADY_IN_CACHE = 0x04, + REQUEST_CANCELLED = 0x05, + INCOMPLETE_REQUEST = 0x06, + CONNECT_ERROR = 0x07, + EXCESSIVE_LOAD = 0x08, + VERSION_FALLBACK = 0x09, + WRONG_STREAM = 0x0A, + PUSH_LIMIT_EXCEEDED = 0x0B, + DUPLICATE_PUSH = 0x0C, + UNKNOWN_STREAM_TYPE = 0x0D, + WRONG_STREAM_COUNT = 0x0E, + CLOSED_CRITICAL_STREAM = 0x0F, + WRONG_STREAM_DIRECTION = 0x10, + EARLY_RESPONSE = 0x11, + MISSING_SETTINGS = 0x12, + UNEXPECTED_FRAME = 0x13, + QPACK_DECOMPRESSION_FAILED, ///< QPACK Error Code + QPACK_ENCODER_STREAM_ERROR, ///< QPACK Error Code + QPACK_DECODER_STREAM_ERROR, ///< QPACK Error Code + GENERAL_PROTOCOL_ERROR = 0xFF, + MALFORMED_FRAME = 0x0100, +}; class Http3Error { @@ -81,13 +108,13 @@ class Http3Error Http3ErrorClass cls = Http3ErrorClass::NONE; union { - Http3AppErrorCode app_error_code; + Http3ErrorCode app_error_code; }; const char *msg = nullptr; protected: Http3Error(){}; - Http3Error(const Http3AppErrorCode error_code, const char *error_msg = nullptr) + Http3Error(const Http3ErrorCode error_code, const char *error_msg = nullptr) : cls(Http3ErrorClass::APPLICATION), app_error_code(error_code), msg(error_msg){}; }; @@ -101,7 +128,7 @@ class Http3ConnectionError : public Http3Error { public: Http3ConnectionError() : Http3Error() {} - Http3ConnectionError(const Http3AppErrorCode error_code, const char *error_msg = nullptr) : Http3Error(error_code, error_msg){}; + Http3ConnectionError(const Http3ErrorCode error_code, const char *error_msg = nullptr) : Http3Error(error_code, error_msg){}; }; class Http3Stream; @@ -110,7 +137,7 @@ class Http3StreamError : public Http3Error { public: Http3StreamError() : Http3Error() {} - Http3StreamError(Http3Stream *s, const Http3AppErrorCode error_code, const char *error_msg = nullptr) + Http3StreamError(Http3Stream *s, const Http3ErrorCode error_code, const char *error_msg = nullptr) : Http3Error(error_code, error_msg), stream(s){}; Http3Stream *stream; From a6ee9e258d157af8266cc83ea89a2408ec6715f4 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 22 Jan 2019 09:23:30 +0900 Subject: [PATCH 1044/1313] HTTP/3: Add debug names functions for stream type, settings id, and error code --- proxy/http3/Http3DebugNames.cc | 95 ++++++++++++++++++++++++++++++++++ proxy/http3/Http3DebugNames.h | 3 ++ 2 files changed, 98 insertions(+) diff --git a/proxy/http3/Http3DebugNames.cc b/proxy/http3/Http3DebugNames.cc index 07b7d75eaa6..24baf15fde2 100644 --- a/proxy/http3/Http3DebugNames.cc +++ b/proxy/http3/Http3DebugNames.cc @@ -49,3 +49,98 @@ Http3DebugNames::frame_type(Http3FrameType type) return "UNKNOWN"; } } + +const char * +Http3DebugNames::stream_type(uint8_t type) +{ + switch (type) { + case static_cast(Http3StreamType::CONTROL): + return "CONTROL"; + case static_cast(Http3StreamType::QPACK_ENCODER): + return "QPACK_ENCODER"; + case static_cast(Http3StreamType::PUSH): + return "PUSH"; + case static_cast(Http3StreamType::QPACK_DECODER): + return "QPACK_DECODER"; + default: + return "UNKNOWN"; + } +} + +const char * +Http3DebugNames::settings_id(uint16_t id) +{ + switch (id) { + case static_cast(Http3SettingsId::HEADER_TABLE_SIZE): + return "HEADER_TABLE_SIZE"; + case static_cast(Http3SettingsId::MAX_HEADER_LIST_SIZE): + return "MAX_HEADER_LIST_SIZE"; + case static_cast(Http3SettingsId::QPACK_BLOCKED_STREAMS): + return "QPACK_BLOCKED_STREAMS"; + case static_cast(Http3SettingsId::NUM_PLACEHOLDERS): + return "NUM_PLACEHOLDERS"; + default: + return "UNKNOWN"; + } +} + +const char * +Http3DebugNames::error_code(uint16_t code) +{ + switch (code) { + case static_cast(Http3ErrorCode::NO_ERROR): + return "NO_ERROR"; + case static_cast(Http3ErrorCode::WRONG_SETTING_DIRECTION): + return "WRONG_SETTING_DIRECTION"; + case static_cast(Http3ErrorCode::PUSH_REFUSED): + return "PUSH_REFUSED"; + case static_cast(Http3ErrorCode::INTERNAL_ERROR): + return "INTERNAL_ERROR"; + case static_cast(Http3ErrorCode::PUSH_ALREADY_IN_CACHE): + return "PUSH_ALREADY_IN_CACHE"; + case static_cast(Http3ErrorCode::REQUEST_CANCELLED): + return "REQUEST_CANCELLED"; + case static_cast(Http3ErrorCode::INCOMPLETE_REQUEST): + return "INCOMPLETE_REQUEST"; + case static_cast(Http3ErrorCode::CONNECT_ERROR): + return "CONNECT_ERROR"; + case static_cast(Http3ErrorCode::EXCESSIVE_LOAD): + return "EXCESSIVE_LOAD"; + case static_cast(Http3ErrorCode::VERSION_FALLBACK): + return "VERSION_FALLBACK"; + case static_cast(Http3ErrorCode::WRONG_STREAM): + return "WRONG_STREAM"; + case static_cast(Http3ErrorCode::PUSH_LIMIT_EXCEEDED): + return "PUSH_LIMIT_EXCEEDED"; + case static_cast(Http3ErrorCode::DUPLICATE_PUSH): + return "DUPLICATE_PUSH"; + case static_cast(Http3ErrorCode::UNKNOWN_STREAM_TYPE): + return "UNKNOWN_STREAM_TYPE"; + case static_cast(Http3ErrorCode::WRONG_STREAM_COUNT): + return "WRONG_STREAM_COUNT"; + case static_cast(Http3ErrorCode::CLOSED_CRITICAL_STREAM): + return "CLOSED_CRITICAL_STREAM"; + case static_cast(Http3ErrorCode::WRONG_STREAM_DIRECTION): + return "WRONG_STREAM_DIRECTION"; + case static_cast(Http3ErrorCode::EARLY_RESPONSE): + return "EARLY_RESPONSE"; + case static_cast(Http3ErrorCode::MISSING_SETTINGS): + return "MISSING_SETTINGS"; + case static_cast(Http3ErrorCode::UNEXPECTED_FRAME): + return "UNEXPECTED_FRAME"; + case static_cast(Http3ErrorCode::QPACK_DECOMPRESSION_FAILED): + return "QPACK_DECOMPRESSION_FAILED"; + case static_cast(Http3ErrorCode::QPACK_ENCODER_STREAM_ERROR): + return "QPACK_ENCODER_STREAM_ERROR"; + case static_cast(Http3ErrorCode::QPACK_DECODER_STREAM_ERROR): + return "QPACK_DECODER_STREAM_ERROR"; + case static_cast(Http3ErrorCode::GENERAL_PROTOCOL_ERROR): + return "GENERAL_PROTOCOL_ERROR"; + default: + if (0x0100 <= code && code <= 0x01FF) { + return "MALFORMED_FRAME"; + } + + return "UNKNOWN"; + } +} diff --git a/proxy/http3/Http3DebugNames.h b/proxy/http3/Http3DebugNames.h index 558dccbb36f..bb61a81be2b 100644 --- a/proxy/http3/Http3DebugNames.h +++ b/proxy/http3/Http3DebugNames.h @@ -29,4 +29,7 @@ class Http3DebugNames { public: static const char *frame_type(Http3FrameType type); + static const char *stream_type(uint8_t type); + static const char *settings_id(uint16_t id); + static const char *error_code(uint16_t code); }; From 6d8da83264fd3a3ce510ad0d3e7476a1661f5a82 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 22 Jan 2019 12:10:49 +0900 Subject: [PATCH 1045/1313] Support ChaCha20 --- .../net/quic/QUICPacketHeaderProtector_openssl.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc b/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc index 13c318fa2d5..0a5e3dc0ac5 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc @@ -26,15 +26,22 @@ bool QUICPacketHeaderProtector::_generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *aead) const { - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + 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, aead, nullptr, key, sample)) { return false; } int len = 0; - if (!EVP_EncryptUpdate(ctx, mask, &len, sample, 16)) { - return false; + if (aead == EVP_chacha20()) { + if (!EVP_EncryptUpdate(ctx, mask, &len, FIVE_ZEROS, sizeof(FIVE_ZEROS))) { + return false; + } + } else { + if (!EVP_EncryptUpdate(ctx, mask, &len, sample, 16)) { + return false; + } } if (!EVP_EncryptFinal_ex(ctx, mask + len, &len)) { return false; From 988ff5c0d365f66c8c85088f0bdc551771d220d8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 22 Jan 2019 14:53:44 +0900 Subject: [PATCH 1046/1313] Advertise hq-17 for now instead of h3-17 --- iocore/net/quic/QUICConfig.cc | 2 +- proxy/http3/Http3ClientSession.cc | 2 +- src/tscore/ink_inet.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index eaab96a3dc6..bd971526c00 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -36,7 +36,7 @@ // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html // Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? using namespace std::literals; -static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5h3-17"sv); +static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-17"sv); int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3ClientSession.cc index e6e595e2d28..f04547d35a7 100644 --- a/proxy/http3/Http3ClientSession.cc +++ b/proxy/http3/Http3ClientSession.cc @@ -105,7 +105,7 @@ Http3ClientSession::get_transact_count() const const char * Http3ClientSession::get_protocol_string() const { - return "h3-17"; + return "hq-17"; } void diff --git a/src/tscore/ink_inet.cc b/src/tscore/ink_inet.cc index 8a279cf2840..3e67924a37c 100644 --- a/src/tscore/ink_inet.cc +++ b/src/tscore/ink_inet.cc @@ -50,7 +50,7 @@ const std::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"sv); const std::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"sv); const std::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"sv); const std::string_view IP_PROTO_TAG_HTTP_2_0("h2"sv); // HTTP/2 over TLS -const std::string_view IP_PROTO_TAG_HTTP_QUIC("h3-17"sv); // HTTP/3 over QUIC +const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-17"sv); // HTTP/3 over QUIC const std::string_view UNIX_PROTO_TAG{"unix"sv}; From ed680fbdd8aae074dfd6fd7f14fa1932c3e51b5f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 Jan 2019 14:39:43 +0900 Subject: [PATCH 1047/1313] Fix reading StreamIO buffer to create HTTP/3 frame --- proxy/http3/Http3Frame.cc | 10 +++++----- proxy/http3/Http3Frame.h | 2 +- proxy/http3/Http3FrameDispatcher.cc | 12 ++++++++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc index aa51a553048..6b6c0147320 100644 --- a/proxy/http3/Http3Frame.cc +++ b/proxy/http3/Http3Frame.cc @@ -372,7 +372,7 @@ Http3FrameFactory::fast_create(const uint8_t *buf, size_t len) } else { this->_unknown_frame->reset(buf, len); } - return _unknown_frame; + return this->_unknown_frame; } std::shared_ptr frame = this->_reusable_frames[static_cast(type)]; @@ -390,18 +390,18 @@ Http3FrameFactory::fast_create(const uint8_t *buf, size_t len) } std::shared_ptr -Http3FrameFactory::fast_create(QUICStreamIO &stream_io, size_t len) +Http3FrameFactory::fast_create(QUICStreamIO &stream_io, size_t frame_len) { uint8_t buf[65536]; // FIXME DATA frames can be giga bytes - ink_assert(sizeof(buf) > len); + ink_assert(sizeof(buf) > frame_len); - if (stream_io.peek(buf, sizeof(buf) < len)) { + if (stream_io.peek(buf, frame_len) < static_cast(frame_len)) { // Return if whole frame data is not available return nullptr; } - return this->fast_create(buf, len); + return this->fast_create(buf, frame_len); } Http3HeadersFrameUPtr diff --git a/proxy/http3/Http3Frame.h b/proxy/http3/Http3Frame.h index 1f9082dd1cf..3273476bdf5 100644 --- a/proxy/http3/Http3Frame.h +++ b/proxy/http3/Http3Frame.h @@ -218,7 +218,7 @@ class Http3FrameFactory * 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. */ - std::shared_ptr fast_create(QUICStreamIO &stream_io, size_t len); + std::shared_ptr fast_create(QUICStreamIO &stream_io, size_t frame_len); std::shared_ptr fast_create(const uint8_t *buf, size_t len); /* diff --git a/proxy/http3/Http3FrameDispatcher.cc b/proxy/http3/Http3FrameDispatcher.cc index 3c4a156f6da..13070728447 100644 --- a/proxy/http3/Http3FrameDispatcher.cc +++ b/proxy/http3/Http3FrameDispatcher.cc @@ -59,10 +59,9 @@ Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) if (this->_reading_state == READING_PAYLOAD_LEN) { // Read a payload length uint8_t length_buf[8]; - if (stream_io.read(length_buf, this->_reading_frame_length_len) != this->_reading_frame_length_len) { + if (stream_io.peek(length_buf, this->_reading_frame_length_len) != this->_reading_frame_length_len) { break; } - nread += this->_reading_frame_length_len; size_t dummy; if (QUICVariableInt::decode(this->_reading_frame_payload_len, dummy, length_buf, sizeof(length_buf)) < 0) { error = Http3ErrorUPtr(new Http3StreamError()); @@ -71,11 +70,16 @@ Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) } // Create a frame - frame = this->_frame_factory.fast_create(stream_io, this->_reading_frame_payload_len); + // Length field length + Type field length (1) + Payload length + size_t frame_len = this->_reading_frame_length_len + 1 + this->_reading_frame_payload_len; + frame = this->_frame_factory.fast_create(stream_io, frame_len); if (frame == nullptr) { break; } - nread += 1 + this->_reading_frame_payload_len; // Type field length (1) + Payload length + + // Consume buffer if frame is created + nread += frame_len; + stream_io.consume(nread); // Dispatch Http3FrameType type = frame->type(); From c9b280286848f0b3965a9a3711d3028e547acc08 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 23 Jan 2019 15:10:39 +0900 Subject: [PATCH 1048/1313] Fix compile warnings on CentOS --- iocore/net/quic/QUICFrame.cc | 1 - iocore/net/quic/QUICPacketHeaderProtector.cc | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index b2d66dd92d9..5d91ab0ddb0 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2007,7 +2007,6 @@ QUICNewConnectionIdFrame::_reset() { this->_sequence = 0; this->_connection_id = QUICConnectionId::ZERO(); - memset(&this->_stateless_reset_token, 0, sizeof(QUICStatelessResetToken)); this->_owner = nullptr; this->_id = 0; diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc index b6260bed930..ce257156b01 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -178,7 +178,7 @@ QUICPacketHeaderProtector::_calc_sample_offset(uint8_t *sample_offset, const uin *sample_offset = 1 + dcil + 4; } - return *sample_offset + 16 <= protected_packet_len; + return static_cast(*sample_offset + 16) <= protected_packet_len; } bool From 0648132e9ba3399106ede3115ff57d9397127288 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 24 Jan 2019 11:17:58 +0900 Subject: [PATCH 1049/1313] Fix stream type check --- iocore/net/quic/QUICStream.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index fd46d4a63b2..1cc0c1fc518 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -91,7 +91,7 @@ QUICStream::connection_info() const bool QUICStream::is_bidirectional() const { - return this->_id < 0x02; + return (this->_id & 0x03) < 0x02; } QUICOffset From 866fe9298e02ee8f644133d1cea119c4d69c6ae4 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 24 Jan 2019 11:54:31 +0900 Subject: [PATCH 1050/1313] Update QPACK Static Table --- proxy/http3/QPACK.cc | 163 +++++++++++++++++++++++++++---------------- 1 file changed, 101 insertions(+), 62 deletions(-) diff --git a/proxy/http3/QPACK.cc b/proxy/http3/QPACK.cc index 941740864b5..9fa397b43fe 100644 --- a/proxy/http3/QPACK.cc +++ b/proxy/http3/QPACK.cc @@ -30,68 +30,107 @@ #define QPACKDebug(fmt, ...) Debug("qpack", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) #define QPACKDTDebug(fmt, ...) Debug("qpack", "" fmt, ##__VA_ARGS__) -const QPACK::Header QPACK::StaticTable::STATIC_HEADER_FIELDS[] = {{"", ""}, // Index 0 is invalid - {":authority", ""}, - {":method", "GET"}, - {":method", "POST"}, - {":path", "/"}, - {":path", "/index.html"}, - {":scheme", "http"}, - {":scheme", "https"}, - {":status", "200"}, - {":status", "204"}, - {":status", "206"}, - {":status", "304"}, - {":status", "400"}, - {":status", "404"}, - {":status", "500"}, - {"accept-charset", ""}, - {"accept-encoding", "gzip, deflate"}, - {"accept-language", ""}, - {"accept-ranges", ""}, - {"accept", ""}, - {"access-control-allow-origin", ""}, - {"age", ""}, - {"allow", ""}, - {"authorization", ""}, - {"cache-control", ""}, - {"content-disposition", ""}, - {"content-encoding", ""}, - {"content-language", ""}, - {"content-length", ""}, - {"content-location", ""}, - {"content-range", ""}, - {"content-type", ""}, - {"cookie", ""}, - {"date", ""}, - {"etag", ""}, - {"expect", ""}, - {"expires", ""}, - {"from", ""}, - {"host", ""}, - {"if-match", ""}, - {"if-modified-since", ""}, - {"if-none-match", ""}, - {"if-range", ""}, - {"if-unmodified-since", ""}, - {"last-modified", ""}, - {"link", ""}, - {"location", ""}, - {"max-forwards", ""}, - {"proxy-authenticate", ""}, - {"proxy-authorization", ""}, - {"range", ""}, - {"referer", ""}, - {"refresh", ""}, - {"retry-after", ""}, - {"server", ""}, - {"set-cookie", ""}, - {"strict-transport-security", ""}, - {"transfer-encoding", ""}, - {"user-agent", ""}, - {"vary", ""}, - {"via", ""}, - {"www-authenticate", ""}}; +// qpack-05 Appendix A. +const QPACK::Header QPACK::StaticTable::STATIC_HEADER_FIELDS[] = { + {":authority", ""}, + {":path", "/"}, + {"age", "0"}, + {"content-disposition", ""}, + {"content-length", "0"}, + {"cookie", ""}, + {"date", ""}, + {"etag", ""}, + {"if-modified-since", ""}, + {"if-none-match", ""}, + {"last-modified", ""}, + {"link", ""}, + {"location", ""}, + {"referer", ""}, + {"set-cookie", ""}, + {":method", "CONNECT"}, + {":method", "DELETE"}, + {":method", "GET"}, + {":method", "HEAD"}, + {":method", "OPTIONS"}, + {":method", "POST"}, + {":method", "PUT"}, + {":scheme", "http"}, + {":scheme", "https"}, + {":status", "103"}, + {":status", "200"}, + {":status", "304"}, + {":status", "404"}, + {":status", "503"}, + {"accept", "*/*"}, + {"accept", "application/dns-message"}, + {"accept-encoding", "gzip, deflate, br"}, + {"accept-ranges", "bytes"}, + {"access-control-allow-headers", "cache-control"}, + {"access-control-allow-headers", "content-type"}, + {"access-control-allow-origin", "*"}, + {"cache-control", "max-age=0"}, + {"cache-control", "max-age=2592000"}, + {"cache-control", "max-age=604800"}, + {"cache-control", "no-cache"}, + {"cache-control", "no-store"}, + {"cache-control", "public, max-age=31536000"}, + {"content-encoding", "br"}, + {"content-encoding", "gzip"}, + {"content-type", "application/dns-message"}, + {"content-type", "application/javascript"}, + {"content-type", "application/json"}, + {"content-type", "application/x-www-form-urlencoded"}, + {"content-type", "image/gif"}, + {"content-type", "image/jpeg"}, + {"content-type", "image/png"}, + {"content-type", "text/css"}, + {"content-type", "text/html; charset=utf-8"}, + {"content-type", "text/plain"}, + {"content-type", "text/plain;charset=utf-8"}, + {"range", "bytes=0-"}, + {"strict-transport-security", "max-age=31536000"}, + {"strict-transport-security", "max-age=31536000; includesubdomains"}, + {"strict-transport-security", "max-age=31536000; includesubdomains; preload"}, + {"vary", "accept-encoding"}, + {"vary", "origin"}, + {"x-content-type-options", "nosniff"}, + {"x-xss-protection", "1; mode=block"}, + {":status", "100"}, + {":status", "204"}, + {":status", "206"}, + {":status", "302"}, + {":status", "400"}, + {":status", "403"}, + {":status", "421"}, + {":status", "425"}, + {":status", "500"}, + {"accept-language", ""}, + {"access-control-allow-credentials", "FALSE"}, + {"access-control-allow-credentials", "TRUE"}, + {"access-control-allow-headers", "*"}, + {"access-control-allow-methods", "get"}, + {"access-control-allow-methods", "get, post, options"}, + {"access-control-allow-methods", "options"}, + {"access-control-expose-headers", "content-length"}, + {"access-control-request-headers", "content-type"}, + {"access-control-request-method", "get"}, + {"access-control-request-method", "post"}, + {"alt-svc", "clear"}, + {"authorization", ""}, + {"content-security-policy", "script-src 'none'; object-src 'none'; base-uri 'none'"}, + {"early-data", "1"}, + {"expect-ct", ""}, + {"forwarded", ""}, + {"if-range", ""}, + {"origin", ""}, + {"purpose", "prefetch"}, + {"server", ""}, + {"timing-allow-origin", "*"}, + {"upgrade-insecure-requests", "1"}, + {"user-agent", ""}, + {"x-forwarded-for", ""}, + {"x-frame-options", "deny"}, + {"x-frame-options", "sameorigin"}}; QPACK::QPACK(QUICConnection *qc, uint16_t max_table_size, uint16_t max_blocking_streams) : QUICApplication(qc), From eb25b14d99d50e5759d76557baa582f0850141b3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 24 Jan 2019 14:39:24 +0900 Subject: [PATCH 1051/1313] Update remote addr --- iocore/net/QUICNetVConnection.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index def4e0017bb..b7b366bbb8b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -2105,6 +2105,7 @@ QUICNetVConnection::_state_connection_established_migrate_connection(const QUICP Connection con; con.setRemote(&(p.from().sa)); this->con.move(con); + this->set_remote_addr(); this->_validate_new_path(); } } else { @@ -2117,6 +2118,7 @@ QUICNetVConnection::_state_connection_established_migrate_connection(const QUICP Connection con; con.setRemote(&(p.from().sa)); this->con.move(con); + this->set_remote_addr(); this->_update_peer_cid(this->_alt_con_manager->migrate_to_alt_cid()); this->_validate_new_path(); From 67673b15edcf91dff08f94cb62c81059f6bf1b25 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 24 Jan 2019 17:14:42 +0900 Subject: [PATCH 1052/1313] Add PADDING frames if packet is too small To gather enough sample for header protection. --- iocore/net/QUICNetVConnection.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b7b366bbb8b..f8473bae194 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1476,6 +1476,13 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa memset(buf.get() + len, 0, min_size - len); len += min_size - len; } + } else { + // Pad with PADDING frames to make sure payload length satisfy the minimum length for sampling for header protection + if (3 > len) { + // FIXME QUICNetVConnection should not know the actual type value of PADDING frame + memset(buf.get() + len, 0, 3 - len); + len += 3 - len; + } } // Packet is retransmittable if it's not ack only packet From 42653598059f89bdc286d58417267331a96ea73d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 24 Jan 2019 17:18:51 +0900 Subject: [PATCH 1053/1313] Send PING frame on an appropriate encryption level --- iocore/net/quic/QUICPinger.cc | 10 ++++------ iocore/net/quic/QUICPinger.h | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICPinger.cc b/iocore/net/quic/QUICPinger.cc index 1249f1fbee7..a559b7d9db3 100644 --- a/iocore/net/quic/QUICPinger.cc +++ b/iocore/net/quic/QUICPinger.cc @@ -26,7 +26,7 @@ void QUICPinger::trigger(QUICEncryptionLevel level) { - this->_need_to_fire[QUICTypeUtil::pn_space_index(level)] = true; + this->_need_to_fire[static_cast(level)] = true; } bool @@ -44,12 +44,10 @@ QUICPinger::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit return frame; } - int index = QUICTypeUtil::pn_space_index(level); - - if (this->_need_to_fire[index] && maximum_frame_size > 0) { + if (this->_need_to_fire[static_cast(level)] && maximum_frame_size > 0) { // don't care ping frame lost or acked - frame = QUICFrameFactory::create_ping_frame(0, nullptr); - this->_need_to_fire[index] = false; + frame = QUICFrameFactory::create_ping_frame(0, nullptr); + this->_need_to_fire[static_cast(level)] = false; } return frame; diff --git a/iocore/net/quic/QUICPinger.h b/iocore/net/quic/QUICPinger.h index 547c3d23ac0..8f06b1d1e7d 100644 --- a/iocore/net/quic/QUICPinger.h +++ b/iocore/net/quic/QUICPinger.h @@ -41,7 +41,7 @@ class QUICPinger : public QUICFrameGenerator private: // Initial, 0/1-RTT, and Handshake - bool _need_to_fire[3] = {false}; + bool _need_to_fire[4] = {false}; // QUICFrameGenerator std::vector From ba58765f6cbdd6e037f5d63cf462d9cb21830bc9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 24 Jan 2019 17:49:34 +0900 Subject: [PATCH 1054/1313] Record encryption level of lost frames --- iocore/net/quic/QUICStream.cc | 24 ++++++++++++++---------- iocore/net/quic/QUICStream.h | 8 ++++---- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 1cc0c1fc518..082adb17638 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -417,14 +417,14 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit QUICFrameUPtr frame = this->create_retransmitted_frame(level, maximum_frame_size, this->_issue_frame_id(), this); if (frame != nullptr) { ink_assert(frame->type() == QUICFrameType::STREAM); - this->_records_stream_frame(*static_cast(frame.get())); + this->_records_stream_frame(level, *static_cast(frame.get())); return frame; } // RESET_STREAM if (this->_reset_reason && !this->_is_reset_sent) { frame = QUICFrameFactory::create_rst_stream_frame(*this->_reset_reason, this->_issue_frame_id(), this); - this->_records_rst_stream_frame(*static_cast(frame.get())); + this->_records_rst_stream_frame(level, *static_cast(frame.get())); this->_state.update_with_sending_frame(*frame); this->_is_reset_sent = true; return frame; @@ -434,7 +434,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit if (this->_stop_sending_reason && !this->_is_stop_sending_sent) { frame = QUICFrameFactory::create_stop_sending_frame(this->id(), this->_stop_sending_reason->code, this->_issue_frame_id(), this); - this->_records_stop_sending_frame(*static_cast(frame.get())); + this->_records_stop_sending_frame(level, *static_cast(frame.get())); this->_state.update_with_sending_frame(*frame); this->_is_stop_sending_sent = true; return frame; @@ -527,7 +527,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit this->_send_offset += len; this->_write_vio.ndone += len; } - this->_records_stream_frame(*static_cast(frame.get())); + this->_records_stream_frame(level, *static_cast(frame.get())); this->_signal_write_event(); this->_state.update_with_sending_frame(*frame); @@ -536,10 +536,11 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit } void -QUICStream::_records_stream_frame(const QUICStreamFrame &frame) +QUICStream::_records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame) { QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = frame.type(); + info->level = level; StreamFrameInfo *frame_info = reinterpret_cast(info->data); frame_info->offset = frame.offset(); frame_info->has_fin = frame.has_fin_flag(); @@ -548,10 +549,11 @@ QUICStream::_records_stream_frame(const QUICStreamFrame &frame) } void -QUICStream::_records_rst_stream_frame(const QUICRstStreamFrame &frame) +QUICStream::_records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame) { QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = frame.type(); + info->level = level; RstStreamFrameInfo *frame_info = reinterpret_cast(info->data); frame_info->error_code = frame.error_code(); frame_info->final_offset = frame.final_offset(); @@ -559,10 +561,11 @@ QUICStream::_records_rst_stream_frame(const QUICRstStreamFrame &frame) } void -QUICStream::_records_stop_sending_frame(const QUICStopSendingFrame &frame) +QUICStream::_records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame) { QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = frame.type(); + info->level = level; StopSendingFrameInfo *frame_info = reinterpret_cast(info->data); frame_info->error_code = frame.error_code(); this->_records_frame(frame.id(), std::move(info)); @@ -873,7 +876,7 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ QUICFrameUPtr frame = this->create_retransmitted_frame(level, maximum_frame_size, this->_issue_frame_id(), this); if (frame != nullptr) { ink_assert(frame->type() == QUICFrameType::CRYPTO); - this->_records_crypto_frame(*static_cast(frame.get())); + this->_records_crypto_frame(level, *static_cast(frame.get())); return frame; } @@ -896,7 +899,7 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ frame = QUICFrameFactory::create_crypto_frame(block, this->_send_offset, this->_issue_frame_id(), this); this->_send_offset += frame_payload_size; this->_write_buffer_reader->consume(frame_payload_size); - this->_records_crypto_frame(*static_cast(frame.get())); + this->_records_crypto_frame(level, *static_cast(frame.get())); return frame; } @@ -917,10 +920,11 @@ QUICCryptoStream::_on_frame_lost(QUICFrameInformationUPtr &info) } void -QUICCryptoStream::_records_crypto_frame(const QUICCryptoFrame &frame) +QUICCryptoStream::_records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFrame &frame) { QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = QUICFrameType::CRYPTO; + info->level = level; CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); crypto_frame_info->offset = frame.offset(); crypto_frame_info->block = frame.data(); diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index be61d2bcc4f..c41a52768de 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -109,9 +109,9 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra Event *_send_tracked_event(Event *, int, VIO *); void _write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin); - void _records_rst_stream_frame(const QUICRstStreamFrame &frame); - void _records_stream_frame(const QUICStreamFrame &frame); - void _records_stop_sending_frame(const QUICStopSendingFrame &frame); + void _records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame); + void _records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame); + void _records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame); QUICStreamErrorUPtr _reset_reason = nullptr; bool _is_reset_sent = false; @@ -192,7 +192,7 @@ class QUICCryptoStream : public QUICFrameGenerator, public QUICFrameRetransmitte void _on_frame_acked(QUICFrameInformationUPtr &info) override; void _on_frame_lost(QUICFrameInformationUPtr &info) override; - void _records_crypto_frame(const QUICCryptoFrame &frame); + void _records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFrame &frame); QUICStreamErrorUPtr _reset_reason = nullptr; QUICOffset _send_offset = 0; From 6dc267a9f5dfe17bfc5b022ae442892d181b3620 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 24 Jan 2019 17:55:41 +0900 Subject: [PATCH 1055/1313] Send PING after path validation This is a workaround for connection migration. --- iocore/net/QUICNetVConnection.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index f8473bae194..b278d792505 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -2175,6 +2175,10 @@ QUICNetVConnection::_handle_path_validation_timeout(Event *data) if (this->_path_validator->is_validated()) { QUICConDebug("Path validated"); 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(); } else { QUICConDebug("Path validation failed"); this->_switch_to_close_state(); From 2ad2237cd2d30bba0cb24711125700e71dd0969c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 28 Jan 2019 11:02:27 +0900 Subject: [PATCH 1056/1313] Record stream id of STREAM frames for retransmission --- iocore/net/quic/QUICStream.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 082adb17638..b75e8284d32 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -542,6 +542,7 @@ QUICStream::_records_stream_frame(QUICEncryptionLevel level, const QUICStreamFra info->type = frame.type(); info->level = level; StreamFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->stream_id = frame.stream_id(); frame_info->offset = frame.offset(); frame_info->has_fin = frame.has_fin_flag(); frame_info->block = frame.data(); From fa9deaaf044b2d36fdb3132de6738fb1b92b9162 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 28 Jan 2019 14:02:35 +0900 Subject: [PATCH 1057/1313] Set fin flag correctly when retransmitter splits STREAM frame --- iocore/net/quic/QUICFrameRetransmitter.cc | 37 ++++++++++++++--------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/iocore/net/quic/QUICFrameRetransmitter.cc b/iocore/net/quic/QUICFrameRetransmitter.cc index 485e13d5d4d..7765ccc988a 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.cc +++ b/iocore/net/quic/QUICFrameRetransmitter.cc @@ -99,27 +99,35 @@ QUICFrameRetransmitter::_create_stream_frame(QUICFrameInformationUPtr &info, uin std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner) { + QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); StreamFrameInfo *stream_info = reinterpret_cast(info->data); - // FIXME: has_offset and has_length should be configurable. - auto frame = QUICFrameFactory::create_stream_frame(stream_info->block, stream_info->stream_id, stream_info->offset, - stream_info->has_fin, true, true, id, owner); - if (frame->size() > maximum_frame_size) { - QUICStreamFrame *stream_frame = static_cast(frame.get()); - if (stream_frame->size() - stream_frame->data_length() > maximum_frame_size) { - // header length is larger than maximum_frame_size. - tmp_queue.push_back(std::move(info)); - return QUICFrameFactory::create_null_frame(); - } - IOBufferBlock *block = stream_frame->data(); - size_t over_length = stream_frame->size() - maximum_frame_size; - block->_end = std::max(block->start(), block->_end - over_length); + static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; + if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) { + tmp_queue.push_back(std::move(info)); + return frame; + } + + // FIXME MAX_STREAM_FRAME_OVERHEAD is here and there + // These size calculation should not exist multiple places + uint64_t maximmum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD; + if (maximmum_data_size > static_cast(stream_info->block->size())) { + frame = QUICFrameFactory::create_stream_frame(stream_info->block, stream_info->stream_id, stream_info->offset, + stream_info->has_fin, true, true, id, owner); + ink_assert(frame->size() <= maximum_frame_size); + stream_info->block = nullptr; + } else { + frame = QUICFrameFactory::create_stream_frame(stream_info->block, stream_info->stream_id, stream_info->offset, false, true, + true, id, owner); + QUICStreamFrame *stream_frame = static_cast(frame.get()); + IOBufferBlock *block = stream_frame->data(); + size_t over_length = stream_frame->size() - maximum_frame_size; + block->_end = std::max(block->start(), block->_end - over_length); if (block->read_avail() == 0) { // no payload tmp_queue.push_back(std::move(info)); return QUICFrameFactory::create_null_frame(); } - stream_info->block->consume(stream_frame->data_length()); stream_info->offset += stream_frame->data_length(); ink_assert(frame->size() <= maximum_frame_size); @@ -127,7 +135,6 @@ QUICFrameRetransmitter::_create_stream_frame(QUICFrameInformationUPtr &info, uin return frame; } - stream_info->block = nullptr; ink_assert(frame != nullptr); return frame; } From 2638c4fc9ab1b4a96955170aa5f54b1b9331b966 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 28 Jan 2019 17:07:15 +0800 Subject: [PATCH 1058/1313] QUIC: Fixed traffic_quic compiler error --- src/traffic_quic/Makefile.inc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/traffic_quic/Makefile.inc b/src/traffic_quic/Makefile.inc index c316eaf2d29..b9291dbd516 100644 --- a/src/traffic_quic/Makefile.inc +++ b/src/traffic_quic/Makefile.inc @@ -48,8 +48,10 @@ traffic_quic_traffic_quic_LDADD = \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/src/tscore/libtscore.la \ + $(top_builddir)/src/tscpp/util/libtscpputil.la \ $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ @HWLOC_LIBS@ \ @YAMLCPP_LIBS@ \ - @OPENSSL_LIBS@ + @OPENSSL_LIBS@ \ + @LIBPCRE@ From 46da77d330379bab623a373dc65851d855eb06fc Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 28 Jan 2019 18:07:18 +0800 Subject: [PATCH 1059/1313] QUIC: Add retransmit fin stream frame test and fixed test_QUICFrameRetransmitter --- .../quic/test/test_QUICFrameRetransmitter.cc | 68 +++++++++++++++++-- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc index 6ea6b11ab12..9dad813e3ca 100644 --- a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc +++ b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc @@ -25,7 +25,8 @@ #include "QUICFrameRetransmitter.h" -constexpr static uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}; +constexpr static uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10}; TEST_CASE("QUICFrameRetransmitter ignore frame which can not be retranmistted", "[quic]") { @@ -138,13 +139,13 @@ TEST_CASE("QUICFrameRetransmitter successfully split stream frame", "[quic]") retransmitter.save_frame_info(std::move(info)); - auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 15); + auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 25); CHECK(frame != nullptr); CHECK(frame->type() == QUICFrameType::STREAM); auto stream_frame = static_cast(frame.get()); CHECK(stream_frame->stream_id() == 0x12345); CHECK(stream_frame->offset() == 0x67890); - CHECK(stream_frame->size() <= 15); + CHECK(stream_frame->size() <= 25); auto size = stream_frame->data_length(); CHECK(memcmp(stream_frame->data()->start(), data, stream_frame->data_length()) == 0); @@ -191,12 +192,12 @@ TEST_CASE("QUICFrameRetransmitter successfully split crypto frame", "[quic]") retransmitter.save_frame_info(std::move(info)); - auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 15); + auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 25); CHECK(frame != nullptr); CHECK(frame->type() == QUICFrameType::CRYPTO); auto crypto_frame = static_cast(frame.get()); CHECK(crypto_frame->offset() == 0x67890); - CHECK(crypto_frame->size() <= 15); + CHECK(crypto_frame->size() <= 25); auto size = crypto_frame->data_length(); CHECK(memcmp(crypto_frame->data()->start(), data, crypto_frame->data_length()) == 0); @@ -222,3 +223,60 @@ TEST_CASE("QUICFrameRetransmitter successfully split crypto frame", "[quic]") CHECK(block->refcount() == 1); CHECK(block->data->refcount() == 1); } + +TEST_CASE("QUICFrameRetransmitter successfully split stream frame with fin flag", "[quic]") +{ + QUICFrameRetransmitter retransmitter; + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = QUICFrameType::STREAM; + info->level = QUICEncryptionLevel::INITIAL; + + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), data, sizeof(data)); + block->fill(sizeof(data)); + + StreamFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->stream_id = 0x12345; + frame_info->offset = 0x67890; + frame_info->block = block; + frame_info->has_fin = true; + CHECK(block->refcount() == 2); + + retransmitter.save_frame_info(std::move(info)); + + auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 25); + CHECK(frame != nullptr); + CHECK(frame->type() == QUICFrameType::STREAM); + auto stream_frame = static_cast(frame.get()); + CHECK(stream_frame->stream_id() == 0x12345); + CHECK(stream_frame->offset() == 0x67890); + CHECK(stream_frame->size() <= 25); + CHECK(stream_frame->has_fin_flag() == false); + + auto size = stream_frame->data_length(); + CHECK(memcmp(stream_frame->data()->start(), data, stream_frame->data_length()) == 0); + // one for var block, one for the left data which saved in retransmitter + CHECK(block->data->refcount() == 2); + // one for var block, one for the left data which saved in retransmitter, one for var frame + CHECK(block->refcount() == 2); + frame = QUICFrameFactory::create_null_frame(); + // one for var block, one for var info + CHECK(block->refcount() == 2); + CHECK(block->data->refcount() == 1); + + frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); + CHECK(frame != nullptr); + CHECK(frame->type() == QUICFrameType::STREAM); + stream_frame = static_cast(frame.get()); + CHECK(stream_frame->stream_id() == 0x12345); + CHECK(stream_frame->offset() == 0x67890 + size); + CHECK(stream_frame->data_length() == sizeof(data) - size); + CHECK(memcmp(stream_frame->data()->start(), data + size, stream_frame->data_length()) == 0); + CHECK(block->refcount() == 1); // one for var block + CHECK(stream_frame->has_fin_flag() == true); + + frame = QUICFrameFactory::create_null_frame(); + CHECK(block->refcount() == 1); + CHECK(block->data->refcount() == 1); +} From d165267ddeea8f1de2a43ba93ecb12e903884bba Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 23 Jan 2019 14:06:07 +0900 Subject: [PATCH 1060/1313] Add prototype of HTTP/3 support with ugly hacks Worked with lsquic-client with HEADER_TABLE_SIZE=0 --- iocore/net/quic/QUICApplication.cc | 7 + iocore/net/quic/QUICApplication.h | 1 + iocore/net/quic/QUICConfig.cc | 2 +- proxy/http3/Http3App.cc | 302 ++++++++++++++++++++++++++ proxy/http3/Http3App.h | 98 +++++++++ proxy/http3/Http3ClientSession.cc | 22 +- proxy/http3/Http3ClientSession.h | 6 + proxy/http3/Http3ClientTransaction.cc | 83 ++++++- proxy/http3/Http3ClientTransaction.h | 5 + proxy/http3/Http3DebugNames.cc | 6 + proxy/http3/Http3DebugNames.h | 1 + proxy/http3/Http3Frame.cc | 15 ++ proxy/http3/Http3Frame.h | 1 + proxy/http3/Http3FrameCollector.cc | 5 + proxy/http3/Http3FrameDispatcher.cc | 8 +- proxy/http3/Http3FrameGenerator.h | 2 + proxy/http3/Http3HeaderFramer.cc | 87 ++++++-- proxy/http3/Http3HeaderFramer.h | 20 +- proxy/http3/Http3HeaderVIOAdaptor.cc | 24 +- proxy/http3/Http3HeaderVIOAdaptor.h | 13 +- proxy/http3/Http3SessionAccept.cc | 8 +- proxy/http3/Http3Types.cc | 41 ++++ proxy/http3/Http3Types.h | 10 +- proxy/http3/Makefile.am | 3 + proxy/http3/QPACK.cc | 31 ++- proxy/http3/QPACK.h | 12 +- proxy/http3/test/test_Http3Frame.cc | 25 +++ src/traffic_quic/quic_client.cc | 45 ++++ src/traffic_quic/quic_client.h | 5 + src/traffic_quic/traffic_quic.cc | 7 + src/tscore/ink_inet.cc | 2 +- 31 files changed, 837 insertions(+), 60 deletions(-) create mode 100644 proxy/http3/Http3App.cc create mode 100644 proxy/http3/Http3App.h create mode 100644 proxy/http3/Http3Types.cc diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 2248361734d..9e533be55f4 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -202,6 +202,13 @@ QUICApplication::set_stream(QUICStream *stream, QUICStreamIO *stream_io) this->_stream_map.insert(std::make_pair(stream->id(), stream_io)); } +// @brief Bind stream and application +void +QUICApplication::set_stream(QUICStreamIO *stream_io) +{ + this->_stream_map.insert(std::make_pair(stream_io->stream_id(), stream_io)); +} + bool QUICApplication::is_stream_set(QUICStream *stream) { diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 00f75626e45..8ebd9ccc8b1 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -84,6 +84,7 @@ class QUICApplication : public Continuation virtual ~QUICApplication(); void set_stream(QUICStream *stream, QUICStreamIO *stream_io = nullptr); + void set_stream(QUICStreamIO *stream_io); bool is_stream_set(QUICStream *stream); void reenable(QUICStream *stream); void unset_stream(QUICStream *stream); diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index bd971526c00..eaab96a3dc6 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -36,7 +36,7 @@ // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html // Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? using namespace std::literals; -static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-17"sv); +static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5h3-17"sv); int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc new file mode 100644 index 00000000000..4d3aaf635e7 --- /dev/null +++ b/proxy/http3/Http3App.cc @@ -0,0 +1,302 @@ +/** @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 "Http3App.h" + +#include "P_Net.h" +#include "P_VConnection.h" + +#include "Http3DebugNames.h" +#include "Http3ClientSession.h" +#include "Http3ClientTransaction.h" + +static constexpr char tag[] = "http3"; +static constexpr char tag_v[] = "v_http3"; + +Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QUICApplication(client_vc) +{ + this->_client_session = new Http3ClientSession(client_vc); + this->_client_session->acl = std::move(session_acl); + this->_client_session->new_connection(client_vc, nullptr, nullptr, false); + + this->_qc->stream_manager()->set_default_application(this); + + this->_settings_handler = new Http3SettingsHandler(); + this->_control_stream_dispatcher.add_handler(this->_settings_handler); + + this->_settings_framer = new Http3SettingsFramer(); + this->_control_stream_collector.add_generator(this->_settings_framer); + + SET_HANDLER(&Http3App::main_event_handler); +} + +Http3App::~Http3App() +{ + delete this->_client_session; + delete this->_settings_handler; + delete this->_settings_framer; +} + +void +Http3App::start() +{ + QUICStreamId stream_id; + QUICConnectionErrorUPtr error = this->create_uni_stream(stream_id, Http3StreamType::CONTROL); + if (error != nullptr) { + ink_abort("Could not creat CONTROL stream"); + } + + this->_local_control_stream = this->_find_stream_io(stream_id); + this->_local_uni_stream_map.insert(std::make_pair(stream_id, Http3StreamType::CONTROL)); + + // Should do this->handleEvent(VC_EVENT_WRITE_READY, vio); ??? + + this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_local_control_stream); +} + +int +Http3App::main_event_handler(int event, Event *data) +{ + Debug(tag_v, "[%s] %s (%d)", this->_qc->cids().data(), get_vc_event_name(event), event); + + VIO *vio = reinterpret_cast(data); + QUICStreamIO *stream_io = this->_find_stream_io(vio); + + if (stream_io == nullptr) { + Debug(tag, "[%s] Unknown Stream", this->_qc->cids().data()); + return -1; + } + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: + if (stream_io->is_bidirectional()) { + this->_handle_bidi_stream_on_read_ready(event, stream_io); + } else { + this->_handle_uni_stream_on_read_ready(event, stream_io); + } + break; + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: + if (stream_io->is_bidirectional()) { + this->_handle_bidi_stream_on_write_ready(event, stream_io); + } else { + this->_handle_uni_stream_on_write_ready(event, stream_io); + } + break; + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: + ink_assert(false); + break; + default: + break; + } + + return EVENT_CONT; +} + +QUICConnectionErrorUPtr +Http3App::create_uni_stream(QUICStreamId &new_stream_id, Http3StreamType type) +{ + QUICConnectionErrorUPtr error = this->_qc->stream_manager()->create_uni_stream(new_stream_id); + + if (error == nullptr) { + QUICStreamIO *stream_io = this->_find_stream_io(new_stream_id); + uint8_t buf[] = {static_cast(type)}; + stream_io->write(buf, sizeof(uint8_t)); + } + + return error; +} + +void +Http3App::_handle_uni_stream_on_read_ready(int /* event */, QUICStreamIO *stream_io) +{ + Http3StreamType type; + auto it = this->_remote_uni_stream_map.find(stream_io->stream_id()); + if (it == this->_remote_uni_stream_map.end()) { + // Set uni stream suitable app (HTTP/3 or QPACK) by stream type + uint8_t buf; + stream_io->read(&buf, 1); + type = Http3Stream::type(&buf); + + Debug("http3", "[%d] %s stream is opened", stream_io->stream_id(), Http3DebugNames::stream_type(type)); + + if (type == Http3StreamType::CONTROL) { + if (this->_remote_control_stream) { + // TODO: make error + } + this->_remote_control_stream = stream_io; + } + + this->_remote_uni_stream_map.insert(std::make_pair(stream_io->stream_id(), type)); + } else { + type = it->second; + } + + switch (type) { + case Http3StreamType::CONTROL: + case Http3StreamType::PUSH: { + uint64_t nread = 0; + this->_control_stream_dispatcher.on_read_ready(*stream_io, nread); + // TODO: when PUSH comes from client, send stream error with HTTP_WRONG_STREAM_DIRECTION + break; + } + case Http3StreamType::QPACK_ENCODER: { + // Change app to QPACK from Http3 + if (this->_qc->direction() == NET_VCONNECTION_IN) { + this->_client_session->remote_qpack()->set_encoder_stream(stream_io); + } else { + this->_client_session->local_qpack()->set_encoder_stream(stream_io); + } + break; + } + case Http3StreamType::QPACK_DECODER: { + if (this->_qc->direction() == NET_VCONNECTION_IN) { + this->_client_session->local_qpack()->set_decoder_stream(stream_io); + } else { + this->_client_session->remote_qpack()->set_decoder_stream(stream_io); + } + break; + } + case Http3StreamType::UNKOWN: + default: + // TODO: just ignore or trigger QUIC STOP_SENDING frame with HTTP_UNKNOWN_STREAM_TYPE + break; + } +} + +void +Http3App::_handle_bidi_stream_on_read_ready(int event, QUICStreamIO *stream_io) +{ + uint8_t dummy; + if (stream_io->peek(&dummy, 1)) { + QUICStreamId stream_id = stream_io->stream_id(); + Http3ClientTransaction *txn = this->_client_session->get_transaction(stream_id); + + if (txn == nullptr) { + txn = new Http3ClientTransaction(this->_client_session, stream_io); + SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); + + txn->new_transaction(); + } else { + SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); + txn->handleEvent(event); + } + } +} + +void +Http3App::_handle_uni_stream_on_write_ready(int /* event */, QUICStreamIO *stream_io) +{ + auto it = this->_local_uni_stream_map.find(stream_io->stream_id()); + if (it == this->_local_uni_stream_map.end()) { + ink_abort("stream not found"); + return; + } + + switch (it->second) { + case Http3StreamType::CONTROL: { + size_t nwritten = 0; + this->_control_stream_collector.on_write_ready(stream_io, nwritten); + break; + } + case Http3StreamType::UNKOWN: + case Http3StreamType::PUSH: + default: + break; + } +} + +void +Http3App::_handle_bidi_stream_on_write_ready(int event, QUICStreamIO *stream_io) +{ + QUICStreamId stream_id = stream_io->stream_id(); + Http3ClientTransaction *txn = this->_client_session->get_transaction(stream_id); + if (txn != nullptr) { + SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); + txn->handleEvent(event); + } +} + +// +// SETTINGS frame handler +// +std::vector +Http3SettingsHandler::interests() +{ + return {Http3FrameType::SETTINGS}; +} + +Http3ErrorUPtr +Http3SettingsHandler::handle_frame(std::shared_ptr frame) +{ + ink_assert(frame->type() == Http3FrameType::SETTINGS); + + const Http3SettingsFrame *settings_frame = dynamic_cast(frame.get()); + + if (!settings_frame) { + // make error + return Http3ErrorUPtr(new Http3NoError()); + } + + if (settings_frame->contains(Http3SettingsId::MAX_HEADER_LIST_SIZE)) { + uint64_t header_list_size = settings_frame->get(Http3SettingsId::MAX_HEADER_LIST_SIZE); + Debug("http3", "SETTINGS_MAX_HEADER_LIST_SIZE: %" PRId64, header_list_size); + } + + if (settings_frame->contains(Http3SettingsId::NUM_PLACEHOLDERS)) { + uint64_t num_placeholders = settings_frame->get(Http3SettingsId::NUM_PLACEHOLDERS); + Debug("http3", "SETTINGS_NUM_PLACEHOLDERS: %" PRId64, num_placeholders); + } + + return Http3ErrorUPtr(new Http3NoError()); +} + +// +// SETTINGS frame framer +// +// TODO: load values from config +Http3FrameUPtr +Http3SettingsFramer::generate_frame(uint16_t max_size) +{ + if (this->_is_sent) { + return Http3FrameFactory::create_null_frame(); + } + + this->_is_sent = true; + + Http3SettingsFrame *frame = http3SettingsFrameAllocator.alloc(); + new (frame) Http3SettingsFrame(); + frame->set(Http3SettingsId::HEADER_TABLE_SIZE, 0x0); + + return Http3SettingsFrameUPtr(frame, &Http3FrameDeleter::delete_settings_frame); +} + +bool +Http3SettingsFramer::is_done() const +{ + return this->_is_done; +} diff --git a/proxy/http3/Http3App.h b/proxy/http3/Http3App.h new file mode 100644 index 00000000000..0a9667022ea --- /dev/null +++ b/proxy/http3/Http3App.h @@ -0,0 +1,98 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "IPAllow.h" + +#include "QUICApplication.h" + +#include "Http3Types.h" +#include "Http3FrameDispatcher.h" +#include "Http3FrameCollector.h" +#include "Http3FrameGenerator.h" +#include "Http3FrameHandler.h" + +class QUICNetVConnection; +class Http3ClientSession; + +/** + * @brief A HTTP/3 application + * @detail + */ +class Http3App : public QUICApplication +{ +public: + Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl); + ~Http3App(); + + void start(); + int main_event_handler(int event, Event *data); + + // TODO: Return StreamIO. It looks bother that coller have to look up StreamIO by stream id. + // Why not create_bidi_stream ? + QUICConnectionErrorUPtr create_uni_stream(QUICStreamId &new_stream_id, Http3StreamType type); + +private: + void _handle_uni_stream_on_read_ready(int event, QUICStreamIO *stream_io); + void _handle_bidi_stream_on_read_ready(int event, QUICStreamIO *stream_io); + void _handle_uni_stream_on_write_ready(int event, QUICStreamIO *stream_io); + void _handle_bidi_stream_on_write_ready(int event, QUICStreamIO *stream_io); + + Http3ClientSession *_client_session = nullptr; + Http3FrameHandler *_settings_handler = nullptr; + Http3FrameGenerator *_settings_framer = nullptr; + + Http3FrameDispatcher _control_stream_dispatcher; + Http3FrameCollector _control_stream_collector; + + QUICStreamIO *_remote_control_stream; + QUICStreamIO *_local_control_stream; + + std::map _remote_uni_stream_map; + std::map _local_uni_stream_map; +}; + +class Http3SettingsHandler : public Http3FrameHandler +{ +public: + Http3SettingsHandler(){}; + + // Http3FrameHandler + std::vector interests() override; + Http3ErrorUPtr handle_frame(std::shared_ptr frame) override; +}; + +class Http3SettingsFramer : public Http3FrameGenerator +{ +public: + Http3SettingsFramer(){}; + + // Http3FrameGenerator + Http3FrameUPtr generate_frame(uint16_t max_size) override; + bool is_done() const override; + +private: + bool _is_done = false; ///< Becarefull when set FIN flag on CONTROL stream. Maybe never? + bool _is_sent = false; ///< Send SETTINGS frame only once +}; diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3ClientSession.cc index f04547d35a7..317a24cc2ae 100644 --- a/proxy/http3/Http3ClientSession.cc +++ b/proxy/http3/Http3ClientSession.cc @@ -23,7 +23,11 @@ #include "Http3ClientSession.h" -Http3ClientSession::Http3ClientSession(NetVConnection *vc) : _client_vc(vc) {} +Http3ClientSession::Http3ClientSession(NetVConnection *vc) : _client_vc(vc) +{ + this->_local_qpack = new QPACK(static_cast(vc)); + this->_remote_qpack = new QPACK(static_cast(vc)); +} Http3ClientSession::~Http3ClientSession() { @@ -31,6 +35,8 @@ Http3ClientSession::~Http3ClientSession() for (Http3ClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { delete t; } + delete this->_local_qpack; + delete this->_remote_qpack; } VIO * @@ -105,7 +111,7 @@ Http3ClientSession::get_transact_count() const const char * Http3ClientSession::get_protocol_string() const { - return "hq-17"; + return IP_PROTO_TAG_HTTP_QUIC.data(); } void @@ -157,3 +163,15 @@ Http3ClientSession::get_transaction(QUICStreamId id) } return nullptr; } + +QPACK * +Http3ClientSession::local_qpack() +{ + return this->_local_qpack; +} + +QPACK * +Http3ClientSession::remote_qpack() +{ + return this->_remote_qpack; +} diff --git a/proxy/http3/Http3ClientSession.h b/proxy/http3/Http3ClientSession.h index 7f2240c4259..38700348051 100644 --- a/proxy/http3/Http3ClientSession.h +++ b/proxy/http3/Http3ClientSession.h @@ -25,6 +25,7 @@ #include "ProxyClientSession.h" #include "Http3ClientTransaction.h" +#include "QPACK.h" class Http3ClientSession : public ProxyClientSession { @@ -57,7 +58,12 @@ class Http3ClientSession : public ProxyClientSession void add_transaction(Http3ClientTransaction *); Http3ClientTransaction *get_transaction(QUICStreamId); + QPACK *local_qpack(); + QPACK *remote_qpack(); + private: NetVConnection *_client_vc = nullptr; + QPACK *_remote_qpack = nullptr; // QPACK for decoding + QPACK *_local_qpack = nullptr; // QPACK for encoding Queue _transaction_list; }; diff --git a/proxy/http3/Http3ClientTransaction.cc b/proxy/http3/Http3ClientTransaction.cc index 009c0c62284..702e3e10277 100644 --- a/proxy/http3/Http3ClientTransaction.cc +++ b/proxy/http3/Http3ClientTransaction.cc @@ -31,6 +31,7 @@ #include "Http3HeaderFramer.h" #include "Http3DataFramer.h" #include "HttpSM.h" +#include "HTTP2.h" #define Http3TransDebug(fmt, ...) \ Debug("http3_trans", "[%s] [%" PRIx32 "] " fmt, \ @@ -62,22 +63,27 @@ Http3ClientTransaction::Http3ClientTransaction(Http3ClientSession *session, QUIC this->sm_reader = this->_read_vio_buf.alloc_reader(); static_cast(this->parent)->add_transaction(this); - this->_header_framer = new Http3HeaderFramer(this, &this->_write_vio); + this->_header_framer = new Http3HeaderFramer(this, &this->_write_vio, session->local_qpack(), stream_io->stream_id()); this->_data_framer = new Http3DataFramer(this, &this->_write_vio); this->_frame_collector.add_generator(this->_header_framer); this->_frame_collector.add_generator(this->_data_framer); // this->_frame_collector.add_generator(this->_push_controller); - this->_header_handler = new Http3HeaderVIOAdaptor(&this->_read_vio); + this->_header_handler = new Http3HeaderVIOAdaptor(&this->_request_header, session->remote_qpack(), this, stream_io->stream_id()); this->_data_handler = new Http3StreamDataVIOAdaptor(&this->_read_vio); + this->_frame_dispatcher.add_handler(this->_header_handler); this->_frame_dispatcher.add_handler(this->_data_handler); + this->_request_header.create(HTTP_TYPE_REQUEST); + SET_HANDLER(&Http3ClientTransaction::state_stream_open); } Http3ClientTransaction::~Http3ClientTransaction() { + this->_request_header.destroy(); + delete this->_header_framer; delete this->_data_framer; delete this->_header_handler; @@ -171,6 +177,18 @@ Http3ClientTransaction::state_stream_open(int event, void *edata) ink_assert(false); break; } + case QPACK_EVENT_DECODE_COMPLETE: { + int res = this->_on_qpack_decode_complete(); + if (res) { + // If READ_READY event is scheduled, should it be canceled? + this->_signal_read_event(); + } + break; + } + case QPACK_EVENT_DECODE_FAILED: { + // FIXME: handle error + break; + } default: Http3TransDebug("Unknown event %d", event); ink_assert(false); @@ -535,6 +553,67 @@ Http3ClientTransaction::_process_write_vio() } } +ParseResult +Http3ClientTransaction::_convert_header_from_3_to_1_1(HTTPHdr *hdr) +{ + // TODO: do HTTP/3 specific convert, if there + + // Dirty hack to bypass checks + char name_a[] = ":authority"; + char value_a[] = "localhost"; + MIMEField *authority_field = this->_request_header.field_create(name_a, sizeof(name_a) - 1); + authority_field->value_set(this->_request_header.m_heap, this->_request_header.m_mime, value_a, sizeof(value_a) - 1); + this->_request_header.field_attach(authority_field); + + char name_s[] = ":scheme"; + char value_s[] = "https"; + MIMEField *scheme_field = this->_request_header.field_create(name_s, sizeof(name_s) - 1); + scheme_field->value_set(this->_request_header.m_heap, this->_request_header.m_mime, value_s, sizeof(value_s) - 1); + this->_request_header.field_attach(scheme_field); + + return http2_convert_header_from_2_to_1_1(hdr); +} + +int +Http3ClientTransaction::_on_qpack_decode_complete() +{ + ParseResult res = this->_convert_header_from_3_to_1_1(&this->_request_header); + if (res == PARSE_RESULT_ERROR) { + return -1; + } + + SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); + MIOBuffer *writer = this->_read_vio.get_writer(); + + // TODO: Http2Stream::send_request has same logic. It originally comes from HttpSM::write_header_into_buffer. + // a). Make HttpSM::write_header_into_buffer static + // or + // b). Add interface to HTTPHdr to dump data + // or + // c). Add interface to HttpSM to handle HTTPHdr directly + int bufindex; + int dumpoffset = 0; + int done, tmp; + IOBufferBlock *block; + do { + bufindex = 0; + tmp = dumpoffset; + block = writer->get_current_block(); + if (!block) { + writer->add_block(); + block = writer->get_current_block(); + } + done = this->_request_header.print(block->start(), block->write_avail(), &bufindex, &tmp); + dumpoffset += bufindex; + writer->fill(bufindex); + if (!done) { + writer->add_block(); + } + } while (!done); + + return 1; +} + void Http3ClientTransaction::transaction_done() { diff --git a/proxy/http3/Http3ClientTransaction.h b/proxy/http3/Http3ClientTransaction.h index b778c203264..a5490fee314 100644 --- a/proxy/http3/Http3ClientTransaction.h +++ b/proxy/http3/Http3ClientTransaction.h @@ -74,6 +74,9 @@ class Http3ClientTransaction : public ProxyClientTransaction int64_t _process_read_vio(); int64_t _process_write_vio(); + ParseResult _convert_header_from_3_to_1_1(HTTPHdr *hdr); + int _on_qpack_decode_complete(); + EThread *_thread = nullptr; Event *_cross_thread_event = nullptr; @@ -85,6 +88,8 @@ class Http3ClientTransaction : public ProxyClientTransaction Event *_read_event = nullptr; Event *_write_event = nullptr; + HTTPHdr _request_header; + // These are for Http3 Http3FrameDispatcher _frame_dispatcher; Http3FrameCollector _frame_collector; diff --git a/proxy/http3/Http3DebugNames.cc b/proxy/http3/Http3DebugNames.cc index 24baf15fde2..e1a78414671 100644 --- a/proxy/http3/Http3DebugNames.cc +++ b/proxy/http3/Http3DebugNames.cc @@ -50,6 +50,12 @@ Http3DebugNames::frame_type(Http3FrameType type) } } +const char * +Http3DebugNames::stream_type(Http3StreamType type) +{ + return Http3DebugNames::stream_type(static_cast(type)); +} + const char * Http3DebugNames::stream_type(uint8_t type) { diff --git a/proxy/http3/Http3DebugNames.h b/proxy/http3/Http3DebugNames.h index bb61a81be2b..c8f34da693c 100644 --- a/proxy/http3/Http3DebugNames.h +++ b/proxy/http3/Http3DebugNames.h @@ -29,6 +29,7 @@ class Http3DebugNames { public: static const char *frame_type(Http3FrameType type); + static const char *stream_type(Http3StreamType type); static const char *stream_type(uint8_t type); static const char *settings_id(uint16_t id); static const char *error_code(uint16_t code); diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc index 6b6c0147320..f704b3d9cd2 100644 --- a/proxy/http3/Http3Frame.cc +++ b/proxy/http3/Http3Frame.cc @@ -415,6 +415,21 @@ Http3FrameFactory::create_headers_frame(const uint8_t *header_block, size_t head return Http3HeadersFrameUPtr(frame, &Http3FrameDeleter::delete_headers_frame); } +Http3HeadersFrameUPtr +Http3FrameFactory::create_headers_frame(IOBufferReader *header_block_reader, size_t header_block_len) +{ + ats_unique_buf buf = ats_unique_malloc(header_block_len); + + int64_t nread; + while ((nread = header_block_reader->read(buf.get(), header_block_len)) > 0) { + ; + } + + Http3HeadersFrame *frame = http3HeadersFrameAllocator.alloc(); + new (frame) Http3HeadersFrame(std::move(buf), header_block_len); + return Http3HeadersFrameUPtr(frame, &Http3FrameDeleter::delete_headers_frame); +} + Http3DataFrameUPtr Http3FrameFactory::create_data_frame(const uint8_t *payload, size_t payload_len) { diff --git a/proxy/http3/Http3Frame.h b/proxy/http3/Http3Frame.h index 3273476bdf5..be0b48e540a 100644 --- a/proxy/http3/Http3Frame.h +++ b/proxy/http3/Http3Frame.h @@ -225,6 +225,7 @@ class Http3FrameFactory * Creates a HEADERS frame. */ static Http3HeadersFrameUPtr create_headers_frame(const uint8_t *header_block, size_t header_block_len); + static Http3HeadersFrameUPtr create_headers_frame(IOBufferReader *header_block_reader, size_t header_block_len); /* * Creates a DATA frame. diff --git a/proxy/http3/Http3FrameCollector.cc b/proxy/http3/Http3FrameCollector.cc index 7409bc15a5b..7ee5afeee7d 100644 --- a/proxy/http3/Http3FrameCollector.cc +++ b/proxy/http3/Http3FrameCollector.cc @@ -23,6 +23,8 @@ #include "Http3FrameCollector.h" +#include "Http3DebugNames.h" + Http3ErrorUPtr Http3FrameCollector::on_write_ready(QUICStreamIO *stream_io, size_t &nwritten) { @@ -39,7 +41,10 @@ Http3FrameCollector::on_write_ready(QUICStreamIO *stream_io, size_t &nwritten) if (frame) { frame->store(tmp + nwritten, &len); nwritten += len; + + Debug("http3", "[TX] [%d] | %s", stream_io->stream_id(), Http3DebugNames::frame_type(frame->type())); } + all_done &= g->is_done(); } diff --git a/proxy/http3/Http3FrameDispatcher.cc b/proxy/http3/Http3FrameDispatcher.cc index 13070728447..24a56c412d7 100644 --- a/proxy/http3/Http3FrameDispatcher.cc +++ b/proxy/http3/Http3FrameDispatcher.cc @@ -21,10 +21,12 @@ * limitations under the License. */ -#include "QUICIntUtil.h" #include "Http3FrameDispatcher.h" -#include "Http3DebugNames.h" + #include "tscore/Diags.h" +#include "QUICIntUtil.h" + +#include "Http3DebugNames.h" // // Frame Dispatcher @@ -83,7 +85,7 @@ Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) // Dispatch Http3FrameType type = frame->type(); - Debug("http3", "[RX] | %s", Http3DebugNames::frame_type(type)); + Debug("http3", "[RX] [%d] | %s", stream_io.stream_id(), Http3DebugNames::frame_type(type)); std::vector handlers = this->_handlers[static_cast(type)]; for (auto h : handlers) { error = h->handle_frame(frame); diff --git a/proxy/http3/Http3FrameGenerator.h b/proxy/http3/Http3FrameGenerator.h index a3633d14402..6da188f6070 100644 --- a/proxy/http3/Http3FrameGenerator.h +++ b/proxy/http3/Http3FrameGenerator.h @@ -23,6 +23,8 @@ #pragma once +#include "Http3Frame.h" + class Http3FrameGenerator { public: diff --git a/proxy/http3/Http3HeaderFramer.cc b/proxy/http3/Http3HeaderFramer.cc index f437cbe0174..6bda091473b 100644 --- a/proxy/http3/Http3HeaderFramer.cc +++ b/proxy/http3/Http3HeaderFramer.cc @@ -21,14 +21,18 @@ * limitations under the License. */ -#include "Http3Frame.h" #include "Http3HeaderFramer.h" -#include "Http3ClientTransaction.h" -#include "HTTP.h" + #include "I_VIO.h" -Http3HeaderFramer::Http3HeaderFramer(Http3ClientTransaction *transaction, VIO *source) - : _transaction(transaction), _source_vio(source) +#include "HTTP.h" +#include "HTTP2.h" + +#include "Http3Frame.h" +#include "Http3ClientTransaction.h" + +Http3HeaderFramer::Http3HeaderFramer(Http3ClientTransaction *transaction, VIO *source, QPACK *qpack, uint64_t stream_id) + : _transaction(transaction), _source_vio(source), _qpack(qpack), _stream_id(stream_id) { http_parser_init(&this->_http_parser); } @@ -45,10 +49,12 @@ Http3HeaderFramer::generate_frame(uint16_t max_size) if (this->_header_block) { // Create frames on demand base on max_size since we don't know how much we can write now - const uint8_t *start = this->_header_block + this->_header_block_wrote; - size_t len = std::min(this->_header_block_len - this->_header_block_wrote, static_cast(max_size)); - Http3FrameUPtr frame = Http3FrameFactory::create_headers_frame(start, len); + uint64_t len = std::min(this->_header_block_len - this->_header_block_wrote, static_cast(max_size)); + + Http3FrameUPtr frame = Http3FrameFactory::create_headers_frame(this->_header_block_reader, len); + this->_header_block_wrote += len; + if (this->_header_block_len == this->_header_block_wrote) { this->_sent_all_data = true; } @@ -64,6 +70,46 @@ Http3HeaderFramer::is_done() const return this->_sent_all_data; } +const char *HTTP3_VALUE_STATUS = ":status"; +const unsigned HTTP3_LEN_STATUS = countof(":status") - 1; +static size_t HTTP3_LEN_STATUS_VALUE_STR = 3; + +// Copy code from http2_generate_h2_header_from_1_1(h1_hdrs, h3_hdrs); +void +Http3HeaderFramer::_convert_header_from_1_1_to_3(HTTPHdr *h3_hdrs, HTTPHdr *h1_hdrs) +{ + // Add ':status' header field + char status_str[HTTP3_LEN_STATUS_VALUE_STR + 1]; + snprintf(status_str, sizeof(status_str), "%d", h1_hdrs->status_get()); + MIMEField *status_field = h3_hdrs->field_create(HTTP3_VALUE_STATUS, HTTP3_LEN_STATUS); + status_field->value_set(h3_hdrs->m_heap, h3_hdrs->m_mime, status_str, HTTP3_LEN_STATUS_VALUE_STR); + h3_hdrs->field_attach(status_field); + + // Copy headers + // Intermediaries SHOULD remove connection-specific header fields. + MIMEFieldIter field_iter; + for (MIMEField *field = h1_hdrs->iter_get_first(&field_iter); field != nullptr; field = h1_hdrs->iter_get_next(&field_iter)) { + const char *name; + int name_len; + const char *value; + int value_len; + name = field->name_get(&name_len); + if ((name_len == MIME_LEN_CONNECTION && strncasecmp(name, MIME_FIELD_CONNECTION, name_len) == 0) || + (name_len == MIME_LEN_KEEP_ALIVE && strncasecmp(name, MIME_FIELD_KEEP_ALIVE, name_len) == 0) || + (name_len == MIME_LEN_PROXY_CONNECTION && strncasecmp(name, MIME_FIELD_PROXY_CONNECTION, name_len) == 0) || + (name_len == MIME_LEN_TRANSFER_ENCODING && strncasecmp(name, MIME_FIELD_TRANSFER_ENCODING, name_len) == 0) || + (name_len == MIME_LEN_UPGRADE && strncasecmp(name, MIME_FIELD_UPGRADE, name_len) == 0)) { + continue; + } + MIMEField *newfield; + name = field->name_get(&name_len); + newfield = h3_hdrs->field_create(name, name_len); + value = field->value_get(&value_len); + newfield->value_set(h3_hdrs->m_heap, h3_hdrs->m_mime, value, value_len); + h3_hdrs->field_attach(newfield); + } +} + void Http3HeaderFramer::_generate_header_block() { @@ -75,25 +121,20 @@ Http3HeaderFramer::_generate_header_block() this->_source_vio->ndone += this->_header.length_get(); switch (parse_result) { - case PARSE_RESULT_DONE: - this->_compress_header(); + case PARSE_RESULT_DONE: { + HTTPHdr h3_hdr; + h3_hdr.create(HTTP_TYPE_RESPONSE); + this->_convert_header_from_1_1_to_3(&h3_hdr, &this->_header); + + this->_header_block = new_MIOBuffer(); + this->_header_block_reader = this->_header_block->alloc_reader(); + + this->_qpack->encode(this->_stream_id, h3_hdr, this->_header_block, this->_header_block_len); break; + } case PARSE_RESULT_CONT: break; default: break; } } - -void -Http3HeaderFramer::_compress_header() -{ - // TODO Compress the header data - // Just copy the header data for now. - int written = 0; - int tmp = 0; - int len = this->_header.length_get(); - this->_header_block = static_cast(ats_malloc(len)); - this->_header.print(reinterpret_cast(this->_header_block), len, &written, &tmp); - this->_header_block_len = written; -} diff --git a/proxy/http3/Http3HeaderFramer.h b/proxy/http3/Http3HeaderFramer.h index 0311a2f72b1..165d178518c 100644 --- a/proxy/http3/Http3HeaderFramer.h +++ b/proxy/http3/Http3HeaderFramer.h @@ -23,9 +23,12 @@ #pragma once +#include "hdrs/HTTP.h" + +#include "QPACK.h" + #include "Http3FrameGenerator.h" #include "Http3Frame.h" -#include "hdrs/HTTP.h" class Http3ClientTransaction; class VIO; @@ -33,7 +36,7 @@ class VIO; class Http3HeaderFramer : public Http3FrameGenerator { public: - Http3HeaderFramer(Http3ClientTransaction *transaction, VIO *source); + Http3HeaderFramer(Http3ClientTransaction *transaction, VIO *source, QPACK *qpack, uint64_t stream_id); // Http3FrameGenerator Http3FrameUPtr generate_frame(uint16_t max_size) override; @@ -42,13 +45,16 @@ class Http3HeaderFramer : public Http3FrameGenerator private: Http3ClientTransaction *_transaction = nullptr; VIO *_source_vio = nullptr; + QPACK *_qpack = nullptr; + MIOBuffer *_header_block = nullptr; + IOBufferReader *_header_block_reader = nullptr; + uint64_t _header_block_len = 0; + uint64_t _header_block_wrote = 0; + uint64_t _stream_id = 0; + bool _sent_all_data = false; HTTPParser _http_parser; HTTPHdr _header; - uint8_t *_header_block = nullptr; - size_t _header_block_len = 0; - size_t _header_block_wrote = 0; - bool _sent_all_data = false; + void _convert_header_from_1_1_to_3(HTTPHdr *h3_hdrs, HTTPHdr *h1_hdrs); void _generate_header_block(); - void _compress_header(); }; diff --git a/proxy/http3/Http3HeaderVIOAdaptor.cc b/proxy/http3/Http3HeaderVIOAdaptor.cc index db7de9cca95..c2e4414151c 100644 --- a/proxy/http3/Http3HeaderVIOAdaptor.cc +++ b/proxy/http3/Http3HeaderVIOAdaptor.cc @@ -22,9 +22,14 @@ */ #include "Http3HeaderVIOAdaptor.h" + #include "I_VIO.h" +#include "HTTP.h" -Http3HeaderVIOAdaptor::Http3HeaderVIOAdaptor(VIO *sink) : _sink_vio(sink) {} +Http3HeaderVIOAdaptor::Http3HeaderVIOAdaptor(HTTPHdr *hdr, QPACK *qpack, Continuation *cont, uint64_t stream_id) + : _request_header(hdr), _qpack(qpack), _cont(cont), _stream_id(stream_id) +{ +} std::vector Http3HeaderVIOAdaptor::interests() @@ -38,11 +43,18 @@ Http3HeaderVIOAdaptor::handle_frame(std::shared_ptr frame) ink_assert(frame->type() == Http3FrameType::HEADERS); const Http3HeadersFrame *hframe = dynamic_cast(frame.get()); - SCOPED_MUTEX_LOCK(lock, this->_sink_vio->mutex, this_ethread()); - - MIOBuffer *writer = this->_sink_vio->get_writer(); - // TODO Uncompress header block - writer->write(hframe->header_block(), hframe->header_block_length()); + int res = this->_qpack->decode(this->_stream_id, hframe->header_block(), hframe->header_block_length(), *this->_request_header, + this->_cont); + + if (res == 0) { + // When decoding is not blocked, continuation should be called directly? + } else if (res == 1) { + // Decoding is blocked. Callback will be fired. + } else if (res < 0) { + // error + } else { + // should not be here + } return Http3ErrorUPtr(new Http3NoError()); } diff --git a/proxy/http3/Http3HeaderVIOAdaptor.h b/proxy/http3/Http3HeaderVIOAdaptor.h index 0a497feefe7..1df2b71a75f 100644 --- a/proxy/http3/Http3HeaderVIOAdaptor.h +++ b/proxy/http3/Http3HeaderVIOAdaptor.h @@ -23,19 +23,22 @@ #pragma once -#include "Http3FrameHandler.h" +#include "QPACK.h" -class VIO; +#include "Http3FrameHandler.h" +// TODO: rename, this is not VIOAdoptor anymore class Http3HeaderVIOAdaptor : public Http3FrameHandler { public: - Http3HeaderVIOAdaptor(VIO *sink); - + Http3HeaderVIOAdaptor(HTTPHdr *hdr, QPACK *qpack, Continuation *cont, uint64_t stream_id); // Http3FrameHandler std::vector interests() override; Http3ErrorUPtr handle_frame(std::shared_ptr frame) override; private: - VIO *_sink_vio = nullptr; + HTTPHdr *_request_header = nullptr; + QPACK *_qpack = nullptr; + Continuation *_cont = nullptr; + uint64_t _stream_id = 0; }; diff --git a/proxy/http3/Http3SessionAccept.cc b/proxy/http3/Http3SessionAccept.cc index 5db8abb08ef..220a5008c3d 100644 --- a/proxy/http3/Http3SessionAccept.cc +++ b/proxy/http3/Http3SessionAccept.cc @@ -26,7 +26,9 @@ #include "P_Net.h" #include "I_Machine.h" #include "IPAllow.h" + #include "QUICSimpleApp.h" +#include "Http3App.h" Http3SessionAccept::Http3SessionAccept(const HttpSessionAccept::Options &_o) : SessionAccept(nullptr), options(_o) { @@ -56,7 +58,11 @@ Http3SessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferRead ats_ip_nptop(client_ip, ipb, sizeof(ipb)), netvc->attributes); } - new QUICSimpleApp(static_cast(netvc), std::move(session_acl)); + // TODO: switch by ALPN + // new QUICSimpleApp(static_cast(netvc), std::move(session_acl)); + // who will destruct this app? + Http3App *app = new Http3App(static_cast(netvc), std::move(session_acl)); + app->start(); return true; } diff --git a/proxy/http3/Http3Types.cc b/proxy/http3/Http3Types.cc new file mode 100644 index 00000000000..77eb2158fb8 --- /dev/null +++ b/proxy/http3/Http3Types.cc @@ -0,0 +1,41 @@ +/** @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 "Http3Types.h" + +Http3StreamType +Http3Stream::type(const uint8_t *buf) +{ + switch (*buf) { + case static_cast(Http3StreamType::CONTROL): + return Http3StreamType::CONTROL; + case static_cast(Http3StreamType::PUSH): + return Http3StreamType::PUSH; + case static_cast(Http3StreamType::QPACK_ENCODER): + return Http3StreamType::QPACK_ENCODER; + case static_cast(Http3StreamType::QPACK_DECODER): + return Http3StreamType::QPACK_DECODER; + default: + return Http3StreamType::UNKOWN; + } +} diff --git a/proxy/http3/Http3Types.h b/proxy/http3/Http3Types.h index 142418fff3a..c37ea628626 100644 --- a/proxy/http3/Http3Types.h +++ b/proxy/http3/Http3Types.h @@ -29,9 +29,9 @@ enum class Http3StreamType : uint8_t { CONTROL = 0x43, ///< HTTP/3 - QPACK_ENCODER = 0x48, ///< QPACK + QPACK_ENCODER = 0x48, ///< QPACK : encoder -> decoder PUSH = 0x50, ///< HTTP/3 - QPACK_DECODER = 0x68, ///< QPACK + QPACK_DECODER = 0x68, ///< QPACK : decoder -> encoder RESERVED = 0x1F, UNKOWN = 0xFF, }; @@ -131,7 +131,11 @@ class Http3ConnectionError : public Http3Error Http3ConnectionError(const Http3ErrorCode error_code, const char *error_msg = nullptr) : Http3Error(error_code, error_msg){}; }; -class Http3Stream; +class Http3Stream +{ +public: + static Http3StreamType type(const uint8_t *buf); +}; class Http3StreamError : public Http3Error { diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index aa6219dad37..5fd1c5045c5 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -26,6 +26,7 @@ AM_CPPFLAGS += \ -I$(abs_top_srcdir)/mgmt/utils \ -I$(abs_top_srcdir)/proxy \ -I$(abs_top_srcdir)/proxy/http \ + -I$(abs_top_srcdir)/proxy/http2 \ -I$(abs_top_srcdir)/proxy/hdrs \ -I$(abs_top_srcdir)/proxy/shared \ -I$(abs_top_srcdir)/proxy/http/remap \ @@ -35,6 +36,8 @@ noinst_LIBRARIES = libhttp3.a libhttp3_a_SOURCES = \ Http3.cc \ + Http3App.cc \ + Http3Types.cc \ Http3SessionAccept.cc \ Http3ClientSession.cc \ Http3ClientTransaction.cc \ diff --git a/proxy/http3/QPACK.cc b/proxy/http3/QPACK.cc index 9fa397b43fe..e1603c8d251 100644 --- a/proxy/http3/QPACK.cc +++ b/proxy/http3/QPACK.cc @@ -175,7 +175,7 @@ QPACK::event_handler(int event, Event *data) } int -QPACK::encode(uint64_t stream_id, HTTPHdr &header_set, MIOBuffer *header_block) +QPACK::encode(uint64_t stream_id, HTTPHdr &header_set, MIOBuffer *header_block, uint64_t &header_block_len) { if (!header_block) { return -1; @@ -209,7 +209,10 @@ QPACK::encode(uint64_t stream_id, HTTPHdr &header_set, MIOBuffer *header_block) this->_encode_prefix(largest_reference, base_index, header_data_prefix); header_block->append_block(header_data_prefix); + header_block_len += header_data_prefix->size(); + header_block->append_block(compressed_headers); + header_block_len += compressed_headers->size(); return 0; } @@ -224,7 +227,7 @@ QPACK::decode(uint64_t stream_id, const uint8_t *header_block, size_t header_blo if (this->_invalid) { thread->schedule_imm(cont, QPACK_EVENT_DECODE_FAILED, nullptr); - return 0; + return -1; } uint64_t tmp = 0; @@ -250,6 +253,20 @@ QPACK::decode(uint64_t stream_id, const uint8_t *header_block, size_t header_blo return 0; } +void +QPACK::set_encoder_stream(QUICStreamIO *stream_io) +{ + this->_encoder_stream_id = stream_io->stream_id(); + this->set_stream(stream_io); +} + +void +QPACK::set_decoder_stream(QUICStreamIO *stream_io) +{ + this->_decoder_stream_id = stream_io->stream_id(); + this->set_stream(stream_io); +} + int QPACK::_encode_prefix(uint16_t largest_reference, uint16_t base_index, IOBufferBlock *prefix) { @@ -1202,6 +1219,11 @@ QPACK::DynamicTable::lookup(const char *name, int name_len, const char *value, i const char *tmp_name = nullptr; const char *tmp_value = nullptr; + // DynamicTable is empty + if (this->_entries_inserted == 0) { + return {candidate_index, match_type}; + } + // TODO Use a tree for better perfomance for (; i <= end; i = (i + 1) % this->_max_entries) { if (name_len != 0 && this->_entries[i].name_len == name_len) { @@ -1220,6 +1242,7 @@ QPACK::DynamicTable::lookup(const char *name, int name_len, const char *value, i } } } + return {candidate_index, match_type}; } @@ -1242,6 +1265,10 @@ QPACK::DynamicTable::insert_entry(bool is_static, uint16_t index, const char *va const QPACK::LookupResult QPACK::DynamicTable::insert_entry(const char *name, uint16_t name_len, const char *value, uint16_t value_len) { + if (this->_max_entries == 0) { + return {UINT16_C(0), QPACK::LookupResult::MatchType::NONE}; + } + // Check if we can make enough space to insert a new entry uint16_t required_len = name_len + value_len; uint16_t available = this->_available; diff --git a/proxy/http3/QPACK.h b/proxy/http3/QPACK.h index 82a65874d8c..68c67acbeff 100644 --- a/proxy/http3/QPACK.h +++ b/proxy/http3/QPACK.h @@ -37,13 +37,14 @@ enum { }; // FIXME This setting should be passed by HTTP/3 -constexpr int SETTINGS_HEADER_TABLE_SIZE = 4096; -constexpr int SETTINGS_QPACK_BLOCKED_STREAMS = 100; +constexpr int SETTINGS_HEADER_TABLE_SIZE = 0; +constexpr int SETTINGS_QPACK_BLOCKED_STREAMS = 0; class QPACK : public QUICApplication { public: - QPACK(QUICConnection *qc, uint16_t max_table_size, uint16_t max_blocking_streams); + QPACK(QUICConnection *qc, uint16_t max_table_size = SETTINGS_HEADER_TABLE_SIZE, + uint16_t max_blocking_streams = SETTINGS_QPACK_BLOCKED_STREAMS); virtual ~QPACK(); int event_handler(int event, Event *data); @@ -52,7 +53,7 @@ class QPACK : public QUICApplication * header_block must have enough size to store all headers in header_set. * The maximum size can be estimated with QPACK::estimate_header_block_size(). */ - int encode(uint64_t stream_id, HTTPHdr &header_set, MIOBuffer *header_block); + int encode(uint64_t stream_id, HTTPHdr &header_set, MIOBuffer *header_block, uint64_t &header_block_len); /* * This will emit either of two events below: @@ -64,6 +65,9 @@ class QPACK : public QUICApplication int cancel(uint64_t stream_id); + void set_encoder_stream(QUICStreamIO *stream_io); + void set_decoder_stream(QUICStreamIO *stream_io); + static size_t estimate_header_block_size(const HTTPHdr &header_set); private: diff --git a/proxy/http3/test/test_Http3Frame.cc b/proxy/http3/test/test_Http3Frame.cc index 38dcc17e5db..321b62ece3d 100644 --- a/proxy/http3/test/test_Http3Frame.cc +++ b/proxy/http3/test/test_Http3Frame.cc @@ -96,6 +96,31 @@ TEST_CASE("Store DATA Frame", "[http3]") } } +TEST_CASE("Store HEADERS Frame", "[http3]") +{ + SECTION("Normal") + { + uint8_t buf[32] = {0}; + size_t len; + uint8_t expected1[] = { + 0x04, // Length + 0x01, // Type + 0x11, 0x22, 0x33, 0x44, // Payload + }; + + uint8_t raw1[] = "\x11\x22\x33\x44"; + ats_unique_buf header_block = ats_unique_malloc(4); + memcpy(header_block.get(), raw1, 4); + + Http3HeadersFrame hdrs_frame(std::move(header_block), 4); + CHECK(hdrs_frame.length() == 4); + + hdrs_frame.store(buf, &len); + CHECK(len == 6); + CHECK(memcmp(buf, expected1, len) == 0); + } +} + TEST_CASE("Load SETTINGS Frame", "[http3]") { SECTION("Normal") diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc index 80680462757..d2eb7e0dd17 100644 --- a/src/traffic_quic/quic_client.cc +++ b/src/traffic_quic/quic_client.cc @@ -128,6 +128,16 @@ QUICClientApp::start(const char *path) std::ofstream f_stream(this->_filename, std::ios::binary | std::ios::trunc); } + if (this->_config->http3) { + this->_start_http_3_session(path); + } else { + this->_start_http_09_session(path); + } +} + +void +QUICClientApp::_start_http_09_session(const char *path) +{ QUICStreamId stream_id; QUICConnectionErrorUPtr error = this->_qc->stream_manager()->create_bidi_stream(stream_id); @@ -149,6 +159,41 @@ QUICClientApp::start(const char *path) stream_io->write_reenable(); } +void +QUICClientApp::_start_http_3_session(const char *path) +{ + QUICConnectionErrorUPtr error; + + QUICStreamId settings_stream_id; + error = this->_qc->stream_manager()->create_uni_stream(settings_stream_id); + + if (error != nullptr) { + Error("%s", error->msg); + ink_abort("Could not create uni stream : %s", error->msg); + } + // TODO: send settings frame + + QUICStreamId stream_id; + error = this->_qc->stream_manager()->create_bidi_stream(stream_id); + + if (error != nullptr) { + Error("%s", error->msg); + ink_abort("Could not create bidi stream : %s", error->msg); + } + + // TODO: move to transaction + char request[1024] = {0}; + int request_len = snprintf(request, sizeof(request), "GET %s\r\n", path); + + QUICClientAppDebug("\n%s", request); + + QUICStreamIO *stream_io = this->_find_stream_io(stream_id); + + stream_io->write(reinterpret_cast(request), request_len); + stream_io->write_done(); + stream_io->write_reenable(); +} + int QUICClientApp::main_event_handler(int event, Event *data) { diff --git a/src/traffic_quic/quic_client.h b/src/traffic_quic/quic_client.h index 384acac658d..fe66740d5b7 100644 --- a/src/traffic_quic/quic_client.h +++ b/src/traffic_quic/quic_client.h @@ -38,6 +38,8 @@ struct QUICClientConfig { char path[1018] = "/"; char debug_tags[1024] = "quic|vv_quic_crypto"; int close = false; + int http0_9 = true; + int http3 = false; }; class QUICClient : public Continuation @@ -63,6 +65,9 @@ class QUICClientApp : public QUICApplication int main_event_handler(int event, Event *data); private: + void _start_http_09_session(const char *path); + void _start_http_3_session(const char *path); + const QUICClientConfig *_config = nullptr; const char *_filename = nullptr; }; diff --git a/src/traffic_quic/traffic_quic.cc b/src/traffic_quic/traffic_quic.cc index ccc56f03eea..879b64f757c 100644 --- a/src/traffic_quic/traffic_quic.cc +++ b/src/traffic_quic/traffic_quic.cc @@ -58,6 +58,9 @@ main(int argc, const char **argv) {"path", 'P', "Path", "S1017", config.path, nullptr, nullptr}, {"debug", 'T', "Vertical-bar-separated Debug Tags", "S1023", config.debug_tags, nullptr, nullptr}, {"close", 'c', "Enable connection close excercise", "F", &config.close, nullptr, nullptr}, + {"http0_9", '-', "Enable HTTP/0.9", "T", &config.http0_9, nullptr, nullptr}, + {"http3", '-', "Enable HTTP/3", "F", &config.http3, nullptr, nullptr}, + HELP_ARGUMENT_DESCRIPTION(), VERSION_ARGUMENT_DESCRIPTION(), RUNROOT_ARGUMENT_DESCRIPTION(), @@ -66,6 +69,10 @@ main(int argc, const char **argv) // Process command line arguments and dump into variables process_args(&appVersionInfo, argument_descriptions, countof(argument_descriptions), argv); + if (config.http3) { + config.http0_9 = false; + } + init_diags(config.debug_tags, nullptr); RecProcessInit(RECM_STAND_ALONE); LibRecordsConfigInit(); diff --git a/src/tscore/ink_inet.cc b/src/tscore/ink_inet.cc index 3e67924a37c..8a279cf2840 100644 --- a/src/tscore/ink_inet.cc +++ b/src/tscore/ink_inet.cc @@ -50,7 +50,7 @@ const std::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"sv); const std::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"sv); const std::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"sv); const std::string_view IP_PROTO_TAG_HTTP_2_0("h2"sv); // HTTP/2 over TLS -const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-17"sv); // HTTP/3 over QUIC +const std::string_view IP_PROTO_TAG_HTTP_QUIC("h3-17"sv); // HTTP/3 over QUIC const std::string_view UNIX_PROTO_TAG{"unix"sv}; From 9672461941d7dee41ebaf983b160f50ee220d231 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 28 Jan 2019 16:01:13 +0900 Subject: [PATCH 1061/1313] Create QPACK ENCODER/DECODER stream --- proxy/http3/Http3App.cc | 64 ++++++++++++++++++++++++++--------------- proxy/http3/Http3App.h | 1 + 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 4d3aaf635e7..09907c4d7d2 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -61,17 +61,16 @@ void Http3App::start() { QUICStreamId stream_id; - QUICConnectionErrorUPtr error = this->create_uni_stream(stream_id, Http3StreamType::CONTROL); - if (error != nullptr) { - ink_abort("Could not creat CONTROL stream"); - } + this->create_uni_stream(stream_id, Http3StreamType::CONTROL); this->_local_control_stream = this->_find_stream_io(stream_id); - this->_local_uni_stream_map.insert(std::make_pair(stream_id, Http3StreamType::CONTROL)); + this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_local_control_stream); - // Should do this->handleEvent(VC_EVENT_WRITE_READY, vio); ??? + this->create_uni_stream(stream_id, Http3StreamType::QPACK_ENCODER); + this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_find_stream_io(stream_id)); - this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_local_control_stream); + this->create_uni_stream(stream_id, Http3StreamType::QPACK_DECODER); + this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_find_stream_io(stream_id)); } int @@ -124,8 +123,15 @@ Http3App::create_uni_stream(QUICStreamId &new_stream_id, Http3StreamType type) if (error == nullptr) { QUICStreamIO *stream_io = this->_find_stream_io(new_stream_id); - uint8_t buf[] = {static_cast(type)}; + + uint8_t buf[] = {static_cast(type)}; stream_io->write(buf, sizeof(uint8_t)); + + this->_local_uni_stream_map.insert(std::make_pair(new_stream_id, type)); + + Debug("http3", "[%llu] %s stream is created", new_stream_id, Http3DebugNames::stream_type(type)); + } else { + ink_abort("Could not creat %s stream", Http3DebugNames::stream_type(type)); } return error; @@ -164,22 +170,9 @@ Http3App::_handle_uni_stream_on_read_ready(int /* event */, QUICStreamIO *stream // TODO: when PUSH comes from client, send stream error with HTTP_WRONG_STREAM_DIRECTION break; } - case Http3StreamType::QPACK_ENCODER: { - // Change app to QPACK from Http3 - if (this->_qc->direction() == NET_VCONNECTION_IN) { - this->_client_session->remote_qpack()->set_encoder_stream(stream_io); - } else { - this->_client_session->local_qpack()->set_encoder_stream(stream_io); - } - break; - } + case Http3StreamType::QPACK_ENCODER: case Http3StreamType::QPACK_DECODER: { - if (this->_qc->direction() == NET_VCONNECTION_IN) { - this->_client_session->local_qpack()->set_decoder_stream(stream_io); - } else { - this->_client_session->remote_qpack()->set_decoder_stream(stream_io); - } - break; + this->_set_qpack_stream(type, stream_io); } case Http3StreamType::UNKOWN: default: @@ -223,6 +216,10 @@ Http3App::_handle_uni_stream_on_write_ready(int /* event */, QUICStreamIO *strea this->_control_stream_collector.on_write_ready(stream_io, nwritten); break; } + case Http3StreamType::QPACK_ENCODER: + case Http3StreamType::QPACK_DECODER: { + this->_set_qpack_stream(it->second, stream_io); + } case Http3StreamType::UNKOWN: case Http3StreamType::PUSH: default: @@ -230,6 +227,27 @@ Http3App::_handle_uni_stream_on_write_ready(int /* event */, QUICStreamIO *strea } } +void +Http3App::_set_qpack_stream(Http3StreamType type, QUICStreamIO *stream_io) +{ + // Change app to QPACK from Http3 + if (type == Http3StreamType::QPACK_ENCODER) { + if (this->_qc->direction() == NET_VCONNECTION_IN) { + this->_client_session->remote_qpack()->set_encoder_stream(stream_io); + } else { + this->_client_session->local_qpack()->set_encoder_stream(stream_io); + } + } else if (type == Http3StreamType::QPACK_DECODER) { + if (this->_qc->direction() == NET_VCONNECTION_IN) { + this->_client_session->local_qpack()->set_decoder_stream(stream_io); + } else { + this->_client_session->remote_qpack()->set_decoder_stream(stream_io); + } + } else { + ink_abort("unkown stream type"); + } +} + void Http3App::_handle_bidi_stream_on_write_ready(int event, QUICStreamIO *stream_io) { diff --git a/proxy/http3/Http3App.h b/proxy/http3/Http3App.h index 0a9667022ea..49e0e07c18e 100644 --- a/proxy/http3/Http3App.h +++ b/proxy/http3/Http3App.h @@ -58,6 +58,7 @@ class Http3App : public QUICApplication void _handle_bidi_stream_on_read_ready(int event, QUICStreamIO *stream_io); void _handle_uni_stream_on_write_ready(int event, QUICStreamIO *stream_io); void _handle_bidi_stream_on_write_ready(int event, QUICStreamIO *stream_io); + void _set_qpack_stream(Http3StreamType type, QUICStreamIO *stream_io); Http3ClientSession *_client_session = nullptr; Http3FrameHandler *_settings_handler = nullptr; From 524d0029fb2b4296a75a065c801d64dcdb50c3b3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 28 Jan 2019 16:20:44 +0900 Subject: [PATCH 1062/1313] Add scheme & authority only if not exists --- proxy/http3/Http3ClientTransaction.cc | 38 +++++++++++++++++---------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/proxy/http3/Http3ClientTransaction.cc b/proxy/http3/Http3ClientTransaction.cc index 702e3e10277..f0ec7d41cc4 100644 --- a/proxy/http3/Http3ClientTransaction.cc +++ b/proxy/http3/Http3ClientTransaction.cc @@ -553,25 +553,35 @@ Http3ClientTransaction::_process_write_vio() } } +// Constant strings for pseudo headers +const char *HTTP3_VALUE_SCHEME = ":scheme"; +const char *HTTP3_VALUE_AUTHORITY = ":authority"; + +const unsigned HTTP3_LEN_SCHEME = countof(":scheme") - 1; +const unsigned HTTP3_LEN_AUTHORITY = countof(":authority") - 1; + ParseResult -Http3ClientTransaction::_convert_header_from_3_to_1_1(HTTPHdr *hdr) +Http3ClientTransaction::_convert_header_from_3_to_1_1(HTTPHdr *hdrs) { // TODO: do HTTP/3 specific convert, if there // Dirty hack to bypass checks - char name_a[] = ":authority"; - char value_a[] = "localhost"; - MIMEField *authority_field = this->_request_header.field_create(name_a, sizeof(name_a) - 1); - authority_field->value_set(this->_request_header.m_heap, this->_request_header.m_mime, value_a, sizeof(value_a) - 1); - this->_request_header.field_attach(authority_field); - - char name_s[] = ":scheme"; - char value_s[] = "https"; - MIMEField *scheme_field = this->_request_header.field_create(name_s, sizeof(name_s) - 1); - scheme_field->value_set(this->_request_header.m_heap, this->_request_header.m_mime, value_s, sizeof(value_s) - 1); - this->_request_header.field_attach(scheme_field); - - return http2_convert_header_from_2_to_1_1(hdr); + MIMEField *field; + if ((field = hdrs->field_find(HTTP3_VALUE_SCHEME, HTTP3_LEN_SCHEME)) == nullptr) { + char value_s[] = "https"; + MIMEField *scheme_field = hdrs->field_create(HTTP3_VALUE_SCHEME, HTTP3_LEN_SCHEME); + scheme_field->value_set(hdrs->m_heap, hdrs->m_mime, value_s, sizeof(value_s) - 1); + hdrs->field_attach(scheme_field); + } + + if ((field = hdrs->field_find(HTTP3_VALUE_AUTHORITY, HTTP3_LEN_AUTHORITY)) == nullptr) { + char value_a[] = "localhost"; + MIMEField *authority_field = hdrs->field_create(HTTP3_VALUE_AUTHORITY, HTTP3_LEN_AUTHORITY); + authority_field->value_set(hdrs->m_heap, hdrs->m_mime, value_a, sizeof(value_a) - 1); + hdrs->field_attach(authority_field); + } + + return http2_convert_header_from_2_to_1_1(hdrs); } int From dc0198f742a0a76bdca8ab840aeb1981a7eb708a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 29 Jan 2019 09:44:24 +0900 Subject: [PATCH 1063/1313] Add IP_PROTO_TAG for HTTP/3 --- include/tscore/ink_inet.h | 1 + lib/records/RecHttp.cc | 6 ++++++ proxy/http/HttpProxyServerMain.cc | 7 ++++++- src/tscore/ink_inet.cc | 3 ++- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/tscore/ink_inet.h b/include/tscore/ink_inet.h index 32e7e2e48d9..4f590101fa4 100644 --- a/include/tscore/ink_inet.h +++ b/include/tscore/ink_inet.h @@ -60,6 +60,7 @@ extern const std::string_view IP_PROTO_TAG_HTTP_1_0; extern const std::string_view IP_PROTO_TAG_HTTP_1_1; extern const std::string_view IP_PROTO_TAG_HTTP_2_0; extern const std::string_view IP_PROTO_TAG_HTTP_QUIC; +extern const std::string_view IP_PROTO_TAG_HTTP_3; struct IpAddr; // forward declare. diff --git a/lib/records/RecHttp.cc b/lib/records/RecHttp.cc index ceda95fed36..253955eb515 100644 --- a/lib/records/RecHttp.cc +++ b/lib/records/RecHttp.cc @@ -42,6 +42,7 @@ const char *const TS_ALPN_PROTOCOL_HTTP_0_9 = IP_PROTO_TAG_HTTP_0_9.data(); const char *const TS_ALPN_PROTOCOL_HTTP_1_0 = IP_PROTO_TAG_HTTP_1_0.data(); const char *const TS_ALPN_PROTOCOL_HTTP_1_1 = IP_PROTO_TAG_HTTP_1_1.data(); const char *const TS_ALPN_PROTOCOL_HTTP_2_0 = IP_PROTO_TAG_HTTP_2_0.data(); +const char *const TS_ALPN_PROTOCOL_HTTP_3 = IP_PROTO_TAG_HTTP_3.data(); const char *const TS_ALPN_PROTOCOL_HTTP_QUIC = IP_PROTO_TAG_HTTP_QUIC.data(); const char *const TS_ALPN_PROTOCOL_GROUP_HTTP = "http"; @@ -50,6 +51,7 @@ const char *const TS_ALPN_PROTOCOL_GROUP_HTTP2 = "http2"; const char *const TS_PROTO_TAG_HTTP_1_0 = TS_ALPN_PROTOCOL_HTTP_1_0; const char *const TS_PROTO_TAG_HTTP_1_1 = TS_ALPN_PROTOCOL_HTTP_1_1; const char *const TS_PROTO_TAG_HTTP_2_0 = TS_ALPN_PROTOCOL_HTTP_2_0; +const char *const TS_PROTO_TAG_HTTP_3 = TS_ALPN_PROTOCOL_HTTP_3; const char *const TS_PROTO_TAG_HTTP_QUIC = TS_ALPN_PROTOCOL_HTTP_QUIC; const char *const TS_PROTO_TAG_TLS_1_3 = IP_PROTO_TAG_TLS_1_3.data(); const char *const TS_PROTO_TAG_TLS_1_2 = IP_PROTO_TAG_TLS_1_2.data(); @@ -67,6 +69,7 @@ int TS_ALPN_PROTOCOL_INDEX_HTTP_0_9 = SessionProtocolNameRegistry::INVALID; int TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = SessionProtocolNameRegistry::INVALID; int TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = SessionProtocolNameRegistry::INVALID; int TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = SessionProtocolNameRegistry::INVALID; +int TS_ALPN_PROTOCOL_INDEX_HTTP_3 = SessionProtocolNameRegistry::INVALID; int TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC = SessionProtocolNameRegistry::INVALID; // Predefined protocol sets for ease of use. @@ -711,6 +714,7 @@ ts_session_protocol_well_known_name_indices_init() TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_1_0); TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_1_1); TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_2_0); + TS_ALPN_PROTOCOL_INDEX_HTTP_3 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_3); TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_QUIC); // Now do the predefined protocol sets. @@ -720,8 +724,10 @@ ts_session_protocol_well_known_name_indices_init() HTTP2_PROTOCOL_SET.markIn(TS_ALPN_PROTOCOL_INDEX_HTTP_2_0); DEFAULT_TLS_SESSION_PROTOCOL_SET.markAllIn(); + DEFAULT_TLS_SESSION_PROTOCOL_SET.markOut(TS_ALPN_PROTOCOL_INDEX_HTTP_3); DEFAULT_TLS_SESSION_PROTOCOL_SET.markOut(TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC); + DEFAULT_QUIC_SESSION_PROTOCOL_SET.markIn(TS_ALPN_PROTOCOL_INDEX_HTTP_3); DEFAULT_QUIC_SESSION_PROTOCOL_SET.markIn(TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC); DEFAULT_NON_TLS_SESSION_PROTOCOL_SET = HTTP_PROTOCOL_SET; diff --git a/proxy/http/HttpProxyServerMain.cc b/proxy/http/HttpProxyServerMain.cc index ac5e6bbbde2..a2edf2c9e62 100644 --- a/proxy/http/HttpProxyServerMain.cc +++ b/proxy/http/HttpProxyServerMain.cc @@ -258,7 +258,12 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned } else if (port.isQUIC()) { QUICNextProtocolAccept *quic = new QUICNextProtocolAccept(); - // HTTP/QUIC + // HTTP/3 + if (port.m_session_protocol_preference.contains(TS_ALPN_PROTOCOL_INDEX_HTTP_3)) { + quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_3, new Http3SessionAccept(accept_opt)); + } + + // HTTP/0.9 over QUIC (for interop only, will be removed) if (port.m_session_protocol_preference.contains(TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC)) { quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC, new Http3SessionAccept(accept_opt)); } diff --git a/src/tscore/ink_inet.cc b/src/tscore/ink_inet.cc index 8a279cf2840..681191ebdd5 100644 --- a/src/tscore/ink_inet.cc +++ b/src/tscore/ink_inet.cc @@ -50,7 +50,8 @@ const std::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"sv); const std::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"sv); const std::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"sv); const std::string_view IP_PROTO_TAG_HTTP_2_0("h2"sv); // HTTP/2 over TLS -const std::string_view IP_PROTO_TAG_HTTP_QUIC("h3-17"sv); // HTTP/3 over QUIC +const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-17"sv); // HTTP/0.9 over QUIC +const std::string_view IP_PROTO_TAG_HTTP_3("h3-17"sv); // HTTP/3 over QUIC const std::string_view UNIX_PROTO_TAG{"unix"sv}; From 7ae64a43e9214c70dfa7b8cb059525b2ea6ad61e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 29 Jan 2019 10:05:04 +0900 Subject: [PATCH 1064/1313] Add a interface to QUICConnection to get negotiated app name --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 11 +++++++++++ iocore/net/quic/QUICConnection.h | 1 + 3 files changed, 13 insertions(+) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 5ff0961f934..38b9284d665 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -210,6 +210,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub NetVConnectionContext_t direction() const override; SSLNextProtocolSet *next_protocol_set() const override; QUICPacketNumber largest_acked_packet_number(QUICEncryptionLevel level) const override; + std::string_view negotiated_application_name() const override; bool is_closed() const override; // QUICConnection (QUICPacketTransmitter) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b278d792505..1f562d3a960 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -895,6 +895,17 @@ QUICNetVConnection::largest_acked_packet_number(QUICEncryptionLevel level) const return this->_loss_detector[index]->largest_acked_packet_number(); } +std::string_view +QUICNetVConnection::negotiated_application_name() const +{ + const uint8_t *name; + unsigned int name_len = 0; + + this->_hs_protocol->negotiated_application_name(&name, &name_len); + + return std::string_view(reinterpret_cast(name), name_len); +} + QUICConnectionErrorUPtr QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) { diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index e2e49da8744..8af0f24d41f 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -63,6 +63,7 @@ class QUICConnectionInfoProvider virtual SSLNextProtocolSet *next_protocol_set() const = 0; virtual bool is_closed() const = 0; virtual QUICPacketNumber largest_acked_packet_number(QUICEncryptionLevel level) const = 0; + virtual std::string_view negotiated_application_name() const = 0; }; class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler, public QUICConnectionInfoProvider From 4ba478f426773c897a13ca666bc7df2e3ae737d9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 29 Jan 2019 10:06:06 +0900 Subject: [PATCH 1065/1313] Switch HTTP/0.9 over QUIC (hq-*) and HTTP/3 (h3-*) by ALPN --- proxy/http3/Http3SessionAccept.cc | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/proxy/http3/Http3SessionAccept.cc b/proxy/http3/Http3SessionAccept.cc index 220a5008c3d..0fd81812619 100644 --- a/proxy/http3/Http3SessionAccept.cc +++ b/proxy/http3/Http3SessionAccept.cc @@ -50,19 +50,29 @@ Http3SessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferRead netvc->attributes = this->options.transport_type; + QUICNetVConnection *qvc = static_cast(netvc); + if (is_debug_tag_set("http3")) { ip_port_text_buffer ipb; - Debug("http3", "[%s] accepted connection from %s transport type = %d", - static_cast(static_cast(netvc))->cids().data(), + Debug("http3", "[%s] accepted connection from %s transport type = %d", qvc->cids().data(), ats_ip_nptop(client_ip, ipb, sizeof(ipb)), netvc->attributes); } - // TODO: switch by ALPN - // new QUICSimpleApp(static_cast(netvc), std::move(session_acl)); - // who will destruct this app? - Http3App *app = new Http3App(static_cast(netvc), std::move(session_acl)); - app->start(); + std::string_view alpn = qvc->negotiated_application_name(); + + if (alpn.empty() || IP_PROTO_TAG_HTTP_QUIC.compare(alpn) == 0) { + Debug("http3", "[%s] start HTTP/0.9 app (ALPN=%s)", qvc->cids().data(), alpn.data()); + + new QUICSimpleApp(qvc, std::move(session_acl)); + } else if (IP_PROTO_TAG_HTTP_3.compare(alpn) == 0) { + Debug("http3", "[%s] start HTTP/3 app (ALPN=%s)", qvc->cids().data(), alpn.data()); + + Http3App *app = new Http3App(qvc, std::move(session_acl)); + app->start(); + } else { + ink_abort("Negotiated App Name is unknown"); + } return true; } From d21e1a82af16f0db20b4c7742a3e8b569ab773d1 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 29 Jan 2019 10:19:26 +0900 Subject: [PATCH 1066/1313] Send NUM_PLACEHOLDERS --- proxy/http3/Http3App.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 09907c4d7d2..d0f82710942 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -309,6 +309,7 @@ Http3SettingsFramer::generate_frame(uint16_t max_size) Http3SettingsFrame *frame = http3SettingsFrameAllocator.alloc(); new (frame) Http3SettingsFrame(); frame->set(Http3SettingsId::HEADER_TABLE_SIZE, 0x0); + frame->set(Http3SettingsId::NUM_PLACEHOLDERS, 100); return Http3SettingsFrameUPtr(frame, &Http3FrameDeleter::delete_settings_frame); } From b5ad80fda358266773eee6ddac28e8198aedfa6a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 29 Jan 2019 10:57:36 +0900 Subject: [PATCH 1067/1313] Fix build error --- include/ts/apidefs.h.in | 3 +++ lib/records/RecHttp.cc | 1 + 2 files changed, 4 insertions(+) diff --git a/include/ts/apidefs.h.in b/include/ts/apidefs.h.in index d54dc71dcc9..3000b51c2a9 100644 --- a/include/ts/apidefs.h.in +++ b/include/ts/apidefs.h.in @@ -1238,12 +1238,14 @@ extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_0_9; extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_1_0; extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_1_1; extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_2_0; +extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_3; extern tsapi const char *const TS_ALPN_PROTOCOL_HTTP_QUIC; extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_0_9; extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_1_0; extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_1_1; extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_2_0; +extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_3; extern tsapi int TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC; extern tsapi const char *const TS_ALPN_PROTOCOL_GROUP_HTTP; @@ -1252,6 +1254,7 @@ extern tsapi const char *const TS_ALPN_PROTOCOL_GROUP_HTTP2; extern tsapi const char *const TS_PROTO_TAG_HTTP_1_0; extern tsapi const char *const TS_PROTO_TAG_HTTP_1_1; extern tsapi const char *const TS_PROTO_TAG_HTTP_2_0; +extern tsapi const char *const TS_PROTO_TAG_HTTP_3; extern tsapi const char *const TS_PROTO_TAG_HTTP_QUIC; extern tsapi const char *const TS_PROTO_TAG_TLS_1_3; extern tsapi const char *const TS_PROTO_TAG_TLS_1_2; diff --git a/lib/records/RecHttp.cc b/lib/records/RecHttp.cc index 253955eb515..7ebd99c5565 100644 --- a/lib/records/RecHttp.cc +++ b/lib/records/RecHttp.cc @@ -735,6 +735,7 @@ ts_session_protocol_well_known_name_indices_init() TSProtoTags.insert(TS_PROTO_TAG_HTTP_1_0); TSProtoTags.insert(TS_PROTO_TAG_HTTP_1_1); TSProtoTags.insert(TS_PROTO_TAG_HTTP_2_0); + TSProtoTags.insert(TS_PROTO_TAG_HTTP_3); TSProtoTags.insert(TS_PROTO_TAG_HTTP_QUIC); TSProtoTags.insert(TS_PROTO_TAG_TLS_1_3); TSProtoTags.insert(TS_PROTO_TAG_TLS_1_2); From 22176bbe62b8ff9ad3bd4934beff032e78e9244e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 29 Jan 2019 10:58:26 +0900 Subject: [PATCH 1068/1313] Revert ALPN list for client --- iocore/net/quic/QUICConfig.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index eaab96a3dc6..bd971526c00 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -36,7 +36,7 @@ // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html // Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? using namespace std::literals; -static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5h3-17"sv); +static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-17"sv); int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; From f8e1e14101044b0e4c2c8f2d24c68bb20549a8f5 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 29 Jan 2019 12:13:36 +0900 Subject: [PATCH 1069/1313] Fix buffer-over-flow --- proxy/http3/Http3SessionAccept.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/proxy/http3/Http3SessionAccept.cc b/proxy/http3/Http3SessionAccept.cc index 0fd81812619..c542abcdb01 100644 --- a/proxy/http3/Http3SessionAccept.cc +++ b/proxy/http3/Http3SessionAccept.cc @@ -62,11 +62,15 @@ Http3SessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferRead std::string_view alpn = qvc->negotiated_application_name(); if (alpn.empty() || IP_PROTO_TAG_HTTP_QUIC.compare(alpn) == 0) { - Debug("http3", "[%s] start HTTP/0.9 app (ALPN=%s)", qvc->cids().data(), alpn.data()); + if (alpn.empty()) { + Debug("http3", "[%s] start HTTP/0.9 app (ALPN=null)", qvc->cids().data()); + } else { + Debug("http3", "[%s] start HTTP/0.9 app (ALPN=%s)", qvc->cids().data(), IP_PROTO_TAG_HTTP_QUIC.data()); + } new QUICSimpleApp(qvc, std::move(session_acl)); } else if (IP_PROTO_TAG_HTTP_3.compare(alpn) == 0) { - Debug("http3", "[%s] start HTTP/3 app (ALPN=%s)", qvc->cids().data(), alpn.data()); + Debug("http3", "[%s] start HTTP/3 app (ALPN=%s)", qvc->cids().data(), IP_PROTO_TAG_HTTP_3.data()); Http3App *app = new Http3App(qvc, std::move(session_acl)); app->start(); From 393b90b4ae8911fac6ddfa5cbb71c56bd2abb82a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 29 Jan 2019 12:39:41 +0900 Subject: [PATCH 1070/1313] HTTP/3: Handle error on creating uni stream --- proxy/http3/Http3App.cc | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index d0f82710942..257f3ad802b 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -61,16 +61,23 @@ void Http3App::start() { QUICStreamId stream_id; + QUICConnectionErrorUPtr error; - this->create_uni_stream(stream_id, Http3StreamType::CONTROL); - this->_local_control_stream = this->_find_stream_io(stream_id); - this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_local_control_stream); + error = this->create_uni_stream(stream_id, Http3StreamType::CONTROL); + if (error == nullptr) { + this->_local_control_stream = this->_find_stream_io(stream_id); + this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_local_control_stream); + } - this->create_uni_stream(stream_id, Http3StreamType::QPACK_ENCODER); - this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_find_stream_io(stream_id)); + error = this->create_uni_stream(stream_id, Http3StreamType::QPACK_ENCODER); + if (error == nullptr) { + this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_find_stream_io(stream_id)); + } - this->create_uni_stream(stream_id, Http3StreamType::QPACK_DECODER); - this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_find_stream_io(stream_id)); + error = this->create_uni_stream(stream_id, Http3StreamType::QPACK_DECODER); + if (error == nullptr) { + this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_find_stream_io(stream_id)); + } } int @@ -131,7 +138,7 @@ Http3App::create_uni_stream(QUICStreamId &new_stream_id, Http3StreamType type) Debug("http3", "[%llu] %s stream is created", new_stream_id, Http3DebugNames::stream_type(type)); } else { - ink_abort("Could not creat %s stream", Http3DebugNames::stream_type(type)); + Debug("http3", "Could not creat %s stream", Http3DebugNames::stream_type(type)); } return error; From 31b690ca332023bf12cc3d790cbd448b8696f7b7 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 31 Jan 2019 11:08:11 +0900 Subject: [PATCH 1071/1313] Print header and payload size of received packet --- iocore/net/QUICNetVConnection.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 1f562d3a960..9872d5c2e50 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1707,8 +1707,8 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) if (packet->type() == QUICPacketType::VERSION_NEGOTIATION) { QUICConDebug("[RX] %s packet size=%u", QUICDebugNames::packet_type(packet->type()), packet->size()); } else { - QUICConDebug("[RX] %s packet #%" PRIu64 " size=%u", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), - packet->size()); + 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; default: From a2cb6851aeba26ea54c86b351d0b17e67e237242 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 31 Jan 2019 11:13:38 +0900 Subject: [PATCH 1072/1313] Bump initial value of max_stream_data_bidi_local_in to allow sending request --- mgmt/RecordsConfig.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 571f4b70cb9..41e24c7abb9 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1368,7 +1368,7 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.initial_max_data_out", RECD_INT, "65536", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_bidi_local_in", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_bidi_local_in", RECD_INT, "4096", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_bidi_local_out", RECD_INT, "4096", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , From 857b2451072e037a1d745859012e9553957e800c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 31 Jan 2019 11:28:16 +0900 Subject: [PATCH 1073/1313] Revert "Bump initial value of max_stream_data_bidi_local_in to allow sending request" This reverts commit a2cb6851aeba26ea54c86b351d0b17e67e237242. --- mgmt/RecordsConfig.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 41e24c7abb9..571f4b70cb9 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1368,7 +1368,7 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.initial_max_data_out", RECD_INT, "65536", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_bidi_local_in", RECD_INT, "4096", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_bidi_local_in", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.initial_max_stream_data_bidi_local_out", RECD_INT, "4096", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , From 119062ff2bcc3dc0ae3ce911b2e97d4eb0bb82c9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 31 Jan 2019 15:21:51 +0900 Subject: [PATCH 1074/1313] Remove a wrong assert Packet number can be 3, and the following switch statement takes care the error --- iocore/net/quic/QUICPacket.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 817c0ca7848..5ef598fc581 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -949,8 +949,6 @@ QUICPacket::calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base) bool QUICPacket::encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len) { - ink_assert(len == 1 || len == 2 || len == 4); - uint64_t mask = 0; switch (len) { case 1: From 306ec3059440b493b9ed0aeafb6d0e538e0ed2d6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 31 Jan 2019 20:58:24 +0900 Subject: [PATCH 1075/1313] Fix frame size calculation on splitting STREAM --- iocore/net/quic/QUICFrameRetransmitter.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICFrameRetransmitter.cc b/iocore/net/quic/QUICFrameRetransmitter.cc index 7765ccc988a..02d03a315db 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.cc +++ b/iocore/net/quic/QUICFrameRetransmitter.cc @@ -110,8 +110,8 @@ QUICFrameRetransmitter::_create_stream_frame(QUICFrameInformationUPtr &info, uin // FIXME MAX_STREAM_FRAME_OVERHEAD is here and there // These size calculation should not exist multiple places - uint64_t maximmum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD; - if (maximmum_data_size > static_cast(stream_info->block->size())) { + uint64_t maximum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD; + if (maximum_data_size >= static_cast(stream_info->block->size())) { frame = QUICFrameFactory::create_stream_frame(stream_info->block, stream_info->stream_id, stream_info->offset, stream_info->has_fin, true, true, id, owner); ink_assert(frame->size() <= maximum_frame_size); @@ -121,7 +121,7 @@ QUICFrameRetransmitter::_create_stream_frame(QUICFrameInformationUPtr &info, uin true, id, owner); QUICStreamFrame *stream_frame = static_cast(frame.get()); IOBufferBlock *block = stream_frame->data(); - size_t over_length = stream_frame->size() - maximum_frame_size; + size_t over_length = stream_frame->data_length() - maximum_data_size; block->_end = std::max(block->start(), block->_end - over_length); if (block->read_avail() == 0) { // no payload From 8c0574a1dae84f6923c101f89469aa93f9fb2715 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 31 Jan 2019 21:35:57 +0900 Subject: [PATCH 1076/1313] Don't respond with RETRY if received packet has short header --- iocore/net/QUICPacketHandler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 32781913d17..20a4b0c549a 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -280,7 +280,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // Server Stateless Retry QUICConfig::scoped_config params; QUICConnectionId cid_in_retry_token; - if (!vc && params->stateless_retry()) { + if (!vc && params->stateless_retry() && QUICInvariants::is_long_header(buf)) { int ret = this->_stateless_retry(buf, buf_len, udp_packet->getConnection(), udp_packet->from, dcid, scid, &cid_in_retry_token); if (ret < 0) { udp_packet->free(); From aa6224028eff21f9bcb3f148060bef0d1a74009f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Feb 2019 09:29:16 +0900 Subject: [PATCH 1077/1313] Fix compile warnings --- proxy/http3/Http3App.cc | 2 +- proxy/http3/Http3ClientSession.cc | 4 ++-- proxy/http3/QPACK.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 257f3ad802b..3af0f84a06e 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -136,7 +136,7 @@ Http3App::create_uni_stream(QUICStreamId &new_stream_id, Http3StreamType type) this->_local_uni_stream_map.insert(std::make_pair(new_stream_id, type)); - Debug("http3", "[%llu] %s stream is created", new_stream_id, Http3DebugNames::stream_type(type)); + Debug("http3", "[%" PRIu64 "] %s stream is created", new_stream_id, Http3DebugNames::stream_type(type)); } else { Debug("http3", "Could not creat %s stream", Http3DebugNames::stream_type(type)); } diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3ClientSession.cc index 317a24cc2ae..2d81533eca3 100644 --- a/proxy/http3/Http3ClientSession.cc +++ b/proxy/http3/Http3ClientSession.cc @@ -25,8 +25,8 @@ Http3ClientSession::Http3ClientSession(NetVConnection *vc) : _client_vc(vc) { - this->_local_qpack = new QPACK(static_cast(vc)); - this->_remote_qpack = new QPACK(static_cast(vc)); + this->_local_qpack = new QPACK(static_cast(vc), 0, 0); + this->_remote_qpack = new QPACK(static_cast(vc), 0, 0); } Http3ClientSession::~Http3ClientSession() diff --git a/proxy/http3/QPACK.cc b/proxy/http3/QPACK.cc index e1603c8d251..8193dcb580e 100644 --- a/proxy/http3/QPACK.cc +++ b/proxy/http3/QPACK.cc @@ -898,7 +898,7 @@ QPACK::_decode(EThread *ethread, Continuation *cont, uint64_t stream_id, const u bool QPACK::_add_to_blocked_list(DecodeRequest *decode_request) { - if (this->_blocked_list.count() >= SETTINGS_QPACK_BLOCKED_STREAMS) { + if (this->_blocked_list.count() >= this->_max_blocking_streams) { return false; } From c5048fb42c090b5219cd9b213aa690eafb33c848 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Feb 2019 10:50:02 +0900 Subject: [PATCH 1078/1313] Print offset in BLOCKED and STREAM_BLOCKED --- iocore/net/quic/QUICFrame.cc | 12 ++++++++++++ iocore/net/quic/QUICFrame.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 5d91ab0ddb0..3ccdae1aa79 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1769,6 +1769,12 @@ QUICBlockedFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos); } +int +QUICBlockedFrame::debug_msg(char *msg, size_t msg_len) const +{ + return snprintf(msg, msg_len, "| BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset()); +} + QUICFrameUPtr QUICBlockedFrame::clone() const { @@ -1857,6 +1863,12 @@ QUICStreamBlockedFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos); } +int +QUICStreamBlockedFrame::debug_msg(char *msg, size_t msg_len) const +{ + return snprintf(msg, msg_len, "| STREAM_BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset()); +} + QUICFrameUPtr QUICStreamBlockedFrame::clone() const { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 549db76938b..402a3e83bac 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -475,6 +475,7 @@ class QUICBlockedFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void parse(const uint8_t *buf, size_t len) override; + virtual int debug_msg(char *msg, size_t msg_len) const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; QUICOffset offset() const; @@ -502,6 +503,7 @@ class QUICStreamBlockedFrame : public QUICFrame virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; virtual void parse(const uint8_t *buf, size_t len) override; + virtual int debug_msg(char *msg, size_t msg_len) const override; QUICStreamId stream_id() const; QUICOffset offset() const; From 33dfc098c1b13f5d34939eb83cae925854f49ff3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Feb 2019 12:02:01 +0900 Subject: [PATCH 1079/1313] Fix compile errors in tests --- iocore/net/quic/Mock.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index e6d3bba0b85..7d87b0784cd 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -281,6 +281,12 @@ class MockQUICConnection : public QUICConnection { } + std::string_view + negotiated_application_name() const override + { + return "h3-17"; + } + int _transmit_count = 0; int _retransmit_count = 0; Ptr _mutex; @@ -372,6 +378,12 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider { return false; } + + std::string_view + negotiated_application_name() const override + { + return "h3-17"; + } }; class MockQUICPacketTransmitter : public QUICPacketTransmitter From 0cac20c26ed7edf44d05c568b8b4aced9e8ff3ad Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Feb 2019 12:02:41 +0900 Subject: [PATCH 1080/1313] Rename StreamBlocked frame to StreamDataBlocked frame --- iocore/net/quic/QUICFrame.cc | 34 +++++++++---------- iocore/net/quic/QUICFrame.h | 14 ++++---- iocore/net/quic/QUICStream.cc | 2 +- iocore/net/quic/QUICStream.h | 2 +- iocore/net/quic/QUICStreamManager.cc | 4 +-- iocore/net/quic/QUICStreamManager.h | 2 +- .../net/quic/test/test_QUICFlowController.cc | 6 ++-- iocore/net/quic/test/test_QUICFrame.cc | 10 +++--- 8 files changed, 37 insertions(+), 37 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 3ccdae1aa79..f9d4e097948 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -41,7 +41,7 @@ ClassAllocator quicMaxStreamDataFrameAllocator("quicMaxS ClassAllocator quicMaxStreamIdFrameAllocator("quicMaxStreamDataIdAllocator"); ClassAllocator quicPingFrameAllocator("quicPingFrameAllocator"); ClassAllocator quicBlockedFrameAllocator("quicBlockedFrameAllocator"); -ClassAllocator quicStreamBlockedFrameAllocator("quicStreamBlockedFrameAllocator"); +ClassAllocator quicStreamBlockedFrameAllocator("quicStreamBlockedFrameAllocator"); ClassAllocator quicStreamIdBlockedFrameAllocator("quicStreamIdBlockedFrameAllocator"); ClassAllocator quicNewConnectionIdFrameAllocator("quicNewConnectionIdFrameAllocator"); ClassAllocator quicStopSendingFrameAllocator("quicStopSendingFrameAllocator"); @@ -1826,13 +1826,13 @@ QUICBlockedFrame::offset() const // // STREAM_DATA_BLOCKED frame // -QUICStreamBlockedFrame::QUICStreamBlockedFrame(const uint8_t *buf, size_t len) +QUICStreamDataBlockedFrame::QUICStreamDataBlockedFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } void -QUICStreamBlockedFrame::_reset() +QUICStreamDataBlockedFrame::_reset() { this->_stream_id = 0; this->_offset = 0; @@ -1844,7 +1844,7 @@ QUICStreamBlockedFrame::_reset() } void -QUICStreamBlockedFrame::parse(const uint8_t *buf, size_t len) +QUICStreamDataBlockedFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); this->_reset(); @@ -1864,25 +1864,25 @@ QUICStreamBlockedFrame::parse(const uint8_t *buf, size_t len) } int -QUICStreamBlockedFrame::debug_msg(char *msg, size_t msg_len) const +QUICStreamDataBlockedFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| STREAM_BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset()); + return snprintf(msg, msg_len, "| STREAM_DATA_BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset()); } QUICFrameUPtr -QUICStreamBlockedFrame::clone() const +QUICStreamDataBlockedFrame::clone() const { return QUICFrameFactory::create_stream_blocked_frame(this->stream_id(), this->offset(), this->_id, this->_owner); } QUICFrameType -QUICStreamBlockedFrame::type() const +QUICStreamDataBlockedFrame::type() const { return QUICFrameType::STREAM_DATA_BLOCKED; } size_t -QUICStreamBlockedFrame::size() const +QUICStreamDataBlockedFrame::size() const { if (this->_size) { return this->_size; @@ -1892,7 +1892,7 @@ QUICStreamBlockedFrame::size() const } size_t -QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const +QUICStreamDataBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const { if (limit < this->size()) { return 0; @@ -1913,13 +1913,13 @@ QUICStreamBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const } QUICStreamId -QUICStreamBlockedFrame::stream_id() const +QUICStreamDataBlockedFrame::stream_id() const { return this->_stream_id; } QUICOffset -QUICStreamBlockedFrame::offset() const +QUICStreamDataBlockedFrame::offset() const { return this->_offset; } @@ -2718,7 +2718,7 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_blocked_frame); case QUICFrameType::STREAM_DATA_BLOCKED: frame = quicStreamBlockedFrameAllocator.alloc(); - new (frame) QUICStreamBlockedFrame(buf, len); + new (frame) QUICStreamDataBlockedFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); case QUICFrameType::STREAMS_BLOCKED: frame = quicStreamIdBlockedFrameAllocator.alloc(); @@ -2898,12 +2898,12 @@ QUICFrameFactory::create_blocked_frame(QUICOffset offset, QUICFrameId id, QUICFr return std::unique_ptr(frame, &QUICFrameDeleter::delete_blocked_frame); } -std::unique_ptr +std::unique_ptr QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) { - QUICStreamBlockedFrame *frame = quicStreamBlockedFrameAllocator.alloc(); - new (frame) QUICStreamBlockedFrame(stream_id, offset, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); + QUICStreamDataBlockedFrame *frame = quicStreamBlockedFrameAllocator.alloc(); + new (frame) QUICStreamDataBlockedFrame(stream_id, offset, id, owner); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); } std::unique_ptr diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 402a3e83bac..10d79bb2ba5 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -490,12 +490,12 @@ class QUICBlockedFrame : public QUICFrame // STREAM_DATA_BLOCKED // -class QUICStreamBlockedFrame : public QUICFrame +class QUICStreamDataBlockedFrame : public QUICFrame { public: - QUICStreamBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICStreamBlockedFrame(const uint8_t *buf, size_t len); - QUICStreamBlockedFrame(QUICStreamId s, QUICOffset o, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) + QUICStreamDataBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} + QUICStreamDataBlockedFrame(const uint8_t *buf, size_t len); + QUICStreamDataBlockedFrame(QUICStreamId s, QUICOffset o, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _stream_id(s), _offset(o){}; QUICFrameUPtr clone() const override; @@ -750,7 +750,7 @@ extern ClassAllocator quicMaxStreamDataFrameAllocator; extern ClassAllocator quicMaxStreamIdFrameAllocator; extern ClassAllocator quicPingFrameAllocator; extern ClassAllocator quicBlockedFrameAllocator; -extern ClassAllocator quicStreamBlockedFrameAllocator; +extern ClassAllocator quicStreamBlockedFrameAllocator; extern ClassAllocator quicStreamIdBlockedFrameAllocator; extern ClassAllocator quicNewConnectionIdFrameAllocator; extern ClassAllocator quicStopSendingFrameAllocator; @@ -851,7 +851,7 @@ class QUICFrameDeleter delete_stream_blocked_frame(QUICFrame *frame) { frame->~QUICFrame(); - quicStreamBlockedFrameAllocator.free(static_cast(frame)); + quicStreamBlockedFrameAllocator.free(static_cast(frame)); } static void @@ -1020,7 +1020,7 @@ class QUICFrameFactory /* * Creates a STREAM_DATA_BLOCKED frame. */ - static std::unique_ptr create_stream_blocked_frame( + static std::unique_ptr create_stream_blocked_frame( QUICStreamId stream_id, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index b75e8284d32..9fdb60954a8 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -380,7 +380,7 @@ QUICStream::recv(const QUICMaxStreamDataFrame &frame) } QUICConnectionErrorUPtr -QUICStream::recv(const QUICStreamBlockedFrame &frame) +QUICStream::recv(const QUICStreamDataBlockedFrame &frame) { // STREAM_DATA_BLOCKED frames are for debugging. Nothing to do here. return nullptr; diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index c41a52768de..27e8cba4286 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -77,7 +77,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame); QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame); - QUICConnectionErrorUPtr recv(const QUICStreamBlockedFrame &frame); + QUICConnectionErrorUPtr recv(const QUICStreamDataBlockedFrame &frame); QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame); QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame); diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 30e38168f46..04b97d6b6d3 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -147,7 +147,7 @@ QUICStreamManager::handle_frame(QUICEncryptionLevel level, const QUICFrame &fram break; case QUICFrameType::STREAM_DATA_BLOCKED: // STREAM_DATA_BLOCKED frame is for debugging. Just propagate to streams - error = this->_handle_frame(static_cast(frame)); + error = this->_handle_frame(static_cast(frame)); break; case QUICFrameType::STREAM: error = this->_handle_frame(static_cast(frame)); @@ -182,7 +182,7 @@ QUICStreamManager::_handle_frame(const QUICMaxStreamDataFrame &frame) } QUICConnectionErrorUPtr -QUICStreamManager::_handle_frame(const QUICStreamBlockedFrame &frame) +QUICStreamManager::_handle_frame(const QUICStreamDataBlockedFrame &frame) { QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); if (stream) { diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 86fd94ffc99..1a89d222d3e 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -74,7 +74,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICConnectionErrorUPtr _handle_frame(const QUICRstStreamFrame &frame); QUICConnectionErrorUPtr _handle_frame(const QUICStopSendingFrame &frame); QUICConnectionErrorUPtr _handle_frame(const QUICMaxStreamDataFrame &frame); - QUICConnectionErrorUPtr _handle_frame(const QUICStreamBlockedFrame &frame); + QUICConnectionErrorUPtr _handle_frame(const QUICStreamDataBlockedFrame &frame); QUICConnectionErrorUPtr _handle_frame(const QUICMaxStreamsFrame &frame); std::vector _encryption_level_filter() override diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index e84d2380043..975d9a5b52a 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -366,7 +366,7 @@ TEST_CASE("Frame retransmission", "[quic]") CHECK(ret == 0); frame = fc.generate_frame(level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 1024); + CHECK(static_cast(frame.get())->offset() == 1024); QUICFrameId id = frame->id(); // Don't retransmit unless the frame is lost @@ -377,7 +377,7 @@ TEST_CASE("Frame retransmission", "[quic]") fc.on_frame_lost(id); frame = fc.generate_frame(level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 1024); + CHECK(static_cast(frame.get())->offset() == 1024); // Don't send if it was not blocked fc.on_frame_lost(frame->id()); @@ -390,7 +390,7 @@ TEST_CASE("Frame retransmission", "[quic]") ret = fc.update(2048); frame = fc.generate_frame(level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 2048); + CHECK(static_cast(frame.get())->offset() == 2048); } SECTION("MAX_DATA frame") diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 85a6d94469a..0e4a1605e2d 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1091,7 +1091,7 @@ TEST_CASE("Store Blocked Frame", "[quic]") CHECK(memcmp(buf, expected, len) == 0); } -TEST_CASE("Load StreamBlocked Frame", "[quic]") +TEST_CASE("Load StreamDataBlocked Frame", "[quic]") { SECTION("Load") { @@ -1103,8 +1103,8 @@ TEST_CASE("Load StreamBlocked Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM_DATA_BLOCKED); CHECK(frame1->size() == 6); - std::shared_ptr stream_blocked_frame = - std::dynamic_pointer_cast(frame1); + std::shared_ptr stream_blocked_frame = + std::dynamic_pointer_cast(frame1); CHECK(stream_blocked_frame != nullptr); CHECK(stream_blocked_frame->stream_id() == 0x01020304); CHECK(stream_blocked_frame->offset() == 0x07); @@ -1122,7 +1122,7 @@ TEST_CASE("Load StreamBlocked Frame", "[quic]") } } -TEST_CASE("Store StreamBlocked Frame", "[quic]") +TEST_CASE("Store StreamDataBlocked Frame", "[quic]") { uint8_t buf[65535]; size_t len; @@ -1132,7 +1132,7 @@ TEST_CASE("Store StreamBlocked Frame", "[quic]") 0x81, 0x02, 0x03, 0x04, // Stream ID 0x07, // Offset }; - QUICStreamBlockedFrame stream_blocked_frame(0x01020304, 0x07); + QUICStreamDataBlockedFrame stream_blocked_frame(0x01020304, 0x07); CHECK(stream_blocked_frame.size() == 6); stream_blocked_frame.store(buf, &len, 65535); From dc684f5a75c294880672d196727c58e33681bf43 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 1 Feb 2019 15:17:50 +0900 Subject: [PATCH 1081/1313] Print length of TLS message on debug log --- iocore/net/quic/QUICTLS_openssl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index bda64d92289..142eb481f5a 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -97,7 +97,7 @@ msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, const uint8_t *tmp = reinterpret_cast(buf); int msg_type = tmp[0]; - Debug(tag, "%s (%d), %s (%d)", content_type_str(content_type), content_type, hs_type_str(msg_type), msg_type); + Debug(tag, "%s (%d), %s (%d) len=%zu", content_type_str(content_type), content_type, hs_type_str(msg_type), msg_type, len); return; } From c83350134c8e4fd3629292e378f7bb365c1cf860 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 1 Feb 2019 15:20:11 +0900 Subject: [PATCH 1082/1313] Bump MAX_PACKET_HEADER_LEN for an endpoint which sending long retry token --- iocore/net/quic/QUICPacket.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index cf30c8ca621..01d99ff7d5b 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -179,7 +179,8 @@ class QUICPacketHeader protected: QUICPacketHeader(){}; - static constexpr size_t MAX_PACKET_HEADER_LEN = 128; + // Token field in Initial packet could be very long. + static constexpr size_t MAX_PACKET_HEADER_LEN = 256; const IpEndpoint _from = {}; From e0df8254057543ddbe0cb3904e9b9aa7a7cb9160 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Feb 2019 16:17:14 +0900 Subject: [PATCH 1083/1313] Rename BLOCKED frame to DATA_BLOCKED frame --- iocore/net/quic/QUICFlowController.cc | 2 +- iocore/net/quic/QUICFrame.cc | 34 +++++++++---------- iocore/net/quic/QUICFrame.h | 17 +++++----- .../net/quic/test/test_QUICFlowController.cc | 6 ++-- iocore/net/quic/test/test_QUICFrame.cc | 5 +-- src/tscore/Diags.cc | 9 +---- 6 files changed, 34 insertions(+), 39 deletions(-) diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index a973543d52f..078f09b0b7f 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -217,7 +217,7 @@ QUICLocalFlowController::_need_to_forward_limit() QUICFrameUPtr QUICRemoteConnectionFlowController::_create_frame() { - auto frame = QUICFrameFactory::create_blocked_frame(this->_offset, this->_issue_frame_id(), this); + auto frame = QUICFrameFactory::create_data_blocked_frame(this->_offset, this->_issue_frame_id(), this); QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = frame->type(); info->level = QUICEncryptionLevel::NONE; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index f9d4e097948..4c78b67e0c3 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -40,7 +40,7 @@ ClassAllocator quicMaxDataFrameAllocator("quicMaxDataFrameAllo ClassAllocator quicMaxStreamDataFrameAllocator("quicMaxStreamDataFrameAllocator"); ClassAllocator quicMaxStreamIdFrameAllocator("quicMaxStreamDataIdAllocator"); ClassAllocator quicPingFrameAllocator("quicPingFrameAllocator"); -ClassAllocator quicBlockedFrameAllocator("quicBlockedFrameAllocator"); +ClassAllocator quicBlockedFrameAllocator("quicBlockedFrameAllocator"); ClassAllocator quicStreamBlockedFrameAllocator("quicStreamBlockedFrameAllocator"); ClassAllocator quicStreamIdBlockedFrameAllocator("quicStreamIdBlockedFrameAllocator"); ClassAllocator quicNewConnectionIdFrameAllocator("quicNewConnectionIdFrameAllocator"); @@ -1737,13 +1737,13 @@ QUICMaxStreamsFrame::maximum_streams() const // // BLOCKED frame // -QUICBlockedFrame::QUICBlockedFrame(const uint8_t *buf, size_t len) +QUICDataBlockedFrame::QUICDataBlockedFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); } void -QUICBlockedFrame::_reset() +QUICDataBlockedFrame::_reset() { this->_offset = 0; @@ -1754,7 +1754,7 @@ QUICBlockedFrame::_reset() } void -QUICBlockedFrame::parse(const uint8_t *buf, size_t len) +QUICDataBlockedFrame::parse(const uint8_t *buf, size_t len) { ink_assert(len >= 1); this->_reset(); @@ -1770,25 +1770,25 @@ QUICBlockedFrame::parse(const uint8_t *buf, size_t len) } int -QUICBlockedFrame::debug_msg(char *msg, size_t msg_len) const +QUICDataBlockedFrame::debug_msg(char *msg, size_t msg_len) const { return snprintf(msg, msg_len, "| BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset()); } QUICFrameUPtr -QUICBlockedFrame::clone() const +QUICDataBlockedFrame::clone() const { - return QUICFrameFactory::create_blocked_frame(this->offset(), this->_id, this->_owner); + return QUICFrameFactory::create_data_blocked_frame(this->offset(), this->_id, this->_owner); } QUICFrameType -QUICBlockedFrame::type() const +QUICDataBlockedFrame::type() const { return QUICFrameType::DATA_BLOCKED; } size_t -QUICBlockedFrame::size() const +QUICDataBlockedFrame::size() const { if (this->_size) { return this->_size; @@ -1798,7 +1798,7 @@ QUICBlockedFrame::size() const } size_t -QUICBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const +QUICDataBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const { if (limit < this->size()) { return 0; @@ -1818,7 +1818,7 @@ QUICBlockedFrame::store(uint8_t *buf, size_t *len, size_t limit) const } QUICOffset -QUICBlockedFrame::offset() const +QUICDataBlockedFrame::offset() const { return this->_offset; } @@ -2714,7 +2714,7 @@ QUICFrameFactory::create(const uint8_t *buf, size_t len) return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_ping_frame); case QUICFrameType::DATA_BLOCKED: frame = quicBlockedFrameAllocator.alloc(); - new (frame) QUICBlockedFrame(buf, len); + new (frame) QUICDataBlockedFrame(buf, len); return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_blocked_frame); case QUICFrameType::STREAM_DATA_BLOCKED: frame = quicStreamBlockedFrameAllocator.alloc(); @@ -2890,12 +2890,12 @@ QUICFrameFactory::create_path_response_frame(const uint8_t *data, QUICFrameId id return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_response_frame); } -std::unique_ptr -QUICFrameFactory::create_blocked_frame(QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) +std::unique_ptr +QUICFrameFactory::create_data_blocked_frame(QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) { - QUICBlockedFrame *frame = quicBlockedFrameAllocator.alloc(); - new (frame) QUICBlockedFrame(offset, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_blocked_frame); + QUICDataBlockedFrame *frame = quicBlockedFrameAllocator.alloc(); + new (frame) QUICDataBlockedFrame(offset, id, owner); + return std::unique_ptr(frame, &QUICFrameDeleter::delete_blocked_frame); } std::unique_ptr diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 10d79bb2ba5..db97e06a8fe 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -463,12 +463,12 @@ class QUICMaxStreamsFrame : public QUICFrame // // BLOCKED // -class QUICBlockedFrame : public QUICFrame +class QUICDataBlockedFrame : public QUICFrame { public: - QUICBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} - QUICBlockedFrame(const uint8_t *buf, size_t len); - QUICBlockedFrame(QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) + QUICDataBlockedFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} + QUICDataBlockedFrame(const uint8_t *buf, size_t len); + QUICDataBlockedFrame(QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _offset(offset){}; QUICFrameUPtr clone() const override; @@ -749,7 +749,7 @@ extern ClassAllocator quicMaxDataFrameAllocator; extern ClassAllocator quicMaxStreamDataFrameAllocator; extern ClassAllocator quicMaxStreamIdFrameAllocator; extern ClassAllocator quicPingFrameAllocator; -extern ClassAllocator quicBlockedFrameAllocator; +extern ClassAllocator quicBlockedFrameAllocator; extern ClassAllocator quicStreamBlockedFrameAllocator; extern ClassAllocator quicStreamIdBlockedFrameAllocator; extern ClassAllocator quicNewConnectionIdFrameAllocator; @@ -844,7 +844,7 @@ class QUICFrameDeleter delete_blocked_frame(QUICFrame *frame) { frame->~QUICFrame(); - quicBlockedFrameAllocator.free(static_cast(frame)); + quicBlockedFrameAllocator.free(static_cast(frame)); } static void @@ -1014,8 +1014,9 @@ class QUICFrameFactory /* * Creates a BLOCKED frame. */ - static std::unique_ptr create_blocked_frame(QUICOffset offset, QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); + static std::unique_ptr create_data_blocked_frame(QUICOffset offset, + QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a STREAM_DATA_BLOCKED frame. diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index 975d9a5b52a..b5cca329e1d 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -326,7 +326,7 @@ TEST_CASE("Frame retransmission", "[quic]") CHECK(ret == 0); frame = fc.generate_frame(level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 1024); + CHECK(static_cast(frame.get())->offset() == 1024); QUICFrameId id = frame->id(); // Don't retransmit unless the frame is lost @@ -337,7 +337,7 @@ TEST_CASE("Frame retransmission", "[quic]") fc.on_frame_lost(id); frame = fc.generate_frame(level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 1024); + CHECK(static_cast(frame.get())->offset() == 1024); // Don't send if it was not blocked fc.on_frame_lost(frame->id()); @@ -350,7 +350,7 @@ TEST_CASE("Frame retransmission", "[quic]") ret = fc.update(2048); frame = fc.generate_frame(level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 2048); + CHECK(static_cast(frame.get())->offset() == 2048); } SECTION("STREAM_DATA_BLOCKED frame") diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 0e4a1605e2d..2751afd4ec7 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1058,7 +1058,8 @@ TEST_CASE("Load Blocked Frame", "[quic]") std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::DATA_BLOCKED); CHECK(frame1->size() == 2); - std::shared_ptr blocked_stream_frame = std::dynamic_pointer_cast(frame1); + std::shared_ptr blocked_stream_frame = + std::dynamic_pointer_cast(frame1); CHECK(blocked_stream_frame != nullptr); CHECK(blocked_stream_frame->offset() == 0x07); } @@ -1083,7 +1084,7 @@ TEST_CASE("Store Blocked Frame", "[quic]") 0x08, // Type 0x07, // Offset }; - QUICBlockedFrame blocked_stream_frame(0x07, 0, nullptr); + QUICDataBlockedFrame blocked_stream_frame(0x07, 0, nullptr); CHECK(blocked_stream_frame.size() == 2); blocked_stream_frame.store(buf, &len, 65535); diff --git a/src/tscore/Diags.cc b/src/tscore/Diags.cc index b34db02566c..815d6d80615 100644 --- a/src/tscore/Diags.cc +++ b/src/tscore/Diags.cc @@ -225,15 +225,8 @@ Diags::print_va(const char *debug_tag, DiagsLevel diags_level, const SourceLocat format_writer.print("[{timestamp}] "); auto timestamp_offset = format_writer.size(); - format_writer.print("{thread-name}"); - format_writer.print(" {}: ", level_name(diags_level)); - if (location(loc, show_location, diags_level)) { - format_writer.print("<{}> ", *loc); - } - - if (debug_tag) { - format_writer.print("({}) ", debug_tag); + format_writer.print("<{:50,50}> ", *loc); } format_writer.print("{}", format_string); From e87727f84a95ae6b3075455e2c5a3b90f9c14d71 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Feb 2019 16:25:45 +0900 Subject: [PATCH 1084/1313] More rename --- iocore/net/quic/QUICFlowController.cc | 2 +- iocore/net/quic/QUICFrame.cc | 9 ++++--- iocore/net/quic/QUICFrame.h | 2 +- .../net/quic/test/test_QUICStreamManager.cc | 8 +++--- iocore/net/quic/test/test_QUICStreamState.cc | 26 +++++++++---------- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 078f09b0b7f..e5162ac6239 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -241,7 +241,7 @@ QUICLocalConnectionFlowController::_create_frame() QUICFrameUPtr QUICRemoteStreamFlowController::_create_frame() { - auto frame = QUICFrameFactory::create_stream_blocked_frame(this->_stream_id, this->_offset, this->_issue_frame_id(), this); + auto frame = QUICFrameFactory::create_stream_data_blocked_frame(this->_stream_id, this->_offset, this->_issue_frame_id(), this); QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = frame->type(); info->level = QUICEncryptionLevel::NONE; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 4c78b67e0c3..2ae36a06f7a 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1735,7 +1735,7 @@ QUICMaxStreamsFrame::maximum_streams() const } // -// BLOCKED frame +// DATA_BLOCKED frame // QUICDataBlockedFrame::QUICDataBlockedFrame(const uint8_t *buf, size_t len) { @@ -1772,7 +1772,7 @@ QUICDataBlockedFrame::parse(const uint8_t *buf, size_t len) int QUICDataBlockedFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset()); + return snprintf(msg, msg_len, "| DATA_BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset()); } QUICFrameUPtr @@ -1872,7 +1872,7 @@ QUICStreamDataBlockedFrame::debug_msg(char *msg, size_t msg_len) const QUICFrameUPtr QUICStreamDataBlockedFrame::clone() const { - return QUICFrameFactory::create_stream_blocked_frame(this->stream_id(), this->offset(), this->_id, this->_owner); + return QUICFrameFactory::create_stream_data_blocked_frame(this->stream_id(), this->offset(), this->_id, this->_owner); } QUICFrameType @@ -2899,7 +2899,8 @@ QUICFrameFactory::create_data_blocked_frame(QUICOffset offset, QUICFrameId id, Q } std::unique_ptr -QUICFrameFactory::create_stream_blocked_frame(QUICStreamId stream_id, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) +QUICFrameFactory::create_stream_data_blocked_frame(QUICStreamId stream_id, QUICOffset offset, QUICFrameId id, + QUICFrameGenerator *owner) { QUICStreamDataBlockedFrame *frame = quicStreamBlockedFrameAllocator.alloc(); new (frame) QUICStreamDataBlockedFrame(stream_id, offset, id, owner); diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index db97e06a8fe..ddb94bdd4b2 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -1021,7 +1021,7 @@ class QUICFrameFactory /* * Creates a STREAM_DATA_BLOCKED frame. */ - static std::unique_ptr create_stream_blocked_frame( + static std::unique_ptr create_stream_data_blocked_frame( QUICStreamId stream_id, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 8188d223af7..9470df94427 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -89,13 +89,13 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") CHECK(sm.stream_count() == 4); // STREAM_DATA_BLOCKED frames create new streams - std::shared_ptr stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0x10, 0); + std::shared_ptr stream_blocked_frame = QUICFrameFactory::create_stream_data_blocked_frame(0x10, 0); sm.handle_frame(level, *stream_blocked_frame); CHECK(sm.stream_count() == 5); // Set local maximum stream id sm.set_max_streams_bidi(100); - std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_blocked_frame(0x18, 0); + std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_data_blocked_frame(0x18, 0); sm.handle_frame(level, *stream_blocked_frame_x); CHECK(sm.stream_count() == 5); } @@ -167,8 +167,8 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") sm.init_flow_control_params(local_tp, remote_tp); // Create a stream with STREAM_DATA_BLOCKED (== noop) - std::shared_ptr stream_blocked_frame_0 = QUICFrameFactory::create_stream_blocked_frame(0, 0); - std::shared_ptr stream_blocked_frame_1 = QUICFrameFactory::create_stream_blocked_frame(4, 0); + std::shared_ptr stream_blocked_frame_0 = QUICFrameFactory::create_stream_data_blocked_frame(0, 0); + std::shared_ptr stream_blocked_frame_1 = QUICFrameFactory::create_stream_data_blocked_frame(4, 0); sm.handle_frame(level, *stream_blocked_frame_0); sm.handle_frame(level, *stream_blocked_frame_1); CHECK(sm.stream_count() == 2); diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index 985d7e7ba70..ad5119f08a6 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -37,10 +37,10 @@ TEST_CASE("QUICSendStreamState", "[quic]") block_4->fill(4); CHECK(block_4->read_avail() == 4); - auto stream_frame = QUICFrameFactory::create_stream_frame(block_4, 1, 0); - auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(block_4, 1, 0, true); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); - auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0, 0); + auto stream_frame = QUICFrameFactory::create_stream_frame(block_4, 1, 0); + auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(block_4, 1, 0, true); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); + auto stream_data_blocked_frame = QUICFrameFactory::create_stream_data_blocked_frame(0, 0); MockQUICTransferProgressProvider pp; SECTION("Ready -> Send -> Data Sent -> Data Recvd") @@ -56,7 +56,7 @@ TEST_CASE("QUICSendStreamState", "[quic]") // Case3. Send STREAM_DATA_BLOCKED CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_DATA_BLOCKED)); - ss.update_with_sending_frame(*stream_blocked_frame); + ss.update_with_sending_frame(*stream_data_blocked_frame); CHECK(ss.get() == QUICStreamState::State::Send); // Case3. Send FIN in a STREAM @@ -81,7 +81,7 @@ TEST_CASE("QUICSendStreamState", "[quic]") // Case2. Send STREAM_DATA_BLOCKED CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_DATA_BLOCKED)); - ss.update_with_sending_frame(*stream_blocked_frame); + ss.update_with_sending_frame(*stream_data_blocked_frame); CHECK(ss.get() == QUICStreamState::State::Send); } @@ -147,7 +147,7 @@ TEST_CASE("QUICSendStreamState", "[quic]") // Case3. Send STREAM_DATA_BLOCKED CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_DATA_BLOCKED)); - ss.update_with_sending_frame(*stream_blocked_frame); + ss.update_with_sending_frame(*stream_data_blocked_frame); CHECK(ss.get() == QUICStreamState::State::Send); // Case3. Send FIN in a STREAM @@ -182,11 +182,11 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") block_4->fill(4); CHECK(block_4->read_avail() == 4); - auto stream_frame = QUICFrameFactory::create_stream_frame(block_4, 1, 0); - auto stream_frame_delayed = QUICFrameFactory::create_stream_frame(block_4, 1, 1); - auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(block_4, 1, 2, true); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); - auto stream_blocked_frame = QUICFrameFactory::create_stream_blocked_frame(0, 0); + auto stream_frame = QUICFrameFactory::create_stream_frame(block_4, 1, 0); + auto stream_frame_delayed = QUICFrameFactory::create_stream_frame(block_4, 1, 1); + auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(block_4, 1, 2, true); + auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); + auto stream_data_blocked_frame = QUICFrameFactory::create_stream_data_blocked_frame(0, 0); SECTION("Recv -> Size Known -> Data Recvd -> Data Read") { @@ -201,7 +201,7 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") // Case2. Recv STREAM_DATA_BLOCKED CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM_DATA_BLOCKED)); - ss.update_with_receiving_frame(*stream_blocked_frame); + ss.update_with_receiving_frame(*stream_data_blocked_frame); CHECK(ss.get() == QUICStreamState::State::Recv); // Case3. Recv FIN in a STREAM From 4d1e6fd9ab66a40f2624d4e486fa084a844be879 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Feb 2019 16:28:29 +0900 Subject: [PATCH 1085/1313] Revert debug log format change for interop --- src/tscore/Diags.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/tscore/Diags.cc b/src/tscore/Diags.cc index 815d6d80615..b34db02566c 100644 --- a/src/tscore/Diags.cc +++ b/src/tscore/Diags.cc @@ -225,8 +225,15 @@ Diags::print_va(const char *debug_tag, DiagsLevel diags_level, const SourceLocat format_writer.print("[{timestamp}] "); auto timestamp_offset = format_writer.size(); + format_writer.print("{thread-name}"); + format_writer.print(" {}: ", level_name(diags_level)); + if (location(loc, show_location, diags_level)) { - format_writer.print("<{:50,50}> ", *loc); + format_writer.print("<{}> ", *loc); + } + + if (debug_tag) { + format_writer.print("({}) ", debug_tag); } format_writer.print("{}", format_string); From d537cf28193a564bcfa5328757be54d63dd97e99 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 1 Feb 2019 17:08:36 +0900 Subject: [PATCH 1086/1313] Add http3/ and quic/ to the derectory structure on README --- README | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README b/README index 1a5f5457f3b..50c45def454 100644 --- a/README +++ b/README @@ -26,6 +26,7 @@ plugins to build large scale web applications. |-- dns/ .............. DNS (asynchronous) |-- hostdb/ ........... Internal DNS cache |-- net/ .............. Network + |-- quic/ ......... QUIC implementation |-- utils/ ............ Utilities |-- lib/ .................. |-- cppapi/ ........... C++ api wrapper for plugin developers @@ -43,6 +44,7 @@ plugins to build large scale web applications. |-- hdrs/ ............. Headers parsing and management |-- http/ ............. The actual HTTP protocol implementation |---http2/ ............ HTTP/2 implementation + |---http3/ ............ HTTP/3 implementation |-- logging/ .......... Flexible logging |-- shared/ ........... Shared files |-- rc/ ................... Installation programs and scripts From 8a9dfd51beae9d53bfd1e4668cffbae2297b644f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sun, 3 Feb 2019 15:35:25 +0900 Subject: [PATCH 1087/1313] Catch up changes on master --- proxy/http3/Http3App.cc | 2 +- proxy/http3/Http3ClientSession.cc | 2 +- proxy/http3/Http3ClientSession.h | 2 +- proxy/http3/QUICSimpleApp.cc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 3af0f84a06e..0718862aea0 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -37,7 +37,7 @@ Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QU { this->_client_session = new Http3ClientSession(client_vc); this->_client_session->acl = std::move(session_acl); - this->_client_session->new_connection(client_vc, nullptr, nullptr, false); + this->_client_session->new_connection(client_vc, nullptr, nullptr); this->_qc->stream_manager()->set_default_application(this); diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3ClientSession.cc index 2d81533eca3..c5c04b237a3 100644 --- a/proxy/http3/Http3ClientSession.cc +++ b/proxy/http3/Http3ClientSession.cc @@ -89,7 +89,7 @@ Http3ClientSession::start() } void -Http3ClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader, bool backdoor) +Http3ClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reade) { this->con_id = static_cast(reinterpret_cast(new_vc))->connection_id(); diff --git a/proxy/http3/Http3ClientSession.h b/proxy/http3/Http3ClientSession.h index 38700348051..8af10b0a739 100644 --- a/proxy/http3/Http3ClientSession.h +++ b/proxy/http3/Http3ClientSession.h @@ -45,7 +45,7 @@ class Http3ClientSession : public ProxyClientSession // Implement ProxyClienSession interface void start() override; void destroy() override; - void new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader, bool backdoor) override; + void new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader) override; NetVConnection *get_netvc() const override; int get_transact_count() const override; const char *get_protocol_string() const override; diff --git a/proxy/http3/QUICSimpleApp.cc b/proxy/http3/QUICSimpleApp.cc index fee0899075a..1fb6377e32f 100644 --- a/proxy/http3/QUICSimpleApp.cc +++ b/proxy/http3/QUICSimpleApp.cc @@ -37,7 +37,7 @@ QUICSimpleApp::QUICSimpleApp(QUICNetVConnection *client_vc, IpAllow::ACL session { this->_client_session = new Http3ClientSession(client_vc); this->_client_session->acl = std::move(session_acl); - this->_client_session->new_connection(client_vc, nullptr, nullptr, false); + this->_client_session->new_connection(client_vc, nullptr, nullptr); this->_qc->stream_manager()->set_default_application(this); From c8a5727e45463b686b789acc75dd4938f03b255f Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 31 Jan 2019 09:22:35 +0800 Subject: [PATCH 1088/1313] QUIC: Retransmit NEW/RETIRE_CONNECTION_ID frame --- iocore/net/quic/QUICAltConnectionManager.cc | 51 +++++++++++++++++++++ iocore/net/quic/QUICAltConnectionManager.h | 9 ++-- iocore/net/quic/QUICPacketRetransmitter.cc | 2 + 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index d272bf648da..246a41e5284 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -283,6 +283,7 @@ QUICAltConnectionManager::generate_frame(QUICEncryptionLevel level, uint64_t con this->_alt_quic_connection_ids_local[i].advertised = true; } + this->_records_new_connection_id_frame(level, *static_cast(frame.get())); return frame; } } @@ -292,6 +293,7 @@ QUICAltConnectionManager::generate_frame(QUICEncryptionLevel level, uint64_t con if (!this->_retired_seq_nums.empty()) { if (auto s = this->_retired_seq_nums.front()) { frame = QUICFrameFactory::create_retire_connection_id_frame(s); + this->_records_retire_connection_id_frame(level, *static_cast(frame.get())); this->_retired_seq_nums.pop(); return frame; } @@ -299,3 +301,52 @@ QUICAltConnectionManager::generate_frame(QUICEncryptionLevel level, uint64_t con return frame; } + +void +QUICAltConnectionManager::_records_new_connection_id_frame(QUICEncryptionLevel level, const QUICNewConnectionIdFrame &frame) +{ + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = frame.type(); + info->level = level; + + AltConnectionInfo *frame_info = reinterpret_cast(info->data); + frame_info->seq_num = frame.sequence(); + frame_info->token = frame.stateless_reset_token(); + frame_info->id = frame.connection_id(); + this->_records_frame(frame.id(), std::move(info)); +} + +void +QUICAltConnectionManager::_records_retire_connection_id_frame(QUICEncryptionLevel level, const QUICRetireConnectionIdFrame &frame) +{ + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = frame.type(); + info->level = level; + *reinterpret_cast(info->data) = frame.seq_num(); + this->_records_frame(frame.id(), std::move(info)); +} + +void +QUICAltConnectionManager::_on_frame_lost(QUICFrameInformationUPtr &info) +{ + switch (info->type) { + case QUICFrameType::NEW_CONNECTION_ID: { + AltConnectionInfo *frame_info = reinterpret_cast(info->data); + for (int i = 0; i < this->_nids; ++i) { + if (this->_alt_quic_connection_ids_local[i].seq_num == frame_info->seq_num) { + ink_assert(this->_alt_quic_connection_ids_local[i].advertised); + this->_alt_quic_connection_ids_local[i].advertised = false; + this->_need_advertise = true; + return; + } + } + break; + } + case QUICFrameType::RETIRE_CONNECTION_ID: { + this->_retired_seq_nums.push(*reinterpret_cast(info->data)); + break; + } + default: + ink_assert(0); + } +} diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index 7391b4a32a7..ce872b3fdb2 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -86,9 +86,7 @@ class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenera QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; private: - class AltConnectionInfo - { - public: + struct AltConnectionInfo { uint64_t seq_num; QUICConnectionId id; QUICStatelessResetToken token; @@ -113,6 +111,11 @@ class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenera void _init_alt_connection_ids(const IpEndpoint *preferred_endpoint = nullptr); bool _update_alt_connection_id(uint64_t chosen_seq_num); + void _records_new_connection_id_frame(QUICEncryptionLevel level, const QUICNewConnectionIdFrame &frame); + void _records_retire_connection_id_frame(QUICEncryptionLevel, const QUICRetireConnectionIdFrame &frame); + + void _on_frame_lost(QUICFrameInformationUPtr &info); + QUICConnectionErrorUPtr _register_remote_connection_id(const QUICNewConnectionIdFrame &frame); QUICConnectionErrorUPtr _retire_remote_connection_id(const QUICRetireConnectionIdFrame &frame); }; diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc index 79173eb3b25..b20078111a0 100644 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ b/iocore/net/quic/QUICPacketRetransmitter.cc @@ -56,6 +56,8 @@ QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) case QUICFrameType::CONNECTION_CLOSE: case QUICFrameType::STREAM: case QUICFrameType::CRYPTO: + case QUICFrameType::NEW_CONNECTION_ID: + case QUICFrameType::RETIRE_CONNECTION_ID: break; default: frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); From 92707337a66e256899026ecc45605d14b64055a0 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 1 Feb 2019 10:41:31 +0800 Subject: [PATCH 1089/1313] QUIC: Cast reference directly --- iocore/net/quic/QUICAltConnectionManager.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 246a41e5284..20343b9b506 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -283,7 +283,7 @@ QUICAltConnectionManager::generate_frame(QUICEncryptionLevel level, uint64_t con this->_alt_quic_connection_ids_local[i].advertised = true; } - this->_records_new_connection_id_frame(level, *static_cast(frame.get())); + this->_records_new_connection_id_frame(level, static_cast(*frame)); return frame; } } @@ -293,7 +293,7 @@ QUICAltConnectionManager::generate_frame(QUICEncryptionLevel level, uint64_t con if (!this->_retired_seq_nums.empty()) { if (auto s = this->_retired_seq_nums.front()) { frame = QUICFrameFactory::create_retire_connection_id_frame(s); - this->_records_retire_connection_id_frame(level, *static_cast(frame.get())); + this->_records_retire_connection_id_frame(level, static_cast(*frame)); this->_retired_seq_nums.pop(); return frame; } From c5f36deb48f418ffd79c26a857e5b68a8ada0074 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Feb 2019 11:12:48 +0900 Subject: [PATCH 1090/1313] Add missing override keyword --- iocore/net/quic/QUICAltConnectionManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index ce872b3fdb2..85579c47302 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -114,7 +114,7 @@ class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenera void _records_new_connection_id_frame(QUICEncryptionLevel level, const QUICNewConnectionIdFrame &frame); void _records_retire_connection_id_frame(QUICEncryptionLevel, const QUICRetireConnectionIdFrame &frame); - void _on_frame_lost(QUICFrameInformationUPtr &info); + void _on_frame_lost(QUICFrameInformationUPtr &info) override; QUICConnectionErrorUPtr _register_remote_connection_id(const QUICNewConnectionIdFrame &frame); QUICConnectionErrorUPtr _retire_remote_connection_id(const QUICRetireConnectionIdFrame &frame); From 7a83ea8c1a9a01ac40649c4114bc1dcbc8c79c03 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Feb 2019 11:40:12 +0900 Subject: [PATCH 1091/1313] Fix test_QUICFrameDispatcher --- iocore/net/quic/test/test_QUICFrameDispatcher.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 5c9f9ccbefb..501eaa96419 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -64,7 +64,7 @@ TEST_CASE("QUICFrameHandler", "[quic]") CHECK(streamManager.getTotalFrameCount() == 1); // CONNECTION_CLOSE frame - QUICConnectionCloseFrame connectionCloseFrame({}); + QUICConnectionCloseFrame connectionCloseFrame(0, 0, "", 0, nullptr); connectionCloseFrame.store(buf, &len, 4096); quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack, is_flow_controlled, nullptr); CHECK(connection.getTotalFrameCount() == 1); From c1501512cb80969b8a3e466e7b86b7e0d647b5a6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Feb 2019 14:06:50 +0900 Subject: [PATCH 1092/1313] Fix tests for QUICTransportParameters --- .../quic/test/test_QUICTransportParameters.cc | 121 +++++++++--------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index f993b4ead96..41a4eb949c8 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -38,12 +38,12 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") 0x00, 0x01, // parameter id 0x00, 0x04, // length of value 0x12, 0x34, 0x56, 0x78, // value - 0x00, 0x02, // parameter id + 0x00, 0x05, // parameter id 0x00, 0x02, // length of value 0x0a, 0x0b, // value 0x00, 0x03, // parameter id 0x00, 0x02, // length of value - 0x01, 0x23, // value + 0x05, 0x67, // value }; QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf)); @@ -53,23 +53,23 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") uint16_t len = 0; const uint8_t *data = nullptr; - data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, len); + data = params_in_ch.getAsBytes(QUICTransportParameterId::ORIGINAL_CONNECTION_ID, len); CHECK(len == 4); CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); - data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_DATA, len); + data = params_in_ch.getAsBytes(QUICTransportParameterId::IDLE_TIMEOUT, len); CHECK(len == 4); CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); - data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, len); + data = params_in_ch.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, len); CHECK(len == 2); CHECK(memcmp(data, "\x0a\x0b", 2) == 0); - data = params_in_ch.getAsBytes(QUICTransportParameterId::IDLE_TIMEOUT, len); + data = params_in_ch.getAsBytes(QUICTransportParameterId::MAX_PACKET_SIZE, len); CHECK(len == 2); - CHECK(memcmp(data, "\x01\x23", 2) == 0); + CHECK(memcmp(data, "\x05\x67", 2) == 0); - data = params_in_ch.getAsBytes(QUICTransportParameterId::MAX_PACKET_SIZE, len); + data = params_in_ch.getAsBytes(QUICTransportParameterId::ACK_DELAY_EXPONENT, len); CHECK(len == 0); CHECK(data == nullptr); } @@ -100,16 +100,16 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") uint8_t expected[] = { 0x05, 0x06, 0x07, 0x08, // initial version 0x00, 0x22, // size of parameters - 0x00, 0x00, // parameter id - 0x00, 0x04, // length of value - 0x11, 0x22, 0x33, 0x44, // value - 0x00, 0x05, // parameter id - 0x00, 0x02, // length of value - 0xab, 0xcd, // value - 0x00, 0x06, // parameter id + 0x00, 0x02, // parameter id 0x00, 0x10, // length of value 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // value 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // value + 0x00, 0x03, // parameter id + 0x00, 0x02, // length of value + 0x5b, 0xcd, // value + 0x00, 0x05, // parameter id + 0x00, 0x04, // length of value + 0x91, 0x22, 0x33, 0x44, // value }; QUICTransportParametersInClientHello params_in_ch(0x05060708); @@ -117,7 +117,7 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") uint32_t max_stream_data = 0x11223344; params_in_ch.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, max_stream_data); - uint16_t max_packet_size = 0xabcd; + uint16_t max_packet_size = 0x1bcd; params_in_ch.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size); uint8_t stateless_reset_token[16] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, @@ -133,23 +133,24 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") { SECTION("OK case") { - uint8_t buf[] = {0x01, 0x02, 0x03, 0x04, // negotiated version - 0x04, // size of supported versions - 0x01, 0x02, 0x03, 0x04, // - 0x00, 0x2a, // size of parameters - 0x00, 0x0a, // parameter id - 0x00, 0x04, // length of value - 0x11, 0x22, 0x33, 0x44, // value - 0x00, 0x01, // parameter id - 0x00, 0x04, // length of value - 0x12, 0x34, 0x56, 0x78, // value - 0x00, 0x03, // parameter id - 0x00, 0x02, // length of value - 0x01, 0x23, // value - 0x00, 0x06, // parameter id - 0x00, 0x10, // length of value - 0x00, 0x10, 0x20, 0x30, // value - 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0}; + uint8_t buf[] = { + 0x01, 0x02, 0x03, 0x04, // negotiated version + 0x04, // size of supported versions + 0x01, 0x02, 0x03, 0x04, // + 0x00, 0x2a, // size of parameters + 0x00, 0x01, // parameter id + 0x00, 0x02, // length of value + 0x51, 0x23, // value + 0x00, 0x02, // parameter id + 0x00, 0x10, // length of value + 0x00, 0x10, 0x20, 0x30, // value + 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0x00, 0x04, // parameter id + 0x00, 0x04, // length of value + 0x92, 0x34, 0x56, 0x78, // value + 0x00, 0x06, // parameter id + 0x00, 0x04, // length of value + 0x91, 0x22, 0x33, 0x44, // value + }; QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf)); CHECK(params_in_ee.is_valid()); @@ -161,19 +162,19 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, len); CHECK(len == 4); - CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); + CHECK(memcmp(data, "\x91\x22\x33\x44", 4) == 0); data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_DATA, len); CHECK(len == 4); - CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); + CHECK(memcmp(data, "\x92\x34\x56\x78", 4) == 0); data = params_in_ee.getAsBytes(QUICTransportParameterId::IDLE_TIMEOUT, len); CHECK(len == 2); - CHECK(memcmp(data, "\x01\x23", 2) == 0); + CHECK(memcmp(data, "\x51\x23", 2) == 0); data = params_in_ee.getAsBytes(QUICTransportParameterId::STATELESS_RESET_TOKEN, len); CHECK(len == 16); - CHECK(memcmp(data, buf + 37, 16) == 0); + CHECK(memcmp(data, buf + 21, 16) == 0); CHECK(!params_in_ee.contains(QUICTransportParameterId::DISABLE_MIGRATION)); } @@ -185,16 +186,16 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") 0x04, // size of supported versions 0x01, 0x02, 0x03, 0x04, // 0x00, 0x1a, // size of parameters - 0x00, 0x0a, // parameter id - 0x00, 0x04, // length of value - 0x11, 0x22, 0x33, 0x44, // value 0x00, 0x01, // parameter id - 0x00, 0x04, // length of value - 0x12, 0x34, 0x56, 0x78, // value - 0x00, 0x03, // parameter id 0x00, 0x02, // length of value - 0x01, 0x23, // value - 0x00, 0x09, // parameter id + 0x51, 0x23, // value + 0x00, 0x04, // parameter id + 0x00, 0x04, // length of value + 0xa2, 0x34, 0x56, 0x78, // value + 0x00, 0x06, // parameter id + 0x00, 0x04, // length of value + 0xa1, 0x22, 0x33, 0x44, // value + 0x00, 0x0c, // parameter id 0x00, 0x00, // length of value }; @@ -206,15 +207,15 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, len); CHECK(len == 4); - CHECK(memcmp(data, "\x11\x22\x33\x44", 4) == 0); + CHECK(memcmp(data, "\xa1\x22\x33\x44", 4) == 0); data = params_in_ee.getAsBytes(QUICTransportParameterId::INITIAL_MAX_DATA, len); CHECK(len == 4); - CHECK(memcmp(data, "\x12\x34\x56\x78", 4) == 0); + CHECK(memcmp(data, "\xa2\x34\x56\x78", 4) == 0); data = params_in_ee.getAsBytes(QUICTransportParameterId::IDLE_TIMEOUT, len); CHECK(len == 2); - CHECK(memcmp(data, "\x01\x23", 2) == 0); + CHECK(memcmp(data, "\x51\x23", 2) == 0); CHECK(params_in_ee.contains(QUICTransportParameterId::DISABLE_MIGRATION)); } @@ -252,12 +253,12 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") 0x01, 0x02, 0x03, 0x04, // version 1 0x05, 0x06, 0x07, 0x08, // version 2 0x00, 0x0e, // size of parameters - 0x00, 0x05, // parameter id + 0x00, 0x03, // parameter id 0x00, 0x02, // length of value - 0xab, 0xcd, // value - 0x00, 0x0a, // parameter id + 0x5b, 0xcd, // value + 0x00, 0x06, // parameter id 0x00, 0x04, // length of value - 0x11, 0x22, 0x33, 0x44, // value + 0x91, 0x22, 0x33, 0x44, // value }; QUICTransportParametersInEncryptedExtensions params_in_ee(0x01020304); @@ -265,7 +266,7 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") uint32_t max_stream_data = 0x11223344; params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, max_stream_data); - uint16_t max_packet_size = 0xabcd; + uint16_t max_packet_size = 0x1bcd; params_in_ee.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size); params_in_ee.add_version(0x01020304); @@ -286,14 +287,14 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") 0x01, 0x02, 0x03, 0x04, // version 1 0x05, 0x06, 0x07, 0x08, // version 2 0x00, 0x12, // size of parameters - 0x00, 0x05, // parameter id + 0x00, 0x03, // parameter id 0x00, 0x02, // length of value - 0xab, 0xcd, // value - 0x00, 0x09, // parameter id - 0x00, 0x00, // length of value - 0x00, 0x0a, // parameter id + 0x5b, 0xcd, // value + 0x00, 0x06, // parameter id 0x00, 0x04, // length of value - 0x11, 0x22, 0x33, 0x44, // value + 0x91, 0x22, 0x33, 0x44, // value + 0x00, 0x0c, // parameter id + 0x00, 0x00, // length of value }; QUICTransportParametersInEncryptedExtensions params_in_ee(0x01020304); @@ -301,7 +302,7 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") uint32_t max_stream_data = 0x11223344; params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, max_stream_data); - uint16_t max_packet_size = 0xabcd; + uint16_t max_packet_size = 0x1bcd; params_in_ee.set(QUICTransportParameterId::MAX_PACKET_SIZE, max_packet_size); params_in_ee.set(QUICTransportParameterId::DISABLE_MIGRATION, nullptr, 0); From f6810b0abcca5e42c321187b4b736e517ce8f07f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Feb 2019 16:05:42 +0900 Subject: [PATCH 1093/1313] Fix tests for QUICFrame This removes tests for RetransmissionFrame --- iocore/net/quic/test/test_QUICFrame.cc | 579 +++++-------------------- 1 file changed, 114 insertions(+), 465 deletions(-) diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 2751afd4ec7..be579dc1388 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -33,36 +33,43 @@ extern const ink_freelist_ops *freelist_class_ops; TEST_CASE("QUICFrame Type", "[quic]") { CHECK(QUICFrame::type(reinterpret_cast("\x00")) == QUICFrameType::PADDING); - CHECK(QUICFrame::type(reinterpret_cast("\x01")) == QUICFrameType::RESET_STREAM); - CHECK(QUICFrame::type(reinterpret_cast("\x02")) == QUICFrameType::CONNECTION_CLOSE); - CHECK(QUICFrame::type(reinterpret_cast("\x04")) == QUICFrameType::MAX_DATA); - CHECK(QUICFrame::type(reinterpret_cast("\x05")) == QUICFrameType::MAX_STREAM_DATA); - CHECK(QUICFrame::type(reinterpret_cast("\x06")) == QUICFrameType::MAX_STREAMS); - CHECK(QUICFrame::type(reinterpret_cast("\x07")) == QUICFrameType::PING); - CHECK(QUICFrame::type(reinterpret_cast("\x08")) == QUICFrameType::DATA_BLOCKED); - CHECK(QUICFrame::type(reinterpret_cast("\x09")) == QUICFrameType::STREAM_DATA_BLOCKED); - CHECK(QUICFrame::type(reinterpret_cast("\x0a")) == QUICFrameType::STREAMS_BLOCKED); - CHECK(QUICFrame::type(reinterpret_cast("\x0b")) == QUICFrameType::NEW_CONNECTION_ID); - CHECK(QUICFrame::type(reinterpret_cast("\x0c")) == QUICFrameType::STOP_SENDING); - CHECK(QUICFrame::type(reinterpret_cast("\x0d")) == QUICFrameType::RETIRE_CONNECTION_ID); - CHECK(QUICFrame::type(reinterpret_cast("\x0e")) == QUICFrameType::PATH_CHALLENGE); - CHECK(QUICFrame::type(reinterpret_cast("\x0f")) == QUICFrameType::PATH_RESPONSE); + CHECK(QUICFrame::type(reinterpret_cast("\x01")) == QUICFrameType::PING); + + // Range of ACK + CHECK(QUICFrame::type(reinterpret_cast("\x02")) == QUICFrameType::ACK); + CHECK(QUICFrame::type(reinterpret_cast("\x03")) == QUICFrameType::ACK); + + CHECK(QUICFrame::type(reinterpret_cast("\x04")) == QUICFrameType::RESET_STREAM); + CHECK(QUICFrame::type(reinterpret_cast("\x05")) == QUICFrameType::STOP_SENDING); + CHECK(QUICFrame::type(reinterpret_cast("\x06")) == QUICFrameType::CRYPTO); + CHECK(QUICFrame::type(reinterpret_cast("\x07")) == QUICFrameType::NEW_TOKEN); // Range of STREAM - CHECK(QUICFrame::type(reinterpret_cast("\x10")) == QUICFrameType::STREAM); - CHECK(QUICFrame::type(reinterpret_cast("\x17")) == QUICFrameType::STREAM); + CHECK(QUICFrame::type(reinterpret_cast("\x08")) == QUICFrameType::STREAM); + CHECK(QUICFrame::type(reinterpret_cast("\x0f")) == QUICFrameType::STREAM); - CHECK(QUICFrame::type(reinterpret_cast("\x18")) == QUICFrameType::CRYPTO); - CHECK(QUICFrame::type(reinterpret_cast("\x19")) == QUICFrameType::NEW_TOKEN); - CHECK(QUICFrame::type(reinterpret_cast("\x18")) == QUICFrameType::CRYPTO); - CHECK(QUICFrame::type(reinterpret_cast("\x19")) == QUICFrameType::NEW_TOKEN); + CHECK(QUICFrame::type(reinterpret_cast("\x10")) == QUICFrameType::MAX_DATA); + CHECK(QUICFrame::type(reinterpret_cast("\x11")) == QUICFrameType::MAX_STREAM_DATA); - // Range of ACK - CHECK(QUICFrame::type(reinterpret_cast("\x1a")) == QUICFrameType::ACK); - CHECK(QUICFrame::type(reinterpret_cast("\x1b")) == QUICFrameType::ACK); + CHECK(QUICFrame::type(reinterpret_cast("\x12")) == QUICFrameType::MAX_STREAMS); + CHECK(QUICFrame::type(reinterpret_cast("\x13")) == QUICFrameType::MAX_STREAMS); + + CHECK(QUICFrame::type(reinterpret_cast("\x14")) == QUICFrameType::DATA_BLOCKED); + CHECK(QUICFrame::type(reinterpret_cast("\x15")) == QUICFrameType::STREAM_DATA_BLOCKED); + + CHECK(QUICFrame::type(reinterpret_cast("\x16")) == QUICFrameType::STREAMS_BLOCKED); + CHECK(QUICFrame::type(reinterpret_cast("\x17")) == QUICFrameType::STREAMS_BLOCKED); + + CHECK(QUICFrame::type(reinterpret_cast("\x18")) == QUICFrameType::NEW_CONNECTION_ID); + CHECK(QUICFrame::type(reinterpret_cast("\x19")) == QUICFrameType::RETIRE_CONNECTION_ID); + CHECK(QUICFrame::type(reinterpret_cast("\x1a")) == QUICFrameType::PATH_CHALLENGE); + CHECK(QUICFrame::type(reinterpret_cast("\x1b")) == QUICFrameType::PATH_RESPONSE); + + CHECK(QUICFrame::type(reinterpret_cast("\x1c")) == QUICFrameType::CONNECTION_CLOSE); + CHECK(QUICFrame::type(reinterpret_cast("\x1d")) == QUICFrameType::CONNECTION_CLOSE); // Undefined ragne - CHECK(QUICFrame::type(reinterpret_cast("\x21")) == QUICFrameType::UNKNOWN); + CHECK(QUICFrame::type(reinterpret_cast("\x1e")) == QUICFrameType::UNKNOWN); CHECK(QUICFrame::type(reinterpret_cast("\xff")) == QUICFrameType::UNKNOWN); } @@ -71,7 +78,7 @@ TEST_CASE("Load STREAM Frame", "[quic]") SECTION("OLF=000") { uint8_t buf1[] = { - 0x10, // 0b00010OLF (OLF=000) + 0x08, // 0b00001OLF (OLF=000) 0x01, // Stream ID 0x01, 0x02, 0x03, 0x04, // Stream Data }; @@ -89,7 +96,7 @@ TEST_CASE("Load STREAM Frame", "[quic]") SECTION("OLF=010") { uint8_t buf1[] = { - 0x12, // 0b00010OLF (OLF=010) + 0x0a, // 0b00001OLF (OLF=010) 0x01, // Stream ID 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data @@ -108,7 +115,7 @@ TEST_CASE("Load STREAM Frame", "[quic]") SECTION("OLF=110") { uint8_t buf1[] = { - 0x16, // 0b00010OLF (OLF=110) + 0x0e, // 0b00001OLF (OLF=110) 0x01, // Stream ID 0x02, // Data Length 0x05, // Data Length @@ -129,7 +136,7 @@ TEST_CASE("Load STREAM Frame", "[quic]") SECTION("OLF=111") { uint8_t buf1[] = { - 0x17, // 0b00010OLF (OLF=110) + 0x0f, // 0b00001OLF (OLF=111) 0x01, // Stream ID 0x02, // Data Length 0x05, // Data Length @@ -150,7 +157,7 @@ TEST_CASE("Load STREAM Frame", "[quic]") SECTION("BAD DATA") { uint8_t buf1[] = { - 0x17, // 0b00010OLF (OLF=110) + 0x0e, // 0b00001OLF (OLF=110) 0x01, // Stream ID 0x02, // Data Length 0x05, // Data Length @@ -164,7 +171,7 @@ TEST_CASE("Load STREAM Frame", "[quic]") SECTION("BAD DATA") { uint8_t buf1[] = { - 0x17, // 0b00010OLF (OLF=110) + 0x0e, // 0b00001OLF (OLF=110) 0x01, // Stream ID }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); @@ -180,7 +187,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") uint8_t buf[32] = {0}; size_t len; uint8_t expected1[] = { - 0x12, // 0b00010OLF (OLF=010) + 0x0a, // 0b00001OLF (OLF=010) 0x01, // Stream ID 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data @@ -205,7 +212,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") uint8_t buf[32] = {0}; size_t len; uint8_t expected2[] = { - 0x16, // 0b00010OLF (OLF=110) + 0x0e, // 0b00001OLF (OLF=110) 0x01, // Stream ID 0x01, // Offset 0x05, // Data Length @@ -230,7 +237,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") uint8_t buf[32] = {0}; size_t len; uint8_t expected3[] = { - 0x16, // 0b00010OLF (OLF=110) + 0x0e, // 0b00001OLF (OLF=110) 0x01, // Stream ID 0x80, 0x01, 0x00, 0x00, // Offset 0x05, // Data Length @@ -255,7 +262,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") uint8_t buf[32] = {0}; size_t len; uint8_t expected4[] = { - 0x16, // 0b00010OLF (OLF=110) + 0x0e, // 0b00001OLF (OLF=110) 0x01, // Stream ID 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset 0x05, // Data Length @@ -280,7 +287,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") uint8_t buf[32] = {0}; size_t len; uint8_t expected5[] = { - 0x16, // 0b00010OLF (OLF=110) + 0x0e, // 0b00001OLF (OLF=110) 0x41, 0x00, // Stream ID 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset 0x05, // Data Length @@ -305,7 +312,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") uint8_t buf[32] = {0}; size_t len; uint8_t expected6[] = { - 0x16, // 0b00010OLF (OLF=110) + 0x0e, // 0b00001OLF (OLF=110) 0x80, 0x01, 0x00, 0x00, // Stream ID 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset 0x05, // Data Length @@ -330,7 +337,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") uint8_t buf[32] = {0}; size_t len; uint8_t expected7[] = { - 0x16, // 0b00010OLF (OLF=110) + 0x0e, // 0b00001OLF (OLF=110) 0x81, 0x00, 0x00, 0x00, // Stream ID 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset 0x05, // Data Length @@ -355,7 +362,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") uint8_t buf[32] = {0}; size_t len; uint8_t expected[] = { - 0x17, // 0b00010OLF (OLF=111) + 0x0f, // 0b00001OLF (OLF=111) 0x81, 0x00, 0x00, 0x00, // Stream ID 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset 0x05, // Data Length @@ -378,7 +385,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") SECTION("split stream frame") { uint8_t buf1[] = { - 0x16, // 0b00010OLF (OLF=110) + 0x0e, // 0b00001OLF (OLF=110) 0x01, // Stream ID 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset 0x0a, // Data Length @@ -414,7 +421,7 @@ TEST_CASE("CRYPTO Frame", "[quic]") SECTION("Loading") { uint8_t buf[] = { - 0x18, // Type + 0x06, // Type 0x80, 0x01, 0x00, 0x00, // Offset 0x05, // Length 0x01, 0x02, 0x03, 0x04, 0x05, // Crypto Data @@ -432,7 +439,7 @@ TEST_CASE("CRYPTO Frame", "[quic]") SECTION("BAD Loading") { uint8_t buf[] = { - 0x18, // Type + 0x06, // Type 0x80, 0x01, 0x00, 0x00, // Offset }; std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); @@ -445,7 +452,7 @@ TEST_CASE("CRYPTO Frame", "[quic]") uint8_t buf[32] = {0}; size_t len; uint8_t expected[] = { - 0x18, // Typr + 0x06, // Typr 0x80, 0x01, 0x00, 0x00, // Offset 0x05, // Length 0x01, 0x02, 0x03, 0x04, 0x05, // Crypto Data @@ -470,7 +477,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") { uint8_t buf1[] = { - 0x1a, // Type + 0x02, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x00, // Ack Block Count @@ -489,7 +496,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") { uint8_t buf1[] = { - 0x1a, // Type + 0x02, // Type 0x80, 0x00, 0x00, 0x01, // Largest Acknowledged 0x41, 0x71, // Ack Delay 0x00, // Ack Block Count @@ -513,7 +520,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("2 Ack Block, 8 bit packet number length, 8 bit block length") { uint8_t buf1[] = { - 0x1a, // Type + 0x02, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x02, // Ack Block Count @@ -551,7 +558,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("load bad frame") { uint8_t buf1[] = { - 0x1a, // Type + 0x02, // Type 0x12, // Largest Acknowledged }; @@ -563,7 +570,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("load bad block") { uint8_t buf1[] = { - 0x1a, // Type + 0x02, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x02, // Ack Block Count @@ -581,7 +588,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length with ECN section") { uint8_t buf1[] = { - 0x1b, // Type + 0x03, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x00, // Ack Block Count @@ -608,7 +615,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length with ECN section") { uint8_t buf1[] = { - 0x1b, // Type + 0x03, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x00, // Ack Block Count @@ -631,7 +638,7 @@ TEST_CASE("Store Ack Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x1a, // Type + 0x02, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x00, // Ack Block Count @@ -652,7 +659,7 @@ TEST_CASE("Store Ack Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x1a, // Type + 0x02, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x02, // Ack Block Count @@ -679,7 +686,7 @@ TEST_CASE("Store Ack Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x1a, // Type + 0x02, // Type 0x12, // Largest Acknowledged 0x74, 0x56, // Ack Delay 0x02, // Ack Block Count @@ -706,7 +713,7 @@ TEST_CASE("Load RESET_STREAM Frame", "[quic]") SECTION("Load") { uint8_t buf1[] = { - 0x01, // Type + 0x04, // Type 0x92, 0x34, 0x56, 0x78, // Stream ID 0x00, 0x01, // Error Code 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset @@ -724,7 +731,7 @@ TEST_CASE("Load RESET_STREAM Frame", "[quic]") SECTION("BAD Load") { uint8_t buf1[] = { - 0x01, // Type + 0x04, // Type 0x92, 0x34, 0x56, 0x78, // Stream ID 0x00, 0x01, // Error Code }; @@ -740,7 +747,7 @@ TEST_CASE("Store RESET_STREAM Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x01, // Type + 0x04, // Type 0x92, 0x34, 0x56, 0x78, // Stream ID 0x00, 0x01, // Error Code 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset @@ -756,7 +763,7 @@ TEST_CASE("Store RESET_STREAM Frame", "[quic]") TEST_CASE("Load Ping Frame", "[quic]") { uint8_t buf[] = { - 0x07, // Type + 0x01, // Type }; std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::PING); @@ -772,7 +779,7 @@ TEST_CASE("Store Ping Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x07, // Type + 0x01, // Type }; QUICPingFrame frame; @@ -817,7 +824,7 @@ TEST_CASE("ConnectionClose Frame", "[quic]") SECTION("loading w/ reason phrase") { uint8_t buf[] = { - 0x02, // Type + 0x1c, // Type 0x00, 0x0A, // Error Code 0x00, // Frame Type 0x05, // Reason Phrase Length @@ -840,7 +847,7 @@ TEST_CASE("ConnectionClose Frame", "[quic]") SECTION("Bad loading") { uint8_t buf[] = { - 0x02, // Type + 0x1c, // Type 0x00, 0x0A, // Error Code 0x00, // Frame Type 0x05, // Reason Phrase Length @@ -854,9 +861,9 @@ TEST_CASE("ConnectionClose Frame", "[quic]") SECTION("loading w/o reason phrase") { uint8_t buf[] = { - 0x02, // Type + 0x1c, // Type 0x00, 0x0A, // Error Code - 0x01, // Frame Type + 0x04, // Frame Type 0x00, // Reason Phrase Length }; std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); @@ -877,9 +884,9 @@ TEST_CASE("ConnectionClose Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x02, // Type + 0x1c, // Type 0x00, 0x0A, // Error Code - 0x10, // Frame Type + 0x08, // Frame Type 0x05, // Reason Phrase Length 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; @@ -898,7 +905,7 @@ TEST_CASE("ConnectionClose Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x02, // Type + 0x1c, // Type 0x00, 0x0A, // Error Code 0x00, // Frame Type 0x00, // Reason Phrase Length @@ -916,7 +923,7 @@ TEST_CASE("Load MaxData Frame", "[quic]") SECTION("Load") { uint8_t buf1[] = { - 0x04, // Type + 0x10, // Type 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); @@ -930,7 +937,7 @@ TEST_CASE("Load MaxData Frame", "[quic]") SECTION("Bad Load") { uint8_t buf1[] = { - 0x04, // Type + 0x10, // Type }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_DATA); @@ -944,7 +951,7 @@ TEST_CASE("Store MaxData Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x04, // Type + 0x10, // Type 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data }; QUICMaxDataFrame max_data_frame(0x1122334455667788, 0, nullptr); @@ -960,7 +967,7 @@ TEST_CASE("Load MaxStreamData Frame", "[quic]") SECTION("Load") { uint8_t buf1[] = { - 0x05, // Type + 0x11, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data }; @@ -977,7 +984,7 @@ TEST_CASE("Load MaxStreamData Frame", "[quic]") SECTION("Load") { uint8_t buf1[] = { - 0x05, // Type + 0x11, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); @@ -992,7 +999,7 @@ TEST_CASE("Store MaxStreamData Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x05, // Type + 0x11, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data }; @@ -1004,12 +1011,12 @@ TEST_CASE("Store MaxStreamData Frame", "[quic]") CHECK(memcmp(buf, expected, len) == 0); } -TEST_CASE("Load MaxStreamId Frame", "[quic]") +TEST_CASE("Load MaxStreams Frame", "[quic]") { SECTION("load") { uint8_t buf1[] = { - 0x06, // Type + 0x12, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); @@ -1022,7 +1029,7 @@ TEST_CASE("Load MaxStreamId Frame", "[quic]") SECTION("bad load") { uint8_t buf1[] = { - 0x06, // Type + 0x12, // Type }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_STREAMS); @@ -1030,13 +1037,13 @@ TEST_CASE("Load MaxStreamId Frame", "[quic]") } } -TEST_CASE("Store MaxStreamId Frame", "[quic]") +TEST_CASE("Store MaxStreams Frame", "[quic]") { uint8_t buf[65535]; size_t len; uint8_t expected[] = { - 0x06, // Type + 0x12, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID }; QUICMaxStreamsFrame max_streams_frame(0x01020304, 0, nullptr); @@ -1047,12 +1054,12 @@ TEST_CASE("Store MaxStreamId Frame", "[quic]") CHECK(memcmp(buf, expected, len) == 0); } -TEST_CASE("Load Blocked Frame", "[quic]") +TEST_CASE("Load DataBlocked Frame", "[quic]") { SECTION("load") { uint8_t buf1[] = { - 0x08, // Type + 0x14, // Type 0x07, // Offset }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); @@ -1067,7 +1074,7 @@ TEST_CASE("Load Blocked Frame", "[quic]") SECTION("bad load") { uint8_t buf1[] = { - 0x08, // Type + 0x14, // Type }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::DATA_BLOCKED); @@ -1075,13 +1082,13 @@ TEST_CASE("Load Blocked Frame", "[quic]") } } -TEST_CASE("Store Blocked Frame", "[quic]") +TEST_CASE("Store DataBlocked Frame", "[quic]") { uint8_t buf[65535]; size_t len; uint8_t expected[] = { - 0x08, // Type + 0x14, // Type 0x07, // Offset }; QUICDataBlockedFrame blocked_stream_frame(0x07, 0, nullptr); @@ -1097,7 +1104,7 @@ TEST_CASE("Load StreamDataBlocked Frame", "[quic]") SECTION("Load") { uint8_t buf1[] = { - 0x09, // Type + 0x15, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID 0x07, // Offset }; @@ -1114,7 +1121,7 @@ TEST_CASE("Load StreamDataBlocked Frame", "[quic]") SECTION("Load") { uint8_t buf1[] = { - 0x09, // Type + 0x15, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); @@ -1129,7 +1136,7 @@ TEST_CASE("Store StreamDataBlocked Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x09, // Type + 0x15, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID 0x07, // Offset }; @@ -1141,12 +1148,12 @@ TEST_CASE("Store StreamDataBlocked Frame", "[quic]") CHECK(memcmp(buf, expected, len) == 0); } -TEST_CASE("Load StreamIdBlocked Frame", "[quic]") +TEST_CASE("Load StreamsBlocked Frame", "[quic]") { SECTION("Load") { uint8_t buf1[] = { - 0x0a, // Type + 0x16, // Type 0x41, 0x02, // Stream ID }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); @@ -1161,7 +1168,7 @@ TEST_CASE("Load StreamIdBlocked Frame", "[quic]") SECTION("Load") { uint8_t buf1[] = { - 0x0a, // Type + 0x16, // Type }; std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAMS_BLOCKED); @@ -1169,13 +1176,13 @@ TEST_CASE("Load StreamIdBlocked Frame", "[quic]") } } -TEST_CASE("Store StreamIdBlocked Frame", "[quic]") +TEST_CASE("Store StreamsBlocked Frame", "[quic]") { uint8_t buf[65535]; size_t len; uint8_t expected[] = { - 0x0a, // Type + 0x16, // Type 0x41, 0x02, // Stream ID }; QUICStreamIdBlockedFrame stream_id_blocked_frame(0x0102, 0, nullptr); @@ -1191,9 +1198,9 @@ TEST_CASE("Load NewConnectionId Frame", "[quic]") SECTION("load") { uint8_t buf1[] = { - 0x0b, // Type - 0x08, // Length + 0x18, // Type 0x41, 0x02, // Sequence + 0x08, // Length 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, @@ -1213,9 +1220,9 @@ TEST_CASE("Load NewConnectionId Frame", "[quic]") SECTION("Bad Load") { uint8_t buf1[] = { - 0x0b, // Type - 0x08, // Length + 0x18, // Type 0x41, 0x02, // Sequence + 0x08, // Length 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token }; @@ -1231,9 +1238,9 @@ TEST_CASE("Store NewConnectionId Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x0b, // Type - 0x08, // Length + 0x18, // Type 0x41, 0x02, // Sequence + 0x08, // Length 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Stateless Reset Token 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, @@ -1252,7 +1259,7 @@ TEST_CASE("Load STOP_SENDING Frame", "[quic]") SECTION("LOAD") { uint8_t buf[] = { - 0x0c, // Type + 0x05, // Type 0x92, 0x34, 0x56, 0x78, // Stream ID 0x00, 0x01, // Error Code }; @@ -1269,7 +1276,7 @@ TEST_CASE("Load STOP_SENDING Frame", "[quic]") SECTION("Bad LOAD") { uint8_t buf[] = { - 0x0c, // Type + 0x05, // Type 0x92, 0x34, 0x56, 0x78, // Stream ID }; std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); @@ -1284,7 +1291,7 @@ TEST_CASE("Store STOP_SENDING Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x0c, // Type + 0x05, // Type 0x92, 0x34, 0x56, 0x78, // Stream ID 0x00, 0x01, // Error Code }; @@ -1301,7 +1308,7 @@ TEST_CASE("Load PATH_CHALLENGE Frame", "[quic]") SECTION("Load") { uint8_t buf[] = { - 0x0e, // Type + 0x1a, // Type 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); @@ -1317,7 +1324,7 @@ TEST_CASE("Load PATH_CHALLENGE Frame", "[quic]") SECTION("Load") { uint8_t buf[] = { - 0x0e, // Type + 0x1a, // Type 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xef, // Data }; std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); @@ -1332,7 +1339,7 @@ TEST_CASE("Store PATH_CHALLENGE Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x0e, // Type + 0x1a, // Type 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; @@ -1354,7 +1361,7 @@ TEST_CASE("Load PATH_RESPONSE Frame", "[quic]") SECTION("Load") { uint8_t buf[] = { - 0x0f, // Type + 0x1b, // Type 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); @@ -1370,7 +1377,7 @@ TEST_CASE("Load PATH_RESPONSE Frame", "[quic]") SECTION("Load") { uint8_t buf[] = { - 0x0f, // Type + 0x1b, // Type 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); @@ -1385,7 +1392,7 @@ TEST_CASE("Store PATH_RESPONSE Frame", "[quic]") size_t len; uint8_t expected[] = { - 0x0f, // Type + 0x1b, // Type 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; @@ -1405,7 +1412,7 @@ TEST_CASE("Store PATH_RESPONSE Frame", "[quic]") TEST_CASE("NEW_TOKEN Frame", "[quic]") { uint8_t raw_new_token_frame[] = { - 0x19, // Type + 0x07, // Type 0x08, // Token Length (i) 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, // Token (*) }; @@ -1453,7 +1460,7 @@ TEST_CASE("NEW_TOKEN Frame", "[quic]") TEST_CASE("RETIRE_CONNECTION_ID Frame", "[quic]") { uint8_t raw_retire_connection_id_frame[] = { - 0x0d, // Type + 0x19, // Type 0x08, // Sequence Number (i) }; size_t raw_retire_connection_id_frame_len = sizeof(raw_retire_connection_id_frame); @@ -1508,11 +1515,11 @@ TEST_CASE("QUICFrameFactory Fast Create Frame", "[quic]") QUICFrameFactory factory; uint8_t buf1[] = { - 0x06, // Type + 0x12, // Type 0x81, 0x02, 0x03, 0x04, // Stream Data }; uint8_t buf2[] = { - 0x06, // Type + 0x12, // Type 0x85, 0x06, 0x07, 0x08, // Stream Data }; std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); @@ -1573,361 +1580,3 @@ TEST_CASE("QUICFrameFactory Create RESET_STREAM with a QUICStreamError", "[quic] CHECK(rst_stream_frame1->stream_id() == 0x1234); CHECK(rst_stream_frame1->final_offset() == 0); } - -// Test for retransmittable frames -TEST_CASE("Retransmit", "[quic][frame][retransmit]") -{ - QUICPacketFactory factory; - MockQUICHandshakeProtocol hs_protocol; - factory.set_hs_protocol(&hs_protocol); - std::vector frames; - QUICPacketUPtr packet = factory.create_protected_packet({reinterpret_cast("\x01\x02\x03\x04"), 4}, 0, {nullptr}, - 0, true, false, frames); - SECTION("STREAM frame split") - { - size_t len; - uint8_t buf1[] = { - 0x16, // 0b00010OLF (OLF=110) - 0x01, // Stream ID - 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset - 0x0a, // Data Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data - 0x11, 0x22, 0x33, 0x44, 0x55, - }; - - uint8_t expected[]{ - 0x16, // 0b00010OLF (OLF=110) - 0x01, // Stream ID - 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, // Offset - 0x05, // Data Length - 0x11, 0x22, 0x33, 0x44, 0x55, // Stream Data - }; - - uint8_t expected2[]{ - 0x16, // 0b00010OLF (OLF=110) - 0x01, // Stream ID - 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset - 0x05, // Data Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data - }; - - uint8_t buffer[128]; - - QUICFrameUPtr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - auto frame = QUICFrameFactory::create_retransmission_frame(std::move(frame1), *packet); - auto frame2 = frame->split(16); - - CHECK(frame2->type() == QUICFrameType::STREAM); - CHECK(frame2->store(buffer, &len, 128)); - CHECK(memcmp(buffer, expected, sizeof(expected)) == 0); - CHECK(frame->store(buffer, &len, 128)); - CHECK(memcmp(buffer, expected2, sizeof(expected2)) == 0); - - QUICFrameDeleter::delete_stream_frame(frame2); - } - - SECTION("STREAM frame") - { - uint8_t frame_buf[] = { - 0x12, // Type, 0b00010OLF (OLF=010) - 0x01, // Stream ID - 0x05, // Data Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 8); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("CRYPTO frame") - { - uint8_t frame_buf[] = { - 0x18, // Type - 0x01, // Offset - 0x05, // Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Crypto Data - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 8); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("RESET_STREAM frame") - { - uint8_t frame_buf[] = { - 0x01, // Type - 0x92, 0x34, 0x56, 0x78, // Stream ID - 0x00, 0x01, // Error Code - 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 15); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("CONNECTION_CLOSE frame") - { - uint8_t frame_buf[] = { - 0x02, // Type - 0x00, 0x0A, // Error Code - 0x00, // Frame Type - 0x05, // Reason Phrase Length - 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == sizeof(frame_buf)); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("APPLICATION_CLOSE frame") - { - uint8_t frame_buf[] = { - 0x03, // Type - 0x00, 0x01, // Error Code - 0x05, // Reason Phrase Length - 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 9); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("MAX_DATA frame") - { - uint8_t frame_buf[] = { - 0x04, // Type - 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 9); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("MAX_STREAM_DATA frame") - { - uint8_t frame_buf[] = { - 0x05, // Type - 0x81, 0x02, 0x03, 0x04, // Stream ID - 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 13); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("MAX_STREAMS frame") - { - uint8_t frame_buf[] = { - 0x06, // Type - 0x81, 0x02, 0x03, 0x04, // Stream ID - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 5); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("PING frame") - { - uint8_t frame_buf[] = { - 0x07, // Type - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 1); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("BLOCKED frame") - { - uint8_t frame_buf[] = { - 0x08, // Type - 0x07, // Offset - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 2); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("STREAM_DATA_BLOCKED frame") - { - uint8_t frame_buf[] = { - 0x09, // Type - 0x81, 0x02, 0x03, 0x04, // Stream ID - 0x07, // Offset - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 6); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("STREAMS_BLOCKED frame") - { - uint8_t frame_buf[] = { - 0x0a, // Type - 0x41, 0x02, // Stream ID - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 3); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("NEW_CONNECTION_ID frame") - { - uint8_t frame_buf[] = { - 0x0b, // Type - 0x08, // Length - 0x41, 0x02, // Sequence - 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID - 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token - 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 28); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("STOP_SENDING frame") - { - uint8_t frame_buf[] = { - 0x0c, // Type - 0x92, 0x34, 0x56, 0x78, // Stream ID - 0x00, 0x01, // Error Code - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 7); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("PATH_CHALLENGE frame") - { - uint8_t frame_buf[] = { - 0x0e, // Type - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 9); - CHECK(memcmp(buf, frame_buf, len) == 0); - } - - SECTION("PATH_RESPONSE frame") - { - uint8_t frame_buf[] = { - 0x0f, // Type - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data - }; - - QUICFrameUPtr frame = QUICFrameFactory::create(frame_buf, sizeof(frame_buf)); - frame = QUICFrameFactory::create_retransmission_frame(std::move(frame), *packet); - - uint8_t buf[32] = {0}; - size_t len; - frame->store(buf, &len, 32); - - CHECK(len == 9); - CHECK(memcmp(buf, frame_buf, len) == 0); - } -} From 1f17391f3364e0df1e3054ddd03c09cfec02459b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Feb 2019 16:43:04 +0900 Subject: [PATCH 1094/1313] Fix tests for QUICStreamManager --- .../net/quic/test/test_QUICStreamManager.cc | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 9470df94427..b4138874ec3 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -44,9 +44,9 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") 0x00, 0x00, 0x00, 0x00, // initial version 0x00, // size of supported versions 0x00, 0x06, // size of parameters - 0x00, 0x02, // parameter id - initial_max_streams_bidi + 0x00, 0x08, // parameter id - initial_max_streams_bidi 0x00, 0x02, // length of value - 0x00, 0x10 // value + 0x40, 0x10 // value }; std::shared_ptr local_tp = std::make_shared(local_tp_buf, sizeof(local_tp_buf)); @@ -54,9 +54,9 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") uint8_t remote_tp_buf[] = { 0x00, 0x00, 0x00, 0x00, // initial version 0x00, 0x06, // size of parameters - 0x00, 0x02, // parameter id - initial_max_streams_bidi + 0x00, 0x08, // parameter id - initial_max_streams_bidi 0x00, 0x02, // length of value - 0x00, 0x10 // value + 0x40, 0x10 // value }; std::shared_ptr remote_tp = std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); @@ -94,7 +94,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") CHECK(sm.stream_count() == 5); // Set local maximum stream id - sm.set_max_streams_bidi(100); + sm.set_max_streams_bidi(5); std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_data_blocked_frame(0x18, 0); sm.handle_frame(level, *stream_blocked_frame_x); CHECK(sm.stream_count() == 5); @@ -141,12 +141,12 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") 0x00, 0x00, 0x00, 0x00, // initial version 0x00, // size of supported versions 0x00, 0x0e, // size of parameters - 0x00, 0x02, // parameter id - initial_max_streams_bidi + 0x00, 0x08, // parameter id - initial_max_streams_bidi 0x00, 0x02, // length of value - 0x00, 0x10, // value - 0x00, 0x00, // parameter id - initial_max_stream_data_bidi_local + 0x40, 0x10, // value + 0x00, 0x05, // parameter id - initial_max_stream_data_bidi_local 0x00, 0x04, // length of value - 0xff, 0xff, 0xff, 0xff // value + 0xbf, 0xff, 0xff, 0xff // value }; std::shared_ptr local_tp = std::make_shared(local_tp_buf, sizeof(local_tp_buf)); @@ -154,12 +154,12 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") uint8_t remote_tp_buf[] = { 0x00, 0x00, 0x00, 0x00, // initial version 0x00, 0x0e, // size of parameters - 0x00, 0x02, // parameter id - initial_max_streams_bidi + 0x00, 0x08, // parameter id - initial_max_streams_bidi 0x00, 0x02, // length of value - 0x00, 0x10, // value - 0x00, 0x0a, // parameter id - initial_max_stream_data_bidi_remote + 0x40, 0x10, // value + 0x00, 0x06, // parameter id - initial_max_stream_data_bidi_remote 0x00, 0x04, // length of value - 0xff, 0xff, 0xff, 0xff // value + 0xbf, 0xff, 0xff, 0xff // value }; std::shared_ptr remote_tp = std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); @@ -198,9 +198,9 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") 0x00, 0x00, 0x00, 0x00, // initial version 0x00, // size of supported versions 0x00, 0x06, // size of parameters - 0x00, 0x02, // parameter id - initial_max_streams_bidi + 0x00, 0x08, // parameter id - initial_max_streams_bidi 0x00, 0x02, // length of value - 0x00, 0x10 // value + 0x40, 0x10 // value }; std::shared_ptr local_tp = std::make_shared(local_tp_buf, sizeof(local_tp_buf)); @@ -208,9 +208,9 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") uint8_t remote_tp_buf[] = { 0x00, 0x00, 0x00, 0x00, // initial version 0x00, 0x06, // size of parameters - 0x00, 0x02, // parameter id - initial_max_streams_bidi + 0x00, 0x08, // parameter id - initial_max_streams_bidi 0x00, 0x02, // length of value - 0x00, 0x10 // value + 0x40, 0x10 // value }; std::shared_ptr remote_tp = std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); From 59014a46f0f07c0d60a16fa8bb1144e40c61f882 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Feb 2019 10:30:07 +0900 Subject: [PATCH 1095/1313] HTTP/3: load settings from records.config Below configs are added - proxy.config.http3.header_table_size - proxy.config.http3.max_header_list_size - proxy.config.http3.qpack_blocked_streams - proxy.config.http3.num_placeholders --- mgmt/RecordsConfig.cc | 15 +++++ proxy/http3/Http3App.cc | 28 ++++++++- proxy/http3/Http3Config.cc | 93 ++++++++++++++++++++++++++++ proxy/http3/Http3Config.h | 60 ++++++++++++++++++ proxy/http3/Makefile.am | 3 +- src/traffic_server/traffic_server.cc | 4 ++ 6 files changed, 199 insertions(+), 4 deletions(-) create mode 100644 proxy/http3/Http3Config.cc create mode 100644 proxy/http3/Http3Config.h diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 624f44dc9fc..8e0cdce53e7 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1332,6 +1332,21 @@ static const RecordElement RecordsConfig[] = {RECT_CONFIG, "proxy.config.http2.zombie_debug_timeout_in", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} , + //############ + //# + //# HTTP/3 global configuration. + //# + //############ + {RECT_CONFIG, "proxy.config.http3.header_table_size", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.http3.max_header_list_size", RECD_INT, "4096", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.http3.qpack_blocked_streams", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.http3.num_placeholders", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} + , + + //############ //# //# QUIC global configuration. diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 0718862aea0..73699082577 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -26,6 +26,7 @@ #include "P_Net.h" #include "P_VConnection.h" +#include "Http3Config.h" #include "Http3DebugNames.h" #include "Http3ClientSession.h" #include "Http3ClientTransaction.h" @@ -33,6 +34,12 @@ static constexpr char tag[] = "http3"; static constexpr char tag_v[] = "v_http3"; +// Default values of settings defined by specs. +static constexpr uint32_t HTTP3_DEFAULT_HEADER_TABLE_SIZE = 0; +static constexpr uint32_t HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE = UINT32_MAX; +static constexpr uint32_t HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS = 0; +static constexpr uint32_t HTTP3_DEFAULT_NUM_PLACEHOLDERS = 0; + Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QUICApplication(client_vc) { this->_client_session = new Http3ClientSession(client_vc); @@ -303,7 +310,6 @@ Http3SettingsHandler::handle_frame(std::shared_ptr frame) // // SETTINGS frame framer // -// TODO: load values from config Http3FrameUPtr Http3SettingsFramer::generate_frame(uint16_t max_size) { @@ -313,10 +319,26 @@ Http3SettingsFramer::generate_frame(uint16_t max_size) this->_is_sent = true; + Http3Config::scoped_config params; + Http3SettingsFrame *frame = http3SettingsFrameAllocator.alloc(); new (frame) Http3SettingsFrame(); - frame->set(Http3SettingsId::HEADER_TABLE_SIZE, 0x0); - frame->set(Http3SettingsId::NUM_PLACEHOLDERS, 100); + + if (params->header_table_size() != HTTP3_DEFAULT_HEADER_TABLE_SIZE) { + frame->set(Http3SettingsId::HEADER_TABLE_SIZE, params->header_table_size()); + } + + if (params->max_header_list_size() != HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE) { + frame->set(Http3SettingsId::NUM_PLACEHOLDERS, params->max_header_list_size()); + } + + if (params->qpack_blocked_streams() != HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS) { + frame->set(Http3SettingsId::QPACK_BLOCKED_STREAMS, params->qpack_blocked_streams()); + } + + if (params->num_placeholders() != HTTP3_DEFAULT_NUM_PLACEHOLDERS) { + frame->set(Http3SettingsId::NUM_PLACEHOLDERS, params->num_placeholders()); + } return Http3SettingsFrameUPtr(frame, &Http3FrameDeleter::delete_settings_frame); } diff --git a/proxy/http3/Http3Config.cc b/proxy/http3/Http3Config.cc new file mode 100644 index 00000000000..87c33f7b426 --- /dev/null +++ b/proxy/http3/Http3Config.cc @@ -0,0 +1,93 @@ +/** @file + * + * HTTP/3 Config + * + * @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 "Http3Config.h" + +int Http3Config::_config_id = 0; + +// +// Http3ConfigParams +// +void +Http3ConfigParams::initialize() +{ + REC_EstablishStaticConfigInt32U(this->_header_table_size, "proxy.config.http3.header_table_size"); + REC_EstablishStaticConfigInt32U(this->_max_header_list_size, "proxy.config.http3.max_header_list_size"); + REC_EstablishStaticConfigInt32U(this->_qpack_blocked_streams, "proxy.config.http3.qpack_blocked_streams"); + REC_EstablishStaticConfigInt32U(this->_num_placeholders, "proxy.config.http3.num_placeholders"); +} + +uint32_t +Http3ConfigParams::header_table_size() const +{ + return this->_header_table_size; +} + +uint32_t +Http3ConfigParams::max_header_list_size() const +{ + return this->_max_header_list_size; +} + +uint32_t +Http3ConfigParams::qpack_blocked_streams() const +{ + return this->_qpack_blocked_streams; +} + +uint32_t +Http3ConfigParams::num_placeholders() const +{ + return this->_num_placeholders; +} + +// +// Http3Config +// +void +Http3Config::startup() +{ + reconfigure(); +} + +void +Http3Config::reconfigure() +{ + Http3ConfigParams *params; + params = new Http3ConfigParams; + // re-read configuration + params->initialize(); + Http3Config::_config_id = configProcessor.set(Http3Config::_config_id, params); +} + +Http3ConfigParams * +Http3Config::acquire() +{ + return static_cast(configProcessor.get(Http3Config::_config_id)); +} + +void +Http3Config::release(Http3ConfigParams *params) +{ + configProcessor.release(Http3Config::_config_id, params); +} diff --git a/proxy/http3/Http3Config.h b/proxy/http3/Http3Config.h new file mode 100644 index 00000000000..9694765549c --- /dev/null +++ b/proxy/http3/Http3Config.h @@ -0,0 +1,60 @@ +/** @file + * + * HTTP/3 Config + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "ProxyConfig.h" + +class Http3ConfigParams : public ConfigInfo +{ +public: + Http3ConfigParams(){}; + ~Http3ConfigParams(){}; + + void initialize(); + + uint32_t header_table_size() const; + uint32_t max_header_list_size() const; + uint32_t qpack_blocked_streams() const; + uint32_t num_placeholders() const; + +private: + uint32_t _header_table_size = 0; + uint32_t _max_header_list_size = 0; + uint32_t _qpack_blocked_streams = 0; + uint32_t _num_placeholders = 0; +}; + +class Http3Config +{ +public: + static void startup(); + static void reconfigure(); + static Http3ConfigParams *acquire(); + static void release(Http3ConfigParams *params); + + using scoped_config = ConfigProcessor::scoped_config; + +private: + static int _config_id; +}; diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index 5fd1c5045c5..50e51b8d898 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -1,5 +1,5 @@ # -# Makefile.am for HTTP over QUIC +# Makefile.am for HTTP/3 # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file @@ -36,6 +36,7 @@ noinst_LIBRARIES = libhttp3.a libhttp3_a_SOURCES = \ Http3.cc \ + Http3Config.cc \ Http3App.cc \ Http3Types.cc \ Http3SessionAccept.cc \ diff --git a/src/traffic_server/traffic_server.cc b/src/traffic_server/traffic_server.cc index 478469a41db..477fa796c4b 100644 --- a/src/traffic_server/traffic_server.cc +++ b/src/traffic_server/traffic_server.cc @@ -99,6 +99,7 @@ extern "C" int plock(int); #if TS_USE_QUIC == 1 #include "Http3.h" +#include "Http3Config.h" #endif #include "tscore/ink_cap.h" @@ -1741,6 +1742,9 @@ main(int /* argc ATS_UNUSED */, const char **argv) // We want to initialize Machine as early as possible because it // has other dependencies. Hopefully not in prep_HttpProxyServer(). HttpConfig::startup(); +#if TS_USE_QUIC == 1 + Http3Config::startup(); +#endif /* Set up the machine with the outbound address if that's set, or the inbound address if set, otherwise let it default. From bdf4de605bfad412ea0301132d5632bb447d3c9f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 5 Feb 2019 12:15:42 +0900 Subject: [PATCH 1096/1313] Fix tests for QUICPacket --- iocore/net/quic/test/test_QUICPacket.cc | 55 +++++++------------------ 1 file changed, 14 insertions(+), 41 deletions(-) diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 143e96f756b..5edc50dd81e 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -30,7 +30,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") SECTION("Long Header (load) Version Negotiation Packet") { const uint8_t input[] = { - 0x80, // Long header, Type: NONE + 0xc0, // Long header, Type: NONE 0x00, 0x00, 0x00, 0x00, // Version 0x55, // DCIL/SCIL 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID @@ -55,14 +55,14 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") SECTION("Long Header (load) INITIAL Packet") { const uint8_t input[] = { - 0xFF, // Long header, Type: INITIAL + 0xc3, // Long header, Type: INITIAL 0x11, 0x22, 0x33, 0x44, // Version 0x55, // DCIL/SCIL 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID 0x00, // Token Length (i), Token (*) 0x02, // Payload length - 0xC1, 0x23, 0x45, 0x67, // Packet number + 0x01, 0x23, 0x45, 0x67, // Packet number 0xff, 0xff, // Payload (dummy) }; ats_unique_buf uinput = ats_unique_malloc(sizeof(input)); @@ -83,12 +83,11 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") SECTION("Long Header (load) RETRY Packet") { const uint8_t input[] = { - 0xFE, // Long header, Type: RETRY + 0xf5, // Long header, Type: RETRY 0x11, 0x22, 0x33, 0x44, // Version 0x55, // DCIL/SCIL 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID - 0x05, // ODCIL 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, // Original Destination Connection ID 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Retry Token 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, @@ -121,14 +120,14 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") size_t len = 0; const uint8_t expected[] = { - 0xFF, // Long header, Type: INITIAL + 0xc3, // Long header, Type: INITIAL 0x11, 0x22, 0x33, 0x44, // Version 0x55, // DCIL/SCIL 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID 0x00, // Token Length (i), Token (*) 0x19, // Length (Not 0x09 because it will have 16 bytes of AEAD tag) - 0xC1, 0x23, 0x45, 0x67, // Packet number + 0x01, 0x23, 0x45, 0x67, // Packet number 0x11, 0x22, 0x33, 0x44, 0x55, // Payload (dummy) }; ats_unique_buf payload = ats_unique_malloc(5); @@ -159,18 +158,17 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") size_t len = 0; const uint8_t expected[] = { - 0xFE, // Long header, Type: RETRY + 0xf5, // Long header, Type: RETRY 0x11, 0x22, 0x33, 0x44, // Version 0x55, // DCIL/SCIL 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Destination Connection ID 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Source Connection ID - 0x05, // ODCIL 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, // Original Destination Connection ID 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Retry Token 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, }; ats_unique_buf payload = ats_unique_malloc(16); - memcpy(payload.get(), expected + 31, 16); + memcpy(payload.get(), expected + 30, 16); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, QUICKeyPhase::INITIAL, 0x11223344, @@ -210,11 +208,11 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") SECTION("Short Header (load)") { const uint8_t input[] = { - 0x30, // Short header with (K=0) + 0x43, // Short header with (K=0) 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Destination Connection ID (144) 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, // 0x10, 0x11, // - 0xC1, 0x23, 0x45, 0x67, // Packet number + 0x01, 0x23, 0x45, 0x67, // Packet number 0xff, 0xff, // Payload (dummy) }; ats_unique_buf uinput = ats_unique_malloc(sizeof(input)); @@ -235,11 +233,11 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") size_t len = 0; const uint8_t expected[] = { - 0x30, // Short header with (K=0) + 0x43, // Short header with (K=0) 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Destination Connection ID (144) 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, // 0x10, 0x11, // - 0xC1, 0x23, 0x45, 0x67, // Packet number + 0x01, 0x23, 0x45, 0x67, // Packet number 0x11, 0x22, 0x33, 0x44, 0x55, // Protected Payload }; size_t payload_len = 5; @@ -267,12 +265,9 @@ TEST_CASE("QUICPacketHeader - Short", "[quic]") TEST_CASE("Encoded Packet Number Length", "[quic]") { - QUICPacketNumber base = 0x6afa2f; + QUICPacketNumber base = 0xabe8bc; - // To be clarify: Is "As a result..." sentence missing "twice" ? - // - // CHECK(QUICPacket::calc_packet_number_len(0x6b2d79, base) == 2); - CHECK(QUICPacket::calc_packet_number_len(0x6bc107, base) == 4); + CHECK(QUICPacket::calc_packet_number_len(0xace8fe, base) == 3); } TEST_CASE("Encoding Packet Number", "[quic]") @@ -294,25 +289,3 @@ TEST_CASE("Decoding Packet Number 1", "[quic]") QUICPacket::decode_packet_number(dst, src, len, base); CHECK(dst == 0xaa8309b3); } - -TEST_CASE("Decoding Packet Number 2", "[quic]") -{ - QUICPacketNumber dst = 0; - QUICPacketNumber src = 0xf1; - size_t len = 1; - QUICPacketNumber base = 0x18bf54f0; - - QUICPacket::decode_packet_number(dst, src, len, base); - CHECK(dst == 0x18bf5571); -} - -TEST_CASE("Decoding Packet Number 3", "[quic]") -{ - QUICPacketNumber dst = 0; - QUICPacketNumber src = 0x5694; - size_t len = 2; - QUICPacketNumber base = 0x44D35695; - - QUICPacket::decode_packet_number(dst, src, len, base); - CHECK(dst == 0x44d39694); -} From 2bebf6c7338e28c6ef0f8c1cdb3fb6c4e57fcc26 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sat, 2 Feb 2019 09:59:30 +0800 Subject: [PATCH 1097/1313] QUIC: Limit the sending after 3 packets with unavlidated path --- iocore/net/P_QUICNetVConnection.h | 5 +- iocore/net/QUICNetVConnection.cc | 31 +++++---- iocore/net/quic/Makefile.am | 13 +++- iocore/net/quic/QUICAddrVerifyState.cc | 66 +++++++++++++++++++ iocore/net/quic/QUICAddrVerifyState.h | 43 ++++++++++++ .../net/quic/test/test_QUICAddrVerifyState.cc | 61 +++++++++++++++++ 6 files changed, 199 insertions(+), 20 deletions(-) create mode 100644 iocore/net/quic/QUICAddrVerifyState.cc create mode 100644 iocore/net/quic/QUICAddrVerifyState.h create mode 100644 iocore/net/quic/test/test_QUICAddrVerifyState.cc diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 38b9284d665..8890ca91f4b 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -59,6 +59,7 @@ #include "quic/QUICPathValidator.h" #include "quic/QUICApplicationMap.h" #include "quic/QUICPacketReceiveQueue.h" +#include "quic/QUICAddrVerifyState.h" // These are included here because older OpenQUIC libraries don't have them. // Don't copy these defines, or use their values directly, they are merely @@ -363,7 +364,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _update_peer_cid(const QUICConnectionId &new_cid); void _update_local_cid(const QUICConnectionId &new_cid); void _rerandomize_original_cid(); - bool _is_src_addr_verified(); QUICHandshakeProtocol *_setup_handshake_protocol(SSL_CTX *ctx); @@ -379,9 +379,10 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub uint64_t _stream_frames_sent = 0; // TODO: Source addresses verification through an address validation token - bool _src_addr_verified = false; bool _has_ack_only_packet_out = false; + QUICAddrVerifyState _verfied_state; + // QUICFrameGenerator void _on_frame_lost(QUICFrameInformationUPtr &info) override; std::vector diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 9872d5c2e50..453002f1977 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -69,8 +69,6 @@ static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(2); static constexpr uint32_t PACKET_PER_EVENT = 256; static constexpr uint32_t MAX_CONSECUTIVE_STREAMS = 8; //< Interrupt sending STREAM frames to send ACK frame -static constexpr uint32_t MAX_PACKETS_WITHOUT_SRC_ADDR_VARIDATION = 3; - static constexpr uint32_t STATE_CLOSING_MAX_SEND_PKT_NUM = 8; // Max number of sending packets which contain a closing frame. static constexpr uint32_t STATE_CLOSING_MAX_RECV_PKT_WIND = 1 << STATE_CLOSING_MAX_SEND_PKT_NUM; @@ -1052,8 +1050,8 @@ QUICNetVConnection::_state_handshake_process_handshake_packet(QUICPacketUPtr pac { // Source address is verified by receiving any message from the client encrypted using the // Handshake keys. - if (this->netvc_context == NET_VCONNECTION_IN && !this->_src_addr_verified) { - this->_src_addr_verified = true; + if (this->netvc_context == NET_VCONNECTION_IN && !this->_verfied_state.is_verified()) { + this->_verfied_state.set_addr_verifed(); } return this->_recv_and_ack(*packet); } @@ -1226,14 +1224,14 @@ QUICNetVConnection::_state_common_send_packet() continue; } - if (this->netvc_context == NET_VCONNECTION_IN && !this->_is_src_addr_verified() && - this->_handshake_packets_sent >= MAX_PACKETS_WITHOUT_SRC_ADDR_VARIDATION) { - error = 1; - break; + uint32_t max_packet_size = udp_payload_len - written; + if (this->netvc_context == NET_VCONNECTION_IN && !this->_verfied_state.is_verified()) { + uint32_t windows = this->_verfied_state.windows(); + QUICConDebug("send to unverified window: %u", windows); + max_packet_size = std::min(max_packet_size, windows); } - uint32_t max_packet_size = udp_payload_len - written; - QUICPacketUPtr packet = this->_packetize_frames(level, max_packet_size); + QUICPacketUPtr packet = this->_packetize_frames(level, max_packet_size); if (packet) { if (this->netvc_context == NET_VCONNECTION_IN && @@ -1241,6 +1239,10 @@ QUICNetVConnection::_state_common_send_packet() ++this->_handshake_packets_sent; } + if (this->netvc_context == NET_VCONNECTION_IN && !this->_verfied_state.is_verified()) { + this->_verfied_state.consume(packet->size()); + } + // TODO: do not write two QUIC Short Header Packets uint8_t *buf = reinterpret_cast(udp_payload->end()); size_t len = 0; @@ -1688,6 +1690,9 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) } this->_last_received_packet_type = packet->type(); + if (!this->_verfied_state.is_verified()) { + this->_verfied_state.fill(packet->size()); + } } // Debug prints @@ -2083,12 +2088,6 @@ QUICNetVConnection::_rerandomize_original_cid() } } -bool -QUICNetVConnection::_is_src_addr_verified() -{ - return this->_src_addr_verified; -} - QUICHandshakeProtocol * QUICNetVConnection::_setup_handshake_protocol(SSL_CTX *ctx) { diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index ba7568318d6..2b122390624 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -81,7 +81,8 @@ libquic_a_SOURCES = \ QUICPathValidator.cc \ QUICPinger.cc \ QUICFrameGenerator.cc \ - QUICFrameRetransmitter.cc + QUICFrameRetransmitter.cc \ + QUICAddrVerifyState.cc # # Check Programs @@ -107,7 +108,8 @@ check_PROGRAMS = \ test_QUICType \ test_QUICTypeUtil \ test_QUICVersionNegotiator \ - test_QUICFrameRetransmitter + test_QUICFrameRetransmitter \ + test_QUICAddrVerifyState TESTS = $(check_PROGRAMS) @@ -288,6 +290,13 @@ test_QUICFrameRetransmitter_SOURCES = \ $(test_main_SOURCES) \ ./test/test_QUICFrameRetransmitter.cc +test_QUICAddrVerifyState_CPPFLAGS = $(test_CPPFLAGS) +test_QUICAddrVerifyState_LDFLAGS = @AM_LDFLAGS@ +test_QUICAddrVerifyState_LDADD = $(test_LDADD) +test_QUICAddrVerifyState_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_QUICAddrVerifyState.cc + # # clang-tidy # diff --git a/iocore/net/quic/QUICAddrVerifyState.cc b/iocore/net/quic/QUICAddrVerifyState.cc new file mode 100644 index 00000000000..67281b592d6 --- /dev/null +++ b/iocore/net/quic/QUICAddrVerifyState.cc @@ -0,0 +1,66 @@ +/** @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 "QUICAddrVerifyState.h" + +void +QUICAddrVerifyState::fill(uint32_t windows) +{ + uint64_t tmp = this->_windows; + if (tmp + windows * 3 > UINT32_MAX) { + // overflow + this->_windows = UINT32_MAX; + return; + } + + this->_windows += windows * 3; +} + +void +QUICAddrVerifyState::consume(uint32_t windows) +{ + if (this->_windows <= windows) { + this->_windows = 0; + return; + } + + this->_windows -= windows; +} + +uint32_t +QUICAddrVerifyState::windows() +{ + return this->_windows; +} + +void +QUICAddrVerifyState::set_addr_verifed() +{ + this->_src_addr_verified = true; +} + +bool +QUICAddrVerifyState::is_verified() const +{ + return this->_src_addr_verified; +} diff --git a/iocore/net/quic/QUICAddrVerifyState.h b/iocore/net/quic/QUICAddrVerifyState.h new file mode 100644 index 00000000000..d6d6c7c4e42 --- /dev/null +++ b/iocore/net/quic/QUICAddrVerifyState.h @@ -0,0 +1,43 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include + +class QUICAddrVerifyState +{ +public: + QUICAddrVerifyState(uint8_t packets, uint32_t windows) : _windows(windows) {} + QUICAddrVerifyState() = default; + + void fill(uint32_t windows); + void consume(uint32_t windows); + void set_addr_verifed(); + uint32_t windows(); + bool is_verified() const; + +private: + bool _src_addr_verified = false; + uint32_t _windows = 0; +}; diff --git a/iocore/net/quic/test/test_QUICAddrVerifyState.cc b/iocore/net/quic/test/test_QUICAddrVerifyState.cc new file mode 100644 index 00000000000..a90135c0bd6 --- /dev/null +++ b/iocore/net/quic/test/test_QUICAddrVerifyState.cc @@ -0,0 +1,61 @@ +/** @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 "catch.hpp" + +#include "P_QUICNetVConnection.h" +#include + +TEST_CASE("QUICAddrVerifyState", "[quic]") +{ + QUICAddrVerifyState state; + + // without consuming + CHECK(state.windows() == 0); + state.fill(10240); + CHECK(state.windows() == 10240 * 3); + + // consume + CHECK(state.windows() == 10240 * 3); + state.consume(10240); + CHECK(state.windows() == 10240 * 2); + state.consume(10240); + CHECK(state.windows() == 10240); + state.consume(10240); + CHECK(state.windows() == 0); + + // fill + state.fill(1); + CHECK(state.windows() == 3); + state.consume(1); + CHECK(state.windows() == 2); + state.consume(1); + CHECK(state.windows() == 1); + state.consume(1); + CHECK(state.windows() == 0); + + // fill overflow + state.fill(UINT32_MAX); + state.fill(2); + CHECK(state.windows() == UINT32_MAX); +} From e0f07c411965567ee476d7fbe792c98e2d6cc128 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 5 Feb 2019 14:13:11 +0900 Subject: [PATCH 1098/1313] Fix tests for QUICPacketHeaderProtector --- iocore/net/quic/test/test_QUICPacketHeaderProtector.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc index 818a64fdd58..2c2e088dbcb 100644 --- a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc @@ -60,11 +60,12 @@ TEST_CASE("QUICPacketHeaderProtector") SECTION("Long header", "[quic]") { uint8_t original[] = { - 0xC0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0xC3, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, }; - uint8_t tmp[48]; + uint8_t tmp[64]; memcpy(tmp, original, sizeof(tmp)); QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); From 90e1bca570574ef1d2179b8669e5fe90ce29a777 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Feb 2019 14:13:47 +0900 Subject: [PATCH 1099/1313] Check decoded header list size on QPACK --- proxy/http3/Http3.cc | 6 +++ proxy/http3/Http3.h | 5 +++ proxy/http3/Http3App.cc | 31 ++++++++++----- proxy/http3/Http3App.h | 6 ++- proxy/http3/Http3ClientSession.cc | 4 +- proxy/http3/QPACK.cc | 65 ++++++++++++++++++++++++------- proxy/http3/QPACK.h | 29 ++++++++------ 7 files changed, 109 insertions(+), 37 deletions(-) diff --git a/proxy/http3/Http3.cc b/proxy/http3/Http3.cc index 74f811b2549..ce885585070 100644 --- a/proxy/http3/Http3.cc +++ b/proxy/http3/Http3.cc @@ -23,6 +23,12 @@ #include "Http3.h" +// Default values of settings defined by specs (draft-17) +const uint32_t HTTP3_DEFAULT_HEADER_TABLE_SIZE = 0; +const uint32_t HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE = UINT32_MAX; +const uint32_t HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS = 0; +const uint32_t HTTP3_DEFAULT_NUM_PLACEHOLDERS = 0; + RecRawStatBlock *http3_rsb; void diff --git a/proxy/http3/Http3.h b/proxy/http3/Http3.h index b3da732d105..f390e06b4bd 100644 --- a/proxy/http3/Http3.h +++ b/proxy/http3/Http3.h @@ -27,6 +27,11 @@ #include "records/I_RecDefs.h" #include "records/I_RecProcess.h" +extern const uint32_t HTTP3_DEFAULT_HEADER_TABLE_SIZE; +extern const uint32_t HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE; +extern const uint32_t HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS; +extern const uint32_t HTTP3_DEFAULT_NUM_PLACEHOLDERS; + extern RecRawStatBlock *http3_rsb; // Container for statistics. class Http3 diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 73699082577..e4bde933fd4 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -34,12 +34,6 @@ static constexpr char tag[] = "http3"; static constexpr char tag_v[] = "v_http3"; -// Default values of settings defined by specs. -static constexpr uint32_t HTTP3_DEFAULT_HEADER_TABLE_SIZE = 0; -static constexpr uint32_t HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE = UINT32_MAX; -static constexpr uint32_t HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS = 0; -static constexpr uint32_t HTTP3_DEFAULT_NUM_PLACEHOLDERS = 0; - Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QUICApplication(client_vc) { this->_client_session = new Http3ClientSession(client_vc); @@ -48,7 +42,7 @@ Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QU this->_qc->stream_manager()->set_default_application(this); - this->_settings_handler = new Http3SettingsHandler(); + this->_settings_handler = new Http3SettingsHandler(this->_client_session); this->_control_stream_dispatcher.add_handler(this->_settings_handler); this->_settings_framer = new Http3SettingsFramer(); @@ -294,13 +288,32 @@ Http3SettingsHandler::handle_frame(std::shared_ptr frame) return Http3ErrorUPtr(new Http3NoError()); } + // TODO: Add length check: the maximum number of values are 2^62 - 1, but some fields have shorter maximum than it. + if (settings_frame->contains(Http3SettingsId::HEADER_TABLE_SIZE)) { + uint64_t header_table_size = settings_frame->get(Http3SettingsId::HEADER_TABLE_SIZE); + this->_session->remote_qpack()->update_max_table_size(header_table_size); + + Debug("http3", "SETTINGS_HEADER_TABLE_SIZE: %" PRId64, header_table_size); + } + if (settings_frame->contains(Http3SettingsId::MAX_HEADER_LIST_SIZE)) { - uint64_t header_list_size = settings_frame->get(Http3SettingsId::MAX_HEADER_LIST_SIZE); - Debug("http3", "SETTINGS_MAX_HEADER_LIST_SIZE: %" PRId64, header_list_size); + uint64_t max_header_list_size = settings_frame->get(Http3SettingsId::MAX_HEADER_LIST_SIZE); + this->_session->remote_qpack()->update_max_header_list_size(max_header_list_size); + + Debug("http3", "SETTINGS_MAX_HEADER_LIST_SIZE: %" PRId64, max_header_list_size); + } + + if (settings_frame->contains(Http3SettingsId::QPACK_BLOCKED_STREAMS)) { + uint64_t qpack_blocked_streams = settings_frame->get(Http3SettingsId::QPACK_BLOCKED_STREAMS); + this->_session->remote_qpack()->update_max_blocking_streams(qpack_blocked_streams); + + Debug("http3", "SETTINGS_QPACK_BLOCKED_STREAMS: %" PRId64, qpack_blocked_streams); } if (settings_frame->contains(Http3SettingsId::NUM_PLACEHOLDERS)) { uint64_t num_placeholders = settings_frame->get(Http3SettingsId::NUM_PLACEHOLDERS); + // TODO: update settings for priority tree + Debug("http3", "SETTINGS_NUM_PLACEHOLDERS: %" PRId64, num_placeholders); } diff --git a/proxy/http3/Http3App.h b/proxy/http3/Http3App.h index 49e0e07c18e..959ad2e037f 100644 --- a/proxy/http3/Http3App.h +++ b/proxy/http3/Http3App.h @@ -77,11 +77,15 @@ class Http3App : public QUICApplication class Http3SettingsHandler : public Http3FrameHandler { public: - Http3SettingsHandler(){}; + Http3SettingsHandler(Http3ClientSession *session) : _session(session){}; // Http3FrameHandler std::vector interests() override; Http3ErrorUPtr handle_frame(std::shared_ptr frame) override; + +private: + // TODO: clarify Http3ClientSession I/F for Http3SettingsHandler and Http3App + Http3ClientSession *_session = nullptr; }; class Http3SettingsFramer : public Http3FrameGenerator diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3ClientSession.cc index c5c04b237a3..0b8e294ee9b 100644 --- a/proxy/http3/Http3ClientSession.cc +++ b/proxy/http3/Http3ClientSession.cc @@ -25,8 +25,8 @@ Http3ClientSession::Http3ClientSession(NetVConnection *vc) : _client_vc(vc) { - this->_local_qpack = new QPACK(static_cast(vc), 0, 0); - this->_remote_qpack = new QPACK(static_cast(vc), 0, 0); + this->_local_qpack = new QPACK(static_cast(vc)); + this->_remote_qpack = new QPACK(static_cast(vc)); } Http3ClientSession::~Http3ClientSession() diff --git a/proxy/http3/QPACK.cc b/proxy/http3/QPACK.cc index 8193dcb580e..bd8f51dc698 100644 --- a/proxy/http3/QPACK.cc +++ b/proxy/http3/QPACK.cc @@ -132,9 +132,10 @@ const QPACK::Header QPACK::StaticTable::STATIC_HEADER_FIELDS[] = { {"x-frame-options", "deny"}, {"x-frame-options", "sameorigin"}}; -QPACK::QPACK(QUICConnection *qc, uint16_t max_table_size, uint16_t max_blocking_streams) +QPACK::QPACK(QUICConnection *qc, uint32_t max_header_list_size, uint16_t max_table_size, uint16_t max_blocking_streams) : QUICApplication(qc), _dynamic_table(max_table_size), + _max_header_list_size(max_header_list_size), _max_table_size(max_table_size), _max_blocking_streams(max_blocking_streams) { @@ -267,6 +268,24 @@ QPACK::set_decoder_stream(QUICStreamIO *stream_io) this->set_stream(stream_io); } +void +QPACK::update_max_header_list_size(uint32_t max_header_list_size) +{ + this->_max_header_list_size = max_header_list_size; +} + +void +QPACK::update_max_table_size(uint16_t max_table_size) +{ + this->_max_table_size = max_table_size; +} + +void +QPACK::update_max_blocking_streams(uint16_t max_blocking_streams) +{ + this->_max_blocking_streams = max_blocking_streams; +} + int QPACK::_encode_prefix(uint16_t largest_reference, uint16_t base_index, IOBufferBlock *prefix) { @@ -615,7 +634,7 @@ QPACK::_encode_literal_header_field_with_postbase_name_ref(uint16_t index, uint1 } int -QPACK::_decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr) +QPACK::_decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, uint32_t &header_len) { // Read index field int len = 0; @@ -644,9 +663,8 @@ QPACK::_decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size } // Create and attach a header - MIMEField *new_field = hdr.field_create(name, name_len); - new_field->value_set(hdr.m_heap, hdr.m_mime, value, value_len); - hdr.field_attach(new_field); + this->_attach_header(hdr, name, name_len, value, value_len, false); + header_len = name_len + value_len; QPACKDebug("Decoded Indexed Header Field: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index, result.index, name_len, name, value_len, value); @@ -655,7 +673,8 @@ QPACK::_decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size } int -QPACK::_decode_literal_header_field_with_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr) +QPACK::_decode_literal_header_field_with_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, + uint32_t &header_len) { int read_len = 0; @@ -701,6 +720,7 @@ QPACK::_decode_literal_header_field_with_name_ref(int16_t base_index, const uint // Create and attach a header this->_attach_header(hdr, name, name_len, value, value_len, never_index); + header_len = name_len + value_len; QPACKDebug("Decoded Literal Header Field With Name Ref: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index, result.index, name_len, name, static_cast(value_len), value); @@ -709,7 +729,7 @@ QPACK::_decode_literal_header_field_with_name_ref(int16_t base_index, const uint } int -QPACK::_decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t buf_len, HTTPHdr &hdr) +QPACK::_decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, uint32_t &header_len) { int read_len = 0; @@ -738,6 +758,7 @@ QPACK::_decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t // Create and attach a header this->_attach_header(hdr, name, name_len, value, value_len, never_index); + header_len = name_len + value_len; QPACKDebug("Decoded Literal Header Field Without Name Ref: name=%.*s, value=%.*s", static_cast(name_len), name, static_cast(value_len), value); @@ -746,7 +767,8 @@ QPACK::_decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t } int -QPACK::_decode_indexed_header_field_with_postbase_index(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr) +QPACK::_decode_indexed_header_field_with_postbase_index(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, + uint32_t &header_len) { // Read index field int len = 0; @@ -772,6 +794,7 @@ QPACK::_decode_indexed_header_field_with_postbase_index(int16_t base_index, cons // Create and attach a header this->_attach_header(hdr, name, name_len, value, value_len, false); + header_len = name_len + value_len; QPACKDebug("Decoded Indexed Header Field With Postbase Index: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index, result.index, name_len, name, value_len, value); @@ -780,7 +803,8 @@ QPACK::_decode_indexed_header_field_with_postbase_index(int16_t base_index, cons } int -QPACK::_decode_literal_header_field_with_postbase_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr) +QPACK::_decode_literal_header_field_with_postbase_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, + uint32_t &header_len) { int read_len = 0; @@ -822,6 +846,7 @@ QPACK::_decode_literal_header_field_with_postbase_name_ref(int16_t base_index, c // Create and attach a header this->_attach_header(hdr, name, name_len, value, value_len, never_index); + header_len = name_len + value_len; QPACKDebug("Decoded Literal Header Field With Postbase Name Ref: base_index=%d, abs_index=%d, name=%.*s, value=%.*s", base_index, static_cast(index), name_len, name, static_cast(value_len), value); @@ -859,22 +884,34 @@ QPACK::_decode_header(const uint8_t *header_block, size_t header_block_len, HTTP } pos += ret; + uint32_t decoded_header_list_size = 0; + // Decode Instructions while (pos < header_block + header_block_len) { + uint32_t header_len = 0; + if (pos[0] & 0x80) { // Index Header Field - ret = this->_decode_indexed_header_field(base_index, pos, remain_len, hdr); + ret = this->_decode_indexed_header_field(base_index, pos, remain_len, hdr, header_len); } else if (pos[0] & 0x40) { // Literal Header Field With Name Reference - ret = this->_decode_literal_header_field_with_name_ref(base_index, pos, remain_len, hdr); + ret = this->_decode_literal_header_field_with_name_ref(base_index, pos, remain_len, hdr, header_len); } else if (pos[0] & 0x20) { // Literal Header Field Without Name Reference - ret = this->_decode_literal_header_field_without_name_ref(pos, remain_len, hdr); + ret = this->_decode_literal_header_field_without_name_ref(pos, remain_len, hdr, header_len); } else if (pos[0] & 0x10) { // Indexed Header Field With Post-Base Index - ret = this->_decode_indexed_header_field_with_postbase_index(base_index, pos, remain_len, hdr); + ret = this->_decode_indexed_header_field_with_postbase_index(base_index, pos, remain_len, hdr, header_len); } else { // Literal Header Field With Post-Base Name Reference - ret = this->_decode_literal_header_field_with_postbase_name_ref(base_index, pos, remain_len, hdr); + ret = this->_decode_literal_header_field_with_postbase_name_ref(base_index, pos, remain_len, hdr, header_len); } + if (ret < 0) { break; } + + decoded_header_list_size += header_len; + if (decoded_header_list_size > this->_max_header_list_size) { + ret = -2; + break; + } + pos += ret; } diff --git a/proxy/http3/QPACK.h b/proxy/http3/QPACK.h index 68c67acbeff..54c3c2b4dab 100644 --- a/proxy/http3/QPACK.h +++ b/proxy/http3/QPACK.h @@ -29,6 +29,8 @@ #include "MIME.h" #include "QUICApplication.h" +#include "Http3.h" + class HTTPHdr; enum { @@ -36,15 +38,12 @@ enum { QPACK_EVENT_DECODE_FAILED, }; -// FIXME This setting should be passed by HTTP/3 -constexpr int SETTINGS_HEADER_TABLE_SIZE = 0; -constexpr int SETTINGS_QPACK_BLOCKED_STREAMS = 0; - class QPACK : public QUICApplication { public: - QPACK(QUICConnection *qc, uint16_t max_table_size = SETTINGS_HEADER_TABLE_SIZE, - uint16_t max_blocking_streams = SETTINGS_QPACK_BLOCKED_STREAMS); + QPACK(QUICConnection *qc, uint32_t max_header_list_size = HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE, + uint16_t max_table_size = HTTP3_DEFAULT_HEADER_TABLE_SIZE, + uint16_t max_blocking_streams = HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS); virtual ~QPACK(); int event_handler(int event, Event *data); @@ -68,6 +67,10 @@ class QPACK : public QUICApplication void set_encoder_stream(QUICStreamIO *stream_io); void set_decoder_stream(QUICStreamIO *stream_io); + void update_max_header_list_size(uint32_t max_header_list_size); + void update_max_table_size(uint16_t max_table_size); + void update_max_blocking_streams(uint16_t max_blocking_streams); + static size_t estimate_header_block_size(const HTTPHdr &header_set); private: @@ -241,6 +244,7 @@ class QPACK : public QUICApplication DynamicTable _dynamic_table; std::map _references; + uint32_t _max_header_list_size = 0; uint16_t _max_table_size = 0; uint16_t _max_blocking_streams = 0; @@ -295,11 +299,14 @@ class QPACK : public QUICApplication void _decode(EThread *ethread, Continuation *cont, uint64_t stream_id, const uint8_t *header_block, size_t header_block_len, HTTPHdr &hdr); int _decode_header(const uint8_t *header_block, size_t header_block_len, HTTPHdr &hdr); - int _decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr); - int _decode_indexed_header_field_with_postbase_index(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr); - int _decode_literal_header_field_with_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr); - int _decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t buf_len, HTTPHdr &hdr); - int _decode_literal_header_field_with_postbase_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr); + int _decode_indexed_header_field(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, uint32_t &header_len); + int _decode_indexed_header_field_with_postbase_index(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, + uint32_t &header_len); + int _decode_literal_header_field_with_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, + uint32_t &header_len); + int _decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, uint32_t &header_len); + int _decode_literal_header_field_with_postbase_name_ref(int16_t base_index, const uint8_t *buf, size_t buf_len, HTTPHdr &hdr, + uint32_t &header_len); // Utilities uint16_t _calc_absolute_index_from_relative_index(uint16_t base_index, uint16_t relative_index); From 982c9baf4b7c9ca86735fc0b28581039bc3f154b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Feb 2019 14:37:35 +0900 Subject: [PATCH 1100/1313] Remove references to HTTP/3 from QPACK --- proxy/http3/Http3App.cc | 1 + proxy/http3/Http3ClientSession.cc | 8 ++++++-- proxy/http3/QPACK.h | 6 +----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index e4bde933fd4..e30adf48a6d 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -26,6 +26,7 @@ #include "P_Net.h" #include "P_VConnection.h" +#include "Http3.h" #include "Http3Config.h" #include "Http3DebugNames.h" #include "Http3ClientSession.h" diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3ClientSession.cc index 0b8e294ee9b..2038e780322 100644 --- a/proxy/http3/Http3ClientSession.cc +++ b/proxy/http3/Http3ClientSession.cc @@ -23,10 +23,14 @@ #include "Http3ClientSession.h" +#include "Http3.h" + Http3ClientSession::Http3ClientSession(NetVConnection *vc) : _client_vc(vc) { - this->_local_qpack = new QPACK(static_cast(vc)); - this->_remote_qpack = new QPACK(static_cast(vc)); + this->_local_qpack = new QPACK(static_cast(vc), HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE, + HTTP3_DEFAULT_HEADER_TABLE_SIZE, HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS); + this->_remote_qpack = new QPACK(static_cast(vc), HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE, + HTTP3_DEFAULT_HEADER_TABLE_SIZE, HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS); } Http3ClientSession::~Http3ClientSession() diff --git a/proxy/http3/QPACK.h b/proxy/http3/QPACK.h index 54c3c2b4dab..85bd7106701 100644 --- a/proxy/http3/QPACK.h +++ b/proxy/http3/QPACK.h @@ -29,8 +29,6 @@ #include "MIME.h" #include "QUICApplication.h" -#include "Http3.h" - class HTTPHdr; enum { @@ -41,9 +39,7 @@ enum { class QPACK : public QUICApplication { public: - QPACK(QUICConnection *qc, uint32_t max_header_list_size = HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE, - uint16_t max_table_size = HTTP3_DEFAULT_HEADER_TABLE_SIZE, - uint16_t max_blocking_streams = HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS); + QPACK(QUICConnection *qc, uint32_t max_header_list_size, uint16_t max_table_size, uint16_t max_blocking_streams); virtual ~QPACK(); int event_handler(int event, Event *data); From 9bbdb911853d9fdfa824338a91dcdbeece1ee843 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Feb 2019 14:39:17 +0900 Subject: [PATCH 1101/1313] Fix unit test of QPACK --- proxy/http3/test/test_QPACK.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/proxy/http3/test/test_QPACK.cc b/proxy/http3/test/test_QPACK.cc index 02fd505ad3e..c2a1311c8ce 100644 --- a/proxy/http3/test/test_QPACK.cc +++ b/proxy/http3/test/test_QPACK.cc @@ -288,7 +288,7 @@ test_encode(const char *qif_file, const char *out_file, int dts, int mbs, int am int n_requests = load_qif_file(qif_file, requests); QUICApplicationDriver driver; - QPACK *qpack = new QPACK(driver.get_connection(), dts, mbs); + QPACK *qpack = new QPACK(driver.get_connection(), UINT32_MAX, dts, mbs); TestQUICStream *encoder_stream = new TestQUICStream(0); TestQUICStream *decoder_stream = new TestQUICStream(9999); qpack->set_stream(encoder_stream); @@ -296,10 +296,11 @@ test_encode(const char *qif_file, const char *out_file, int dts, int mbs, int am uint64_t stream_id = 1; MIOBuffer *header_block = new_MIOBuffer(); + uint64_t header_block_len = 0; IOBufferReader *header_block_reader = header_block->alloc_reader(); for (int i = 0; i < n_requests; ++i) { HTTPHdr *hdr = requests[i]; - ret = qpack->encode(stream_id, *hdr, header_block); + ret = qpack->encode(stream_id, *hdr, header_block, header_block_len); if (ret < 0) { break; } @@ -334,7 +335,7 @@ test_decode(const char *enc_file, const char *out_file, int dts, int mbs, int am TestQPACKEventHandler *event_handler = new TestQPACKEventHandler(); QUICApplicationDriver driver; - QPACK *qpack = new QPACK(driver.get_connection(), dts, mbs); + QPACK *qpack = new QPACK(driver.get_connection(), UINT32_MAX, dts, mbs); TestQUICStream *encoder_stream = new TestQUICStream(0); qpack->set_stream(encoder_stream); From 666ee793da1c177bc5d4ee785422896888fb51fc Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 5 Feb 2019 14:49:30 +0900 Subject: [PATCH 1102/1313] Remove QUICPacketRetransmitter --- iocore/net/P_QUICNetVConnection.h | 2 - iocore/net/QUICNetVConnection.cc | 16 +-- iocore/net/quic/Makefile.am | 1 - iocore/net/quic/QUICPacketRetransmitter.cc | 109 --------------------- iocore/net/quic/QUICPacketRetransmitter.h | 43 -------- 5 files changed, 1 insertion(+), 170 deletions(-) delete mode 100644 iocore/net/quic/QUICPacketRetransmitter.cc delete mode 100644 iocore/net/quic/QUICPacketRetransmitter.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 8890ca91f4b..7d7b8d71df1 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -52,7 +52,6 @@ #include "quic/QUICHandshakeProtocol.h" #include "quic/QUICAckFrameCreator.h" #include "quic/QUICPinger.h" -#include "quic/QUICPacketRetransmitter.h" #include "quic/QUICLossDetector.h" #include "quic/QUICStreamManager.h" #include "quic/QUICAltConnectionManager.h" @@ -254,7 +253,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICFrameFactory _frame_factory; QUICAckFrameManager _ack_frame_manager; QUICPinger _pinger; - QUICPacketRetransmitter _packet_retransmitter; QUICPacketHeaderProtector _ph_protector; QUICRTTMeasure _rtt_measure; QUICApplicationMap *_application_map = nullptr; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 453002f1977..e68d5ea0595 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -472,9 +472,7 @@ QUICNetVConnection::stream_manager() void QUICNetVConnection::retransmit_packet(const QUICPacket &packet) { - QUICConDebug("Retransmit %s packet #%" PRIu64, QUICDebugNames::packet_type(packet.type()), packet.packet_number()); - - this->_packet_retransmitter.retransmit_packet(packet); + QUICConDebug("[NOP] Retransmit %s packet #%" PRIu64, QUICDebugNames::packet_type(packet.type()), packet.packet_number()); } Ptr @@ -955,7 +953,6 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack } this->_congestion_controller->reset(); SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); - this->_packet_retransmitter.reset(); // start handshake over this->_handshake_handler->reset(); @@ -1031,7 +1028,6 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) } this->_congestion_controller->reset(); SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); - this->_packet_retransmitter.reset(); this->_packet_recv_queue.reset(); // Initialize Key Materials with peer CID. Because peer CID is DCID of (second) INITIAL packet from client which reply to RETRY @@ -1381,16 +1377,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } } - // Lost frames - frame = this->_packet_retransmitter.generate_frame(level, UINT16_MAX, max_frame_size); - while (frame) { - ++frame_count; - probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, frame, frames); - - frame = this->_packet_retransmitter.generate_frame(level, UINT16_MAX, max_frame_size); - } - // MAX_DATA frame = this->_local_flow_controller->generate_frame(level, UINT16_MAX, max_frame_size); if (frame) { diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 2b122390624..9e555204c37 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -77,7 +77,6 @@ libquic_a_SOURCES = \ QUICApplicationMap.cc \ QUICIncomingFrameBuffer.cc \ QUICPacketReceiveQueue.cc \ - QUICPacketRetransmitter.cc \ QUICPathValidator.cc \ QUICPinger.cc \ QUICFrameGenerator.cc \ diff --git a/iocore/net/quic/QUICPacketRetransmitter.cc b/iocore/net/quic/QUICPacketRetransmitter.cc deleted file mode 100644 index b20078111a0..00000000000 --- a/iocore/net/quic/QUICPacketRetransmitter.cc +++ /dev/null @@ -1,109 +0,0 @@ -/** @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 "QUICPacketRetransmitter.h" -#include "QUICDebugNames.h" - -void -QUICPacketRetransmitter::retransmit_packet(const QUICPacket &packet) -{ - ink_assert(packet.type() != QUICPacketType::VERSION_NEGOTIATION && packet.type() != QUICPacketType::UNINITIALIZED); - - // Get payload from a header because packet.payload() is encrypted - uint16_t size = packet.header().payload_size(); - const uint8_t *payload = packet.header().payload(); - - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - uint16_t cursor = 0; - - while (cursor < size) { - frame = QUICFrameFactory::create(payload + cursor, size - cursor); - cursor += frame->size(); - - switch (frame->type()) { - case QUICFrameType::PADDING: - case QUICFrameType::ACK: - case QUICFrameType::PATH_CHALLENGE: - case QUICFrameType::PATH_RESPONSE: - case QUICFrameType::RESET_STREAM: - case QUICFrameType::DATA_BLOCKED: - case QUICFrameType::STREAM_DATA_BLOCKED: - case QUICFrameType::MAX_DATA: - case QUICFrameType::MAX_STREAM_DATA: - case QUICFrameType::NEW_TOKEN: - case QUICFrameType::PING: - case QUICFrameType::STOP_SENDING: - case QUICFrameType::CONNECTION_CLOSE: - case QUICFrameType::STREAM: - case QUICFrameType::CRYPTO: - case QUICFrameType::NEW_CONNECTION_ID: - case QUICFrameType::RETIRE_CONNECTION_ID: - break; - default: - frame = QUICFrameFactory::create_retransmission_frame(frame->clone(), packet); - int index = static_cast(QUICTypeUtil::encryption_level(packet.type())); - this->_retransmission_frames[index].push(std::move(frame)); - break; - } - } -} - -void -QUICPacketRetransmitter::reset() -{ - for (auto level : QUIC_ENCRYPTION_LEVELS) { - int index = static_cast(level); - while (!this->_retransmission_frames[index].empty()) { - this->_retransmission_frames[index].pop(); - } - } -} - -bool -QUICPacketRetransmitter::will_generate_frame(QUICEncryptionLevel level) -{ - return !this->_retransmission_frames[static_cast(level)].empty(); -} - -QUICFrameUPtr -QUICPacketRetransmitter::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) -{ - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - int index = static_cast(level); - if (!this->_retransmission_frames[index].empty()) { - frame = std::move(this->_retransmission_frames[index].front()); - this->_retransmission_frames[index].pop(); - - if (frame->size() > maximum_frame_size) { - auto new_frame = QUICFrameFactory::split_frame(frame.get(), maximum_frame_size); - if (new_frame) { - this->_retransmission_frames[index].push(std::move(new_frame)); - } else { - // failed to split frame return nullptr - this->_retransmission_frames[index].push(std::move(frame)); - frame = QUICFrameFactory::create_null_frame(); - } - } - } - return frame; -} diff --git a/iocore/net/quic/QUICPacketRetransmitter.h b/iocore/net/quic/QUICPacketRetransmitter.h deleted file mode 100644 index 93de7cf0f24..00000000000 --- a/iocore/net/quic/QUICPacketRetransmitter.h +++ /dev/null @@ -1,43 +0,0 @@ -/** @file - * - * A brief file description - * - * @section license License - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "QUICPacket.h" -#include "QUICFrame.h" -#include "QUICFrameGenerator.h" -#include - -class QUICPacketRetransmitter : public QUICFrameGenerator -{ -public: - void retransmit_packet(const QUICPacket &packet); - void reset(); - - // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; - -private: - std::queue _retransmission_frames[4]; -}; From 8c4f40f845d659f7f757754fef9e2cd4d0604818 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 5 Feb 2019 15:43:51 +0900 Subject: [PATCH 1103/1313] Remove QUICRetransmissionFrame --- iocore/net/quic/QUICFrame.cc | 65 ------------------------------------ iocore/net/quic/QUICFrame.h | 38 --------------------- 2 files changed, 103 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 2ae36a06f7a..0bb66ad06a3 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -49,7 +49,6 @@ ClassAllocator quicPathChallengeFrameAllocator("quicPath ClassAllocator quicPathResponseFrameAllocator("quicPathResponseFrameAllocator"); ClassAllocator quicNewTokenFrameAllocator("quicNewTokenFrameAllocator"); ClassAllocator quicRetireConnectionIdFrameAllocator("quicRetireConnectionIdFrameAllocator"); -ClassAllocator quicRetransmissionFrameAllocator("quicRetransmissionFrameAllocator"); #define LEFT_SPACE(pos) ((size_t)(buf + len - pos)) #define FRAME_SIZE(pos) (pos - buf) @@ -2594,62 +2593,6 @@ QUICRetireConnectionIdFrame::seq_num() const return this->_seq_num; } -// -// QUICRetransmissionFrame -// -QUICRetransmissionFrame::QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet) - : QUICFrame(original_frame->id(), original_frame->generated_by()), _packet_type(original_packet.type()) -{ - this->_frame = std::move(original_frame); -} - -QUICFrameUPtr -QUICRetransmissionFrame::clone() const -{ - ink_assert(!"Retransmission frames shouldn't be cloned"); - return QUICFrameFactory::create_null_frame(); -} - -QUICFrameType -QUICRetransmissionFrame::type() const -{ - return this->_frame->type(); -} - -size_t -QUICRetransmissionFrame::size() const -{ - return this->_frame->size(); -} - -size_t -QUICRetransmissionFrame::store(uint8_t *buf, size_t *len, size_t limit) const -{ - return this->_frame->store(buf, len, limit); -} - -int -QUICRetransmissionFrame::debug_msg(char *msg, size_t msg_len) const -{ - return snprintf(msg, msg_len, "| %s size=%zu (retransmission)", QUICDebugNames::frame_type(this->type()), this->size()); -} - -QUICPacketType -QUICRetransmissionFrame::packet_type() const -{ - return this->_packet_type; -} - -QUICFrame * -QUICRetransmissionFrame::split(size_t size) -{ - if (this->_frame->type() != QUICFrameType::STREAM) { - return nullptr; - } - - return this->_frame->split(size); -} - // // QUICFrameFactory // @@ -2970,14 +2913,6 @@ QUICFrameFactory::create_retire_connection_id_frame(uint64_t seq_num, QUICFrameI &QUICFrameDeleter::delete_retire_connection_id_frame); } -std::unique_ptr -QUICFrameFactory::create_retransmission_frame(QUICFrameUPtr original_frame, const QUICPacket &original_packet) -{ - QUICRetransmissionFrame *frame = quicRetransmissionFrameAllocator.alloc(); - new (frame) QUICRetransmissionFrame(std::move(original_frame), original_packet); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_retransmission_frame); -} - QUICFrameId QUICFrameInfo::id() { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index ddb94bdd4b2..e8dba5b4107 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -716,29 +716,6 @@ class QUICRetireConnectionIdFrame : public QUICFrame uint64_t _seq_num = 0; }; -// -// Retransmission Frame - Not on the spec -// - -class QUICRetransmissionFrame : public QUICFrame -{ -public: - QUICRetransmissionFrame() {} - QUICRetransmissionFrame(QUICFrameUPtr original_frame, const QUICPacket &original_packet); - QUICFrameUPtr clone() const override; - QUICFrameType type() const override; - virtual size_t size() const override; - virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; - virtual int debug_msg(char *msg, size_t msg_len) const override; - QUICPacketType packet_type() const; - QUICFrame *split(size_t size) override; - -private: - QUICFrameUPtr _frame = QUICFrameUPtr(nullptr, nullptr); - ats_unique_buf _data = ats_unique_buf(nullptr); - QUICPacketType _packet_type; -}; - extern ClassAllocator quicStreamFrameAllocator; extern ClassAllocator quicCryptoFrameAllocator; extern ClassAllocator quicAckFrameAllocator; @@ -758,7 +735,6 @@ extern ClassAllocator quicPathChallengeFrameAllocator; extern ClassAllocator quicPathResponseFrameAllocator; extern ClassAllocator quicNewTokenFrameAllocator; extern ClassAllocator quicRetireConnectionIdFrameAllocator; -extern ClassAllocator quicRetransmissionFrameAllocator; class QUICFrameDeleter { @@ -902,13 +878,6 @@ class QUICFrameDeleter frame->~QUICFrame(); quicRetireConnectionIdFrameAllocator.free(static_cast(frame)); } - - static void - delete_retransmission_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicRetransmissionFrameAllocator.free(static_cast(frame)); - } }; // @@ -1070,13 +1039,6 @@ class QUICFrameFactory static std::unique_ptr create_retire_connection_id_frame( uint64_t seq_num, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - /* - * Creates a retransmission frame, which is very special. - * This retransmission frame will be used only for retransmission and it's not a standard frame type. - */ - static std::unique_ptr create_retransmission_frame( - QUICFrameUPtr original_frame, const QUICPacket &original_packet); - private: // FIXME Actual number of frame types is several but some of the values are not sequential. std::shared_ptr _reusable_frames[256] = {nullptr}; From a62ea1c0e065815585ba2be5380eaa0c26abfcd0 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 5 Feb 2019 16:06:15 +0900 Subject: [PATCH 1104/1313] Remove QUICFrame::split which was used from RetransmisionFrame --- iocore/net/quic/QUICFrame.cc | 83 ------------------------------------ iocore/net/quic/QUICFrame.h | 9 ---- 2 files changed, 92 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 0bb66ad06a3..3530fe19b8a 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -125,12 +125,6 @@ QUICFrame::debug_msg(char *msg, size_t msg_len) const return snprintf(msg, msg_len, "| %s size=%zu", QUICDebugNames::frame_type(this->type()), this->size()); } -QUICFrame * -QUICFrame::split(size_t size) -{ - return nullptr; -} - bool QUICFrame::valid() const { @@ -216,45 +210,6 @@ QUICStreamFrame::_reset() this->_size = 0; } -QUICFrame * -QUICStreamFrame::split(size_t size) -{ - size_t header_len = 1 + QUICVariableInt::size(this->_stream_id); - if (this->_has_offset_field) { - header_len += QUICVariableInt::size(this->_offset); - } - if (this->_has_length_field) { - header_len += QUICVariableInt::size(this->_block->read_avail()); - } - - if (size <= header_len) { - return nullptr; - } - bool fin = this->has_fin_flag(); - - ink_assert(size < this->size()); - ink_assert(this->_block.get() != nullptr); - - size_t data_len = size - header_len; - - Ptr new_block = make_ptr(this->_block->clone()); - new_block->consume(data_len); - this->_block->_end = std::min(this->_block->_start + data_len, this->_block->_buf_end); - - if (this->has_offset_field()) { - this->_offset = this->offset(); - } - - this->_fin = false; - this->_stream_id = this->stream_id(); - - QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(new_block, this->stream_id(), this->offset() + this->data_length(), fin, this->_has_offset_field, - this->_has_length_field, this->_id, this->_owner); - - return frame; -} - QUICFrameUPtr QUICStreamFrame::clone() const { @@ -464,33 +419,6 @@ QUICCryptoFrame::_reset() this->_size = 0; } -QUICFrame * -QUICCryptoFrame::split(size_t size) -{ - size_t header_len = 1 + QUICVariableInt::size(this->_offset) + QUICVariableInt::size(this->_block->read_avail()); - if (size <= header_len) { - return nullptr; - } - - ink_assert(size < this->size()); - - size_t data_len = size - header_len; - - ink_assert(size < this->size()); - ink_assert(this->_block.get() != nullptr); - - Ptr new_block = make_ptr(this->_block->clone()); - new_block->consume(data_len); - this->_block->_end = std::min(this->_block->_start + data_len, this->_block->_buf_end); - - this->_offset = this->offset(); - - QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); - new (frame) QUICCryptoFrame(this->_block, this->offset() + data_len, this->_id, this->_owner); - - return frame; -} - QUICFrameUPtr QUICCryptoFrame::clone() const { @@ -2738,17 +2666,6 @@ QUICFrameFactory::create_crypto_frame(Ptr &block, QUICOffset offs return QUICCryptoFrameUPtr(frame, &QUICFrameDeleter::delete_crypto_frame); } -QUICFrameUPtr -QUICFrameFactory::split_frame(QUICFrame *frame, size_t size) -{ - auto new_frame = frame->split(size); - if (!new_frame) { - return QUICFrameFactory::create_null_frame(); - } - - return QUICFrameUPtr(new_frame, &QUICFrameDeleter::delete_stream_frame); -} - std::unique_ptr QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameId id, QUICFrameGenerator *owner) diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index e8dba5b4107..7b7a1a93edc 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -63,7 +63,6 @@ class QUICFrame virtual size_t size() const = 0; virtual bool is_probing_frame() const; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const = 0; - virtual QUICFrame *split(size_t size); virtual int debug_msg(char *msg, size_t msg_len) const; virtual void parse(const uint8_t *buf, size_t len){}; virtual QUICFrameGenerator *generated_by(); @@ -92,7 +91,6 @@ class QUICStreamFrame : public QUICFrame bool has_offset_field = true, bool has_length_field = true, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - QUICFrame *split(size_t size) override; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -133,7 +131,6 @@ class QUICCryptoFrame : public QUICFrame QUICCryptoFrame(const uint8_t *buf, size_t len); QUICCryptoFrame(Ptr &block, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - QUICFrame *split(size_t size) override; QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; @@ -886,12 +883,6 @@ class QUICFrameDeleter class QUICFrameFactory { public: - /* - * Split Stream frame into two frame - * Return the new frame - */ - static QUICFrameUPtr split_frame(QUICFrame *frame, size_t size); - /* * This is for an empty QUICFrameUptr. * Empty frames are used for variable initialization and return value of frame creation failure From b6e9a7bdc6b6ecb3237222582d24ae200d7a228f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Feb 2019 16:37:33 +0900 Subject: [PATCH 1105/1313] Remove tests for features removed --- iocore/net/quic/test/test_QUICFrame.cc | 33 -------------------------- 1 file changed, 33 deletions(-) diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index be579dc1388..61c5fe4c455 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -381,39 +381,6 @@ TEST_CASE("Store STREAM Frame", "[quic]") CHECK(len == 19); CHECK(memcmp(buf, expected, len) == 0); } - - SECTION("split stream frame") - { - uint8_t buf1[] = { - 0x0e, // 0b00001OLF (OLF=110) - 0x01, // Stream ID - 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // Offset - 0x0a, // Data Length - 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data - 0x11, 0x22, 0x33, 0x44, 0x55, - }; - - QUICFrameUPtr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); - CHECK(frame1->type() == QUICFrameType::STREAM); - CHECK(frame1->size() == 21); - QUICStreamFrame *stream_frame = dynamic_cast(frame1.get()); - CHECK(stream_frame->offset() == 0x100000000); - CHECK(stream_frame->stream_id() == 0x01); - CHECK(stream_frame->data_length() == 10); - QUICStreamFrame *stream_frame2 = dynamic_cast(stream_frame->split(16)); - CHECK(stream_frame->stream_id() == 0x01); - CHECK(stream_frame->data_length() == 5); - CHECK(memcmp(stream_frame->data()->start(), "\x01\x02\x03\x04\x05", stream_frame->data_length()) == 0); - CHECK(stream_frame->offset() == 0x100000000); - - frame1 = QUICFrameFactory::create_null_frame(); - CHECK(stream_frame2->data_length() == 5); - CHECK(memcmp(stream_frame2->data()->start(), "\x11\x22\x33\x44\x55", stream_frame2->data_length()) == 0); - CHECK(stream_frame2->offset() == 0x100000000 + 5); - CHECK(stream_frame2->stream_id() == 0x01); - - QUICFrameDeleter::delete_stream_frame(stream_frame2); - } } TEST_CASE("CRYPTO Frame", "[quic]") From 8decc8350d2a1ee01a628e38a40e5f13ddefcd06 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Feb 2019 17:20:36 +0900 Subject: [PATCH 1106/1313] Separate out QUICPacketFactory --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/quic/Makefile.am | 1 + iocore/net/quic/QUICHandshake.cc | 1 + iocore/net/quic/QUICHandshake.h | 1 + iocore/net/quic/QUICPacket.cc | 315 +------------------- iocore/net/quic/QUICPacket.h | 56 ---- iocore/net/quic/QUICPacketFactory.cc | 342 ++++++++++++++++++++++ iocore/net/quic/QUICPacketFactory.h | 83 ++++++ iocore/net/quic/QUICPacketReceiveQueue.cc | 1 + iocore/net/quic/QUICPacketReceiveQueue.h | 2 + 10 files changed, 434 insertions(+), 369 deletions(-) create mode 100644 iocore/net/quic/QUICPacketFactory.cc create mode 100644 iocore/net/quic/QUICPacketFactory.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 7d7b8d71df1..b9f7590de63 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -44,6 +44,7 @@ #include "quic/QUICConnectionTable.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" diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 9e555204c37..92d45c98eb7 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -48,6 +48,7 @@ libquic_a_SOURCES = \ QUICTypes.cc \ QUICIntUtil.cc \ QUICPacket.cc \ + QUICPacketFactory.cc \ QUICFrame.cc \ QUICFrameDispatcher.cc \ QUICVersionNegotiator.cc \ diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index b1254d27470..cde0495f659 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -27,6 +27,7 @@ #include "QUICEvents.h" #include "QUICGlobals.h" +#include "QUICPacketFactory.h" #include "QUICVersionNegotiator.h" #include "QUICConfig.h" #include "QUICStream.h" diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index bab48e4bd5a..3e46ea5c149 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -34,6 +34,7 @@ * @brief Send/Receive CRYPTO frame and do Cryptographic Handshake */ class QUICVersionNegotiator; +class QUICPacketFactory; class SSLNextProtocolSet; class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 5ef598fc581..8619789748d 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -30,14 +30,11 @@ #include "QUICDebugNames.h" using namespace std::literals; -static constexpr std::string_view tag = "quic_packet"sv; -static constexpr std::string_view tag_v = "v_quic_crypto"sv; -static constexpr uint64_t aead_tag_len = 16; +static constexpr std::string_view tag = "quic_packet"sv; +static constexpr uint64_t aead_tag_len = 16; #define QUICDebug(dcid, scid, fmt, ...) \ Debug(tag.data(), "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__); -#define QUICVDebug(dcid, scid, fmt, ...) \ - Debug(tag_v.data(), "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__); ClassAllocator quicPacketAllocator("quicPacketAllocator"); ClassAllocator quicPacketLongHeaderAllocator("quicPacketLongHeaderAllocator"); @@ -1008,311 +1005,3 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si return true; } - -// -// QUICPacketFactory -// -QUICPacketUPtr -QUICPacketFactory::create_null_packet() -{ - return {nullptr, &QUICPacketDeleter::delete_null_packet}; -} - -QUICPacketUPtr -QUICPacketFactory::create(IpEndpoint from, 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, 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 { - 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->_hs_protocol->is_key_derived(header->key_phase(), false)) { - if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - header->key_phase())) { - result = QUICPacketCreationResult::SUCCESS; - } else { - result = QUICPacketCreationResult::FAILED; - } - } else { - result = QUICPacketCreationResult::NOT_READY; - } - break; - case QUICPacketType::INITIAL: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::INITIAL, false)) { - if (QUICTypeUtil::is_supported_version(header->version())) { - if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::INITIAL)) { - result = QUICPacketCreationResult::SUCCESS; - } else { - result = QUICPacketCreationResult::FAILED; - } - } else { - result = QUICPacketCreationResult::SUCCESS; - } - } else { - result = QUICPacketCreationResult::IGNORED; - } - break; - case QUICPacketType::HANDSHAKE: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::HANDSHAKE, false)) { - if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::HANDSHAKE)) { - result = QUICPacketCreationResult::SUCCESS; - } else { - result = QUICPacketCreationResult::FAILED; - } - } else { - result = QUICPacketCreationResult::IGNORED; - } - break; - case QUICPacketType::ZERO_RTT_PROTECTED: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::ZERO_RTT, false)) { - if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::ZERO_RTT)) { - result = QUICPacketCreationResult::SUCCESS; - } else { - result = QUICPacketCreationResult::IGNORED; - } - } else { - result = QUICPacketCreationResult::NOT_READY; - } - break; - default: - result = QUICPacketCreationResult::FAILED; - break; - } - } - - QUICPacket *packet = nullptr; - if (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::UNSUPPORTED) { - packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(std::move(header), std::move(plain_txt), plain_txt_len); - } - - return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); -} - -QUICPacketUPtr -QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUICConnectionId scid) -{ - size_t len = sizeof(QUICVersion) * countof(QUIC_SUPPORTED_VERSIONS); - ats_unique_buf versions(reinterpret_cast(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; - } - - // 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, std::move(versions), len); - - return QUICPacketFactory::_create_unprotected_packet(std::move(header)); -} - -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, std::vector &frames, - ats_unique_buf token, size_t token_len) -{ - int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); - QUICPacketNumber pn = this->_packet_number_generator[index].next(); - QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, destination_cid, source_cid, pn, base_packet_number, - this->_version, std::move(payload), len, std::move(token), token_len); - return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); -} - -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()); - - 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)); -} - -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, std::vector &frames) -{ - int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::HANDSHAKE); - QUICPacketNumber pn = this->_packet_number_generator[index].next(); - QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::HANDSHAKE, QUICKeyPhase::HANDSHAKE, destination_cid, source_cid, pn, base_packet_number, - this->_version, std::move(payload), len); - return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); -} - -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, std::vector &frames) -{ - int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ZERO_RTT); - QUICPacketNumber pn = this->_packet_number_generator[index].next(); - QUICPacketHeaderUPtr header = - QUICPacketHeader::build(QUICPacketType::ZERO_RTT_PROTECTED, QUICKeyPhase::ZERO_RTT, destination_cid, source_cid, pn, - base_packet_number, this->_version, std::move(payload), len); - return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); -} - -QUICPacketUPtr -QUICPacketFactory::create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable, bool probing, - std::vector &frames) -{ - int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ONE_RTT); - QUICPacketNumber pn = this->_packet_number_generator[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, frames); -} - -QUICPacketUPtr -QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessResetToken stateless_reset_token) -{ - std::random_device rnd; - - uint8_t random_packet_number = static_cast(rnd() & 0xFF); - size_t payload_len = static_cast((rnd() & 0xFF) | 16); // Mimimum length has to be 16 - ats_unique_buf payload = ats_unique_malloc(payload_len + 16); - uint8_t *naked_payload = payload.get(); - - // Generate random octets - for (int i = payload_len - 1; i >= 0; --i) { - naked_payload[i] = static_cast(rnd() & 0xFF); - } - // Copy stateless reset token into payload - memcpy(naked_payload + payload_len - 16, stateless_reset_token.buf(), 16); - - // 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)); -} - -QUICPacketUPtr -QUICPacketFactory::_create_unprotected_packet(QUICPacketHeaderUPtr header) -{ - ats_unique_buf cleartext = ats_unique_malloc(2048); - size_t cleartext_len = header->payload_size(); - - memcpy(cleartext.get(), header->payload(), cleartext_len); - QUICPacket *packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(std::move(header), std::move(cleartext), cleartext_len, false, false); - - return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); -} - -QUICPacketUPtr -QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing, - std::vector &frames) -{ - // TODO: use pmtu of UnixNetVConnection - size_t max_cipher_txt_len = 2048; - ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); - size_t cipher_txt_len = 0; - - 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; - if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->size(), header->key_phase())) { - packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable, probing, frames); - } else { - QUICDebug(dcid, scid, "Failed to encrypt a packet"); - } - - return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); -} - -void -QUICPacketFactory::set_version(QUICVersion negotiated_version) -{ - this->_version = negotiated_version; -} - -void -QUICPacketFactory::set_hs_protocol(const QUICHandshakeProtocol *hs_protocol) -{ - this->_hs_protocol = hs_protocol; -} - -bool -QUICPacketFactory::is_ready_to_create_protected_packet() -{ - return this->_hs_protocol->is_handshake_finished(); -} - -void -QUICPacketFactory::reset() -{ - for (auto s : QUIC_PN_SPACES) { - this->_packet_number_generator[static_cast(s)].reset(); - } -} - -// -// QUICPacketNumberGenerator -// -QUICPacketNumberGenerator::QUICPacketNumberGenerator() {} - -QUICPacketNumber -QUICPacketNumberGenerator::next() -{ - // TODO Increment the number at least one but not only always one - return this->_current++; -} - -void -QUICPacketNumberGenerator::reset() -{ - this->_current = 0; -} diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 01d99ff7d5b..8a5f4720c20 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -390,17 +390,6 @@ class QUICPacket : public QUICTrackablePacket bool _is_probing_packet = false; }; -class QUICPacketNumberGenerator -{ -public: - QUICPacketNumberGenerator(); - QUICPacketNumber next(); - void reset(); - -private: - std::atomic _current = 0; -}; - using QUICPacketDeleterFunc = void (*)(QUICPacket *p); using QUICPacketUPtr = std::unique_ptr; @@ -421,48 +410,3 @@ class QUICPacketDeleter quicPacketAllocator.free(packet); } }; - -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); - - QUICPacketUPtr create(IpEndpoint from, 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 retransmittable, bool probing, std::vector &frame, - 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, - bool retransmittable, bool probing, std::vector &frames); - QUICPacketUPtr 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, std::vector &frames); - QUICPacketUPtr create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable, bool probing, - std::vector &frames); - void set_version(QUICVersion negotiated_version); - - // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICCryptoInfoProvider or somethign instead. - // For now it receives a CONST pointer so PacketFactory cannot bother handshake. - void set_hs_protocol(const QUICHandshakeProtocol *hs_protocol); - - bool is_ready_to_create_protected_packet(); - void reset(); - -private: - QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; - const QUICHandshakeProtocol *_hs_protocol = nullptr; - // 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 retransmittable, bool probing, - std::vector &frames); -}; diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc new file mode 100644 index 00000000000..c1ada3c1741 --- /dev/null +++ b/iocore/net/quic/QUICPacketFactory.cc @@ -0,0 +1,342 @@ +/** @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 "QUICPacketFactory.h" +#include "QUICDebugNames.h" + +using namespace std::literals; +static constexpr std::string_view tag = "quic_packet"sv; +static constexpr std::string_view tag_v = "v_quic_packet"sv; + +#define QUICDebug(dcid, scid, fmt, ...) \ + Debug(tag.data(), "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__); +#define QUICVDebug(dcid, scid, fmt, ...) \ + Debug(tag_v.data(), "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__); + +// +// QUICPacketNumberGenerator +// +QUICPacketNumberGenerator::QUICPacketNumberGenerator() {} + +QUICPacketNumber +QUICPacketNumberGenerator::next() +{ + // TODO Increment the number at least one but not only always one + return this->_current++; +} + +void +QUICPacketNumberGenerator::reset() +{ + this->_current = 0; +} + +// +// QUICPacketFactory +// +QUICPacketUPtr +QUICPacketFactory::create_null_packet() +{ + return {nullptr, &QUICPacketDeleter::delete_null_packet}; +} + +QUICPacketUPtr +QUICPacketFactory::create(IpEndpoint from, 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, 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 { + 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->_hs_protocol->is_key_derived(header->key_phase(), false)) { + if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + header->key_phase())) { + result = QUICPacketCreationResult::SUCCESS; + } else { + result = QUICPacketCreationResult::FAILED; + } + } else { + result = QUICPacketCreationResult::NOT_READY; + } + break; + case QUICPacketType::INITIAL: + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::INITIAL, false)) { + if (QUICTypeUtil::is_supported_version(header->version())) { + if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + QUICKeyPhase::INITIAL)) { + result = QUICPacketCreationResult::SUCCESS; + } else { + result = QUICPacketCreationResult::FAILED; + } + } else { + result = QUICPacketCreationResult::SUCCESS; + } + } else { + result = QUICPacketCreationResult::IGNORED; + } + break; + case QUICPacketType::HANDSHAKE: + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::HANDSHAKE, false)) { + if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + QUICKeyPhase::HANDSHAKE)) { + result = QUICPacketCreationResult::SUCCESS; + } else { + result = QUICPacketCreationResult::FAILED; + } + } else { + result = QUICPacketCreationResult::IGNORED; + } + break; + case QUICPacketType::ZERO_RTT_PROTECTED: + if (this->_hs_protocol->is_key_derived(QUICKeyPhase::ZERO_RTT, false)) { + if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + QUICKeyPhase::ZERO_RTT)) { + result = QUICPacketCreationResult::SUCCESS; + } else { + result = QUICPacketCreationResult::IGNORED; + } + } else { + result = QUICPacketCreationResult::NOT_READY; + } + break; + default: + result = QUICPacketCreationResult::FAILED; + break; + } + } + + QUICPacket *packet = nullptr; + if (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::UNSUPPORTED) { + packet = quicPacketAllocator.alloc(); + new (packet) QUICPacket(std::move(header), std::move(plain_txt), plain_txt_len); + } + + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); +} + +QUICPacketUPtr +QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUICConnectionId scid) +{ + size_t len = sizeof(QUICVersion) * countof(QUIC_SUPPORTED_VERSIONS); + ats_unique_buf versions(reinterpret_cast(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; + } + + // 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, std::move(versions), len); + + return QUICPacketFactory::_create_unprotected_packet(std::move(header)); +} + +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, std::vector &frames, + ats_unique_buf token, size_t token_len) +{ + int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); + QUICPacketNumber pn = this->_packet_number_generator[index].next(); + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, destination_cid, source_cid, pn, base_packet_number, + this->_version, std::move(payload), len, std::move(token), token_len); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); +} + +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()); + + 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)); +} + +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, std::vector &frames) +{ + int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::HANDSHAKE); + QUICPacketNumber pn = this->_packet_number_generator[index].next(); + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::HANDSHAKE, QUICKeyPhase::HANDSHAKE, destination_cid, source_cid, pn, base_packet_number, + this->_version, std::move(payload), len); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); +} + +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, std::vector &frames) +{ + int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ZERO_RTT); + QUICPacketNumber pn = this->_packet_number_generator[index].next(); + QUICPacketHeaderUPtr header = + QUICPacketHeader::build(QUICPacketType::ZERO_RTT_PROTECTED, QUICKeyPhase::ZERO_RTT, destination_cid, source_cid, pn, + base_packet_number, this->_version, std::move(payload), len); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); +} + +QUICPacketUPtr +QUICPacketFactory::create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, + ats_unique_buf payload, size_t len, bool retransmittable, bool probing, + std::vector &frames) +{ + int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ONE_RTT); + QUICPacketNumber pn = this->_packet_number_generator[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, frames); +} + +QUICPacketUPtr +QUICPacketFactory::create_stateless_reset_packet(QUICConnectionId connection_id, QUICStatelessResetToken stateless_reset_token) +{ + std::random_device rnd; + + uint8_t random_packet_number = static_cast(rnd() & 0xFF); + size_t payload_len = static_cast((rnd() & 0xFF) | 16); // Mimimum length has to be 16 + ats_unique_buf payload = ats_unique_malloc(payload_len + 16); + uint8_t *naked_payload = payload.get(); + + // Generate random octets + for (int i = payload_len - 1; i >= 0; --i) { + naked_payload[i] = static_cast(rnd() & 0xFF); + } + // Copy stateless reset token into payload + memcpy(naked_payload + payload_len - 16, stateless_reset_token.buf(), 16); + + // 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)); +} + +QUICPacketUPtr +QUICPacketFactory::_create_unprotected_packet(QUICPacketHeaderUPtr header) +{ + ats_unique_buf cleartext = ats_unique_malloc(2048); + size_t cleartext_len = header->payload_size(); + + memcpy(cleartext.get(), header->payload(), cleartext_len); + QUICPacket *packet = quicPacketAllocator.alloc(); + new (packet) QUICPacket(std::move(header), std::move(cleartext), cleartext_len, false, false); + + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); +} + +QUICPacketUPtr +QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing, + std::vector &frames) +{ + // TODO: use pmtu of UnixNetVConnection + size_t max_cipher_txt_len = 2048; + ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); + size_t cipher_txt_len = 0; + + 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; + if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), + header->packet_number(), header->buf(), header->size(), header->key_phase())) { + packet = quicPacketAllocator.alloc(); + new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable, probing, frames); + } else { + QUICDebug(dcid, scid, "Failed to encrypt a packet"); + } + + return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); +} + +void +QUICPacketFactory::set_version(QUICVersion negotiated_version) +{ + this->_version = negotiated_version; +} + +void +QUICPacketFactory::set_hs_protocol(const QUICHandshakeProtocol *hs_protocol) +{ + this->_hs_protocol = hs_protocol; +} + +bool +QUICPacketFactory::is_ready_to_create_protected_packet() +{ + return this->_hs_protocol->is_handshake_finished(); +} + +void +QUICPacketFactory::reset() +{ + for (auto s : QUIC_PN_SPACES) { + this->_packet_number_generator[static_cast(s)].reset(); + } +} diff --git a/iocore/net/quic/QUICPacketFactory.h b/iocore/net/quic/QUICPacketFactory.h new file mode 100644 index 00000000000..b79b93187aa --- /dev/null +++ b/iocore/net/quic/QUICPacketFactory.h @@ -0,0 +1,83 @@ +/** @file + * + * QUIC packet factory + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICTypes.h" +#include "QUICPacket.h" + +class QUICPacketNumberGenerator +{ +public: + QUICPacketNumberGenerator(); + QUICPacketNumber next(); + void reset(); + +private: + std::atomic _current = 0; +}; + +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); + + QUICPacketUPtr create(IpEndpoint from, 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 retransmittable, bool probing, std::vector &frame, + 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, + bool retransmittable, bool probing, std::vector &frames); + QUICPacketUPtr 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, std::vector &frames); + QUICPacketUPtr create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, + ats_unique_buf payload, size_t len, bool retransmittable, bool probing, + std::vector &frames); + void set_version(QUICVersion negotiated_version); + + // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICCryptoInfoProvider or somethign instead. + // For now it receives a CONST pointer so PacketFactory cannot bother handshake. + void set_hs_protocol(const QUICHandshakeProtocol *hs_protocol); + + bool is_ready_to_create_protected_packet(); + void reset(); + +private: + QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; + const QUICHandshakeProtocol *_hs_protocol = nullptr; + // 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 retransmittable, bool probing, + std::vector &frames); +}; diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index ae6b5344c6d..255a2662dcf 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -22,6 +22,7 @@ */ #include "QUICPacketReceiveQueue.h" +#include "QUICPacketFactory.h" #include "QUICIntUtil.h" diff --git a/iocore/net/quic/QUICPacketReceiveQueue.h b/iocore/net/quic/QUICPacketReceiveQueue.h index a3518ff883a..5eccb8a0793 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.h +++ b/iocore/net/quic/QUICPacketReceiveQueue.h @@ -28,6 +28,8 @@ #include "QUICPacket.h" +class QUICPacketFactory; + class QUICPacketReceiveQueue { public: From dbbd4683d6c425946a0bbfa2b52312755fc3b297 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Feb 2019 17:22:31 +0900 Subject: [PATCH 1107/1313] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d7456bd5fc8..bbd2e18dd43 100644 --- a/.gitignore +++ b/.gitignore @@ -92,6 +92,7 @@ lib/perl/lib/Apache/TS.pm iocore/net/test_certlookup iocore/net/test_UDPNet iocore/net/quic/test_QUICAckFrameCreator +iocore/net/quic/test_QUICAddrVerifyState iocore/net/quic/test_QUICAltConnectionManager iocore/net/quic/test_QUICFlowController iocore/net/quic/test_QUICFrame @@ -104,6 +105,7 @@ iocore/net/quic/test_QUICInvariants iocore/net/quic/test_QUICKeyGenerator iocore/net/quic/test_QUICLossDetector iocore/net/quic/test_QUICPacket +iocore/net/quic/test_QUICPacketHeaderProtector iocore/net/quic/test_QUICPacketFactory iocore/net/quic/test_QUICStream iocore/net/quic/test_QUICStreamManager From 08843763757513761262500030a44f5fc1c3caf1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Feb 2019 17:36:36 +0900 Subject: [PATCH 1108/1313] Remove unused code --- iocore/net/QUICNetVConnection.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e68d5ea0595..70f05cd4abc 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -521,10 +521,6 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), this->_remote_flow_controller->current_limit()); this->_schedule_packet_write_ready(); - - break; - case QUICFrameType::PING: - // Nothing to do break; case QUICFrameType::DATA_BLOCKED: // DATA_BLOCKED frame is for debugging. Nothing to do here. From 59eab471bd3cf75248d88a7064074e294ec8e2f6 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 28 Jan 2019 17:50:36 +0800 Subject: [PATCH 1109/1313] QUIC: Refresh ack frame when previous ack_frame lost --- iocore/net/quic/QUICAckFrameCreator.cc | 16 +++++- iocore/net/quic/QUICAckFrameCreator.h | 3 +- .../net/quic/test/test_QUICAckFrameCreator.cc | 49 +++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 5f6df9a8205..a7ccd7c2cdc 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -104,6 +104,15 @@ QUICAckFrameManager::_on_frame_acked(QUICFrameInformationUPtr &info) this->_ack_creator[index]->forget(ack_info->largest_acknowledged); } +void +QUICAckFrameManager::_on_frame_lost(QUICFrameInformationUPtr &info) +{ + ink_assert(info->type == QUICFrameType::ACK); + int index = QUICTypeUtil::pn_space_index(info->level); + // when ack frame lost. Force to refresh the frame. + this->_ack_creator[index]->refresh_frame(true); +} + QUICFrameId QUICAckFrameManager::issue_frame_id() { @@ -131,8 +140,13 @@ QUICAckFrameManager::timer_fired() // QUICAckFrameManager::QUICAckFrameCreator // void -QUICAckFrameManager::QUICAckFrameCreator::refresh_frame() +QUICAckFrameManager::QUICAckFrameCreator::refresh_frame(bool force) { + if (force && !this->_packet_numbers.empty()) { + this->_available = true; + this->_should_send = true; + } + if (this->_available) { // make sure we have the new ack_frame to override the old one. this->_ack_frame = this->create_ack_frame(); diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 91e77f5cf43..f3d1072be67 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -57,7 +57,7 @@ class QUICAckFrameManager : public QUICFrameGenerator std::unique_ptr generate_ack_frame(uint16_t maximum_frame_size); // timer event handler, refresh _ack_frame; - void refresh_frame(); + void refresh_frame(bool force = false); QUICPacketNumber largest_ack_number(); ink_hrtime largest_ack_received_time(); @@ -112,6 +112,7 @@ class QUICAckFrameManager : public QUICFrameGenerator private: virtual void _on_frame_acked(QUICFrameInformationUPtr &info) override; + virtual void _on_frame_lost(QUICFrameInformationUPtr &info) override; /* * Returns QUICAckFrame only if ACK frame is able to be sent. diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index a02d0d91df4..47fa0edc862 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -286,3 +286,52 @@ TEST_CASE("QUICAckFrameManager_QUICAckFrameCreator", "[quic]") CHECK(packet_numbers.largest_ack_number() == 0); CHECK(packet_numbers.largest_ack_received_time() == 0); } + +TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") +{ + QUICAckFrameManager ack_manager; + QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; + + // Initial state + std::shared_ptr ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); + std::shared_ptr frame = std::static_pointer_cast(ack_frame); + CHECK(frame == nullptr); + + ack_manager.update(level, 2, 1, false); + ack_manager.update(level, 5, 1, false); + ack_manager.update(level, 6, 1, false); + ack_manager.update(level, 8, 1, false); + ack_manager.update(level, 9, 1, false); + + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); + CHECK(frame != nullptr); + CHECK(frame->ack_block_count() == 2); + CHECK(frame->largest_acknowledged() == 9); + CHECK(frame->ack_block_section()->first_ack_block() == 1); + CHECK(frame->ack_block_section()->begin()->gap() == 0); + + ack_manager.on_frame_lost(frame->id()); + CHECK(ack_manager.will_generate_frame(level) == true); + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); + CHECK(frame != nullptr); + CHECK(frame->ack_block_count() == 2); + CHECK(frame->largest_acknowledged() == 9); + CHECK(frame->ack_block_section()->first_ack_block() == 1); + CHECK(frame->ack_block_section()->begin()->gap() == 0); + + CHECK(ack_manager.will_generate_frame(level) == false); + ack_manager.on_frame_lost(frame->id()); + CHECK(ack_manager.will_generate_frame(level) == true); + ack_manager.update(level, 7, 1, false); + ack_manager.update(level, 4, 1, false); + + ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); + frame = std::static_pointer_cast(ack_frame); + CHECK(frame != nullptr); + CHECK(frame->ack_block_count() == 1); + CHECK(frame->largest_acknowledged() == 9); + CHECK(frame->ack_block_section()->first_ack_block() == 5); + CHECK(frame->ack_block_section()->begin()->gap() == 0); +} From 96f46c5ac6a039089ee1f62da3f7e536a11e9291 Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 30 Jan 2019 16:15:22 +0800 Subject: [PATCH 1110/1313] QUIC: Only generate ack frame in QUICFrameGenerator::generate_frame --- iocore/net/P_QUICNetVConnection.h | 1 - iocore/net/QUICNetVConnection.cc | 33 +++++---- iocore/net/quic/QUICAckFrameCreator.cc | 73 +++++++------------ iocore/net/quic/QUICAckFrameCreator.h | 14 ++-- .../net/quic/test/test_QUICAckFrameCreator.cc | 8 +- 5 files changed, 56 insertions(+), 73 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index b9f7590de63..13bd7b34086 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -305,7 +305,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _unschedule_ack_manager_periodic(); Event *_ack_manager_periodic = nullptr; - bool _refresh_ack_frame_manager(); uint64_t _maximum_stream_frame_data_size(); void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr &frame, diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 70f05cd4abc..c0e7c8cb2b4 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -619,7 +619,15 @@ QUICNetVConnection::state_handshake(int event, Event *data) break; } case QUIC_EVENT_ACK_PERIODIC: { - if (!this->_refresh_ack_frame_manager()) { + bool need_schedule = false; + for (auto level : QUIC_ENCRYPTION_LEVELS) { + if (this->_ack_frame_manager.will_generate_frame(level)) { + need_schedule = true; + break; + } + } + + if (!need_schedule) { break; } @@ -669,7 +677,15 @@ QUICNetVConnection::state_connection_established(int event, Event *data) break; } case QUIC_EVENT_ACK_PERIODIC: { - if (!this->_refresh_ack_frame_manager()) { + bool need_schedule = false; + for (auto level : QUIC_ENCRYPTION_LEVELS) { + if (this->_ack_frame_manager.will_generate_frame(level)) { + need_schedule = true; + break; + } + } + + if (!need_schedule) { break; } @@ -2177,19 +2193,6 @@ QUICNetVConnection::_handle_path_validation_timeout(Event *data) } } -bool -QUICNetVConnection::_refresh_ack_frame_manager() -{ - this->_ack_frame_manager.timer_fired(); - for (auto level : QUIC_PN_SPACES) { - if (this->_ack_frame_manager.will_generate_frame(level)) { - return true; - } - } - - return false; -} - // QUICFrameGenerator bool QUICNetVConnection::will_generate_frame(QUICEncryptionLevel level) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index a7ccd7c2cdc..b09250caefe 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -110,7 +110,7 @@ QUICAckFrameManager::_on_frame_lost(QUICFrameInformationUPtr &info) ink_assert(info->type == QUICFrameType::ACK); int index = QUICTypeUtil::pn_space_index(info->level); // when ack frame lost. Force to refresh the frame. - this->_ack_creator[index]->refresh_frame(true); + this->_ack_creator[index]->refresh_frame(); } QUICFrameId @@ -125,32 +125,20 @@ QUICAckFrameManager::ack_delay_exponent() const return this->_ack_delay_exponent; } -int -QUICAckFrameManager::timer_fired() -{ - for (auto level : QUIC_PN_SPACES) { - int index = QUICTypeUtil::pn_space_index(level); - this->_ack_creator[index]->refresh_frame(); - } - - return 0; -} - // // QUICAckFrameManager::QUICAckFrameCreator // void -QUICAckFrameManager::QUICAckFrameCreator::refresh_frame(bool force) +QUICAckFrameManager::QUICAckFrameCreator::refresh_frame() { - if (force && !this->_packet_numbers.empty()) { - this->_available = true; - this->_should_send = true; - } + QUICConfig::scoped_config params; - if (this->_available) { - // make sure we have the new ack_frame to override the old one. - this->_ack_frame = this->create_ack_frame(); + if (this->_packet_numbers.empty() || !this->_available) { + return; } + + // we have something to send + this->_should_send = true; } void @@ -167,7 +155,7 @@ QUICAckFrameManager::QUICAckFrameCreator::forget(QUICPacketNumber largest_acknow this->_available |= !(*it).ack_only; } - if (this->_packet_numbers.size() == 0 || !this->_available) { + if (this->_packet_numbers.empty() || !this->_available) { this->_should_send = false; } } @@ -186,11 +174,6 @@ QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_numb this->_latest_packet_received_time = Thread::get_hrtime(); } - // delay too much time - if (this->_latest_packet_received_time + params->max_ack_delay_in() <= Thread::get_hrtime()) { - this->_should_send = true; - } - // unorder packet should send ack immediately to accellerate the recovery if (this->_expect_next != packet_number) { this->_should_send = true; @@ -215,12 +198,9 @@ QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_numb this->_should_send = this->_available ? this->_should_send : false; } - this->_expect_next = packet_number + 1; + this->_has_new_data = true; + this->_expect_next = packet_number + 1; this->_packet_numbers.push_back({ack_only, packet_number}); - - if (this->_should_send && this->_available) { - this->_ack_frame = this->create_ack_frame(); - } } size_t @@ -262,18 +242,6 @@ QUICAckFrameManager::QUICAckFrameCreator::sort() std::unique_ptr QUICAckFrameManager::QUICAckFrameCreator::generate_ack_frame(uint16_t maximum_frame_size) -{ - std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); - if (this->_ack_frame && this->_ack_frame->size() <= maximum_frame_size) { - ack_frame = std::move(this->_ack_frame); - this->_ack_frame = nullptr; - } - - return ack_frame; -} - -std::unique_ptr -QUICAckFrameManager::QUICAckFrameCreator::create_ack_frame() { std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); if (!this->_available) { @@ -282,10 +250,11 @@ QUICAckFrameManager::QUICAckFrameCreator::create_ack_frame() } ack_frame = this->_create_ack_frame(); - if (ack_frame != nullptr) { - this->_available = false; + if (ack_frame == nullptr || ack_frame->size() < maximum_frame_size) { this->_should_send = false; this->_latest_packet_received_time = 0; + } else { + return QUICFrameFactory::create_null_ack_frame(); } return ack_frame; @@ -299,6 +268,8 @@ QUICAckFrameManager::QUICAckFrameCreator::_create_ack_frame() this->sort(); std::list &list = this->_packet_numbers; + this->_has_new_data = false; + uint8_t gap = 0; uint64_t length = 0; auto it = list.begin(); @@ -372,9 +343,17 @@ QUICAckFrameManager::QUICAckFrameCreator::available() const } bool -QUICAckFrameManager::QUICAckFrameCreator::is_ack_frame_ready() const +QUICAckFrameManager::QUICAckFrameCreator::is_ack_frame_ready() { - return this->_ack_frame != nullptr; + QUICConfig::scoped_config params; + + if (this->_available && this->_has_new_data && !this->_packet_numbers.empty() && + this->_latest_packet_received_time + params->max_ack_delay_in() <= Thread::get_hrtime()) { + // when we has new data and the data is available to send (not ack only). and we delay for too much time. Send it out + this->_should_send = true; + } + + return this->_should_send && this->_available && !this->_packet_numbers.empty(); } QUICAckFrameManager::QUICAckFrameCreator::QUICAckFrameCreator(QUICEncryptionLevel level, QUICAckFrameManager *ack_manager) diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index f3d1072be67..a9090fb5afd 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -50,14 +50,13 @@ class QUICAckFrameManager : public QUICFrameGenerator void sort(); void forget(QUICPacketNumber largest_acknowledged); bool available() const; - bool is_ack_frame_ready() const; - std::unique_ptr create_ack_frame(); + bool is_ack_frame_ready(); // Checks maximum_frame_size and return _ack_frame std::unique_ptr generate_ack_frame(uint16_t maximum_frame_size); // timer event handler, refresh _ack_frame; - void refresh_frame(bool force = false); + void refresh_frame(); QUICPacketNumber largest_ack_number(); ink_hrtime largest_ack_received_time(); @@ -67,16 +66,16 @@ class QUICAckFrameManager : public QUICFrameGenerator std::unique_ptr _create_ack_frame(); std::list _packet_numbers; - bool _available = false; - bool _should_send = false; + 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; QUICPacketNumber _largest_ack_number = 0; QUICPacketNumber _expect_next = 0; ink_hrtime _largest_ack_received_time = 0; ink_hrtime _latest_packet_received_time = 0; - std::unique_ptr _ack_frame = QUICFrameFactory::create_null_ack_frame(); - QUICAckFrameManager *_ack_manager = nullptr; + QUICAckFrameManager *_ack_manager = nullptr; QUICEncryptionLevel _level = QUICEncryptionLevel::NONE; }; @@ -106,7 +105,6 @@ class QUICAckFrameManager : public QUICFrameGenerator */ QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; - int timer_fired(); QUICFrameId issue_frame_id(); uint8_t ack_delay_exponent() const; diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 47fa0edc862..ccdaf3dbddf 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -177,7 +177,8 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") ack_manager.update(level, 0, 1, false); CHECK(ack_manager.will_generate_frame(level) == false); - ack_manager.timer_fired(); + sleep(1); + Thread::get_hrtime_updated(); CHECK(ack_manager.will_generate_frame(level) == true); } @@ -197,7 +198,8 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") ack_manager.update(level, 2, 1, false); // Delay due to some reason, the frame is not valued any more, but still valued - ack_manager.timer_fired(); + sleep(1); + Thread::get_hrtime_updated(); CHECK(ack_manager.will_generate_frame(level) == true); ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); frame = std::static_pointer_cast(ack_frame); @@ -334,4 +336,6 @@ TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") CHECK(frame->largest_acknowledged() == 9); CHECK(frame->ack_block_section()->first_ack_block() == 5); CHECK(frame->ack_block_section()->begin()->gap() == 0); + + CHECK(ack_manager.will_generate_frame(level) == false); } From 10e1056e29710562edb0f8d25b9350ceefff6766 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 1 Feb 2019 10:26:33 +0800 Subject: [PATCH 1111/1313] QUIC: Remove useless QUICConfig and rename resfresh_frame --- iocore/net/QUICNetVConnection.cc | 8 +++++--- iocore/net/quic/QUICAckFrameCreator.cc | 26 +++++++++++++++++--------- iocore/net/quic/QUICAckFrameCreator.h | 7 +++++-- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index c0e7c8cb2b4..7ef01c543eb 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -241,6 +241,7 @@ QUICNetVConnection::startEvent(int event, Event *e) void QUICNetVConnection::start() { + ink_release_assert(this->thread != nullptr); QUICConfig::scoped_config params; this->_five_tuple.update(this->local_addr, this->remote_addr, SOCK_DGRAM); @@ -250,12 +251,16 @@ QUICNetVConnection::start() this->_reset_token = QUICStatelessResetToken(this->_quic_connection_id, params->instance_id()); this->_hs_protocol = this->_setup_handshake_protocol(params->server_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol, this->_reset_token, params->stateless_retry()); + this->_ack_frame_manager.set_max_ack_delay(params->max_ack_delay_in()); + this->_ack_manager_periodic = this->thread->schedule_every(this, params->max_ack_delay_in(), QUIC_EVENT_ACK_PERIODIC); } else { this->_ack_frame_manager.set_ack_delay_exponent(params->ack_delay_exponent_out()); this->_hs_protocol = this->_setup_handshake_protocol(params->client_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol); this->_handshake_handler->start(&this->_packet_factory, params->vn_exercise_enabled()); this->_handshake_handler->do_handshake(); + this->_ack_frame_manager.set_max_ack_delay(params->max_ack_delay_out()); + this->_ack_manager_periodic = this->thread->schedule_every(this, params->max_ack_delay_out(), QUIC_EVENT_ACK_PERIODIC); } this->_application_map = new QUICApplicationMap(); @@ -281,9 +286,6 @@ 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); - - ink_release_assert(this->thread != nullptr); - this->_ack_manager_periodic = this->thread->schedule_every(this, params->max_ack_delay_in(), QUIC_EVENT_ACK_PERIODIC); } void diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index b09250caefe..910c3b9e956 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -110,7 +110,7 @@ QUICAckFrameManager::_on_frame_lost(QUICFrameInformationUPtr &info) ink_assert(info->type == QUICFrameType::ACK); int index = QUICTypeUtil::pn_space_index(info->level); // when ack frame lost. Force to refresh the frame. - this->_ack_creator[index]->refresh_frame(); + this->_ack_creator[index]->refresh_state(); } QUICFrameId @@ -125,14 +125,20 @@ QUICAckFrameManager::ack_delay_exponent() const return this->_ack_delay_exponent; } +void +QUICAckFrameManager::set_max_ack_delay(uint16_t delay) +{ + for (auto level : QUIC_PN_SPACES) { + this->_ack_creator[static_cast(level)]->set_max_ack_delay(delay); + } +} + // // QUICAckFrameManager::QUICAckFrameCreator // void -QUICAckFrameManager::QUICAckFrameCreator::refresh_frame() +QUICAckFrameManager::QUICAckFrameCreator::refresh_state() { - QUICConfig::scoped_config params; - if (this->_packet_numbers.empty() || !this->_available) { return; } @@ -163,8 +169,6 @@ QUICAckFrameManager::QUICAckFrameCreator::forget(QUICPacketNumber largest_acknow void QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_number, size_t size, bool ack_only) { - QUICConfig::scoped_config params; - if (packet_number == 0 || packet_number > this->_largest_ack_number) { this->_largest_ack_received_time = Thread::get_hrtime(); this->_largest_ack_number = packet_number; @@ -345,10 +349,8 @@ QUICAckFrameManager::QUICAckFrameCreator::available() const bool QUICAckFrameManager::QUICAckFrameCreator::is_ack_frame_ready() { - QUICConfig::scoped_config params; - if (this->_available && this->_has_new_data && !this->_packet_numbers.empty() && - this->_latest_packet_received_time + params->max_ack_delay_in() <= Thread::get_hrtime()) { + this->_latest_packet_received_time + this->_max_ack_delay * HRTIME_MSECOND <= Thread::get_hrtime()) { // when we has new data and the data is available to send (not ack only). and we delay for too much time. Send it out this->_should_send = true; } @@ -356,6 +358,12 @@ QUICAckFrameManager::QUICAckFrameCreator::is_ack_frame_ready() return this->_should_send && this->_available && !this->_packet_numbers.empty(); } +void +QUICAckFrameManager::QUICAckFrameCreator::set_max_ack_delay(uint16_t delay) +{ + this->_max_ack_delay = delay; +} + QUICAckFrameManager::QUICAckFrameCreator::QUICAckFrameCreator(QUICEncryptionLevel level, QUICAckFrameManager *ack_manager) : _ack_manager(ack_manager), _level(level) { diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index a9090fb5afd..1920d6c034a 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -51,12 +51,13 @@ class QUICAckFrameManager : public QUICFrameGenerator void forget(QUICPacketNumber largest_acknowledged); bool available() const; bool is_ack_frame_ready(); + void set_max_ack_delay(uint16_t delay); // Checks maximum_frame_size and return _ack_frame std::unique_ptr generate_ack_frame(uint16_t maximum_frame_size); - // timer event handler, refresh _ack_frame; - void refresh_frame(); + // refresh state when frame lost + void refresh_state(); QUICPacketNumber largest_ack_number(); ink_hrtime largest_ack_received_time(); @@ -70,6 +71,7 @@ class QUICAckFrameManager : public QUICFrameGenerator 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; + uint16_t _max_ack_delay = 25; QUICPacketNumber _largest_ack_number = 0; QUICPacketNumber _expect_next = 0; ink_hrtime _largest_ack_received_time = 0; @@ -86,6 +88,7 @@ class QUICAckFrameManager : public QUICFrameGenerator ~QUICAckFrameManager(); void set_ack_delay_exponent(uint8_t ack_delay_exponent); + void set_max_ack_delay(uint16_t delay); void set_force_to_send(bool on = true); bool force_to_send() const; From 6a057e7d813ce0d2e17dc40abf5d3395f9faa7e7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Feb 2019 16:38:51 +0900 Subject: [PATCH 1112/1313] Use QUICFrameGenerators interface instead of using individual classes --- iocore/net/P_QUICNetVConnection.h | 2 + iocore/net/QUICNetVConnection.cc | 160 +++++++++------------------ iocore/net/quic/QUICFrame.cc | 12 ++ iocore/net/quic/QUICFrame.h | 2 + iocore/net/quic/QUICHandshake.cc | 3 + iocore/net/quic/QUICPathValidator.cc | 3 + iocore/net/quic/QUICPinger.cc | 16 ++- iocore/net/quic/QUICPinger.h | 5 +- 8 files changed, 88 insertions(+), 115 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 13bd7b34086..6aac61b3f1e 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -276,6 +276,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICAltConnectionManager *_alt_con_manager = nullptr; QUICPathValidator *_path_validator = nullptr; + std::vector _frame_generators; + QUICPacketReceiveQueue _packet_recv_queue = {this->_packet_factory, this->_ph_protector}; QUICConnectionErrorUPtr _connection_error = nullptr; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 7ef01c543eb..d5d940d0d77 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -282,6 +282,17 @@ QUICNetVConnection::start() this->_path_validator = new QUICPathValidator(); this->_stream_manager = new QUICStreamManager(this, &this->_rtt_measure, this->_application_map); + // Register frame generators + this->_frame_generators.push_back(this->_handshake_handler); // CRYPTO + this->_frame_generators.push_back(this->_path_validator); // PATH_CHALLENGE, PATH_RESPOSNE + this->_frame_generators.push_back(this->_local_flow_controller); // MAX_DATA + this->_frame_generators.push_back(this->_remote_flow_controller); // DATA_BLOCKED + this->_frame_generators.push_back(this); // NEW_TOKEN + this->_frame_generators.push_back(this->_stream_manager); // STREAM, MAX_STREAM_DATA, STREAM_DATA_BLOCKED + this->_frame_generators.push_back(&this->_ack_frame_manager); // ACK + this->_frame_generators.push_back(&this->_pinger); // PING + + // Register frame handlers this->_frame_dispatcher->add_handler(this); this->_frame_dispatcher->add_handler(this->_stream_manager); this->_frame_dispatcher->add_handler(this->_path_validator); @@ -492,7 +503,7 @@ QUICNetVConnection::handle_received_packet(UDPPacket *packet) void QUICNetVConnection::ping() { - this->_pinger.trigger(QUICEncryptionLevel::ONE_RTT); + this->_pinger.request(QUICEncryptionLevel::ONE_RTT); } void @@ -996,6 +1007,7 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, params->instance_id(), params->num_alt_connection_ids(), params->preferred_address()); + this->_frame_generators.push_back(this->_alt_con_manager); this->_frame_dispatcher->add_handler(this->_alt_con_manager); } error = this->_handshake_handler->start(packet.get(), &this->_packet_factory, this->_alt_con_manager->preferred_address()); @@ -1354,125 +1366,56 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); std::vector frames; - // CRYPTO - frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); - while (frame) { - ++frame_count; - probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, frame, frames); - frame = this->_handshake_handler->generate_frame(level, UINT16_MAX, max_frame_size); + if (this->_has_ack_only_packet_out) { + // Sent too much ack_only packet. At this moment we need to packetize a ping frame + // to force peer send ack frame. + this->_pinger.request(level); } - // NEW_TOKEN - frame = this->generate_frame(level, UINT16_MAX, max_frame_size); - if (frame) { - ++frame_count; - probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, frame, frames); - } - - // PATH_CHALLENGE, PATH_RESPOSNE - frame = this->_path_validator->generate_frame(level, UINT16_MAX, max_frame_size); - if (frame) { - ++frame_count; - probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, frame, frames); - } - - // NEW_CONNECTION_ID - if (this->_alt_con_manager) { - frame = this->_alt_con_manager->generate_frame(level, UINT16_MAX, max_frame_size); - while (frame) { - ++frame_count; - probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, frame, frames); - - frame = this->_alt_con_manager->generate_frame(level, UINT16_MAX, max_frame_size); - } - } - - // MAX_DATA - frame = this->_local_flow_controller->generate_frame(level, UINT16_MAX, max_frame_size); - if (frame) { - ++frame_count; - probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, frame, frames); - } - - // DATA_BLOCKED - if (this->_remote_flow_controller->credit() == 0 && this->_stream_manager->will_generate_frame(level)) { - frame = this->_remote_flow_controller->generate_frame(level, UINT16_MAX, max_frame_size); - if (frame) { - ++frame_count; - probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, frame, frames); - } - } - - // STREAM, MAX_STREAM_DATA, STREAM_DATA_BLOCKED - if (!this->_path_validator->is_validating()) { - frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); - while (frame) { - ++frame_count; - probing |= frame->is_probing_frame(); - if (frame->type() == QUICFrameType::STREAM) { - int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); - QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), - this->_remote_flow_controller->current_limit()); - ink_assert(ret == 0); + bool ack_only = true; + for (auto g : this->_frame_generators) { + while (g->will_generate_frame(level)) { + // FIXME will_generate_frame should receive more parameters so we don't need extra checks + if (g == this->_remote_flow_controller && !this->_stream_manager->will_generate_frame(level)) { + break; } - this->_store_frame(buf, len, max_frame_size, frame, frames); - - if (++this->_stream_frames_sent % MAX_CONSECUTIVE_STREAMS == 0) { + if (g == this->_stream_manager && this->_path_validator->is_validating()) { break; } - frame = this->_stream_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); - } - } + // Common block + frame = g->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + if (frame) { + ++frame_count; + probing |= frame->is_probing_frame(); + if (frame->is_flow_controlled()) { + int ret = this->_remote_flow_controller->update(this->_stream_manager->total_offset_sent()); + QUICFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller->current_offset(), + this->_remote_flow_controller->current_limit()); + ink_assert(ret == 0); + } + this->_store_frame(buf, len, max_frame_size, frame, frames); - // ACK - if (frame_count == 0) { - if (this->_ack_frame_manager.will_generate_frame(level)) { - frame = this->_ack_frame_manager.generate_frame(level, UINT16_MAX, max_frame_size); - } - } else { - frame = this->_ack_frame_manager.generate_frame(level, UINT16_MAX, max_frame_size); - } + // FIXME ACK frame should have priority + if (frame->type() == QUICFrameType::STREAM) { + if (++this->_stream_frames_sent % MAX_CONSECUTIVE_STREAMS == 0) { + break; + } + } - bool ack_only = false; - if (frame != nullptr) { - if (frame_count == 0) { - ack_only = true; - } - ++frame_count; - probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, frame, frames); - } + if (ack_only && frame->type() != QUICFrameType::ACK) { + ack_only = false; + this->_pinger.cancel(level); + } - QUICConfig::scoped_config params; - if (ack_only) { - if (this->_has_ack_only_packet_out) { - // Sent too much ack_only packet. At this moment we need to packetize a ping frame - // to force peer send ack frame. - // Just call trigger to not send multiple PING frames, because application could request sending PING. - this->_pinger.trigger(level); - } else { - this->_has_ack_only_packet_out = true; + } else { + // Move to next generator + break; + } } - } else if (!ack_only) { - this->_has_ack_only_packet_out = false; } - // PING - frame = this->_pinger.generate_frame(level, UINT16_MAX, max_frame_size); - if (frame) { - ++frame_count; - ack_only = false; - this->_has_ack_only_packet_out = false; - probing |= frame->is_probing_frame(); - this->_store_frame(buf, len, max_frame_size, frame, frames); - } + this->_has_ack_only_packet_out = ack_only; // Schedule a packet if (len != 0) { @@ -1926,6 +1869,7 @@ QUICNetVConnection::_switch_to_established_state() pref_addr_buf = remote_tp->getAsBytes(QUICTransportParameterId::PREFERRED_ADDRESS, len); this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, params->instance_id(), 1, {pref_addr_buf, len}); + this->_frame_generators.push_back(this->_alt_con_manager); this->_frame_dispatcher->add_handler(this->_alt_con_manager); } } else { diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 3530fe19b8a..a32a9d37274 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -84,6 +84,12 @@ QUICFrame::is_probing_frame() const return false; } +bool +QUICFrame::is_flow_controlled() const +{ + return false; +} + QUICFrameId QUICFrame::id() const { @@ -250,6 +256,12 @@ QUICStreamFrame::size() const return size; } +bool +QUICStreamFrame::is_flow_controlled() const +{ + return true; +} + size_t QUICStreamFrame::store(uint8_t *buf, size_t *len, size_t limit) const { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 7b7a1a93edc..94002a268ae 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -62,6 +62,7 @@ class QUICFrame virtual QUICFrameType type() const; virtual size_t size() const = 0; virtual bool is_probing_frame() const; + virtual bool is_flow_controlled() const; virtual size_t store(uint8_t *buf, size_t *len, 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){}; @@ -94,6 +95,7 @@ class QUICStreamFrame : public QUICFrame QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; + virtual bool is_flow_controlled() const override; virtual size_t store(uint8_t *buf, size_t *len, 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) override; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index cde0495f659..51349dec341 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -351,6 +351,9 @@ QUICHandshake::generate_frame(QUICEncryptionLevel level, uint64_t connection_cre { QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + // CRYPTO frame is not flow-controlled + connection_credit = UINT64_MAX; + if (!this->_is_level_matched(level)) { return frame; } diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index 8cac22a191a..40e2d140d58 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -131,6 +131,9 @@ QUICPathValidator::generate_frame(QUICEncryptionLevel level, uint64_t connection { QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + // PATH_CHALLENGE and PATH_RESPONSE are not flow-controlled + connection_credit = UINT64_MAX; + if (!this->_is_level_matched(level)) { return frame; } diff --git a/iocore/net/quic/QUICPinger.cc b/iocore/net/quic/QUICPinger.cc index a559b7d9db3..c34e820fec3 100644 --- a/iocore/net/quic/QUICPinger.cc +++ b/iocore/net/quic/QUICPinger.cc @@ -24,15 +24,21 @@ #include "QUICPinger.h" void -QUICPinger::trigger(QUICEncryptionLevel level) +QUICPinger::request(QUICEncryptionLevel level) { - this->_need_to_fire[static_cast(level)] = true; + ++this->_need_to_fire[static_cast(level)]; +} + +void +QUICPinger::cancel(QUICEncryptionLevel level) +{ + --this->_need_to_fire[static_cast(level)]; } bool QUICPinger::will_generate_frame(QUICEncryptionLevel level) { - return this->_need_to_fire[QUICTypeUtil::pn_space_index(level)]; + return this->_need_to_fire[QUICTypeUtil::pn_space_index(level)] > 0; } QUICFrameUPtr @@ -44,10 +50,10 @@ QUICPinger::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit return frame; } - if (this->_need_to_fire[static_cast(level)] && maximum_frame_size > 0) { + if (this->_need_to_fire[static_cast(level)] > 0 && maximum_frame_size > 0) { // don't care ping frame lost or acked frame = QUICFrameFactory::create_ping_frame(0, nullptr); - this->_need_to_fire[static_cast(level)] = false; + this->_need_to_fire[static_cast(level)] = 0; } return frame; diff --git a/iocore/net/quic/QUICPinger.h b/iocore/net/quic/QUICPinger.h index 8f06b1d1e7d..6658eb24083 100644 --- a/iocore/net/quic/QUICPinger.h +++ b/iocore/net/quic/QUICPinger.h @@ -33,7 +33,8 @@ class QUICPinger : public QUICFrameGenerator public: QUICPinger() {} - void trigger(QUICEncryptionLevel level); + void request(QUICEncryptionLevel level); + void cancel(QUICEncryptionLevel level); // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; @@ -41,7 +42,7 @@ class QUICPinger : public QUICFrameGenerator private: // Initial, 0/1-RTT, and Handshake - bool _need_to_fire[4] = {false}; + uint64_t _need_to_fire[4] = {0}; // QUICFrameGenerator std::vector From 57ce5d89416e07174516f4775053ff8cad01114a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 7 Feb 2019 12:09:55 +0900 Subject: [PATCH 1113/1313] Remove a mutex for frame transmitter We had frame transmitter but it was removed at some point. --- iocore/net/P_QUICNetVConnection.h | 1 - iocore/net/QUICNetVConnection.cc | 4 ---- 2 files changed, 5 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 6aac61b3f1e..8e7481473e8 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -337,7 +337,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICConnectionErrorUPtr _state_closing_send_packet(); Ptr _packet_transmitter_mutex; - Ptr _frame_transmitter_mutex; void _init_flow_control_params(const std::shared_ptr &local_tp, const std::shared_ptr &remote_tp); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index d5d940d0d77..f7146cc52e7 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -93,7 +93,6 @@ QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_ci { SET_HANDLER((NetVConnHandler)&QUICNetVConnection::startEvent); this->_packet_transmitter_mutex = new_ProxyMutex(); - this->_frame_transmitter_mutex = new_ProxyMutex(); this->_udp_con = udp_con; this->_packet_handler = packet_handler; this->_peer_quic_connection_id = peer_cid; @@ -119,7 +118,6 @@ QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_ci { SET_HANDLER((NetVConnHandler)&QUICNetVConnection::acceptEvent); this->_packet_transmitter_mutex = new_ProxyMutex(); - this->_frame_transmitter_mutex = new_ProxyMutex(); this->_udp_con = udp_con; this->_packet_handler = packet_handler; this->_peer_quic_connection_id = peer_cid; @@ -1363,7 +1361,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa QUICFrameUPtr frame(nullptr, nullptr); SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); - SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); std::vector frames; if (this->_has_ack_only_packet_out) { @@ -1452,7 +1449,6 @@ void QUICNetVConnection::_packetize_closing_frame() { SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); - SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread()); if (this->_connection_error == nullptr || this->_the_final_packet) { return; From e319305aa7bbfeded37fe5ad7cf244505c266e83 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 8 Feb 2019 11:43:03 +0900 Subject: [PATCH 1114/1313] Fix eternal PING bug --- iocore/net/QUICNetVConnection.cc | 3 +++ iocore/net/quic/QUICPinger.cc | 4 +++- iocore/net/quic/QUICPinger.h | 3 --- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index f7146cc52e7..811d7e1cb51 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1411,6 +1411,9 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } } } + if (frame_count == 0) { + ack_only = false; + } this->_has_ack_only_packet_out = ack_only; diff --git a/iocore/net/quic/QUICPinger.cc b/iocore/net/quic/QUICPinger.cc index c34e820fec3..01917c4426f 100644 --- a/iocore/net/quic/QUICPinger.cc +++ b/iocore/net/quic/QUICPinger.cc @@ -32,7 +32,9 @@ QUICPinger::request(QUICEncryptionLevel level) void QUICPinger::cancel(QUICEncryptionLevel level) { - --this->_need_to_fire[static_cast(level)]; + if (this->_need_to_fire[static_cast(level)] > 0) { + --this->_need_to_fire[static_cast(level)]; + } } bool diff --git a/iocore/net/quic/QUICPinger.h b/iocore/net/quic/QUICPinger.h index 6658eb24083..7251723d760 100644 --- a/iocore/net/quic/QUICPinger.h +++ b/iocore/net/quic/QUICPinger.h @@ -49,9 +49,6 @@ class QUICPinger : public QUICFrameGenerator _encryption_level_filter() override { return { - QUICEncryptionLevel::INITIAL, - QUICEncryptionLevel::ZERO_RTT, - QUICEncryptionLevel::HANDSHAKE, QUICEncryptionLevel::ONE_RTT, }; } From 9a34336e4bcf77a096049b1e8db3da1110ce6cd5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 8 Feb 2019 11:45:36 +0900 Subject: [PATCH 1115/1313] Remove QUICFrame allocators --- iocore/net/P_QUICNetVConnection.h | 5 +- iocore/net/QUICNetVConnection.cc | 33 +- iocore/net/quic/QUICAckFrameCreator.cc | 31 +- iocore/net/quic/QUICAckFrameCreator.h | 9 +- iocore/net/quic/QUICAltConnectionManager.cc | 13 +- iocore/net/quic/QUICAltConnectionManager.h | 3 +- iocore/net/quic/QUICFlowController.cc | 55 ++- iocore/net/quic/QUICFlowController.h | 19 +- iocore/net/quic/QUICFrame.cc | 514 +++++++------------- iocore/net/quic/QUICFrame.h | 305 +++--------- iocore/net/quic/QUICFrameDispatcher.cc | 15 +- iocore/net/quic/QUICFrameGenerator.h | 10 +- iocore/net/quic/QUICFrameRetransmitter.cc | 38 +- iocore/net/quic/QUICFrameRetransmitter.h | 12 +- iocore/net/quic/QUICHandshake.cc | 16 +- iocore/net/quic/QUICHandshake.h | 3 +- iocore/net/quic/QUICIncomingFrameBuffer.cc | 38 +- iocore/net/quic/QUICIncomingFrameBuffer.h | 10 +- iocore/net/quic/QUICPathValidator.cc | 17 +- iocore/net/quic/QUICPathValidator.h | 3 +- iocore/net/quic/QUICPinger.cc | 8 +- iocore/net/quic/QUICPinger.h | 3 +- iocore/net/quic/QUICStream.cc | 48 +- iocore/net/quic/QUICStream.h | 6 +- iocore/net/quic/QUICStreamManager.cc | 12 +- iocore/net/quic/QUICStreamManager.h | 3 +- 26 files changed, 461 insertions(+), 768 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 8e7481473e8..55a4c8af2bd 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -224,7 +224,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) override; int in_closed_queue = 0; @@ -309,7 +310,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub Event *_ack_manager_periodic = nullptr; uint64_t _maximum_stream_frame_data_size(); - void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr &frame, + void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrame &frame, std::vector &frames); QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size); void _packetize_closing_frame(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 811d7e1cb51..2460a08b5ef 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1318,11 +1318,11 @@ QUICNetVConnection::_state_closing_send_packet() } void -QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrameUPtr &frame, +QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrame &frame, std::vector &frames) { size_t l = 0; - frame->store(buf.get() + offset, &l, max_frame_size); + frame.store(buf.get() + offset, &l, max_frame_size); // frame should be stored because it's created with max_frame_size ink_assert(l != 0); @@ -1332,11 +1332,11 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t & if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) { char msg[1024]; - frame->debug_msg(msg, sizeof(msg)); + frame.debug_msg(msg, sizeof(msg)); QUICConDebug("[TX] %s", msg); } - frames.emplace_back(frame->id(), frame->generated_by()); + frames.emplace_back(frame.id(), frame.generated_by()); } QUICPacketUPtr @@ -1358,7 +1358,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa int frame_count = 0; size_t len = 0; ats_unique_buf buf = ats_unique_malloc(max_packet_size); - QUICFrameUPtr frame(nullptr, nullptr); SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); std::vector frames; @@ -1370,6 +1369,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } bool ack_only = true; + uint8_t frame_instance_buffer[1024]; // This is for a frame instance but not serialized frame data + QUICFrame *frame = nullptr; for (auto g : this->_frame_generators) { while (g->will_generate_frame(level)) { // FIXME will_generate_frame should receive more parameters so we don't need extra checks @@ -1381,7 +1382,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } // Common block - frame = g->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size); + frame = g->generate_frame(frame_instance_buffer, level, this->_remote_flow_controller->credit(), max_frame_size); if (frame) { ++frame_count; probing |= frame->is_probing_frame(); @@ -1391,7 +1392,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa this->_remote_flow_controller->current_limit()); ink_assert(ret == 0); } - this->_store_frame(buf, len, max_frame_size, frame, frames); + this->_store_frame(buf, len, max_frame_size, *frame, frames); // FIXME ACK frame should have priority if (frame->type() == QUICFrameType::STREAM) { @@ -1405,6 +1406,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa this->_pinger.cancel(level); } + frame->~QUICFrame(); } else { // Move to next generator break; @@ -1457,10 +1459,11 @@ QUICNetVConnection::_packetize_closing_frame() return; } - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrame *frame = nullptr; // CONNECTION_CLOSE - frame = QUICFrameFactory::create_connection_close_frame(*this->_connection_error); + uint8_t frame_buf[1024]; + frame = QUICFrameFactory::create_connection_close_frame(frame_buf, *this->_connection_error); uint32_t max_size = this->maximum_quic_packet_size(); ats_unique_buf buf = ats_unique_malloc(max_size); @@ -1468,7 +1471,7 @@ QUICNetVConnection::_packetize_closing_frame() size_t len = 0; uint64_t max_frame_size = static_cast(max_size); std::vector frames; - this->_store_frame(buf, len, max_frame_size, frame, frames); + this->_store_frame(buf, len, max_frame_size, *frame, frames); QUICEncryptionLevel level = this->_hs_protocol->current_encryption_level(); ink_assert(level != QUICEncryptionLevel::ZERO_RTT); @@ -2149,10 +2152,10 @@ QUICNetVConnection::will_generate_frame(QUICEncryptionLevel level) return !this->_is_resumption_token_sent; } -QUICFrameUPtr -QUICNetVConnection::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICFrame * +QUICNetVConnection::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrame *frame = nullptr; if (!this->_is_level_matched(level)) { return frame; @@ -2164,13 +2167,13 @@ QUICNetVConnection::generate_frame(QUICEncryptionLevel level, uint64_t connectio // TODO Make expiration period configurable QUICResumptionToken token(this->get_remote_endpoint(), this->connection_id(), Thread::get_hrtime() + HRTIME_HOURS(24)); - frame = QUICFrameFactory::create_new_token_frame(token, this->_issue_frame_id(), this); + frame = QUICFrameFactory::create_new_token_frame(buf, token, this->_issue_frame_id(), this); if (frame) { if (frame->size() < maximum_frame_size) { this->_is_resumption_token_sent = true; } else { // Cancel generating frame - frame = QUICFrameFactory::create_null_frame(); + frame = nullptr; } } diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 910c3b9e956..6f634c50e33 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -57,10 +57,11 @@ QUICAckFrameManager::update(QUICEncryptionLevel level, QUICPacketNumber packet_n return 0; } -QUICFrameUPtr -QUICAckFrameManager::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICFrame * +QUICAckFrameManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) { - std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); + QUICAckFrame *ack_frame = nullptr; if (!this->_is_level_matched(level) || level == QUICEncryptionLevel::ZERO_RTT) { return ack_frame; @@ -68,7 +69,7 @@ QUICAckFrameManager::generate_frame(QUICEncryptionLevel level, uint64_t connecti int index = QUICTypeUtil::pn_space_index(level); auto &ack_creator = this->_ack_creator[index]; - ack_frame = ack_creator->generate_ack_frame(maximum_frame_size); + ack_frame = ack_creator->generate_ack_frame(buf, maximum_frame_size); if (ack_frame != nullptr) { QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); @@ -244,31 +245,31 @@ QUICAckFrameManager::QUICAckFrameCreator::sort() this->_packet_numbers.sort([](const RecvdPacket &a, const RecvdPacket &b) -> bool { return a.packet_number > b.packet_number; }); } -std::unique_ptr -QUICAckFrameManager::QUICAckFrameCreator::generate_ack_frame(uint16_t maximum_frame_size) +QUICAckFrame * +QUICAckFrameManager::QUICAckFrameCreator::generate_ack_frame(uint8_t *buf, uint16_t maximum_frame_size) { - std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); + QUICAckFrame *ack_frame = nullptr; if (!this->_available) { this->_should_send = false; return ack_frame; } - ack_frame = this->_create_ack_frame(); + ack_frame = this->_create_ack_frame(buf); if (ack_frame == nullptr || ack_frame->size() < maximum_frame_size) { this->_should_send = false; this->_latest_packet_received_time = 0; } else { - return QUICFrameFactory::create_null_ack_frame(); + return nullptr; } return ack_frame; } -std::unique_ptr -QUICAckFrameManager::QUICAckFrameCreator::_create_ack_frame() +QUICAckFrame * +QUICAckFrameManager::QUICAckFrameCreator::_create_ack_frame(uint8_t *buf) { ink_assert(this->_packet_numbers.size() > 0); - std::unique_ptr ack_frame = QUICFrameFactory::create_null_ack_frame(); + QUICAckFrame *ack_frame = nullptr; this->sort(); std::list &list = this->_packet_numbers; @@ -307,8 +308,8 @@ QUICAckFrameManager::QUICAckFrameCreator::_create_ack_frame() ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { uint64_t delay = this->_calculate_delay(); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_ack_manager->issue_frame_id(), - this->_ack_manager); + ack_frame = QUICFrameFactory::create_ack_frame(buf, largest_ack_number, delay, length - 1, + this->_ack_manager->issue_frame_id(), this->_ack_manager); } gap = last_ack_number - pn; @@ -320,7 +321,7 @@ QUICAckFrameManager::QUICAckFrameCreator::_create_ack_frame() ack_frame->ack_block_section()->add_ack_block({static_cast(gap - 1), length - 1}); } else { uint64_t delay = this->_calculate_delay(); - ack_frame = QUICFrameFactory::create_ack_frame(largest_ack_number, delay, length - 1, this->_ack_manager->issue_frame_id(), + ack_frame = QUICFrameFactory::create_ack_frame(buf, largest_ack_number, delay, length - 1, this->_ack_manager->issue_frame_id(), this->_ack_manager); } diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 1920d6c034a..2f88649c426 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -54,7 +54,7 @@ class QUICAckFrameManager : public QUICFrameGenerator void set_max_ack_delay(uint16_t delay); // Checks maximum_frame_size and return _ack_frame - std::unique_ptr generate_ack_frame(uint16_t maximum_frame_size); + QUICAckFrame *generate_ack_frame(uint8_t *buf, uint16_t maximum_frame_size); // refresh state when frame lost void refresh_state(); @@ -64,7 +64,7 @@ class QUICAckFrameManager : public QUICFrameGenerator private: uint64_t _calculate_delay(); - std::unique_ptr _create_ack_frame(); + QUICAckFrame *_create_ack_frame(uint8_t *buf); std::list _packet_numbers; bool _available = false; // packet_number has data to sent @@ -106,7 +106,8 @@ class QUICAckFrameManager : public QUICFrameGenerator /* * Calls create directly. */ - QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) override; QUICFrameId issue_frame_id(); uint8_t ack_delay_exponent() const; @@ -119,7 +120,7 @@ class QUICAckFrameManager : public QUICFrameGenerator * Returns QUICAckFrame only if ACK frame is able to be sent. * Caller must send the ACK frame to the peer if it was returned. */ - std::unique_ptr _create_ack_frame(QUICEncryptionLevel level); + QUICAckFrame *_create_ack_frame(uint8_t *buf, QUICEncryptionLevel level); uint64_t _calculate_delay(QUICEncryptionLevel level); std::vector _encryption_level_filter() override diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 20343b9b506..ad05d8de453 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -260,10 +260,11 @@ QUICAltConnectionManager::will_generate_frame(QUICEncryptionLevel level) return this->_need_advertise || !this->_retired_seq_nums.empty(); } -QUICFrameUPtr -QUICAltConnectionManager::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICFrame * +QUICAltConnectionManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) { - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrame *frame = nullptr; if (!this->_is_level_matched(level)) { return frame; } @@ -272,13 +273,13 @@ QUICAltConnectionManager::generate_frame(QUICEncryptionLevel level, uint64_t con int count = this->_nids; for (int i = 0; i < count; ++i) { if (!this->_alt_quic_connection_ids_local[i].advertised) { - frame = QUICFrameFactory::create_new_connection_id_frame(this->_alt_quic_connection_ids_local[i].seq_num, + frame = QUICFrameFactory::create_new_connection_id_frame(buf, this->_alt_quic_connection_ids_local[i].seq_num, this->_alt_quic_connection_ids_local[i].id, this->_alt_quic_connection_ids_local[i].token); if (frame && frame->size() > maximum_frame_size) { // Cancel generating frame - frame = QUICFrameFactory::create_null_frame(); + frame = nullptr; } else { this->_alt_quic_connection_ids_local[i].advertised = true; } @@ -292,7 +293,7 @@ QUICAltConnectionManager::generate_frame(QUICEncryptionLevel level, uint64_t con if (!this->_retired_seq_nums.empty()) { if (auto s = this->_retired_seq_nums.front()) { - frame = QUICFrameFactory::create_retire_connection_id_frame(s); + frame = QUICFrameFactory::create_retire_connection_id_frame(buf, s); this->_records_retire_connection_id_frame(level, static_cast(*frame)); this->_retired_seq_nums.pop(); return frame; diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index 85579c47302..de495278a2f 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -83,7 +83,8 @@ class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenera // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) override; private: struct AltConnectionInfo { diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index e5162ac6239..03a685a14a4 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -102,21 +102,23 @@ QUICFlowController::will_generate_frame(QUICEncryptionLevel level) return false; } - return this->_frame != nullptr; + return this->_should_create_frame; } -QUICFrameUPtr -QUICFlowController::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICFrame * +QUICFlowController::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrame *frame = nullptr; if (!this->_is_level_matched(level)) { return frame; } - if (this->_frame && this->_frame->size() <= maximum_frame_size) { - frame = std::move(this->_frame); - this->_frame = nullptr; + if (this->_should_create_frame) { + frame = this->_create_frame(buf); + if (frame && frame->size() <= maximum_frame_size) { + this->_should_create_frame = false; + } } return frame; @@ -129,8 +131,8 @@ void QUICRemoteFlowController::forward_limit(QUICOffset new_limit) { QUICFlowController::forward_limit(new_limit); - this->_blocked = false; - this->_frame = nullptr; + this->_blocked = false; + this->_should_create_frame = false; } int @@ -141,8 +143,8 @@ QUICRemoteFlowController::update(QUICOffset offset) // Create BLOCKED(_STREAM) frame // The frame will be sent if stream has something to send. if (offset >= this->_limit) { - this->_frame = this->_create_frame(); - this->_blocked = true; + this->_should_create_frame = true; + this->_blocked = true; } return ret; @@ -153,7 +155,7 @@ QUICRemoteFlowController::_on_frame_lost(QUICFrameInformationUPtr &info) { ink_assert(info->type == QUICFrameType::DATA_BLOCKED || info->type == QUICFrameType::STREAM_DATA_BLOCKED); if (this->_offset == *reinterpret_cast(info->data)) { - this->_frame = this->_create_frame(); + this->_should_create_frame = true; } } @@ -172,7 +174,7 @@ QUICLocalFlowController::forward_limit(QUICOffset new_limit) // Create MAX_(STREAM_)DATA frame. The frame will be sent on next WRITE_READY event on QUICNetVC if (this->_need_to_forward_limit()) { QUICFlowController::forward_limit(new_limit); - this->_frame = this->_create_frame(); + this->_should_create_frame = true; } } @@ -196,7 +198,7 @@ QUICLocalFlowController::_on_frame_lost(QUICFrameInformationUPtr &info) { ink_assert(info->type == QUICFrameType::MAX_DATA || info->type == QUICFrameType::MAX_STREAM_DATA); if (this->_limit == *reinterpret_cast(info->data)) { - this->_frame = this->_create_frame(); + this->_should_create_frame = true; } } @@ -214,10 +216,10 @@ QUICLocalFlowController::_need_to_forward_limit() // // QUIC[Remote|Local][Connection|Stream]FlowController // -QUICFrameUPtr -QUICRemoteConnectionFlowController::_create_frame() +QUICFrame * +QUICRemoteConnectionFlowController::_create_frame(uint8_t *buf) { - auto frame = QUICFrameFactory::create_data_blocked_frame(this->_offset, this->_issue_frame_id(), this); + 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; @@ -226,10 +228,10 @@ QUICRemoteConnectionFlowController::_create_frame() return frame; } -QUICFrameUPtr -QUICLocalConnectionFlowController::_create_frame() +QUICFrame * +QUICLocalConnectionFlowController::_create_frame(uint8_t *buf) { - auto frame = QUICFrameFactory::create_max_data_frame(this->_limit, this->_issue_frame_id(), this); + 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; @@ -238,10 +240,11 @@ QUICLocalConnectionFlowController::_create_frame() return frame; } -QUICFrameUPtr -QUICRemoteStreamFlowController::_create_frame() +QUICFrame * +QUICRemoteStreamFlowController::_create_frame(uint8_t *buf) { - auto frame = QUICFrameFactory::create_stream_data_blocked_frame(this->_stream_id, this->_offset, this->_issue_frame_id(), this); + 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; @@ -250,10 +253,10 @@ QUICRemoteStreamFlowController::_create_frame() return frame; } -QUICFrameUPtr -QUICLocalStreamFlowController::_create_frame() +QUICFrame * +QUICLocalStreamFlowController::_create_frame(uint8_t *buf) { - auto frame = QUICFrameFactory::create_max_stream_data_frame(this->_stream_id, this->_limit, this->_issue_frame_id(), this); + 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; diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index b10daad9d29..3e59b997cc6 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -61,15 +61,16 @@ class QUICFlowController : public QUICFrameGenerator // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) override; protected: QUICFlowController(uint64_t initial_limit) : _limit(initial_limit) {} - virtual QUICFrameUPtr _create_frame() = 0; + virtual QUICFrame *_create_frame(uint8_t *buf) = 0; - QUICOffset _offset = 0; //< Largest sent/received offset - QUICOffset _limit = 0; //< Maximum amount of data to send/receive - QUICFrameUPtr _frame = QUICFrameFactory::create_null_frame(); + QUICOffset _offset = 0; //< Largest sent/received offset + QUICOffset _limit = 0; //< Maximum amount of data to send/receive + bool _should_create_frame = false; }; class QUICRemoteFlowController : public QUICFlowController @@ -112,7 +113,7 @@ class QUICRemoteConnectionFlowController : public QUICRemoteFlowController { public: QUICRemoteConnectionFlowController(uint64_t initial_limit) : QUICRemoteFlowController(initial_limit) {} - QUICFrameUPtr _create_frame() override; + QUICFrame *_create_frame(uint8_t *buf) override; }; class QUICLocalConnectionFlowController : public QUICLocalFlowController @@ -122,7 +123,7 @@ class QUICLocalConnectionFlowController : public QUICLocalFlowController : QUICLocalFlowController(rtt_provider, initial_limit) { } - QUICFrameUPtr _create_frame() override; + QUICFrame *_create_frame(uint8_t *buf) override; }; class QUICRemoteStreamFlowController : public QUICRemoteFlowController @@ -132,7 +133,7 @@ class QUICRemoteStreamFlowController : public QUICRemoteFlowController : QUICRemoteFlowController(initial_limit), _stream_id(stream_id) { } - QUICFrameUPtr _create_frame() override; + QUICFrame *_create_frame(uint8_t *buf) override; private: QUICStreamId _stream_id = 0; @@ -145,7 +146,7 @@ class QUICLocalStreamFlowController : public QUICLocalFlowController : QUICLocalFlowController(rtt_provider, initial_limit), _stream_id(stream_id) { } - QUICFrameUPtr _create_frame() override; + QUICFrame *_create_frame(uint8_t *buf) override; private: QUICStreamId _stream_id = 0; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index a32a9d37274..79c16c8c8cc 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -30,26 +30,6 @@ #include "QUICDebugNames.h" #include "QUICPacket.h" -ClassAllocator quicStreamFrameAllocator("quicStreamFrameAllocator"); -ClassAllocator quicCryptoFrameAllocator("quicCryptoFrameAllocator"); -ClassAllocator quicAckFrameAllocator("quicAckFrameAllocator"); -ClassAllocator quicPaddingFrameAllocator("quicPaddingFrameAllocator"); -ClassAllocator quicRstStreamFrameAllocator("quicRstStreamFrameAllocator"); -ClassAllocator quicConnectionCloseFrameAllocator("quicConnectionCloseFrameAllocator"); -ClassAllocator quicMaxDataFrameAllocator("quicMaxDataFrameAllocator"); -ClassAllocator quicMaxStreamDataFrameAllocator("quicMaxStreamDataFrameAllocator"); -ClassAllocator quicMaxStreamIdFrameAllocator("quicMaxStreamDataIdAllocator"); -ClassAllocator quicPingFrameAllocator("quicPingFrameAllocator"); -ClassAllocator quicBlockedFrameAllocator("quicBlockedFrameAllocator"); -ClassAllocator quicStreamBlockedFrameAllocator("quicStreamBlockedFrameAllocator"); -ClassAllocator quicStreamIdBlockedFrameAllocator("quicStreamIdBlockedFrameAllocator"); -ClassAllocator quicNewConnectionIdFrameAllocator("quicNewConnectionIdFrameAllocator"); -ClassAllocator quicStopSendingFrameAllocator("quicStopSendingFrameAllocator"); -ClassAllocator quicPathChallengeFrameAllocator("quicPathChallengeFrameAllocator"); -ClassAllocator quicPathResponseFrameAllocator("quicPathResponseFrameAllocator"); -ClassAllocator quicNewTokenFrameAllocator("quicNewTokenFrameAllocator"); -ClassAllocator quicRetireConnectionIdFrameAllocator("quicRetireConnectionIdFrameAllocator"); - #define LEFT_SPACE(pos) ((size_t)(buf + len - pos)) #define FRAME_SIZE(pos) (pos - buf) @@ -158,6 +138,16 @@ QUICStreamFrame::QUICStreamFrame(const uint8_t *buf, size_t len) this->parse(buf, len); } +QUICStreamFrame::QUICStreamFrame(const QUICStreamFrame &o) + : _block(make_ptr(o._block->clone())), + _stream_id(o._stream_id), + _offset(o._offset), + _fin(o._fin), + _has_offset_field(o._has_offset_field), + _has_length_field(o._has_length_field) +{ +} + void QUICStreamFrame::parse(const uint8_t *buf, size_t len) { @@ -216,14 +206,6 @@ QUICStreamFrame::_reset() this->_size = 0; } -QUICFrameUPtr -QUICStreamFrame::clone() const -{ - Ptr new_block = make_ptr(this->_block->clone()); - return QUICFrameFactory::create_stream_frame(new_block, this->stream_id(), this->offset(), this->has_fin_flag(), - this->has_offset_field(), this->has_length_field(), this->_id, this->_owner); -} - QUICFrameType QUICStreamFrame::type() const { @@ -389,6 +371,10 @@ QUICCryptoFrame::QUICCryptoFrame(const uint8_t *buf, size_t len) this->parse(buf, len); } +QUICCryptoFrame::QUICCryptoFrame(const QUICCryptoFrame &o) : _offset(o._offset), _block(make_ptr(o._block->clone())) +{ +} + void QUICCryptoFrame::parse(const uint8_t *buf, size_t len) { @@ -431,12 +417,12 @@ QUICCryptoFrame::_reset() this->_size = 0; } -QUICFrameUPtr -QUICCryptoFrame::clone() const -{ - Ptr block = make_ptr(this->_block->clone()); - return QUICFrameFactory::create_crypto_frame(block, this->offset(), this->_id, this->_owner); -} +// QUICFrame * +// QUICCryptoFrame::clone(uint8_t *buf) const +// { +// Ptr block = make_ptr(this->_block->clone()); +// return QUICFrameFactory::create_crypto_frame(buf, block, this->offset(), this->_id, this->_owner); +// } QUICFrameType QUICCryptoFrame::type() const @@ -612,19 +598,6 @@ QUICAckFrame::~QUICAckFrame() } } -QUICFrameUPtr -QUICAckFrame::clone() const -{ - std::unique_ptr newframe = QUICFrameFactory::create_ack_frame( - this->largest_acknowledged(), this->ack_delay(), this->ack_block_section()->first_ack_block(), this->_id, this->_owner); - - for (auto &ack_block : *this->ack_block_section()) { - newframe->ack_block_section()->add_ack_block({ack_block.gap(), ack_block.length()}); - } - - return newframe; -} - QUICFrameType QUICAckFrame::type() const { @@ -1010,13 +983,6 @@ QUICRstStreamFrame::_reset() this->_size = 0; } -QUICFrameUPtr -QUICRstStreamFrame::clone() const -{ - return QUICFrameFactory::create_rst_stream_frame(this->stream_id(), this->error_code(), this->final_offset(), this->_id, - this->_owner); -} - QUICFrameType QUICRstStreamFrame::type() const { @@ -1078,12 +1044,6 @@ QUICRstStreamFrame::final_offset() const // PING frame // -QUICFrameUPtr -QUICPingFrame::clone() const -{ - return QUICFrameFactory::create_ping_frame(this->_id, this->_owner); -} - QUICPingFrame::QUICPingFrame(const uint8_t *buf, size_t len) { this->parse(buf, len); @@ -1138,13 +1098,6 @@ QUICPaddingFrame::parse(const uint8_t *buf, size_t len) this->_size = 1; } -QUICFrameUPtr -QUICPaddingFrame::clone() const -{ - ink_assert(!"You shouldn't clone padding frames"); - return QUICFrameFactory::create_null_frame(); -} - QUICFrameType QUICPaddingFrame::type() const { @@ -1268,13 +1221,6 @@ QUICConnectionCloseFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos); } -QUICFrameUPtr -QUICConnectionCloseFrame::clone() const -{ - return QUICFrameFactory::create_connection_close_frame(this->error_code(), this->frame_type(), this->reason_phrase_length(), - this->reason_phrase(), this->_id, this->_owner); -} - QUICFrameType QUICConnectionCloseFrame::type() const { @@ -1427,12 +1373,6 @@ QUICMaxDataFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos); } -QUICFrameUPtr -QUICMaxDataFrame::clone() const -{ - return QUICFrameFactory::create_max_data_frame(this->maximum_data(), this->_id, this->_owner); -} - QUICFrameType QUICMaxDataFrame::type() const { @@ -1527,12 +1467,6 @@ QUICMaxStreamDataFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos); } -QUICFrameUPtr -QUICMaxStreamDataFrame::clone() const -{ - return QUICFrameFactory::create_max_stream_data_frame(this->stream_id(), this->maximum_stream_data(), this->_id, this->_owner); -} - QUICFrameType QUICMaxStreamDataFrame::type() const { @@ -1627,12 +1561,6 @@ QUICMaxStreamsFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos); } -QUICFrameUPtr -QUICMaxStreamsFrame::clone() const -{ - return QUICFrameFactory::create_max_streams_frame(this->maximum_streams(), this->_id, this->_owner); -} - QUICFrameType QUICMaxStreamsFrame::type() const { @@ -1714,12 +1642,6 @@ QUICDataBlockedFrame::debug_msg(char *msg, size_t msg_len) const return snprintf(msg, msg_len, "| DATA_BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset()); } -QUICFrameUPtr -QUICDataBlockedFrame::clone() const -{ - return QUICFrameFactory::create_data_blocked_frame(this->offset(), this->_id, this->_owner); -} - QUICFrameType QUICDataBlockedFrame::type() const { @@ -1808,12 +1730,6 @@ QUICStreamDataBlockedFrame::debug_msg(char *msg, size_t msg_len) const return snprintf(msg, msg_len, "| STREAM_DATA_BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset()); } -QUICFrameUPtr -QUICStreamDataBlockedFrame::clone() const -{ - return QUICFrameFactory::create_stream_data_blocked_frame(this->stream_id(), this->offset(), this->_id, this->_owner); -} - QUICFrameType QUICStreamDataBlockedFrame::type() const { @@ -1898,12 +1814,6 @@ QUICStreamIdBlockedFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos); } -QUICFrameUPtr -QUICStreamIdBlockedFrame::clone() const -{ - return QUICFrameFactory::create_stream_id_blocked_frame(this->stream_id(), this->_id, this->_owner); -} - QUICFrameType QUICStreamIdBlockedFrame::type() const { @@ -2000,14 +1910,6 @@ QUICNewConnectionIdFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos) + 16; } -QUICFrameUPtr -QUICNewConnectionIdFrame::clone() const -{ - // FIXME: Connection ID and Stateless rese token have to be the same - return QUICFrameFactory::create_new_connection_id_frame(this->sequence(), this->connection_id(), this->stateless_reset_token(), - this->_id, this->_owner); -} - QUICFrameType QUICNewConnectionIdFrame::type() const { @@ -2123,12 +2025,6 @@ QUICStopSendingFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos) + 2; } -QUICFrameUPtr -QUICStopSendingFrame::clone() const -{ - return QUICFrameFactory::create_stop_sending_frame(this->stream_id(), this->error_code(), this->_id, this->_owner); -} - QUICFrameType QUICStopSendingFrame::type() const { @@ -2212,12 +2108,6 @@ QUICPathChallengeFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos) + QUICPathChallengeFrame::DATA_LEN; } -QUICFrameUPtr -QUICPathChallengeFrame::clone() const -{ - return QUICFrameFactory::create_path_challenge_frame(this->data(), this->_id, this->_owner); -} - QUICFrameType QUICPathChallengeFrame::type() const { @@ -2296,12 +2186,6 @@ QUICPathResponseFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos) + QUICPathChallengeFrame::DATA_LEN; } -QUICFrameUPtr -QUICPathResponseFrame::clone() const -{ - return QUICFrameFactory::create_path_response_frame(this->data(), this->_id, this->_owner); -} - QUICFrameType QUICPathResponseFrame::type() const { @@ -2383,13 +2267,6 @@ QUICNewTokenFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos) + this->_token_length; } -QUICFrameUPtr -QUICNewTokenFrame::clone() const -{ - // clone() will be removed when all frame generators are responsible for retransmittion - return QUICFrameFactory::create_null_frame(); -} - QUICFrameType QUICNewTokenFrame::type() const { @@ -2480,12 +2357,6 @@ QUICRetireConnectionIdFrame::parse(const uint8_t *buf, size_t len) this->_size = FRAME_SIZE(pos); } -QUICFrameUPtr -QUICRetireConnectionIdFrame::clone() const -{ - return QUICFrameFactory::create_retire_connection_id_frame(this->seq_num(), this->_id, this->_owner); -} - QUICFrameType QUICRetireConnectionIdFrame::type() const { @@ -2534,121 +2405,121 @@ QUICRetireConnectionIdFrame::seq_num() const } // -// QUICFrameFactory +// UNKNOWN // +QUICFrameType +QUICUnknownFrame::type() const +{ + return QUICFrameType::UNKNOWN; +} -QUICFrameUPtr -QUICFrameFactory::create_null_frame() +size_t +QUICUnknownFrame::size() const { - return {nullptr, &QUICFrameDeleter::delete_null_frame}; + // FIXME size should be readable + return 0; } -std::unique_ptr -QUICFrameFactory::create_null_ack_frame() +size_t +QUICUnknownFrame::store(uint8_t *buf, size_t *len, size_t limit) const +{ + return 0; +} + +void +QUICUnknownFrame::parse(const uint8_t *buf, size_t len) { - return {nullptr, &QUICFrameDeleter::delete_null_frame}; } -QUICFrameUPtr -QUICFrameFactory::create(const uint8_t *buf, size_t len) +int +QUICUnknownFrame::debug_msg(char *msg, size_t msg_len) const { - QUICFrame *frame; + return 0; +} - switch (QUICFrame::type(buf)) { +// +// QUICFrameFactory +// + +QUICFrame * +QUICFrameFactory::create(uint8_t *buf, const uint8_t *src, size_t len) +{ + switch (QUICFrame::type(src)) { case QUICFrameType::STREAM: - frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); + new (buf) QUICStreamFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::CRYPTO: - frame = quicCryptoFrameAllocator.alloc(); - new (frame) QUICCryptoFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_crypto_frame); + new (buf) QUICCryptoFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::ACK: - frame = quicAckFrameAllocator.alloc(); - new (frame) QUICAckFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_ack_frame); + new (buf) QUICAckFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::PADDING: - frame = quicPaddingFrameAllocator.alloc(); - new (frame) QUICPaddingFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_padding_frame); + new (buf) QUICPaddingFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::RESET_STREAM: - frame = quicRstStreamFrameAllocator.alloc(); - new (frame) QUICRstStreamFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_rst_stream_frame); + new (buf) QUICRstStreamFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::CONNECTION_CLOSE: - frame = quicConnectionCloseFrameAllocator.alloc(); - new (frame) QUICConnectionCloseFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_connection_close_frame); + new (buf) QUICConnectionCloseFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::MAX_DATA: - frame = quicMaxDataFrameAllocator.alloc(); - new (frame) QUICMaxDataFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_max_data_frame); + new (buf) QUICMaxDataFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::MAX_STREAM_DATA: - frame = quicMaxStreamDataFrameAllocator.alloc(); - new (frame) QUICMaxStreamDataFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); + new (buf) QUICMaxStreamDataFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::MAX_STREAMS: - frame = quicMaxStreamIdFrameAllocator.alloc(); - new (frame) QUICMaxStreamsFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_max_streams_frame); + new (buf) QUICMaxStreamsFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::PING: - frame = quicPingFrameAllocator.alloc(); - new (frame) QUICPingFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_ping_frame); + new (buf) QUICPingFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::DATA_BLOCKED: - frame = quicBlockedFrameAllocator.alloc(); - new (frame) QUICDataBlockedFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_blocked_frame); + new (buf) QUICDataBlockedFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::STREAM_DATA_BLOCKED: - frame = quicStreamBlockedFrameAllocator.alloc(); - new (frame) QUICStreamDataBlockedFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); + new (buf) QUICStreamDataBlockedFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::STREAMS_BLOCKED: - frame = quicStreamIdBlockedFrameAllocator.alloc(); - new (frame) QUICStreamIdBlockedFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stream_id_blocked_frame); + new (buf) QUICStreamIdBlockedFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::NEW_CONNECTION_ID: - frame = quicNewConnectionIdFrameAllocator.alloc(); - new (frame) QUICNewConnectionIdFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_new_connection_id_frame); + new (buf) QUICNewConnectionIdFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::STOP_SENDING: - frame = quicStopSendingFrameAllocator.alloc(); - new (frame) QUICStopSendingFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_stop_sending_frame); + new (buf) QUICStopSendingFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::PATH_CHALLENGE: - frame = quicPathChallengeFrameAllocator.alloc(); - new (frame) QUICPathChallengeFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_path_challenge_frame); + new (buf) QUICPathChallengeFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::PATH_RESPONSE: - frame = quicPathResponseFrameAllocator.alloc(); - new (frame) QUICPathResponseFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_path_response_frame); + new (buf) QUICPathResponseFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::NEW_TOKEN: - frame = quicNewTokenFrameAllocator.alloc(); - new (frame) QUICNewTokenFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_new_token_frame); + new (buf) QUICNewTokenFrame(src, len); + return reinterpret_cast(buf); case QUICFrameType::RETIRE_CONNECTION_ID: - frame = quicRetireConnectionIdFrameAllocator.alloc(); - new (frame) QUICRetireConnectionIdFrame(buf, len); - return QUICFrameUPtr(frame, &QUICFrameDeleter::delete_retire_connection_id_frame); + new (buf) QUICRetireConnectionIdFrame(src, len); + return reinterpret_cast(buf); default: // Unknown frame - Debug("quic_frame_factory", "Unknown frame type %x", buf[0]); - return QUICFrameFactory::create_null_frame(); + Debug("quic_frame_factory", "Unknown frame type %x", src[0]); + return nullptr; } } -std::shared_ptr +const QUICFrame & QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) { if (QUICFrame::type(buf) == QUICFrameType::UNKNOWN) { - return nullptr; + return this->_unknown_frame; } - std::shared_ptr frame = this->_reusable_frames[static_cast(QUICFrame::type(buf))]; + QUICFrame *frame = this->_reusable_frames[static_cast(QUICFrame::type(buf))]; if (frame == nullptr) { - frame = QUICFrameFactory::create(buf, len); + frame = QUICFrameFactory::create(static_cast(malloc(1024)), buf, len); if (frame != nullptr) { this->_reusable_frames[static_cast(QUICFrame::type(buf))] = frame; } @@ -2656,190 +2527,173 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) frame->parse(buf, len); } - return frame; + return *frame; } -QUICStreamFrameUPtr -QUICFrameFactory::create_stream_frame(Ptr &block, QUICStreamId stream_id, QUICOffset offset, bool last, +QUICStreamFrame * +QUICFrameFactory::create_stream_frame(uint8_t *buf, Ptr &block, QUICStreamId stream_id, QUICOffset offset, bool last, bool has_offset_field, bool has_length_field, QUICFrameId id, QUICFrameGenerator *owner) { Ptr new_block = make_ptr(block->clone()); - QUICStreamFrame *frame = quicStreamFrameAllocator.alloc(); - new (frame) QUICStreamFrame(new_block, stream_id, offset, last, has_offset_field, has_length_field, id, owner); - return QUICStreamFrameUPtr(frame, &QUICFrameDeleter::delete_stream_frame); + new (buf) QUICStreamFrame(new_block, stream_id, offset, last, has_offset_field, has_length_field, id, owner); + return reinterpret_cast(buf); } -QUICCryptoFrameUPtr -QUICFrameFactory::create_crypto_frame(Ptr &block, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) +QUICCryptoFrame * +QUICFrameFactory::create_crypto_frame(uint8_t *buf, Ptr &block, QUICOffset offset, QUICFrameId id, + QUICFrameGenerator *owner) { Ptr new_block = make_ptr(block->clone()); - QUICCryptoFrame *frame = quicCryptoFrameAllocator.alloc(); - new (frame) QUICCryptoFrame(new_block, offset, id, owner); - return QUICCryptoFrameUPtr(frame, &QUICFrameDeleter::delete_crypto_frame); + new (buf) QUICCryptoFrame(new_block, offset, id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, - QUICFrameId id, QUICFrameGenerator *owner) +QUICAckFrame * +QUICFrameFactory::create_ack_frame(uint8_t *buf, QUICPacketNumber largest_acknowledged, uint64_t ack_delay, + uint64_t first_ack_block, QUICFrameId id, QUICFrameGenerator *owner) { - QUICAckFrame *frame = quicAckFrameAllocator.alloc(); - new (frame) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_ack_frame); + new (buf) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block, id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_connection_close_frame(uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length, - const char *reason_phrase, QUICFrameId id, QUICFrameGenerator *owner) +QUICConnectionCloseFrame * +QUICFrameFactory::create_connection_close_frame(uint8_t *buf, uint16_t error_code, QUICFrameType frame_type, + uint16_t reason_phrase_length, const char *reason_phrase, QUICFrameId id, + QUICFrameGenerator *owner) { - QUICConnectionCloseFrame *frame = quicConnectionCloseFrameAllocator.alloc(); - new (frame) QUICConnectionCloseFrame(error_code, frame_type, reason_phrase_length, reason_phrase, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_connection_close_frame); + new (buf) QUICConnectionCloseFrame(error_code, frame_type, reason_phrase_length, reason_phrase, id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_connection_close_frame(QUICConnectionError &error, QUICFrameId id, QUICFrameGenerator *owner) +QUICConnectionCloseFrame * +QUICFrameFactory::create_connection_close_frame(uint8_t *buf, QUICConnectionError &error, QUICFrameId id, QUICFrameGenerator *owner) { ink_assert(error.cls == QUICErrorClass::TRANSPORT); if (error.msg) { - return QUICFrameFactory::create_connection_close_frame(error.code, error.frame_type(), strlen(error.msg), error.msg, id, owner); + return QUICFrameFactory::create_connection_close_frame(buf, error.code, error.frame_type(), strlen(error.msg), error.msg, id, + owner); } else { - return QUICFrameFactory::create_connection_close_frame(error.code, error.frame_type(), 0, nullptr, id, owner); + return QUICFrameFactory::create_connection_close_frame(buf, error.code, error.frame_type(), 0, nullptr, id, owner); } } -std::unique_ptr -QUICFrameFactory::create_max_data_frame(uint64_t maximum_data, QUICFrameId id, QUICFrameGenerator *owner) +QUICMaxDataFrame * +QUICFrameFactory::create_max_data_frame(uint8_t *buf, uint64_t maximum_data, QUICFrameId id, QUICFrameGenerator *owner) { - QUICMaxDataFrame *frame = quicMaxDataFrameAllocator.alloc(); - new (frame) QUICMaxDataFrame(maximum_data, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_data_frame); + new (buf) QUICMaxDataFrame(maximum_data, id, owner); + return reinterpret_cast(buf); } - -std::unique_ptr -QUICFrameFactory::create_max_stream_data_frame(QUICStreamId stream_id, uint64_t maximum_data, QUICFrameId id, +QUICMaxStreamDataFrame * +QUICFrameFactory::create_max_stream_data_frame(uint8_t *buf, QUICStreamId stream_id, uint64_t maximum_data, QUICFrameId id, QUICFrameGenerator *owner) { - QUICMaxStreamDataFrame *frame = quicMaxStreamDataFrameAllocator.alloc(); - new (frame) QUICMaxStreamDataFrame(stream_id, maximum_data, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_stream_data_frame); + new (buf) QUICMaxStreamDataFrame(stream_id, maximum_data, id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_max_streams_frame(QUICStreamId maximum_streams, QUICFrameId id, QUICFrameGenerator *owner) +QUICMaxStreamsFrame * +QUICFrameFactory::create_max_streams_frame(uint8_t *buf, QUICStreamId maximum_streams, QUICFrameId id, QUICFrameGenerator *owner) { - QUICMaxStreamsFrame *frame = quicMaxStreamIdFrameAllocator.alloc(); - new (frame) QUICMaxStreamsFrame(maximum_streams, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_max_streams_frame); + new (buf) QUICMaxStreamsFrame(maximum_streams, id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_ping_frame(QUICFrameId id, QUICFrameGenerator *owner) +QUICPingFrame * +QUICFrameFactory::create_ping_frame(uint8_t *buf, QUICFrameId id, QUICFrameGenerator *owner) { - QUICPingFrame *frame = quicPingFrameAllocator.alloc(); - new (frame) QUICPingFrame(id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_ping_frame); + new (buf) QUICPingFrame(id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_path_challenge_frame(const uint8_t *data, QUICFrameId id, QUICFrameGenerator *owner) +QUICPathChallengeFrame * +QUICFrameFactory::create_path_challenge_frame(uint8_t *buf, const uint8_t *data, QUICFrameId id, QUICFrameGenerator *owner) { - ats_unique_buf buf = ats_unique_malloc(QUICPathChallengeFrame::DATA_LEN); - memcpy(buf.get(), data, QUICPathChallengeFrame::DATA_LEN); + ats_unique_buf challenge_data = ats_unique_malloc(QUICPathChallengeFrame::DATA_LEN); + memcpy(challenge_data.get(), data, QUICPathChallengeFrame::DATA_LEN); - QUICPathChallengeFrame *frame = quicPathChallengeFrameAllocator.alloc(); - new (frame) QUICPathChallengeFrame(std::move(buf), id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_challenge_frame); + new (buf) QUICPathChallengeFrame(std::move(challenge_data), id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_path_response_frame(const uint8_t *data, QUICFrameId id, QUICFrameGenerator *owner) +QUICPathResponseFrame * +QUICFrameFactory::create_path_response_frame(uint8_t *buf, const uint8_t *data, QUICFrameId id, QUICFrameGenerator *owner) { - ats_unique_buf buf = ats_unique_malloc(QUICPathResponseFrame::DATA_LEN); - memcpy(buf.get(), data, QUICPathResponseFrame::DATA_LEN); + ats_unique_buf response_data = ats_unique_malloc(QUICPathResponseFrame::DATA_LEN); + memcpy(response_data.get(), data, QUICPathResponseFrame::DATA_LEN); - QUICPathResponseFrame *frame = quicPathResponseFrameAllocator.alloc(); - new (frame) QUICPathResponseFrame(std::move(buf), id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_path_response_frame); + new (buf) QUICPathResponseFrame(std::move(response_data), id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_data_blocked_frame(QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) +QUICDataBlockedFrame * +QUICFrameFactory::create_data_blocked_frame(uint8_t *buf, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) { - QUICDataBlockedFrame *frame = quicBlockedFrameAllocator.alloc(); - new (frame) QUICDataBlockedFrame(offset, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_blocked_frame); + new (buf) QUICDataBlockedFrame(offset, id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_stream_data_blocked_frame(QUICStreamId stream_id, QUICOffset offset, QUICFrameId id, +QUICStreamDataBlockedFrame * +QUICFrameFactory::create_stream_data_blocked_frame(uint8_t *buf, QUICStreamId stream_id, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner) { - QUICStreamDataBlockedFrame *frame = quicStreamBlockedFrameAllocator.alloc(); - new (frame) QUICStreamDataBlockedFrame(stream_id, offset, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_blocked_frame); + new (buf) QUICStreamDataBlockedFrame(stream_id, offset, id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_stream_id_blocked_frame(QUICStreamId stream_id, QUICFrameId id, QUICFrameGenerator *owner) +QUICStreamIdBlockedFrame * +QUICFrameFactory::create_stream_id_blocked_frame(uint8_t *buf, QUICStreamId stream_id, QUICFrameId id, QUICFrameGenerator *owner) { - QUICStreamIdBlockedFrame *frame = quicStreamIdBlockedFrameAllocator.alloc(); - new (frame) QUICStreamIdBlockedFrame(stream_id, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_stream_id_blocked_frame); + new (buf) QUICStreamIdBlockedFrame(stream_id, id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, - QUICFrameId id, QUICFrameGenerator *owner) +QUICRstStreamFrame * +QUICFrameFactory::create_rst_stream_frame(uint8_t *buf, QUICStreamId stream_id, QUICAppErrorCode error_code, + QUICOffset final_offset, QUICFrameId id, QUICFrameGenerator *owner) { - QUICRstStreamFrame *frame = quicRstStreamFrameAllocator.alloc(); - new (frame) QUICRstStreamFrame(stream_id, error_code, final_offset, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_rst_stream_frame); + new (buf) QUICRstStreamFrame(stream_id, error_code, final_offset, id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_rst_stream_frame(QUICStreamError &error, QUICFrameId id, QUICFrameGenerator *owner) +QUICRstStreamFrame * +QUICFrameFactory::create_rst_stream_frame(uint8_t *buf, QUICStreamError &error, QUICFrameId id, QUICFrameGenerator *owner) { - return QUICFrameFactory::create_rst_stream_frame(error.stream->id(), error.code, error.stream->final_offset(), id, owner); + return QUICFrameFactory::create_rst_stream_frame(buf, error.stream->id(), error.code, error.stream->final_offset(), id, owner); } -std::unique_ptr -QUICFrameFactory::create_stop_sending_frame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameId id, +QUICStopSendingFrame * +QUICFrameFactory::create_stop_sending_frame(uint8_t *buf, QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameId id, QUICFrameGenerator *owner) { - QUICStopSendingFrame *frame = quicStopSendingFrameAllocator.alloc(); - new (frame) QUICStopSendingFrame(stream_id, error_code, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_stop_sending_frame); + new (buf) QUICStopSendingFrame(stream_id, error_code, id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_new_connection_id_frame(uint32_t sequence, QUICConnectionId connectoin_id, +QUICNewConnectionIdFrame * +QUICFrameFactory::create_new_connection_id_frame(uint8_t *buf, uint32_t sequence, QUICConnectionId connectoin_id, QUICStatelessResetToken stateless_reset_token, QUICFrameId id, QUICFrameGenerator *owner) { - QUICNewConnectionIdFrame *frame = quicNewConnectionIdFrameAllocator.alloc(); - new (frame) QUICNewConnectionIdFrame(sequence, connectoin_id, stateless_reset_token, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_connection_id_frame); + new (buf) QUICNewConnectionIdFrame(sequence, connectoin_id, stateless_reset_token, id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_new_token_frame(const QUICResumptionToken &token, QUICFrameId id, QUICFrameGenerator *owner) +QUICNewTokenFrame * +QUICFrameFactory::create_new_token_frame(uint8_t *buf, const QUICResumptionToken &token, QUICFrameId id, QUICFrameGenerator *owner) { uint64_t token_len = token.length(); ats_unique_buf token_buf = ats_unique_malloc(token_len); memcpy(token_buf.get(), token.buf(), token_len); - QUICNewTokenFrame *frame = quicNewTokenFrameAllocator.alloc(); - new (frame) QUICNewTokenFrame(std::move(token_buf), token_len, id, owner); - return std::unique_ptr(frame, &QUICFrameDeleter::delete_new_token_frame); + new (buf) QUICNewTokenFrame(std::move(token_buf), token_len, id, owner); + return reinterpret_cast(buf); } -std::unique_ptr -QUICFrameFactory::create_retire_connection_id_frame(uint64_t seq_num, QUICFrameId id, QUICFrameGenerator *owner) +QUICRetireConnectionIdFrame * +QUICFrameFactory::create_retire_connection_id_frame(uint8_t *buf, uint64_t seq_num, QUICFrameId id, QUICFrameGenerator *owner) { - QUICRetireConnectionIdFrame *frame = quicRetireConnectionIdFrameAllocator.alloc(); - new (frame) QUICRetireConnectionIdFrame(seq_num, id, owner); - return std::unique_ptr(frame, - &QUICFrameDeleter::delete_retire_connection_id_frame); + new (buf) QUICRetireConnectionIdFrame(seq_num, id, owner); + return reinterpret_cast(buf); } QUICFrameId diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 94002a268ae..18289f761e5 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -58,7 +58,6 @@ class QUICFrame QUICFrameId id() const; - virtual QUICFrameUPtr clone() const = 0; virtual QUICFrameType type() const; virtual size_t size() const = 0; virtual bool is_probing_frame() const; @@ -91,8 +90,8 @@ class QUICStreamFrame : public QUICFrame QUICStreamFrame(Ptr &block, QUICStreamId streamid, QUICOffset offset, bool last = false, bool has_offset_field = true, bool has_length_field = true, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + QUICStreamFrame(const QUICStreamFrame &o); - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual bool is_flow_controlled() const override; @@ -132,8 +131,8 @@ class QUICCryptoFrame : public QUICFrame QUICCryptoFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICCryptoFrame(const uint8_t *buf, size_t len); QUICCryptoFrame(Ptr &block, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + QUICCryptoFrame(const QUICCryptoFrame &o); - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -257,7 +256,6 @@ class QUICAckFrame : public QUICFrame QUICFrameGenerator *owner = nullptr); virtual ~QUICAckFrame(); - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -293,7 +291,6 @@ class QUICRstStreamFrame : public QUICFrame QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -320,7 +317,6 @@ class QUICPingFrame : public QUICFrame public: QUICPingFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICPingFrame(const uint8_t *buf, size_t len); - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -338,7 +334,6 @@ class QUICPaddingFrame : public QUICFrame public: QUICPaddingFrame() {} QUICPaddingFrame(const uint8_t *buf, size_t len); - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual bool is_probing_frame() const override; @@ -361,7 +356,6 @@ class QUICConnectionCloseFrame : public QUICFrame // Constructor for application protocol error codes QUICConnectionCloseFrame(uint16_t error_code, uint64_t reason_phrase_length, const char *reason_phrase, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -393,7 +387,6 @@ class QUICMaxDataFrame : public QUICFrame QUICMaxDataFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICMaxDataFrame(const uint8_t *buf, size_t len); QUICMaxDataFrame(uint64_t maximum_data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -419,7 +412,6 @@ class QUICMaxStreamDataFrame : public QUICFrame QUICMaxStreamDataFrame(const uint8_t *buf, size_t len); QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void parse(const uint8_t *buf, size_t len) override; @@ -446,7 +438,6 @@ class QUICMaxStreamsFrame : public QUICFrame QUICMaxStreamsFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICMaxStreamsFrame(const uint8_t *buf, size_t len); QUICMaxStreamsFrame(QUICStreamId maximum_streams, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -470,7 +461,6 @@ class QUICDataBlockedFrame : public QUICFrame QUICDataBlockedFrame(QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _offset(offset){}; - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void parse(const uint8_t *buf, size_t len) override; @@ -497,7 +487,6 @@ class QUICStreamDataBlockedFrame : public QUICFrame QUICStreamDataBlockedFrame(QUICStreamId s, QUICOffset o, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _stream_id(s), _offset(o){}; - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -526,7 +515,6 @@ class QUICStreamIdBlockedFrame : public QUICFrame : QUICFrame(id, owner), _stream_id(s) { } - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -553,7 +541,6 @@ class QUICNewConnectionIdFrame : public QUICFrame QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _sequence(seq), _connection_id(cid), _stateless_reset_token(token){}; - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -584,7 +571,6 @@ class QUICStopSendingFrame : public QUICFrame QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual void parse(const uint8_t *buf, size_t len) override; @@ -614,7 +600,6 @@ class QUICPathChallengeFrame : public QUICFrame : QUICFrame(id, owner), _data(std::move(data)) { } - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual bool is_probing_frame() const override; @@ -643,7 +628,6 @@ class QUICPathResponseFrame : public QUICFrame : QUICFrame(id, owner), _data(std::move(data)) { } - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual bool is_probing_frame() const override; @@ -671,7 +655,6 @@ class QUICNewTokenFrame : public QUICFrame : QUICFrame(id, owner), _token_length(token_length), _token(std::move(token)) { } - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -700,7 +683,6 @@ class QUICRetireConnectionIdFrame : public QUICFrame : QUICFrame(id, owner), _seq_num(seq_num) { } - QUICFrameUPtr clone() const override; virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; @@ -715,168 +697,17 @@ class QUICRetireConnectionIdFrame : public QUICFrame uint64_t _seq_num = 0; }; -extern ClassAllocator quicStreamFrameAllocator; -extern ClassAllocator quicCryptoFrameAllocator; -extern ClassAllocator quicAckFrameAllocator; -extern ClassAllocator quicPaddingFrameAllocator; -extern ClassAllocator quicRstStreamFrameAllocator; -extern ClassAllocator quicConnectionCloseFrameAllocator; -extern ClassAllocator quicMaxDataFrameAllocator; -extern ClassAllocator quicMaxStreamDataFrameAllocator; -extern ClassAllocator quicMaxStreamIdFrameAllocator; -extern ClassAllocator quicPingFrameAllocator; -extern ClassAllocator quicBlockedFrameAllocator; -extern ClassAllocator quicStreamBlockedFrameAllocator; -extern ClassAllocator quicStreamIdBlockedFrameAllocator; -extern ClassAllocator quicNewConnectionIdFrameAllocator; -extern ClassAllocator quicStopSendingFrameAllocator; -extern ClassAllocator quicPathChallengeFrameAllocator; -extern ClassAllocator quicPathResponseFrameAllocator; -extern ClassAllocator quicNewTokenFrameAllocator; -extern ClassAllocator quicRetireConnectionIdFrameAllocator; - -class QUICFrameDeleter -{ -public: - // TODO Probably these methods should call destructor - static void - delete_null_frame(QUICFrame *frame) - { - ink_assert(frame == nullptr); - } - - static void - delete_stream_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicStreamFrameAllocator.free(static_cast(frame)); - } - - static void - delete_crypto_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicCryptoFrameAllocator.free(static_cast(frame)); - } - - static void - delete_ack_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicAckFrameAllocator.free(static_cast(frame)); - } - - static void - delete_padding_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicPaddingFrameAllocator.free(static_cast(frame)); - } - - static void - delete_rst_stream_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicRstStreamFrameAllocator.free(static_cast(frame)); - } - - static void - delete_connection_close_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicConnectionCloseFrameAllocator.free(static_cast(frame)); - } - - static void - delete_max_data_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicMaxDataFrameAllocator.free(static_cast(frame)); - } - - static void - delete_max_stream_data_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicMaxStreamDataFrameAllocator.free(static_cast(frame)); - } - - static void - delete_max_streams_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicMaxStreamIdFrameAllocator.free(static_cast(frame)); - } - - static void - delete_ping_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicPingFrameAllocator.free(static_cast(frame)); - } - - static void - delete_blocked_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicBlockedFrameAllocator.free(static_cast(frame)); - } - - static void - delete_stream_blocked_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicStreamBlockedFrameAllocator.free(static_cast(frame)); - } - - static void - delete_stream_id_blocked_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicStreamIdBlockedFrameAllocator.free(static_cast(frame)); - } - - static void - delete_new_connection_id_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicNewConnectionIdFrameAllocator.free(static_cast(frame)); - } - - static void - delete_stop_sending_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicStopSendingFrameAllocator.free(static_cast(frame)); - } - - static void - delete_path_challenge_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicPathChallengeFrameAllocator.free(static_cast(frame)); - } - - static void - delete_path_response_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicPathResponseFrameAllocator.free(static_cast(frame)); - } - - static void - delete_new_token_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicNewTokenFrameAllocator.free(static_cast(frame)); - } +// +// UNKNOWN +// - static void - delete_retire_connection_id_frame(QUICFrame *frame) - { - frame->~QUICFrame(); - quicRetireConnectionIdFrameAllocator.free(static_cast(frame)); - } +class QUICUnknownFrame : public QUICFrame +{ + QUICFrameType type() const override; + size_t size() const override; + size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + void parse(const uint8_t *buf, size_t len) override; + int debug_msg(char *msg, size_t msg_len) const override; }; // @@ -885,156 +716,140 @@ class QUICFrameDeleter class QUICFrameFactory { public: - /* - * This is for an empty QUICFrameUptr. - * Empty frames are used for variable initialization and return value of frame creation failure - */ - static QUICFrameUPtr create_null_frame(); - static std::unique_ptr create_null_ack_frame(); - /* * This is used for creating a QUICFrame object based on received data. */ - static QUICFrameUPtr create(const uint8_t *buf, size_t len); + static QUICFrame *create(uint8_t *buf, const uint8_t *src, size_t len); /* * 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. */ - std::shared_ptr fast_create(const uint8_t *buf, size_t len); + const QUICFrame &fast_create(const uint8_t *buf, size_t len); /* * Creates a STREAM frame. * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ - static QUICStreamFrameUPtr create_stream_frame(Ptr &block, QUICStreamId stream_id, QUICOffset offset, - bool last = false, bool has_offset_field = true, bool has_length_field = true, - QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + static QUICStreamFrame *create_stream_frame(uint8_t *buf, Ptr &block, QUICStreamId stream_id, QUICOffset offset, + bool last = false, bool has_offset_field = true, bool has_length_field = true, + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a CRYPTO frame. * You have to make sure that the data size won't exceed the maximum size of QUIC packet. */ - static QUICCryptoFrameUPtr create_crypto_frame(Ptr &block, QUICOffset offset, QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); + static QUICCryptoFrame *create_crypto_frame(uint8_t *buf, Ptr &block, QUICOffset offset, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a ACK frame. * You shouldn't call this directly but through QUICAckFrameCreator because QUICAckFrameCreator manages packet numbers that we * need to ack. */ - static std::unique_ptr create_ack_frame(QUICPacketNumber largest_acknowledged, - uint64_t ack_delay, uint64_t first_ack_block, - QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); + static QUICAckFrame *create_ack_frame(uint8_t *buf, QUICPacketNumber largest_acknowledged, uint64_t ack_delay, + uint64_t first_ack_block, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a CONNECTION_CLOSE frame. */ - static std::unique_ptr create_connection_close_frame( - uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr, - QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + static QUICConnectionCloseFrame *create_connection_close_frame(uint8_t *buf, uint16_t error_code, QUICFrameType frame_type, + uint16_t reason_phrase_length = 0, + const char *reason_phrase = nullptr, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); - static std::unique_ptr create_connection_close_frame( - QUICConnectionError &error, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + static QUICConnectionCloseFrame *create_connection_close_frame(uint8_t *buf, QUICConnectionError &error, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a MAX_DATA frame. */ - static std::unique_ptr create_max_data_frame(uint64_t maximum_data, QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); + static QUICMaxDataFrame *create_max_data_frame(uint8_t *buf, uint64_t maximum_data, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* / * Creates a MAX_STREAM_DATA frame. */ - static std::unique_ptr create_max_stream_data_frame( - QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + static QUICMaxStreamDataFrame *create_max_stream_data_frame(uint8_t *buf, QUICStreamId stream_id, uint64_t maximum_stream_data, + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a MAX_STREAMS frame. */ - static std::unique_ptr create_max_streams_frame(QUICStreamId maximum_streams, - QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); + static QUICMaxStreamsFrame *create_max_streams_frame(uint8_t *buf, QUICStreamId maximum_streams, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a PING frame */ - static std::unique_ptr create_ping_frame(QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); + static QUICPingFrame *create_ping_frame(uint8_t *buf, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a PATH_CHALLENGE frame */ - static std::unique_ptr create_path_challenge_frame( - const uint8_t *data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + static QUICPathChallengeFrame *create_path_challenge_frame(uint8_t *buf, const uint8_t *data, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a PATH_RESPONSE frame */ - static std::unique_ptr create_path_response_frame( - const uint8_t *data, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + static QUICPathResponseFrame *create_path_response_frame(uint8_t *buf, const uint8_t *data, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a BLOCKED frame. */ - static std::unique_ptr create_data_blocked_frame(QUICOffset offset, - QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); + static QUICDataBlockedFrame *create_data_blocked_frame(uint8_t *buf, QUICOffset offset, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a STREAM_DATA_BLOCKED frame. */ - static std::unique_ptr create_stream_data_blocked_frame( - QUICStreamId stream_id, QUICOffset offset, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + static QUICStreamDataBlockedFrame *create_stream_data_blocked_frame(uint8_t *buf, QUICStreamId stream_id, QUICOffset offset, + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a STREAMS_BLOCKED frame. */ - static std::unique_ptr create_stream_id_blocked_frame( - QUICStreamId stream_id, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + static QUICStreamIdBlockedFrame *create_stream_id_blocked_frame(uint8_t *buf, QUICStreamId stream_id, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a RESET_STREAM frame. */ - static std::unique_ptr create_rst_stream_frame(QUICStreamId stream_id, - QUICAppErrorCode error_code, - QUICOffset final_offset, - QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); - static std::unique_ptr create_rst_stream_frame(QUICStreamError &error, - QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); + static QUICRstStreamFrame *create_rst_stream_frame(uint8_t *buf, QUICStreamId stream_id, QUICAppErrorCode error_code, + QUICOffset final_offset, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); + static QUICRstStreamFrame *create_rst_stream_frame(uint8_t *buf, QUICStreamError &error, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a STOP_SENDING frame. */ - static std::unique_ptr create_stop_sending_frame(QUICStreamId stream_id, - QUICAppErrorCode error_code, - QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); + static QUICStopSendingFrame *create_stop_sending_frame(uint8_t *buf, QUICStreamId stream_id, QUICAppErrorCode error_code, + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); /* * Creates a NEW_CONNECTION_ID frame. */ - static std::unique_ptr create_new_connection_id_frame( - uint32_t sequence, QUICConnectionId connectoin_id, QUICStatelessResetToken stateless_reset_token, QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); + static QUICNewConnectionIdFrame *create_new_connection_id_frame(uint8_t *buf, uint32_t sequence, QUICConnectionId connectoin_id, + QUICStatelessResetToken stateless_reset_token, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a NEW_TOKEN frame */ - static std::unique_ptr create_new_token_frame(const QUICResumptionToken &token, - QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); + static QUICNewTokenFrame *create_new_token_frame(uint8_t *buf, const QUICResumptionToken &token, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); /* * Creates a RETIRE_CONNECTION_ID frame */ - static std::unique_ptr create_retire_connection_id_frame( - uint64_t seq_num, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + static QUICRetireConnectionIdFrame *create_retire_connection_id_frame(uint8_t *buf, uint64_t seq_num, QUICFrameId id = 0, + QUICFrameGenerator *owner = nullptr); private: // FIXME Actual number of frame types is several but some of the values are not sequential. - std::shared_ptr _reusable_frames[256] = {nullptr}; + QUICFrame *_reusable_frames[256] = {nullptr}; + QUICUnknownFrame _unknown_frame; }; class QUICFrameInfo diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 8b81de22ebf..990cdea6a16 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -45,24 +45,23 @@ 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) { - std::shared_ptr frame(nullptr); uint16_t cursor = 0; ack_only = true; is_flow_controlled = false; QUICConnectionErrorUPtr error = nullptr; while (cursor < size) { - frame = this->_frame_factory.fast_create(payload + cursor, size - cursor); - if (frame == nullptr) { + const QUICFrame &frame = this->_frame_factory.fast_create(payload + cursor, size - cursor); + if (frame.type() == QUICFrameType::UNKNOWN) { QUICDebug("Failed to create a frame (%u bytes skipped)", size - cursor); break; } if (has_non_probing_frame) { - *has_non_probing_frame |= !frame->is_probing_frame(); + *has_non_probing_frame |= !frame.is_probing_frame(); } - cursor += frame->size(); + cursor += frame.size(); - QUICFrameType type = frame->type(); + QUICFrameType type = frame.type(); if (type == QUICFrameType::STREAM) { is_flow_controlled = true; @@ -70,7 +69,7 @@ QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *pa if (is_debug_tag_set(tag) && type != QUICFrameType::PADDING) { char msg[1024]; - frame->debug_msg(msg, sizeof(msg)); + frame.debug_msg(msg, sizeof(msg)); QUICDebug("[RX] %s", msg); } @@ -80,7 +79,7 @@ QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *pa std::vector handlers = this->_handlers[static_cast(type)]; for (auto h : handlers) { - error = h->handle_frame(level, *frame.get()); + error = h->handle_frame(level, frame); // TODO: is there any case to continue this loop even if error? if (error != nullptr) { return error; diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index 0f1c50f1713..9c34d5750e0 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -30,8 +30,14 @@ class QUICFrameGenerator { public: virtual ~QUICFrameGenerator(){}; - virtual bool will_generate_frame(QUICEncryptionLevel level) = 0; - virtual QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) = 0; + virtual bool will_generate_frame(QUICEncryptionLevel level) = 0; + + /* + * This function constructs an instance of QUICFrame on buf. + * It returns a pointer for the frame if it succeeded, and returns nullptr if it failed. + */ + virtual QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) = 0; void on_frame_acked(QUICFrameId id); void on_frame_lost(QUICFrameId id); diff --git a/iocore/net/quic/QUICFrameRetransmitter.cc b/iocore/net/quic/QUICFrameRetransmitter.cc index 02d03a315db..008b72c161b 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.cc +++ b/iocore/net/quic/QUICFrameRetransmitter.cc @@ -29,11 +29,11 @@ ClassAllocator quicFrameInformationAllocator("quicFrameInformationAllocator"); -QUICFrameUPtr -QUICFrameRetransmitter::create_retransmitted_frame(QUICEncryptionLevel level, uint16_t maximum_frame_size, QUICFrameId id, - QUICFrameGenerator *owner) +QUICFrame * +QUICFrameRetransmitter::create_retransmitted_frame(uint8_t *buf, QUICEncryptionLevel level, uint16_t maximum_frame_size, + QUICFrameId id, QUICFrameGenerator *owner) { - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrame *frame = nullptr; if (this->_lost_frame_info_queue.empty()) { return frame; } @@ -52,10 +52,10 @@ QUICFrameRetransmitter::create_retransmitted_frame(QUICEncryptionLevel level, ui switch (info->type) { case QUICFrameType::STREAM: - frame = this->_create_stream_frame(info, maximum_frame_size, tmp_queue, id, owner); + frame = this->_create_stream_frame(buf, info, maximum_frame_size, tmp_queue, id, owner); break; case QUICFrameType::CRYPTO: - frame = this->_create_crypto_frame(info, maximum_frame_size, tmp_queue, id, owner); + frame = this->_create_crypto_frame(buf, info, maximum_frame_size, tmp_queue, id, owner); break; default: ink_assert("unknown frame type"); @@ -94,12 +94,12 @@ QUICFrameRetransmitter::_append_info_queue(std::deque } } -QUICFrameUPtr -QUICFrameRetransmitter::_create_stream_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, +QUICFrame * +QUICFrameRetransmitter::_create_stream_frame(uint8_t *buf, QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner) { - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrame *frame = nullptr; StreamFrameInfo *stream_info = reinterpret_cast(info->data); static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; @@ -112,21 +112,21 @@ QUICFrameRetransmitter::_create_stream_frame(QUICFrameInformationUPtr &info, uin // These size calculation should not exist multiple places uint64_t maximum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD; if (maximum_data_size >= static_cast(stream_info->block->size())) { - frame = QUICFrameFactory::create_stream_frame(stream_info->block, stream_info->stream_id, stream_info->offset, + frame = QUICFrameFactory::create_stream_frame(buf, stream_info->block, stream_info->stream_id, stream_info->offset, stream_info->has_fin, true, true, id, owner); ink_assert(frame->size() <= maximum_frame_size); stream_info->block = nullptr; } else { - frame = QUICFrameFactory::create_stream_frame(stream_info->block, stream_info->stream_id, stream_info->offset, false, true, + frame = QUICFrameFactory::create_stream_frame(buf, stream_info->block, stream_info->stream_id, stream_info->offset, false, true, true, id, owner); - QUICStreamFrame *stream_frame = static_cast(frame.get()); + QUICStreamFrame *stream_frame = static_cast(frame); IOBufferBlock *block = stream_frame->data(); size_t over_length = stream_frame->data_length() - maximum_data_size; block->_end = std::max(block->start(), block->_end - over_length); if (block->read_avail() == 0) { // no payload tmp_queue.push_back(std::move(info)); - return QUICFrameFactory::create_null_frame(); + return nullptr; } stream_info->block->consume(stream_frame->data_length()); stream_info->offset += stream_frame->data_length(); @@ -139,20 +139,20 @@ QUICFrameRetransmitter::_create_stream_frame(QUICFrameInformationUPtr &info, uin return frame; } -QUICFrameUPtr -QUICFrameRetransmitter::_create_crypto_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, +QUICFrame * +QUICFrameRetransmitter::_create_crypto_frame(uint8_t *buf, QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner) { CryptoFrameInfo *crypto_info = reinterpret_cast(info->data); // FIXME: has_offset and has_length should be configurable. - auto frame = QUICFrameFactory::create_crypto_frame(crypto_info->block, crypto_info->offset, id, owner); + auto frame = QUICFrameFactory::create_crypto_frame(buf, crypto_info->block, crypto_info->offset, id, owner); if (frame->size() > maximum_frame_size) { - QUICCryptoFrame *crypto_frame = static_cast(frame.get()); + QUICCryptoFrame *crypto_frame = static_cast(frame); if (crypto_frame->size() - crypto_frame->data_length() > maximum_frame_size) { // header length is larger than maximum_frame_size. tmp_queue.push_back(std::move(info)); - return QUICFrameFactory::create_null_frame(); + return nullptr; } IOBufferBlock *block = crypto_frame->data(); @@ -161,7 +161,7 @@ QUICFrameRetransmitter::_create_crypto_frame(QUICFrameInformationUPtr &info, uin if (block->read_avail() == 0) { // no payload tmp_queue.push_back(std::move(info)); - return QUICFrameFactory::create_null_frame(); + return nullptr; } crypto_info->block->consume(crypto_frame->data_length()); diff --git a/iocore/net/quic/QUICFrameRetransmitter.h b/iocore/net/quic/QUICFrameRetransmitter.h index f64d71fe5b5..bbd53c3bec9 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.h +++ b/iocore/net/quic/QUICFrameRetransmitter.h @@ -71,15 +71,15 @@ struct AckFrameInfo { class QUICFrameRetransmitter { public: - virtual QUICFrameUPtr create_retransmitted_frame(QUICEncryptionLevel level, uint16_t maximum_frame_size, QUICFrameId id = 0, - QUICFrameGenerator *owner = nullptr); + virtual QUICFrame *create_retransmitted_frame(uint8_t *buf, QUICEncryptionLevel level, uint16_t maximum_frame_size, + QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); virtual void save_frame_info(QUICFrameInformationUPtr info); private: - QUICFrameUPtr _create_stream_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, - std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner); - QUICFrameUPtr _create_crypto_frame(QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, - std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner); + QUICFrame *_create_stream_frame(uint8_t *buf, QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner); + QUICFrame *_create_crypto_frame(uint8_t *buf, QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, + std::deque &tmp_queue, QUICFrameId id, QUICFrameGenerator *owner); void _append_info_queue(std::deque &tmp_queue); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 51349dec341..ef69639dfd0 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -346,19 +346,17 @@ QUICHandshake::will_generate_frame(QUICEncryptionLevel level) return this->_crypto_streams[static_cast(level)].will_generate_frame(level); } -QUICFrameUPtr -QUICHandshake::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICFrame * +QUICHandshake::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - // CRYPTO frame is not flow-controlled - connection_credit = UINT64_MAX; + // connection_credit = UINT64_MAX; - if (!this->_is_level_matched(level)) { - return frame; - } + QUICFrame *frame = nullptr; - frame = this->_crypto_streams[static_cast(level)].generate_frame(level, connection_credit, maximum_frame_size); + if (this->_is_level_matched(level)) { + frame = this->_crypto_streams[static_cast(level)].generate_frame(buf, level, connection_credit, maximum_frame_size); + } return frame; } diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 3e46ea5c149..56436b6d1c6 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -52,7 +52,8 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) override; // for client side QUICConnectionErrorUPtr start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled); diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index 09c870e2383..6e448d1ee55 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -29,9 +29,11 @@ void QUICIncomingFrameBuffer::clear() { + // FIXME delete the items this->_out_of_order_queue.clear(); while (!this->_recv_buffer.empty()) { + // FIXME delete the items this->_recv_buffer.pop(); } @@ -52,13 +54,13 @@ QUICIncomingStreamFrameBuffer::~QUICIncomingStreamFrameBuffer() this->clear(); } -QUICFrameSPtr +const QUICFrame * QUICIncomingStreamFrameBuffer::pop() { if (this->_recv_buffer.empty()) { auto elem = this->_out_of_order_queue.find(this->_recv_offset); while (elem != this->_out_of_order_queue.end()) { - QUICStreamFrameSPtr frame = std::static_pointer_cast(elem->second); + const QUICStreamFrame *frame = static_cast(elem->second); this->_recv_buffer.push(frame); this->_recv_offset += frame->data_length(); @@ -78,18 +80,18 @@ QUICIncomingStreamFrameBuffer::pop() QUICConnectionErrorUPtr QUICIncomingStreamFrameBuffer::insert(const QUICFrame &frame) { - const QUICStreamFrame *stream_frame = static_cast(&frame); + const QUICStreamFrame &stream_frame = static_cast(frame); - QUICOffset offset = stream_frame->offset(); - size_t len = stream_frame->data_length(); + QUICOffset offset = stream_frame.offset(); + size_t len = stream_frame.data_length(); - QUICConnectionErrorUPtr err = this->_check_and_set_fin_flag(offset, len, stream_frame->has_fin_flag()); + QUICConnectionErrorUPtr err = this->_check_and_set_fin_flag(offset, len, stream_frame.has_fin_flag()); if (err != nullptr) { return err; } // Ignore empty stream frame except pure fin stream frame - if (len == 0 && !stream_frame->has_fin_flag()) { + if (len == 0 && !stream_frame.has_fin_flag()) { return nullptr; } @@ -97,11 +99,11 @@ QUICIncomingStreamFrameBuffer::insert(const QUICFrame &frame) // dup frame; return nullptr; } else if (this->_recv_offset == offset) { - this->_recv_offset = offset + len; - QUICFrameSPtr cloned = frame.clone(); + this->_recv_offset = offset + len; + QUICFrame *cloned = new QUICStreamFrame(stream_frame); this->_recv_buffer.push(cloned); } else { - QUICFrameSPtr cloned = frame.clone(); + QUICFrame *cloned = new QUICStreamFrame(stream_frame); this->_out_of_order_queue.insert(std::make_pair(offset, cloned)); } @@ -185,13 +187,13 @@ QUICIncomingCryptoFrameBuffer::~QUICIncomingCryptoFrameBuffer() super::clear(); } -QUICFrameSPtr +const QUICFrame * QUICIncomingCryptoFrameBuffer::pop() { if (this->_recv_buffer.empty()) { auto elem = this->_out_of_order_queue.find(this->_recv_offset); while (elem != this->_out_of_order_queue.end()) { - QUICCryptoFrameSPtr frame = std::static_pointer_cast(elem->second); + const QUICCryptoFrame *frame = static_cast(elem->second); this->_recv_buffer.push(frame); this->_recv_offset += frame->data_length(); @@ -212,10 +214,10 @@ QUICIncomingCryptoFrameBuffer::pop() QUICConnectionErrorUPtr QUICIncomingCryptoFrameBuffer::insert(const QUICFrame &frame) { - const QUICCryptoFrame *crypto_frame = static_cast(&frame); + const QUICCryptoFrame &crypto_frame = static_cast(frame); - QUICOffset offset = crypto_frame->offset(); - size_t len = crypto_frame->data_length(); + QUICOffset offset = crypto_frame.offset(); + size_t len = crypto_frame.data_length(); // Ignore empty stream frame if (len == 0) { @@ -226,11 +228,11 @@ QUICIncomingCryptoFrameBuffer::insert(const QUICFrame &frame) // dup frame; return nullptr; } else if (this->_recv_offset == offset) { - this->_recv_offset = offset + len; - QUICFrameSPtr cloned = frame.clone(); + this->_recv_offset = offset + len; + QUICFrame *cloned = new QUICCryptoFrame(crypto_frame); this->_recv_buffer.push(cloned); } else { - QUICFrameSPtr cloned = frame.clone(); + QUICFrame *cloned = new QUICCryptoFrame(crypto_frame); this->_out_of_order_queue.insert(std::make_pair(offset, cloned)); } diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index cbca7bb9969..3dffc32022b 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -33,7 +33,7 @@ class QUICIncomingFrameBuffer { public: - virtual QUICFrameSPtr pop() = 0; + virtual const QUICFrame *pop() = 0; /* * Becasue frames passed by FrameDispatcher is temporal, this clones a passed frame to ensure that we can use it later. */ @@ -44,8 +44,8 @@ class QUICIncomingFrameBuffer protected: QUICOffset _recv_offset = 0; - std::queue _recv_buffer; - std::map _out_of_order_queue; + std::queue _recv_buffer; + std::map _out_of_order_queue; }; class QUICIncomingStreamFrameBuffer : public QUICIncomingFrameBuffer, public QUICTransferProgressProvider @@ -56,7 +56,7 @@ class QUICIncomingStreamFrameBuffer : public QUICIncomingFrameBuffer, public QUI QUICIncomingStreamFrameBuffer() {} ~QUICIncomingStreamFrameBuffer(); - QUICFrameSPtr pop() override; + const QUICFrame *pop() override; QUICConnectionErrorUPtr insert(const QUICFrame &frame) override; void clear() override; @@ -81,7 +81,7 @@ class QUICIncomingCryptoFrameBuffer : public QUICIncomingFrameBuffer QUICIncomingCryptoFrameBuffer() {} ~QUICIncomingCryptoFrameBuffer(); - QUICFrameSPtr pop() override; + const QUICFrame *pop() override; QUICConnectionErrorUPtr insert(const QUICFrame &frame) override; private: diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index 40e2d140d58..b0207db8e8c 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -126,10 +126,11 @@ QUICPathValidator::will_generate_frame(QUICEncryptionLevel level) return (this->_has_outgoing_challenge || this->_has_outgoing_response); } -QUICFrameUPtr -QUICPathValidator::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_quic_packet_size) +QUICFrame * +QUICPathValidator::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_quic_packet_size) { - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrame *frame = nullptr; // PATH_CHALLENGE and PATH_RESPONSE are not flow-controlled connection_credit = UINT64_MAX; @@ -139,19 +140,19 @@ QUICPathValidator::generate_frame(QUICEncryptionLevel level, uint64_t connection } if (this->_has_outgoing_response) { - frame = QUICFrameFactory::create_path_response_frame(this->_incoming_challenge); + frame = QUICFrameFactory::create_path_response_frame(buf, this->_incoming_challenge); if (frame && frame->size() > maximum_quic_packet_size) { // Cancel generating frame - frame = QUICFrameFactory::create_null_frame(); + frame = nullptr; } else { this->_has_outgoing_response = false; } } else if (this->_has_outgoing_challenge) { - frame = QUICFrameFactory::create_path_challenge_frame(this->_outgoing_challenge + - (QUICPathChallengeFrame::DATA_LEN * (this->_has_outgoing_challenge - 1))); + frame = QUICFrameFactory::create_path_challenge_frame( + buf, this->_outgoing_challenge + (QUICPathChallengeFrame::DATA_LEN * (this->_has_outgoing_challenge - 1))); if (frame && frame->size() > maximum_quic_packet_size) { // Cancel generating frame - frame = QUICFrameFactory::create_null_frame(); + frame = nullptr; } else { --this->_has_outgoing_challenge; ink_assert(this->_has_outgoing_challenge >= 0); diff --git a/iocore/net/quic/QUICPathValidator.h b/iocore/net/quic/QUICPathValidator.h index afa4abfb8ff..d79d5f68ac2 100644 --- a/iocore/net/quic/QUICPathValidator.h +++ b/iocore/net/quic/QUICPathValidator.h @@ -42,7 +42,8 @@ class QUICPathValidator : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameGeneratro bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) override; private: enum class ValidationState : int { diff --git a/iocore/net/quic/QUICPinger.cc b/iocore/net/quic/QUICPinger.cc index 01917c4426f..f7e1977bac2 100644 --- a/iocore/net/quic/QUICPinger.cc +++ b/iocore/net/quic/QUICPinger.cc @@ -43,10 +43,10 @@ QUICPinger::will_generate_frame(QUICEncryptionLevel level) return this->_need_to_fire[QUICTypeUtil::pn_space_index(level)] > 0; } -QUICFrameUPtr -QUICPinger::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICFrame * +QUICPinger::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrame *frame = nullptr; if (!this->_is_level_matched(level)) { return frame; @@ -54,7 +54,7 @@ QUICPinger::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit if (this->_need_to_fire[static_cast(level)] > 0 && maximum_frame_size > 0) { // don't care ping frame lost or acked - frame = QUICFrameFactory::create_ping_frame(0, nullptr); + frame = QUICFrameFactory::create_ping_frame(buf, 0, nullptr); this->_need_to_fire[static_cast(level)] = 0; } diff --git a/iocore/net/quic/QUICPinger.h b/iocore/net/quic/QUICPinger.h index 7251723d760..80098e8b444 100644 --- a/iocore/net/quic/QUICPinger.h +++ b/iocore/net/quic/QUICPinger.h @@ -38,7 +38,8 @@ class QUICPinger : public QUICFrameGenerator // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) override; private: // Initial, 0/1-RTT, and Handshake diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 9fdb60954a8..d92b1d0718b 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -338,11 +338,11 @@ QUICStream::recv(const QUICStreamFrame &frame) return error; } - auto new_frame = this->_received_stream_frame_buffer.pop(); - QUICStreamFrameSPtr stream_frame = nullptr; + auto new_frame = this->_received_stream_frame_buffer.pop(); + const QUICStreamFrame *stream_frame = nullptr; while (new_frame != nullptr) { - stream_frame = std::static_pointer_cast(new_frame); + stream_frame = static_cast(new_frame); this->_write_to_read_vio(stream_frame->offset(), reinterpret_cast(stream_frame->data()->start()), stream_frame->data_length(), stream_frame->has_fin_flag()); @@ -409,22 +409,22 @@ QUICStream::will_generate_frame(QUICEncryptionLevel level) return this->_write_vio.get_reader()->read_avail() > 0; } -QUICFrameUPtr -QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICFrame * +QUICStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); - QUICFrameUPtr frame = this->create_retransmitted_frame(level, maximum_frame_size, this->_issue_frame_id(), this); + QUICFrame *frame = this->create_retransmitted_frame(buf, level, maximum_frame_size, this->_issue_frame_id(), this); if (frame != nullptr) { ink_assert(frame->type() == QUICFrameType::STREAM); - this->_records_stream_frame(level, *static_cast(frame.get())); + this->_records_stream_frame(level, *static_cast(frame)); return frame; } // RESET_STREAM if (this->_reset_reason && !this->_is_reset_sent) { - frame = QUICFrameFactory::create_rst_stream_frame(*this->_reset_reason, this->_issue_frame_id(), this); - this->_records_rst_stream_frame(level, *static_cast(frame.get())); + frame = QUICFrameFactory::create_rst_stream_frame(buf, *this->_reset_reason, this->_issue_frame_id(), this); + this->_records_rst_stream_frame(level, *static_cast(frame)); this->_state.update_with_sending_frame(*frame); this->_is_reset_sent = true; return frame; @@ -433,15 +433,15 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit // STOP_SENDING if (this->_stop_sending_reason && !this->_is_stop_sending_sent) { frame = - QUICFrameFactory::create_stop_sending_frame(this->id(), this->_stop_sending_reason->code, this->_issue_frame_id(), this); - this->_records_stop_sending_frame(level, *static_cast(frame.get())); + QUICFrameFactory::create_stop_sending_frame(buf, this->id(), this->_stop_sending_reason->code, this->_issue_frame_id(), this); + this->_records_stop_sending_frame(level, *static_cast(frame)); this->_state.update_with_sending_frame(*frame); this->_is_stop_sending_sent = true; return frame; } // MAX_STREAM_DATA - frame = this->_local_flow_controller.generate_frame(level, UINT16_MAX, maximum_frame_size); + frame = this->_local_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size); if (frame) { return frame; } @@ -477,7 +477,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit uint64_t stream_credit = this->_remote_flow_controller.credit(); if (stream_credit == 0) { // STREAM_DATA_BLOCKED - frame = this->_remote_flow_controller.generate_frame(level, UINT16_MAX, maximum_frame_size); + frame = this->_remote_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size); return frame; } @@ -503,8 +503,8 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit // STREAM - Pure FIN or data length is lager than 0 // FIXME has_length_flag and has_offset_flag should be configurable - frame = - QUICFrameFactory::create_stream_frame(block, this->_id, this->_send_offset, fin, true, true, this->_issue_frame_id(), this); + frame = QUICFrameFactory::create_stream_frame(buf, block, this->_id, this->_send_offset, fin, true, true, this->_issue_frame_id(), + this); if (!this->_state.is_allowed_to_send(*frame)) { QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); return frame; @@ -527,7 +527,7 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit this->_send_offset += len; this->_write_vio.ndone += len; } - this->_records_stream_frame(level, *static_cast(frame.get())); + this->_records_stream_frame(level, *static_cast(frame)); this->_signal_write_event(); this->_state.update_with_sending_frame(*frame); @@ -832,7 +832,7 @@ QUICCryptoStream::recv(const QUICCryptoFrame &frame) auto new_frame = this->_received_stream_frame_buffer.pop(); while (new_frame != nullptr) { - QUICCryptoFrameSPtr crypto_frame = std::static_pointer_cast(new_frame); + const QUICCryptoFrame *crypto_frame = static_cast(new_frame); this->_read_buffer->write(reinterpret_cast(crypto_frame->data()->start()), crypto_frame->data_length()); new_frame = this->_received_stream_frame_buffer.pop(); @@ -865,19 +865,19 @@ QUICCryptoStream::will_generate_frame(QUICEncryptionLevel level) return this->_write_buffer_reader->is_read_avail_more_than(0); } -QUICFrameUPtr -QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICFrame * +QUICCryptoStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { QUICConnectionErrorUPtr error = nullptr; if (this->_reset_reason) { - return QUICFrameFactory::create_rst_stream_frame(*this->_reset_reason); + return QUICFrameFactory::create_rst_stream_frame(buf, *this->_reset_reason); } - QUICFrameUPtr frame = this->create_retransmitted_frame(level, maximum_frame_size, this->_issue_frame_id(), this); + QUICFrame *frame = this->create_retransmitted_frame(buf, level, maximum_frame_size, this->_issue_frame_id(), this); if (frame != nullptr) { ink_assert(frame->type() == QUICFrameType::CRYPTO); - this->_records_crypto_frame(level, *static_cast(frame.get())); + this->_records_crypto_frame(level, *static_cast(frame)); return frame; } @@ -897,10 +897,10 @@ QUICCryptoStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_ block->_end = std::min(block->start() + frame_payload_size, block->_buf_end); ink_assert(static_cast(block->read_avail()) == frame_payload_size); - frame = QUICFrameFactory::create_crypto_frame(block, this->_send_offset, this->_issue_frame_id(), this); + frame = QUICFrameFactory::create_crypto_frame(buf, block, this->_send_offset, this->_issue_frame_id(), this); this->_send_offset += frame_payload_size; this->_write_buffer_reader->consume(frame_payload_size); - this->_records_crypto_frame(level, *static_cast(frame.get())); + this->_records_crypto_frame(level, *static_cast(frame)); return frame; } diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 27e8cba4286..85f121e4af5 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -92,7 +92,8 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) override; // QUICTransferProgressProvider bool is_transfer_goal_set() const override; @@ -186,7 +187,8 @@ class QUICCryptoStream : public QUICFrameGenerator, public QUICFrameRetransmitte // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) override; private: void _on_frame_acked(QUICFrameInformationUPtr &info) override; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 04b97d6b6d3..ea99d3f1fbf 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -406,11 +406,10 @@ QUICStreamManager::will_generate_frame(QUICEncryptionLevel level) return false; } -QUICFrameUPtr -QUICStreamManager::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICFrame * +QUICStreamManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { - // FIXME We should pick a stream based on priority - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrame *frame = nullptr; if (!this->_is_level_matched(level)) { return frame; @@ -421,15 +420,16 @@ QUICStreamManager::generate_frame(QUICEncryptionLevel level, uint64_t connection return frame; } + // FIXME We should pick a stream based on priority for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { - frame = s->generate_frame(level, connection_credit, maximum_frame_size); + frame = s->generate_frame(buf, level, connection_credit, maximum_frame_size); if (frame) { break; } } if (frame != nullptr && frame->type() == QUICFrameType::STREAM) { - this->add_total_offset_sent(static_cast(frame.get())->data_length()); + this->add_total_offset_sent(static_cast(frame)->data_length()); } return frame; diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 1a89d222d3e..4277f5c5f6f 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -65,7 +65,8 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrameUPtr generate_frame(QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size) override; private: QUICStream *_find_stream(QUICStreamId id); From 6e164ab1600542cd8d0b1d7890fa2543f29bf011 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 8 Feb 2019 16:10:37 +0900 Subject: [PATCH 1116/1313] Use pre-allocated buffer for QUICFrameFactory::fast_create --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICFrame.cc | 5 +++-- iocore/net/quic/QUICFrame.h | 3 +++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 2460a08b5ef..0b56542d7a7 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1369,7 +1369,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } bool ack_only = true; - uint8_t frame_instance_buffer[1024]; // This is for a frame instance but not serialized frame data + uint8_t frame_instance_buffer[QUICFrame::MAX_INSTANCE_SIZE]; // This is for a frame instance but not serialized frame data QUICFrame *frame = nullptr; for (auto g : this->_frame_generators) { while (g->will_generate_frame(level)) { diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 79c16c8c8cc..f0fc83a13d6 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2516,10 +2516,11 @@ QUICFrameFactory::fast_create(const uint8_t *buf, size_t len) return this->_unknown_frame; } - QUICFrame *frame = this->_reusable_frames[static_cast(QUICFrame::type(buf))]; + ptrdiff_t type_index = static_cast(QUICFrame::type(buf)); + QUICFrame *frame = this->_reusable_frames[type_index]; if (frame == nullptr) { - frame = QUICFrameFactory::create(static_cast(malloc(1024)), buf, len); + frame = QUICFrameFactory::create(this->_buf_for_fast_create + (type_index * QUICFrame::MAX_INSTANCE_SIZE), buf, len); if (frame != nullptr) { this->_reusable_frames[static_cast(QUICFrame::type(buf))] = frame; } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 18289f761e5..8b2186ea434 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -53,6 +53,8 @@ using QUICFrameId = uint64_t; class QUICFrame { public: + constexpr static int MAX_INSTANCE_SIZE = 256; + virtual ~QUICFrame() {} static QUICFrameType type(const uint8_t *buf); @@ -849,6 +851,7 @@ class QUICFrameFactory private: // FIXME Actual number of frame types is several but some of the values are not sequential. QUICFrame *_reusable_frames[256] = {nullptr}; + uint8_t _buf_for_fast_create[256 * QUICFrame::MAX_INSTANCE_SIZE]; QUICUnknownFrame _unknown_frame; }; From 9afd8c997cb88c0390685c41c17cfd7d7081c7dc Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 8 Feb 2019 16:15:18 +0900 Subject: [PATCH 1117/1313] Use QUICFrame::MAX_INSTANCE_FRAME --- iocore/net/QUICNetVConnection.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 0b56542d7a7..839f43cb899 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1462,7 +1462,7 @@ QUICNetVConnection::_packetize_closing_frame() QUICFrame *frame = nullptr; // CONNECTION_CLOSE - uint8_t frame_buf[1024]; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; frame = QUICFrameFactory::create_connection_close_frame(frame_buf, *this->_connection_error); uint32_t max_size = this->maximum_quic_packet_size(); From b4507fb3451ec11596835547ac126ebe171dcc33 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 13 Feb 2019 11:33:28 +0900 Subject: [PATCH 1118/1313] Update tests that create QUICFrame instances --- iocore/net/quic/QUICFrame.h | 3 + .../net/quic/test/test_QUICAckFrameCreator.cc | 68 ++--- .../net/quic/test/test_QUICFlowController.cc | 84 +++--- iocore/net/quic/test/test_QUICFrame.cc | 243 ++++++++---------- .../quic/test/test_QUICFrameRetransmitter.cc | 62 +++-- .../quic/test/test_QUICIncomingFrameBuffer.cc | 106 +++++--- iocore/net/quic/test/test_QUICLossDetector.cc | 22 +- iocore/net/quic/test/test_QUICStream.cc | 38 +-- .../net/quic/test/test_QUICStreamManager.cc | 44 ++-- iocore/net/quic/test/test_QUICStreamState.cc | 31 ++- 10 files changed, 384 insertions(+), 317 deletions(-) diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 8b2186ea434..225a66ca1eb 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -257,6 +257,9 @@ class QUICAckFrame : public QUICFrame QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); + // There's no reasont restrict copy, but we need to write the copy constructor. Otherwise it will crash on destruct. + QUICAckFrame(const QUICAckFrame &) = delete; + virtual ~QUICAckFrame(); virtual QUICFrameType type() const override; virtual size_t size() const override; diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index ccdaf3dbddf..15b1e13dc91 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -31,16 +31,17 @@ TEST_CASE("QUICAckFrameManager", "[quic]") { QUICAckFrameManager ack_manager; QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; // Initial state - std::shared_ptr ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - std::shared_ptr frame = std::static_pointer_cast(ack_frame); + QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + QUICAckFrame *frame = static_cast(ack_frame); CHECK(frame == nullptr); // One packet ack_manager.update(level, 1, 1, false); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 1); @@ -54,8 +55,8 @@ TEST_CASE("QUICAckFrameManager", "[quic]") ack_manager.update(level, 5, 1, false); ack_manager.update(level, 3, 1, false); ack_manager.update(level, 4, 1, false); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 5); @@ -65,8 +66,8 @@ TEST_CASE("QUICAckFrameManager", "[quic]") ack_manager.update(level, 6, 1, false); ack_manager.update(level, 7, 1, false); ack_manager.update(level, 10, 1, false); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); CHECK(frame->largest_acknowledged() == 10); @@ -77,14 +78,14 @@ TEST_CASE("QUICAckFrameManager", "[quic]") ack_manager.on_frame_acked(frame->id()); CHECK(ack_manager.will_generate_frame(level) == false); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); CHECK(ack_frame == nullptr); ack_manager.update(level, 11, 1, false); ack_manager.update(level, 12, 1, false); ack_manager.update(level, 13, 1, false); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 13); @@ -98,11 +99,11 @@ TEST_CASE("QUICAckFrameManager", "[quic]") ack_manager.update(level, 15, 1, true); ack_manager.update(level, 16, 1, true); CHECK(ack_manager.will_generate_frame(level) == false); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); ack_manager.update(level, 17, 1, false); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 17); @@ -187,8 +188,9 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") QUICAckFrameManager ack_manager; QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; - std::shared_ptr ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - std::shared_ptr frame = std::static_pointer_cast(ack_frame); + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + QUICAckFrame *frame = static_cast(ack_frame); CHECK(frame == nullptr); // unorder frame should sent immediately @@ -201,8 +203,8 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") sleep(1); Thread::get_hrtime_updated(); CHECK(ack_manager.will_generate_frame(level) == true); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); CHECK(frame->ack_block_count() == 0); CHECK(frame->largest_acknowledged() == 2); @@ -217,8 +219,9 @@ TEST_CASE("QUICAckFrameManager_loss_recover", "[quic]") QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; // Initial state - std::shared_ptr ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - std::shared_ptr frame = std::static_pointer_cast(ack_frame); + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + QUICAckFrame *frame = static_cast(ack_frame); CHECK(frame == nullptr); ack_manager.update(level, 2, 1, false); @@ -227,8 +230,8 @@ TEST_CASE("QUICAckFrameManager_loss_recover", "[quic]") ack_manager.update(level, 8, 1, false); ack_manager.update(level, 9, 1, false); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 2); CHECK(frame->largest_acknowledged() == 9); @@ -239,8 +242,8 @@ TEST_CASE("QUICAckFrameManager_loss_recover", "[quic]") ack_manager.update(level, 7, 1, false); ack_manager.update(level, 4, 1, false); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); CHECK(frame->largest_acknowledged() == 9); @@ -293,10 +296,11 @@ TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") { QUICAckFrameManager ack_manager; QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; // Initial state - std::shared_ptr ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - std::shared_ptr frame = std::static_pointer_cast(ack_frame); + QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + QUICAckFrame *frame = static_cast(ack_frame); CHECK(frame == nullptr); ack_manager.update(level, 2, 1, false); @@ -305,8 +309,8 @@ TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") ack_manager.update(level, 8, 1, false); ack_manager.update(level, 9, 1, false); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 2); CHECK(frame->largest_acknowledged() == 9); @@ -315,8 +319,8 @@ TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") ack_manager.on_frame_lost(frame->id()); CHECK(ack_manager.will_generate_frame(level) == true); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 2); CHECK(frame->largest_acknowledged() == 9); @@ -329,8 +333,8 @@ TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") ack_manager.update(level, 7, 1, false); ack_manager.update(level, 4, 1, false); - ack_frame = ack_manager.generate_frame(level, UINT16_MAX, UINT16_MAX); - frame = std::static_pointer_cast(ack_frame); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); CHECK(frame->largest_acknowledged() == 9); diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index b5cca329e1d..83335609f8c 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -52,6 +52,7 @@ class MockRTTProvider : public QUICRTTProvider TEST_CASE("QUICFlowController_Local_Connection", "[quic]") { int ret = 0; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; MockRTTProvider rp(DEFAULT_RTT); QUICLocalConnectionFlowController fc(&rp, 1024); @@ -97,7 +98,7 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") fc.forward_limit(2048); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 2048); - QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024); + QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024); CHECK(frame); CHECK(frame->type() == QUICFrameType::MAX_DATA); @@ -110,6 +111,7 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") { int ret = 0; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; QUICRemoteConnectionFlowController fc(1024); // Check initial state @@ -148,7 +150,7 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") CHECK(fc.current_offset() == 1000); CHECK(fc.current_limit() == 1024); CHECK(ret != 0); - QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024); + QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024); CHECK(frame); CHECK(frame->type() == QUICFrameType::DATA_BLOCKED); @@ -166,6 +168,7 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") TEST_CASE("QUICFlowController_Remote_Connection_ZERO_Credit", "[quic]") { int ret = 0; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; QUICRemoteConnectionFlowController fc(1024); // Check initial state @@ -180,7 +183,7 @@ TEST_CASE("QUICFlowController_Remote_Connection_ZERO_Credit", "[quic]") CHECK(fc.will_generate_frame(QUICEncryptionLevel::ONE_RTT)); // if there're anything to send - QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024); + QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024); CHECK(frame); CHECK(frame->type() == QUICFrameType::DATA_BLOCKED); @@ -198,6 +201,7 @@ TEST_CASE("QUICFlowController_Remote_Connection_ZERO_Credit", "[quic]") TEST_CASE("QUICFlowController_Local_Stream", "[quic]") { int ret = 0; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; MockRTTProvider rp(DEFAULT_RTT); QUICLocalStreamFlowController fc(&rp, 1024, 0); @@ -243,7 +247,7 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]") fc.forward_limit(2048); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 2048); - QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024); + QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024); CHECK(frame); CHECK(frame->type() == QUICFrameType::MAX_STREAM_DATA); @@ -316,152 +320,156 @@ TEST_CASE("Frame retransmission", "[quic]") SECTION("BLOCKED frame") { int ret = 0; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; QUICRemoteConnectionFlowController fc(1024); // Check initial state - auto frame = fc.generate_frame(level, 1024, 1024); + auto frame = fc.generate_frame(frame_buf, level, 1024, 1024); CHECK(!frame); ret = fc.update(1024); CHECK(ret == 0); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 1024); + CHECK(static_cast(frame)->offset() == 1024); QUICFrameId id = frame->id(); // Don't retransmit unless the frame is lost - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(!frame); // Retransmit fc.on_frame_lost(id); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 1024); + CHECK(static_cast(frame)->offset() == 1024); // Don't send if it was not blocked fc.on_frame_lost(frame->id()); fc.forward_limit(2048); ret = fc.update(1536); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); CHECK(!frame); // This should not be retransmition ret = fc.update(2048); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 2048); + CHECK(static_cast(frame)->offset() == 2048); } SECTION("STREAM_DATA_BLOCKED frame") { int ret = 0; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; QUICRemoteStreamFlowController fc(1024, 0); // Check initial state - auto frame = fc.generate_frame(level, 1024, 1024); + auto frame = fc.generate_frame(frame_buf, level, 1024, 1024); CHECK(!frame); ret = fc.update(1024); CHECK(ret == 0); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 1024); + CHECK(static_cast(frame)->offset() == 1024); QUICFrameId id = frame->id(); // Don't retransmit unless the frame is lost - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(!frame); // Retransmit fc.on_frame_lost(id); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 1024); + CHECK(static_cast(frame)->offset() == 1024); // Don't send if it was not blocked fc.on_frame_lost(frame->id()); fc.forward_limit(2048); ret = fc.update(1536); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); CHECK(!frame); // This should not be retransmition ret = fc.update(2048); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->offset() == 2048); + CHECK(static_cast(frame)->offset() == 2048); } SECTION("MAX_DATA frame") { int ret = 0; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; MockRTTProvider rp(DEFAULT_RTT); QUICLocalConnectionFlowController fc(&rp, 1024); // Check initial state - auto frame = fc.generate_frame(level, 1024, 1024); + auto frame = fc.generate_frame(frame_buf, level, 1024, 1024); CHECK(!frame); fc.update(1024); fc.forward_limit(1024); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->maximum_data() == 1024); + CHECK(static_cast(frame)->maximum_data() == 1024); QUICFrameId id = frame->id(); // Don't retransmit unless the frame is lost - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(!frame); // Retransmit fc.on_frame_lost(id); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->maximum_data() == 1024); + CHECK(static_cast(frame)->maximum_data() == 1024); // Send new one if it was updated fc.on_frame_lost(id); fc.forward_limit(2048); fc.update(2048); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->maximum_data() == 2048); + CHECK(static_cast(frame)->maximum_data() == 2048); } SECTION("MAX_STREAM_DATA frame") { int ret = 0; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; MockRTTProvider rp(DEFAULT_RTT); QUICLocalStreamFlowController fc(&rp, 1024, 0); // Check initial state - auto frame = fc.generate_frame(level, 1024, 1024); + auto frame = fc.generate_frame(frame_buf, level, 1024, 1024); CHECK(!frame); fc.update(1024); fc.forward_limit(1024); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->maximum_stream_data() == 1024); + CHECK(static_cast(frame)->maximum_stream_data() == 1024); QUICFrameId id = frame->id(); // Don't retransmit unless the frame is lost - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(!frame); // Retransmit fc.on_frame_lost(id); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->maximum_stream_data() == 1024); + CHECK(static_cast(frame)->maximum_stream_data() == 1024); // Send new one if it was updated fc.on_frame_lost(id); fc.forward_limit(2048); fc.update(2048); - frame = fc.generate_frame(level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024); REQUIRE(frame); - CHECK(static_cast(frame.get())->maximum_stream_data() == 2048); + CHECK(static_cast(frame)->maximum_stream_data() == 2048); } } diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 61c5fe4c455..1f502736292 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -75,6 +75,8 @@ TEST_CASE("QUICFrame Type", "[quic]") TEST_CASE("Load STREAM Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + SECTION("OLF=000") { uint8_t buf1[] = { @@ -82,10 +84,10 @@ TEST_CASE("Load STREAM Frame", "[quic]") 0x01, // Stream ID 0x01, 0x02, 0x03, 0x04, // Stream Data }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM); CHECK(frame1->size() == 6); - std::shared_ptr stream_frame = std::dynamic_pointer_cast(frame1); + const QUICStreamFrame *stream_frame = static_cast(frame1); CHECK(stream_frame->stream_id() == 0x01); CHECK(stream_frame->offset() == 0x00); CHECK(stream_frame->data_length() == 4); @@ -101,10 +103,10 @@ TEST_CASE("Load STREAM Frame", "[quic]") 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM); CHECK(frame1->size() == 8); - std::shared_ptr stream_frame = std::dynamic_pointer_cast(frame1); + const QUICStreamFrame *stream_frame = static_cast(frame1); CHECK(stream_frame->stream_id() == 0x01); CHECK(stream_frame->offset() == 0x00); CHECK(stream_frame->data_length() == 5); @@ -121,11 +123,11 @@ TEST_CASE("Load STREAM Frame", "[quic]") 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM); CHECK(frame1->size() == 9); - std::shared_ptr stream_frame = std::dynamic_pointer_cast(frame1); + const QUICStreamFrame *stream_frame = static_cast(frame1); CHECK(stream_frame->stream_id() == 0x01); CHECK(stream_frame->offset() == 0x02); CHECK(stream_frame->data_length() == 5); @@ -142,11 +144,11 @@ TEST_CASE("Load STREAM Frame", "[quic]") 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, 0x05, // Stream Data }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM); CHECK(frame1->size() == 9); - std::shared_ptr stream_frame = std::dynamic_pointer_cast(frame1); + const QUICStreamFrame *stream_frame = static_cast(frame1); CHECK(stream_frame->stream_id() == 0x01); CHECK(stream_frame->offset() == 0x02); CHECK(stream_frame->data_length() == 5); @@ -163,7 +165,7 @@ TEST_CASE("Load STREAM Frame", "[quic]") 0x05, // Data Length 0x01, 0x02, 0x03, 0x04, // BAD Stream Data }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM); CHECK(frame1->valid() == false); } @@ -174,7 +176,7 @@ TEST_CASE("Load STREAM Frame", "[quic]") 0x0e, // 0b00001OLF (OLF=110) 0x01, // Stream ID }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM); CHECK(frame1->valid() == false); } @@ -385,6 +387,7 @@ TEST_CASE("Store STREAM Frame", "[quic]") TEST_CASE("CRYPTO Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("Loading") { uint8_t buf[] = { @@ -393,11 +396,11 @@ TEST_CASE("CRYPTO Frame", "[quic]") 0x05, // Length 0x01, 0x02, 0x03, 0x04, 0x05, // Crypto Data }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::CRYPTO); CHECK(frame->size() == sizeof(buf)); - std::shared_ptr crypto_frame = std::dynamic_pointer_cast(frame); + const QUICCryptoFrame *crypto_frame = static_cast(frame); CHECK(crypto_frame->offset() == 0x010000); CHECK(crypto_frame->data_length() == 5); CHECK(memcmp(crypto_frame->data()->start(), "\x01\x02\x03\x04\x05", 5) == 0); @@ -409,7 +412,7 @@ TEST_CASE("CRYPTO Frame", "[quic]") 0x06, // Type 0x80, 0x01, 0x00, 0x00, // Offset }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::CRYPTO); CHECK(frame->valid() == false); } @@ -441,6 +444,7 @@ TEST_CASE("CRYPTO Frame", "[quic]") TEST_CASE("Load Ack Frame 1", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("0 Ack Block, 8 bit packet number length, 8 bit block length") { uint8_t buf1[] = { @@ -450,10 +454,10 @@ TEST_CASE("Load Ack Frame 1", "[quic]") 0x00, // Ack Block Count 0x00, // Ack Block Section }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); CHECK(frame1->size() == 6); - std::shared_ptr ack_frame1 = std::dynamic_pointer_cast(frame1); + const QUICAckFrame *ack_frame1 = static_cast(frame1); CHECK(ack_frame1 != nullptr); CHECK(ack_frame1->ack_block_count() == 0); CHECK(ack_frame1->largest_acknowledged() == 0x12); @@ -469,11 +473,11 @@ TEST_CASE("Load Ack Frame 1", "[quic]") 0x00, // Ack Block Count 0x80, 0x00, 0x00, 0x01, // Ack Block Section (First ACK Block Length) }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); CHECK(frame1->size() == 12); - std::shared_ptr ack_frame1 = std::dynamic_pointer_cast(frame1); + const QUICAckFrame *ack_frame1 = static_cast(frame1); CHECK(ack_frame1 != nullptr); CHECK(ack_frame1->largest_acknowledged() == 0x01); CHECK(ack_frame1->ack_delay() == 0x0171); @@ -498,10 +502,10 @@ TEST_CASE("Load Ack Frame 1", "[quic]") 0xc9, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, // Ack Block Section (ACK Block 2 Length) }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); CHECK(frame1->size() == 21); - std::shared_ptr ack_frame1 = std::dynamic_pointer_cast(frame1); + const QUICAckFrame *ack_frame1 = static_cast(frame1); CHECK(ack_frame1 != nullptr); CHECK(ack_frame1->largest_acknowledged() == 0x12); CHECK(ack_frame1->ack_delay() == 0x3456); @@ -529,7 +533,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") 0x12, // Largest Acknowledged }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); CHECK(frame1->valid() == false); } @@ -547,7 +551,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") 0x85, 0x06, 0x07, 0x08, // Ack Block Section (Gap 2) }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); CHECK(frame1->valid() == false); } @@ -565,10 +569,10 @@ TEST_CASE("Load Ack Frame 1", "[quic]") 0x02, // ECT1 0x03, // ECN-CE }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); CHECK(frame1->size() == 9); - std::shared_ptr ack_frame1 = std::dynamic_pointer_cast(frame1); + const QUICAckFrame *ack_frame1 = static_cast(frame1); CHECK(ack_frame1 != nullptr); CHECK(ack_frame1->ack_block_count() == 0); CHECK(ack_frame1->largest_acknowledged() == 0x12); @@ -591,7 +595,7 @@ TEST_CASE("Load Ack Frame 1", "[quic]") 0x01, // ECT0 0x02, // ECT1 }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::ACK); CHECK(frame1->valid() == false); } @@ -646,37 +650,11 @@ TEST_CASE("Store Ack Frame", "[quic]") CHECK(len == 21); CHECK(memcmp(buf, expected, len) == 0); } - - SECTION("Clone ACK frame", "[quic]") - { - uint8_t buf[32] = {0}; - size_t len; - - uint8_t expected[] = { - 0x02, // Type - 0x12, // Largest Acknowledged - 0x74, 0x56, // Ack Delay - 0x02, // Ack Block Count - 0x01, // Ack Block Section (First ACK Block Length) - 0x02, // Ack Block Section (Gap 1) - 0x43, 0x04, // Ack Block Section (ACK Block 1 Length) - 0x85, 0x06, 0x07, 0x08, // Ack Block Section (Gap 2) - 0xc9, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, // Ack Block Section (ACK Block 2 Length) - }; - QUICAckFrame ack_frame(0x12, 0x3456, 0x01); - QUICAckFrame::AckBlockSection *section = ack_frame.ack_block_section(); - section->add_ack_block({0x02, 0x0304}); - section->add_ack_block({0x05060708, 0x090a0b0c0d0e0f10}); - - auto cloned = ack_frame.clone(); - cloned->store(buf, &len, sizeof(buf)); - CHECK(len == 21); - CHECK(memcmp(buf, expected, len) == 0); - } } TEST_CASE("Load RESET_STREAM Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("Load") { uint8_t buf1[] = { @@ -685,10 +663,10 @@ TEST_CASE("Load RESET_STREAM Frame", "[quic]") 0x00, 0x01, // Error Code 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Final Offset }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::RESET_STREAM); CHECK(frame1->size() == 15); - std::shared_ptr rst_stream_frame1 = std::dynamic_pointer_cast(frame1); + const QUICRstStreamFrame *rst_stream_frame1 = static_cast(frame1); CHECK(rst_stream_frame1 != nullptr); CHECK(rst_stream_frame1->error_code() == 0x0001); CHECK(rst_stream_frame1->stream_id() == 0x12345678); @@ -702,7 +680,7 @@ TEST_CASE("Load RESET_STREAM Frame", "[quic]") 0x92, 0x34, 0x56, 0x78, // Stream ID 0x00, 0x01, // Error Code }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::RESET_STREAM); CHECK(frame1->valid() == false); } @@ -729,14 +707,15 @@ TEST_CASE("Store RESET_STREAM Frame", "[quic]") TEST_CASE("Load Ping Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; uint8_t buf[] = { 0x01, // Type }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::PING); CHECK(frame->size() == 1); - std::shared_ptr ping_frame = std::dynamic_pointer_cast(frame); + const QUICPingFrame *ping_frame = static_cast(frame); CHECK(ping_frame != nullptr); } @@ -759,13 +738,14 @@ TEST_CASE("Store Ping Frame", "[quic]") TEST_CASE("Load Padding Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; uint8_t buf1[] = { 0x00, // Type }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::PADDING); CHECK(frame1->size() == 1); - std::shared_ptr paddingFrame1 = std::dynamic_pointer_cast(frame1); + const QUICPaddingFrame *paddingFrame1 = static_cast(frame1); CHECK(paddingFrame1 != nullptr); } @@ -785,6 +765,7 @@ TEST_CASE("Store Padding Frame", "[quic]") TEST_CASE("ConnectionClose Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; uint8_t reason_phrase[] = {0x41, 0x42, 0x43, 0x44, 0x45}; size_t reason_phrase_len = sizeof(reason_phrase); @@ -798,12 +779,11 @@ TEST_CASE("ConnectionClose Frame", "[quic]") 0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE"); }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::CONNECTION_CLOSE); CHECK(frame->size() == sizeof(buf)); - std::shared_ptr conn_close_frame = - std::dynamic_pointer_cast(frame); + const QUICConnectionCloseFrame *conn_close_frame = static_cast(frame); CHECK(conn_close_frame != nullptr); CHECK(conn_close_frame->error_code() == static_cast(QUICTransErrorCode::PROTOCOL_VIOLATION)); CHECK(conn_close_frame->frame_type() == QUICFrameType::UNKNOWN); @@ -820,7 +800,7 @@ TEST_CASE("ConnectionClose Frame", "[quic]") 0x05, // Reason Phrase Length }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::CONNECTION_CLOSE); CHECK(frame->valid() == false); } @@ -833,12 +813,11 @@ TEST_CASE("ConnectionClose Frame", "[quic]") 0x04, // Frame Type 0x00, // Reason Phrase Length }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::CONNECTION_CLOSE); CHECK(frame->size() == sizeof(buf)); - std::shared_ptr conn_close_frame = - std::dynamic_pointer_cast(frame); + const QUICConnectionCloseFrame *conn_close_frame = static_cast(frame); CHECK(conn_close_frame != nullptr); CHECK(conn_close_frame->error_code() == static_cast(QUICTransErrorCode::PROTOCOL_VIOLATION)); CHECK(conn_close_frame->frame_type() == QUICFrameType::RESET_STREAM); @@ -887,16 +866,17 @@ TEST_CASE("ConnectionClose Frame", "[quic]") TEST_CASE("Load MaxData Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("Load") { uint8_t buf1[] = { 0x10, // Type 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Data }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_DATA); CHECK(frame1->size() == 9); - std::shared_ptr max_data_frame = std::dynamic_pointer_cast(frame1); + const QUICMaxDataFrame *max_data_frame = static_cast(frame1); CHECK(max_data_frame != nullptr); CHECK(max_data_frame->maximum_data() == 0x1122334455667788ULL); } @@ -906,7 +886,7 @@ TEST_CASE("Load MaxData Frame", "[quic]") uint8_t buf1[] = { 0x10, // Type }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_DATA); CHECK(frame1->valid() == false); } @@ -931,6 +911,7 @@ TEST_CASE("Store MaxData Frame", "[quic]") TEST_CASE("Load MaxStreamData Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("Load") { uint8_t buf1[] = { @@ -938,11 +919,10 @@ TEST_CASE("Load MaxStreamData Frame", "[quic]") 0x81, 0x02, 0x03, 0x04, // Stream ID 0xd1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 // Maximum Stream Data }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_STREAM_DATA); CHECK(frame1->size() == 13); - std::shared_ptr maxStreamDataFrame1 = - std::dynamic_pointer_cast(frame1); + const QUICMaxStreamDataFrame *maxStreamDataFrame1 = static_cast(frame1); CHECK(maxStreamDataFrame1 != nullptr); CHECK(maxStreamDataFrame1->stream_id() == 0x01020304); CHECK(maxStreamDataFrame1->maximum_stream_data() == 0x1122334455667788ULL); @@ -954,7 +934,7 @@ TEST_CASE("Load MaxStreamData Frame", "[quic]") 0x11, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_STREAM_DATA); CHECK(frame1->valid() == false); } @@ -980,16 +960,17 @@ TEST_CASE("Store MaxStreamData Frame", "[quic]") TEST_CASE("Load MaxStreams Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("load") { uint8_t buf1[] = { 0x12, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_STREAMS); CHECK(frame1->size() == 5); - std::shared_ptr max_streams_frame = std::dynamic_pointer_cast(frame1); + const QUICMaxStreamsFrame *max_streams_frame = static_cast(frame1); CHECK(max_streams_frame != nullptr); CHECK(max_streams_frame->maximum_streams() == 0x01020304); } @@ -998,7 +979,7 @@ TEST_CASE("Load MaxStreams Frame", "[quic]") uint8_t buf1[] = { 0x12, // Type }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::MAX_STREAMS); CHECK(frame1->valid() == false); } @@ -1023,17 +1004,17 @@ TEST_CASE("Store MaxStreams Frame", "[quic]") TEST_CASE("Load DataBlocked Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("load") { uint8_t buf1[] = { 0x14, // Type 0x07, // Offset }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::DATA_BLOCKED); CHECK(frame1->size() == 2); - std::shared_ptr blocked_stream_frame = - std::dynamic_pointer_cast(frame1); + const QUICDataBlockedFrame *blocked_stream_frame = static_cast(frame1); CHECK(blocked_stream_frame != nullptr); CHECK(blocked_stream_frame->offset() == 0x07); } @@ -1043,7 +1024,7 @@ TEST_CASE("Load DataBlocked Frame", "[quic]") uint8_t buf1[] = { 0x14, // Type }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::DATA_BLOCKED); CHECK(frame1->valid() == false); } @@ -1068,6 +1049,7 @@ TEST_CASE("Store DataBlocked Frame", "[quic]") TEST_CASE("Load StreamDataBlocked Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("Load") { uint8_t buf1[] = { @@ -1075,11 +1057,10 @@ TEST_CASE("Load StreamDataBlocked Frame", "[quic]") 0x81, 0x02, 0x03, 0x04, // Stream ID 0x07, // Offset }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM_DATA_BLOCKED); CHECK(frame1->size() == 6); - std::shared_ptr stream_blocked_frame = - std::dynamic_pointer_cast(frame1); + const QUICStreamDataBlockedFrame *stream_blocked_frame = static_cast(frame1); CHECK(stream_blocked_frame != nullptr); CHECK(stream_blocked_frame->stream_id() == 0x01020304); CHECK(stream_blocked_frame->offset() == 0x07); @@ -1091,7 +1072,7 @@ TEST_CASE("Load StreamDataBlocked Frame", "[quic]") 0x15, // Type 0x81, 0x02, 0x03, 0x04, // Stream ID }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAM_DATA_BLOCKED); CHECK(frame1->valid() == false); } @@ -1117,17 +1098,17 @@ TEST_CASE("Store StreamDataBlocked Frame", "[quic]") TEST_CASE("Load StreamsBlocked Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("Load") { uint8_t buf1[] = { 0x16, // Type 0x41, 0x02, // Stream ID }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAMS_BLOCKED); CHECK(frame1->size() == 3); - std::shared_ptr stream_id_blocked_frame = - std::dynamic_pointer_cast(frame1); + const QUICStreamIdBlockedFrame *stream_id_blocked_frame = static_cast(frame1); CHECK(stream_id_blocked_frame != nullptr); CHECK(stream_id_blocked_frame->stream_id() == 0x0102); } @@ -1137,7 +1118,7 @@ TEST_CASE("Load StreamsBlocked Frame", "[quic]") uint8_t buf1[] = { 0x16, // Type }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::STREAMS_BLOCKED); CHECK(frame1->valid() == false); } @@ -1162,6 +1143,7 @@ TEST_CASE("Store StreamsBlocked Frame", "[quic]") TEST_CASE("Load NewConnectionId Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("load") { uint8_t buf1[] = { @@ -1172,11 +1154,10 @@ TEST_CASE("Load NewConnectionId Frame", "[quic]") 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::NEW_CONNECTION_ID); CHECK(frame1->size() == 28); - std::shared_ptr new_con_id_frame = - std::dynamic_pointer_cast(frame1); + const QUICNewConnectionIdFrame *new_con_id_frame = static_cast(frame1); CHECK(new_con_id_frame != nullptr); CHECK(new_con_id_frame->sequence() == 0x0102); CHECK((new_con_id_frame->connection_id() == @@ -1193,7 +1174,7 @@ TEST_CASE("Load NewConnectionId Frame", "[quic]") 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // Connection ID 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, // Stateless Reset Token }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1->type() == QUICFrameType::NEW_CONNECTION_ID); CHECK(frame1->valid() == false); } @@ -1223,6 +1204,7 @@ TEST_CASE("Store NewConnectionId Frame", "[quic]") TEST_CASE("Load STOP_SENDING Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("LOAD") { uint8_t buf[] = { @@ -1230,11 +1212,11 @@ TEST_CASE("Load STOP_SENDING Frame", "[quic]") 0x92, 0x34, 0x56, 0x78, // Stream ID 0x00, 0x01, // Error Code }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::STOP_SENDING); CHECK(frame->size() == 7); - std::shared_ptr stop_sending_frame = std::dynamic_pointer_cast(frame); + const QUICStopSendingFrame *stop_sending_frame = static_cast(frame); CHECK(stop_sending_frame != nullptr); CHECK(stop_sending_frame->stream_id() == 0x12345678); CHECK(stop_sending_frame->error_code() == 0x0001); @@ -1246,7 +1228,7 @@ TEST_CASE("Load STOP_SENDING Frame", "[quic]") 0x05, // Type 0x92, 0x34, 0x56, 0x78, // Stream ID }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::STOP_SENDING); CHECK(frame->valid() == false); } @@ -1272,18 +1254,18 @@ TEST_CASE("Store STOP_SENDING Frame", "[quic]") TEST_CASE("Load PATH_CHALLENGE Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("Load") { uint8_t buf[] = { 0x1a, // Type 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::PATH_CHALLENGE); CHECK(frame->size() == 9); - std::shared_ptr path_challenge_frame = - std::dynamic_pointer_cast(frame); + const QUICPathChallengeFrame *path_challenge_frame = static_cast(frame); CHECK(path_challenge_frame != nullptr); CHECK(memcmp(path_challenge_frame->data(), "\x01\x23\x45\x67\x89\xab\xcd\xef", QUICPathChallengeFrame::DATA_LEN) == 0); } @@ -1294,7 +1276,7 @@ TEST_CASE("Load PATH_CHALLENGE Frame", "[quic]") 0x1a, // Type 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xef, // Data }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::PATH_CHALLENGE); CHECK(frame->valid() == false); } @@ -1325,18 +1307,18 @@ TEST_CASE("Store PATH_CHALLENGE Frame", "[quic]") TEST_CASE("Load PATH_RESPONSE Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; SECTION("Load") { uint8_t buf[] = { 0x1b, // Type 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::PATH_RESPONSE); CHECK(frame->size() == 9); - std::shared_ptr path_response_frame = - std::dynamic_pointer_cast(frame); + const QUICPathResponseFrame *path_response_frame = static_cast(frame); CHECK(path_response_frame != nullptr); CHECK(memcmp(path_response_frame->data(), "\x01\x23\x45\x67\x89\xab\xcd\xef", QUICPathResponseFrame::DATA_LEN) == 0); } @@ -1347,7 +1329,7 @@ TEST_CASE("Load PATH_RESPONSE Frame", "[quic]") 0x1b, // Type 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, // Data }; - std::shared_ptr frame = QUICFrameFactory::create(buf, sizeof(buf)); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, buf, sizeof(buf)); CHECK(frame->type() == QUICFrameType::PATH_RESPONSE); CHECK(frame->valid() == false); } @@ -1378,6 +1360,7 @@ TEST_CASE("Store PATH_RESPONSE Frame", "[quic]") TEST_CASE("NEW_TOKEN Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; uint8_t raw_new_token_frame[] = { 0x07, // Type 0x08, // Token Length (i) @@ -1390,11 +1373,11 @@ TEST_CASE("NEW_TOKEN Frame", "[quic]") SECTION("load") { - std::shared_ptr frame = QUICFrameFactory::create(raw_new_token_frame, raw_new_token_frame_len); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, raw_new_token_frame, raw_new_token_frame_len); CHECK(frame->type() == QUICFrameType::NEW_TOKEN); CHECK(frame->size() == raw_new_token_frame_len); - std::shared_ptr new_token_frame = std::dynamic_pointer_cast(frame); + const QUICNewTokenFrame *new_token_frame = static_cast(frame); CHECK(new_token_frame != nullptr); CHECK(new_token_frame->token_length() == raw_token_len); CHECK(memcmp(new_token_frame->token(), raw_token, raw_token_len) == 0); @@ -1402,7 +1385,7 @@ TEST_CASE("NEW_TOKEN Frame", "[quic]") SECTION("bad load") { - std::shared_ptr frame = QUICFrameFactory::create(raw_new_token_frame, raw_new_token_frame_len - 5); + const QUICFrame *frame = QUICFrameFactory::create(frame_buf, raw_new_token_frame, raw_new_token_frame_len - 5); CHECK(frame->type() == QUICFrameType::NEW_TOKEN); CHECK(frame->valid() == false); } @@ -1426,6 +1409,7 @@ TEST_CASE("NEW_TOKEN Frame", "[quic]") TEST_CASE("RETIRE_CONNECTION_ID Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; uint8_t raw_retire_connection_id_frame[] = { 0x19, // Type 0x08, // Sequence Number (i) @@ -1435,21 +1419,20 @@ TEST_CASE("RETIRE_CONNECTION_ID Frame", "[quic]") SECTION("load") { - std::shared_ptr frame = - QUICFrameFactory::create(raw_retire_connection_id_frame, raw_retire_connection_id_frame_len); + const QUICFrame *frame = + QUICFrameFactory::create(frame_buf, raw_retire_connection_id_frame, raw_retire_connection_id_frame_len); CHECK(frame->type() == QUICFrameType::RETIRE_CONNECTION_ID); CHECK(frame->size() == raw_retire_connection_id_frame_len); - std::shared_ptr retire_connection_id_frame = - std::dynamic_pointer_cast(frame); + const QUICRetireConnectionIdFrame *retire_connection_id_frame = static_cast(frame); CHECK(retire_connection_id_frame != nullptr); CHECK(retire_connection_id_frame->seq_num() == seq_num); } SECTION("bad load") { - std::shared_ptr frame = - QUICFrameFactory::create(raw_retire_connection_id_frame, raw_retire_connection_id_frame_len - 1); + const QUICFrame *frame = + QUICFrameFactory::create(frame_buf, raw_retire_connection_id_frame, raw_retire_connection_id_frame_len - 1); CHECK(frame->type() == QUICFrameType::RETIRE_CONNECTION_ID); CHECK(frame->valid() == false); } @@ -1470,10 +1453,11 @@ TEST_CASE("RETIRE_CONNECTION_ID Frame", "[quic]") TEST_CASE("QUICFrameFactory Create Unknown Frame", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; uint8_t buf1[] = { 0x20, // Type }; - std::shared_ptr frame1 = QUICFrameFactory::create(buf1, sizeof(buf1)); + const QUICFrame *frame1 = QUICFrameFactory::create(frame_buf, buf1, sizeof(buf1)); CHECK(frame1 == nullptr); } @@ -1489,21 +1473,19 @@ TEST_CASE("QUICFrameFactory Fast Create Frame", "[quic]") 0x12, // Type 0x85, 0x06, 0x07, 0x08, // Stream Data }; - std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); - CHECK(frame1 != nullptr); + const QUICFrame &frame1 = factory.fast_create(buf1, sizeof(buf1)); + CHECK(frame1.type() == QUICFrameType::MAX_STREAMS); - std::shared_ptr max_streams_frame1 = std::dynamic_pointer_cast(frame1); - CHECK(max_streams_frame1 != nullptr); - CHECK(max_streams_frame1->maximum_streams() == 0x01020304); + const QUICMaxStreamsFrame &max_streams_frame1 = static_cast(frame1); + CHECK(max_streams_frame1.maximum_streams() == 0x01020304); - std::shared_ptr frame2 = factory.fast_create(buf2, sizeof(buf2)); - CHECK(frame2 != nullptr); + const QUICFrame &frame2 = factory.fast_create(buf2, sizeof(buf2)); + CHECK(frame2.type() == QUICFrameType::MAX_STREAMS); - std::shared_ptr max_streams_frame2 = std::dynamic_pointer_cast(frame2); - CHECK(max_streams_frame2 != nullptr); - CHECK(max_streams_frame2->maximum_streams() == 0x05060708); + const QUICMaxStreamsFrame &max_streams_frame2 = static_cast(frame2); + CHECK(max_streams_frame2.maximum_streams() == 0x05060708); - CHECK(frame1 == frame2); + CHECK(&frame1 == &frame2); } TEST_CASE("QUICFrameFactory Fast Create Unknown Frame", "[quic]") @@ -1513,23 +1495,23 @@ TEST_CASE("QUICFrameFactory Fast Create Unknown Frame", "[quic]") uint8_t buf1[] = { 0x20, // Type }; - std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); - CHECK(frame1 == nullptr); + const QUICFrame &frame1 = factory.fast_create(buf1, sizeof(buf1)); + CHECK(frame1.type() == QUICFrameType::UNKNOWN); } TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + std::unique_ptr error = std::unique_ptr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR)); - std::unique_ptr connection_close_frame1 = - QUICFrameFactory::create_connection_close_frame(*error); + const QUICConnectionCloseFrame *connection_close_frame1 = QUICFrameFactory::create_connection_close_frame(frame_buf, *error); CHECK(connection_close_frame1->error_code() == static_cast(QUICTransErrorCode::INTERNAL_ERROR)); CHECK(connection_close_frame1->reason_phrase_length() == 0); CHECK(connection_close_frame1->reason_phrase() == nullptr); error = std::unique_ptr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR, "test")); - std::unique_ptr connection_close_frame2 = - QUICFrameFactory::create_connection_close_frame(*error); + const QUICConnectionCloseFrame *connection_close_frame2 = QUICFrameFactory::create_connection_close_frame(frame_buf, *error); CHECK(connection_close_frame2->error_code() == static_cast(QUICTransErrorCode::INTERNAL_ERROR)); CHECK(connection_close_frame2->reason_phrase_length() == 4); CHECK(memcmp(connection_close_frame2->reason_phrase(), "test", 4) == 0); @@ -1537,12 +1519,13 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", TEST_CASE("QUICFrameFactory Create RESET_STREAM with a QUICStreamError", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; MockQUICRTTProvider mock_rtt; MockQUICConnection mock_connection; QUICStream stream(&mock_rtt, &mock_connection, 0x1234, 0, 0); std::unique_ptr error = std::unique_ptr(new QUICStreamError(&stream, static_cast(0x01))); - std::unique_ptr rst_stream_frame1 = QUICFrameFactory::create_rst_stream_frame(*error); + const QUICRstStreamFrame *rst_stream_frame1 = QUICFrameFactory::create_rst_stream_frame(frame_buf, *error); CHECK(rst_stream_frame1->error_code() == 0x01); CHECK(rst_stream_frame1->stream_id() == 0x1234); CHECK(rst_stream_frame1->final_offset() == 0); diff --git a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc index 9dad813e3ca..39d50b7a18c 100644 --- a/iocore/net/quic/test/test_QUICFrameRetransmitter.cc +++ b/iocore/net/quic/test/test_QUICFrameRetransmitter.cc @@ -36,7 +36,8 @@ TEST_CASE("QUICFrameRetransmitter ignore frame which can not be retranmistted", info->level = QUICEncryptionLevel::NONE; retransmitter.save_frame_info(std::move(info)); - CHECK(retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX) == nullptr); + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + CHECK(retransmitter.create_retransmitted_frame(frame_buf, QUICEncryptionLevel::INITIAL, UINT16_MAX) == nullptr); } // TEST_CASE("QUICFrameRetransmitter ignore frame which can not be split", "[quic]") @@ -58,7 +59,8 @@ TEST_CASE("QUICFrameRetransmitter ignore frame which has wrong level", "[quic]") info->level = QUICEncryptionLevel::HANDSHAKE; retransmitter.save_frame_info(std::move(info)); - CHECK(retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX) == nullptr); + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + CHECK(retransmitter.create_retransmitted_frame(frame_buf, QUICEncryptionLevel::INITIAL, UINT16_MAX) == nullptr); } TEST_CASE("QUICFrameRetransmitter successfully create retransmitted frame", "[quic]") @@ -80,7 +82,8 @@ TEST_CASE("QUICFrameRetransmitter successfully create retransmitted frame", "[qu retransmitter.save_frame_info(std::move(info)); - auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + auto frame = retransmitter.create_retransmitted_frame(frame_buf, QUICEncryptionLevel::INITIAL, UINT16_MAX); CHECK(frame != nullptr); CHECK(frame->type() == QUICFrameType::STREAM); } @@ -106,15 +109,17 @@ TEST_CASE("QUICFrameRetransmitter successfully create stream frame", "[quic]") retransmitter.save_frame_info(std::move(info)); CHECK(block->refcount() == 2); // block's refcount doesn't change - auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + auto frame = retransmitter.create_retransmitted_frame(frame_buf, QUICEncryptionLevel::INITIAL, UINT16_MAX); CHECK(frame != nullptr); CHECK(frame->type() == QUICFrameType::STREAM); - auto stream_frame = static_cast(frame.get()); + auto stream_frame = static_cast(frame); CHECK(stream_frame->stream_id() == 0x12345); CHECK(stream_frame->offset() == 0x67890); CHECK(stream_frame->data_length() == sizeof(data)); CHECK(memcmp(stream_frame->data()->start(), data, sizeof(data)) == 0); - frame = QUICFrameFactory::create_null_frame(); + std::destroy_at(frame); + frame = nullptr; // Becasue the info has been released, the refcount should be 1 (var block). CHECK(block->refcount() == 1); } @@ -139,10 +144,11 @@ TEST_CASE("QUICFrameRetransmitter successfully split stream frame", "[quic]") retransmitter.save_frame_info(std::move(info)); - auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 25); + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + auto frame = retransmitter.create_retransmitted_frame(frame_buf, QUICEncryptionLevel::INITIAL, 25); CHECK(frame != nullptr); CHECK(frame->type() == QUICFrameType::STREAM); - auto stream_frame = static_cast(frame.get()); + auto stream_frame = static_cast(frame); CHECK(stream_frame->stream_id() == 0x12345); CHECK(stream_frame->offset() == 0x67890); CHECK(stream_frame->size() <= 25); @@ -153,22 +159,24 @@ TEST_CASE("QUICFrameRetransmitter successfully split stream frame", "[quic]") CHECK(block->data->refcount() == 2); // one for var block, one for the left data which saved in retransmitter, one for var frame CHECK(block->refcount() == 2); - frame = QUICFrameFactory::create_null_frame(); + std::destroy_at(frame); + frame = nullptr; // one for var block, one for var info CHECK(block->refcount() == 2); CHECK(block->data->refcount() == 1); - frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); + frame = retransmitter.create_retransmitted_frame(frame_buf, QUICEncryptionLevel::INITIAL, UINT16_MAX); CHECK(frame != nullptr); CHECK(frame->type() == QUICFrameType::STREAM); - stream_frame = static_cast(frame.get()); + stream_frame = static_cast(frame); CHECK(stream_frame->stream_id() == 0x12345); CHECK(stream_frame->offset() == 0x67890 + size); CHECK(stream_frame->data_length() == sizeof(data) - size); CHECK(memcmp(stream_frame->data()->start(), data + size, stream_frame->data_length()) == 0); CHECK(block->refcount() == 1); // one for var block - frame = QUICFrameFactory::create_null_frame(); + std::destroy_at(frame); + frame = nullptr; CHECK(block->refcount() == 1); CHECK(block->data->refcount() == 1); } @@ -192,10 +200,11 @@ TEST_CASE("QUICFrameRetransmitter successfully split crypto frame", "[quic]") retransmitter.save_frame_info(std::move(info)); - auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 25); + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + auto frame = retransmitter.create_retransmitted_frame(frame_buf, QUICEncryptionLevel::INITIAL, 25); CHECK(frame != nullptr); CHECK(frame->type() == QUICFrameType::CRYPTO); - auto crypto_frame = static_cast(frame.get()); + auto crypto_frame = static_cast(frame); CHECK(crypto_frame->offset() == 0x67890); CHECK(crypto_frame->size() <= 25); @@ -205,21 +214,23 @@ TEST_CASE("QUICFrameRetransmitter successfully split crypto frame", "[quic]") CHECK(block->data->refcount() == 2); // one for var block, one for the left data which saved in retransmitter, one for var frame CHECK(block->refcount() == 2); - frame = QUICFrameFactory::create_null_frame(); + std::destroy_at(frame); + frame = nullptr; // one for var block, one for var info CHECK(block->refcount() == 2); CHECK(block->data->refcount() == 1); - frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); + frame = retransmitter.create_retransmitted_frame(frame_buf, QUICEncryptionLevel::INITIAL, UINT16_MAX); CHECK(frame != nullptr); CHECK(frame->type() == QUICFrameType::CRYPTO); - crypto_frame = static_cast(frame.get()); + crypto_frame = static_cast(frame); CHECK(crypto_frame->offset() == 0x67890 + size); CHECK(crypto_frame->data_length() == sizeof(data) - size); CHECK(memcmp(crypto_frame->data()->start(), data + size, crypto_frame->data_length()) == 0); CHECK(block->refcount() == 1); // one for var block - frame = QUICFrameFactory::create_null_frame(); + std::destroy_at(frame); + frame = nullptr; CHECK(block->refcount() == 1); CHECK(block->data->refcount() == 1); } @@ -245,10 +256,11 @@ TEST_CASE("QUICFrameRetransmitter successfully split stream frame with fin flag" retransmitter.save_frame_info(std::move(info)); - auto frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, 25); + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + auto frame = retransmitter.create_retransmitted_frame(frame_buf, QUICEncryptionLevel::INITIAL, 25); CHECK(frame != nullptr); CHECK(frame->type() == QUICFrameType::STREAM); - auto stream_frame = static_cast(frame.get()); + auto stream_frame = static_cast(frame); CHECK(stream_frame->stream_id() == 0x12345); CHECK(stream_frame->offset() == 0x67890); CHECK(stream_frame->size() <= 25); @@ -260,15 +272,16 @@ TEST_CASE("QUICFrameRetransmitter successfully split stream frame with fin flag" CHECK(block->data->refcount() == 2); // one for var block, one for the left data which saved in retransmitter, one for var frame CHECK(block->refcount() == 2); - frame = QUICFrameFactory::create_null_frame(); + std::destroy_at(frame); + frame = nullptr; // one for var block, one for var info CHECK(block->refcount() == 2); CHECK(block->data->refcount() == 1); - frame = retransmitter.create_retransmitted_frame(QUICEncryptionLevel::INITIAL, UINT16_MAX); + frame = retransmitter.create_retransmitted_frame(frame_buf, QUICEncryptionLevel::INITIAL, UINT16_MAX); CHECK(frame != nullptr); CHECK(frame->type() == QUICFrameType::STREAM); - stream_frame = static_cast(frame.get()); + stream_frame = static_cast(frame); CHECK(stream_frame->stream_id() == 0x12345); CHECK(stream_frame->offset() == 0x67890 + size); CHECK(stream_frame->data_length() == sizeof(data) - size); @@ -276,7 +289,8 @@ TEST_CASE("QUICFrameRetransmitter successfully split stream frame with fin flag" CHECK(block->refcount() == 1); // one for var block CHECK(stream_frame->has_fin_flag() == true); - frame = QUICFrameFactory::create_null_frame(); + std::destroy_at(frame); + frame = nullptr; CHECK(block->refcount() == 1); CHECK(block->data->refcount() == 1); } diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 90e3680305a..2338129d523 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -29,6 +29,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; QUICStream *stream = new QUICStream(); QUICIncomingStreamFrameBuffer buffer; QUICErrorUPtr err = nullptr; @@ -44,7 +45,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") SECTION("single frame") { - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 0, true); + QUICStreamFrame *stream1_frame_0_r = QUICFrameFactory::create_stream_frame(frame_buf, block_1024, 1, 0, true); err = buffer.insert(*stream1_frame_0_r); CHECK(err == nullptr); @@ -52,11 +53,16 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") SECTION("multiple frames") { - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 0); - std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 1024); - std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 2048, true); - std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 3072, true); - std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 4096); + uint8_t frame_buf0[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf1[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf2[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf3[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf4[QUICFrame::MAX_INSTANCE_SIZE]; + QUICStreamFrame *stream1_frame_0_r = QUICFrameFactory::create_stream_frame(frame_buf0, block_1024, 1, 0); + QUICStreamFrame *stream1_frame_1_r = QUICFrameFactory::create_stream_frame(frame_buf1, block_1024, 1, 1024); + QUICStreamFrame *stream1_frame_2_r = QUICFrameFactory::create_stream_frame(frame_buf2, block_1024, 1, 2048, true); + QUICStreamFrame *stream1_frame_3_r = QUICFrameFactory::create_stream_frame(frame_buf3, block_1024, 1, 3072, true); + QUICStreamFrame *stream1_frame_4_r = QUICFrameFactory::create_stream_frame(frame_buf4, block_1024, 1, 4096); buffer.insert(*stream1_frame_0_r); buffer.insert(*stream1_frame_1_r); @@ -84,9 +90,12 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") SECTION("Pure FIN") { - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 0); - std::shared_ptr stream1_frame_empty = QUICFrameFactory::create_stream_frame(block_0, 1, 1024); - std::shared_ptr stream1_frame_pure_fin = QUICFrameFactory::create_stream_frame(block_0, 1, 1024, true); + uint8_t frame_buf0[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf1[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf2[QUICFrame::MAX_INSTANCE_SIZE]; + QUICStreamFrame *stream1_frame_0_r = QUICFrameFactory::create_stream_frame(frame_buf0, block_1024, 1, 0); + QUICStreamFrame *stream1_frame_empty = QUICFrameFactory::create_stream_frame(frame_buf1, block_0, 1, 1024); + QUICStreamFrame *stream1_frame_pure_fin = QUICFrameFactory::create_stream_frame(frame_buf2, block_0, 1, 1024, true); err = buffer.insert(*stream1_frame_0_r); CHECK(err == nullptr); @@ -116,12 +125,19 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") block_0->alloc(); CHECK(block_0->read_avail() == 0); - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 0); - std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 1024); - std::shared_ptr stream1_frame_empty = QUICFrameFactory::create_stream_frame(block_0, 1, 2048); - std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 2048); - std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 3072); - std::shared_ptr stream1_frame_4_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 4096, true); + uint8_t frame_buf0[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf1[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf2[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf3[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf4[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf5[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf6[QUICFrame::MAX_INSTANCE_SIZE]; + QUICStreamFrame *stream1_frame_0_r = QUICFrameFactory::create_stream_frame(frame_buf0, block_1024, 1, 0); + QUICStreamFrame *stream1_frame_1_r = QUICFrameFactory::create_stream_frame(frame_buf1, block_1024, 1, 1024); + QUICStreamFrame *stream1_frame_empty = QUICFrameFactory::create_stream_frame(frame_buf2, block_0, 1, 2048); + QUICStreamFrame *stream1_frame_2_r = QUICFrameFactory::create_stream_frame(frame_buf3, block_1024, 1, 2048); + QUICStreamFrame *stream1_frame_3_r = QUICFrameFactory::create_stream_frame(frame_buf4, block_1024, 1, 3072); + QUICStreamFrame *stream1_frame_4_r = QUICFrameFactory::create_stream_frame(frame_buf5, block_1024, 1, 4096, true); buffer.insert(*stream1_frame_0_r); buffer.insert(*stream1_frame_1_r); @@ -131,15 +147,15 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") buffer.insert(*stream1_frame_4_r); CHECK(!buffer.empty()); - auto frame = std::static_pointer_cast(buffer.pop()); + auto frame = static_cast(buffer.pop()); CHECK(frame->offset() == 0); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 1024); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 2048); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 3072); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 4096); CHECK(buffer.empty()); @@ -152,15 +168,15 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") buffer.insert(*stream1_frame_0_r); CHECK(!buffer.empty()); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 0); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 1024); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 2048); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 3072); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 4096); CHECK(buffer.empty()); @@ -182,10 +198,18 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") block_0->alloc(); CHECK(block_0->read_avail() == 0); - std::shared_ptr stream1_frame_0_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 0); - std::shared_ptr stream1_frame_1_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 1024); - std::shared_ptr stream1_frame_2_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 2048, true); - std::shared_ptr stream1_frame_3_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 2048, true); + uint8_t frame_buf0[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf1[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf2[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf3[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf4[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf5[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf6[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t frame_buf7[QUICFrame::MAX_INSTANCE_SIZE]; + QUICStreamFrame *stream1_frame_0_r = QUICFrameFactory::create_stream_frame(frame_buf0, block_1024, 1, 0); + QUICStreamFrame *stream1_frame_1_r = QUICFrameFactory::create_stream_frame(frame_buf1, block_1024, 1, 1024); + QUICStreamFrame *stream1_frame_2_r = QUICFrameFactory::create_stream_frame(frame_buf2, block_1024, 1, 2048, true); + QUICStreamFrame *stream1_frame_3_r = QUICFrameFactory::create_stream_frame(frame_buf3, block_1024, 1, 2048, true); buffer.insert(*stream1_frame_0_r); buffer.insert(*stream1_frame_1_r); @@ -193,22 +217,22 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") err = buffer.insert(*stream1_frame_3_r); CHECK(err == nullptr); - auto frame = std::static_pointer_cast(buffer.pop()); + auto frame = static_cast(buffer.pop()); CHECK(frame->offset() == 0); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 1024); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 2048); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame == nullptr); CHECK(buffer.empty()); buffer.clear(); - std::shared_ptr stream2_frame_0_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 0); - std::shared_ptr stream2_frame_1_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 1024); - std::shared_ptr stream2_frame_2_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 1024); - std::shared_ptr stream2_frame_3_r = QUICFrameFactory::create_stream_frame(block_1024, 1, 2048, true); + QUICStreamFrame *stream2_frame_0_r = QUICFrameFactory::create_stream_frame(frame_buf4, block_1024, 1, 0); + QUICStreamFrame *stream2_frame_1_r = QUICFrameFactory::create_stream_frame(frame_buf5, block_1024, 1, 1024); + QUICStreamFrame *stream2_frame_2_r = QUICFrameFactory::create_stream_frame(frame_buf6, block_1024, 1, 1024); + QUICStreamFrame *stream2_frame_3_r = QUICFrameFactory::create_stream_frame(frame_buf7, block_1024, 1, 2048, true); buffer.insert(*stream2_frame_0_r); buffer.insert(*stream2_frame_1_r); @@ -216,13 +240,13 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") err = buffer.insert(*stream2_frame_3_r); CHECK(err == nullptr); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 0); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 1024); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame->offset() == 2048); - frame = std::static_pointer_cast(buffer.pop()); + frame = static_cast(buffer.pop()); CHECK(frame == nullptr); CHECK(buffer.empty()); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 3722553a22e..9cb040bc692 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -41,10 +41,10 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") MockQUICConnectionInfoProvider info; MockQUICCongestionController cc(&info); QUICLossDetector detector(&tx, &info, &cc, &rtt_measure, 0); - ats_unique_buf payload = ats_unique_malloc(512); - size_t payload_len = 512; - QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); - std::shared_ptr frame = QUICFrameFactory::create_null_ack_frame(); + ats_unique_buf payload = ats_unique_malloc(512); + size_t payload_len = 512; + QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); + QUICAckFrame *frame = nullptr; std::vector dummy_frames; SECTION("Handshake") @@ -142,9 +142,10 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") afm.update(QUICEncryptionLevel::INITIAL, pn8, payload_len, false); afm.update(QUICEncryptionLevel::INITIAL, pn9, payload_len, false); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); - std::shared_ptr x = afm.generate_frame(QUICEncryptionLevel::INITIAL, 2048, 2048); - frame = std::dynamic_pointer_cast(x); - detector.handle_frame(QUICEncryptionLevel::INITIAL, *frame.get()); + uint8_t buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *x = afm.generate_frame(buf, QUICEncryptionLevel::INITIAL, 2048, 2048); + frame = static_cast(x); + detector.handle_frame(QUICEncryptionLevel::INITIAL, *frame); ink_hrtime_sleep(HRTIME_MSECONDS(5000)); CHECK(cc.lost_packets.size() == 3); @@ -163,6 +164,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") TEST_CASE("QUICLossDetector_HugeGap", "[quic]") { + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; MockQUICPacketTransmitter tx; MockQUICConnectionInfoProvider info; MockQUICCongestionController cc(&info); @@ -172,10 +174,10 @@ TEST_CASE("QUICLossDetector_HugeGap", "[quic]") // Check initial state CHECK(tx.retransmitted.size() == 0); - auto t1 = Thread::get_hrtime(); - std::shared_ptr ack = QUICFrameFactory::create_ack_frame(100000000, 100, 10000000); + auto t1 = Thread::get_hrtime(); + QUICAckFrame *ack = QUICFrameFactory::create_ack_frame(frame_buf, 100000000, 100, 10000000); ack->ack_block_section()->add_ack_block({20000000, 30000000}); - detector.handle_frame(QUICEncryptionLevel::INITIAL, *ack.get()); + detector.handle_frame(QUICEncryptionLevel::INITIAL, *ack); auto t2 = Thread::get_hrtime(); CHECK(t2 - t1 < HRTIME_MSECONDS(100)); } diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index c36e460cddc..fcca4c678f4 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -36,6 +36,8 @@ TEST_CASE("QUICStream", "[quic]") memcpy(block->start(), payload, sizeof(payload)); block->fill(sizeof(payload)); + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + Ptr new_block = make_ptr(block->clone()); new_block->_end = new_block->_start + 2; std::shared_ptr frame_1 = std::make_shared(new_block, stream_id, 0); @@ -217,33 +219,33 @@ TEST_CASE("QUICStream", "[quic]") QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; const char data[1024] = {0}; - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrame *frame = nullptr; write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); CHECK(stream->will_generate_frame(level) == false); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); CHECK(stream->will_generate_frame(level) == false); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); CHECK(stream->will_generate_frame(level) == false); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); CHECK(stream->will_generate_frame(level) == false); @@ -251,7 +253,7 @@ TEST_CASE("QUICStream", "[quic]") write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); CHECK(frame); CHECK(frame->type() == QUICFrameType::STREAM_DATA_BLOCKED); CHECK(stream->will_generate_frame(level) == true); @@ -262,7 +264,7 @@ TEST_CASE("QUICStream", "[quic]") // This should send a frame stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); CHECK(stream->will_generate_frame(level) == false); @@ -273,13 +275,13 @@ TEST_CASE("QUICStream", "[quic]") write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); CHECK(stream->will_generate_frame(level) == true); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM_DATA_BLOCKED); // Update window @@ -287,7 +289,7 @@ TEST_CASE("QUICStream", "[quic]") stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); CHECK(frame->type() == QUICFrameType::STREAM); CHECK(stream->will_generate_frame(level) == false); } @@ -352,18 +354,18 @@ TEST_CASE("QUICStream", "[quic]") stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrame *frame = nullptr; stream->reset(QUICStreamErrorUPtr(new QUICStreamError(stream.get(), QUIC_APP_ERROR_CODE_STOPPING))); - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); REQUIRE(frame); CHECK(frame->type() == QUICFrameType::RESET_STREAM); // Don't send it again untill it is considers as lost - CHECK(stream->generate_frame(level, 4096, 4096) == nullptr); + CHECK(stream->generate_frame(frame_buf, level, 4096, 4096) == nullptr); // Loss the frame stream->on_frame_lost(frame->id()); // After the loss the frame should be regenerated - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); REQUIRE(frame); CHECK(frame->type() == QUICFrameType::RESET_STREAM); } @@ -382,18 +384,18 @@ TEST_CASE("QUICStream", "[quic]") stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); + QUICFrame *frame = nullptr; stream->stop_sending(QUICStreamErrorUPtr(new QUICStreamError(stream.get(), QUIC_APP_ERROR_CODE_STOPPING))); - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); REQUIRE(frame); CHECK(frame->type() == QUICFrameType::STOP_SENDING); // Don't send it again untill it is considers as lost - CHECK(stream->generate_frame(level, 4096, 4096) == nullptr); + CHECK(stream->generate_frame(frame_buf, level, 4096, 4096) == nullptr); // Loss the frame stream->on_frame_lost(frame->id()); // After the loss the frame should be regenerated - frame = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096); REQUIRE(frame); CHECK(frame->type() == QUICFrameType::STOP_SENDING); } diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index b4138874ec3..31e3a5a7db4 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -69,8 +69,10 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") block->fill(4); CHECK(block->read_avail() == 4); - std::shared_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(block, 0, 0); - std::shared_ptr stream_frame_4 = QUICFrameFactory::create_stream_frame(block, 4, 0); + uint8_t stream_frame_0_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t stream_frame_4_buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *stream_frame_0 = QUICFrameFactory::create_stream_frame(stream_frame_0_buf, block, 0, 0); + QUICFrame *stream_frame_4 = QUICFrameFactory::create_stream_frame(stream_frame_4_buf, block, 4, 0); CHECK(sm.stream_count() == 0); sm.handle_frame(level, *stream_frame_0); CHECK(sm.stream_count() == 1); @@ -78,24 +80,28 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") CHECK(sm.stream_count() == 2); // RESET_STREAM frames create new streams - std::shared_ptr rst_stream_frame = - QUICFrameFactory::create_rst_stream_frame(8, static_cast(0x01), 0); + uint8_t rst_stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *rst_stream_frame = + QUICFrameFactory::create_rst_stream_frame(rst_stream_frame_buf, 8, static_cast(0x01), 0); sm.handle_frame(level, *rst_stream_frame); CHECK(sm.stream_count() == 3); // MAX_STREAM_DATA frames create new streams - std::shared_ptr max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(0x0c, 0); + uint8_t max_stream_data_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *max_stream_data_frame = QUICFrameFactory::create_max_stream_data_frame(max_stream_data_frame_buf, 0x0c, 0); sm.handle_frame(level, *max_stream_data_frame); CHECK(sm.stream_count() == 4); // STREAM_DATA_BLOCKED frames create new streams - std::shared_ptr stream_blocked_frame = QUICFrameFactory::create_stream_data_blocked_frame(0x10, 0); + uint8_t stream_blocked_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *stream_blocked_frame = QUICFrameFactory::create_stream_data_blocked_frame(stream_blocked_frame_buf, 0x10, 0); sm.handle_frame(level, *stream_blocked_frame); CHECK(sm.stream_count() == 5); // Set local maximum stream id sm.set_max_streams_bidi(5); - std::shared_ptr stream_blocked_frame_x = QUICFrameFactory::create_stream_data_blocked_frame(0x18, 0); + uint8_t stream_blocked_frame_x_buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *stream_blocked_frame_x = QUICFrameFactory::create_stream_data_blocked_frame(stream_blocked_frame_x_buf, 0x18, 0); sm.handle_frame(level, *stream_blocked_frame_x); CHECK(sm.stream_count() == 5); } @@ -122,7 +128,8 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") block->fill(4); CHECK(block->read_avail() == 4); - std::shared_ptr stream_frame_0 = QUICFrameFactory::create_stream_frame(block, 0, 7); + uint8_t stream_frame_0_buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *stream_frame_0 = QUICFrameFactory::create_stream_frame(stream_frame_0_buf, block, 0, 7); sm.handle_frame(level, *stream_frame_0); CHECK("succeed"); @@ -167,8 +174,10 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") sm.init_flow_control_params(local_tp, remote_tp); // Create a stream with STREAM_DATA_BLOCKED (== noop) - std::shared_ptr stream_blocked_frame_0 = QUICFrameFactory::create_stream_data_blocked_frame(0, 0); - std::shared_ptr stream_blocked_frame_1 = QUICFrameFactory::create_stream_data_blocked_frame(4, 0); + uint8_t stream_blocked_frame_0_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t stream_blocked_frame_1_buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *stream_blocked_frame_0 = QUICFrameFactory::create_stream_data_blocked_frame(stream_blocked_frame_0_buf, 0, 0); + QUICFrame *stream_blocked_frame_1 = QUICFrameFactory::create_stream_data_blocked_frame(stream_blocked_frame_1_buf, 4, 0); sm.handle_frame(level, *stream_blocked_frame_0); sm.handle_frame(level, *stream_blocked_frame_1); CHECK(sm.stream_count() == 2); @@ -180,7 +189,8 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") block->fill(1024); CHECK(block->read_avail() == 1024); - std::shared_ptr stream_frame_1 = QUICFrameFactory::create_stream_frame(block, 8, 0); + uint8_t stream_frame_1_buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *stream_frame_1 = QUICFrameFactory::create_stream_frame(stream_frame_1_buf, block, 8, 0); sm.handle_frame(level, *stream_frame_1); CHECK(sm.total_offset_received() == 1024); } @@ -223,8 +233,10 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") block_3->fill(3); CHECK(block_3->read_avail() == 3); - std::shared_ptr stream_frame_0_r = QUICFrameFactory::create_stream_frame(block_3, 0, 0); - std::shared_ptr stream_frame_4_r = QUICFrameFactory::create_stream_frame(block_3, 4, 0); + uint8_t stream_frame0_buf_r[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t stream_frame4_buf_r[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *stream_frame_0_r = QUICFrameFactory::create_stream_frame(stream_frame0_buf_r, block_3, 0, 0); + QUICFrame *stream_frame_4_r = QUICFrameFactory::create_stream_frame(stream_frame4_buf_r, block_3, 4, 0); sm.handle_frame(level, *stream_frame_0_r); sm.handle_frame(level, *stream_frame_4_r); CHECK(sm.stream_count() == 2); @@ -236,14 +248,16 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") CHECK(block_1024->read_avail() == 1024); // total_offset should be a integer in unit of octets - QUICFrameUPtr stream_frame_0 = QUICFrameFactory::create_stream_frame(block_1024, 0, 0); + uint8_t stream_frame0_buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *stream_frame_0 = QUICFrameFactory::create_stream_frame(stream_frame0_buf, block_1024, 0, 0); mock_app.send(reinterpret_cast(block_1024->buf()), 1024, 0); sm.add_total_offset_sent(1024); sleep(2); CHECK(sm.total_offset_sent() == 1024); // total_offset should be a integer in unit of octets - QUICFrameUPtr stream_frame_4 = QUICFrameFactory::create_stream_frame(block_1024, 4, 0); + uint8_t stream_frame4_buf[QUICFrame::MAX_INSTANCE_SIZE]; + QUICFrame *stream_frame_4 = QUICFrameFactory::create_stream_frame(stream_frame4_buf, block_1024, 4, 0); mock_app.send(reinterpret_cast(block_1024->buf()), 1024, 4); sm.add_total_offset_sent(1024); sleep(2); diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index ad5119f08a6..080866928df 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -37,10 +37,16 @@ TEST_CASE("QUICSendStreamState", "[quic]") block_4->fill(4); CHECK(block_4->read_avail() == 4); - auto stream_frame = QUICFrameFactory::create_stream_frame(block_4, 1, 0); - auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(block_4, 1, 0, true); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); - auto stream_data_blocked_frame = QUICFrameFactory::create_stream_data_blocked_frame(0, 0); + uint8_t stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t stream_frame_with_fin_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t rst_stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t stream_data_blocked_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + + auto stream_frame = QUICFrameFactory::create_stream_frame(stream_frame_buf, block_4, 1, 0); + auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(stream_frame_with_fin_buf, block_4, 1, 0, true); + auto rst_stream_frame = + QUICFrameFactory::create_rst_stream_frame(rst_stream_frame_buf, 0, static_cast(0x01), 0); + auto stream_data_blocked_frame = QUICFrameFactory::create_stream_data_blocked_frame(stream_data_blocked_frame_buf, 0, 0); MockQUICTransferProgressProvider pp; SECTION("Ready -> Send -> Data Sent -> Data Recvd") @@ -182,11 +188,18 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") block_4->fill(4); CHECK(block_4->read_avail() == 4); - auto stream_frame = QUICFrameFactory::create_stream_frame(block_4, 1, 0); - auto stream_frame_delayed = QUICFrameFactory::create_stream_frame(block_4, 1, 1); - auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(block_4, 1, 2, true); - auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(0, static_cast(0x01), 0); - auto stream_data_blocked_frame = QUICFrameFactory::create_stream_data_blocked_frame(0, 0); + uint8_t stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t stream_frame_delayed_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t stream_frame_with_fin_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t rst_stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t stream_data_blocked_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + + auto stream_frame = QUICFrameFactory::create_stream_frame(stream_frame_buf, block_4, 1, 0); + auto stream_frame_delayed = QUICFrameFactory::create_stream_frame(stream_frame_delayed_buf, block_4, 1, 1); + auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(stream_frame_with_fin_buf, block_4, 1, 2, true); + auto rst_stream_frame = + QUICFrameFactory::create_rst_stream_frame(rst_stream_frame_buf, 0, static_cast(0x01), 0); + auto stream_data_blocked_frame = QUICFrameFactory::create_stream_data_blocked_frame(stream_data_blocked_frame_buf, 0, 0); SECTION("Recv -> Size Known -> Data Recvd -> Data Read") { From 37082d54ccc9ccf9bf2026612eac2ec731068117 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 13 Feb 2019 15:31:26 +0900 Subject: [PATCH 1119/1313] Create and delete QUICStreamFrame on QUICStream side --- iocore/net/quic/QUICIncomingFrameBuffer.cc | 44 ++++---- iocore/net/quic/QUICIncomingFrameBuffer.h | 12 +-- iocore/net/quic/QUICStream.cc | 17 ++- .../quic/test/test_QUICIncomingFrameBuffer.cc | 76 +++++++------ iocore/net/quic/test/test_QUICStream.cc | 100 +++++++++--------- 5 files changed, 136 insertions(+), 113 deletions(-) diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index 6e448d1ee55..1af365160f1 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -26,14 +26,22 @@ // // QUICIncomingFrameBuffer // + +QUICIncomingFrameBuffer::~QUICIncomingFrameBuffer() +{ + this->clear(); +} + void QUICIncomingFrameBuffer::clear() { - // FIXME delete the items + for (auto ite : this->_out_of_order_queue) { + delete ite.second; + } this->_out_of_order_queue.clear(); while (!this->_recv_buffer.empty()) { - // FIXME delete the items + delete this->_recv_buffer.front(); this->_recv_buffer.pop(); } @@ -78,20 +86,20 @@ QUICIncomingStreamFrameBuffer::pop() } QUICConnectionErrorUPtr -QUICIncomingStreamFrameBuffer::insert(const QUICFrame &frame) +QUICIncomingStreamFrameBuffer::insert(const QUICFrame *frame) { - const QUICStreamFrame &stream_frame = static_cast(frame); + const QUICStreamFrame *stream_frame = static_cast(frame); - QUICOffset offset = stream_frame.offset(); - size_t len = stream_frame.data_length(); + QUICOffset offset = stream_frame->offset(); + size_t len = stream_frame->data_length(); - QUICConnectionErrorUPtr err = this->_check_and_set_fin_flag(offset, len, stream_frame.has_fin_flag()); + QUICConnectionErrorUPtr err = this->_check_and_set_fin_flag(offset, len, stream_frame->has_fin_flag()); if (err != nullptr) { return err; } // Ignore empty stream frame except pure fin stream frame - if (len == 0 && !stream_frame.has_fin_flag()) { + if (len == 0 && !stream_frame->has_fin_flag()) { return nullptr; } @@ -100,11 +108,9 @@ QUICIncomingStreamFrameBuffer::insert(const QUICFrame &frame) return nullptr; } else if (this->_recv_offset == offset) { this->_recv_offset = offset + len; - QUICFrame *cloned = new QUICStreamFrame(stream_frame); - this->_recv_buffer.push(cloned); + this->_recv_buffer.push(stream_frame); } else { - QUICFrame *cloned = new QUICStreamFrame(stream_frame); - this->_out_of_order_queue.insert(std::make_pair(offset, cloned)); + this->_out_of_order_queue.insert(std::make_pair(offset, stream_frame)); } return nullptr; @@ -212,12 +218,12 @@ QUICIncomingCryptoFrameBuffer::pop() } QUICConnectionErrorUPtr -QUICIncomingCryptoFrameBuffer::insert(const QUICFrame &frame) +QUICIncomingCryptoFrameBuffer::insert(const QUICFrame *frame) { - const QUICCryptoFrame &crypto_frame = static_cast(frame); + const QUICCryptoFrame *crypto_frame = static_cast(frame); - QUICOffset offset = crypto_frame.offset(); - size_t len = crypto_frame.data_length(); + QUICOffset offset = crypto_frame->offset(); + size_t len = crypto_frame->data_length(); // Ignore empty stream frame if (len == 0) { @@ -229,11 +235,9 @@ QUICIncomingCryptoFrameBuffer::insert(const QUICFrame &frame) return nullptr; } else if (this->_recv_offset == offset) { this->_recv_offset = offset + len; - QUICFrame *cloned = new QUICCryptoFrame(crypto_frame); - this->_recv_buffer.push(cloned); + this->_recv_buffer.push(crypto_frame); } else { - QUICFrame *cloned = new QUICCryptoFrame(crypto_frame); - this->_out_of_order_queue.insert(std::make_pair(offset, cloned)); + this->_out_of_order_queue.insert(std::make_pair(offset, crypto_frame)); } return nullptr; diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index 3dffc32022b..6251908b6d6 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -33,11 +33,9 @@ class QUICIncomingFrameBuffer { public: - virtual const QUICFrame *pop() = 0; - /* - * Becasue frames passed by FrameDispatcher is temporal, this clones a passed frame to ensure that we can use it later. - */ - virtual QUICConnectionErrorUPtr insert(const QUICFrame &frame) = 0; + ~QUICIncomingFrameBuffer(); + virtual const QUICFrame *pop() = 0; + virtual QUICConnectionErrorUPtr insert(const QUICFrame *frame) = 0; virtual void clear(); virtual bool empty(); @@ -57,7 +55,7 @@ class QUICIncomingStreamFrameBuffer : public QUICIncomingFrameBuffer, public QUI ~QUICIncomingStreamFrameBuffer(); const QUICFrame *pop() override; - QUICConnectionErrorUPtr insert(const QUICFrame &frame) override; + QUICConnectionErrorUPtr insert(const QUICFrame *frame) override; void clear() override; // QUICTransferProgressProvider @@ -82,7 +80,7 @@ class QUICIncomingCryptoFrameBuffer : public QUICIncomingFrameBuffer ~QUICIncomingCryptoFrameBuffer(); const QUICFrame *pop() override; - QUICConnectionErrorUPtr insert(const QUICFrame &frame) override; + QUICConnectionErrorUPtr insert(const QUICFrame *frame) override; private: }; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index d92b1d0718b..132df1fca62 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -332,7 +332,9 @@ QUICStream::recv(const QUICStreamFrame &frame) return std::make_unique(QUICTransErrorCode::FLOW_CONTROL_ERROR); } - QUICConnectionErrorUPtr error = this->_received_stream_frame_buffer.insert(frame); + // Make a copy and insert it into the receive buffer because the frame passed is temporal + QUICFrame *cloned = new QUICStreamFrame(frame); + QUICConnectionErrorUPtr error = this->_received_stream_frame_buffer.insert(cloned); if (error != nullptr) { this->_received_stream_frame_buffer.clear(); return error; @@ -340,20 +342,25 @@ QUICStream::recv(const QUICStreamFrame &frame) auto new_frame = this->_received_stream_frame_buffer.pop(); const QUICStreamFrame *stream_frame = nullptr; + uint64_t last_offset = 0; + uint64_t last_length = 0; while (new_frame != nullptr) { stream_frame = static_cast(new_frame); + last_offset = stream_frame->offset(); + last_length = stream_frame->data_length(); this->_write_to_read_vio(stream_frame->offset(), reinterpret_cast(stream_frame->data()->start()), stream_frame->data_length(), stream_frame->has_fin_flag()); this->_state.update_with_receiving_frame(*new_frame); + delete new_frame; new_frame = this->_received_stream_frame_buffer.pop(); } // Forward limit of local flow controller with the largest reordered stream frame if (stream_frame) { - this->_reordered_bytes = stream_frame->offset() + stream_frame->data_length(); + this->_reordered_bytes = last_offset + last_length; this->_local_flow_controller.forward_limit(this->_reordered_bytes + this->_flow_control_buffer_size); QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), this->_local_flow_controller.current_limit()); @@ -824,7 +831,9 @@ QUICCryptoStream::reset_recv_offset() QUICConnectionErrorUPtr QUICCryptoStream::recv(const QUICCryptoFrame &frame) { - QUICConnectionErrorUPtr error = this->_received_stream_frame_buffer.insert(frame); + // Make a copy and insert it into the receive buffer because the frame passed is temporal + QUICFrame *cloned = new QUICCryptoFrame(frame); + QUICConnectionErrorUPtr error = this->_received_stream_frame_buffer.insert(cloned); if (error != nullptr) { this->_received_stream_frame_buffer.clear(); return error; @@ -835,6 +844,8 @@ QUICCryptoStream::recv(const QUICCryptoFrame &frame) const QUICCryptoFrame *crypto_frame = static_cast(new_frame); this->_read_buffer->write(reinterpret_cast(crypto_frame->data()->start()), crypto_frame->data_length()); + + delete new_frame; new_frame = this->_received_stream_frame_buffer.pop(); } diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 2338129d523..7a5674325ef 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -47,8 +47,10 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") { QUICStreamFrame *stream1_frame_0_r = QUICFrameFactory::create_stream_frame(frame_buf, block_1024, 1, 0, true); - err = buffer.insert(*stream1_frame_0_r); + err = buffer.insert(new QUICStreamFrame(*stream1_frame_0_r)); CHECK(err == nullptr); + + buffer.clear(); } SECTION("multiple frames") @@ -64,28 +66,34 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") QUICStreamFrame *stream1_frame_3_r = QUICFrameFactory::create_stream_frame(frame_buf3, block_1024, 1, 3072, true); QUICStreamFrame *stream1_frame_4_r = QUICFrameFactory::create_stream_frame(frame_buf4, block_1024, 1, 4096); - buffer.insert(*stream1_frame_0_r); - buffer.insert(*stream1_frame_1_r); - buffer.insert(*stream1_frame_2_r); - err = buffer.insert(*stream1_frame_3_r); + buffer.insert(new QUICStreamFrame(*stream1_frame_0_r)); + buffer.insert(new QUICStreamFrame(*stream1_frame_1_r)); + buffer.insert(new QUICStreamFrame(*stream1_frame_2_r)); + err = buffer.insert(new QUICStreamFrame(*stream1_frame_3_r)); CHECK(err->cls == QUICErrorClass::TRANSPORT); CHECK(err->code == static_cast(QUICTransErrorCode::FINAL_OFFSET_ERROR)); + buffer.clear(); + QUICIncomingStreamFrameBuffer buffer2; - buffer2.insert(*stream1_frame_3_r); - buffer2.insert(*stream1_frame_0_r); - buffer2.insert(*stream1_frame_1_r); - err = buffer2.insert(*stream1_frame_2_r); + buffer2.insert(new QUICStreamFrame(*stream1_frame_3_r)); + buffer2.insert(new QUICStreamFrame(*stream1_frame_0_r)); + buffer2.insert(new QUICStreamFrame(*stream1_frame_1_r)); + err = buffer2.insert(new QUICStreamFrame(*stream1_frame_2_r)); CHECK(err->cls == QUICErrorClass::TRANSPORT); CHECK(err->code == static_cast(QUICTransErrorCode::FINAL_OFFSET_ERROR)); + buffer2.clear(); + QUICIncomingStreamFrameBuffer buffer3; - buffer3.insert(*stream1_frame_4_r); - err = buffer3.insert(*stream1_frame_3_r); + buffer3.insert(new QUICStreamFrame(*stream1_frame_4_r)); + err = buffer3.insert(new QUICStreamFrame(*stream1_frame_3_r)); CHECK(err->cls == QUICErrorClass::TRANSPORT); CHECK(err->code == static_cast(QUICTransErrorCode::FINAL_OFFSET_ERROR)); + + buffer3.clear(); } SECTION("Pure FIN") @@ -97,14 +105,16 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") QUICStreamFrame *stream1_frame_empty = QUICFrameFactory::create_stream_frame(frame_buf1, block_0, 1, 1024); QUICStreamFrame *stream1_frame_pure_fin = QUICFrameFactory::create_stream_frame(frame_buf2, block_0, 1, 1024, true); - err = buffer.insert(*stream1_frame_0_r); + err = buffer.insert(new QUICStreamFrame(*stream1_frame_0_r)); CHECK(err == nullptr); - err = buffer.insert(*stream1_frame_empty); + err = buffer.insert(new QUICStreamFrame(*stream1_frame_empty)); CHECK(err == nullptr); - err = buffer.insert(*stream1_frame_pure_fin); + err = buffer.insert(new QUICStreamFrame(*stream1_frame_pure_fin)); CHECK(err == nullptr); + + buffer.clear(); } delete stream; @@ -139,12 +149,12 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") QUICStreamFrame *stream1_frame_3_r = QUICFrameFactory::create_stream_frame(frame_buf4, block_1024, 1, 3072); QUICStreamFrame *stream1_frame_4_r = QUICFrameFactory::create_stream_frame(frame_buf5, block_1024, 1, 4096, true); - buffer.insert(*stream1_frame_0_r); - buffer.insert(*stream1_frame_1_r); - buffer.insert(*stream1_frame_empty); - buffer.insert(*stream1_frame_2_r); - buffer.insert(*stream1_frame_3_r); - buffer.insert(*stream1_frame_4_r); + buffer.insert(new QUICStreamFrame(*stream1_frame_0_r)); + buffer.insert(new QUICStreamFrame(*stream1_frame_1_r)); + buffer.insert(new QUICStreamFrame(*stream1_frame_empty)); + buffer.insert(new QUICStreamFrame(*stream1_frame_2_r)); + buffer.insert(new QUICStreamFrame(*stream1_frame_3_r)); + buffer.insert(new QUICStreamFrame(*stream1_frame_4_r)); CHECK(!buffer.empty()); auto frame = static_cast(buffer.pop()); @@ -161,11 +171,11 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") buffer.clear(); - buffer.insert(*stream1_frame_4_r); - buffer.insert(*stream1_frame_3_r); - buffer.insert(*stream1_frame_2_r); - buffer.insert(*stream1_frame_1_r); - buffer.insert(*stream1_frame_0_r); + buffer.insert(new QUICStreamFrame(*stream1_frame_4_r)); + buffer.insert(new QUICStreamFrame(*stream1_frame_3_r)); + buffer.insert(new QUICStreamFrame(*stream1_frame_2_r)); + buffer.insert(new QUICStreamFrame(*stream1_frame_1_r)); + buffer.insert(new QUICStreamFrame(*stream1_frame_0_r)); CHECK(!buffer.empty()); frame = static_cast(buffer.pop()); @@ -211,10 +221,10 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") QUICStreamFrame *stream1_frame_2_r = QUICFrameFactory::create_stream_frame(frame_buf2, block_1024, 1, 2048, true); QUICStreamFrame *stream1_frame_3_r = QUICFrameFactory::create_stream_frame(frame_buf3, block_1024, 1, 2048, true); - buffer.insert(*stream1_frame_0_r); - buffer.insert(*stream1_frame_1_r); - buffer.insert(*stream1_frame_2_r); - err = buffer.insert(*stream1_frame_3_r); + buffer.insert(new QUICStreamFrame(*stream1_frame_0_r)); + buffer.insert(new QUICStreamFrame(*stream1_frame_1_r)); + buffer.insert(new QUICStreamFrame(*stream1_frame_2_r)); + err = buffer.insert(new QUICStreamFrame(*stream1_frame_3_r)); CHECK(err == nullptr); auto frame = static_cast(buffer.pop()); @@ -234,10 +244,10 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") QUICStreamFrame *stream2_frame_2_r = QUICFrameFactory::create_stream_frame(frame_buf6, block_1024, 1, 1024); QUICStreamFrame *stream2_frame_3_r = QUICFrameFactory::create_stream_frame(frame_buf7, block_1024, 1, 2048, true); - buffer.insert(*stream2_frame_0_r); - buffer.insert(*stream2_frame_1_r); - buffer.insert(*stream2_frame_2_r); - err = buffer.insert(*stream2_frame_3_r); + buffer.insert(new QUICStreamFrame(*stream2_frame_0_r)); + buffer.insert(new QUICStreamFrame(*stream2_frame_1_r)); + buffer.insert(new QUICStreamFrame(*stream2_frame_2_r)); + err = buffer.insert(new QUICStreamFrame(*stream2_frame_3_r)); CHECK(err == nullptr); frame = static_cast(buffer.pop()); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index fcca4c678f4..bf6aadc37d0 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -38,44 +38,44 @@ TEST_CASE("QUICStream", "[quic]") uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; - Ptr new_block = make_ptr(block->clone()); - new_block->_end = new_block->_start + 2; - std::shared_ptr frame_1 = std::make_shared(new_block, stream_id, 0); + Ptr new_block = make_ptr(block->clone()); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_1(new_block, stream_id, 0); block->consume(2); - new_block = block->clone(); - new_block->_end = new_block->_start + 2; - std::shared_ptr frame_2 = std::make_shared(new_block, stream_id, 2); + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_2(new_block, stream_id, 2); block->consume(2); - new_block = block->clone(); - new_block->_end = new_block->_start + 2; - std::shared_ptr frame_3 = std::make_shared(new_block, stream_id, 4); + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_3(new_block, stream_id, 4); block->consume(2); - new_block = block->clone(); - new_block->_end = new_block->_start + 2; - std::shared_ptr frame_4 = std::make_shared(new_block, stream_id, 6); + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_4(new_block, stream_id, 6); block->consume(2); - new_block = block->clone(); - new_block->_end = new_block->_start + 2; - std::shared_ptr frame_5 = std::make_shared(new_block, stream_id, 8); + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_5(new_block, stream_id, 8); block->consume(2); - new_block = block->clone(); - new_block->_end = new_block->_start + 2; - std::shared_ptr frame_6 = std::make_shared(new_block, stream_id, 10); + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_6(new_block, stream_id, 10); block->consume(2); - new_block = block->clone(); - new_block->_end = new_block->_start + 2; - std::shared_ptr frame_7 = std::make_shared(new_block, stream_id, 12); + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_7(new_block, stream_id, 12); block->consume(2); - new_block = block->clone(); - new_block->_end = new_block->_start + 2; - std::shared_ptr frame_8 = std::make_shared(new_block, stream_id, 14); + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_8(new_block, stream_id, 14); block->consume(2); SECTION("QUICStream_assembling_byte_stream_1") @@ -88,14 +88,14 @@ TEST_CASE("QUICStream", "[quic]") std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, 1024, 1024)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); - stream->recv(*frame_1); - stream->recv(*frame_2); - stream->recv(*frame_3); - stream->recv(*frame_4); - stream->recv(*frame_5); - stream->recv(*frame_6); - stream->recv(*frame_7); - stream->recv(*frame_8); + stream->recv(frame_1); + stream->recv(frame_2); + stream->recv(frame_3); + stream->recv(frame_4); + stream->recv(frame_5); + stream->recv(frame_6); + stream->recv(frame_7); + stream->recv(frame_8); uint8_t buf[32]; int64_t len = reader->read_avail(); @@ -115,14 +115,14 @@ TEST_CASE("QUICStream", "[quic]") std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); - stream->recv(*frame_8); - stream->recv(*frame_7); - stream->recv(*frame_6); - stream->recv(*frame_5); - stream->recv(*frame_4); - stream->recv(*frame_3); - stream->recv(*frame_2); - stream->recv(*frame_1); + stream->recv(frame_8); + stream->recv(frame_7); + stream->recv(frame_6); + stream->recv(frame_5); + stream->recv(frame_4); + stream->recv(frame_3); + stream->recv(frame_2); + stream->recv(frame_1); uint8_t buf[32]; int64_t len = reader->read_avail(); @@ -142,16 +142,16 @@ TEST_CASE("QUICStream", "[quic]") std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); - stream->recv(*frame_8); - stream->recv(*frame_7); - stream->recv(*frame_6); - stream->recv(*frame_7); // duplicated frame - stream->recv(*frame_5); - stream->recv(*frame_3); - stream->recv(*frame_1); - stream->recv(*frame_2); - stream->recv(*frame_4); - stream->recv(*frame_5); // duplicated frame + stream->recv(frame_8); + stream->recv(frame_7); + stream->recv(frame_6); + stream->recv(frame_7); // duplicated frame + stream->recv(frame_5); + stream->recv(frame_3); + stream->recv(frame_1); + stream->recv(frame_2); + stream->recv(frame_4); + stream->recv(frame_5); // duplicated frame uint8_t buf[32]; int64_t len = reader->read_avail(); From 8ff58c73ae440dc1505eef52fc36ef490edb9cb5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Feb 2019 12:09:54 +0900 Subject: [PATCH 1120/1313] Remove unused aliases --- iocore/net/quic/QUICFrame.h | 9 --------- iocore/net/quic/QUICFrameHandler.h | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 225a66ca1eb..f2d9964d5e3 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -39,15 +39,6 @@ class QUICCryptoFrame; class QUICPacket; class QUICFrameGenerator; -using QUICFrameDeleterFunc = void (*)(QUICFrame *p); -using QUICFrameUPtr = std::unique_ptr; -using QUICStreamFrameUPtr = std::unique_ptr; -using QUICCryptoFrameUPtr = std::unique_ptr; - -using QUICFrameSPtr = std::shared_ptr; -using QUICStreamFrameSPtr = std::shared_ptr; -using QUICCryptoFrameSPtr = std::shared_ptr; - using QUICFrameId = uint64_t; class QUICFrame diff --git a/iocore/net/quic/QUICFrameHandler.h b/iocore/net/quic/QUICFrameHandler.h index e237d438e4a..12c3fc9e5e3 100644 --- a/iocore/net/quic/QUICFrameHandler.h +++ b/iocore/net/quic/QUICFrameHandler.h @@ -24,7 +24,7 @@ #pragma once #include -#include +class QUICFrame; class QUICFrameHandler { From 682f1d8f7d80714d803c60618dc9147d08520c06 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Feb 2019 16:20:06 +0900 Subject: [PATCH 1121/1313] Fix typo --- iocore/net/quic/QUICPathValidator.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index b0207db8e8c..6f29c3c21f5 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -127,8 +127,7 @@ QUICPathValidator::will_generate_frame(QUICEncryptionLevel level) } QUICFrame * -QUICPathValidator::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_quic_packet_size) +QUICPathValidator::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { QUICFrame *frame = nullptr; @@ -141,7 +140,7 @@ QUICPathValidator::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint6 if (this->_has_outgoing_response) { frame = QUICFrameFactory::create_path_response_frame(buf, this->_incoming_challenge); - if (frame && frame->size() > maximum_quic_packet_size) { + if (frame && frame->size() > maximum_frame_size) { // Cancel generating frame frame = nullptr; } else { @@ -150,7 +149,7 @@ QUICPathValidator::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint6 } else if (this->_has_outgoing_challenge) { frame = QUICFrameFactory::create_path_challenge_frame( buf, this->_outgoing_challenge + (QUICPathChallengeFrame::DATA_LEN * (this->_has_outgoing_challenge - 1))); - if (frame && frame->size() > maximum_quic_packet_size) { + if (frame && frame->size() > maximum_frame_size) { // Cancel generating frame frame = nullptr; } else { From 9184dbf153d7df8f992306358c7f21f67ee15743 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Feb 2019 16:31:19 +0900 Subject: [PATCH 1122/1313] Make maximum/minimum_quic_packet_size private Since nobody use it. --- iocore/net/P_QUICNetVConnection.h | 4 ++-- iocore/net/QUICNetVConnection.cc | 10 +++++----- iocore/net/quic/Mock.h | 12 ------------ iocore/net/quic/QUICConnection.h | 15 --------------- 4 files changed, 7 insertions(+), 34 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 55a4c8af2bd..763fab2f6f0 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -205,8 +205,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICConnectionId connection_id() const override; std::string_view cids() const override; const QUICFiveTuple five_tuple() const override; - uint32_t maximum_quic_packet_size() const override; - uint32_t minimum_quic_packet_size() override; uint32_t pmtu() const override; NetVConnectionContext_t direction() const override; SSLNextProtocolSet *next_protocol_set() const override; @@ -309,6 +307,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _unschedule_ack_manager_periodic(); Event *_ack_manager_periodic = nullptr; + uint32_t _maximum_quic_packet_size() const; + uint32_t _minimum_quic_packet_size(); uint64_t _maximum_stream_frame_data_size(); void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrame &frame, std::vector &frames); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 839f43cb899..90a5171a3dc 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -446,7 +446,7 @@ QUICNetVConnection::direction() const } uint32_t -QUICNetVConnection::minimum_quic_packet_size() +QUICNetVConnection::_minimum_quic_packet_size() { if (netvc_context == NET_VCONNECTION_OUT) { // FIXME Only the first packet need to be 1200 bytes at least @@ -459,7 +459,7 @@ QUICNetVConnection::minimum_quic_packet_size() } uint32_t -QUICNetVConnection::maximum_quic_packet_size() const +QUICNetVConnection::_maximum_quic_packet_size() const { if (this->options.ip_family == PF_INET6) { return this->_pmtu - UDP_HEADER_SIZE - IPV6_HEADER_SIZE; @@ -471,7 +471,7 @@ QUICNetVConnection::maximum_quic_packet_size() const uint64_t QUICNetVConnection::_maximum_stream_frame_data_size() { - return this->maximum_quic_packet_size() - MAX_STREAM_FRAME_OVERHEAD - MAX_PACKET_OVERHEAD; + return this->_maximum_quic_packet_size() - MAX_STREAM_FRAME_OVERHEAD - MAX_PACKET_OVERHEAD; } QUICStreamManager * @@ -1423,7 +1423,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa if (len != 0) { if (level == QUICEncryptionLevel::INITIAL && this->netvc_context == NET_VCONNECTION_OUT) { // Pad with PADDING frames - uint64_t min_size = this->minimum_quic_packet_size(); + uint64_t min_size = this->_minimum_quic_packet_size(); if (this->_av_token) { min_size = min_size - this->_av_token_len; } @@ -1465,7 +1465,7 @@ QUICNetVConnection::_packetize_closing_frame() uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; frame = QUICFrameFactory::create_connection_close_frame(frame_buf, *this->_connection_error); - uint32_t max_size = this->maximum_quic_packet_size(); + uint32_t max_size = this->_maximum_quic_packet_size(); ats_unique_buf buf = ats_unique_malloc(max_size); size_t len = 0; diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 7d87b0784cd..4a4bf38c601 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -212,18 +212,6 @@ class MockQUICConnection : public QUICConnection return nullptr; } - uint32_t - minimum_quic_packet_size() override - { - return 1200; - } - - uint32_t - maximum_quic_packet_size() const override - { - return 1200; - } - uint32_t pmtu() const override { diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 8af0f24d41f..fbe3b44fbb5 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -43,21 +43,6 @@ class QUICConnectionInfoProvider virtual std::string_view cids() const = 0; virtual const QUICFiveTuple five_tuple() const = 0; - /* - * Retruns the maximum packet size at the time called - * - * The size depends on PMTU. - */ - virtual uint32_t maximum_quic_packet_size() const = 0; - - /* - * Returns the mimimum packet size at the time called - * - * If the connection is an outgoing connection and you have not sent Client Initial packet, - * this return the minimum size for it, which is 1200. - */ - virtual uint32_t minimum_quic_packet_size() = 0; - virtual uint32_t pmtu() const = 0; virtual NetVConnectionContext_t direction() const = 0; virtual SSLNextProtocolSet *next_protocol_set() const = 0; From 1a160b4c586b5d5c5f8c6444d9c789169ed11bb7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Feb 2019 16:54:20 +0900 Subject: [PATCH 1123/1313] Make QUICNetVC::largest_acked_packet_number() private --- iocore/net/P_QUICNetVConnection.h | 3 ++- iocore/net/QUICNetVConnection.cc | 10 +++++----- iocore/net/quic/Mock.h | 24 ------------------------ iocore/net/quic/QUICConnection.h | 11 +++++------ 4 files changed, 12 insertions(+), 36 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 763fab2f6f0..abe6620898e 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -208,7 +208,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub uint32_t pmtu() const override; NetVConnectionContext_t direction() const override; SSLNextProtocolSet *next_protocol_set() const override; - QUICPacketNumber largest_acked_packet_number(QUICEncryptionLevel level) const override; std::string_view negotiated_application_name() const override; bool is_closed() const override; @@ -307,9 +306,11 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _unschedule_ack_manager_periodic(); Event *_ack_manager_periodic = nullptr; + QUICPacketNumber _largest_acked_packet_number(QUICEncryptionLevel level) const; uint32_t _maximum_quic_packet_size() const; uint32_t _minimum_quic_packet_size(); uint64_t _maximum_stream_frame_data_size(); + void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrame &frame, std::vector &frames); QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 90a5171a3dc..1a410ec4391 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -907,7 +907,7 @@ QUICNetVConnection::next_protocol_set() const } QUICPacketNumber -QUICNetVConnection::largest_acked_packet_number(QUICEncryptionLevel level) const +QUICNetVConnection::_largest_acked_packet_number(QUICEncryptionLevel level) const { int index = QUICTypeUtil::pn_space_index(level); @@ -1551,25 +1551,25 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi } packet = this->_packet_factory.create_initial_packet( - dcid, this->_quic_connection_id, this->largest_acked_packet_number(QUICEncryptionLevel::INITIAL), std::move(buf), len, + dcid, this->_quic_connection_id, this->_largest_acked_packet_number(QUICEncryptionLevel::INITIAL), std::move(buf), len, retransmittable, probing, frames, 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, - this->largest_acked_packet_number(QUICEncryptionLevel::HANDSHAKE), + this->_largest_acked_packet_number(QUICEncryptionLevel::HANDSHAKE), std::move(buf), len, retransmittable, probing, frames); break; } case QUICPacketType::ZERO_RTT_PROTECTED: { packet = this->_packet_factory.create_zero_rtt_packet(this->_original_quic_connection_id, this->_quic_connection_id, - this->largest_acked_packet_number(QUICEncryptionLevel::ZERO_RTT), + this->_largest_acked_packet_number(QUICEncryptionLevel::ZERO_RTT), std::move(buf), len, retransmittable, probing, frames); break; } case QUICPacketType::PROTECTED: { packet = this->_packet_factory.create_protected_packet(this->_peer_quic_connection_id, - this->largest_acked_packet_number(QUICEncryptionLevel::ONE_RTT), + this->_largest_acked_packet_number(QUICEncryptionLevel::ONE_RTT), std::move(buf), len, retransmittable, probing, frames); break; } diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 4a4bf38c601..9ab283d5a99 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -218,12 +218,6 @@ class MockQUICConnection : public QUICConnection return 1280; } - QUICPacketNumber - largest_acked_packet_number(QUICEncryptionLevel level) const override - { - return 0; - } - NetVConnectionContext_t direction() const override { @@ -325,30 +319,12 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider return std::string_view("00000000-00000000"sv); } - uint32_t - minimum_quic_packet_size() override - { - return 1200; - } - - uint32_t - maximum_quic_packet_size() const override - { - return 1200; - } - uint32_t pmtu() const override { return 1280; } - QUICPacketNumber - largest_acked_packet_number(QUICEncryptionLevel level) const override - { - return 0; - } - NetVConnectionContext_t direction() const override { diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index fbe3b44fbb5..96efe4f2c0a 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -43,12 +43,11 @@ class QUICConnectionInfoProvider virtual std::string_view cids() const = 0; virtual const QUICFiveTuple five_tuple() const = 0; - virtual uint32_t pmtu() const = 0; - virtual NetVConnectionContext_t direction() const = 0; - virtual SSLNextProtocolSet *next_protocol_set() const = 0; - virtual bool is_closed() const = 0; - virtual QUICPacketNumber largest_acked_packet_number(QUICEncryptionLevel level) const = 0; - virtual std::string_view negotiated_application_name() const = 0; + virtual uint32_t pmtu() const = 0; + virtual NetVConnectionContext_t direction() const = 0; + virtual SSLNextProtocolSet *next_protocol_set() const = 0; + virtual bool is_closed() const = 0; + virtual std::string_view negotiated_application_name() const = 0; }; class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler, public QUICConnectionInfoProvider From adcfe785b5d4f514870aaef04e7f0207921a189c Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 12 Feb 2019 15:49:19 +0800 Subject: [PATCH 1124/1313] QUIC: Rename QUICPacket::retransmittable to ack_eliciting --- iocore/net/quic/QUICLossDetector.cc | 2 +- iocore/net/quic/QUICPacket.cc | 28 ++++++++++++++-------------- iocore/net/quic/QUICPacket.h | 10 +++++----- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 61796d7aa18..6aba8208e56 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -151,7 +151,7 @@ QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) } QUICPacketNumber packet_number = packet->packet_number(); - bool is_ack_only = !packet->is_retransmittable(); + bool is_ack_only = !packet->is_ack_eliciting(); size_t sent_bytes = is_ack_only ? 0 : packet->size(); this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); this->_on_packet_sent(packet_number, is_ack_only, is_handshake, sent_bytes, std::move(packet)); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 8619789748d..be7d3abc7a8 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -798,24 +798,24 @@ QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size this->_payload_size = payload_len; } -QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing) +QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool ack_eliciting, bool probing) { - this->_header = std::move(header); - this->_payload = std::move(payload); - this->_payload_size = payload_len; - this->_is_retransmittable = retransmittable; - this->_is_probing_packet = probing; + this->_header = std::move(header); + this->_payload = std::move(payload); + this->_payload_size = payload_len; + this->_is_ack_eliciting = ack_eliciting; + this->_is_probing_packet = probing; } -QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing, +QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool ack_eliciting, bool probing, std::vector &frames) : QUICTrackablePacket(frames) { - this->_header = std::move(header); - this->_payload = std::move(payload); - this->_payload_size = payload_len; - this->_is_retransmittable = retransmittable; - this->_is_probing_packet = probing; + this->_header = std::move(header); + this->_payload = std::move(payload); + this->_payload_size = payload_len; + this->_is_ack_eliciting = ack_eliciting; + this->_is_probing_packet = probing; } QUICPacket::~QUICPacket() @@ -876,9 +876,9 @@ QUICPacket::version() const } bool -QUICPacket::is_retransmittable() const +QUICPacket::is_ack_eliciting() const { - return this->_is_retransmittable; + return this->_is_ack_eliciting; } bool diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 8a5f4720c20..121c94a41f4 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -333,14 +333,14 @@ class QUICPacket : public QUICTrackablePacket /* * Creates a QUICPacket with a QUICPacketHeader, a buffer that contains payload and a flag that indicates whether the packet is - * retransmittable + * 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. */ - QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing); + QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool ack_eliciting, bool probing); - QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool retransmittable, bool probing, + QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool ack_eliciting, bool probing, std::vector &frames); ~QUICPacket(); @@ -353,7 +353,7 @@ class QUICPacket : public QUICTrackablePacket QUICVersion version() const; const QUICPacketHeader &header() const; const uint8_t *payload() const; - bool is_retransmittable() const; + bool is_ack_eliciting() const; bool is_probing_packet() const; /* @@ -386,7 +386,7 @@ class QUICPacket : public QUICTrackablePacket QUICPacketHeaderUPtr _header = QUICPacketHeaderUPtr(nullptr, &QUICPacketHeaderDeleter::delete_null_header); ats_unique_buf _payload = ats_unique_buf(nullptr); size_t _payload_size = 0; - bool _is_retransmittable = false; + bool _is_ack_eliciting = false; bool _is_probing_packet = false; }; From 48a89c4712b0e9adb808744ba67bdd88ab3305e3 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 12 Feb 2019 16:23:49 +0800 Subject: [PATCH 1125/1313] QUIC: Adds crypto flags --- iocore/net/P_QUICNetVConnection.h | 4 ++-- iocore/net/QUICNetVConnection.cc | 36 ++++++++++++++++------------ iocore/net/quic/QUICPacket.cc | 25 ++++++++++++++----- iocore/net/quic/QUICPacket.h | 15 ++++++++---- iocore/net/quic/QUICPacketFactory.cc | 12 +++++----- iocore/net/quic/QUICPacketFactory.h | 14 +++++------ 6 files changed, 65 insertions(+), 41 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index abe6620898e..c3d12b3e434 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -315,10 +315,10 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub std::vector &frames); QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size); void _packetize_closing_frame(); - QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, bool probing, + QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, bool probing, bool crypto, std::vector &frames, QUICPacketType type = QUICPacketType::UNINITIALIZED); QUICPacketUPtr _build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing, - std::vector &frames); + bool crypto, std::vector &frames); QUICConnectionErrorUPtr _recv_and_ack(QUICPacket &packet, bool *has_non_probing_frame = nullptr); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 1a410ec4391..4c57a26ed78 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1368,7 +1368,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa this->_pinger.request(level); } - bool ack_only = true; + bool ack_eliciting = false; + bool crypto = false; uint8_t frame_instance_buffer[QUICFrame::MAX_INSTANCE_SIZE]; // This is for a frame instance but not serialized frame data QUICFrame *frame = nullptr; for (auto g : this->_frame_generators) { @@ -1401,11 +1402,16 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } } - if (ack_only && frame->type() != QUICFrameType::ACK) { - ack_only = false; + if (!ack_eliciting && frame->type() != QUICFrameType::ACK) { + ack_eliciting = true; this->_pinger.cancel(level); } + if (frame->type() == QUICFrameType::CRYPTO && + (level == QUICEncryptionLevel::INITIAL || level == QUICEncryptionLevel::HANDSHAKE)) { + crypto = true; + } + frame->~QUICFrame(); } else { // Move to next generator @@ -1414,10 +1420,10 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } } if (frame_count == 0) { - ack_only = false; + ack_eliciting = false; } - this->_has_ack_only_packet_out = ack_only; + this->_has_ack_only_packet_out = !ack_eliciting; // Schedule a packet if (len != 0) { @@ -1444,7 +1450,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } // Packet is retransmittable if it's not ack only packet - packet = this->_build_packet(level, std::move(buf), len, !ack_only, probing, frames); + packet = this->_build_packet(level, std::move(buf), len, ack_eliciting, probing, crypto, frames); } return packet; @@ -1475,7 +1481,7 @@ QUICNetVConnection::_packetize_closing_frame() QUICEncryptionLevel level = this->_hs_protocol->current_encryption_level(); ink_assert(level != QUICEncryptionLevel::ZERO_RTT); - this->_the_final_packet = this->_build_packet(level, std::move(buf), len, false, false, frames); + this->_the_final_packet = this->_build_packet(level, std::move(buf), len, true, false, false, frames); } QUICConnectionErrorUPtr @@ -1521,14 +1527,14 @@ QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_fram } QUICPacketUPtr -QUICNetVConnection::_build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing, - std::vector &frames) +QUICNetVConnection::_build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool ack_eliciting, bool probing, + bool crypto, std::vector &frames) { - return this->_build_packet(std::move(buf), len, retransmittable, probing, frames, QUICTypeUtil::packet_type(level)); + return this->_build_packet(std::move(buf), len, ack_eliciting, probing, crypto, frames, QUICTypeUtil::packet_type(level)); } QUICPacketUPtr -QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmittable, bool probing, +QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool ack_eliciting, bool probing, bool crypto, std::vector &frames, QUICPacketType type) { QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); @@ -1552,25 +1558,25 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi packet = this->_packet_factory.create_initial_packet( dcid, this->_quic_connection_id, this->_largest_acked_packet_number(QUICEncryptionLevel::INITIAL), std::move(buf), len, - retransmittable, probing, frames, std::move(token), token_len); + ack_eliciting, probing, crypto, frames, 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, this->_largest_acked_packet_number(QUICEncryptionLevel::HANDSHAKE), - std::move(buf), len, retransmittable, probing, frames); + std::move(buf), len, ack_eliciting, probing, crypto, frames); break; } case QUICPacketType::ZERO_RTT_PROTECTED: { packet = this->_packet_factory.create_zero_rtt_packet(this->_original_quic_connection_id, this->_quic_connection_id, this->_largest_acked_packet_number(QUICEncryptionLevel::ZERO_RTT), - std::move(buf), len, retransmittable, probing, frames); + std::move(buf), len, ack_eliciting, probing, frames); 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, retransmittable, probing, frames); + std::move(buf), len, ack_eliciting, probing, frames); break; } default: diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index be7d3abc7a8..9ed9afb29e8 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -69,6 +69,12 @@ QUICPacketHeader::from() const return this->_from; } +bool +QUICPacketHeader::is_crypto_packet() const +{ + return false; +} + uint16_t QUICPacketHeader::packet_size() const { @@ -93,23 +99,23 @@ QUICPacketHeader::load(const IpEndpoint from, ats_unique_buf buf, size_t len, QU QUICPacketHeaderUPtr QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid, - QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, + QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, bool crypto, ats_unique_buf payload, size_t len) { QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); new (long_header) QUICPacketLongHeader(type, key_phase, destination_cid, source_cid, packet_number, base_packet_number, version, - std::move(payload), len); + crypto, std::move(payload), len); return QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); } QUICPacketHeaderUPtr QUICPacketHeader::build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid, - QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, + 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) { QUICPacketLongHeader *long_header = quicPacketLongHeaderAllocator.alloc(); new (long_header) QUICPacketLongHeader(type, key_phase, destination_cid, source_cid, packet_number, base_packet_number, version, - std::move(payload), len, std::move(token), token_len); + crypto, std::move(payload), len, std::move(token), token_len); return QUICPacketHeaderUPtr(long_header, &QUICPacketHeaderDeleter::delete_long_header); } @@ -202,8 +208,8 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, size_t len, - ats_unique_buf token, size_t token_len) + QUICPacketNumber base_packet_number, QUICVersion version, bool crypto, + ats_unique_buf buf, size_t len, ats_unique_buf token, size_t token_len) { this->_type = type; this->_destination_cid = destination_cid; @@ -217,6 +223,7 @@ QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key this->_payload = std::move(buf); this->_payload_length = len; this->_key_phase = key_phase; + this->_is_crypto_packet = crypto; if (this->_type == QUICPacketType::VERSION_NEGOTIATION) { this->_buf_len = @@ -256,6 +263,12 @@ QUICPacketLongHeader::type() const } } +bool +QUICPacketLongHeader::is_crypto_packet() const +{ + return this->_is_crypto_packet; +} + bool QUICPacketLongHeader::type(QUICPacketType &type, const uint8_t *packet, size_t packet_len) { diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 121c94a41f4..79342c07104 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -73,6 +73,8 @@ class QUICPacketHeader ~QUICPacketHeader() {} const uint8_t *buf(); + virtual bool is_crypto_packet() const; + const IpEndpoint &from() const; virtual QUICPacketType type() const = 0; @@ -139,7 +141,8 @@ class QUICPacketHeader */ static QUICPacketHeaderUPtr build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len); + QUICPacketNumber base_packet_number, QUICVersion version, bool crypto, ats_unique_buf payload, + size_t len); /* * Build a QUICPacketHeader @@ -148,8 +151,8 @@ class QUICPacketHeader */ static QUICPacketHeaderUPtr build(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICPacketNumber packet_number, - QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len, - ats_unique_buf token, size_t token_len); + QUICPacketNumber base_packet_number, QUICVersion version, bool crypto, ats_unique_buf payload, + size_t len, ats_unique_buf token, size_t token_len); /* * Build a QUICPacketHeader @@ -208,8 +211,8 @@ class QUICPacketLongHeader : public QUICPacketHeader virtual ~QUICPacketLongHeader(){}; QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base); QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, QUICConnectionId source_cid, - QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf buf, - size_t len, ats_unique_buf token = ats_unique_buf(nullptr), size_t token_len = 0); + 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, QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICConnectionId original_dcid, ats_unique_buf retry_token, size_t retry_token_len); @@ -221,6 +224,7 @@ class QUICPacketLongHeader : public QUICPacketHeader QUICPacketNumber packet_number() const; bool has_version() const; bool is_valid() const; + bool is_crypto_packet() const override; QUICVersion version() const; const uint8_t *payload() const; const uint8_t *token() const; @@ -253,6 +257,7 @@ class QUICPacketLongHeader : public QUICPacketHeader 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; }; class QUICPacketShortHeader : public QUICPacketHeader diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc index c1ada3c1741..1a9cd2c50e1 100644 --- a/iocore/net/quic/QUICPacketFactory.cc +++ b/iocore/net/quic/QUICPacketFactory.cc @@ -182,7 +182,7 @@ QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUIC // 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, std::move(versions), len); + 0x00, 0x00, 0x00, false, std::move(versions), len); return QUICPacketFactory::_create_unprotected_packet(std::move(header)); } @@ -190,14 +190,14 @@ QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUIC 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, std::vector &frames, + bool retransmittable, bool probing, bool crypto, std::vector &frames, ats_unique_buf token, size_t token_len) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); QUICPacketNumber pn = this->_packet_number_generator[index].next(); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, destination_cid, source_cid, pn, base_packet_number, - this->_version, std::move(payload), len, std::move(token), token_len); + this->_version, crypto, std::move(payload), len, std::move(token), token_len); return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); } @@ -217,13 +217,13 @@ QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICCon 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, std::vector &frames) + bool retransmittable, bool probing, bool crypto, std::vector &frames) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::HANDSHAKE); QUICPacketNumber pn = this->_packet_number_generator[index].next(); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::HANDSHAKE, QUICKeyPhase::HANDSHAKE, destination_cid, source_cid, pn, base_packet_number, - this->_version, std::move(payload), len); + this->_version, crypto, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); } @@ -236,7 +236,7 @@ QUICPacketFactory::create_zero_rtt_packet(QUICConnectionId destination_cid, QUIC QUICPacketNumber pn = this->_packet_number_generator[index].next(); QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::ZERO_RTT_PROTECTED, QUICKeyPhase::ZERO_RTT, destination_cid, source_cid, pn, - base_packet_number, this->_version, std::move(payload), len); + base_packet_number, this->_version, false, std::move(payload), len); return this->_create_encrypted_packet(std::move(header), retransmittable, probing, frames); } diff --git a/iocore/net/quic/QUICPacketFactory.h b/iocore/net/quic/QUICPacketFactory.h index b79b93187aa..7641c71b553 100644 --- a/iocore/net/quic/QUICPacketFactory.h +++ b/iocore/net/quic/QUICPacketFactory.h @@ -50,17 +50,17 @@ class QUICPacketFactory QUICPacketUPtr create(IpEndpoint from, 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 retransmittable, bool probing, std::vector &frame, + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool ack_eliciting, + bool probing, bool crypto, std::vector &frame, 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, - bool retransmittable, bool probing, std::vector &frames); + bool ack_eliciting, bool probing, bool crypto, std::vector &frames); QUICPacketUPtr 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, std::vector &frames); + QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool ack_eliciting, + bool probing, std::vector &frames); QUICPacketUPtr create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable, bool probing, + ats_unique_buf payload, size_t len, bool ack_eliciting, bool probing, std::vector &frames); void set_version(QUICVersion negotiated_version); @@ -78,6 +78,6 @@ class QUICPacketFactory QUICPacketNumberGenerator _packet_number_generator[3]; static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeaderUPtr header); - QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing, + QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool ack_eliciting, bool probing, std::vector &frames); }; From 9352e40ca6ddcaac44a6d084398600ddff0ce180 Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 13 Feb 2019 11:16:30 +0800 Subject: [PATCH 1126/1313] QUIC: LossDetector draft-17 --- iocore/net/quic/QUICConfig.cc | 60 +--- iocore/net/quic/QUICConfig.h | 26 +- iocore/net/quic/QUICCongestionController.cc | 8 +- iocore/net/quic/QUICLossDetector.cc | 377 ++++++++------------ iocore/net/quic/QUICLossDetector.h | 75 ++-- iocore/net/quic/QUICPacket.cc | 6 + iocore/net/quic/QUICPacket.h | 1 + 7 files changed, 226 insertions(+), 327 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index bd971526c00..2b2621e40ce 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -172,23 +172,15 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_max_ack_delay_out, "proxy.config.quic.max_ack_delay_out"); // Loss Detection - REC_EstablishStaticConfigInt32U(this->_ld_max_tlps, "proxy.config.quic.loss_detection.max_tlps"); - REC_EstablishStaticConfigInt32U(this->_ld_reordering_threshold, "proxy.config.quic.loss_detection.reordering_threshold"); - REC_EstablishStaticConfigFloat(this->_ld_time_reordering_fraction, "proxy.config.quic.loss_detection.time_reordering_fraction"); - REC_EstablishStaticConfigInt32U(this->_ld_time_loss_detection, "proxy.config.quic.loss_detection.using_time_loss_detection"); + REC_EstablishStaticConfigInt32U(this->_ld_packet_threshold, "proxy.config.quic.loss_detection.packet_threshold"); + REC_EstablishStaticConfigFloat(this->_ld_time_threshold, "proxy.config.quic.loss_detection.time_threshold"); uint32_t timeout = 0; - REC_EstablishStaticConfigInt32U(timeout, "proxy.config.quic.loss_detection.min_tlp_timeout"); - this->_ld_min_tlp_timeout = HRTIME_MSECONDS(timeout); + REC_EstablishStaticConfigInt32U(timeout, "proxy.config.quic.loss_detection.granularity"); + this->_ld_granularity = HRTIME_MSECONDS(timeout); - REC_EstablishStaticConfigInt32U(timeout, "proxy.config.quic.loss_detection.min_rto_timeout"); - this->_ld_min_rto_timeout = HRTIME_MSECONDS(timeout); - - REC_EstablishStaticConfigInt32U(timeout, "proxy.config.quic.loss_detection.delayed_ack_timeout"); - this->_ld_delayed_ack_timeout = HRTIME_MSECONDS(timeout); - - REC_EstablishStaticConfigInt32U(timeout, "proxy.config.quic.loss_detection.default_initial_rtt"); - this->_ld_default_initial_rtt = HRTIME_MSECONDS(timeout); + REC_EstablishStaticConfigInt32U(timeout, "proxy.config.quic.loss_detection.initial_rtt"); + this->_ld_initial_rtt = HRTIME_MSECONDS(timeout); // Congestion Control REC_EstablishStaticConfigInt32U(this->_cc_default_mss, "proxy.config.quic.congestion_control.default_mss"); @@ -379,51 +371,27 @@ QUICConfigParams::client_ssl_ctx() const } uint32_t -QUICConfigParams::ld_max_tlps() const +QUICConfigParams::ld_packet_threshold() const { - return _ld_max_tlps; -} - -uint32_t -QUICConfigParams::ld_reordering_threshold() const -{ - return _ld_reordering_threshold; + return _ld_packet_threshold; } float -QUICConfigParams::ld_time_reordering_fraction() const -{ - return _ld_time_reordering_fraction; -} - -uint32_t -QUICConfigParams::ld_time_loss_detection() const -{ - return _ld_time_loss_detection; -} - -ink_hrtime -QUICConfigParams::ld_min_tlp_timeout() const -{ - return _ld_min_tlp_timeout; -} - -ink_hrtime -QUICConfigParams::ld_min_rto_timeout() const +QUICConfigParams::ld_time_threshold() const { - return _ld_min_rto_timeout; + return _ld_time_threshold; } ink_hrtime -QUICConfigParams::ld_delayed_ack_timeout() const +QUICConfigParams::ld_granularity() const { - return _ld_delayed_ack_timeout; + return _ld_granularity; } ink_hrtime -QUICConfigParams::ld_default_initial_rtt() const +QUICConfigParams::ld_initial_rtt() const { - return _ld_default_initial_rtt; + return _ld_initial_rtt; } uint32_t diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index cd182b2c105..7ba3c3475f3 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -70,14 +70,10 @@ class QUICConfigParams : public ConfigInfo uint8_t max_ack_delay_out() const; // Loss Detection - uint32_t ld_max_tlps() const; - uint32_t ld_reordering_threshold() const; - float ld_time_reordering_fraction() const; - uint32_t ld_time_loss_detection() const; - ink_hrtime ld_min_tlp_timeout() const; - ink_hrtime ld_min_rto_timeout() const; - ink_hrtime ld_delayed_ack_timeout() const; - ink_hrtime ld_default_initial_rtt() const; + uint32_t ld_packet_threshold() const; + float ld_time_threshold() const; + ink_hrtime ld_granularity() const; + ink_hrtime ld_initial_rtt() const; // Congestion Control uint32_t cc_default_mss() const; @@ -129,15 +125,11 @@ class QUICConfigParams : public ConfigInfo uint32_t _max_ack_delay_in = 0; uint32_t _max_ack_delay_out = 0; - // [draft-11 recovery] 3.5.1. Constants of interest - uint32_t _ld_max_tlps = 2; - uint32_t _ld_reordering_threshold = 3; - float _ld_time_reordering_fraction = 0.125; - uint32_t _ld_time_loss_detection = 0; - ink_hrtime _ld_min_tlp_timeout = HRTIME_MSECONDS(10); - ink_hrtime _ld_min_rto_timeout = HRTIME_MSECONDS(200); - ink_hrtime _ld_delayed_ack_timeout = HRTIME_MSECONDS(25); - ink_hrtime _ld_default_initial_rtt = HRTIME_MSECONDS(100); + // [draft-17 recovery] 6.4.1. Constants of interest + uint32_t _ld_packet_threshold = 3; + float _ld_time_threshold = 1.25; + ink_hrtime _ld_granularity = HRTIME_MSECONDS(1); + ink_hrtime _ld_initial_rtt = HRTIME_MSECONDS(100); // [draft-11 recovery] 4.7.1. Constants of interest uint32_t _cc_default_mss = 1460; diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 2cd1ea5f4bb..128639d5266 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -69,18 +69,18 @@ QUICCongestionController::on_packet_acked(const PacketInfo &acked_packet) { // Remove from bytes_in_flight. SCOPED_MUTEX_LOCK(lock, this->_cc_mutex, this_ethread()); - this->_bytes_in_flight -= acked_packet.bytes; + this->_bytes_in_flight -= acked_packet.sent_bytes; if (this->_in_recovery(acked_packet.packet_number)) { // Do not increase congestion window in recovery period. return; } if (this->_congestion_window < this->_ssthresh) { // Slow start. - this->_congestion_window += acked_packet.bytes; + this->_congestion_window += acked_packet.sent_bytes; QUICCCDebug("slow start window chaged"); } else { // Congestion avoidance. - this->_congestion_window += this->_k_default_mss * acked_packet.bytes / this->_congestion_window; + this->_congestion_window += this->_k_default_mss * acked_packet.sent_bytes / this->_congestion_window; QUICCCDebug("Congestion avoidance window changed"); } } @@ -95,7 +95,7 @@ QUICCongestionController::on_packets_lost(const std::map_cc_mutex, this_ethread()); // Remove lost packets from bytes_in_flight. for (auto &lost_packet : lost_packets) { - this->_bytes_in_flight -= lost_packet.second->bytes; + this->_bytes_in_flight -= lost_packet.second->sent_bytes; } QUICPacketNumber largest_lost_packet = lost_packets.rbegin()->first; // Start a new recovery epoch if the lost packet is larger diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 6aba8208e56..b2cfff9af72 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -45,14 +45,10 @@ QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConne this->_loss_detection_mutex = new_ProxyMutex(); QUICConfig::scoped_config params; - this->_k_max_tlps = params->ld_max_tlps(); - this->_k_reordering_threshold = params->ld_reordering_threshold(); - this->_k_time_reordering_fraction = params->ld_time_reordering_fraction(); - this->_k_using_time_loss_detection = params->ld_time_loss_detection(); - this->_k_min_tlp_timeout = params->ld_min_tlp_timeout(); - this->_k_min_rto_timeout = params->ld_min_rto_timeout(); - this->_k_delayed_ack_timeout = params->ld_delayed_ack_timeout(); - this->_k_default_initial_rtt = params->ld_default_initial_rtt(); + this->_k_packet_threshold = params->ld_packet_threshold(); + this->_k_time_threshold = params->ld_time_threshold(); + this->_k_granularity = params->ld_granularity(); + this->_k_initial_rtt = params->ld_initial_rtt(); this->reset(); @@ -61,9 +57,9 @@ QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConne QUICLossDetector::~QUICLossDetector() { - if (this->_loss_detection_alarm) { - this->_loss_detection_alarm->cancel(); - this->_loss_detection_alarm = nullptr; + if (this->_loss_detection_timer) { + this->_loss_detection_timer->cancel(); + this->_loss_detection_timer = nullptr; } this->_sent_packets.clear(); @@ -80,7 +76,7 @@ QUICLossDetector::event_handler(int event, Event *edata) if (this->_loss_detection_alarm_at <= Thread::get_hrtime()) { this->_loss_detection_alarm_at = 0; this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); - this->_on_loss_detection_alarm(); + this->_on_loss_detection_timeout(); } break; } @@ -88,9 +84,9 @@ QUICLossDetector::event_handler(int event, Event *edata) SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); QUICLDDebug("Shutdown"); - if (this->_loss_detection_alarm) { - this->_loss_detection_alarm->cancel(); - this->_loss_detection_alarm = nullptr; + if (this->_loss_detection_timer) { + this->_loss_detection_timer->cancel(); + this->_loss_detection_timer = nullptr; } break; } @@ -136,49 +132,42 @@ QUICLossDetector::largest_acked_packet_number() } void -QUICLossDetector::on_packet_sent(QUICPacketUPtr packet) +QUICLossDetector::on_packet_sent(QUICPacketUPtr packet, bool in_flight) { - bool is_handshake = false; - QUICPacketType type = packet->type(); - - if (type == QUICPacketType::VERSION_NEGOTIATION) { + if (packet->type() == QUICPacketType::VERSION_NEGOTIATION) { return; } - // Is CRYPTO[EOED] on 0-RTT handshake? - if (type == QUICPacketType::INITIAL || type == QUICPacketType::HANDSHAKE) { - is_handshake = true; - } - - QUICPacketNumber packet_number = packet->packet_number(); - bool is_ack_only = !packet->is_ack_eliciting(); - size_t sent_bytes = is_ack_only ? 0 : packet->size(); - this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); - this->_on_packet_sent(packet_number, is_ack_only, is_handshake, sent_bytes, std::move(packet)); + this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); + auto packet_number = packet->packet_number(); + auto ack_eliciting = packet->is_ack_eliciting(); + auto crypto = packet->is_crypto_packet(); + auto sent_bytes = packet->size(); + this->_on_packet_sent(packet_number, ack_eliciting, in_flight, crypto, sent_bytes, std::move(packet)); } void QUICLossDetector::reset() { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - if (this->_loss_detection_alarm) { - this->_loss_detection_alarm->cancel(); - this->_loss_detection_alarm = nullptr; + if (this->_loss_detection_timer) { + this->_loss_detection_timer->cancel(); + this->_loss_detection_timer = nullptr; } this->_sent_packets.clear(); - // [draft-11 recovery] 3.5.3. Initialization - this->_handshake_outstanding = 0; - this->_retransmittable_outstanding = 0; - - if (this->_k_using_time_loss_detection) { - this->_reordering_threshold = UINT32_MAX; - this->_time_reordering_fraction = this->_k_time_reordering_fraction; - } else { - this->_reordering_threshold = this->_k_reordering_threshold; - this->_time_reordering_fraction = INFINITY; - } + // [draft-17 recovery] 6.4.3. Initialization + this->_crypto_count = 0; + this->_pto_count = 0; + this->_loss_time = 0; + this->_smoothed_rtt = 0; + this->_rttvar = 0; + this->_min_rtt = INT64_MAX; + this->_time_of_last_sent_ack_eliciting_packet = 0; + this->_time_of_last_sent_crypto_packet = 0; + this->_largest_sent_packet = 0; + this->_largest_acked_packet = 0; } void @@ -188,30 +177,25 @@ QUICLossDetector::update_ack_delay_exponent(uint8_t ack_delay_exponent) } void -QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes, - QUICPacketUPtr packet) +QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool ack_eliciting, bool in_flight, bool is_crypto_packet, + size_t sent_bytes, QUICPacketUPtr packet) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); ink_hrtime now = Thread::get_hrtime(); this->_largest_sent_packet = packet_number; // FIXME Should we really keep actual packet object? - if (!is_ack_only) { - PacketInfoUPtr packet_info(new PacketInfo({packet_number, now, is_ack_only, is_handshake, sent_bytes, std::move(packet)})); - this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); - - if (is_handshake) { - this->_time_of_last_sent_handshake_packet = now; + PacketInfoUPtr packet_info = PacketInfoUPtr(new PacketInfo( + {packet_number, now, ack_eliciting, is_crypto_packet, in_flight, ack_eliciting ? sent_bytes : 0, std::move(packet)})); + this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); + if (ack_eliciting) { + if (is_crypto_packet) { + this->_time_of_last_sent_crypto_packet = now; } - this->_time_of_last_sent_retransmittable_packet = now; + + this->_time_of_last_sent_ack_eliciting_packet = now; this->_cc->on_packet_sent(sent_bytes); - this->_set_loss_detection_alarm(); - } else { - // -- ADDITIONAL CODE -- - // To simplify code - setting sent_bytes only if the packet is not ack_only. - PacketInfoUPtr packet_info(new PacketInfo({packet_number, now, is_ack_only, is_handshake, 0, std::move(packet)})); - this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); - // -- END OF ADDITIONAL CODE -- + this->_set_loss_detection_timer(); } } @@ -221,55 +205,66 @@ QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame) SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - this->_largest_acked_packet = ack_frame.largest_acknowledged(); - // If the largest acked is newly acked, update the RTT. + this->_largest_acked_packet = std::max(this->_largest_acked_packet, ack_frame.largest_acknowledged()); + // If the largest acknowledged is newly acked and + // ack-eliciting, update the RTT. auto pi = this->_sent_packets.find(ack_frame.largest_acknowledged()); if (pi != this->_sent_packets.end()) { - this->_latest_rtt = Thread::get_hrtime() - pi->second->time; + this->_latest_rtt = Thread::get_hrtime() - pi->second->time_sent; // _latest_rtt is nanosecond but ack_frame.ack_delay is microsecond and scaled ink_hrtime delay = HRTIME_USECONDS(ack_frame.ack_delay() << this->_ack_delay_exponent); - this->_update_rtt(this->_latest_rtt, delay, ack_frame.largest_acknowledged()); + this->_update_rtt(this->_latest_rtt, delay); } QUICLDVDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), - this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); + this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); + + // TODO ECN + // if (ACK frame contains ECN information): + // ProcessECN(ack) // Find all newly acked packets. + bool newly_acked_packets = false; for (auto &&range : this->_determine_newly_acked_packets(ack_frame)) { for (auto ite = this->_sent_packets.begin(); ite != this->_sent_packets.end(); /* no increment here*/) { auto tmp_ite = ite; tmp_ite++; if (range.contains(ite->first)) { + newly_acked_packets = true; this->_on_packet_acked(*(ite->second)); } ite = tmp_ite; } } + if (!newly_acked_packets) { + return; + } + + this->_crypto_count = 0; + this->_pto_count = 0; + QUICLDVDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), - this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); + this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); - this->_detect_lost_packets(ack_frame.largest_acknowledged()); + this->_detect_lost_packets(); QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), - this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); + this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); - this->_set_loss_detection_alarm(); + this->_set_loss_detection_timer(); } void -QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICPacketNumber largest_acked) +QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay) { // min_rtt ignores ack delay. this->_min_rtt = std::min(this->_min_rtt, latest_rtt); + // Limit ack_delay by max_ack_delay + ack_delay = std::min(ack_delay, this->_max_ack_delay); // Adjust for ack delay if it's plausible. if (latest_rtt - this->_min_rtt > ack_delay) { latest_rtt -= ack_delay; - // Only save into max ack delay if it's used for rtt calculation and is not ack only. - auto pi = this->_sent_packets.find(largest_acked); - if (pi != this->_sent_packets.end() && !pi->second->ack_only) { - this->_max_ack_delay = std::max(this->_max_ack_delay, ack_delay); - } } // Based on {{RFC6298}}. if (this->_smoothed_rtt == 0) { @@ -291,19 +286,10 @@ QUICLossDetector::_on_packet_acked(const PacketInfo &acked_packet) SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number); - if (!acked_packet.ack_only) { + if (acked_packet.ack_eliciting) { this->_cc->on_packet_acked(acked_packet); } - // If a packet sent prior to RTO was acked, then the RTO - // was spurious. Otherwise, inform congestion control. - if (this->_rto_count > 0 && acked_packet.packet_number > this->_largest_sent_before_rto) { - this->_cc->on_retransmission_timeout_verified(); - } - this->_handshake_count = 0; - this->_tlp_count = 0; - this->_rto_count = 0; - for (QUICFrameInfo &frame_info : acked_packet.packet->frames()) { auto reactor = frame_info.generated_by(); if (reactor == nullptr) { @@ -317,18 +303,18 @@ QUICLossDetector::_on_packet_acked(const PacketInfo &acked_packet) } void -QUICLossDetector::_set_loss_detection_alarm() +QUICLossDetector::_set_loss_detection_timer() { - ink_hrtime alarm_duration; + ink_hrtime timeout; // Don't arm the alarm if there are no packets with retransmittable data in flight. // -- MODIFIED CODE -- - // In psuedocode, `bytes_in_flight` is used, but we're tracking "retransmittable data in flight" by `_retransmittable_outstanding` - if (this->_retransmittable_outstanding == 0) { - if (this->_loss_detection_alarm) { + // In psuedocode, `bytes_in_flight` is used, but we're tracking "retransmittable data in flight" by `_ack_eliciting_outstanding` + if (this->_ack_eliciting_outstanding == 0) { + if (this->_loss_detection_timer) { this->_loss_detection_alarm_at = 0; - this->_loss_detection_alarm->cancel(); - this->_loss_detection_alarm = nullptr; + this->_loss_detection_timer->cancel(); + this->_loss_detection_timer = nullptr; QUICLDDebug("Loss detection alarm has been unset"); } @@ -336,147 +322,114 @@ QUICLossDetector::_set_loss_detection_alarm() } // -- END OF MODIFIED CODE -- - if (this->_handshake_outstanding) { + if (this->_crypto_outstanding) { // Handshake retransmission alarm. if (this->_smoothed_rtt == 0) { - alarm_duration = 2 * this->_k_default_initial_rtt; + timeout = 2 * this->_k_initial_rtt; } else { - alarm_duration = 2 * this->_smoothed_rtt; + timeout = 2 * this->_smoothed_rtt; } - alarm_duration = std::max(alarm_duration + this->_max_ack_delay, this->_k_min_tlp_timeout); - alarm_duration = alarm_duration * (1 << this->_handshake_count); + timeout = std::max(timeout, this->_k_granularity); + timeout = timeout * (1 << this->_crypto_count); - this->_loss_detection_alarm_at = this->_time_of_last_sent_handshake_packet + alarm_duration; - QUICLDDebug("Handshake retransmission alarm will be set"); + this->_loss_detection_alarm_at = this->_time_of_last_sent_crypto_packet + timeout; + QUICLDDebug("crypto packet alarm will be set: %ld", this->_loss_detection_alarm_at); // -- ADDITIONAL CODE -- // In psudocode returning here, but we don't do for scheduling _loss_detection_alarm event. // -- END OF ADDITIONAL CODE -- } else { if (this->_loss_time != 0) { - // Early retransmit timer or time loss detection. - alarm_duration = this->_loss_time - this->_time_of_last_sent_retransmittable_packet; - QUICLDDebug("Early retransmit timer or time loss detection will be set"); + // Time threshold loss detection. + this->_loss_detection_alarm_at = this->_loss_time; + QUICLDDebug("time threshold loss detection timer: %ld", this->_loss_detection_alarm_at); } else { - // RTO or TLP alarm - alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; - alarm_duration = std::max(alarm_duration, this->_k_min_rto_timeout); - alarm_duration = alarm_duration * (1 << this->_rto_count); - - if (this->_tlp_count < this->_k_max_tlps) { - // Tail Loss Probe - ink_hrtime tlp_alarm_duration = - std::max(static_cast(1.5 * this->_smoothed_rtt + this->_max_ack_delay), this->_k_min_tlp_timeout); - alarm_duration = std::min(tlp_alarm_duration, alarm_duration); - } - QUICLDDebug("RTO or TLP alarm will be set"); - } - - // -- ADDITIONAL CODE -- - // alarm_curation can be negative value because _loss_time is updated in _detect_lost_packets() - // In that case, perhaps we should trigger the alarm immediately. - if (alarm_duration < 0) { - alarm_duration = 1; + // PTO Duration + timeout = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; + timeout = std::max(timeout, this->_k_granularity); + timeout = timeout * (1 << this->_pto_count); + this->_loss_detection_alarm_at = this->_time_of_last_sent_ack_eliciting_packet + timeout; + QUICLDDebug("PTO timeout will be set: %ld", this->_loss_detection_alarm_at); } - // -- END OF ADDITONAL CODE -- - - this->_loss_detection_alarm_at = this->_time_of_last_sent_retransmittable_packet + alarm_duration; - } - QUICLDDebug("Loss detection alarm has been set to %" PRId64 "ms", alarm_duration / HRTIME_MSECOND); + QUICLDDebug("Loss detection alarm has been set to %" PRId64 "ms", timeout / HRTIME_MSECOND); - if (!this->_loss_detection_alarm) { - this->_loss_detection_alarm = eventProcessor.schedule_every(this, HRTIME_MSECONDS(25)); + if (!this->_loss_detection_timer) { + this->_loss_detection_timer = eventProcessor.schedule_every(this, HRTIME_MSECONDS(25)); + } } } void -QUICLossDetector::_on_loss_detection_alarm() +QUICLossDetector::_on_loss_detection_timeout() { - if (this->_handshake_outstanding) { + if (this->_crypto_outstanding) { // Handshake retransmission alarm. - this->_retransmit_all_unacked_handshake_data(); - this->_handshake_count++; + this->_retransmit_all_unacked_crypto_data(); + this->_crypto_count++; } else if (this->_loss_time != 0) { // Early retransmit or Time Loss Detection - this->_detect_lost_packets(this->_largest_acked_packet); - } else if (this->_tlp_count < this->_k_max_tlps) { - // Tail Loss Probe. - QUICLDVDebug("TLP"); - // FIXME TLP causes inifinite loop somehow - // this->_send_one_packet(); - this->_tlp_count++; + this->_detect_lost_packets(); } else { - // RTO. - if (this->_rto_count == 0) { - this->_largest_sent_before_rto = this->_largest_sent_packet; - } - QUICLDVDebug("RTO"); + QUICLDVDebug("PTO"); this->_send_two_packets(); - this->_rto_count++; + this->_pto_count++; } QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), - this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load()); + this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); if (is_debug_tag_set("v_quic_loss_detector")) { for (auto &unacked : this->_sent_packets) { - QUICLDVDebug("#%" PRIu64 " is_handshake=%i is_ack_only=%i size=%zu", unacked.first, unacked.second->handshake, - unacked.second->ack_only, unacked.second->bytes); + QUICLDVDebug("#%" PRIu64 " is_crypto=%i ack_eliciting=%i size=%zu", unacked.first, unacked.second->is_crypto_packet, + unacked.second->ack_eliciting, unacked.second->sent_bytes); } } - this->_set_loss_detection_alarm(); + this->_set_loss_detection_timer(); } void -QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_number) +QUICLossDetector::_detect_lost_packets() { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - this->_loss_time = 0; + this->_loss_time = 0; + ink_hrtime loss_delay = this->_k_time_threshold * std::max(this->_latest_rtt, this->_smoothed_rtt); std::map lost_packets; - double delay_until_lost = INFINITY; - if (this->_k_using_time_loss_detection) { - delay_until_lost = (1 + this->_time_reordering_fraction) * std::max(this->_latest_rtt, this->_smoothed_rtt); - } else if (largest_acked_packet_number == this->_largest_sent_packet) { - // Early retransmit alarm. - delay_until_lost = 5.0 / 4.0 * std::max(this->_latest_rtt, this->_smoothed_rtt); - } + // Packets sent before this time are deemed lost. + ink_hrtime lost_send_time = Thread::get_hrtime() - loss_delay; + + // Packets with packet numbers before this are deemed lost. + QUICPacketNumber lost_pn = this->_largest_acked_packet - this->_k_packet_threshold; - for (auto it = this->_sent_packets.begin(); it != this->_sent_packets.end();) { - if (it->first >= largest_acked_packet_number) { + for (auto it = this->_sent_packets.begin(); it != this->_sent_packets.end(); ++it) { + if (it->first >= this->_largest_acked_packet) { break; } - ink_hrtime time_since_sent = Thread::get_hrtime() - it->second->time; - uint64_t delta = largest_acked_packet_number - it->second->packet_number; - if (time_since_sent > delay_until_lost || delta > this->_reordering_threshold) { - if (time_since_sent > delay_until_lost) { - QUICLDDebug("Lost: time since sent is too long (#%" PRId64 " sent=%" PRId64 ", delay=%lf, fraction=%lf, lrtt=%" PRId64 - ", srtt=%" PRId64 ")", - it->first, time_since_sent, delay_until_lost, this->_time_reordering_fraction, this->_latest_rtt, - this->_smoothed_rtt); + + auto &unacked = it->second; + + // Mark packet as lost, or set time when it should be marked. + if (unacked->time_sent < lost_send_time || unacked->packet_number < lost_pn) { + if (unacked->time_sent < lost_send_time) { + QUICLDDebug("Lost: time since sent is too long (#%" PRId64 " sent=%" PRId64 ", delay=%" PRId64 + ", fraction=%lf, lrtt=%" PRId64 ", srtt=%" PRId64 ")", + it->first, unacked->time_sent, lost_send_time, this->_k_time_threshold, this->_latest_rtt, this->_smoothed_rtt); } else { QUICLDDebug("Lost: packet delta is too large (#%" PRId64 " largest=%" PRId64 " threshold=%" PRId32 ")", it->first, - largest_acked_packet_number, this->_reordering_threshold); + this->_largest_acked_packet, this->_k_packet_threshold); } - if (!it->second->ack_only) { + if (unacked->in_flight) { lost_packets.insert({it->first, it->second.get()}); + } else if (this->_loss_time == 0) { + this->_loss_time = unacked->time_sent + loss_delay; } else { - // -- ADDITIONAL CODE -- - // We remove only "ack-only" packets for life time management of packets. - // Packets in lost_packets will be removed from sent_packet later. - it = this->_remove_from_sent_packet_list(it); - continue; - // -- END OF ADDITIONAL CODE -- + this->_loss_time = std::min(this->_loss_time, unacked->time_sent + loss_delay); } - } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) { - this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent; } - - ++it; } // Inform the congestion controller of lost packets and @@ -500,50 +453,33 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_num // ===== Functions below are used on the spec but there're no pseudo code ===== void -QUICLossDetector::_retransmit_all_unacked_handshake_data() +QUICLossDetector::_retransmit_all_unacked_crypto_data() { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - std::set retransmitted_handshake_packets; + std::set retransmitted_crypto_packets; std::map lost_packets; for (auto &info : this->_sent_packets) { - retransmitted_handshake_packets.insert(info.first); - lost_packets.insert({info.first, info.second.get()}); - this->_transmitter->retransmit_packet(*info.second->packet); + if (info.second->is_crypto_packet) { + retransmitted_crypto_packets.insert(info.first); + this->_retransmit_lost_packet(info.second->packet); + lost_packets.insert({info.first, info.second.get()}); + } } this->_cc->on_packets_lost(lost_packets); - for (auto packet_number : retransmitted_handshake_packets) { + for (auto packet_number : retransmitted_crypto_packets) { this->_remove_from_sent_packet_list(packet_number); } } -void -QUICLossDetector::_send_one_packet() -{ - SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); - SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - - auto ite = this->_sent_packets.rbegin(); - if (ite != this->_sent_packets.rend()) { - this->_transmitter->retransmit_packet(*ite->second->packet); - } -} - void QUICLossDetector::_send_two_packets() { SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - auto ite = this->_sent_packets.rbegin(); - if (ite != this->_sent_packets.rend()) { - this->_transmitter->retransmit_packet(*ite->second->packet); - ite++; - if (ite != this->_sent_packets.rend()) { - this->_transmitter->retransmit_packet(*ite->second->packet); - } - } + // TODO sent ping } // ===== Functions below are helper functions ===== @@ -562,7 +498,6 @@ QUICLossDetector::_retransmit_lost_packet(QUICPacketUPtr &packet) reactor->on_frame_lost(frame_info.id()); } - this->_transmitter->retransmit_packet(*packet); } std::set @@ -592,13 +527,13 @@ QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, Packe // Increment counters auto ite = this->_sent_packets.find(packet_number); if (ite != this->_sent_packets.end()) { - if (ite->second->handshake) { - ++this->_handshake_outstanding; - ink_assert(this->_handshake_outstanding.load() > 0); + if (ite->second->is_crypto_packet) { + ++this->_crypto_outstanding; + ink_assert(this->_crypto_outstanding.load() > 0); } - if (!ite->second->ack_only) { - ++this->_retransmittable_outstanding; - ink_assert(this->_retransmittable_outstanding.load() > 0); + if (!ite->second->ack_eliciting) { + ++this->_ack_eliciting_outstanding; + ink_assert(this->_ack_eliciting_outstanding.load() > 0); } } } @@ -627,13 +562,13 @@ QUICLossDetector::_decrement_outstanding_counters(std::map_sent_packets.end()) { // Decrement counters - if (it->second->handshake) { - ink_assert(this->_handshake_outstanding.load() > 0); - --this->_handshake_outstanding; + if (it->second->is_crypto_packet) { + ink_assert(this->_crypto_outstanding.load() > 0); + --this->_crypto_outstanding; } - if (!it->second->ack_only) { - ink_assert(this->_retransmittable_outstanding.load() > 0); - --this->_retransmittable_outstanding; + if (!it->second->ack_eliciting) { + ink_assert(this->_ack_eliciting_outstanding.load() > 0); + --this->_ack_eliciting_outstanding; } } } @@ -643,8 +578,8 @@ QUICLossDetector::current_rto_period() { ink_hrtime alarm_duration; alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; - alarm_duration = std::max(alarm_duration, this->_k_min_rto_timeout); - alarm_duration = alarm_duration * (1 << this->_rto_count); + alarm_duration = std::max(alarm_duration, this->_k_granularity); + alarm_duration = alarm_duration * (1 << this->_pto_count); return alarm_duration; } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index c04c12f7946..cc3dee306f9 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -41,12 +41,17 @@ class QUICLossDetector; struct PacketInfo { + // 6.3.1. Sent Packet Fields QUICPacketNumber packet_number; - ink_hrtime time; - bool ack_only; - bool handshake; - size_t bytes; + ink_hrtime time_sent; + bool ack_eliciting; + bool is_crypto_packet; + bool in_flight; + size_t sent_bytes; + + // addition QUICPacketUPtr packet; + // end }; using PacketInfoUPtr = std::unique_ptr; @@ -117,7 +122,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler std::vector interests() override; virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; - void on_packet_sent(QUICPacketUPtr packet); + void on_packet_sent(QUICPacketUPtr packet, bool in_flight = true); QUICPacketNumber largest_acked_packet_number(); void update_ack_delay_exponent(uint8_t ack_delay_exponent); void reset(); @@ -128,42 +133,34 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler uint8_t _ack_delay_exponent = 3; - // [draft-11 recovery] 3.5.1. Constants of interest + // [draft-17 recovery] 6.4.1. Constants of interest // Values will be loaded from records.config via QUICConfig at constructor - uint32_t _k_max_tlps = 0; - uint32_t _k_reordering_threshold = 0; - float _k_time_reordering_fraction = 0.0; - bool _k_using_time_loss_detection = false; - ink_hrtime _k_min_tlp_timeout = 0; - ink_hrtime _k_min_rto_timeout = 0; - ink_hrtime _k_delayed_ack_timeout = 0; - ink_hrtime _k_default_initial_rtt = 0; + uint32_t _k_packet_threshold = 0; + float _k_time_threshold = 0.0; + ink_hrtime _k_granularity = 0; + ink_hrtime _k_initial_rtt = 0; // [draft-11 recovery] 3.5.2. Variables of interest // Keep the order as the same as the spec so that we can see the difference easily. - Action *_loss_detection_alarm = nullptr; - uint32_t _handshake_count = 0; - uint32_t _tlp_count = 0; - uint32_t _rto_count = 0; - uint32_t _largest_sent_before_rto = 0; - ink_hrtime _time_of_last_sent_retransmittable_packet = 0; - ink_hrtime _time_of_last_sent_handshake_packet = 0; - uint32_t _largest_sent_packet = 0; - uint32_t _largest_acked_packet = 0; - ink_hrtime _latest_rtt = 0; - ink_hrtime _smoothed_rtt = 0; - ink_hrtime _rttvar = 0; - ink_hrtime _min_rtt = INT64_MAX; - ink_hrtime _max_ack_delay = 0; - uint32_t _reordering_threshold = 0; - double _time_reordering_fraction = 0.0; - ink_hrtime _loss_time = 0; + Action *_loss_detection_timer = nullptr; + uint32_t _crypto_count = 0; + uint32_t _pto_count = 0; + ink_hrtime _time_of_last_sent_ack_eliciting_packet = 0; + ink_hrtime _time_of_last_sent_crypto_packet = 0; + QUICPacketNumber _largest_sent_packet = 0; + QUICPacketNumber _largest_acked_packet = 0; + ink_hrtime _latest_rtt = 0; + ink_hrtime _smoothed_rtt = 0; + ink_hrtime _rttvar = 0; + ink_hrtime _min_rtt = INT64_MAX; + ink_hrtime _max_ack_delay = 0; + ink_hrtime _loss_time = 0; std::map _sent_packets; // These are not defined on the spec but expected to be count // These counter have to be updated when inserting / erasing packets from _sent_packets with following functions. - std::atomic _handshake_outstanding; - std::atomic _retransmittable_outstanding; + std::atomic _crypto_outstanding; + std::atomic _ack_eliciting_outstanding; void _add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr packet_info); void _remove_from_sent_packet_list(QUICPacketNumber packet_number); std::map::iterator _remove_from_sent_packet_list( @@ -176,19 +173,19 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler */ ink_hrtime _loss_detection_alarm_at = 0; - void _on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes, + void _on_packet_sent(QUICPacketNumber packet_number, bool ack_eliciting, bool in_flight, bool is_crypto_packet, size_t sent_bytes, QUICPacketUPtr packet); void _on_ack_received(const QUICAckFrame &ack_frame); void _on_packet_acked(const PacketInfo &acked_packet); - void _update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICPacketNumber largest_acked); - void _detect_lost_packets(QUICPacketNumber largest_acked); - void _set_loss_detection_alarm(); - void _on_loss_detection_alarm(); + void _update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay); + void _detect_lost_packets(); + void _set_loss_detection_timer(); + void _on_loss_detection_timeout(); void _retransmit_lost_packet(QUICPacketUPtr &packet); std::set _determine_newly_acked_packets(const QUICAckFrame &ack_frame); - void _retransmit_all_unacked_handshake_data(); + void _retransmit_all_unacked_crypto_data(); void _send_one_packet(); void _send_two_packets(); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 9ed9afb29e8..c5e640aeae5 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -870,6 +870,12 @@ QUICPacket::packet_number() const return this->_header->packet_number(); } +bool +QUICPacket::is_crypto_packet() const +{ + return this->_header->is_crypto_packet(); +} + const QUICPacketHeader & QUICPacket::header() const { diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 79342c07104..0a81b99d23c 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -359,6 +359,7 @@ class QUICPacket : public QUICTrackablePacket const QUICPacketHeader &header() const; const uint8_t *payload() const; bool is_ack_eliciting() const; + bool is_crypto_packet() const; bool is_probing_packet() const; /* From 9979ff48bf86207c908ccdefa8b8bb0ca2c302c3 Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 13 Feb 2019 12:36:36 +0800 Subject: [PATCH 1127/1313] QUIC: Send Ping frame correctly --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 10 +++------- iocore/net/quic/QUICPinger.cc | 11 +++++++++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index c3d12b3e434..e20da7f746e 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -380,7 +380,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub uint64_t _stream_frames_sent = 0; // TODO: Source addresses verification through an address validation token - bool _has_ack_only_packet_out = false; + bool _has_ack_eliciting_packet_out = true; QUICAddrVerifyState _verfied_state; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 4c57a26ed78..b2f1b6f7736 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1362,7 +1362,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); std::vector frames; - if (this->_has_ack_only_packet_out) { + if (!this->_has_ack_eliciting_packet_out) { // Sent too much ack_only packet. At this moment we need to packetize a ping frame // to force peer send ack frame. this->_pinger.request(level); @@ -1419,11 +1419,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } } } - if (frame_count == 0) { - ack_eliciting = false; - } - - this->_has_ack_only_packet_out = !ack_eliciting; // Schedule a packet if (len != 0) { @@ -1450,7 +1445,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } // Packet is retransmittable if it's not ack only packet - packet = this->_build_packet(level, std::move(buf), len, ack_eliciting, probing, crypto, frames); + packet = this->_build_packet(level, std::move(buf), len, ack_eliciting, probing, crypto, frames); + this->_has_ack_eliciting_packet_out = ack_eliciting; } return packet; diff --git a/iocore/net/quic/QUICPinger.cc b/iocore/net/quic/QUICPinger.cc index f7e1977bac2..f2e40a577ac 100644 --- a/iocore/net/quic/QUICPinger.cc +++ b/iocore/net/quic/QUICPinger.cc @@ -26,12 +26,19 @@ void QUICPinger::request(QUICEncryptionLevel level) { + if (!this->_is_level_matched(level)) { + return; + } ++this->_need_to_fire[static_cast(level)]; } void QUICPinger::cancel(QUICEncryptionLevel level) { + if (!this->_is_level_matched(level)) { + return; + } + if (this->_need_to_fire[static_cast(level)] > 0) { --this->_need_to_fire[static_cast(level)]; } @@ -40,6 +47,10 @@ QUICPinger::cancel(QUICEncryptionLevel level) bool QUICPinger::will_generate_frame(QUICEncryptionLevel level) { + if (!this->_is_level_matched(level)) { + return false; + } + return this->_need_to_fire[QUICTypeUtil::pn_space_index(level)] > 0; } From cdf771bd0c9d526322fe35ce1c7a8b88c512bc39 Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 13 Feb 2019 15:27:29 +0800 Subject: [PATCH 1128/1313] QUIC: Remove unneccessary log with unvverified path --- iocore/net/QUICNetVConnection.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b2f1b6f7736..28d784c317d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1246,9 +1246,7 @@ QUICNetVConnection::_state_common_send_packet() uint32_t max_packet_size = udp_payload_len - written; if (this->netvc_context == NET_VCONNECTION_IN && !this->_verfied_state.is_verified()) { - uint32_t windows = this->_verfied_state.windows(); - QUICConDebug("send to unverified window: %u", windows); - max_packet_size = std::min(max_packet_size, windows); + max_packet_size = std::min(max_packet_size, this->_verfied_state.windows()); } QUICPacketUPtr packet = this->_packetize_frames(level, max_packet_size); @@ -1260,6 +1258,7 @@ QUICNetVConnection::_state_common_send_packet() } 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()); } From fe61dc5e73bbf8a55b4c0e41b090a5a806657ace Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 14 Feb 2019 12:38:07 +0800 Subject: [PATCH 1129/1313] QUIC: Adds draft-17 congestion controller --- iocore/net/quic/QUICConfig.cc | 18 +++-- iocore/net/quic/QUICConfig.h | 12 ++-- iocore/net/quic/QUICCongestionController.cc | 76 +++++++++++++-------- iocore/net/quic/QUICLossDetector.cc | 4 +- iocore/net/quic/QUICLossDetector.h | 31 +++++---- 5 files changed, 88 insertions(+), 53 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 2b2621e40ce..0c3dfffd96b 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -183,10 +183,12 @@ QUICConfigParams::initialize() this->_ld_initial_rtt = HRTIME_MSECONDS(timeout); // Congestion Control - REC_EstablishStaticConfigInt32U(this->_cc_default_mss, "proxy.config.quic.congestion_control.default_mss"); + REC_EstablishStaticConfigInt32U(this->_cc_max_datagram_size, "proxy.config.quic.congestion_control.max_datagram_size"); REC_EstablishStaticConfigInt32U(this->_cc_initial_window_scale, "proxy.config.quic.congestion_control.initial_window_scale"); REC_EstablishStaticConfigInt32U(this->_cc_minimum_window_scale, "proxy.config.quic.congestion_control.minimum_window_scale"); REC_EstablishStaticConfigFloat(this->_cc_loss_reduction_factor, "proxy.config.quic.congestion_control.loss_reduction_factor"); + REC_EstablishStaticConfigInt32U(this->_cc_persistent_congestion_threshold, + "proxy.config.quic.congestion_control.persistent_congestion_threshold"); this->_server_ssl_ctx = quic_init_server_ssl_ctx(this); this->_client_ssl_ctx = quic_init_client_ssl_ctx(this); @@ -395,21 +397,21 @@ QUICConfigParams::ld_initial_rtt() const } uint32_t -QUICConfigParams::cc_default_mss() const +QUICConfigParams::cc_max_datagram_size() const { - return _cc_default_mss; + return _cc_max_datagram_size; } uint32_t QUICConfigParams::cc_initial_window() const { - return _cc_initial_window_scale * _cc_default_mss; + return _cc_initial_window_scale * _cc_max_datagram_size; } uint32_t QUICConfigParams::cc_minimum_window() const { - return _cc_minimum_window_scale * _cc_default_mss; + return _cc_minimum_window_scale * _cc_max_datagram_size; } float @@ -418,6 +420,12 @@ QUICConfigParams::cc_loss_reduction_factor() const return _cc_loss_reduction_factor; } +uint32_t +QUICConfigParams::cc_persistent_congestion_threshold() const +{ + return _cc_persistent_congestion_threshold; +} + uint8_t QUICConfigParams::scid_len() { diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 7ba3c3475f3..306f544e9ef 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -76,10 +76,11 @@ class QUICConfigParams : public ConfigInfo ink_hrtime ld_initial_rtt() const; // Congestion Control - uint32_t cc_default_mss() const; + uint32_t cc_max_datagram_size() const; uint32_t cc_initial_window() const; uint32_t cc_minimum_window() const; float cc_loss_reduction_factor() const; + uint32_t cc_persistent_congestion_threshold() const; static int connection_table_size(); static uint8_t scid_len(); @@ -132,10 +133,11 @@ class QUICConfigParams : public ConfigInfo ink_hrtime _ld_initial_rtt = HRTIME_MSECONDS(100); // [draft-11 recovery] 4.7.1. Constants of interest - uint32_t _cc_default_mss = 1460; - uint32_t _cc_initial_window_scale = 10; // Actual initial window size is this value multiplied by the _cc_default_mss - uint32_t _cc_minimum_window_scale = 2; // Actual minimum window size is this value multiplied by the _cc_default_mss - float _cc_loss_reduction_factor = 0.5; + uint32_t _cc_max_datagram_size = 1200; + uint32_t _cc_initial_window_scale = 10; // Actual initial window size is this value multiplied by the _cc_default_mss + uint32_t _cc_minimum_window_scale = 2; // Actual minimum window size is this value multiplied by the _cc_default_mss + float _cc_loss_reduction_factor = 0.5; + uint32_t _cc_persistent_congestion_threshold = 2; }; class QUICConfig diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 128639d5266..905bb5a2bd2 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -43,10 +43,11 @@ QUICCongestionController::QUICCongestionController(QUICConnectionInfoProvider *i this->_cc_mutex = new_ProxyMutex(); QUICConfig::scoped_config params; - this->_k_default_mss = params->cc_default_mss(); - this->_k_initial_window = params->cc_initial_window(); - this->_k_minimum_window = params->cc_minimum_window(); - this->_k_loss_reduction_factor = params->cc_loss_reduction_factor(); + this->_k_max_datagram_size = params->cc_max_datagram_size(); + this->_k_initial_window = params->cc_initial_window(); + this->_k_minimum_window = params->cc_minimum_window(); + this->_k_loss_reduction_factor = params->cc_loss_reduction_factor(); + this->_k_persistent_congestion_threshold = params->cc_persistent_congestion_threshold(); this->reset(); } @@ -59,9 +60,9 @@ QUICCongestionController::on_packet_sent(size_t bytes_sent) } bool -QUICCongestionController::_in_recovery(QUICPacketNumber packet_number) +QUICCongestionController::_in_recovery(ink_hrtime sent_time) { - return packet_number <= this->_end_of_recovery; + return sent_time <= this->_recovery_start_time; } void @@ -70,7 +71,7 @@ QUICCongestionController::on_packet_acked(const PacketInfo &acked_packet) // Remove from bytes_in_flight. SCOPED_MUTEX_LOCK(lock, this->_cc_mutex, this_ethread()); this->_bytes_in_flight -= acked_packet.sent_bytes; - if (this->_in_recovery(acked_packet.packet_number)) { + if (this->_in_recovery(acked_packet.time_sent)) { // Do not increase congestion window in recovery period. return; } @@ -80,13 +81,44 @@ QUICCongestionController::on_packet_acked(const PacketInfo &acked_packet) QUICCCDebug("slow start window chaged"); } else { // Congestion avoidance. - this->_congestion_window += this->_k_default_mss * acked_packet.sent_bytes / this->_congestion_window; + this->_congestion_window += this->_k_max_datagram_size * acked_packet.sent_bytes / this->_congestion_window; QUICCCDebug("Congestion avoidance window changed"); } } void -QUICCongestionController::on_packets_lost(const std::map &lost_packets) +QUICCongestionController::_congestion_event(ink_hrtime sent_time, uint32_t pto_count) +{ + // Start a new congestion event if the sent time is larger + // than the start time of the previous recovery epoch. + if (!this->_in_recovery(sent_time)) { + this->_recovery_start_time = Thread::get_hrtime(); + 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; + if (pto_count > this->_k_persistent_congestion_threshold) { + this->_congestion_window = this->_k_minimum_window; + } + } +} + +void +QUICCongestionController::process_ecn(const PacketInfo &acked_largest_packet, QUICAckFrame::EcnSection *ecn_section, + uint32_t pto_count) +{ + // If the ECN-CE counter reported by the peer has increased, + // this could be a new congestion event. + if (ecn_section->ecn_ce_count() > this->_ecn_ce_counter) { + this->_ecn_ce_counter = ecn_section->ecn_ce_count(); + // Start a new congestion event if the last acknowledged + // packet was sent after the start of the previous + // recovery epoch. + this->_congestion_event(acked_largest_packet.time_sent, pto_count); + } +} + +void +QUICCongestionController::on_packets_lost(const std::map &lost_packets, uint32_t pto_count) { if (lost_packets.empty()) { return; @@ -97,22 +129,10 @@ QUICCongestionController::on_packets_lost(const std::map_bytes_in_flight -= lost_packet.second->sent_bytes; } - QUICPacketNumber largest_lost_packet = lost_packets.rbegin()->first; + auto &largest_lost_packet = lost_packets.rbegin()->second; // Start a new recovery epoch if the lost packet is larger // than the end of the previous recovery epoch. - if (!this->_in_recovery(largest_lost_packet)) { - this->_end_of_recovery = largest_lost_packet; - 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; - QUICCCDebug("packet lost, window changed"); - } -} - -void -QUICCongestionController::on_retransmission_timeout_verified() -{ - this->_congestion_window = this->_k_minimum_window; + this->_congestion_event(largest_lost_packet->time_sent, pto_count); } bool @@ -153,14 +173,14 @@ QUICCongestionController::current_ssthresh() const return this->_ssthresh; } -// [draft-11 recovery] 4.7.3. Initialization +// [draft-17 recovery] 7.9.3. Initialization void QUICCongestionController::reset() { SCOPED_MUTEX_LOCK(lock, this->_cc_mutex, this_ethread()); - this->_bytes_in_flight = 0; - this->_congestion_window = this->_k_initial_window; - this->_end_of_recovery = 0; - this->_ssthresh = UINT32_MAX; + this->_bytes_in_flight = 0; + this->_congestion_window = this->_k_initial_window; + this->_recovery_start_time = 0; + this->_ssthresh = UINT32_MAX; } diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index b2cfff9af72..461e8e89f98 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -435,7 +435,7 @@ QUICLossDetector::_detect_lost_packets() // Inform the congestion controller of lost packets and // lets it decide whether to retransmit immediately. if (!lost_packets.empty()) { - this->_cc->on_packets_lost(lost_packets); + this->_cc->on_packets_lost(lost_packets, this->_pto_count); for (auto lost_packet : lost_packets) { // -- 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 @@ -468,7 +468,7 @@ QUICLossDetector::_retransmit_all_unacked_crypto_data() } } - this->_cc->on_packets_lost(lost_packets); + this->_cc->on_packets_lost(lost_packets, this->_pto_count); for (auto packet_number : retransmitted_crypto_packets) { this->_remove_from_sent_packet_list(packet_number); } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index cc3dee306f9..cb02842226d 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -79,8 +79,9 @@ class QUICCongestionController virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); void on_packet_acked(const PacketInfo &acked_packet); - virtual void on_packets_lost(const std::map &packets); + virtual void on_packets_lost(const std::map &packets, uint32_t pto_count); void on_retransmission_timeout_verified(); + void process_ecn(const PacketInfo &acked_largest_packet, QUICAckFrame::EcnSection *ecn_section, uint32_t pto_count); bool check_credit() const; uint32_t open_window() const; void reset(); @@ -93,22 +94,26 @@ class QUICCongestionController private: Ptr _cc_mutex; - // [draft-11 recovery] 4.7.1. Constants of interest - // Values will be loaded from records.config via QUICConfig at constructor - uint32_t _k_default_mss = 0; - uint32_t _k_initial_window = 0; - uint32_t _k_minimum_window = 0; - float _k_loss_reduction_factor = 0.0; + void _congestion_event(ink_hrtime sent_time, uint32_t pto_count); - // [draft-11 recovery] 4.7.2. Variables of interest - uint32_t _bytes_in_flight = 0; - uint32_t _congestion_window = 0; - QUICPacketNumber _end_of_recovery = 0; - uint32_t _ssthresh = UINT32_MAX; + // [draft-17 recovery] 7.9.1. Constants of interest + // Values will be loaded from records.config via QUICConfig at constructor + uint32_t _k_max_datagram_size = 0; + uint32_t _k_initial_window = 0; + uint32_t _k_minimum_window = 0; + float _k_loss_reduction_factor = 0.0; + uint32_t _k_persistent_congestion_threshold = 0; + + // [draft-17 recovery] 7.9.2. Variables of interest + uint32_t _ecn_ce_counter = 0; + uint32_t _bytes_in_flight = 0; + uint32_t _congestion_window = 0; + ink_hrtime _recovery_start_time = 0; + uint32_t _ssthresh = UINT32_MAX; QUICConnectionInfoProvider *_info = nullptr; - bool _in_recovery(QUICPacketNumber packet_number); + bool _in_recovery(ink_hrtime sent_time); }; class QUICLossDetector : public Continuation, public QUICFrameHandler From 93b24bbf2c67f07bd7089fd28ecfb65dc4135655 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 14 Feb 2019 12:58:02 +0800 Subject: [PATCH 1130/1313] QUIC: process ecn section --- iocore/net/quic/QUICCongestionController.cc | 2 +- iocore/net/quic/QUICLossDetector.cc | 3 +++ iocore/net/quic/QUICLossDetector.h | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 905bb5a2bd2..2aba4c2c727 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -103,7 +103,7 @@ QUICCongestionController::_congestion_event(ink_hrtime sent_time, uint32_t pto_c } void -QUICCongestionController::process_ecn(const PacketInfo &acked_largest_packet, QUICAckFrame::EcnSection *ecn_section, +QUICCongestionController::process_ecn(const PacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section, uint32_t pto_count) { // If the ECN-CE counter reported by the peer has increased, diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 461e8e89f98..91eacfccb04 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -222,6 +222,9 @@ QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame) // TODO ECN // if (ACK frame contains ECN information): // ProcessECN(ack) + if (ack_frame.ecn_section() != nullptr && pi != this->_sent_packets.end()) { + this->_cc->process_ecn(*pi->second, ack_frame.ecn_section(), this->_pto_count); + } // Find all newly acked packets. bool newly_acked_packets = false; diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index cb02842226d..42a2102e229 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -81,7 +81,7 @@ class QUICCongestionController void on_packet_acked(const PacketInfo &acked_packet); virtual void on_packets_lost(const std::map &packets, uint32_t pto_count); void on_retransmission_timeout_verified(); - void process_ecn(const PacketInfo &acked_largest_packet, QUICAckFrame::EcnSection *ecn_section, uint32_t pto_count); + void process_ecn(const PacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section, uint32_t pto_count); bool check_credit() const; uint32_t open_window() const; void reset(); From 732c2b4d93d066426b892fda1c724934666f01fc Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 14 Feb 2019 13:30:43 +0800 Subject: [PATCH 1131/1313] QUIC: Fixed Initial const vars --- iocore/net/quic/QUICConfig.cc | 20 +++++++++++++------- mgmt/RecordsConfig.cc | 21 ++++++++------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 0c3dfffd96b..75d02c42780 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -183,12 +183,13 @@ QUICConfigParams::initialize() this->_ld_initial_rtt = HRTIME_MSECONDS(timeout); // Congestion Control - REC_EstablishStaticConfigInt32U(this->_cc_max_datagram_size, "proxy.config.quic.congestion_control.max_datagram_size"); - REC_EstablishStaticConfigInt32U(this->_cc_initial_window_scale, "proxy.config.quic.congestion_control.initial_window_scale"); - REC_EstablishStaticConfigInt32U(this->_cc_minimum_window_scale, "proxy.config.quic.congestion_control.minimum_window_scale"); - REC_EstablishStaticConfigFloat(this->_cc_loss_reduction_factor, "proxy.config.quic.congestion_control.loss_reduction_factor"); - REC_EstablishStaticConfigInt32U(this->_cc_persistent_congestion_threshold, - "proxy.config.quic.congestion_control.persistent_congestion_threshold"); + // REC_EstablishStaticConfigInt32U(this->_cc_max_datagram_size, "proxy.config.quic.congestion_control.max_datagram_size"); + // REC_EstablishStaticConfigInt32U(this->_cc_initial_window_scale, "proxy.config.quic.congestion_control.initial_window_scale"); + // REC_EstablishStaticConfigInt32U(this->_cc_minimum_window_scale, "proxy.config.quic.congestion_control.minimum_window_scale"); + // REC_EstablishStaticConfigFloat(this->_cc_loss_reduction_factor, + // "proxy.config.quic.congestion_control.loss_reduction_factor"); + // REC_EstablishStaticConfigInt32U(this->_cc_persistent_congestion_threshold, + // "proxy.config.quic.congestion_control.persistent_congestion_threshold"); this->_server_ssl_ctx = quic_init_server_ssl_ctx(this); this->_client_ssl_ctx = quic_init_client_ssl_ctx(this); @@ -405,7 +406,12 @@ QUICConfigParams::cc_max_datagram_size() const uint32_t QUICConfigParams::cc_initial_window() const { - return _cc_initial_window_scale * _cc_max_datagram_size; + // kInitialWindow: Default limit on the initial amount of data in + // flight, in bytes. Taken from [RFC6928]. The RECOMMENDED value is + // the minimum of 10 * kMaxDatagramSize and max(2* kMaxDatagramSize, + // 14600)). + return std::min(_cc_initial_window_scale * _cc_max_datagram_size, + std::max(2 * _cc_max_datagram_size, static_cast(14600))); } uint32_t diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 8e0cdce53e7..150ba24eb9f 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1410,24 +1410,17 @@ static const RecordElement RecordsConfig[] = {RECT_CONFIG, "proxy.config.quic.max_ack_delay_out", RECD_INT, "25", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , // Constants of Loss Detection - {RECT_CONFIG, "proxy.config.quic.loss_detection.max_tlps", RECD_INT, "2", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.loss_detection.packet_threshold", RECD_INT, "3", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.loss_detection.reordering_threshold", RECD_INT, "3", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.loss_detection.time_threshold", RECD_FLOAT, "1.25", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.loss_detection.time_reordering_fraction", RECD_FLOAT, "0.125", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[\\.0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.loss_detection.granularity", RECD_INT, "1", RECU_DYNAMIC, RR_NULL, RECC_STR, "[0-1]", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.loss_detection.using_time_loss_detection", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "[0-1]", RECA_NULL} - , - {RECT_CONFIG, "proxy.config.quic.loss_detection.min_tlp_timeout", RECD_INT, "10", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} - , - {RECT_CONFIG, "proxy.config.quic.loss_detection.min_rto_timeout", RECD_INT, "200", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} - , - {RECT_CONFIG, "proxy.config.quic.loss_detection.delayed_ack_timeout", RECD_INT, "25", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} - , - {RECT_CONFIG, "proxy.config.quic.loss_detection.default_initial_rtt", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.loss_detection.initial_rtt", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , + // Constatns of Congestion Control - {RECT_CONFIG, "proxy.config.quic.congestion_control.default_mss", RECD_INT, "1460", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.congestion_control.max_datagram_size", RECD_INT, "1200", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.congestion_control.initial_window_scale", RECD_INT, "10", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , @@ -1435,6 +1428,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.congestion_control.loss_reduction_factor", RECD_FLOAT, "0.5", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[\\.0-9]+$", RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.congestion_control.persistent_congestion_threshold", RECD_INT, "2", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[\\.0-9]+$", RECA_NULL} + , //# Add LOCAL Records Here {RECT_LOCAL, "proxy.local.incoming_ip_to_bind", RECD_STRING, nullptr, RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL} From 3d3cde2d96fc68ae9f15d72f93e95b4e52ea4852 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 14 Feb 2019 13:34:53 +0800 Subject: [PATCH 1132/1313] QUIC: uncomment the congestion controller config --- iocore/net/quic/QUICConfig.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 75d02c42780..f7e15549eb8 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -183,13 +183,12 @@ QUICConfigParams::initialize() this->_ld_initial_rtt = HRTIME_MSECONDS(timeout); // Congestion Control - // REC_EstablishStaticConfigInt32U(this->_cc_max_datagram_size, "proxy.config.quic.congestion_control.max_datagram_size"); - // REC_EstablishStaticConfigInt32U(this->_cc_initial_window_scale, "proxy.config.quic.congestion_control.initial_window_scale"); - // REC_EstablishStaticConfigInt32U(this->_cc_minimum_window_scale, "proxy.config.quic.congestion_control.minimum_window_scale"); - // REC_EstablishStaticConfigFloat(this->_cc_loss_reduction_factor, - // "proxy.config.quic.congestion_control.loss_reduction_factor"); - // REC_EstablishStaticConfigInt32U(this->_cc_persistent_congestion_threshold, - // "proxy.config.quic.congestion_control.persistent_congestion_threshold"); + REC_EstablishStaticConfigInt32U(this->_cc_max_datagram_size, "proxy.config.quic.congestion_control.max_datagram_size"); + REC_EstablishStaticConfigInt32U(this->_cc_initial_window_scale, "proxy.config.quic.congestion_control.initial_window_scale"); + REC_EstablishStaticConfigInt32U(this->_cc_minimum_window_scale, "proxy.config.quic.congestion_control.minimum_window_scale"); + REC_EstablishStaticConfigFloat(this->_cc_loss_reduction_factor, "proxy.config.quic.congestion_control.loss_reduction_factor"); + REC_EstablishStaticConfigInt32U(this->_cc_persistent_congestion_threshold, + "proxy.config.quic.congestion_control.persistent_congestion_threshold"); this->_server_ssl_ctx = quic_init_server_ssl_ctx(this); this->_client_ssl_ctx = quic_init_client_ssl_ctx(this); From 8fb23d69452471d2cc08ec8d50d5ddc292a4b9f4 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 14 Feb 2019 15:51:50 +0800 Subject: [PATCH 1133/1313] QUIC: Fixed test cases --- iocore/net/quic/Mock.h | 30 ++++++- iocore/net/quic/test/test_QUICLossDetector.cc | 88 +++++++++++-------- iocore/net/quic/test/test_QUICPacket.cc | 4 +- .../net/quic/test/test_QUICPacketFactory.cc | 2 +- .../quic/test/test_QUICVersionNegotiator.cc | 8 +- 5 files changed, 87 insertions(+), 45 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 9ab283d5a99..20e25d07603 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -379,7 +379,7 @@ class MockQUICCongestionController : public QUICCongestionController MockQUICCongestionController(QUICConnectionInfoProvider *info) : QUICCongestionController(info) {} // Override virtual void - on_packets_lost(const std::map &packets) override + on_packets_lost(const std::map &packets, uint32_t pto_count) override { for (auto &p : packets) { lost_packets.insert(p.first); @@ -714,3 +714,31 @@ class MockQUICTransferProgressProvider : public QUICTransferProgressProvider uint64_t _transfer_progress = 0; uint64_t _transfer_goal = UINT64_MAX; }; + +class MockQUICFrameGenerator : public QUICFrameGenerator +{ +public: + bool + will_generate_frame(QUICEncryptionLevel level) override + { + return true; + } + + QUICFrame * + generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) + { + QUICFrame *frame = QUICFrameFactory::create_ping_frame(buf, 0, this); + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + this->_records_frame(0, std::move(info)); + return frame; + } + + int lost_frame_count = 0; + +private: + void + _on_frame_lost(QUICFrameInformationUPtr &info) + { + lost_frame_count++; + } +}; diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 9cb040bc692..46b66a6ac97 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -49,11 +49,17 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") SECTION("Handshake") { + MockQUICFrameGenerator g; // Check initial state - CHECK(tx.retransmitted.size() == 0); + uint8_t frame_buffer[1024] = {0}; + CHECK(g.lost_frame_count == 0); + QUICFrame *ping_frame = g.generate_frame(frame_buffer, QUICEncryptionLevel::HANDSHAKE, 4, UINT16_MAX); + + uint8_t raw[4]; + size_t len; + CHECK(ping_frame->store(raw, &len, 10240) < 4); // Send SERVER_CLEARTEXT (Handshake message) - uint8_t raw[4] = {0}; ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); memcpy(payload.get(), raw, sizeof(raw)); @@ -61,21 +67,21 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") QUICPacketHeader::build(QUICPacketType::HANDSHAKE, QUICKeyPhase::HANDSHAKE, {reinterpret_cast("\xff\xdd\xbb\x99\x77\x55\x33\x11"), 8}, {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x00000001, 0, 0x00112233, - std::move(payload), sizeof(raw)); + false, std::move(payload), sizeof(raw)); QUICPacketUPtr packet = QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true, false), [](QUICPacket *p) { delete p; }); detector.on_packet_sent(std::move(packet)); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); - CHECK(tx.retransmitted.size() > 0); + CHECK(g.lost_frame_count >= 0); // Receive ACK QUICAckFrame frame(0x01, 20, 0); frame.ack_block_section()->add_ack_block({0, 1ULL}); detector.handle_frame(QUICEncryptionLevel::INITIAL, frame); ink_hrtime_sleep(HRTIME_MSECONDS(1500)); - int retransmit_count = tx.retransmitted.size(); + int retransmit_count = g.lost_frame_count; ink_hrtime_sleep(HRTIME_MSECONDS(1500)); - CHECK(tx.retransmitted.size() == retransmit_count); + CHECK(g.lost_frame_count == retransmit_count); } SECTION("1-RTT") @@ -84,43 +90,47 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") CHECK(tx.retransmitted.size() == 0); // Send packet (1) to (7) - payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload = ats_unique_malloc(payload_len); + QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet2 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload = ats_unique_malloc(payload_len); + QUICPacketUPtr packet2 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet3 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload = ats_unique_malloc(payload_len); + QUICPacketUPtr packet3 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet4 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload = ats_unique_malloc(payload_len); + QUICPacketUPtr packet4 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet5 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload = ats_unique_malloc(payload_len); + QUICPacketUPtr packet5 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet6 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload = ats_unique_malloc(payload_len); + QUICPacketUPtr packet6 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet7 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload = ats_unique_malloc(payload_len); + QUICPacketUPtr packet7 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet8 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload = ats_unique_malloc(payload_len); + QUICPacketUPtr packet8 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet9 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload = ats_unique_malloc(payload_len); + QUICPacketUPtr packet9 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false, dummy_frames); - - QUICPacketNumber pn1 = packet1->packet_number(); - QUICPacketNumber pn2 = packet2->packet_number(); - QUICPacketNumber pn3 = packet3->packet_number(); - QUICPacketNumber pn4 = packet4->packet_number(); - QUICPacketNumber pn5 = packet5->packet_number(); - QUICPacketNumber pn6 = packet6->packet_number(); - QUICPacketNumber pn7 = packet7->packet_number(); - QUICPacketNumber pn8 = packet8->packet_number(); - QUICPacketNumber pn9 = packet9->packet_number(); + payload = ats_unique_malloc(payload_len); + QUICPacketUPtr packet10 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload_len, true, false, dummy_frames); + + QUICPacketNumber pn1 = packet1->packet_number(); + QUICPacketNumber pn2 = packet2->packet_number(); + QUICPacketNumber pn3 = packet3->packet_number(); + QUICPacketNumber pn4 = packet4->packet_number(); + QUICPacketNumber pn5 = packet5->packet_number(); + QUICPacketNumber pn6 = packet6->packet_number(); + QUICPacketNumber pn7 = packet7->packet_number(); + QUICPacketNumber pn8 = packet8->packet_number(); + QUICPacketNumber pn9 = packet9->packet_number(); + QUICPacketNumber pn10 = packet10->packet_number(); detector.on_packet_sent(std::move(packet1)); detector.on_packet_sent(std::move(packet2)); @@ -131,9 +141,9 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") detector.on_packet_sent(std::move(packet7)); detector.on_packet_sent(std::move(packet8)); detector.on_packet_sent(std::move(packet9)); + detector.on_packet_sent(std::move(packet10)); - ink_hrtime_sleep(HRTIME_MSECONDS(1000)); - + ink_hrtime_sleep(HRTIME_MSECONDS(2000)); // Receive an ACK for (1) (4) (5) (7) (8) (9) afm.update(QUICEncryptionLevel::INITIAL, pn1, payload_len, false); afm.update(QUICEncryptionLevel::INITIAL, pn4, payload_len, false); @@ -141,13 +151,14 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") afm.update(QUICEncryptionLevel::INITIAL, pn7, payload_len, false); afm.update(QUICEncryptionLevel::INITIAL, pn8, payload_len, false); afm.update(QUICEncryptionLevel::INITIAL, pn9, payload_len, false); - ink_hrtime_sleep(HRTIME_MSECONDS(1000)); + afm.update(QUICEncryptionLevel::INITIAL, pn10, payload_len, false); uint8_t buf[QUICFrame::MAX_INSTANCE_SIZE]; QUICFrame *x = afm.generate_frame(buf, QUICEncryptionLevel::INITIAL, 2048, 2048); frame = static_cast(x); + ink_hrtime_sleep(HRTIME_MSECONDS(1000)); detector.handle_frame(QUICEncryptionLevel::INITIAL, *frame); - ink_hrtime_sleep(HRTIME_MSECONDS(5000)); + // Lost because of packet_threshold. CHECK(cc.lost_packets.size() == 3); CHECK(cc.lost_packets.find(pn1) == cc.lost_packets.end()); @@ -159,6 +170,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") CHECK(cc.lost_packets.find(pn7) == cc.lost_packets.end()); CHECK(cc.lost_packets.find(pn8) == cc.lost_packets.end()); CHECK(cc.lost_packets.find(pn9) == cc.lost_packets.end()); + CHECK(cc.lost_packets.find(pn9) == cc.lost_packets.end()); } } diff --git a/iocore/net/quic/test/test_QUICPacket.cc b/iocore/net/quic/test/test_QUICPacket.cc index 5edc50dd81e..f50d156af65 100644 --- a/iocore/net/quic/test/test_QUICPacket.cc +++ b/iocore/net/quic/test/test_QUICPacket.cc @@ -135,7 +135,8 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") QUICPacketHeaderUPtr header = QUICPacketHeader::build( QUICPacketType::INITIAL, QUICKeyPhase::INITIAL, {reinterpret_cast("\x01\x02\x03\x04\x05\x06\x07\x08"), 8}, - {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x01234567, 0, 0x11223344, std::move(payload), 5); + {reinterpret_cast("\x11\x12\x13\x14\x15\x16\x17\x18"), 8}, 0x01234567, 0, 0x11223344, true, + std::move(payload), 5); CHECK(header->size() == sizeof(expected) - 5); CHECK(header->packet_size() == sizeof(expected)); @@ -146,6 +147,7 @@ TEST_CASE("QUICPacketHeader - Long", "[quic]") CHECK(header->packet_number() == 0x01234567); CHECK(header->has_version() == true); CHECK(header->version() == 0x11223344); + CHECK(header->is_crypto_packet()); header->store(buf, &len); CHECK(len == header->size()); diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 7f2535f1aad..dd1f057c08c 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -98,7 +98,7 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") QUICPacketUPtr packet = factory.create_handshake_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), 0, - std::move(payload), sizeof(raw), true, false, dummy_frames); + std::move(payload), sizeof(raw), true, false, true, dummy_frames); CHECK(packet->type() == QUICPacketType::HANDSHAKE); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index bfb0a06cae7..d7230fb5d8d 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -42,7 +42,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frames); + packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, true, dummy_frames); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -61,7 +61,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frames); + packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, true, dummy_frames); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -80,7 +80,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frames); + packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, true, dummy_frames); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); @@ -124,7 +124,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, dummy_frames); + packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, true, dummy_frames); // Server send VN packet based on Initial packet QUICPacketUPtr vn_packet = From 3eac14ffd020cd40917e84506269a5f33e70d946 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 14 Feb 2019 16:05:09 +0800 Subject: [PATCH 1134/1313] QUIC: Adds log for lost packet and add comment to the changes with spec --- iocore/net/quic/QUICCongestionController.cc | 9 +++++++++ iocore/net/quic/QUICLossDetector.cc | 1 + 2 files changed, 10 insertions(+) diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 2aba4c2c727..53ab1f55486 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -86,6 +86,9 @@ QUICCongestionController::on_packet_acked(const PacketInfo &acked_packet) } } +// addtional code +// the original one is: +// CongestionEvent(sent_time): void QUICCongestionController::_congestion_event(ink_hrtime sent_time, uint32_t pto_count) { @@ -102,6 +105,9 @@ QUICCongestionController::_congestion_event(ink_hrtime sent_time, uint32_t pto_c } } +// additional code +// the original one is: +// ProcessECN(ack): void QUICCongestionController::process_ecn(const PacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section, uint32_t pto_count) @@ -117,6 +123,9 @@ QUICCongestionController::process_ecn(const PacketInfo &acked_largest_packet, co } } +// additional code +// the original one is: +// OnPacketsLost(lost_packets): void QUICCongestionController::on_packets_lost(const std::map &lost_packets, uint32_t pto_count) { diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 91eacfccb04..43738b67798 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -493,6 +493,7 @@ QUICLossDetector::_retransmit_lost_packet(QUICPacketUPtr &packet) SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); + QUICLDDebug("[NOP] Retransmit %s packet #%" PRIu64, QUICDebugNames::packet_type(packet->type()), packet->packet_number()); for (QUICFrameInfo &frame_info : packet->frames()) { auto reactor = frame_info.generated_by(); if (reactor == nullptr) { From a2b365707c5b3350129e8eb96002bfeb04df85b5 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Feb 2019 09:35:42 +0900 Subject: [PATCH 1135/1313] Fix compiler warnings - missing override keyword --- iocore/net/quic/QUICPacket.h | 44 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 0a81b99d23c..3b1bd6d9fbc 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -217,21 +217,21 @@ class QUICPacketLongHeader : public QUICPacketHeader QUICConnectionId source_cid, QUICConnectionId original_dcid, ats_unique_buf retry_token, size_t retry_token_len); - QUICPacketType type() const; - QUICConnectionId destination_cid() const; - QUICConnectionId source_cid() const; + QUICPacketType type() const override; + QUICConnectionId destination_cid() const override; + QUICConnectionId source_cid() const override; QUICConnectionId original_dcid() const; - QUICPacketNumber packet_number() const; - bool has_version() const; - bool is_valid() 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; - const uint8_t *payload() const; + QUICVersion version() const override; + const uint8_t *payload() const override; const uint8_t *token() const; size_t token_len() const; - QUICKeyPhase key_phase() const; - uint16_t size() const; - void store(uint8_t *buf, size_t *len) const; + QUICKeyPhase key_phase() const override; + uint16_t size() const override; + void store(uint8_t *buf, size_t *len) const override; 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); @@ -270,21 +270,21 @@ class QUICPacketShortHeader : public QUICPacketHeader QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len); QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId connection_id, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf buf, size_t len); - QUICPacketType type() const; - QUICConnectionId destination_cid() const; + QUICPacketType type() const override; + QUICConnectionId destination_cid() const override; QUICConnectionId - source_cid() const + source_cid() const override { return QUICConnectionId::ZERO(); } - QUICPacketNumber packet_number() const; - bool has_version() const; - bool is_valid() const; - QUICVersion version() const; - const uint8_t *payload() const; - QUICKeyPhase key_phase() const; - uint16_t size() const; - void store(uint8_t *buf, size_t *len) const; + 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; + QUICKeyPhase key_phase() const override; + uint16_t size() const override; + void store(uint8_t *buf, size_t *len) const override; static bool key_phase(QUICKeyPhase &key_phase, const uint8_t *packet, size_t packet_len); static bool packet_number_offset(uint8_t &pn_offset, const uint8_t *packet, size_t packet_len, int dcil); From 3e6f177a1bd8f6fd58f71664d4bee18639f4bd63 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Feb 2019 09:36:57 +0900 Subject: [PATCH 1136/1313] Fix compiler warnings - wrong format for ink_hrtime --- iocore/net/quic/QUICLossDetector.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 43738b67798..d15287e182a 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -336,7 +336,7 @@ QUICLossDetector::_set_loss_detection_timer() timeout = timeout * (1 << this->_crypto_count); this->_loss_detection_alarm_at = this->_time_of_last_sent_crypto_packet + timeout; - QUICLDDebug("crypto packet alarm will be set: %ld", this->_loss_detection_alarm_at); + QUICLDDebug("crypto packet alarm will be set: %" PRId64, this->_loss_detection_alarm_at); // -- ADDITIONAL CODE -- // In psudocode returning here, but we don't do for scheduling _loss_detection_alarm event. // -- END OF ADDITIONAL CODE -- @@ -344,7 +344,7 @@ QUICLossDetector::_set_loss_detection_timer() if (this->_loss_time != 0) { // Time threshold loss detection. this->_loss_detection_alarm_at = this->_loss_time; - QUICLDDebug("time threshold loss detection timer: %ld", this->_loss_detection_alarm_at); + QUICLDDebug("time threshold loss detection timer: %" PRId64, this->_loss_detection_alarm_at); } else { // PTO Duration @@ -352,7 +352,7 @@ QUICLossDetector::_set_loss_detection_timer() timeout = std::max(timeout, this->_k_granularity); timeout = timeout * (1 << this->_pto_count); this->_loss_detection_alarm_at = this->_time_of_last_sent_ack_eliciting_packet + timeout; - QUICLDDebug("PTO timeout will be set: %ld", this->_loss_detection_alarm_at); + QUICLDDebug("PTO timeout will be set: %" PRId64, this->_loss_detection_alarm_at); } QUICLDDebug("Loss detection alarm has been set to %" PRId64 "ms", timeout / HRTIME_MSECOND); From 32aaa2520fda1b44dd6b4ec9ce1d59ef4983fa27 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Feb 2019 09:56:32 +0900 Subject: [PATCH 1137/1313] Cleanup: remove unused counter QUICNetVConnection::_handshake_packets_sent is deprecated in favor of 2bebf6c7338e28c6ef0f8c1cdb3fb6c4e57fcc26. --- iocore/net/P_QUICNetVConnection.h | 4 +--- iocore/net/QUICNetVConnection.cc | 5 ----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e20da7f746e..e35c54c58cb 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -375,9 +375,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub size_t _av_token_len = 0; bool _is_resumption_token_sent = false; - // This is for limiting number of packets that a server can send without path validation - uint32_t _handshake_packets_sent = 0; - uint64_t _stream_frames_sent = 0; + uint64_t _stream_frames_sent = 0; // TODO: Source addresses verification through an address validation token bool _has_ack_eliciting_packet_out = true; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 28d784c317d..00031816bd3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1252,11 +1252,6 @@ QUICNetVConnection::_state_common_send_packet() QUICPacketUPtr packet = this->_packetize_frames(level, max_packet_size); if (packet) { - if (this->netvc_context == NET_VCONNECTION_IN && - (packet->type() == QUICPacketType::INITIAL || packet->type() == QUICPacketType::HANDSHAKE)) { - ++this->_handshake_packets_sent; - } - 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()); From da5385f76a6f1de6e2ecab8792889f33757cbf5b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Feb 2019 11:00:53 +0900 Subject: [PATCH 1138/1313] Make _has_new_data flag true only if received packet is not ack only --- iocore/net/quic/QUICAckFrameCreator.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 6f634c50e33..7214fdc0817 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -198,13 +198,13 @@ QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_numb } if (!ack_only) { - this->_available = true; + this->_available = true; + this->_has_new_data = true; } else { this->_should_send = this->_available ? this->_should_send : false; } - this->_has_new_data = true; - this->_expect_next = packet_number + 1; + this->_expect_next = packet_number + 1; this->_packet_numbers.push_back({ack_only, packet_number}); } From 0b84cf33d14accb558fa9e9b695d13a0f394868a Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 15 Feb 2019 11:29:28 +0800 Subject: [PATCH 1139/1313] QUIC: AckCreator only response to non-ack-only packet --- iocore/net/quic/QUICAckFrameCreator.cc | 2 +- .../net/quic/test/test_QUICAckFrameCreator.cc | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 7214fdc0817..55b8d6fbb31 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -193,7 +193,7 @@ QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_numb } // can not delay handshake packet - if (this->_level == QUICEncryptionLevel::INITIAL || this->_level == QUICEncryptionLevel::HANDSHAKE) { + if ((this->_level == QUICEncryptionLevel::INITIAL || this->_level == QUICEncryptionLevel::HANDSHAKE) && !ack_only) { this->_should_send = true; } diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 15b1e13dc91..7e0d4108e6e 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -343,3 +343,70 @@ TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") CHECK(ack_manager.will_generate_frame(level) == false); } + +TEST_CASE("QUICAckFrameManager ack only packet", "[quic]") +{ + SECTION("INITIAL") + { + QUICAckFrameManager ack_manager; + QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + + // Initial state + QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + QUICAckFrame *frame = static_cast(ack_frame); + CHECK(frame == nullptr); + + ack_manager.update(level, 1, 1, false); + ack_manager.update(level, 2, 1, false); + ack_manager.update(level, 3, 1, false); + ack_manager.update(level, 4, 1, false); + ack_manager.update(level, 5, 1, false); + + CHECK(ack_manager.will_generate_frame(level) == true); + + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); + CHECK(frame != nullptr); + CHECK(frame->ack_block_count() == 0); + CHECK(frame->largest_acknowledged() == 5); + CHECK(frame->ack_block_section()->first_ack_block() == 4); + CHECK(frame->ack_block_section()->begin()->gap() == 0); + + ack_manager.update(level, 6, 1, true); + ack_manager.update(level, 7, 1, true); + CHECK(ack_manager.will_generate_frame(level) == false); + } + + SECTION("ONE_RTT") + { + QUICAckFrameManager ack_manager; + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + + // Initial state + QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + QUICAckFrame *frame = static_cast(ack_frame); + CHECK(frame == nullptr); + + ack_manager.update(level, 1, 1, false); + ack_manager.update(level, 2, 1, false); + ack_manager.update(level, 3, 1, false); + ack_manager.update(level, 4, 1, false); + ack_manager.update(level, 5, 1, false); + + CHECK(ack_manager.will_generate_frame(level) == true); + + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + frame = static_cast(ack_frame); + CHECK(frame != nullptr); + CHECK(frame->ack_block_count() == 0); + CHECK(frame->largest_acknowledged() == 5); + CHECK(frame->ack_block_section()->first_ack_block() == 4); + CHECK(frame->ack_block_section()->begin()->gap() == 0); + + ack_manager.update(level, 6, 1, true); + ack_manager.update(level, 7, 1, true); + CHECK(ack_manager.will_generate_frame(level) == false); + } +} From d06806f97669e402d53cb7c42299956fbfcd9cf8 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 15 Feb 2019 14:26:02 +0900 Subject: [PATCH 1140/1313] Fix compiler warnings - unused parameter --- iocore/net/quic/QUICAckFrameCreator.cc | 5 ++++- iocore/net/quic/QUICAltConnectionManager.cc | 5 ++++- iocore/net/quic/QUICFlowController.cc | 6 +++++- iocore/net/quic/QUICHandshake.cc | 3 --- iocore/net/quic/QUICPathValidator.cc | 9 +++++---- iocore/net/quic/QUICPinger.cc | 5 ++++- iocore/net/quic/QUICStream.cc | 6 +++++- 7 files changed, 27 insertions(+), 12 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 55b8d6fbb31..db93cd21853 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -57,8 +57,11 @@ QUICAckFrameManager::update(QUICEncryptionLevel level, QUICPacketNumber packet_n return 0; } +/** + * @param connection_credit This is not used. Because ACK frame is not flow-controlled + */ QUICFrame * -QUICAckFrameManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, +QUICAckFrameManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, uint16_t maximum_frame_size) { QUICAckFrame *ack_frame = nullptr; diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index ad05d8de453..0e284e85a7b 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -260,8 +260,11 @@ QUICAltConnectionManager::will_generate_frame(QUICEncryptionLevel level) return this->_need_advertise || !this->_retired_seq_nums.empty(); } +/** + * @param connection_credit This is not used. Because NEW_CONNECTION_ID frame is not flow-controlled + */ QUICFrame * -QUICAltConnectionManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, +QUICAltConnectionManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, uint16_t maximum_frame_size) { QUICFrame *frame = nullptr; diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 03a685a14a4..84f120a9e42 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -105,8 +105,12 @@ QUICFlowController::will_generate_frame(QUICEncryptionLevel level) return this->_should_create_frame; } +/** + * @param connection_credit This is not used. Because MAX_(STREAM_)DATA frame are not flow-controlled + */ QUICFrame * -QUICFlowController::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICFlowController::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, + uint16_t maximum_frame_size) { QUICFrame *frame = nullptr; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index ef69639dfd0..dfd6ed1450c 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -349,9 +349,6 @@ QUICHandshake::will_generate_frame(QUICEncryptionLevel level) QUICFrame * QUICHandshake::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) { - // CRYPTO frame is not flow-controlled - // connection_credit = UINT64_MAX; - QUICFrame *frame = nullptr; if (this->_is_level_matched(level)) { diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index 6f29c3c21f5..4436f583857 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -126,14 +126,15 @@ QUICPathValidator::will_generate_frame(QUICEncryptionLevel level) return (this->_has_outgoing_challenge || this->_has_outgoing_response); } +/** + * @param connection_credit This is not used. Because PATH_CHALLENGE and PATH_RESPONSE frame are not flow-controlled + */ QUICFrame * -QUICPathValidator::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICPathValidator::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, + uint16_t maximum_frame_size) { QUICFrame *frame = nullptr; - // PATH_CHALLENGE and PATH_RESPONSE are not flow-controlled - connection_credit = UINT64_MAX; - if (!this->_is_level_matched(level)) { return frame; } diff --git a/iocore/net/quic/QUICPinger.cc b/iocore/net/quic/QUICPinger.cc index f2e40a577ac..eb892bc133d 100644 --- a/iocore/net/quic/QUICPinger.cc +++ b/iocore/net/quic/QUICPinger.cc @@ -54,8 +54,11 @@ QUICPinger::will_generate_frame(QUICEncryptionLevel level) return this->_need_to_fire[QUICTypeUtil::pn_space_index(level)] > 0; } +/** + * @param connection_credit This is not used. Because PING frame is not flow-controlled + */ QUICFrame * -QUICPinger::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICPinger::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, uint16_t maximum_frame_size) { QUICFrame *frame = nullptr; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 132df1fca62..32516cca0d3 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -876,8 +876,12 @@ QUICCryptoStream::will_generate_frame(QUICEncryptionLevel level) return this->_write_buffer_reader->is_read_avail_more_than(0); } +/** + * @param connection_credit This is not used. Because CRYPTO frame is not flow-controlled + */ QUICFrame * -QUICCryptoStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICCryptoStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, + uint16_t maximum_frame_size) { QUICConnectionErrorUPtr error = nullptr; From 6b2773c82f4ab05b4bd2983fe9ca52321c3bb798 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 15 Feb 2019 13:48:07 +0800 Subject: [PATCH 1141/1313] QUIC: Fixed crash when records connection id frame --- iocore/net/quic/QUICAltConnectionManager.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 0e284e85a7b..7a7980d8c7c 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -283,11 +283,11 @@ QUICAltConnectionManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level if (frame && frame->size() > maximum_frame_size) { // Cancel generating frame frame = nullptr; - } else { + } else if (frame != nullptr) { + this->_records_new_connection_id_frame(level, static_cast(*frame)); this->_alt_quic_connection_ids_local[i].advertised = true; } - this->_records_new_connection_id_frame(level, static_cast(*frame)); return frame; } } From 38600d49cebfe1eb53ef69561d57737b7bd9fc48 Mon Sep 17 00:00:00 2001 From: scw00 Date: Sun, 17 Feb 2019 11:34:53 +0800 Subject: [PATCH 1142/1313] QUIC: Refactor QUICStream State --- iocore/net/quic/QUICDebugNames.cc | 78 +-- iocore/net/quic/QUICDebugNames.h | 2 +- iocore/net/quic/QUICIncomingFrameBuffer.cc | 6 + iocore/net/quic/QUICIncomingFrameBuffer.h | 1 + iocore/net/quic/QUICStream.cc | 25 +- iocore/net/quic/QUICStream.h | 10 +- iocore/net/quic/QUICStreamState.cc | 490 +++++++++--------- iocore/net/quic/QUICStreamState.h | 140 +++-- .../quic/test/test_QUICIncomingFrameBuffer.cc | 4 + iocore/net/quic/test/test_QUICStreamState.cc | 334 ++++++++---- 10 files changed, 626 insertions(+), 464 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index cfeed61c04d..a841a9d73e7 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -209,41 +209,51 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) } const char * -QUICDebugNames::stream_state(const QUICStreamState &state) +QUICDebugNames::stream_state(const int state) { - switch (state.get()) { - case QUICStreamState::State::_Init: - return "INIT"; - case QUICStreamState::State::Ready: - return "READY"; - case QUICStreamState::State::Send: - return "SEND"; - case QUICStreamState::State::DataSent: - return "DATA_SENT"; - case QUICStreamState::State::DataRecvd: - return "DATA_RECVD"; - case QUICStreamState::State::ResetSent: - return "RESET_SENT"; - case QUICStreamState::State::ResetRecvd: - return "RESET_RECVD"; - case QUICStreamState::State::Recv: - return "RECV"; - case QUICStreamState::State::SizeKnown: - return "SIZE_KNOWN"; - case QUICStreamState::State::DataRead: - return "DATA_READ"; - case QUICStreamState::State::ResetRead: - return "RESET_READ"; - case QUICStreamState::State::Open: - return "OPEN"; - case QUICStreamState::State::HC_L: - return "HC_L"; - case QUICStreamState::State::HC_R: - return "HC_R"; - case QUICStreamState::State::Closed: - return "CLOSED"; - case QUICStreamState::State::_Invalid: - return "INVALID"; + switch (state) { + case 0: + return "QUICSendStreamState::Init"; + case 1: + return "QUICSendStreamState::Ready"; + case 2: + return "QUICSendStreamState::Send"; + case 3: + return "QUICSendStreamState::DataSent"; + case 4: + return "QUICSendStreamState::DataRecvd"; + case 5: + return "QUICSendStreamState::ResetSent"; + case 6: + return "QUICSendStreamState::ResetRecvd"; + case 7: + return "QUICReceiveStreamState::Init"; + case 8: + return "QUICReceiveStreamState::Recv"; + case 9: + return "QUICReceiveStreamState::SizeKnown"; + case 10: + return "QUICReceiveStreamState::DataRecvd"; + case 11: + return "QUICReceiveStreamState::ResetRecvd"; + case 12: + return "QUICReceiveStreamState::DataRead"; + case 13: + return "QUICReceiveStreamState::ResetRead"; + case 14: + return "QUICBidirectionalStreamState::Init"; + case 15: + return "QUICBidirectionalStreamState::Idle"; + case 16: + return "QUICBidirectionalStreamState::Open"; + case 17: + return "QUICBidirectionalStreamState::HC_R"; + case 18: + return "QUICBidirectionalStreamState::HC_L"; + case 19: + return "QUICBidirectionalStreamState::Closed"; + case 20: + return "QUICBidirectionalStreamState::Invalid"; default: return "UNKNOWN"; } diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index 8bc2c100662..ede96731627 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -36,7 +36,7 @@ class QUICDebugNames static const char *error_class(QUICErrorClass cls); static const char *error_code(uint16_t code); static const char *transport_parameter_id(QUICTransportParameterId id); - static const char *stream_state(const QUICStreamState &state); + static const char *stream_state(const int state); static const char *quic_event(int event); static const char *key_phase(QUICKeyPhase phase); static const char *encryption_level(QUICEncryptionLevel level); diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index 1af365160f1..db8913af7b3 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -32,6 +32,12 @@ QUICIncomingFrameBuffer::~QUICIncomingFrameBuffer() this->clear(); } +bool +QUICIncomingStreamFrameBuffer::has_all_data() const +{ + return this->_recv_offset == this->_fin_offset; +} + void QUICIncomingFrameBuffer::clear() { diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index 6251908b6d6..4850a0c3852 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -57,6 +57,7 @@ class QUICIncomingStreamFrameBuffer : public QUICIncomingFrameBuffer, public QUI const QUICFrame *pop() override; QUICConnectionErrorUPtr insert(const QUICFrame *frame) override; void clear() override; + bool has_all_data() const; // QUICTransferProgressProvider bool is_transfer_goal_set() const override; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 32516cca0d3..2ef8a5d8fda 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -30,15 +30,15 @@ #define QUICStreamDebug(fmt, ...) \ Debug("quic_stream", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ - QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) + QUICDebugNames::stream_state(static_cast(this->_state.get())), ##__VA_ARGS__) #define QUICVStreamDebug(fmt, ...) \ Debug("v_quic_stream", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ - QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) + QUICDebugNames::stream_state(static_cast(this->_state.get())), ##__VA_ARGS__) #define QUICStreamFCDebug(fmt, ...) \ Debug("quic_flow_ctrl", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ - QUICDebugNames::stream_state(this->_state), ##__VA_ARGS__) + QUICDebugNames::stream_state(static_cast(this->_state.get())), ##__VA_ARGS__) static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; @@ -51,8 +51,7 @@ QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider _remote_flow_controller(send_max_stream_data, _id), _local_flow_controller(rtt_provider, recv_max_stream_data, _id), _flow_control_buffer_size(recv_max_stream_data), - _received_stream_frame_buffer(), - _state(nullptr, &this->_progress_vio, this, nullptr) + _received_stream_frame_buffer() { SET_HANDLER(&QUICStream::state_stream_open); mutex = new_ProxyMutex(); @@ -297,13 +296,7 @@ QUICStream::_write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t void QUICStream::on_read() { - this->_state.update_on_read(); -} - -void -QUICStream::on_eos() -{ - this->_state.update_on_eos(); + this->_state.update_on_user_read_event(); } /** @@ -340,6 +333,10 @@ QUICStream::recv(const QUICStreamFrame &frame) return error; } + if (this->_received_stream_frame_buffer.has_all_data()) { + this->_state.update_on_transport_recv_event(); + } + auto new_frame = this->_received_stream_frame_buffer.pop(); const QUICStreamFrame *stream_frame = nullptr; uint64_t last_offset = 0; @@ -599,7 +596,9 @@ QUICStream::_on_frame_acked(QUICFrameInformationUPtr &info) break; } - this->_state.update_on_ack(); + if (this->_is_reset_complete || this->_is_transfer_complete) { + this->_state.update_on_transport_send_event(); + } } void diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 85f121e4af5..2610008363f 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -43,11 +43,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra { public: QUICStream() - : VConnection(nullptr), - _remote_flow_controller(0, 0), - _local_flow_controller(nullptr, 0, 0), - _received_stream_frame_buffer(), - _state(nullptr, nullptr, nullptr, nullptr) + : VConnection(nullptr), _remote_flow_controller(0, 0), _local_flow_controller(nullptr, 0, 0), _received_stream_frame_buffer() { } QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t recv_max_stream_data, @@ -73,7 +69,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra * QUICApplication need to call one of these functions when it process VC_EVENT_* */ void on_read(); - void on_eos(); + // void on_eos(); QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame); QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame); @@ -144,7 +140,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra QUICIncomingStreamFrameBuffer _received_stream_frame_buffer; // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState - QUICBidirectionalStreamState _state; + QUICBidirectionalStreamStateMachine _state; // QUICFrameGenerator void _on_frame_acked(QUICFrameInformationUPtr &info) override; diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index a91e9f45323..437510a4a7e 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -24,111 +24,79 @@ #include "QUICStreamState.h" #include "tscore/ink_assert.h" -void -QUICStreamState::_set_state(State s) -{ - ink_assert(s != State::_Init); - ink_assert(s != State::_Invalid); - this->_state = s; -} - // ---------QUICReceiveStreamState ----------- bool -QUICReceiveStreamState::is_allowed_to_send(const QUICFrame &frame) const +QUICReceiveStreamStateMachine::is_allowed_to_send(const QUICFrame &frame) const { return this->is_allowed_to_send(frame.type()); } bool -QUICReceiveStreamState::is_allowed_to_send(QUICFrameType type) const +QUICReceiveStreamStateMachine::is_allowed_to_send(QUICFrameType type) const { - // Return true or break out the switch to return false - switch (this->get()) { - case State::_Init: - if (type == QUICFrameType::STREAM || type == QUICFrameType::RESET_STREAM || type == QUICFrameType::MAX_STREAM_DATA || - type == QUICFrameType::STREAM_DATA_BLOCKED) { - return true; - } - break; - case State::_Invalid: - // Everthing is invalid on this state - break; - case State::Recv: - if (type == QUICFrameType::NEW_CONNECTION_ID || type == QUICFrameType::PATH_CHALLENGE) { - return true; - } - if (type == QUICFrameType::ACK) { - return true; - } - if (type == QUICFrameType::MAX_STREAM_DATA || type == QUICFrameType::STOP_SENDING) { - return true; - } - break; - case State::SizeKnown: - if (type == QUICFrameType::ACK) { - return true; - } - if (type == QUICFrameType::STOP_SENDING) { - return true; - } - break; - case State::DataRecvd: - if (type != QUICFrameType::STREAM && type != QUICFrameType::RESET_STREAM && type != QUICFrameType::STREAM_DATA_BLOCKED) { - return true; - } - break; - case State::DataRead: - if (type == QUICFrameType::STOP_SENDING) { - return true; - } - break; - case State::ResetRecvd: - // It should not send any frame after receiving RESET_STREAM - break; - case State::ResetRead: - // It should not send any frame after receiving RESET_STREAM - break; - default: - ink_assert(!"Unknown state"); - break; + if (type != QUICFrameType::STOP_SENDING && type != QUICFrameType::MAX_STREAM_DATA) { + return false; + } + + QUICReceiveStreamState state = this->get(); + // The receiver only sends MAX_STREAM_DATA in the “Recv” state. + if (type == QUICFrameType::MAX_STREAM_DATA && state == QUICReceiveStreamState::Recv) { + return true; + } + + // A receiver can send STOP_SENDING in any state where it has not received a RESET_STREAM frame; that is states other than “Reset + // Recvd” or “Reset Read”. + if (type == QUICFrameType::STOP_SENDING && state != QUICReceiveStreamState::ResetRecvd && + state != QUICReceiveStreamState::ResetRead) { + return true; } return false; } bool -QUICReceiveStreamState::is_allowed_to_receive(const QUICFrame &frame) const +QUICReceiveStreamStateMachine::is_allowed_to_receive(const QUICFrame &frame) const { return this->is_allowed_to_receive(frame.type()); } bool -QUICReceiveStreamState::is_allowed_to_receive(QUICFrameType type) const +QUICReceiveStreamStateMachine::is_allowed_to_receive(QUICFrameType type) const { + if (type != QUICFrameType::STREAM && type != QUICFrameType::STREAM_DATA_BLOCKED && type != QUICFrameType::RESET_STREAM) { + return false; + } + // Return true or break out the switch to return false + if (this->get() == QUICReceiveStreamState::Init && + (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM)) { + return true; + } + switch (this->get()) { - case State::_Init: - if (type == QUICFrameType::STREAM || type == QUICFrameType::RESET_STREAM || type == QUICFrameType::MAX_STREAM_DATA || - type == QUICFrameType::STREAM_DATA_BLOCKED) { + case QUICReceiveStreamState::Recv: + if (type == QUICFrameType::STREAM || type == QUICFrameType::RESET_STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED) { return true; } break; - case State::_Invalid: - // Everthing is invalid on this state + case QUICReceiveStreamState::SizeKnown: + // STREAM_DATA_BLOCKED must be older frame because we have already received fin . + if (type == QUICFrameType::STREAM || type == QUICFrameType::RESET_STREAM) { + return true; + } break; - case State::Recv: - return true; - case State::SizeKnown: - return true; - case State::DataRecvd: - return true; - case State::DataRead: - return true; - case State::ResetRecvd: - return true; - case State::ResetRead: - return true; + case QUICReceiveStreamState::DataRecvd: + // once we are in DataRecvd, discard all stale STREAM frame and peer's RESET_STREAM frame to try our best to collect data. + break; + // FIXME: once receiving RESET_STREAM frame. We don't transit this state to DataRecvd. + case QUICReceiveStreamState::ResetRecvd: + return false; + case QUICReceiveStreamState::Init: + // Discard every thing when we are in terminal state. + case QUICReceiveStreamState::DataRead: + case QUICReceiveStreamState::ResetRead: + return false; default: ink_assert(!"Unknown state"); break; @@ -138,71 +106,43 @@ QUICReceiveStreamState::is_allowed_to_receive(QUICFrameType type) const } void -QUICReceiveStreamState::update_with_sending_frame(const QUICFrame &frame) +QUICReceiveStreamStateMachine::update_with_sending_frame(const QUICFrame &frame) { } void -QUICReceiveStreamState::update_with_receiving_frame(const QUICFrame &frame) +QUICReceiveStreamStateMachine::update_with_receiving_frame(const QUICFrame &frame) { + // The receiving part of a stream initiated by a peer (types 1 and 3 for a client, or 0 and 2 for a server) is created when the + // first STREAM, STREAM_DATA_BLOCKED, or RESET_STREAM is received for that stream. + QUICReceiveStreamState state = this->get(); + QUICFrameType type = frame.type(); + + if (state == QUICReceiveStreamState::Init && + (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM)) { + this->_set_state(QUICReceiveStreamState::Recv); + } + switch (this->get()) { - case State::_Init: - if (frame.type() == QUICFrameType::STREAM) { - this->_set_state(State::Recv); - if (static_cast(frame).has_fin_flag()) { - this->_set_state(State::SizeKnown); - if (this->_in_progress->is_transfer_complete()) { - this->_set_state(State::DataRecvd); - } - } - } else if (frame.type() == QUICFrameType::RESET_STREAM) { - this->_set_state(State::Recv); - this->_set_state(State::ResetRecvd); - } else if (frame.type() == QUICFrameType::MAX_STREAM_DATA || frame.type() == QUICFrameType::STREAM_DATA_BLOCKED) { - this->_set_state(State::Recv); - } else { - this->_set_state(State::_Invalid); - } - break; - case State::Recv: - if (frame.type() == QUICFrameType::STREAM) { + case QUICReceiveStreamState::Recv: + if (type == QUICFrameType::STREAM) { if (static_cast(frame).has_fin_flag()) { - this->_set_state(State::SizeKnown); - if (this->_in_progress->transfer_progress() == this->_in_progress->transfer_goal()) { - this->_set_state(State::DataRecvd); - } - } - } else if (frame.type() == QUICFrameType::RESET_STREAM) { - this->_set_state(State::ResetRecvd); - } - break; - case State::SizeKnown: - if (frame.type() == QUICFrameType::STREAM) { - if (this->_in_progress->transfer_progress() == this->_in_progress->transfer_goal()) { - this->_set_state(State::DataRecvd); + this->_set_state(QUICReceiveStreamState::SizeKnown); } - } else if (frame.type() == QUICFrameType::RESET_STREAM) { - this->_set_state(State::ResetRecvd); + } else if (type == QUICFrameType::RESET_STREAM) { + this->_set_state(QUICReceiveStreamState::ResetRecvd); } break; - case State::DataRecvd: - if (frame.type() == QUICFrameType::RESET_STREAM) { - this->_set_state(State::ResetRecvd); - } - break; - case State::DataRead: - break; - case State::ResetRecvd: - if (frame.type() == QUICFrameType::STREAM) { - if (this->_in_progress->transfer_progress() == this->_in_progress->transfer_goal()) { - this->_set_state(State::DataRecvd); - } + case QUICReceiveStreamState::SizeKnown: + if (type == QUICFrameType::RESET_STREAM) { + this->_set_state(QUICReceiveStreamState::ResetRecvd); } break; - case State::ResetRead: - break; - case State::_Invalid: - // Once we get illegal state, no way to recover it + case QUICReceiveStreamState::Init: + case QUICReceiveStreamState::DataRecvd: + case QUICReceiveStreamState::ResetRecvd: + case QUICReceiveStreamState::DataRead: + case QUICReceiveStreamState::ResetRead: break; default: ink_assert(!"Unknown state"); @@ -211,69 +151,92 @@ QUICReceiveStreamState::update_with_receiving_frame(const QUICFrame &frame) } void -QUICReceiveStreamState::update(const QUICStreamState &opposite_side) +QUICReceiveStreamStateMachine::update_on_user_read_event() { switch (this->get()) { - case State::_Init: - ink_assert(opposite_side.get() != State::_Init); - this->_set_state(State::Recv); + case QUICReceiveStreamState::DataRecvd: + this->_set_state(QUICReceiveStreamState::DataRead); + break; + case QUICReceiveStreamState::ResetRecvd: + this->_set_state(QUICReceiveStreamState::ResetRead); + break; + case QUICReceiveStreamState::Recv: + case QUICReceiveStreamState::SizeKnown: + case QUICReceiveStreamState::DataRead: + case QUICReceiveStreamState::ResetRead: break; + case QUICReceiveStreamState::Init: default: - ink_assert(!"This shouldn't be happen"); + ink_assert(!"Unknown state"); break; } } void -QUICReceiveStreamState::update_on_read() +QUICReceiveStreamStateMachine::update_on_transport_recv_event() { - if (this->_in_progress->is_transfer_complete()) { - this->_set_state(State::DataRead); + if (this->get() == QUICReceiveStreamState::SizeKnown) { + this->_set_state(QUICReceiveStreamState::DataRecvd); } } void -QUICReceiveStreamState::update_on_eos() +QUICReceiveStreamStateMachine::update(const QUICSendStreamState state) { - this->_set_state(State::ResetRead); + // The receiving part of a stream enters the “Recv” state when the sending part of a bidirectional stream initiated by the + // endpoint (type 0 for a client, type 1 for a server) enters the “Ready” state. + switch (this->get()) { + case QUICReceiveStreamState::Init: + if (state == QUICSendStreamState::Ready) { + this->_set_state(QUICReceiveStreamState::Recv); + } + break; + default: + break; + } } // ---------- QUICSendStreamState ------------- bool -QUICSendStreamState::is_allowed_to_send(const QUICFrame &frame) const +QUICSendStreamStateMachine::is_allowed_to_send(const QUICFrame &frame) const { return this->is_allowed_to_send(frame.type()); } bool -QUICSendStreamState::is_allowed_to_send(QUICFrameType type) const +QUICSendStreamStateMachine::is_allowed_to_send(QUICFrameType type) const { + if (type != QUICFrameType::STREAM && type != QUICFrameType::STREAM_DATA_BLOCKED && type != QUICFrameType::RESET_STREAM) { + return false; + } + switch (this->get()) { - case State::_Init: - break; - case State::Ready: + case QUICSendStreamState::Ready: if (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM) { return true; } break; - case State::Send: + case QUICSendStreamState::Send: if (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM) { return true; } break; - case State::DataSent: + case QUICSendStreamState::DataSent: if (type == QUICFrameType::RESET_STREAM) { return true; } break; - case State::DataRecvd: + // A sender MUST NOT send any of these frames from a terminal state (“Data Recvd” or “Reset Recvd”). + case QUICSendStreamState::DataRecvd: + case QUICSendStreamState::ResetRecvd: break; - case State::ResetSent: - break; - case State::ResetRecvd: - break; - case State::_Invalid: + // A sender MUST NOT send STREAM or STREAM_DATA_BLOCKED after sending a RESET_STREAM; that is, in the terminal states and in the + // “Reset Sent” state. + case QUICSendStreamState::ResetSent: + if (type == QUICFrameType::RESET_STREAM) { + return true; + } break; default: ink_assert("This shouuldn't be happen"); @@ -284,56 +247,77 @@ QUICSendStreamState::is_allowed_to_send(QUICFrameType type) const } bool -QUICSendStreamState::is_allowed_to_receive(const QUICFrame &frame) const +QUICSendStreamStateMachine::is_allowed_to_receive(const QUICFrame &frame) const { return this->is_allowed_to_receive(frame.type()); } bool -QUICSendStreamState::is_allowed_to_receive(QUICFrameType type) const +QUICSendStreamStateMachine::is_allowed_to_receive(QUICFrameType type) const { + if (type != QUICFrameType::STOP_SENDING && type != QUICFrameType::MAX_STREAM_DATA) { + return false; + } + + // A sender could receive either of these two frames(MAX_STREAM_DATA and STOP_SENDING) in any state as a result of delayed + // delivery of packets. + // PS: Because we need to reply a RESET_STREAM frame. STOP_SENDING frame is accpeted in all states. But we + // don't need to do anything for MAX_STREAM_DATA frame when we are in terminal state. + if (type == QUICFrameType::STOP_SENDING) { + return true; + } + + switch (this->get()) { + case QUICSendStreamState::Ready: + case QUICSendStreamState::Send: + if (type == QUICFrameType::MAX_STREAM_DATA) { + return true; + } + break; + // "MAX_STREAM_DATA frames might be received until the peer receives the final stream offset. The endpoint can safely ignore + // any MAX_STREAM_DATA frames it receives from its peer for a stream in this state." + case QUICSendStreamState::DataSent: + case QUICSendStreamState::ResetSent: + case QUICSendStreamState::DataRecvd: + case QUICSendStreamState::ResetRecvd: + break; + default: + break; + } + return false; } void -QUICSendStreamState::update_with_sending_frame(const QUICFrame &frame) +QUICSendStreamStateMachine::update_with_sending_frame(const QUICFrame &frame) { + QUICSendStreamState state = this->get(); + QUICFrameType type = frame.type(); + if (state == QUICSendStreamState::Ready && + (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM)) { + this->_set_state(QUICSendStreamState::Send); + } + switch (this->get()) { - case State::_Init: - break; - case State::Ready: - if (frame.type() == QUICFrameType::STREAM) { - this->_set_state(State::Send); + case QUICSendStreamState::Send: + if (type == QUICFrameType::STREAM) { if (static_cast(frame).has_fin_flag()) { - this->_set_state(State::DataSent); + this->_set_state(QUICSendStreamState::DataSent); } - } else if (frame.type() == QUICFrameType::STREAM_DATA_BLOCKED) { - this->_set_state(State::Send); - } else if (frame.type() == QUICFrameType::RESET_STREAM) { - this->_set_state(State::ResetSent); + } else if (type == QUICFrameType::RESET_STREAM) { + this->_set_state(QUICSendStreamState::ResetSent); } break; - case State::Send: - if (frame.type() == QUICFrameType::STREAM) { - if (static_cast(frame).has_fin_flag()) { - this->_set_state(State::DataSent); - } - } else if (frame.type() == QUICFrameType::RESET_STREAM) { - this->_set_state(State::ResetSent); - } - break; - case State::DataSent: - if (frame.type() == QUICFrameType::RESET_STREAM) { - this->_set_state(State::ResetSent); + case QUICSendStreamState::DataSent: + if (type == QUICFrameType::RESET_STREAM) { + this->_set_state(QUICSendStreamState::ResetSent); } break; - case State::DataRecvd: - break; - case State::ResetSent: - break; - case State::ResetRecvd: - break; - case State::_Invalid: + case QUICSendStreamState::Init: + case QUICSendStreamState::Ready: + case QUICSendStreamState::DataRecvd: + case QUICSendStreamState::ResetSent: + case QUICSendStreamState::ResetRecvd: break; default: ink_assert(!"Unknown state"); @@ -342,139 +326,155 @@ QUICSendStreamState::update_with_sending_frame(const QUICFrame &frame) } void -QUICSendStreamState::update_with_receiving_frame(const QUICFrame &frame) +QUICSendStreamStateMachine::update_with_receiving_frame(const QUICFrame &frame) { } void -QUICSendStreamState::update(const QUICStreamState &opposite_side) +QUICSendStreamStateMachine::update_on_transport_send_event() { switch (this->get()) { - case State::_Init: - ink_assert(opposite_side.get() != State::_Init); - this->_set_state(State::Ready); + case QUICSendStreamState::DataSent: + this->_set_state(QUICSendStreamState::DataRecvd); + break; + case QUICSendStreamState::ResetSent: + this->_set_state(QUICSendStreamState::ResetRecvd); break; default: - ink_assert(!"This shouldn't be happen"); break; } } void -QUICSendStreamState::update_on_ack() +QUICSendStreamStateMachine::update(const QUICReceiveStreamState state) { - if (this->_out_progress->is_transfer_complete()) { - this->_set_state(State::DataRecvd); - } else if (this->_out_progress->is_cancelled()) { - this->_set_state(State::ResetRecvd); + // The sending part of a bidirectional stream initiated by a peer (type 0 for a server, type 1 for a client) enters the “Ready” + // state then immediately transitions to the “Send” state if the receiving part enters the “Recv” state (Section 3.2). + switch (this->get()) { + case QUICSendStreamState::Ready: + if (state == QUICReceiveStreamState::Recv) { + this->_set_state(QUICSendStreamState::Send); + } + break; + default: + break; } } // ---------QUICBidirectionalStreamState ----------- -QUICStreamState::State -QUICBidirectionalStreamState::get() const +QUICBidirectionalStreamState +QUICBidirectionalStreamStateMachine::get() const { - QUICStreamState::State s_state = this->_send_stream_state.get(); - QUICStreamState::State r_state = this->_recv_stream_state.get(); - - if (s_state == State::Ready || s_state == State::Send || s_state == State::DataSent) { - if (r_state == State::Recv || r_state == State::SizeKnown) { - return State::Open; - } else if (r_state == State::DataRecvd || r_state == State::DataRead) { - return State::HC_R; - } else if (r_state == State::ResetRecvd || r_state == State::ResetRead) { - return State::HC_R; + QUICSendStreamState s_state = this->_send_stream_state.get(); + QUICReceiveStreamState r_state = this->_recv_stream_state.get(); + + if (s_state == QUICSendStreamState::Ready || r_state == QUICReceiveStreamState::Init) { + return QUICBidirectionalStreamState::Idle; + } else if (s_state == QUICSendStreamState::Ready || s_state == QUICSendStreamState::Send || + s_state == QUICSendStreamState::DataSent) { + if (r_state == QUICReceiveStreamState::Recv || r_state == QUICReceiveStreamState::SizeKnown) { + return QUICBidirectionalStreamState::Open; + } else if (r_state == QUICReceiveStreamState::DataRecvd || r_state == QUICReceiveStreamState::DataRead) { + return QUICBidirectionalStreamState::HC_R; + } else if (r_state == QUICReceiveStreamState::ResetRecvd || r_state == QUICReceiveStreamState::ResetRead) { + return QUICBidirectionalStreamState::HC_R; } else { ink_assert(false); - return State::_Invalid; + return QUICBidirectionalStreamState::Invalid; } - } else if (s_state == State::DataRecvd) { - if (r_state == State::Recv || r_state == State::SizeKnown) { - return State::HC_L; - } else if (r_state == State::DataRecvd || r_state == State::DataRead) { - return State::Closed; - } else if (r_state == State::ResetRecvd || r_state == State::ResetRead) { - return State::Closed; + } else if (s_state == QUICSendStreamState::DataRecvd) { + if (r_state == QUICReceiveStreamState::Recv || r_state == QUICReceiveStreamState::SizeKnown) { + return QUICBidirectionalStreamState::HC_L; + } else if (r_state == QUICReceiveStreamState::DataRecvd || r_state == QUICReceiveStreamState::DataRead) { + return QUICBidirectionalStreamState::Closed; + } else if (r_state == QUICReceiveStreamState::ResetRecvd || r_state == QUICReceiveStreamState::ResetRead) { + return QUICBidirectionalStreamState::Closed; } else { ink_assert(false); - return State::_Invalid; + return QUICBidirectionalStreamState::Invalid; } - } else if (s_state == State::ResetSent || s_state == State::ResetRecvd) { - if (r_state == State::Recv || r_state == State::SizeKnown) { - return State::HC_L; - } else if (r_state == State::DataRecvd || r_state == State::DataRead) { - return State::Closed; - } else if (r_state == State::ResetRecvd || r_state == State::ResetRead) { - return State::Closed; + } else if (s_state == QUICSendStreamState::ResetSent || s_state == QUICSendStreamState::ResetRecvd) { + if (r_state == QUICReceiveStreamState::Recv || r_state == QUICReceiveStreamState::SizeKnown) { + return QUICBidirectionalStreamState::HC_L; + } else if (r_state == QUICReceiveStreamState::DataRecvd || r_state == QUICReceiveStreamState::DataRead) { + return QUICBidirectionalStreamState::Closed; + } else if (r_state == QUICReceiveStreamState::ResetRecvd || r_state == QUICReceiveStreamState::ResetRead) { + return QUICBidirectionalStreamState::Closed; } else { ink_assert(false); - return State::_Invalid; + return QUICBidirectionalStreamState::Invalid; } - } else if (s_state == State::_Init && r_state == State::_Init) { - return State::_Init; } else { ink_assert(false); - return State::_Invalid; + return QUICBidirectionalStreamState::Invalid; } } void -QUICBidirectionalStreamState::update_with_sending_frame(const QUICFrame &frame) +QUICBidirectionalStreamStateMachine::update_with_sending_frame(const QUICFrame &frame) { + // The receiving part of a stream enters the “Recv” state when the sending part of a bidirectional stream initiated by the + // endpoint (type 0 for a client, type 1 for a server) enters the “Ready” state. this->_send_stream_state.update_with_sending_frame(frame); - if (this->_recv_stream_state.get() == State::_Init) { - this->_recv_stream_state.update(this->_send_stream_state); + // PS: It should not happen because we initialize the send side and read side together. And the SendState has the default state + // "Ready". But to obey the specs, we do this as follow. + if (this->_send_stream_state.get() == QUICSendStreamState::Ready && + this->_recv_stream_state.get() == QUICReceiveStreamState::Init) { + this->_recv_stream_state.update(this->_send_stream_state.get()); } } void -QUICBidirectionalStreamState::update_with_receiving_frame(const QUICFrame &frame) +QUICBidirectionalStreamStateMachine::update_with_receiving_frame(const QUICFrame &frame) { + // The sending part of a bidirectional stream initiated by a peer (type 0 for a server, type 1 for a client) enters the “Ready” + // state then immediately transitions to the “Send” state if the receiving part enters the “Recv” state (Section 3.2). this->_recv_stream_state.update_with_receiving_frame(frame); - if (this->_send_stream_state.get() == State::_Init) { - this->_send_stream_state.update(this->_recv_stream_state); + if (this->_send_stream_state.get() == QUICSendStreamState::Ready && + this->_recv_stream_state.get() == QUICReceiveStreamState::Recv) { + this->_send_stream_state.update(this->_recv_stream_state.get()); } } void -QUICBidirectionalStreamState::update_on_ack() +QUICBidirectionalStreamStateMachine::update_on_transport_recv_event() { - this->_send_stream_state.update_on_ack(); + this->_recv_stream_state.update_on_transport_recv_event(); } void -QUICBidirectionalStreamState::update_on_read() +QUICBidirectionalStreamStateMachine::update_on_transport_send_event() { - this->_recv_stream_state.update_on_read(); + this->_send_stream_state.update_on_transport_send_event(); } void -QUICBidirectionalStreamState::update_on_eos() +QUICBidirectionalStreamStateMachine::update_on_user_read_event() { - this->_recv_stream_state.update_on_eos(); + this->_recv_stream_state.update_on_user_read_event(); } bool -QUICBidirectionalStreamState::is_allowed_to_send(const QUICFrame &frame) const +QUICBidirectionalStreamStateMachine::is_allowed_to_send(const QUICFrame &frame) const { return this->is_allowed_to_send(frame.type()); } bool -QUICBidirectionalStreamState::is_allowed_to_send(QUICFrameType type) const +QUICBidirectionalStreamStateMachine::is_allowed_to_send(QUICFrameType type) const { return this->_send_stream_state.is_allowed_to_send(type) || this->_recv_stream_state.is_allowed_to_send(type); } bool -QUICBidirectionalStreamState::is_allowed_to_receive(const QUICFrame &frame) const +QUICBidirectionalStreamStateMachine::is_allowed_to_receive(const QUICFrame &frame) const { return this->is_allowed_to_receive(frame.type()); } bool -QUICBidirectionalStreamState::is_allowed_to_receive(QUICFrameType type) const +QUICBidirectionalStreamStateMachine::is_allowed_to_receive(QUICFrameType type) const { return this->_send_stream_state.is_allowed_to_receive(type) || this->_recv_stream_state.is_allowed_to_receive(type); } diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h index dab2d8c8ce4..1422c6d9445 100644 --- a/iocore/net/quic/QUICStreamState.h +++ b/iocore/net/quic/QUICStreamState.h @@ -26,37 +26,34 @@ #include "QUICFrame.h" #include "QUICTransferProgressProvider.h" -class QUICStreamState +enum class QUICSendStreamState { + Init = 0, + Ready = 1, + Send = 2, + DataSent = 3, + DataRecvd = 4, + ResetSent = 5, + ResetRecvd = 6, +}; + +enum class QUICReceiveStreamState { + Init = 7, + Recv = 8, + SizeKnown = 9, + DataRecvd = 10, + ResetRecvd = 11, + DataRead = 12, + ResetRead = 13, +}; + +enum class QUICBidirectionalStreamState { Init = 14, Idle = 15, Open = 16, HC_R = 17, HC_L = 18, Closed = 19, Invalid = 20 }; + +template class QUICStreamStateMachine { public: - enum class State { - // Common - _Init, - _Invalid, - // SendStreamState - Ready, - Send, - DataSent, - DataRecvd, - ResetSent, - ResetRecvd, - // ReceiveStreamState - Recv, - SizeKnown, - /* DataRecvd, (dup)*/ - DataRead, - /* ResetRecvd, (dup)*/ - ResetRead, - // Bidirectional - Open, - HC_R, - HC_L, - Closed - }; - - virtual ~QUICStreamState() {} - - virtual State + virtual ~QUICStreamStateMachine() {} + + virtual T get() const { return this->_state; @@ -65,87 +62,86 @@ class QUICStreamState virtual void update_with_sending_frame(const QUICFrame &frame) = 0; virtual void update_with_receiving_frame(const QUICFrame &frame) = 0; + virtual void + update_on_transport_send_event() + { + } + virtual void + update_on_transport_recv_event() + { + } + virtual void + update_on_user_read_event() + { + } + virtual bool is_allowed_to_send(QUICFrameType type) const = 0; virtual bool is_allowed_to_send(const QUICFrame &frame) const = 0; virtual bool is_allowed_to_receive(QUICFrameType type) const = 0; virtual bool is_allowed_to_receive(const QUICFrame &frame) const = 0; protected: - void _set_state(State s); - -private: - State _state = State::_Init; -}; - -class QUICUnidirectionalStreamState : public QUICStreamState -{ -public: - QUICUnidirectionalStreamState(QUICTransferProgressProvider *in, QUICTransferProgressProvider *out) - : _in_progress(in), _out_progress(out) + void + _set_state(T s) { + ink_assert(s != T::Init); + this->_state = s; } - virtual void update(const QUICStreamState &opposite_side) = 0; -protected: - QUICTransferProgressProvider *_in_progress = nullptr; - QUICTransferProgressProvider *_out_progress = nullptr; +private: + T _state = T::Init; }; -class QUICSendStreamState : public QUICUnidirectionalStreamState +class QUICSendStreamStateMachine : public QUICStreamStateMachine { public: - QUICSendStreamState(QUICTransferProgressProvider *in, QUICTransferProgressProvider *out) : QUICUnidirectionalStreamState(in, out) - { - this->_set_state(State::Ready); - } + QUICSendStreamStateMachine() { this->_set_state(QUICSendStreamState::Ready); }; void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; - void update(const QUICStreamState &opposite_side) override; - void update_on_ack(); + + void update_on_transport_send_event() override; bool is_allowed_to_send(QUICFrameType type) const override; bool is_allowed_to_send(const QUICFrame &frame) const override; bool is_allowed_to_receive(QUICFrameType type) const override; bool is_allowed_to_receive(const QUICFrame &frame) const override; + + void update(const QUICReceiveStreamState opposite_side); }; -class QUICReceiveStreamState : public QUICUnidirectionalStreamState +class QUICReceiveStreamStateMachine : public QUICStreamStateMachine { public: - QUICReceiveStreamState(QUICTransferProgressProvider *in, QUICTransferProgressProvider *out) - : QUICUnidirectionalStreamState(in, out) - { - } + QUICReceiveStreamStateMachine() = default; void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; - void update(const QUICStreamState &opposite_side) override; - void update_on_read(); - void update_on_eos(); + + void update_on_transport_recv_event() override; + void update_on_user_read_event() override; bool is_allowed_to_send(QUICFrameType type) const override; bool is_allowed_to_send(const QUICFrame &frame) const override; bool is_allowed_to_receive(QUICFrameType type) const override; bool is_allowed_to_receive(const QUICFrame &frame) const override; + + void update(const QUICSendStreamState opposite_side); }; -class QUICBidirectionalStreamState : public QUICStreamState +class QUICBidirectionalStreamStateMachine : public QUICStreamStateMachine { public: - QUICBidirectionalStreamState(QUICTransferProgressProvider *send_in, QUICTransferProgressProvider *send_out, - QUICTransferProgressProvider *recv_in, QUICTransferProgressProvider *recv_out) - : _send_stream_state(send_in, send_out), _recv_stream_state(recv_in, recv_out) - { - this->_recv_stream_state.update(this->_send_stream_state); - } - State get() const override; + QUICBidirectionalStreamStateMachine() { this->_recv_stream_state.update(this->_send_stream_state.get()); }; + + QUICBidirectionalStreamState get() const override; void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; - void update_on_ack(); - void update_on_read(); - void update_on_eos(); + + void update_on_transport_send_event() override; + void update_on_transport_recv_event() override; + void update_on_user_read_event() override; bool is_allowed_to_send(QUICFrameType type) const override; bool is_allowed_to_send(const QUICFrame &frame) const override; @@ -153,6 +149,6 @@ class QUICBidirectionalStreamState : public QUICStreamState bool is_allowed_to_receive(const QUICFrame &frame) const override; private: - QUICSendStreamState _send_stream_state; - QUICReceiveStreamState _recv_stream_state; + QUICSendStreamStateMachine _send_stream_state; + QUICReceiveStreamStateMachine _recv_stream_state; }; diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 7a5674325ef..bd2ae3a888c 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -168,6 +168,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") frame = static_cast(buffer.pop()); CHECK(frame->offset() == 4096); CHECK(buffer.empty()); + CHECK(buffer.has_all_data()); buffer.clear(); @@ -189,6 +190,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") frame = static_cast(buffer.pop()); CHECK(frame->offset() == 4096); CHECK(buffer.empty()); + CHECK(buffer.has_all_data()); delete stream; } @@ -236,6 +238,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") frame = static_cast(buffer.pop()); CHECK(frame == nullptr); CHECK(buffer.empty()); + CHECK(buffer.has_all_data()); buffer.clear(); @@ -259,6 +262,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") frame = static_cast(buffer.pop()); CHECK(frame == nullptr); CHECK(buffer.empty()); + CHECK(buffer.has_all_data()); delete stream; } diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index 080866928df..8d9719ef17f 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -49,117 +49,110 @@ TEST_CASE("QUICSendStreamState", "[quic]") auto stream_data_blocked_frame = QUICFrameFactory::create_stream_data_blocked_frame(stream_data_blocked_frame_buf, 0, 0); MockQUICTransferProgressProvider pp; - SECTION("Ready -> Send -> Data Sent -> Data Recvd") + SECTION("SendStreamState: Ready -> Send -> Data Sent -> Data Recvd") { // Case1. Create Stream (Sending) - QUICSendStreamState ss(nullptr, &pp); - CHECK(ss.get() == QUICStreamState::State::Ready); + QUICSendStreamStateMachine ss; + CHECK(ss.get() == QUICSendStreamState::Ready); // Case2. Send STREAM CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); ss.update_with_sending_frame(*stream_frame); - CHECK(ss.get() == QUICStreamState::State::Send); + CHECK(ss.get() == QUICSendStreamState::Send); // Case3. Send STREAM_DATA_BLOCKED CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_DATA_BLOCKED)); ss.update_with_sending_frame(*stream_data_blocked_frame); - CHECK(ss.get() == QUICStreamState::State::Send); + CHECK(ss.get() == QUICSendStreamState::Send); // Case3. Send FIN in a STREAM CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); ss.update_with_sending_frame(*stream_frame_with_fin); - CHECK(ss.get() == QUICStreamState::State::DataSent); + CHECK(ss.get() == QUICSendStreamState::DataSent); // Case4. STREAM is not allowed to send CHECK(!ss.is_allowed_to_send(QUICFrameType::STREAM)); // Case5. Receive all ACKs - pp.set_transfer_complete(true); - ss.update_on_ack(); - CHECK(ss.get() == QUICStreamState::State::DataRecvd); + ss.update_on_transport_send_event(); + CHECK(ss.get() == QUICSendStreamState::DataRecvd); } - SECTION("Ready -> Send") + SECTION("QUICSendStreamState: Ready -> Send") { // Case1. Create Stream (Sending) - QUICSendStreamState ss(nullptr, &pp); - CHECK(ss.get() == QUICStreamState::State::Ready); + QUICSendStreamStateMachine ss; + CHECK(ss.get() == QUICSendStreamState::Ready); // Case2. Send STREAM_DATA_BLOCKED CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_DATA_BLOCKED)); ss.update_with_sending_frame(*stream_data_blocked_frame); - CHECK(ss.get() == QUICStreamState::State::Send); + CHECK(ss.get() == QUICSendStreamState::Send); } SECTION("Ready -> Reset Sent -> Reset Recvd") { - MockQUICTransferProgressProvider pp; - // Case1. Create Stream (Sending) - QUICSendStreamState ss(nullptr, &pp); - CHECK(ss.get() == QUICStreamState::State::Ready); + QUICSendStreamStateMachine ss; + CHECK(ss.get() == QUICSendStreamState::Ready); // Case2. Send RESET_STREAM CHECK(ss.is_allowed_to_send(QUICFrameType::RESET_STREAM)); ss.update_with_sending_frame(*rst_stream_frame); - CHECK(ss.get() == QUICStreamState::State::ResetSent); + CHECK(ss.get() == QUICSendStreamState::ResetSent); // Case3. Receive ACK for STREAM - ss.update_on_ack(); - CHECK(ss.get() == QUICStreamState::State::ResetSent); + CHECK(ss.get() == QUICSendStreamState::ResetSent); // Case4. Receive ACK for RESET_STREAM - pp.set_cancelled(true); - ss.update_on_ack(); - CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + ss.update_on_transport_send_event(); + CHECK(ss.get() == QUICSendStreamState::ResetRecvd); } - SECTION("Ready -> Send -> Reset Sent -> Reset Recvd") + SECTION("QUICSendStreamState: Ready -> Send -> Reset Sent -> Reset Recvd") { // Case1. Create Stream (Sending) - QUICSendStreamState ss(nullptr, &pp); - CHECK(ss.get() == QUICStreamState::State::Ready); + QUICSendStreamStateMachine ss; + CHECK(ss.get() == QUICSendStreamState::Ready); // Case2. Send STREAM CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); ss.update_with_sending_frame(*stream_frame); - CHECK(ss.get() == QUICStreamState::State::Send); + CHECK(ss.get() == QUICSendStreamState::Send); // Case3. Send RESET_STREAM CHECK(ss.is_allowed_to_send(QUICFrameType::RESET_STREAM)); ss.update_with_sending_frame(*rst_stream_frame); - CHECK(ss.get() == QUICStreamState::State::ResetSent); + CHECK(ss.get() == QUICSendStreamState::ResetSent); // Case4. Receive ACK for STREAM - ss.update_on_ack(); - CHECK(ss.get() == QUICStreamState::State::ResetSent); + CHECK(ss.get() == QUICSendStreamState::ResetSent); // Case5. Receive ACK for RESET_STREAM - pp.set_cancelled(true); - ss.update_on_ack(); - CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + ss.update_on_transport_send_event(); + CHECK(ss.get() == QUICSendStreamState::ResetRecvd); } - SECTION("Ready -> Send -> Data Sent -> Reset Sent -> Reset Recvd") + SECTION("QUICSendStreamState: Ready -> Send -> Data Sent -> Reset Sent -> Reset Recvd") { // Case1. Create Stream (Sending) - QUICSendStreamState ss(nullptr, &pp); - CHECK(ss.get() == QUICStreamState::State::Ready); + QUICSendStreamStateMachine ss; + CHECK(ss.get() == QUICSendStreamState::Ready); // Case2. Send STREAM CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); ss.update_with_sending_frame(*stream_frame); - CHECK(ss.get() == QUICStreamState::State::Send); + CHECK(ss.get() == QUICSendStreamState::Send); // Case3. Send STREAM_DATA_BLOCKED CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM_DATA_BLOCKED)); ss.update_with_sending_frame(*stream_data_blocked_frame); - CHECK(ss.get() == QUICStreamState::State::Send); + CHECK(ss.get() == QUICSendStreamState::Send); // Case3. Send FIN in a STREAM CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); ss.update_with_sending_frame(*stream_frame_with_fin); - CHECK(ss.get() == QUICStreamState::State::DataSent); + CHECK(ss.get() == QUICSendStreamState::DataSent); // Case4. STREAM is not allowed to send CHECK(!ss.is_allowed_to_send(QUICFrameType::STREAM)); @@ -167,16 +160,14 @@ TEST_CASE("QUICSendStreamState", "[quic]") // Case4. Send RESET_STREAM CHECK(ss.is_allowed_to_send(QUICFrameType::RESET_STREAM)); ss.update_with_sending_frame(*rst_stream_frame); - CHECK(ss.get() == QUICStreamState::State::ResetSent); + CHECK(ss.get() == QUICSendStreamState::ResetSent); // Case5. Receive ACK for STREAM - ss.update_on_ack(); - CHECK(ss.get() == QUICStreamState::State::ResetSent); + CHECK(ss.get() == QUICSendStreamState::ResetSent); // Case6. Receive ACK for RESET_STREAM - pp.set_cancelled(true); - ss.update_on_ack(); - CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + ss.update_on_transport_send_event(); + CHECK(ss.get() == QUICSendStreamState::ResetRecvd); } } @@ -203,36 +194,32 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") SECTION("Recv -> Size Known -> Data Recvd -> Data Read") { - MockQUICTransferProgressProvider in_progress; - // Case1. Recv STREAM - QUICReceiveStreamState ss(&in_progress, nullptr); + QUICReceiveStreamStateMachine ss; + CHECK(ss.is_allowed_to_send(QUICFrameType::MAX_STREAM_DATA) == false); CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - in_progress.set_transfer_progress(1); ss.update_with_receiving_frame(*stream_frame); - CHECK(ss.get() == QUICStreamState::State::Recv); + CHECK(ss.get() == QUICReceiveStreamState::Recv); // Case2. Recv STREAM_DATA_BLOCKED CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM_DATA_BLOCKED)); ss.update_with_receiving_frame(*stream_data_blocked_frame); - CHECK(ss.get() == QUICStreamState::State::Recv); + CHECK(ss.get() == QUICReceiveStreamState::Recv); // Case3. Recv FIN in a STREAM CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - in_progress.set_transfer_goal(3); ss.update_with_receiving_frame(*stream_frame_with_fin); - CHECK(ss.get() == QUICStreamState::State::SizeKnown); + CHECK(ss.get() == QUICReceiveStreamState::SizeKnown); // Case4. Recv ALL data CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - in_progress.set_transfer_progress(3); ss.update_with_receiving_frame(*stream_frame_delayed); - CHECK(ss.get() == QUICStreamState::State::DataRecvd); + ss.update_on_transport_recv_event(); + CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); // Case5. Read data - in_progress.set_transfer_complete(true); - ss.update_on_read(); - CHECK(ss.get() == QUICStreamState::State::DataRead); + ss.update_on_user_read_event(); + CHECK(ss.get() == QUICReceiveStreamState::DataRead); } SECTION("Recv -> Reset Recvd -> Reset Read") @@ -240,97 +227,260 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") MockQUICTransferProgressProvider in_progress; // Case1. Recv STREAM - QUICReceiveStreamState ss(&in_progress, nullptr); + QUICReceiveStreamStateMachine ss; CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); ss.update_with_receiving_frame(*stream_frame); - CHECK(ss.get() == QUICStreamState::State::Recv); + CHECK(ss.get() == QUICReceiveStreamState::Recv); // Case2. Recv RESET_STREAM CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); ss.update_with_receiving_frame(*rst_stream_frame); - CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + CHECK(ss.get() == QUICReceiveStreamState::ResetRecvd); // Case3. Handle reset - ss.update_on_eos(); - CHECK(ss.get() == QUICStreamState::State::ResetRead); + ss.update_on_user_read_event(); + CHECK(ss.get() == QUICReceiveStreamState::ResetRead); } SECTION("Recv -> Size Known -> Reset Recvd") { - MockQUICTransferProgressProvider in_progress; - // Case1. Recv STREAM - QUICReceiveStreamState ss(&in_progress, nullptr); + QUICReceiveStreamStateMachine ss; CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); ss.update_with_receiving_frame(*stream_frame); - CHECK(ss.get() == QUICStreamState::State::Recv); + CHECK(ss.get() == QUICReceiveStreamState::Recv); // Case2. Recv FIN in a STREAM CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); ss.update_with_receiving_frame(*stream_frame_with_fin); - CHECK(ss.get() == QUICStreamState::State::SizeKnown); + CHECK(ss.get() == QUICReceiveStreamState::SizeKnown); // Case3. Recv RESET_STREAM CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); ss.update_with_receiving_frame(*rst_stream_frame); - CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + CHECK(ss.get() == QUICReceiveStreamState::ResetRecvd); } - SECTION("Recv -> Size Known -> Data Recvd -> Reset Recvd") + SECTION("Recv -> Size Known -> Data Recvd !-> Reset Recvd") { - MockQUICTransferProgressProvider in_progress; - // Case1. Recv STREAM - QUICReceiveStreamState ss(&in_progress, nullptr); + QUICReceiveStreamStateMachine ss; CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - in_progress.set_transfer_progress(1); ss.update_with_receiving_frame(*stream_frame); - CHECK(ss.get() == QUICStreamState::State::Recv); + CHECK(ss.get() == QUICReceiveStreamState::Recv); // Case2. Recv FIN in a STREAM CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - in_progress.set_transfer_goal(3); ss.update_with_receiving_frame(*stream_frame_with_fin); - CHECK(ss.get() == QUICStreamState::State::SizeKnown); + CHECK(ss.get() == QUICReceiveStreamState::SizeKnown); // Case3. Recv ALL data CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - in_progress.set_transfer_progress(3); ss.update_with_receiving_frame(*stream_frame_delayed); - CHECK(ss.get() == QUICStreamState::State::DataRecvd); + ss.update_on_transport_recv_event(); + CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); // Case4. Recv RESET_STREAM - CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); + CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM) == false); ss.update_with_receiving_frame(*rst_stream_frame); - CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); } - SECTION("Recv -> Size Known -> Reset Recvd -> Data Recvd") + SECTION("Recv -> Size Known -> Reset Recvd !-> Data Recvd") { - MockQUICTransferProgressProvider in_progress; - // Case1. Recv STREAM - QUICReceiveStreamState ss(&in_progress, nullptr); + QUICReceiveStreamStateMachine ss; CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - in_progress.set_transfer_progress(1); ss.update_with_receiving_frame(*stream_frame); - CHECK(ss.get() == QUICStreamState::State::Recv); + CHECK(ss.get() == QUICReceiveStreamState::Recv); // Case2. Recv FIN in a STREAM CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - in_progress.set_transfer_goal(3); ss.update_with_receiving_frame(*stream_frame_with_fin); - CHECK(ss.get() == QUICStreamState::State::SizeKnown); + CHECK(ss.get() == QUICReceiveStreamState::SizeKnown); + CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING)); // Case3. Recv RESET_STREAM CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); ss.update_with_receiving_frame(*rst_stream_frame); - CHECK(ss.get() == QUICStreamState::State::ResetRecvd); + CHECK(ss.get() == QUICReceiveStreamState::ResetRecvd); + CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING) == false); // Case4. Recv ALL data + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM) == false); + ss.update_with_receiving_frame(*stream_frame_delayed); + ss.update_on_transport_recv_event(); + CHECK(ss.get() == QUICReceiveStreamState::ResetRecvd); + ss.update_on_user_read_event(); + CHECK(ss.get() == QUICReceiveStreamState::ResetRead); + CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING) == false); + } + + SECTION("Discard STREAM and RESET_STREAM in DataRecvd") + { + // Case1. Recv STREAM + QUICReceiveStreamStateMachine ss; + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + CHECK(ss.get() == QUICReceiveStreamState::Recv); + + // Case2. Recv FIN in a STREAM + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICReceiveStreamState::SizeKnown); + + // Case3. Recv ALL data CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - in_progress.set_transfer_progress(3); ss.update_with_receiving_frame(*stream_frame_delayed); - CHECK(ss.get() == QUICStreamState::State::DataRecvd); + ss.update_on_transport_recv_event(); + CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); + + CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM) == false); + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM) == false); + CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING)); + } +} + +TEST_CASE("QUICBidState", "[quic]") +{ + Ptr block_4 = make_ptr(new_IOBufferBlock()); + block_4->alloc(); + block_4->fill(4); + CHECK(block_4->read_avail() == 4); + + uint8_t stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t stream_frame_delayed_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t stream_frame_with_fin_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t rst_stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + + auto stream_frame = QUICFrameFactory::create_stream_frame(stream_frame_buf, block_4, 1, 0); + auto stream_frame_delayed = QUICFrameFactory::create_stream_frame(stream_frame_delayed_buf, block_4, 1, 1); + auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(stream_frame_with_fin_buf, block_4, 1, 2, true); + auto rst_stream_frame = + QUICFrameFactory::create_rst_stream_frame(rst_stream_frame_buf, 0, static_cast(0x01), 0); + + SECTION("QUICBidState idle -> open -> HC_R 1") + { + QUICBidirectionalStreamStateMachine ss; + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + ss.update_with_receiving_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + + ss.update_on_transport_recv_event(); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_R); + } + + SECTION("QUICBidState idle -> open -> HC_R 2") + { + QUICBidirectionalStreamStateMachine ss; + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + ss.update_with_receiving_frame(*rst_stream_frame); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_R); + } + + SECTION("QUICBidState idle -> open -> HC_L 1") + { + QUICBidirectionalStreamStateMachine ss; + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame); + + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + ss.update_with_sending_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + + ss.update_on_transport_send_event(); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + + ss.update_with_sending_frame(*stream_frame_delayed); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + } + + SECTION("QUICBidState idle -> open -> HC_L 2") + { + QUICBidirectionalStreamStateMachine ss; + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame); + + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + ss.update_with_sending_frame(*rst_stream_frame); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + } + + SECTION("QUICBidState idle -> open -> closed 1") + { + QUICBidirectionalStreamStateMachine ss; + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame); + + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + ss.update_with_sending_frame(*rst_stream_frame); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + + ss.update_with_receiving_frame(*rst_stream_frame); + CHECK(ss.get() == QUICBidirectionalStreamState::Closed); + + ss.update_on_user_read_event(); + CHECK(ss.get() == QUICBidirectionalStreamState::Closed); + } + + SECTION("QUICBidState idle -> open -> closed 2") + { + QUICBidirectionalStreamStateMachine ss; + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + ss.update_on_transport_send_event(); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + + ss.update_with_receiving_frame(*rst_stream_frame); + CHECK(ss.get() == QUICBidirectionalStreamState::Closed); + + ss.update_on_user_read_event(); + CHECK(ss.get() == QUICBidirectionalStreamState::Closed); + } + + SECTION("QUICBidState idle -> open -> closed 3") + { + QUICBidirectionalStreamStateMachine ss; + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + ss.update_on_transport_send_event(); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + + ss.update_with_receiving_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + + ss.update_on_transport_recv_event(); + CHECK(ss.get() == QUICBidirectionalStreamState::Closed); } } From 1ccd18dcb8c087224b4f14e634e779a161f1bdfe Mon Sep 17 00:00:00 2001 From: scw00 Date: Sun, 17 Feb 2019 15:19:30 +0800 Subject: [PATCH 1143/1313] QUIC: Do not discard frame in StreamState --- iocore/net/quic/QUICStreamState.cc | 40 +++----------------- iocore/net/quic/test/test_QUICStreamState.cc | 10 ++--- 2 files changed, 10 insertions(+), 40 deletions(-) diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index 437510a4a7e..604a7de1532 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -64,44 +64,11 @@ QUICReceiveStreamStateMachine::is_allowed_to_receive(const QUICFrame &frame) con bool QUICReceiveStreamStateMachine::is_allowed_to_receive(QUICFrameType type) const { - if (type != QUICFrameType::STREAM && type != QUICFrameType::STREAM_DATA_BLOCKED && type != QUICFrameType::RESET_STREAM) { - return false; - } - - // Return true or break out the switch to return false - if (this->get() == QUICReceiveStreamState::Init && - (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM)) { + // always allow receive these frames. + if (type == QUICFrameType::STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED || type == QUICFrameType::RESET_STREAM) { return true; } - switch (this->get()) { - case QUICReceiveStreamState::Recv: - if (type == QUICFrameType::STREAM || type == QUICFrameType::RESET_STREAM || type == QUICFrameType::STREAM_DATA_BLOCKED) { - return true; - } - break; - case QUICReceiveStreamState::SizeKnown: - // STREAM_DATA_BLOCKED must be older frame because we have already received fin . - if (type == QUICFrameType::STREAM || type == QUICFrameType::RESET_STREAM) { - return true; - } - break; - case QUICReceiveStreamState::DataRecvd: - // once we are in DataRecvd, discard all stale STREAM frame and peer's RESET_STREAM frame to try our best to collect data. - break; - // FIXME: once receiving RESET_STREAM frame. We don't transit this state to DataRecvd. - case QUICReceiveStreamState::ResetRecvd: - return false; - case QUICReceiveStreamState::Init: - // Discard every thing when we are in terminal state. - case QUICReceiveStreamState::DataRead: - case QUICReceiveStreamState::ResetRead: - return false; - default: - ink_assert(!"Unknown state"); - break; - } - return false; } @@ -280,6 +247,9 @@ QUICSendStreamStateMachine::is_allowed_to_receive(QUICFrameType type) const case QUICSendStreamState::ResetSent: case QUICSendStreamState::DataRecvd: case QUICSendStreamState::ResetRecvd: + if (type == QUICFrameType::MAX_STREAM_DATA) { + return true; + } break; default: break; diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index 8d9719ef17f..714538c6c29 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -281,7 +281,7 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); // Case4. Recv RESET_STREAM - CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM) == false); + CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); ss.update_with_receiving_frame(*rst_stream_frame); CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); } @@ -307,7 +307,7 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING) == false); // Case4. Recv ALL data - CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM) == false); + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); ss.update_with_receiving_frame(*stream_frame_delayed); ss.update_on_transport_recv_event(); CHECK(ss.get() == QUICReceiveStreamState::ResetRecvd); @@ -316,7 +316,7 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING) == false); } - SECTION("Discard STREAM and RESET_STREAM in DataRecvd") + SECTION("Do not discard STREAM and RESET_STREAM in DataRecvd") { // Case1. Recv STREAM QUICReceiveStreamStateMachine ss; @@ -335,8 +335,8 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") ss.update_on_transport_recv_event(); CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); - CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM) == false); - CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM) == false); + CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING)); } } From 8535ce79ad887b806d519439b56b0e9cc7d17672 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 19 Feb 2019 08:31:09 +0800 Subject: [PATCH 1144/1313] Clang-Format and signal user event only on consuming all data --- iocore/net/quic/QUICDebugNames.cc | 62 ++++++++++++++++++++----------- iocore/net/quic/QUICDebugNames.h | 4 +- iocore/net/quic/QUICStream.cc | 10 +++-- iocore/net/quic/QUICStreamState.h | 38 +++++++++++-------- 4 files changed, 72 insertions(+), 42 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index a841a9d73e7..0b06e5b9fda 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -209,50 +209,68 @@ QUICDebugNames::transport_parameter_id(QUICTransportParameterId id) } const char * -QUICDebugNames::stream_state(const int state) +QUICDebugNames::stream_state(const QUICSendStreamState state) { switch (state) { - case 0: + case QUICSendStreamState::Init: return "QUICSendStreamState::Init"; - case 1: + case QUICSendStreamState::Ready: return "QUICSendStreamState::Ready"; - case 2: + case QUICSendStreamState::Send: return "QUICSendStreamState::Send"; - case 3: + case QUICSendStreamState::DataSent: return "QUICSendStreamState::DataSent"; - case 4: + case QUICSendStreamState::DataRecvd: return "QUICSendStreamState::DataRecvd"; - case 5: + case QUICSendStreamState::ResetSent: return "QUICSendStreamState::ResetSent"; - case 6: + case QUICSendStreamState::ResetRecvd: return "QUICSendStreamState::ResetRecvd"; - case 7: + default: + return "UNKNOWN"; + } +} + +const char * +QUICDebugNames::stream_state(const QUICReceiveStreamState state) +{ + switch (state) { + case QUICReceiveStreamState::Init: return "QUICReceiveStreamState::Init"; - case 8: + case QUICReceiveStreamState::Recv: return "QUICReceiveStreamState::Recv"; - case 9: + case QUICReceiveStreamState::SizeKnown: return "QUICReceiveStreamState::SizeKnown"; - case 10: + case QUICReceiveStreamState::DataRecvd: return "QUICReceiveStreamState::DataRecvd"; - case 11: + case QUICReceiveStreamState::ResetRecvd: return "QUICReceiveStreamState::ResetRecvd"; - case 12: + case QUICReceiveStreamState::DataRead: return "QUICReceiveStreamState::DataRead"; - case 13: + case QUICReceiveStreamState::ResetRead: return "QUICReceiveStreamState::ResetRead"; - case 14: + default: + return "UNKNOWN"; + } +} + +const char * +QUICDebugNames::stream_state(const QUICBidirectionalStreamState state) +{ + switch (state) { + case QUICBidirectionalStreamState::Init: return "QUICBidirectionalStreamState::Init"; - case 15: + case QUICBidirectionalStreamState::Idle: return "QUICBidirectionalStreamState::Idle"; - case 16: + case QUICBidirectionalStreamState::Open: return "QUICBidirectionalStreamState::Open"; - case 17: + case QUICBidirectionalStreamState::HC_R: return "QUICBidirectionalStreamState::HC_R"; - case 18: + case QUICBidirectionalStreamState::HC_L: return "QUICBidirectionalStreamState::HC_L"; - case 19: + case QUICBidirectionalStreamState::Closed: return "QUICBidirectionalStreamState::Closed"; - case 20: + case QUICBidirectionalStreamState::Invalid: return "QUICBidirectionalStreamState::Invalid"; default: return "UNKNOWN"; diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index ede96731627..926f552efd9 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -36,7 +36,9 @@ class QUICDebugNames static const char *error_class(QUICErrorClass cls); static const char *error_code(uint16_t code); static const char *transport_parameter_id(QUICTransportParameterId id); - static const char *stream_state(const int state); + static const char *stream_state(const QUICSendStreamState state); + static const char *stream_state(const QUICReceiveStreamState state); + static const char *stream_state(const QUICBidirectionalStreamState state); static const char *quic_event(int event); static const char *key_phase(QUICKeyPhase phase); static const char *encryption_level(QUICEncryptionLevel level); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 2ef8a5d8fda..a7a2a471d43 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -30,15 +30,15 @@ #define QUICStreamDebug(fmt, ...) \ Debug("quic_stream", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ - QUICDebugNames::stream_state(static_cast(this->_state.get())), ##__VA_ARGS__) + QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__) #define QUICVStreamDebug(fmt, ...) \ Debug("v_quic_stream", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ - QUICDebugNames::stream_state(static_cast(this->_state.get())), ##__VA_ARGS__) + QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__) #define QUICStreamFCDebug(fmt, ...) \ Debug("quic_flow_ctrl", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ - QUICDebugNames::stream_state(static_cast(this->_state.get())), ##__VA_ARGS__) + QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__) static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; @@ -296,7 +296,9 @@ QUICStream::_write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t void QUICStream::on_read() { - this->_state.update_on_user_read_event(); + if (this->_received_stream_frame_buffer.empty() && this->_received_stream_frame_buffer.has_all_data()) { + this->_state.update_on_user_read_event(); + } } /** diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h index 1422c6d9445..524e34b2faf 100644 --- a/iocore/net/quic/QUICStreamState.h +++ b/iocore/net/quic/QUICStreamState.h @@ -27,26 +27,34 @@ #include "QUICTransferProgressProvider.h" enum class QUICSendStreamState { - Init = 0, - Ready = 1, - Send = 2, - DataSent = 3, - DataRecvd = 4, - ResetSent = 5, - ResetRecvd = 6, + Init, + Ready, + Send, + DataSent, + DataRecvd, + ResetSent, + ResetRecvd, }; enum class QUICReceiveStreamState { - Init = 7, - Recv = 8, - SizeKnown = 9, - DataRecvd = 10, - ResetRecvd = 11, - DataRead = 12, - ResetRead = 13, + Init, + Recv, + SizeKnown, + DataRecvd, + ResetRecvd, + DataRead, + ResetRead, }; -enum class QUICBidirectionalStreamState { Init = 14, Idle = 15, Open = 16, HC_R = 17, HC_L = 18, Closed = 19, Invalid = 20 }; +enum class QUICBidirectionalStreamState { + Init, + Idle, + Open, + HC_R, + HC_L, + Closed, + Invalid, +}; template class QUICStreamStateMachine { From c9552adbb67db43e2996042ed3728093e7e266e2 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 19 Feb 2019 11:08:42 +0800 Subject: [PATCH 1145/1313] QUIC: Bring back QUICTransferProgressProvider --- iocore/net/quic/Mock.h | 2 +- iocore/net/quic/QUICIncomingFrameBuffer.cc | 2 +- iocore/net/quic/QUICStream.cc | 15 +- iocore/net/quic/QUICStream.h | 6 +- iocore/net/quic/QUICStreamState.cc | 60 ++- iocore/net/quic/QUICStreamState.h | 66 ++-- iocore/net/quic/test/test_QUICStreamState.cc | 381 ++++++++++--------- 7 files changed, 275 insertions(+), 257 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 20e25d07603..1210c822a14 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -663,7 +663,7 @@ class MockQUICTransferProgressProvider : public QUICTransferProgressProvider bool is_transfer_complete() const override { - return this->_is_transfer_complete; + return this->_is_transfer_complete || this->_transfer_progress >= this->_transfer_goal; } bool diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index db8913af7b3..401792e8f55 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -176,7 +176,7 @@ QUICIncomingStreamFrameBuffer::is_transfer_goal_set() const uint64_t QUICIncomingStreamFrameBuffer::transfer_progress() const { - return this->_max_offset; + return this->_recv_offset; } uint64_t diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index a7a2a471d43..132e2cc940a 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -51,7 +51,8 @@ QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider _remote_flow_controller(send_max_stream_data, _id), _local_flow_controller(rtt_provider, recv_max_stream_data, _id), _flow_control_buffer_size(recv_max_stream_data), - _received_stream_frame_buffer() + _received_stream_frame_buffer(), + _state(nullptr, &this->_progress_vio, this, nullptr) { SET_HANDLER(&QUICStream::state_stream_open); mutex = new_ProxyMutex(); @@ -296,9 +297,7 @@ QUICStream::_write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t void QUICStream::on_read() { - if (this->_received_stream_frame_buffer.empty() && this->_received_stream_frame_buffer.has_all_data()) { - this->_state.update_on_user_read_event(); - } + this->_state.update_on_read(); } /** @@ -335,10 +334,6 @@ QUICStream::recv(const QUICStreamFrame &frame) return error; } - if (this->_received_stream_frame_buffer.has_all_data()) { - this->_state.update_on_transport_recv_event(); - } - auto new_frame = this->_received_stream_frame_buffer.pop(); const QUICStreamFrame *stream_frame = nullptr; uint64_t last_offset = 0; @@ -598,9 +593,7 @@ QUICStream::_on_frame_acked(QUICFrameInformationUPtr &info) break; } - if (this->_is_reset_complete || this->_is_transfer_complete) { - this->_state.update_on_transport_send_event(); - } + this->_state.update_on_ack(); } void diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 2610008363f..93e0dee7155 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -43,7 +43,11 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra { public: QUICStream() - : VConnection(nullptr), _remote_flow_controller(0, 0), _local_flow_controller(nullptr, 0, 0), _received_stream_frame_buffer() + : VConnection(nullptr), + _remote_flow_controller(0, 0), + _local_flow_controller(nullptr, 0, 0), + _received_stream_frame_buffer(), + _state(nullptr, nullptr, nullptr, nullptr) { } QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t recv_max_stream_data, diff --git a/iocore/net/quic/QUICStreamState.cc b/iocore/net/quic/QUICStreamState.cc index 604a7de1532..d88348dcc17 100644 --- a/iocore/net/quic/QUICStreamState.cc +++ b/iocore/net/quic/QUICStreamState.cc @@ -95,18 +95,27 @@ QUICReceiveStreamStateMachine::update_with_receiving_frame(const QUICFrame &fram if (type == QUICFrameType::STREAM) { if (static_cast(frame).has_fin_flag()) { this->_set_state(QUICReceiveStreamState::SizeKnown); + if (this->_in_progress->is_transfer_complete()) { + this->_set_state(QUICReceiveStreamState::DataRecvd); + } } } else if (type == QUICFrameType::RESET_STREAM) { this->_set_state(QUICReceiveStreamState::ResetRecvd); } break; case QUICReceiveStreamState::SizeKnown: - if (type == QUICFrameType::RESET_STREAM) { + if (type == QUICFrameType::STREAM && this->_in_progress->is_transfer_complete()) { + this->_set_state(QUICReceiveStreamState::DataRecvd); + } else if (type == QUICFrameType::RESET_STREAM) { this->_set_state(QUICReceiveStreamState::ResetRecvd); } break; - case QUICReceiveStreamState::Init: case QUICReceiveStreamState::DataRecvd: + if (type == QUICFrameType::STREAM && this->_in_progress->is_transfer_complete()) { + this->_set_state(QUICReceiveStreamState::ResetRecvd); + } + break; + case QUICReceiveStreamState::Init: case QUICReceiveStreamState::ResetRecvd: case QUICReceiveStreamState::DataRead: case QUICReceiveStreamState::ResetRead: @@ -118,33 +127,17 @@ QUICReceiveStreamStateMachine::update_with_receiving_frame(const QUICFrame &fram } void -QUICReceiveStreamStateMachine::update_on_user_read_event() +QUICReceiveStreamStateMachine::update_on_read() { - switch (this->get()) { - case QUICReceiveStreamState::DataRecvd: + if (this->_in_progress->is_transfer_complete()) { this->_set_state(QUICReceiveStreamState::DataRead); - break; - case QUICReceiveStreamState::ResetRecvd: - this->_set_state(QUICReceiveStreamState::ResetRead); - break; - case QUICReceiveStreamState::Recv: - case QUICReceiveStreamState::SizeKnown: - case QUICReceiveStreamState::DataRead: - case QUICReceiveStreamState::ResetRead: - break; - case QUICReceiveStreamState::Init: - default: - ink_assert(!"Unknown state"); - break; } } void -QUICReceiveStreamStateMachine::update_on_transport_recv_event() +QUICReceiveStreamStateMachine::update_on_eos() { - if (this->get() == QUICReceiveStreamState::SizeKnown) { - this->_set_state(QUICReceiveStreamState::DataRecvd); - } + this->_set_state(QUICReceiveStreamState::ResetRead); } void @@ -301,17 +294,12 @@ QUICSendStreamStateMachine::update_with_receiving_frame(const QUICFrame &frame) } void -QUICSendStreamStateMachine::update_on_transport_send_event() +QUICSendStreamStateMachine::update_on_ack() { - switch (this->get()) { - case QUICSendStreamState::DataSent: + if (this->_out_progress->is_transfer_complete()) { this->_set_state(QUICSendStreamState::DataRecvd); - break; - case QUICSendStreamState::ResetSent: + } else if (this->_out_progress->is_cancelled()) { this->_set_state(QUICSendStreamState::ResetRecvd); - break; - default: - break; } } @@ -408,21 +396,21 @@ QUICBidirectionalStreamStateMachine::update_with_receiving_frame(const QUICFrame } void -QUICBidirectionalStreamStateMachine::update_on_transport_recv_event() +QUICBidirectionalStreamStateMachine::update_on_ack() { - this->_recv_stream_state.update_on_transport_recv_event(); + this->_send_stream_state.update_on_ack(); } void -QUICBidirectionalStreamStateMachine::update_on_transport_send_event() +QUICBidirectionalStreamStateMachine::update_on_read() { - this->_send_stream_state.update_on_transport_send_event(); + this->_recv_stream_state.update_on_read(); } void -QUICBidirectionalStreamStateMachine::update_on_user_read_event() +QUICBidirectionalStreamStateMachine::update_on_eos() { - this->_recv_stream_state.update_on_user_read_event(); + this->_recv_stream_state.update_on_eos(); } bool diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h index 524e34b2faf..7a7ad1246be 100644 --- a/iocore/net/quic/QUICStreamState.h +++ b/iocore/net/quic/QUICStreamState.h @@ -70,19 +70,6 @@ template class QUICStreamStateMachine virtual void update_with_sending_frame(const QUICFrame &frame) = 0; virtual void update_with_receiving_frame(const QUICFrame &frame) = 0; - virtual void - update_on_transport_send_event() - { - } - virtual void - update_on_transport_recv_event() - { - } - virtual void - update_on_user_read_event() - { - } - virtual bool is_allowed_to_send(QUICFrameType type) const = 0; virtual bool is_allowed_to_send(const QUICFrame &frame) const = 0; virtual bool is_allowed_to_receive(QUICFrameType type) const = 0; @@ -100,15 +87,32 @@ template class QUICStreamStateMachine T _state = T::Init; }; -class QUICSendStreamStateMachine : public QUICStreamStateMachine +class QUICUnidirectionalStreamStateMachine { public: - QUICSendStreamStateMachine() { this->_set_state(QUICSendStreamState::Ready); }; + QUICUnidirectionalStreamStateMachine(QUICTransferProgressProvider *in, QUICTransferProgressProvider *out) + : _in_progress(in), _out_progress(out) + { + } + +protected: + QUICTransferProgressProvider *_in_progress = nullptr; + QUICTransferProgressProvider *_out_progress = nullptr; +}; + +class QUICSendStreamStateMachine : public QUICUnidirectionalStreamStateMachine, public QUICStreamStateMachine +{ +public: + QUICSendStreamStateMachine(QUICTransferProgressProvider *in, QUICTransferProgressProvider *out) + : QUICUnidirectionalStreamStateMachine(in, out) + { + ink_assert(out != nullptr); + this->_set_state(QUICSendStreamState::Ready); + } void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; - - void update_on_transport_send_event() override; + void update_on_ack(); bool is_allowed_to_send(QUICFrameType type) const override; bool is_allowed_to_send(const QUICFrame &frame) const override; @@ -118,16 +122,20 @@ class QUICSendStreamStateMachine : public QUICStreamStateMachine +class QUICReceiveStreamStateMachine : public QUICUnidirectionalStreamStateMachine, + public QUICStreamStateMachine { public: - QUICReceiveStreamStateMachine() = default; + QUICReceiveStreamStateMachine(QUICTransferProgressProvider *in, QUICTransferProgressProvider *out) + : QUICUnidirectionalStreamStateMachine(in, out) + { + ink_assert(in != nullptr); + } void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; - - void update_on_transport_recv_event() override; - void update_on_user_read_event() override; + void update_on_read(); + void update_on_eos(); bool is_allowed_to_send(QUICFrameType type) const override; bool is_allowed_to_send(const QUICFrame &frame) const override; @@ -140,16 +148,20 @@ class QUICReceiveStreamStateMachine : public QUICStreamStateMachine { public: - QUICBidirectionalStreamStateMachine() { this->_recv_stream_state.update(this->_send_stream_state.get()); }; + QUICBidirectionalStreamStateMachine(QUICTransferProgressProvider *send_in, QUICTransferProgressProvider *send_out, + QUICTransferProgressProvider *recv_in, QUICTransferProgressProvider *recv_out) + : _send_stream_state(send_in, send_out), _recv_stream_state(recv_in, recv_out) + { + this->_recv_stream_state.update(this->_send_stream_state.get()); + }; QUICBidirectionalStreamState get() const override; void update_with_sending_frame(const QUICFrame &frame) override; void update_with_receiving_frame(const QUICFrame &frame) override; - - void update_on_transport_send_event() override; - void update_on_transport_recv_event() override; - void update_on_user_read_event() override; + void update_on_ack(); + void update_on_read(); + void update_on_eos(); bool is_allowed_to_send(QUICFrameType type) const override; bool is_allowed_to_send(const QUICFrame &frame) const override; diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index 714538c6c29..c9a9f128adf 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -52,7 +52,7 @@ TEST_CASE("QUICSendStreamState", "[quic]") SECTION("SendStreamState: Ready -> Send -> Data Sent -> Data Recvd") { // Case1. Create Stream (Sending) - QUICSendStreamStateMachine ss; + QUICSendStreamStateMachine ss(nullptr, &pp); CHECK(ss.get() == QUICSendStreamState::Ready); // Case2. Send STREAM @@ -74,14 +74,15 @@ TEST_CASE("QUICSendStreamState", "[quic]") CHECK(!ss.is_allowed_to_send(QUICFrameType::STREAM)); // Case5. Receive all ACKs - ss.update_on_transport_send_event(); + pp.set_transfer_complete(true); + ss.update_on_ack(); CHECK(ss.get() == QUICSendStreamState::DataRecvd); } SECTION("QUICSendStreamState: Ready -> Send") { // Case1. Create Stream (Sending) - QUICSendStreamStateMachine ss; + QUICSendStreamStateMachine ss(nullptr, &pp); CHECK(ss.get() == QUICSendStreamState::Ready); // Case2. Send STREAM_DATA_BLOCKED @@ -92,8 +93,10 @@ TEST_CASE("QUICSendStreamState", "[quic]") SECTION("Ready -> Reset Sent -> Reset Recvd") { + MockQUICTransferProgressProvider pp; + // Case1. Create Stream (Sending) - QUICSendStreamStateMachine ss; + QUICSendStreamStateMachine ss(nullptr, &pp); CHECK(ss.get() == QUICSendStreamState::Ready); // Case2. Send RESET_STREAM @@ -105,14 +108,15 @@ TEST_CASE("QUICSendStreamState", "[quic]") CHECK(ss.get() == QUICSendStreamState::ResetSent); // Case4. Receive ACK for RESET_STREAM - ss.update_on_transport_send_event(); + pp.set_cancelled(true); + ss.update_on_ack(); CHECK(ss.get() == QUICSendStreamState::ResetRecvd); } SECTION("QUICSendStreamState: Ready -> Send -> Reset Sent -> Reset Recvd") { // Case1. Create Stream (Sending) - QUICSendStreamStateMachine ss; + QUICSendStreamStateMachine ss(nullptr, &pp); CHECK(ss.get() == QUICSendStreamState::Ready); // Case2. Send STREAM @@ -126,17 +130,19 @@ TEST_CASE("QUICSendStreamState", "[quic]") CHECK(ss.get() == QUICSendStreamState::ResetSent); // Case4. Receive ACK for STREAM + ss.update_on_ack(); CHECK(ss.get() == QUICSendStreamState::ResetSent); // Case5. Receive ACK for RESET_STREAM - ss.update_on_transport_send_event(); + pp.set_cancelled(true); + ss.update_on_ack(); CHECK(ss.get() == QUICSendStreamState::ResetRecvd); } SECTION("QUICSendStreamState: Ready -> Send -> Data Sent -> Reset Sent -> Reset Recvd") { // Case1. Create Stream (Sending) - QUICSendStreamStateMachine ss; + QUICSendStreamStateMachine ss(nullptr, &pp); CHECK(ss.get() == QUICSendStreamState::Ready); // Case2. Send STREAM @@ -163,10 +169,12 @@ TEST_CASE("QUICSendStreamState", "[quic]") CHECK(ss.get() == QUICSendStreamState::ResetSent); // Case5. Receive ACK for STREAM + ss.update_on_ack(); CHECK(ss.get() == QUICSendStreamState::ResetSent); // Case6. Receive ACK for RESET_STREAM - ss.update_on_transport_send_event(); + pp.set_cancelled(true); + ss.update_on_ack(); CHECK(ss.get() == QUICSendStreamState::ResetRecvd); } } @@ -194,10 +202,13 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") SECTION("Recv -> Size Known -> Data Recvd -> Data Read") { + MockQUICTransferProgressProvider in_progress; + // Case1. Recv STREAM - QUICReceiveStreamStateMachine ss; + QUICReceiveStreamStateMachine ss(&in_progress, nullptr); CHECK(ss.is_allowed_to_send(QUICFrameType::MAX_STREAM_DATA) == false); CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_progress(1); ss.update_with_receiving_frame(*stream_frame); CHECK(ss.get() == QUICReceiveStreamState::Recv); @@ -208,17 +219,19 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") // Case3. Recv FIN in a STREAM CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_goal(3); ss.update_with_receiving_frame(*stream_frame_with_fin); CHECK(ss.get() == QUICReceiveStreamState::SizeKnown); // Case4. Recv ALL data CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_progress(3); ss.update_with_receiving_frame(*stream_frame_delayed); - ss.update_on_transport_recv_event(); CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); // Case5. Read data - ss.update_on_user_read_event(); + in_progress.set_transfer_complete(true); + ss.update_on_read(); CHECK(ss.get() == QUICReceiveStreamState::DataRead); } @@ -227,7 +240,7 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") MockQUICTransferProgressProvider in_progress; // Case1. Recv STREAM - QUICReceiveStreamStateMachine ss; + QUICReceiveStreamStateMachine ss(&in_progress, nullptr); CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); ss.update_with_receiving_frame(*stream_frame); CHECK(ss.get() == QUICReceiveStreamState::Recv); @@ -238,14 +251,16 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") CHECK(ss.get() == QUICReceiveStreamState::ResetRecvd); // Case3. Handle reset - ss.update_on_user_read_event(); + ss.update_on_eos(); CHECK(ss.get() == QUICReceiveStreamState::ResetRead); } SECTION("Recv -> Size Known -> Reset Recvd") { + MockQUICTransferProgressProvider in_progress; + // Case1. Recv STREAM - QUICReceiveStreamStateMachine ss; + QUICReceiveStreamStateMachine ss(&in_progress, nullptr); CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); ss.update_with_receiving_frame(*stream_frame); CHECK(ss.get() == QUICReceiveStreamState::Recv); @@ -263,21 +278,25 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") SECTION("Recv -> Size Known -> Data Recvd !-> Reset Recvd") { + MockQUICTransferProgressProvider in_progress; + // Case1. Recv STREAM - QUICReceiveStreamStateMachine ss; + QUICReceiveStreamStateMachine ss(&in_progress, nullptr); CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_progress(1); ss.update_with_receiving_frame(*stream_frame); CHECK(ss.get() == QUICReceiveStreamState::Recv); // Case2. Recv FIN in a STREAM CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_goal(3); ss.update_with_receiving_frame(*stream_frame_with_fin); CHECK(ss.get() == QUICReceiveStreamState::SizeKnown); // Case3. Recv ALL data CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_progress(3); ss.update_with_receiving_frame(*stream_frame_delayed); - ss.update_on_transport_recv_event(); CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); // Case4. Recv RESET_STREAM @@ -288,199 +307,201 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") SECTION("Recv -> Size Known -> Reset Recvd !-> Data Recvd") { + MockQUICTransferProgressProvider in_progress; + // Case1. Recv STREAM - QUICReceiveStreamStateMachine ss; + QUICReceiveStreamStateMachine ss(&in_progress, nullptr); CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_progress(1); ss.update_with_receiving_frame(*stream_frame); CHECK(ss.get() == QUICReceiveStreamState::Recv); // Case2. Recv FIN in a STREAM CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_goal(3); ss.update_with_receiving_frame(*stream_frame_with_fin); CHECK(ss.get() == QUICReceiveStreamState::SizeKnown); - CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING)); // Case3. Recv RESET_STREAM CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); ss.update_with_receiving_frame(*rst_stream_frame); CHECK(ss.get() == QUICReceiveStreamState::ResetRecvd); - CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING) == false); // Case4. Recv ALL data CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_progress(3); ss.update_with_receiving_frame(*stream_frame_delayed); - ss.update_on_transport_recv_event(); CHECK(ss.get() == QUICReceiveStreamState::ResetRecvd); - ss.update_on_user_read_event(); - CHECK(ss.get() == QUICReceiveStreamState::ResetRead); CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING) == false); } SECTION("Do not discard STREAM and RESET_STREAM in DataRecvd") { + MockQUICTransferProgressProvider in_progress; + // Case1. Recv STREAM - QUICReceiveStreamStateMachine ss; + QUICReceiveStreamStateMachine ss(&in_progress, nullptr); CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); ss.update_with_receiving_frame(*stream_frame); CHECK(ss.get() == QUICReceiveStreamState::Recv); // Case2. Recv FIN in a STREAM - CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - ss.update_with_receiving_frame(*stream_frame_with_fin); - CHECK(ss.get() == QUICReceiveStreamState::SizeKnown); - - // Case3. Recv ALL data - CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - ss.update_with_receiving_frame(*stream_frame_delayed); - ss.update_on_transport_recv_event(); - CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); - - CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); - CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING)); + // CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + // ss.update_with_receiving_frame(*stream_frame_with_fin); + // CHECK(ss.get() == QUICReceiveStreamState::SizeKnown); + + // // Case3. Recv ALL data + // CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + // ss.update_with_receiving_frame(*stream_frame_delayed); + // ss.update_on_transport_recv_event(); + // CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); + + // CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); + // CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + // CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING)); } } -TEST_CASE("QUICBidState", "[quic]") -{ - Ptr block_4 = make_ptr(new_IOBufferBlock()); - block_4->alloc(); - block_4->fill(4); - CHECK(block_4->read_avail() == 4); - - uint8_t stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; - uint8_t stream_frame_delayed_buf[QUICFrame::MAX_INSTANCE_SIZE]; - uint8_t stream_frame_with_fin_buf[QUICFrame::MAX_INSTANCE_SIZE]; - uint8_t rst_stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; - - auto stream_frame = QUICFrameFactory::create_stream_frame(stream_frame_buf, block_4, 1, 0); - auto stream_frame_delayed = QUICFrameFactory::create_stream_frame(stream_frame_delayed_buf, block_4, 1, 1); - auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(stream_frame_with_fin_buf, block_4, 1, 2, true); - auto rst_stream_frame = - QUICFrameFactory::create_rst_stream_frame(rst_stream_frame_buf, 0, static_cast(0x01), 0); - - SECTION("QUICBidState idle -> open -> HC_R 1") - { - QUICBidirectionalStreamStateMachine ss; - CHECK(ss.get() == QUICBidirectionalStreamState::Idle); - - CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - ss.update_with_receiving_frame(*stream_frame); - - CHECK(ss.get() == QUICBidirectionalStreamState::Open); - ss.update_with_receiving_frame(*stream_frame_with_fin); - CHECK(ss.get() == QUICBidirectionalStreamState::Open); - - ss.update_on_transport_recv_event(); - CHECK(ss.get() == QUICBidirectionalStreamState::HC_R); - } - - SECTION("QUICBidState idle -> open -> HC_R 2") - { - QUICBidirectionalStreamStateMachine ss; - CHECK(ss.get() == QUICBidirectionalStreamState::Idle); - - CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - ss.update_with_receiving_frame(*stream_frame); - - CHECK(ss.get() == QUICBidirectionalStreamState::Open); - ss.update_with_receiving_frame(*rst_stream_frame); - CHECK(ss.get() == QUICBidirectionalStreamState::HC_R); - } - - SECTION("QUICBidState idle -> open -> HC_L 1") - { - QUICBidirectionalStreamStateMachine ss; - CHECK(ss.get() == QUICBidirectionalStreamState::Idle); - - CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); - ss.update_with_sending_frame(*stream_frame); - - CHECK(ss.get() == QUICBidirectionalStreamState::Open); - ss.update_with_sending_frame(*stream_frame_with_fin); - CHECK(ss.get() == QUICBidirectionalStreamState::Open); - - ss.update_on_transport_send_event(); - CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); - - ss.update_with_sending_frame(*stream_frame_delayed); - CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); - } - - SECTION("QUICBidState idle -> open -> HC_L 2") - { - QUICBidirectionalStreamStateMachine ss; - CHECK(ss.get() == QUICBidirectionalStreamState::Idle); - - CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); - ss.update_with_sending_frame(*stream_frame); - - CHECK(ss.get() == QUICBidirectionalStreamState::Open); - ss.update_with_sending_frame(*rst_stream_frame); - CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); - } - - SECTION("QUICBidState idle -> open -> closed 1") - { - QUICBidirectionalStreamStateMachine ss; - CHECK(ss.get() == QUICBidirectionalStreamState::Idle); - - CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); - ss.update_with_sending_frame(*stream_frame); - - CHECK(ss.get() == QUICBidirectionalStreamState::Open); - ss.update_with_sending_frame(*rst_stream_frame); - CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); - - CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - ss.update_with_receiving_frame(*stream_frame); - - ss.update_with_receiving_frame(*rst_stream_frame); - CHECK(ss.get() == QUICBidirectionalStreamState::Closed); - - ss.update_on_user_read_event(); - CHECK(ss.get() == QUICBidirectionalStreamState::Closed); - } - - SECTION("QUICBidState idle -> open -> closed 2") - { - QUICBidirectionalStreamStateMachine ss; - CHECK(ss.get() == QUICBidirectionalStreamState::Idle); - - CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); - ss.update_with_sending_frame(*stream_frame_with_fin); - CHECK(ss.get() == QUICBidirectionalStreamState::Open); - ss.update_on_transport_send_event(); - CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); - - CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - ss.update_with_receiving_frame(*stream_frame); - - ss.update_with_receiving_frame(*rst_stream_frame); - CHECK(ss.get() == QUICBidirectionalStreamState::Closed); - - ss.update_on_user_read_event(); - CHECK(ss.get() == QUICBidirectionalStreamState::Closed); - } - - SECTION("QUICBidState idle -> open -> closed 3") - { - QUICBidirectionalStreamStateMachine ss; - CHECK(ss.get() == QUICBidirectionalStreamState::Idle); - - CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); - ss.update_with_sending_frame(*stream_frame_with_fin); - CHECK(ss.get() == QUICBidirectionalStreamState::Open); - ss.update_on_transport_send_event(); - CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); - - CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - ss.update_with_receiving_frame(*stream_frame); - - ss.update_with_receiving_frame(*stream_frame_with_fin); - CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); - - ss.update_on_transport_recv_event(); - CHECK(ss.get() == QUICBidirectionalStreamState::Closed); - } -} +// TEST_CASE("QUICBidState", "[quic]") +// { +// Ptr block_4 = make_ptr(new_IOBufferBlock()); +// block_4->alloc(); +// block_4->fill(4); +// CHECK(block_4->read_avail() == 4); +// +// uint8_t stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; +// uint8_t stream_frame_delayed_buf[QUICFrame::MAX_INSTANCE_SIZE]; +// uint8_t stream_frame_with_fin_buf[QUICFrame::MAX_INSTANCE_SIZE]; +// uint8_t rst_stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; +// +// auto stream_frame = QUICFrameFactory::create_stream_frame(stream_frame_buf, block_4, 1, 0); +// auto stream_frame_delayed = QUICFrameFactory::create_stream_frame(stream_frame_delayed_buf, block_4, 1, 1); +// auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(stream_frame_with_fin_buf, block_4, 1, 2, true); +// auto rst_stream_frame = +// QUICFrameFactory::create_rst_stream_frame(rst_stream_frame_buf, 0, static_cast(0x01), 0); +// +// SECTION("QUICBidState idle -> open -> HC_R 1") +// { +// QUICBidirectionalStreamStateMachine ss; +// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); +// +// CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); +// ss.update_with_receiving_frame(*stream_frame); +// +// CHECK(ss.get() == QUICBidirectionalStreamState::Open); +// ss.update_with_receiving_frame(*stream_frame_with_fin); +// CHECK(ss.get() == QUICBidirectionalStreamState::Open); +// +// ss.update_on_transport_recv_event(); +// CHECK(ss.get() == QUICBidirectionalStreamState::HC_R); +// } +// +// SECTION("QUICBidState idle -> open -> HC_R 2") +// { +// QUICBidirectionalStreamStateMachine ss; +// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); +// +// CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); +// ss.update_with_receiving_frame(*stream_frame); +// +// CHECK(ss.get() == QUICBidirectionalStreamState::Open); +// ss.update_with_receiving_frame(*rst_stream_frame); +// CHECK(ss.get() == QUICBidirectionalStreamState::HC_R); +// } +// +// SECTION("QUICBidState idle -> open -> HC_L 1") +// { +// QUICBidirectionalStreamStateMachine ss; +// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); +// +// CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); +// ss.update_with_sending_frame(*stream_frame); +// +// CHECK(ss.get() == QUICBidirectionalStreamState::Open); +// ss.update_with_sending_frame(*stream_frame_with_fin); +// CHECK(ss.get() == QUICBidirectionalStreamState::Open); +// +// ss.update_on_transport_send_event(); +// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); +// +// ss.update_with_sending_frame(*stream_frame_delayed); +// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); +// } +// +// SECTION("QUICBidState idle -> open -> HC_L 2") +// { +// QUICBidirectionalStreamStateMachine ss; +// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); +// +// CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); +// ss.update_with_sending_frame(*stream_frame); +// +// CHECK(ss.get() == QUICBidirectionalStreamState::Open); +// ss.update_with_sending_frame(*rst_stream_frame); +// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); +// } +// +// SECTION("QUICBidState idle -> open -> closed 1") +// { +// QUICBidirectionalStreamStateMachine ss; +// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); +// +// CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); +// ss.update_with_sending_frame(*stream_frame); +// +// CHECK(ss.get() == QUICBidirectionalStreamState::Open); +// ss.update_with_sending_frame(*rst_stream_frame); +// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); +// +// CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); +// ss.update_with_receiving_frame(*stream_frame); +// +// ss.update_with_receiving_frame(*rst_stream_frame); +// CHECK(ss.get() == QUICBidirectionalStreamState::Closed); +// +// ss.update_on_user_read_event(); +// CHECK(ss.get() == QUICBidirectionalStreamState::Closed); +// } +// +// SECTION("QUICBidState idle -> open -> closed 2") +// { +// QUICBidirectionalStreamStateMachine ss; +// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); +// +// CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); +// ss.update_with_sending_frame(*stream_frame_with_fin); +// CHECK(ss.get() == QUICBidirectionalStreamState::Open); +// ss.update_on_transport_send_event(); +// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); +// +// CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); +// ss.update_with_receiving_frame(*stream_frame); +// +// ss.update_with_receiving_frame(*rst_stream_frame); +// CHECK(ss.get() == QUICBidirectionalStreamState::Closed); +// +// ss.update_on_user_read_event(); +// CHECK(ss.get() == QUICBidirectionalStreamState::Closed); +// } +// +// SECTION("QUICBidState idle -> open -> closed 3") +// { +// QUICBidirectionalStreamStateMachine ss; +// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); +// +// CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); +// ss.update_with_sending_frame(*stream_frame_with_fin); +// CHECK(ss.get() == QUICBidirectionalStreamState::Open); +// ss.update_on_transport_send_event(); +// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); +// +// CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); +// ss.update_with_receiving_frame(*stream_frame); +// +// ss.update_with_receiving_frame(*stream_frame_with_fin); +// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); +// +// ss.update_on_transport_recv_event(); +// CHECK(ss.get() == QUICBidirectionalStreamState::Closed); +// } +// } From 914ffb3618c7c13eae4341952351777342bdb347 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 19 Feb 2019 11:46:59 +0800 Subject: [PATCH 1146/1313] QUIC: Fixed test cases --- iocore/net/quic/QUICIncomingFrameBuffer.cc | 6 - iocore/net/quic/QUICIncomingFrameBuffer.h | 1 - iocore/net/quic/QUICStream.cc | 6 + iocore/net/quic/QUICStream.h | 2 +- iocore/net/quic/test/test_QUICStreamState.cc | 337 ++++++++++--------- 5 files changed, 188 insertions(+), 164 deletions(-) diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index 401792e8f55..519a749b683 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -32,12 +32,6 @@ QUICIncomingFrameBuffer::~QUICIncomingFrameBuffer() this->clear(); } -bool -QUICIncomingStreamFrameBuffer::has_all_data() const -{ - return this->_recv_offset == this->_fin_offset; -} - void QUICIncomingFrameBuffer::clear() { diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.h b/iocore/net/quic/QUICIncomingFrameBuffer.h index 4850a0c3852..6251908b6d6 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.h +++ b/iocore/net/quic/QUICIncomingFrameBuffer.h @@ -57,7 +57,6 @@ class QUICIncomingStreamFrameBuffer : public QUICIncomingFrameBuffer, public QUI const QUICFrame *pop() override; QUICConnectionErrorUPtr insert(const QUICFrame *frame) override; void clear() override; - bool has_all_data() const; // QUICTransferProgressProvider bool is_transfer_goal_set() const override; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 132e2cc940a..608fb4dd2e6 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -300,6 +300,12 @@ QUICStream::on_read() this->_state.update_on_read(); } +void +QUICStream::on_eos() +{ + this->_state.update_on_eos(); +} + /** * @brief Receive STREAM frame * @detail When receive STREAM frame, reorder frames and write to buffer of read_vio. diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 93e0dee7155..62763a99dc4 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -73,7 +73,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra * QUICApplication need to call one of these functions when it process VC_EVENT_* */ void on_read(); - // void on_eos(); + void on_eos(); QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame); QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame); diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index c9a9f128adf..0e753a6d026 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -49,7 +49,7 @@ TEST_CASE("QUICSendStreamState", "[quic]") auto stream_data_blocked_frame = QUICFrameFactory::create_stream_data_blocked_frame(stream_data_blocked_frame_buf, 0, 0); MockQUICTransferProgressProvider pp; - SECTION("SendStreamState: Ready -> Send -> Data Sent -> Data Recvd") + SECTION("Ready -> Send -> Data Sent -> Data Recvd") { // Case1. Create Stream (Sending) QUICSendStreamStateMachine ss(nullptr, &pp); @@ -79,7 +79,7 @@ TEST_CASE("QUICSendStreamState", "[quic]") CHECK(ss.get() == QUICSendStreamState::DataRecvd); } - SECTION("QUICSendStreamState: Ready -> Send") + SECTION("Ready -> Send") { // Case1. Create Stream (Sending) QUICSendStreamStateMachine ss(nullptr, &pp); @@ -113,7 +113,7 @@ TEST_CASE("QUICSendStreamState", "[quic]") CHECK(ss.get() == QUICSendStreamState::ResetRecvd); } - SECTION("QUICSendStreamState: Ready -> Send -> Reset Sent -> Reset Recvd") + SECTION("Ready -> Send -> Reset Sent -> Reset Recvd") { // Case1. Create Stream (Sending) QUICSendStreamStateMachine ss(nullptr, &pp); @@ -139,7 +139,7 @@ TEST_CASE("QUICSendStreamState", "[quic]") CHECK(ss.get() == QUICSendStreamState::ResetRecvd); } - SECTION("QUICSendStreamState: Ready -> Send -> Data Sent -> Reset Sent -> Reset Recvd") + SECTION("Ready -> Send -> Data Sent -> Reset Sent -> Reset Recvd") { // Case1. Create Stream (Sending) QUICSendStreamStateMachine ss(nullptr, &pp); @@ -346,162 +346,187 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") CHECK(ss.get() == QUICReceiveStreamState::Recv); // Case2. Recv FIN in a STREAM - // CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - // ss.update_with_receiving_frame(*stream_frame_with_fin); - // CHECK(ss.get() == QUICReceiveStreamState::SizeKnown); + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICReceiveStreamState::SizeKnown); // // Case3. Recv ALL data - // CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - // ss.update_with_receiving_frame(*stream_frame_delayed); + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + in_progress.set_transfer_complete(true); + ss.update_with_receiving_frame(*stream_frame_delayed); // ss.update_on_transport_recv_event(); - // CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); + CHECK(ss.get() == QUICReceiveStreamState::DataRecvd); - // CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); - // CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); - // CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING)); + CHECK(ss.is_allowed_to_receive(QUICFrameType::RESET_STREAM)); + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + CHECK(ss.is_allowed_to_send(QUICFrameType::STOP_SENDING)); } } -// TEST_CASE("QUICBidState", "[quic]") -// { -// Ptr block_4 = make_ptr(new_IOBufferBlock()); -// block_4->alloc(); -// block_4->fill(4); -// CHECK(block_4->read_avail() == 4); -// -// uint8_t stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; -// uint8_t stream_frame_delayed_buf[QUICFrame::MAX_INSTANCE_SIZE]; -// uint8_t stream_frame_with_fin_buf[QUICFrame::MAX_INSTANCE_SIZE]; -// uint8_t rst_stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; -// -// auto stream_frame = QUICFrameFactory::create_stream_frame(stream_frame_buf, block_4, 1, 0); -// auto stream_frame_delayed = QUICFrameFactory::create_stream_frame(stream_frame_delayed_buf, block_4, 1, 1); -// auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(stream_frame_with_fin_buf, block_4, 1, 2, true); -// auto rst_stream_frame = -// QUICFrameFactory::create_rst_stream_frame(rst_stream_frame_buf, 0, static_cast(0x01), 0); -// -// SECTION("QUICBidState idle -> open -> HC_R 1") -// { -// QUICBidirectionalStreamStateMachine ss; -// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); -// -// CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); -// ss.update_with_receiving_frame(*stream_frame); -// -// CHECK(ss.get() == QUICBidirectionalStreamState::Open); -// ss.update_with_receiving_frame(*stream_frame_with_fin); -// CHECK(ss.get() == QUICBidirectionalStreamState::Open); -// -// ss.update_on_transport_recv_event(); -// CHECK(ss.get() == QUICBidirectionalStreamState::HC_R); -// } -// -// SECTION("QUICBidState idle -> open -> HC_R 2") -// { -// QUICBidirectionalStreamStateMachine ss; -// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); -// -// CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); -// ss.update_with_receiving_frame(*stream_frame); -// -// CHECK(ss.get() == QUICBidirectionalStreamState::Open); -// ss.update_with_receiving_frame(*rst_stream_frame); -// CHECK(ss.get() == QUICBidirectionalStreamState::HC_R); -// } -// -// SECTION("QUICBidState idle -> open -> HC_L 1") -// { -// QUICBidirectionalStreamStateMachine ss; -// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); -// -// CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); -// ss.update_with_sending_frame(*stream_frame); -// -// CHECK(ss.get() == QUICBidirectionalStreamState::Open); -// ss.update_with_sending_frame(*stream_frame_with_fin); -// CHECK(ss.get() == QUICBidirectionalStreamState::Open); -// -// ss.update_on_transport_send_event(); -// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); -// -// ss.update_with_sending_frame(*stream_frame_delayed); -// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); -// } -// -// SECTION("QUICBidState idle -> open -> HC_L 2") -// { -// QUICBidirectionalStreamStateMachine ss; -// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); -// -// CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); -// ss.update_with_sending_frame(*stream_frame); -// -// CHECK(ss.get() == QUICBidirectionalStreamState::Open); -// ss.update_with_sending_frame(*rst_stream_frame); -// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); -// } -// -// SECTION("QUICBidState idle -> open -> closed 1") -// { -// QUICBidirectionalStreamStateMachine ss; -// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); -// -// CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); -// ss.update_with_sending_frame(*stream_frame); -// -// CHECK(ss.get() == QUICBidirectionalStreamState::Open); -// ss.update_with_sending_frame(*rst_stream_frame); -// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); -// -// CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); -// ss.update_with_receiving_frame(*stream_frame); -// -// ss.update_with_receiving_frame(*rst_stream_frame); -// CHECK(ss.get() == QUICBidirectionalStreamState::Closed); -// -// ss.update_on_user_read_event(); -// CHECK(ss.get() == QUICBidirectionalStreamState::Closed); -// } -// -// SECTION("QUICBidState idle -> open -> closed 2") -// { -// QUICBidirectionalStreamStateMachine ss; -// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); -// -// CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); -// ss.update_with_sending_frame(*stream_frame_with_fin); -// CHECK(ss.get() == QUICBidirectionalStreamState::Open); -// ss.update_on_transport_send_event(); -// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); -// -// CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); -// ss.update_with_receiving_frame(*stream_frame); -// -// ss.update_with_receiving_frame(*rst_stream_frame); -// CHECK(ss.get() == QUICBidirectionalStreamState::Closed); -// -// ss.update_on_user_read_event(); -// CHECK(ss.get() == QUICBidirectionalStreamState::Closed); -// } -// -// SECTION("QUICBidState idle -> open -> closed 3") -// { -// QUICBidirectionalStreamStateMachine ss; -// CHECK(ss.get() == QUICBidirectionalStreamState::Idle); -// -// CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); -// ss.update_with_sending_frame(*stream_frame_with_fin); -// CHECK(ss.get() == QUICBidirectionalStreamState::Open); -// ss.update_on_transport_send_event(); -// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); -// -// CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); -// ss.update_with_receiving_frame(*stream_frame); -// -// ss.update_with_receiving_frame(*stream_frame_with_fin); -// CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); -// -// ss.update_on_transport_recv_event(); -// CHECK(ss.get() == QUICBidirectionalStreamState::Closed); -// } -// } +TEST_CASE("QUICBidState", "[quic]") +{ + Ptr block_4 = make_ptr(new_IOBufferBlock()); + block_4->alloc(); + block_4->fill(4); + CHECK(block_4->read_avail() == 4); + + uint8_t stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t stream_frame_delayed_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t stream_frame_with_fin_buf[QUICFrame::MAX_INSTANCE_SIZE]; + uint8_t rst_stream_frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + + auto stream_frame = QUICFrameFactory::create_stream_frame(stream_frame_buf, block_4, 1, 0); + auto stream_frame_delayed = QUICFrameFactory::create_stream_frame(stream_frame_delayed_buf, block_4, 1, 1); + auto stream_frame_with_fin = QUICFrameFactory::create_stream_frame(stream_frame_with_fin_buf, block_4, 1, 2, true); + auto rst_stream_frame = + QUICFrameFactory::create_rst_stream_frame(rst_stream_frame_buf, 0, static_cast(0x01), 0); + + SECTION("QUICBidState idle -> open -> HC_R 1") + { + MockQUICTransferProgressProvider in_progress; + MockQUICTransferProgressProvider out_progress; + + QUICBidirectionalStreamStateMachine ss(nullptr, &out_progress, &in_progress, nullptr); + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + in_progress.set_transfer_complete(true); + ss.update_with_receiving_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_R); + } + + SECTION("QUICBidState idle -> open -> HC_R 2") + { + MockQUICTransferProgressProvider in_progress; + MockQUICTransferProgressProvider out_progress; + + QUICBidirectionalStreamStateMachine ss(nullptr, &out_progress, &in_progress, nullptr); + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + ss.update_with_receiving_frame(*rst_stream_frame); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_R); + } + + SECTION("QUICBidState idle -> open -> HC_L 1") + { + MockQUICTransferProgressProvider in_progress; + MockQUICTransferProgressProvider out_progress; + + QUICBidirectionalStreamStateMachine ss(nullptr, &out_progress, &in_progress, nullptr); + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame); + + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + ss.update_with_sending_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + + out_progress.set_transfer_complete(true); + ss.update_on_ack(); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + + ss.update_with_sending_frame(*stream_frame_delayed); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + } + + SECTION("QUICBidState idle -> open -> HC_L 2") + { + MockQUICTransferProgressProvider in_progress; + MockQUICTransferProgressProvider out_progress; + + QUICBidirectionalStreamStateMachine ss(nullptr, &out_progress, &in_progress, nullptr); + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame); + + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + ss.update_with_sending_frame(*rst_stream_frame); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + } + + SECTION("QUICBidState idle -> open -> closed 1") + { + MockQUICTransferProgressProvider in_progress; + MockQUICTransferProgressProvider out_progress; + + QUICBidirectionalStreamStateMachine ss(nullptr, &out_progress, &in_progress, nullptr); + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame); + + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + ss.update_with_sending_frame(*rst_stream_frame); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + + ss.update_with_receiving_frame(*rst_stream_frame); + CHECK(ss.get() == QUICBidirectionalStreamState::Closed); + + ss.update_on_eos(); + CHECK(ss.get() == QUICBidirectionalStreamState::Closed); + } + + SECTION("QUICBidState idle -> open -> closed 2") + { + MockQUICTransferProgressProvider in_progress; + MockQUICTransferProgressProvider out_progress; + + QUICBidirectionalStreamStateMachine ss(nullptr, &out_progress, &in_progress, nullptr); + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + out_progress.set_transfer_complete(true); + ss.update_on_ack(); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame); + + ss.update_with_receiving_frame(*rst_stream_frame); + CHECK(ss.get() == QUICBidirectionalStreamState::Closed); + + in_progress.set_transfer_complete(true); + ss.update_on_eos(); + CHECK(ss.get() == QUICBidirectionalStreamState::Closed); + } + + SECTION("QUICBidState idle -> open -> closed 3") + { + MockQUICTransferProgressProvider in_progress; + MockQUICTransferProgressProvider out_progress; + + QUICBidirectionalStreamStateMachine ss(nullptr, &out_progress, &in_progress, nullptr); + CHECK(ss.get() == QUICBidirectionalStreamState::Idle); + + CHECK(ss.is_allowed_to_send(QUICFrameType::STREAM)); + ss.update_with_sending_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICBidirectionalStreamState::Open); + out_progress.set_transfer_complete(true); + ss.update_on_ack(); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + + CHECK(ss.is_allowed_to_receive(QUICFrameType::STREAM)); + ss.update_with_receiving_frame(*stream_frame_delayed); + + ss.update_with_receiving_frame(*stream_frame_with_fin); + CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); + + in_progress.set_transfer_complete(true); + ss.update_on_read(); + CHECK(ss.get() == QUICBidirectionalStreamState::Closed); + } +} From f4b4625d4cc0c3b281de2bb85d00fad0dd65b402 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 19 Feb 2019 11:52:06 +0800 Subject: [PATCH 1147/1313] QUIC: Fixed QUICIncomingFrameBuffer test --- iocore/net/quic/QUICIncomingFrameBuffer.cc | 2 +- iocore/net/quic/QUICStreamState.h | 2 -- .../quic/test/test_QUICIncomingFrameBuffer.cc | 4 ---- iocore/net/quic/test/test_QUICStreamState.cc | 16 ++++++++-------- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index 519a749b683..1af365160f1 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -170,7 +170,7 @@ QUICIncomingStreamFrameBuffer::is_transfer_goal_set() const uint64_t QUICIncomingStreamFrameBuffer::transfer_progress() const { - return this->_recv_offset; + return this->_max_offset; } uint64_t diff --git a/iocore/net/quic/QUICStreamState.h b/iocore/net/quic/QUICStreamState.h index 7a7ad1246be..f95bfc04712 100644 --- a/iocore/net/quic/QUICStreamState.h +++ b/iocore/net/quic/QUICStreamState.h @@ -106,7 +106,6 @@ class QUICSendStreamStateMachine : public QUICUnidirectionalStreamStateMachine, QUICSendStreamStateMachine(QUICTransferProgressProvider *in, QUICTransferProgressProvider *out) : QUICUnidirectionalStreamStateMachine(in, out) { - ink_assert(out != nullptr); this->_set_state(QUICSendStreamState::Ready); } @@ -129,7 +128,6 @@ class QUICReceiveStreamStateMachine : public QUICUnidirectionalStreamStateMachin QUICReceiveStreamStateMachine(QUICTransferProgressProvider *in, QUICTransferProgressProvider *out) : QUICUnidirectionalStreamStateMachine(in, out) { - ink_assert(in != nullptr); } void update_with_sending_frame(const QUICFrame &frame) override; diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index bd2ae3a888c..7a5674325ef 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -168,7 +168,6 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") frame = static_cast(buffer.pop()); CHECK(frame->offset() == 4096); CHECK(buffer.empty()); - CHECK(buffer.has_all_data()); buffer.clear(); @@ -190,7 +189,6 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") frame = static_cast(buffer.pop()); CHECK(frame->offset() == 4096); CHECK(buffer.empty()); - CHECK(buffer.has_all_data()); delete stream; } @@ -238,7 +236,6 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") frame = static_cast(buffer.pop()); CHECK(frame == nullptr); CHECK(buffer.empty()); - CHECK(buffer.has_all_data()); buffer.clear(); @@ -262,7 +259,6 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") frame = static_cast(buffer.pop()); CHECK(frame == nullptr); CHECK(buffer.empty()); - CHECK(buffer.has_all_data()); delete stream; } diff --git a/iocore/net/quic/test/test_QUICStreamState.cc b/iocore/net/quic/test/test_QUICStreamState.cc index 0e753a6d026..b5538669d16 100644 --- a/iocore/net/quic/test/test_QUICStreamState.cc +++ b/iocore/net/quic/test/test_QUICStreamState.cc @@ -363,7 +363,7 @@ TEST_CASE("QUICReceiveStreamState", "[quic]") } } -TEST_CASE("QUICBidState", "[quic]") +TEST_CASE("QUICBidiState", "[quic]") { Ptr block_4 = make_ptr(new_IOBufferBlock()); block_4->alloc(); @@ -381,7 +381,7 @@ TEST_CASE("QUICBidState", "[quic]") auto rst_stream_frame = QUICFrameFactory::create_rst_stream_frame(rst_stream_frame_buf, 0, static_cast(0x01), 0); - SECTION("QUICBidState idle -> open -> HC_R 1") + SECTION("QUICBidiState idle -> open -> HC_R 1") { MockQUICTransferProgressProvider in_progress; MockQUICTransferProgressProvider out_progress; @@ -398,7 +398,7 @@ TEST_CASE("QUICBidState", "[quic]") CHECK(ss.get() == QUICBidirectionalStreamState::HC_R); } - SECTION("QUICBidState idle -> open -> HC_R 2") + SECTION("QUICBidiState idle -> open -> HC_R 2") { MockQUICTransferProgressProvider in_progress; MockQUICTransferProgressProvider out_progress; @@ -414,7 +414,7 @@ TEST_CASE("QUICBidState", "[quic]") CHECK(ss.get() == QUICBidirectionalStreamState::HC_R); } - SECTION("QUICBidState idle -> open -> HC_L 1") + SECTION("QUICBidiState idle -> open -> HC_L 1") { MockQUICTransferProgressProvider in_progress; MockQUICTransferProgressProvider out_progress; @@ -437,7 +437,7 @@ TEST_CASE("QUICBidState", "[quic]") CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); } - SECTION("QUICBidState idle -> open -> HC_L 2") + SECTION("QUICBidiState idle -> open -> HC_L 2") { MockQUICTransferProgressProvider in_progress; MockQUICTransferProgressProvider out_progress; @@ -453,7 +453,7 @@ TEST_CASE("QUICBidState", "[quic]") CHECK(ss.get() == QUICBidirectionalStreamState::HC_L); } - SECTION("QUICBidState idle -> open -> closed 1") + SECTION("QUICBidiState idle -> open -> closed 1") { MockQUICTransferProgressProvider in_progress; MockQUICTransferProgressProvider out_progress; @@ -478,7 +478,7 @@ TEST_CASE("QUICBidState", "[quic]") CHECK(ss.get() == QUICBidirectionalStreamState::Closed); } - SECTION("QUICBidState idle -> open -> closed 2") + SECTION("QUICBidiState idle -> open -> closed 2") { MockQUICTransferProgressProvider in_progress; MockQUICTransferProgressProvider out_progress; @@ -504,7 +504,7 @@ TEST_CASE("QUICBidState", "[quic]") CHECK(ss.get() == QUICBidirectionalStreamState::Closed); } - SECTION("QUICBidState idle -> open -> closed 3") + SECTION("QUICBidiState idle -> open -> closed 3") { MockQUICTransferProgressProvider in_progress; MockQUICTransferProgressProvider out_progress; From 6b10433908147e337f36ba2cc2cea95c9da18c55 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Feb 2019 17:22:28 +0900 Subject: [PATCH 1148/1313] Update for draft-18 --- iocore/net/QUICNetVConnection.cc | 6 +- iocore/net/quic/Mock.h | 4 +- iocore/net/quic/QUICAltConnectionManager.cc | 29 +++-- iocore/net/quic/QUICAltConnectionManager.h | 6 +- iocore/net/quic/QUICConfig.cc | 28 +++-- iocore/net/quic/QUICConfig.h | 13 +- iocore/net/quic/QUICTransportParameters.cc | 10 +- iocore/net/quic/QUICTypes.cc | 116 ++++++++++-------- iocore/net/quic/QUICTypes.h | 14 ++- .../test/test_QUICAltConnectionManager.cc | 55 ++++++--- .../net/quic/test/test_QUICPacketFactory.cc | 2 +- mgmt/RecordsConfig.cc | 4 +- src/tscore/ink_inet.cc | 4 +- 13 files changed, 179 insertions(+), 112 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 00031816bd3..e681230fe9b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1002,9 +1002,9 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe if (this->netvc_context == NET_VCONNECTION_IN) { if (!this->_alt_con_manager) { QUICConfig::scoped_config params; - this->_alt_con_manager = - new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, params->instance_id(), - params->num_alt_connection_ids(), params->preferred_address()); + this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, + params->instance_id(), params->num_alt_connection_ids(), + params->preferred_address_ipv4(), params->preferred_address_ipv6()); this->_frame_generators.push_back(this->_alt_con_manager); this->_frame_dispatcher->add_handler(this->_alt_con_manager); } diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 1210c822a14..d552394f21b 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -266,7 +266,7 @@ class MockQUICConnection : public QUICConnection std::string_view negotiated_application_name() const override { - return "h3-17"; + return "h3-18"; } int _transmit_count = 0; @@ -346,7 +346,7 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider std::string_view negotiated_application_name() const override { - return "h3-17"; + return "h3-18"; } }; diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 7a7980d8c7c..1e0574da53f 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -46,14 +46,15 @@ QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConne QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, QUICConnectionId peer_initial_cid, uint32_t instance_id, uint8_t num_alt_con, - const IpEndpoint *preferred_endpoint) + const IpEndpoint *preferred_endpoint_ipv4, + const IpEndpoint *preferred_endpoint_ipv6) : _qc(qc), _ctable(ctable), _instance_id(instance_id), _nids(num_alt_con) { // 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 = static_cast(ats_malloc(sizeof(AltConnectionInfo) * this->_nids)); - this->_init_alt_connection_ids(preferred_endpoint); + this->_init_alt_connection_ids(preferred_endpoint_ipv4, preferred_endpoint_ipv6); } QUICAltConnectionManager::~QUICAltConnectionManager() @@ -117,18 +118,32 @@ QUICAltConnectionManager::_generate_next_alt_con_info() } void -QUICAltConnectionManager::_init_alt_connection_ids(const IpEndpoint *preferred_endpoint) +QUICAltConnectionManager::_init_alt_connection_ids(const IpEndpoint *preferred_endpoint_ipv4, + const IpEndpoint *preferred_endpoint_ipv6) { - if (preferred_endpoint) { + if (preferred_endpoint_ipv4 || preferred_endpoint_ipv6) { this->_alt_quic_connection_ids_local[0] = this->_generate_next_alt_con_info(); // This alt cid will be advertised via Transport Parameter this->_alt_quic_connection_ids_local[0].advertised = true; - this->_preferred_address = new QUICPreferredAddress(*preferred_endpoint, this->_alt_quic_connection_ids_local[0].id, - this->_alt_quic_connection_ids_local[0].token); + IpEndpoint empty_endpoint_ipv4; + IpEndpoint empty_endpoint_ipv6; + empty_endpoint_ipv4.sa.sa_family = AF_UNSPEC; + empty_endpoint_ipv6.sa.sa_family = AF_UNSPEC; + if (preferred_endpoint_ipv4 == nullptr) { + preferred_endpoint_ipv4 = &empty_endpoint_ipv4; + } + if (preferred_endpoint_ipv6 == nullptr) { + preferred_endpoint_ipv6 = &empty_endpoint_ipv6; + } + + // FIXME Check nullptr dereference + this->_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); } - for (int i = (preferred_endpoint ? 1 : 0); i < this->_nids; ++i) { + for (int i = (preferred_endpoint_ipv4 || preferred_endpoint_ipv6 ? 1 : 0); i < this->_nids; ++i) { this->_alt_quic_connection_ids_local[i] = this->_generate_next_alt_con_info(); } this->_need_advertise = true; diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index de495278a2f..97086c5d8aa 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -44,7 +44,8 @@ class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenera * Constructor for servers */ QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, QUICConnectionId peer_initial_cid, uint32_t instance_id, - uint8_t num_alt_con, const IpEndpoint *preferred_endpoint = nullptr); + uint8_t num_alt_con, const IpEndpoint *preferred_endpoint_ipv4 = nullptr, + const IpEndpoint *preferred_endpoint_ipv6 = nullptr); ~QUICAltConnectionManager(); /** @@ -109,7 +110,8 @@ class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenera QUICPreferredAddress *_preferred_address = nullptr; AltConnectionInfo _generate_next_alt_con_info(); - void _init_alt_connection_ids(const IpEndpoint *preferred_endpoint = nullptr); + void _init_alt_connection_ids(const IpEndpoint *preferred_endpoint_ipv4 = nullptr, + const IpEndpoint *preferred_endpoint_ipv6 = nullptr); bool _update_alt_connection_id(uint64_t chosen_seq_num); void _records_new_connection_id_frame(QUICEncryptionLevel level, const QUICNewConnectionIdFrame &frame); diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index f7e15549eb8..8ec9e4f8b24 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -36,7 +36,7 @@ // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html // Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? using namespace std::literals; -static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-17"sv); +static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-18"sv); int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; @@ -146,9 +146,13 @@ QUICConfigParams::initialize() // Transport Parameters REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_in, "proxy.config.quic.no_activity_timeout_in"); REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_out, "proxy.config.quic.no_activity_timeout_out"); - REC_ReadConfigStringAlloc(this->_preferred_address, "proxy.config.quic.preferred_address"); - if (this->_preferred_address) { - ats_ip_pton(this->_preferred_address, &this->_preferred_endpoint); + REC_ReadConfigStringAlloc(this->_preferred_address_ipv4, "proxy.config.quic.preferred_address_ipv4"); + if (this->_preferred_address_ipv4) { + ats_ip_pton(this->_preferred_address_ipv4, &this->_preferred_endpoint_ipv4); + } + REC_ReadConfigStringAlloc(this->_preferred_address_ipv6, "proxy.config.quic.preferred_address_ipv6"); + if (this->_preferred_address_ipv6) { + ats_ip_pton(this->_preferred_address_ipv6, &this->_preferred_endpoint_ipv6); } REC_EstablishStaticConfigInt32U(this->_initial_max_data_in, "proxy.config.quic.initial_max_data_in"); REC_EstablishStaticConfigInt32U(this->_initial_max_data_out, "proxy.config.quic.initial_max_data_out"); @@ -207,13 +211,23 @@ QUICConfigParams::no_activity_timeout_out() const } const IpEndpoint * -QUICConfigParams::preferred_address() const +QUICConfigParams::preferred_address_ipv4() const +{ + if (!this->_preferred_address_ipv4) { + return nullptr; + } + + return &this->_preferred_endpoint_ipv4; +} + +const IpEndpoint * +QUICConfigParams::preferred_address_ipv6() const { - if (!this->_preferred_address) { + if (!this->_preferred_address_ipv6) { return nullptr; } - return &this->_preferred_endpoint; + return &this->_preferred_endpoint_ipv6; } uint32_t diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 306f544e9ef..f40e012bec9 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -51,7 +51,8 @@ class QUICConfigParams : public ConfigInfo // Transport Parameters uint32_t no_activity_timeout_in() const; uint32_t no_activity_timeout_out() const; - const IpEndpoint *preferred_address() const; + const IpEndpoint *preferred_address_ipv4() const; + const IpEndpoint *preferred_address_ipv6() const; uint32_t initial_max_data_in() const; uint32_t initial_max_data_out() const; uint32_t initial_max_stream_data_bidi_local_in() const; @@ -105,10 +106,12 @@ class QUICConfigParams : public ConfigInfo SSL_CTX *_client_ssl_ctx = nullptr; // Transport Parameters - uint32_t _no_activity_timeout_in = 0; - uint32_t _no_activity_timeout_out = 0; - const char *_preferred_address = nullptr; - IpEndpoint _preferred_endpoint; + uint32_t _no_activity_timeout_in = 0; + uint32_t _no_activity_timeout_out = 0; + const char *_preferred_address_ipv4 = nullptr; + const char *_preferred_address_ipv6 = nullptr; + IpEndpoint _preferred_endpoint_ipv4; + IpEndpoint _preferred_endpoint_ipv6; uint32_t _initial_max_data_in = 0; uint32_t _initial_max_data_out = 0; uint32_t _initial_max_stream_data_bidi_local_in = 0; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 0362c3f4c5a..8fe99cbe16d 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -300,12 +300,14 @@ QUICTransportParameters::_print() const QUICPreferredAddress pref_addr(p.second->data(), p.second->len()); char cid_hex_str[QUICConnectionId::MAX_HEX_STR_LENGTH]; char token_hex_str[QUICStatelessResetToken::LEN * 2 + 1]; - char ep_hex_str[512]; + char ep_ipv4_hex_str[512]; + char ep_ipv6_hex_str[512]; pref_addr.cid().hex(cid_hex_str, sizeof(cid_hex_str)); to_hex_str(token_hex_str, sizeof(token_hex_str), pref_addr.token().buf(), QUICStatelessResetToken::LEN); - ats_ip_nptop(pref_addr.endpoint(), ep_hex_str, sizeof(ep_hex_str)); - Debug(tag, "%s: Endpoint=%s, CID=%s, Token=%s", QUICDebugNames::transport_parameter_id(p.first), ep_hex_str, cid_hex_str, - token_hex_str); + ats_ip_nptop(pref_addr.endpoint_ipv4(), ep_ipv4_hex_str, sizeof(ep_ipv4_hex_str)); + ats_ip_nptop(pref_addr.endpoint_ipv6(), ep_ipv6_hex_str, sizeof(ep_ipv6_hex_str)); + Debug(tag, "%s: Endpoint(IPv4)=%s, Endpoint(IPv6)=%s, CID=%s, Token=%s", QUICDebugNames::transport_parameter_id(p.first), + ep_ipv4_hex_str, ep_ipv6_hex_str, cid_hex_str, token_hex_str); } else { Debug(tag, "%s: (long data)", QUICDebugNames::transport_parameter_id(p.first)); } diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index a826f47c96d..85dedd61f4e 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -366,40 +366,29 @@ QUICPreferredAddress::QUICPreferredAddress(const uint8_t *buf, uint16_t len) const uint8_t *p = buf; - // ipVersion - uint64_t type = p[0]; - p += 1; + // ipv4Address + in_addr_t addr_ipv4; + memcpy(&addr_ipv4, p, 4); + p += 4; + + // ipv4Port + in_port_t port_ipv4; + memcpy(&port_ipv4, p, 2); + p += 2; - // ipAddress - uint16_t addr_len = p[0]; - p += 1; - if (type == 4) { - if (addr_len == 4) { - in_addr_t addr; - memcpy(&addr, p, addr_len); - p += 4; - in_port_t port; - memcpy(&port, p, 2); - p += 2; - ats_ip4_set(&this->_endpoint, addr, port); - } else { - return; - } - } else if (type == 6) { - if (addr_len == TS_IP6_SIZE) { - in6_addr addr; - memcpy(&addr, p, addr_len); - p += TS_IP6_SIZE; - in_port_t port; - memcpy(&port, p, 2); - p += 2; - ats_ip6_set(&this->_endpoint, addr, port); - } else { - return; - } - } else { - return; - } + ats_ip4_set(&this->_endpoint_ipv4, addr_ipv4, port_ipv4); + + // ipv6Address + in6_addr addr_ipv6; + memcpy(&addr_ipv6, p, 16); + p += TS_IP6_SIZE; + + // ipv6Port + in_port_t port_ipv6; + memcpy(&port_ipv6, p, 2); + p += 2; + + ats_ip6_set(&this->_endpoint_ipv6, addr_ipv6, port_ipv6); // CID uint16_t cid_len = QUICIntUtil::read_nbytes_as_uint(p, 1); @@ -419,10 +408,28 @@ QUICPreferredAddress::is_available() const return this->_valid; } +bool +QUICPreferredAddress::has_ipv4() const +{ + return this->_endpoint_ipv4.isValid(); +} + +bool +QUICPreferredAddress::has_ipv6() const +{ + return this->_endpoint_ipv6.isValid(); +} + +const IpEndpoint +QUICPreferredAddress::endpoint_ipv4() const +{ + return this->_endpoint_ipv4; +} + const IpEndpoint -QUICPreferredAddress::endpoint() const +QUICPreferredAddress::endpoint_ipv6() const { - return this->_endpoint; + return this->_endpoint_ipv6; } const QUICConnectionId @@ -443,30 +450,31 @@ QUICPreferredAddress::store(uint8_t *buf, uint16_t &len) const size_t dummy; uint8_t *p = buf; - // ipVersion - if (this->_endpoint.isIp4()) { - p[0] = 4; - } else if (this->_endpoint.isIp6()) { - p[0] = 6; + if (this->_endpoint_ipv4.isValid()) { + // ipv4Address + memcpy(p, &ats_ip4_addr_cast(this->_endpoint_ipv4), 4); + p += 4; + + // ipv4Port + memcpy(p, &ats_ip_port_cast(this->_endpoint_ipv4), 2); + p += 2; } else { - return; + memset(p, 0, 6); + p += 6; } - p += 1; - // ipAddress - size_t addr_len = ats_ip_addr_size(this->_endpoint); - p[0] = addr_len; - p += 1; - if (this->_endpoint.isIp4()) { - memcpy(p, &ats_ip4_addr_cast(this->_endpoint), addr_len); + if (this->_endpoint_ipv6.isValid()) { + // ipv6Address + memcpy(p, &ats_ip6_addr_cast(this->_endpoint_ipv6), 16); + p += 16; + + // ipv6Port + memcpy(p, &ats_ip_port_cast(this->_endpoint_ipv6), 2); + p += 2; } else { - memcpy(p, &ats_ip6_addr_cast(this->_endpoint), addr_len); + memset(p, 0, 18); + p += 18; } - p += addr_len; - - // port - memcpy(p, &ats_ip_port_cast(this->_endpoint), 2); - p += 2; // CID uint8_t cid_len = this->_cid.length(); diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 31fe659b5d2..44515814785 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -50,7 +50,7 @@ using QUICOffset = uint64_t; // Note: Fix QUIC_ALPN_PROTO_LIST in QUICConfig.cc // Note: Change ExtensionType (QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID) if it's changed constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff000011, + 0xff000012, }; constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; @@ -399,21 +399,25 @@ class QUICPreferredAddress constexpr static int16_t MIN_LEN = 26; constexpr static int16_t MAX_LEN = 295; - QUICPreferredAddress(IpEndpoint endpoint, QUICConnectionId cid, QUICStatelessResetToken token) - : _endpoint(endpoint), _cid(cid), _token(token), _valid(true) + QUICPreferredAddress(IpEndpoint endpoint_ipv4, IpEndpoint endpoint_ipv6, QUICConnectionId cid, QUICStatelessResetToken token) + : _endpoint_ipv4(endpoint_ipv4), _endpoint_ipv6(endpoint_ipv6), _cid(cid), _token(token), _valid(true) { } QUICPreferredAddress(const uint8_t *buf, uint16_t len); bool is_available() const; - const IpEndpoint endpoint() const; + bool has_ipv4() const; + bool has_ipv6() const; + const IpEndpoint endpoint_ipv4() const; + const IpEndpoint endpoint_ipv6() const; const QUICConnectionId cid() const; const QUICStatelessResetToken token() const; void store(uint8_t *buf, uint16_t &len) const; private: - IpEndpoint _endpoint; + IpEndpoint _endpoint_ipv4; + IpEndpoint _endpoint_ipv6; QUICConnectionId _cid; QUICStatelessResetToken _token; bool _valid = false; diff --git a/iocore/net/quic/test/test_QUICAltConnectionManager.cc b/iocore/net/quic/test/test_QUICAltConnectionManager.cc index 5c1bdca43fc..d30da7b390a 100644 --- a/iocore/net/quic/test/test_QUICAltConnectionManager.cc +++ b/iocore/net/quic/test/test_QUICAltConnectionManager.cc @@ -29,40 +29,55 @@ TEST_CASE("QUICPreferredAddress", "[quic]") { - const uint8_t buf[] = { - 0x04, // ipVersion - 0x04, // ipAddress length - 0x01, 0x02, 0x03, 0x04, // ipAddress - 0x11, 0x22, // port - 0x01, // connectionId length - 0x55, // connectionId - 0x10, 0x11, 0x12, 0x13, // statelessResetToken - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + uint8_t buf[] = { + 0x12, 0x34, 0x56, 0x78, // IPv4 address + 0x23, 0x45, // IPv4 port + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, // IPv6 address + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x34, 0x56, // IPv6 port + 0x01, // ConnectionId length + 0x55, // ConnectionId + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, // Stateless Reset Token + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, }; uint8_t cid_buf[] = {0x55}; QUICConnectionId cid55(cid_buf, sizeof(cid_buf)); + in6_addr ipv6_addr; + memcpy(ipv6_addr.s6_addr, "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", 16); SECTION("load") { auto pref_addr = new QUICPreferredAddress(buf, sizeof(buf)); CHECK(pref_addr->is_available()); - CHECK(pref_addr->endpoint().isIp4()); - CHECK(pref_addr->endpoint().host_order_port() == 0x1122); - CHECK(pref_addr->endpoint().sin.sin_addr.s_addr == 0x04030201); + CHECK(pref_addr->has_ipv4()); + CHECK(pref_addr->endpoint_ipv4().isIp4()); + CHECK(pref_addr->endpoint_ipv4().host_order_port() == 0x2345); + CHECK(pref_addr->endpoint_ipv4().sin.sin_addr.s_addr == 0x78563412); + CHECK(pref_addr->has_ipv6()); + CHECK(pref_addr->endpoint_ipv6().isIp6()); + CHECK(pref_addr->endpoint_ipv6().host_order_port() == 0x3456); + CHECK(memcmp(pref_addr->endpoint_ipv6().sin6.sin6_addr.s6_addr, ipv6_addr.s6_addr, 16) == 0); CHECK(pref_addr->cid() == cid55); - CHECK(memcmp(pref_addr->token().buf(), buf + 10, 16) == 0); + CHECK(memcmp(pref_addr->token().buf(), buf + 26, 16) == 0); } SECTION("store") { - IpEndpoint ep; - ats_ip4_set(&ep, 0x04030201, 0x2211); + IpEndpoint ep_ipv4; + ats_ip4_set(&ep_ipv4, 0x78563412, 0x4523); - auto pref_addr = new QUICPreferredAddress(ep, cid55, {buf + 10}); + IpEndpoint ep_ipv6; + ats_ip6_set(&ep_ipv6, ipv6_addr, 0x5634); + + auto pref_addr = new QUICPreferredAddress(ep_ipv4, ep_ipv6, cid55, {buf + 26}); CHECK(pref_addr->is_available()); - CHECK(pref_addr->endpoint().isIp4()); - CHECK(pref_addr->endpoint().host_order_port() == 0x1122); - CHECK(pref_addr->endpoint().sin.sin_addr.s_addr == 0x04030201); + CHECK(pref_addr->has_ipv4()); + CHECK(pref_addr->endpoint_ipv4().isIp4()); + CHECK(pref_addr->endpoint_ipv4().host_order_port() == 0x2345); + CHECK(pref_addr->endpoint_ipv4().sin.sin_addr.s_addr == 0x78563412); + CHECK(pref_addr->has_ipv6()); + CHECK(pref_addr->endpoint_ipv6().isIp6()); + CHECK(pref_addr->endpoint_ipv6().host_order_port() == 0x3456); + CHECK(memcmp(pref_addr->endpoint_ipv6().sin6.sin6_addr.s6_addr, ipv6_addr.s6_addr, 16) == 0); CHECK(pref_addr->cid() == cid55); uint8_t actual[QUICPreferredAddress::MAX_LEN]; @@ -76,5 +91,7 @@ TEST_CASE("QUICPreferredAddress", "[quic]") { auto pref_addr = new QUICPreferredAddress(nullptr, 0); CHECK(!pref_addr->is_available()); + CHECK(!pref_addr->has_ipv4()); + CHECK(!pref_addr->has_ipv6()); } } diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index dd1f057c08c..35995f3d3db 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -53,7 +53,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x55, // DCIL/SCIL 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Destination Connection ID 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection ID - 0xff, 0x00, 0x00, 0x11, // Supported Version + 0xff, 0x00, 0x00, 0x12, // Supported Version }; uint8_t buf[1024] = {0}; size_t buf_len; diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 150ba24eb9f..3bfbda48931 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1375,7 +1375,9 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_out", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.preferred_address", RECD_STRING, nullptr , RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.preferred_address_ipv4", RECD_STRING, nullptr , RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} + , + {RECT_CONFIG, "proxy.config.quic.preferred_address_ipv6", RECD_STRING, nullptr , RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.initial_max_data_in", RECD_INT, "65536", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , diff --git a/src/tscore/ink_inet.cc b/src/tscore/ink_inet.cc index 681191ebdd5..429f52ac075 100644 --- a/src/tscore/ink_inet.cc +++ b/src/tscore/ink_inet.cc @@ -50,8 +50,8 @@ const std::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"sv); const std::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"sv); const std::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"sv); const std::string_view IP_PROTO_TAG_HTTP_2_0("h2"sv); // HTTP/2 over TLS -const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-17"sv); // HTTP/0.9 over QUIC -const std::string_view IP_PROTO_TAG_HTTP_3("h3-17"sv); // HTTP/3 over QUIC +const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-18"sv); // HTTP/0.9 over QUIC +const std::string_view IP_PROTO_TAG_HTTP_3("h3-18"sv); // HTTP/3 over QUIC const std::string_view UNIX_PROTO_TAG{"unix"sv}; From f574354d0035d0094e3939a942a5e08c8bbc5d97 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 25 Feb 2019 11:11:14 +0900 Subject: [PATCH 1149/1313] Fix compile warning on Fedora29 --- iocore/net/quic/QUICFrame.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index f0fc83a13d6..c0924293224 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -139,7 +139,8 @@ QUICStreamFrame::QUICStreamFrame(const uint8_t *buf, size_t len) } QUICStreamFrame::QUICStreamFrame(const QUICStreamFrame &o) - : _block(make_ptr(o._block->clone())), + : QUICFrame(o), + _block(make_ptr(o._block->clone())), _stream_id(o._stream_id), _offset(o._offset), _fin(o._fin), @@ -371,7 +372,8 @@ QUICCryptoFrame::QUICCryptoFrame(const uint8_t *buf, size_t len) this->parse(buf, len); } -QUICCryptoFrame::QUICCryptoFrame(const QUICCryptoFrame &o) : _offset(o._offset), _block(make_ptr(o._block->clone())) +QUICCryptoFrame::QUICCryptoFrame(const QUICCryptoFrame &o) + : QUICFrame(o), _offset(o._offset), _block(make_ptr(o._block->clone())) { } From 4462afc9ff7cf62006db56d0093a4bc8b5c9eeae Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 25 Feb 2019 14:54:31 +0900 Subject: [PATCH 1150/1313] Fix memory leaks in QUICIncomingFrameBuffer --- iocore/net/quic/QUICIncomingFrameBuffer.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iocore/net/quic/QUICIncomingFrameBuffer.cc b/iocore/net/quic/QUICIncomingFrameBuffer.cc index 1af365160f1..154563f4278 100644 --- a/iocore/net/quic/QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/QUICIncomingFrameBuffer.cc @@ -95,16 +95,19 @@ QUICIncomingStreamFrameBuffer::insert(const QUICFrame *frame) QUICConnectionErrorUPtr err = this->_check_and_set_fin_flag(offset, len, stream_frame->has_fin_flag()); if (err != nullptr) { + delete frame; return err; } // Ignore empty stream frame except pure fin stream frame if (len == 0 && !stream_frame->has_fin_flag()) { + delete frame; return nullptr; } if (this->_recv_offset > offset) { // dup frame; + delete frame; return nullptr; } else if (this->_recv_offset == offset) { this->_recv_offset = offset + len; @@ -227,11 +230,13 @@ QUICIncomingCryptoFrameBuffer::insert(const QUICFrame *frame) // Ignore empty stream frame if (len == 0) { + delete frame; return nullptr; } if (this->_recv_offset > offset) { // dup frame; + delete frame; return nullptr; } else if (this->_recv_offset == offset) { this->_recv_offset = offset + len; From e6a9def4e848f9314029b7ab3ee917a42daf2d92 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 26 Feb 2019 15:07:03 +0900 Subject: [PATCH 1151/1313] Don't send multiple PATH_CHALLENGE on the same packet This closes #5064 --- iocore/net/P_QUICNetVConnection.h | 6 ++--- iocore/net/QUICNetVConnection.cc | 27 +++++++++++++-------- iocore/net/quic/QUICAckFrameCreator.cc | 4 +-- iocore/net/quic/QUICAckFrameCreator.h | 6 ++--- iocore/net/quic/QUICAltConnectionManager.cc | 4 +-- iocore/net/quic/QUICAltConnectionManager.h | 6 ++--- iocore/net/quic/QUICFlowController.cc | 4 +-- iocore/net/quic/QUICFlowController.h | 6 ++--- iocore/net/quic/QUICFrameGenerator.h | 4 +-- iocore/net/quic/QUICHandshake.cc | 10 +++++--- iocore/net/quic/QUICHandshake.h | 6 ++--- iocore/net/quic/QUICPathValidator.cc | 10 ++++++-- iocore/net/quic/QUICPathValidator.h | 7 +++--- iocore/net/quic/QUICPinger.cc | 5 ++-- iocore/net/quic/QUICPinger.h | 6 ++--- iocore/net/quic/QUICStream.cc | 13 +++++----- iocore/net/quic/QUICStream.h | 12 ++++----- iocore/net/quic/QUICStreamManager.cc | 9 ++++--- iocore/net/quic/QUICStreamManager.h | 6 ++--- 19 files changed, 85 insertions(+), 66 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index e35c54c58cb..7ad5199cea6 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -220,9 +220,9 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_frame_size) override; + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; int in_closed_queue = 0; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e681230fe9b..5806b5ca712 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -630,9 +630,10 @@ QUICNetVConnection::state_handshake(int event, Event *data) break; } case QUIC_EVENT_ACK_PERIODIC: { - bool need_schedule = false; + ink_hrtime timestamp = Thread::get_hrtime(); + bool need_schedule = false; for (auto level : QUIC_ENCRYPTION_LEVELS) { - if (this->_ack_frame_manager.will_generate_frame(level)) { + if (this->_ack_frame_manager.will_generate_frame(level, timestamp)) { need_schedule = true; break; } @@ -688,9 +689,10 @@ QUICNetVConnection::state_connection_established(int event, Event *data) break; } case QUIC_EVENT_ACK_PERIODIC: { - bool need_schedule = false; + ink_hrtime timestamp = Thread::get_hrtime(); + bool need_schedule = false; for (auto level : QUIC_ENCRYPTION_LEVELS) { - if (this->_ack_frame_manager.will_generate_frame(level)) { + if (this->_ack_frame_manager.will_generate_frame(level, timestamp)) { need_schedule = true; break; } @@ -1336,6 +1338,8 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t & QUICPacketUPtr QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size) { + ink_hrtime timestamp = Thread::get_hrtime(); + QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); if (max_packet_size <= MAX_PACKET_OVERHEAD) { return packet; @@ -1367,9 +1371,9 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa uint8_t frame_instance_buffer[QUICFrame::MAX_INSTANCE_SIZE]; // This is for a frame instance but not serialized frame data QUICFrame *frame = nullptr; for (auto g : this->_frame_generators) { - while (g->will_generate_frame(level)) { + while (g->will_generate_frame(level, timestamp)) { // FIXME will_generate_frame should receive more parameters so we don't need extra checks - if (g == this->_remote_flow_controller && !this->_stream_manager->will_generate_frame(level)) { + if (g == this->_remote_flow_controller && !this->_stream_manager->will_generate_frame(level, timestamp)) { break; } if (g == this->_stream_manager && this->_path_validator->is_validating()) { @@ -1377,7 +1381,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } // Common block - frame = g->generate_frame(frame_instance_buffer, level, this->_remote_flow_controller->credit(), max_frame_size); + frame = g->generate_frame(frame_instance_buffer, level, this->_remote_flow_controller->credit(), max_frame_size, timestamp); if (frame) { ++frame_count; probing |= frame->is_probing_frame(); @@ -2102,11 +2106,13 @@ QUICNetVConnection::_state_connection_established_initiate_connection_migration( ink_assert(this->netvc_context == NET_VCONNECTION_OUT); QUICConnectionErrorUPtr error = nullptr; + ink_hrtime timestamp = Thread::get_hrtime(); std::shared_ptr remote_tp = this->_handshake_handler->remote_transport_parameters(); if (this->_connection_migration_initiated || remote_tp->contains(QUICTransportParameterId::DISABLE_MIGRATION) || - !this->_alt_con_manager->is_ready_to_migrate() || this->_alt_con_manager->will_generate_frame(QUICEncryptionLevel::ONE_RTT)) { + !this->_alt_con_manager->is_ready_to_migrate() || + this->_alt_con_manager->will_generate_frame(QUICEncryptionLevel::ONE_RTT, timestamp)) { return error; } @@ -2139,7 +2145,7 @@ QUICNetVConnection::_handle_path_validation_timeout(Event *data) // QUICFrameGenerator bool -QUICNetVConnection::will_generate_frame(QUICEncryptionLevel level) +QUICNetVConnection::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { if (!this->_is_level_matched(level)) { return false; @@ -2149,7 +2155,8 @@ QUICNetVConnection::will_generate_frame(QUICEncryptionLevel level) } QUICFrame * -QUICNetVConnection::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICNetVConnection::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) { QUICFrame *frame = nullptr; diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index db93cd21853..e60183e8171 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -62,7 +62,7 @@ QUICAckFrameManager::update(QUICEncryptionLevel level, QUICPacketNumber packet_n */ QUICFrame * QUICAckFrameManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, - uint16_t maximum_frame_size) + uint16_t maximum_frame_size, ink_hrtime timestamp) { QUICAckFrame *ack_frame = nullptr; @@ -88,7 +88,7 @@ QUICAckFrameManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uin } bool -QUICAckFrameManager::will_generate_frame(QUICEncryptionLevel level) +QUICAckFrameManager::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { // No ACK frame on ZERO_RTT level if (!this->_is_level_matched(level) || level == QUICEncryptionLevel::ZERO_RTT) { diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 2f88649c426..c9ea683a9f7 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -101,13 +101,13 @@ class QUICAckFrameManager : public QUICFrameGenerator /* * Returns true only if should send ack. */ - bool will_generate_frame(QUICEncryptionLevel level) override; + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; /* * Calls create directly. */ - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_frame_size) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; QUICFrameId issue_frame_id(); uint8_t ack_delay_exponent() const; diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index 1e0574da53f..ae6d65671e2 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -266,7 +266,7 @@ QUICAltConnectionManager::invalidate_alt_connections() } bool -QUICAltConnectionManager::will_generate_frame(QUICEncryptionLevel level) +QUICAltConnectionManager::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { if (!this->_is_level_matched(level)) { return false; @@ -280,7 +280,7 @@ QUICAltConnectionManager::will_generate_frame(QUICEncryptionLevel level) */ QUICFrame * QUICAltConnectionManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, - uint16_t maximum_frame_size) + uint16_t maximum_frame_size, ink_hrtime timestamp) { QUICFrame *frame = nullptr; if (!this->_is_level_matched(level)) { diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index 97086c5d8aa..f16f2ba5bd4 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -83,9 +83,9 @@ class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenera virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_frame_size) override; + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; private: struct AltConnectionInfo { diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc index 84f120a9e42..7c2e3db9e0b 100644 --- a/iocore/net/quic/QUICFlowController.cc +++ b/iocore/net/quic/QUICFlowController.cc @@ -96,7 +96,7 @@ QUICFlowController::set_limit(QUICOffset limit) // For RemoteFlowController, caller of this function should also check QUICStreamManager::will_generate_frame() bool -QUICFlowController::will_generate_frame(QUICEncryptionLevel level) +QUICFlowController::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { if (!this->_is_level_matched(level)) { return false; @@ -110,7 +110,7 @@ QUICFlowController::will_generate_frame(QUICEncryptionLevel level) */ QUICFrame * QUICFlowController::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, - uint16_t maximum_frame_size) + uint16_t maximum_frame_size, ink_hrtime timestamp) { QUICFrame *frame = nullptr; diff --git a/iocore/net/quic/QUICFlowController.h b/iocore/net/quic/QUICFlowController.h index 3e59b997cc6..c3cb6371139 100644 --- a/iocore/net/quic/QUICFlowController.h +++ b/iocore/net/quic/QUICFlowController.h @@ -60,9 +60,9 @@ class QUICFlowController : public QUICFrameGenerator virtual void set_limit(QUICOffset limit); // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_frame_size) override; + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; protected: QUICFlowController(uint64_t initial_limit) : _limit(initial_limit) {} diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index 9c34d5750e0..af04928d89d 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -30,14 +30,14 @@ class QUICFrameGenerator { public: virtual ~QUICFrameGenerator(){}; - virtual bool will_generate_frame(QUICEncryptionLevel level) = 0; + virtual bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) = 0; /* * This function constructs an instance of QUICFrame on buf. * It returns a pointer for the frame if it succeeded, and returns nullptr if it failed. */ virtual QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_frame_size) = 0; + uint16_t maximum_frame_size, ink_hrtime timestamp) = 0; void on_frame_acked(QUICFrameId id); void on_frame_lost(QUICFrameId id); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index dfd6ed1450c..2a96af3bf63 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -337,22 +337,24 @@ QUICHandshake::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) } bool -QUICHandshake::will_generate_frame(QUICEncryptionLevel level) +QUICHandshake::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { if (!this->_is_level_matched(level)) { return false; } - return this->_crypto_streams[static_cast(level)].will_generate_frame(level); + return this->_crypto_streams[static_cast(level)].will_generate_frame(level, timestamp); } QUICFrame * -QUICHandshake::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICHandshake::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) { QUICFrame *frame = nullptr; if (this->_is_level_matched(level)) { - frame = this->_crypto_streams[static_cast(level)].generate_frame(buf, level, connection_credit, maximum_frame_size); + frame = + this->_crypto_streams[static_cast(level)].generate_frame(buf, level, connection_credit, maximum_frame_size, timestamp); } return frame; diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 56436b6d1c6..e97eea386c4 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -51,9 +51,9 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_frame_size) override; + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; // for client side QUICConnectionErrorUPtr start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled); diff --git a/iocore/net/quic/QUICPathValidator.cc b/iocore/net/quic/QUICPathValidator.cc index 4436f583857..40a23904886 100644 --- a/iocore/net/quic/QUICPathValidator.cc +++ b/iocore/net/quic/QUICPathValidator.cc @@ -117,12 +117,16 @@ QUICPathValidator::handle_frame(QUICEncryptionLevel level, const QUICFrame &fram // QUICFrameGenerator // bool -QUICPathValidator::will_generate_frame(QUICEncryptionLevel level) +QUICPathValidator::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { if (!this->_is_level_matched(level)) { return false; } + if (this->_last_sent_at == timestamp) { + return false; + } + return (this->_has_outgoing_challenge || this->_has_outgoing_response); } @@ -131,7 +135,7 @@ QUICPathValidator::will_generate_frame(QUICEncryptionLevel level) */ QUICFrame * QUICPathValidator::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, - uint16_t maximum_frame_size) + uint16_t maximum_frame_size, ink_hrtime timestamp) { QUICFrame *frame = nullptr; @@ -159,5 +163,7 @@ QUICPathValidator::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint6 } } + this->_last_sent_at = timestamp; + return frame; } diff --git a/iocore/net/quic/QUICPathValidator.h b/iocore/net/quic/QUICPathValidator.h index d79d5f68ac2..47a2975d108 100644 --- a/iocore/net/quic/QUICPathValidator.h +++ b/iocore/net/quic/QUICPathValidator.h @@ -41,9 +41,9 @@ class QUICPathValidator : public QUICFrameHandler, public QUICFrameGenerator QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICFrameGeneratro - bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_frame_size) override; + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; private: enum class ValidationState : int { @@ -54,6 +54,7 @@ class QUICPathValidator : public QUICFrameHandler, public QUICFrameGenerator ValidationState _state = ValidationState::NOT_VALIDATED; int _has_outgoing_challenge = 0; bool _has_outgoing_response = false; + ink_hrtime _last_sent_at = 0; uint8_t _incoming_challenge[QUICPathChallengeFrame::DATA_LEN]; uint8_t _outgoing_challenge[QUICPathChallengeFrame::DATA_LEN * 3]; diff --git a/iocore/net/quic/QUICPinger.cc b/iocore/net/quic/QUICPinger.cc index eb892bc133d..e1a70ee0f4b 100644 --- a/iocore/net/quic/QUICPinger.cc +++ b/iocore/net/quic/QUICPinger.cc @@ -45,7 +45,7 @@ QUICPinger::cancel(QUICEncryptionLevel level) } bool -QUICPinger::will_generate_frame(QUICEncryptionLevel level) +QUICPinger::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { if (!this->_is_level_matched(level)) { return false; @@ -58,7 +58,8 @@ QUICPinger::will_generate_frame(QUICEncryptionLevel level) * @param connection_credit This is not used. Because PING frame is not flow-controlled */ QUICFrame * -QUICPinger::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, uint16_t maximum_frame_size) +QUICPinger::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, uint16_t maximum_frame_size, + ink_hrtime timestamp) { QUICFrame *frame = nullptr; diff --git a/iocore/net/quic/QUICPinger.h b/iocore/net/quic/QUICPinger.h index 80098e8b444..26b967dbe4c 100644 --- a/iocore/net/quic/QUICPinger.h +++ b/iocore/net/quic/QUICPinger.h @@ -37,9 +37,9 @@ class QUICPinger : public QUICFrameGenerator void cancel(QUICEncryptionLevel level); // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_frame_size) override; + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; private: // Initial, 0/1-RTT, and Handshake diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 608fb4dd2e6..401382c1660 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -411,13 +411,14 @@ QUICStream::recv(const QUICRstStreamFrame &frame) } bool -QUICStream::will_generate_frame(QUICEncryptionLevel level) +QUICStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { return this->_write_vio.get_reader()->read_avail() > 0; } QUICFrame * -QUICStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) { SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); @@ -448,7 +449,7 @@ QUICStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t con } // MAX_STREAM_DATA - frame = this->_local_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size); + frame = this->_local_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size, timestamp); if (frame) { return frame; } @@ -484,7 +485,7 @@ QUICStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t con uint64_t stream_credit = this->_remote_flow_controller.credit(); if (stream_credit == 0) { // STREAM_DATA_BLOCKED - frame = this->_remote_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size); + frame = this->_remote_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size, timestamp); return frame; } @@ -871,7 +872,7 @@ QUICCryptoStream::write(const uint8_t *buf, int64_t len) } bool -QUICCryptoStream::will_generate_frame(QUICEncryptionLevel level) +QUICCryptoStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { return this->_write_buffer_reader->is_read_avail_more_than(0); } @@ -881,7 +882,7 @@ QUICCryptoStream::will_generate_frame(QUICEncryptionLevel level) */ QUICFrame * QUICCryptoStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, - uint16_t maximum_frame_size) + uint16_t maximum_frame_size, ink_hrtime timestamp) { QUICConnectionErrorUPtr error = nullptr; diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 62763a99dc4..b40e47159b1 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -91,9 +91,9 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra LINK(QUICStream, link); // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_frame_size) override; + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; // QUICTransferProgressProvider bool is_transfer_goal_set() const override; @@ -186,9 +186,9 @@ class QUICCryptoStream : public QUICFrameGenerator, public QUICFrameRetransmitte LINK(QUICStream, link); // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_frame_size) override; + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; private: void _on_frame_acked(QUICFrameInformationUPtr &info) override; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index ea99d3f1fbf..30d043dead2 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -386,7 +386,7 @@ QUICStreamManager::set_default_application(QUICApplication *app) } bool -QUICStreamManager::will_generate_frame(QUICEncryptionLevel level) +QUICStreamManager::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { if (!this->_is_level_matched(level)) { return false; @@ -398,7 +398,7 @@ QUICStreamManager::will_generate_frame(QUICEncryptionLevel level) } for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { - if (s->will_generate_frame(level)) { + if (s->will_generate_frame(level, timestamp)) { return true; } } @@ -407,7 +407,8 @@ QUICStreamManager::will_generate_frame(QUICEncryptionLevel level) } QUICFrame * -QUICStreamManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) +QUICStreamManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) { QUICFrame *frame = nullptr; @@ -422,7 +423,7 @@ QUICStreamManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint6 // FIXME We should pick a stream based on priority for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { - frame = s->generate_frame(buf, level, connection_credit, maximum_frame_size); + frame = s->generate_frame(buf, level, connection_credit, maximum_frame_size, timestamp); if (frame) { break; } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 4277f5c5f6f..eeabf1d9417 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -64,9 +64,9 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level) override; - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_frame_size) override; + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; private: QUICStream *_find_stream(QUICStreamId id); From fba23d972c9f551960de0e61ca1512c22fd9522c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Feb 2019 18:15:29 +0900 Subject: [PATCH 1152/1313] Introduce QUICPacketProtectionKeyInfo --- iocore/net/P_QUICNetVConnection.h | 4 +- iocore/net/QUICNetVConnection.cc | 4 +- iocore/net/quic/QUICHandshakeProtocol.cc | 1 + iocore/net/quic/QUICHandshakeProtocol.h | 6 ++- iocore/net/quic/QUICPacketFactory.cc | 2 + iocore/net/quic/QUICPacketFactory.h | 6 +++ iocore/net/quic/QUICPacketHeaderProtector.h | 5 +++ iocore/net/quic/QUICPacketProtectionKeyInfo.h | 38 +++++++++++++++++++ iocore/net/quic/QUICTLS.h | 2 +- iocore/net/quic/QUICTLS_openssl.cc | 4 +- 10 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 iocore/net/quic/QUICPacketProtectionKeyInfo.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 7ad5199cea6..4c18ac4c6a0 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -60,6 +60,7 @@ #include "quic/QUICApplicationMap.h" #include "quic/QUICPacketReceiveQueue.h" #include "quic/QUICAddrVerifyState.h" +#include "quic/QUICPacketProtectionKeyInfo.h" // These are included here because older OpenQUIC libraries don't have them. // Don't copy these defines, or use their values directly, they are merely @@ -246,7 +247,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub char _cids_data[MAX_CIDS_SIZE] = {0}; std::string_view _cids; - UDPConnection *_udp_con = nullptr; + UDPConnection *_udp_con = nullptr; + QUICPacketProtectionKeyInfo _pp_key_info; QUICPacketHandler *_packet_handler = nullptr; QUICPacketFactory _packet_factory; QUICFrameFactory _frame_factory; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5806b5ca712..e6f94b67542 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -74,7 +74,7 @@ static constexpr uint32_t STATE_CLOSING_MAX_RECV_PKT_WIND = 1 << STATE_CLOSING_M ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); -QUICNetVConnection::QUICNetVConnection() {} +QUICNetVConnection::QUICNetVConnection() : _packet_factory(this->_pp_key_info), _ph_protector(this->_pp_key_info) {} QUICNetVConnection::~QUICNetVConnection() { @@ -2039,7 +2039,7 @@ QUICNetVConnection::_setup_handshake_protocol(SSL_CTX *ctx) { // Initialize handshake protocol specific stuff // For QUICv1 TLS is the only option - QUICTLS *tls = new QUICTLS(ctx, this->direction()); + QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx, this->direction()); SSL_set_ex_data(tls->ssl_handle(), QUIC::ssl_quic_qc_index, static_cast(this)); return tls; } diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc index 8fa07012819..9f65c1e307e 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ b/iocore/net/quic/QUICHandshakeProtocol.cc @@ -22,6 +22,7 @@ */ #include "QUICHandshakeProtocol.h" #include "QUICTypes.h" +#include "QUICPacketProtectionKeyInfo.h" QUICPacketProtection::~QUICPacketProtection() {} diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index f2d37c01430..a128fd7b421 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -28,6 +28,7 @@ #include "QUICTransportParameters.h" class QUICHandshakeProtocol; +class QUICPacketProtectionKeyInfo; class QUICPacketProtection { @@ -54,7 +55,7 @@ struct QUICHandshakeMsgs { class QUICHandshakeProtocol { public: - QUICHandshakeProtocol(){}; + QUICHandshakeProtocol(QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {} virtual ~QUICHandshakeProtocol(){}; virtual int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) = 0; @@ -80,4 +81,7 @@ class QUICHandshakeProtocol uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; virtual QUICEncryptionLevel current_encryption_level() const = 0; virtual void abort_handshake() = 0; + +protected: + QUICPacketProtectionKeyInfo &_pp_key_info; }; diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc index 1a9cd2c50e1..d410eae03cd 100644 --- a/iocore/net/quic/QUICPacketFactory.cc +++ b/iocore/net/quic/QUICPacketFactory.cc @@ -22,6 +22,7 @@ */ #include "QUICPacketFactory.h" +#include "QUICPacketProtectionKeyInfo.h" #include "QUICDebugNames.h" using namespace std::literals; @@ -97,6 +98,7 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP result = QUICPacketCreationResult::SUCCESS; break; case QUICPacketType::PROTECTED: + this->_pp_key_info.has_key_for(header->key_phase()); if (this->_hs_protocol->is_key_derived(header->key_phase(), false)) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), diff --git a/iocore/net/quic/QUICPacketFactory.h b/iocore/net/quic/QUICPacketFactory.h index 7641c71b553..7f02aa39606 100644 --- a/iocore/net/quic/QUICPacketFactory.h +++ b/iocore/net/quic/QUICPacketFactory.h @@ -26,6 +26,8 @@ #include "QUICTypes.h" #include "QUICPacket.h" +class QUICPacketProtectionKeyInfo; + class QUICPacketNumberGenerator { public: @@ -47,6 +49,8 @@ class QUICPacketFactory static QUICPacketUPtr create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICConnectionId original_dcid, QUICRetryToken &token); + QUICPacketFactory(QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {} + QUICPacketUPtr create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result); QUICPacketUPtr create_initial_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, @@ -74,6 +78,8 @@ class QUICPacketFactory private: QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; const QUICHandshakeProtocol *_hs_protocol = nullptr; + QUICPacketProtectionKeyInfo &_pp_key_info; + // Initial, 0/1-RTT, and Handshake QUICPacketNumberGenerator _packet_number_generator[3]; diff --git a/iocore/net/quic/QUICPacketHeaderProtector.h b/iocore/net/quic/QUICPacketHeaderProtector.h index f98a2e65f3c..94b490d2e4b 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.h +++ b/iocore/net/quic/QUICPacketHeaderProtector.h @@ -27,9 +27,13 @@ #include "QUICKeyGenerator.h" #include "QUICHandshakeProtocol.h" +class QUICPacketProtectionKeyInfo; + class QUICPacketHeaderProtector { public: + QUICPacketHeaderProtector(QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {} + bool unprotect(uint8_t *protected_packet, size_t protected_packet_len) const; bool protect(uint8_t *unprotected_packet, size_t unprotected_packet_len, int dcil) const; @@ -38,6 +42,7 @@ class QUICPacketHeaderProtector void set_hs_protocol(const QUICHandshakeProtocol *hs_protocol); private: + QUICPacketProtectionKeyInfo &_pp_key_info; const QUICHandshakeProtocol *_hs_protocol = nullptr; bool _calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len, int dcil) const; diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.h b/iocore/net/quic/QUICPacketProtectionKeyInfo.h new file mode 100644 index 00000000000..512a34a86c3 --- /dev/null +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.h @@ -0,0 +1,38 @@ +/** @file + * + * QUIC Packet Protection Key Info + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICTypes.h" + +class QUICPacketProtectionKeyInfo +{ +public: + void add_key(QUICEncryptionLevel level, int key, QUICKeyPhase phase); + void update_key(QUICEncryptionLevel level, int key); + void remove_key(QUICEncryptionLevel level); + void remove_key(QUICEncryptionLevel level, QUICKeyPhase phase); + + void has_key_for(QUICKeyPhase phase); + void get_key(QUICEncryptionLevel level) const; +}; diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index e523e0e72b4..65f3eaa64ba 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -39,7 +39,7 @@ class QUICTLS : public QUICHandshakeProtocol { public: - QUICTLS(SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx); + QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx); ~QUICTLS(); // TODO: integrate with _early_data_processed diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 142eb481f5a..212ed2bfbc7 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -233,8 +233,8 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t return; } -QUICTLS::QUICTLS(SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx) - : QUICHandshakeProtocol(), _ssl(SSL_new(ssl_ctx)), _netvc_context(nvc_ctx) +QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx) + : QUICHandshakeProtocol(pp_key_info), _ssl(SSL_new(ssl_ctx)), _netvc_context(nvc_ctx) { ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); From d030ade1e6c0868414e8dacbe82c02205a9a225a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 20 Feb 2019 12:04:50 +0900 Subject: [PATCH 1153/1313] Remove set_hs_protocol from QUICPacketHeaderProtector --- iocore/net/QUICNetVConnection.cc | 3 +- iocore/net/quic/Makefile.am | 1 + iocore/net/quic/QUICHandshakeProtocol.h | 1 - iocore/net/quic/QUICKeyGenerator.cc | 9 +- iocore/net/quic/QUICKeyGenerator.h | 5 +- iocore/net/quic/QUICPacketFactory.cc | 2 +- iocore/net/quic/QUICPacketFactory.h | 4 +- iocore/net/quic/QUICPacketHeaderProtector.cc | 55 +++++++--- iocore/net/quic/QUICPacketHeaderProtector.h | 12 +-- .../net/quic/QUICPacketProtectionKeyInfo.cc | 102 ++++++++++++++++++ iocore/net/quic/QUICPacketProtectionKeyInfo.h | 33 +++++- iocore/net/quic/QUICTLS.cc | 24 +++-- iocore/net/quic/QUICTLS.h | 2 +- iocore/net/quic/QUICTLS_openssl.cc | 94 +++++++++++----- iocore/net/quic/QUICTypes.h | 2 +- 15 files changed, 278 insertions(+), 71 deletions(-) create mode 100644 iocore/net/quic/QUICPacketProtectionKeyInfo.cc diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e6f94b67542..bb9bdfa20b5 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -245,6 +245,7 @@ QUICNetVConnection::start() this->_five_tuple.update(this->local_addr, this->remote_addr, SOCK_DGRAM); // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not if (this->direction() == NET_VCONNECTION_IN) { + this->_pp_key_info.set_context(QUICPacketProtectionKeyInfo::Context::SERVER); this->_ack_frame_manager.set_ack_delay_exponent(params->ack_delay_exponent_in()); this->_reset_token = QUICStatelessResetToken(this->_quic_connection_id, params->instance_id()); this->_hs_protocol = this->_setup_handshake_protocol(params->server_ssl_ctx()); @@ -252,6 +253,7 @@ QUICNetVConnection::start() this->_ack_frame_manager.set_max_ack_delay(params->max_ack_delay_in()); this->_ack_manager_periodic = this->thread->schedule_every(this, params->max_ack_delay_in(), QUIC_EVENT_ACK_PERIODIC); } else { + this->_pp_key_info.set_context(QUICPacketProtectionKeyInfo::Context::CLIENT); this->_ack_frame_manager.set_ack_delay_exponent(params->ack_delay_exponent_out()); this->_hs_protocol = this->_setup_handshake_protocol(params->client_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol); @@ -265,7 +267,6 @@ QUICNetVConnection::start() this->_frame_dispatcher = new QUICFrameDispatcher(this); this->_packet_factory.set_hs_protocol(this->_hs_protocol); - this->_ph_protector.set_hs_protocol(this->_hs_protocol); // Create frame handlers this->_congestion_controller = new QUICCongestionController(this); diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 92d45c98eb7..dfe5da76c83 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -61,6 +61,7 @@ libquic_a_SOURCES = \ QUICHandshake.cc \ QUICHandshakeProtocol.cc \ QUICPacketHeaderProtector.cc \ + QUICPacketProtectionKeyInfo.cc \ $(QUICPHProtector_impl) \ QUICTLS.cc \ $(QUICTLS_impl) \ diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index a128fd7b421..1421fd28afb 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -68,7 +68,6 @@ class QUICHandshakeProtocol virtual void negotiated_application_name(const uint8_t **name, unsigned int *len) const = 0; virtual const KeyMaterial *key_material_for_encryption(QUICKeyPhase phase) const = 0; virtual const KeyMaterial *key_material_for_decryption(QUICKeyPhase phase) const = 0; - virtual const QUIC_EVP_CIPHER *cipher_for_hp(QUICKeyPhase phase) const = 0; virtual std::shared_ptr local_transport_parameters() = 0; virtual std::shared_ptr remote_transport_parameters() = 0; diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index d37234aa94d..8db5ea72b49 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -43,7 +43,7 @@ constexpr static std::string_view LABEL_FOR_IV("quic iv"sv); constexpr static std::string_view LABEL_FOR_HP("quic hp"sv); std::unique_ptr -QUICKeyGenerator::generate(QUICConnectionId cid) +QUICKeyGenerator::generate(uint8_t *hp_key, QUICConnectionId cid) { std::unique_ptr km = std::make_unique(); @@ -78,16 +78,21 @@ QUICKeyGenerator::generate(QUICConnectionId cid) this->_generate(*km, hkdf, secret, secret_len, cipher); + memcpy(hp_key, km->hp, 512); + return km; } std::unique_ptr -QUICKeyGenerator::regenerate(const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher, QUICHKDF &hkdf) +QUICKeyGenerator::regenerate(uint8_t *hp_key, const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher, + QUICHKDF &hkdf) { std::unique_ptr km = std::make_unique(); this->_generate(*km, hkdf, secret, secret_len, cipher); + memcpy(hp_key, km->hp, 512); + return km; } diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index 4d9bf2d426c..9891c40f7fe 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -55,9 +55,10 @@ class QUICKeyGenerator * Generate keys for Initial encryption level * The keys for the remaining encryption level are derived by TLS stack with "quic " prefix */ - std::unique_ptr generate(QUICConnectionId cid); + std::unique_ptr generate(uint8_t *hp_key, QUICConnectionId cid); - std::unique_ptr regenerate(const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher, QUICHKDF &hkdf); + std::unique_ptr regenerate(uint8_t *hp_key, const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher, + QUICHKDF &hkdf); private: Context _ctx = Context::SERVER; diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc index d410eae03cd..89dede48e88 100644 --- a/iocore/net/quic/QUICPacketFactory.cc +++ b/iocore/net/quic/QUICPacketFactory.cc @@ -98,7 +98,6 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP result = QUICPacketCreationResult::SUCCESS; break; case QUICPacketType::PROTECTED: - this->_pp_key_info.has_key_for(header->key_phase()); if (this->_hs_protocol->is_key_derived(header->key_phase(), false)) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), @@ -112,6 +111,7 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } break; case QUICPacketType::INITIAL: + this->_pp_key_info.decryption_key_for_pp(QUICEncryptionLevel::INITIAL); if (this->_hs_protocol->is_key_derived(QUICKeyPhase::INITIAL, false)) { if (QUICTypeUtil::is_supported_version(header->version())) { if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), diff --git a/iocore/net/quic/QUICPacketFactory.h b/iocore/net/quic/QUICPacketFactory.h index 7f02aa39606..c4201cd23ef 100644 --- a/iocore/net/quic/QUICPacketFactory.h +++ b/iocore/net/quic/QUICPacketFactory.h @@ -49,7 +49,7 @@ class QUICPacketFactory static QUICPacketUPtr create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICConnectionId original_dcid, QUICRetryToken &token); - QUICPacketFactory(QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {} + QUICPacketFactory(const QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {} QUICPacketUPtr create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result); @@ -78,7 +78,7 @@ class QUICPacketFactory private: QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; const QUICHandshakeProtocol *_hs_protocol = nullptr; - QUICPacketProtectionKeyInfo &_pp_key_info; + const QUICPacketProtectionKeyInfo &_pp_key_info; // Initial, 0/1-RTT, and Handshake QUICPacketNumberGenerator _packet_number_generator[3]; diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc index ce257156b01..bbebc0ca408 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -21,6 +21,7 @@ * limitations under the License. */ +#include "QUICPacketProtectionKeyInfo.h" #include "QUICPacketHeaderProtector.h" #include "QUICDebugNames.h" #include "QUICPacket.h" @@ -41,6 +42,7 @@ QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotect QUICKeyPhase phase; QUICPacketType type; + QUICEncryptionLevel level; if (QUICInvariants::is_long_header(unprotected_packet)) { QUICPacketLongHeader::key_phase(phase, unprotected_packet, unprotected_packet_len); QUICPacketLongHeader::type(type, unprotected_packet, unprotected_packet_len); @@ -49,18 +51,33 @@ QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotect phase = QUICKeyPhase::PHASE_0; type = QUICPacketType::PROTECTED; } + switch (phase) { + case QUICKeyPhase::PHASE_0: + case QUICKeyPhase::PHASE_1: + level = QUICEncryptionLevel::ONE_RTT; + break; + case QUICKeyPhase::HANDSHAKE: + level = QUICEncryptionLevel::HANDSHAKE; + break; + case QUICKeyPhase::INITIAL: + level = QUICEncryptionLevel::INITIAL; + break; + case QUICKeyPhase::ZERO_RTT: + level = QUICEncryptionLevel::ZERO_RTT; + break; + } Debug("v_quic_pne", "Protecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), QUICDebugNames::key_phase(phase)); - const QUIC_EVP_CIPHER *aead = this->_hs_protocol->cipher_for_hp(phase); + const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher_for_hp(level); if (!aead) { Debug("quic_pne", "Failed to encrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } - const KeyMaterial *km = this->_hs_protocol->key_material_for_encryption(phase); - if (!km) { + const uint8_t *key = this->_pp_key_info.encryption_key_for_hp(level); + if (!key) { Debug("quic_pne", "Failed to encrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } @@ -72,7 +89,7 @@ QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotect } uint8_t mask[EVP_MAX_BLOCK_LENGTH]; - if (!this->_generate_mask(mask, unprotected_packet + sample_offset, km->hp, aead)) { + if (!this->_generate_mask(mask, unprotected_packet + sample_offset, key, aead)) { Debug("v_quic_pne", "Failed to generate a mask"); return false; } @@ -103,6 +120,7 @@ QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected QUICKeyPhase phase; QUICPacketType type; + QUICEncryptionLevel level; if (QUICInvariants::is_long_header(protected_packet)) { QUICPacketLongHeader::key_phase(phase, protected_packet, protected_packet_len); QUICPacketLongHeader::type(type, protected_packet, protected_packet_len); @@ -111,18 +129,33 @@ QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected phase = QUICKeyPhase::PHASE_0; type = QUICPacketType::PROTECTED; } + switch (phase) { + case QUICKeyPhase::PHASE_0: + case QUICKeyPhase::PHASE_1: + level = QUICEncryptionLevel::ONE_RTT; + break; + case QUICKeyPhase::HANDSHAKE: + level = QUICEncryptionLevel::HANDSHAKE; + break; + case QUICKeyPhase::INITIAL: + level = QUICEncryptionLevel::INITIAL; + break; + case QUICKeyPhase::ZERO_RTT: + level = QUICEncryptionLevel::ZERO_RTT; + break; + } Debug("v_quic_pne", "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), QUICDebugNames::key_phase(phase)); - const QUIC_EVP_CIPHER *aead = this->_hs_protocol->cipher_for_hp(phase); + const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher_for_hp(level); if (!aead) { Debug("quic_pne", "Failed to decrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } - const KeyMaterial *km = this->_hs_protocol->key_material_for_decryption(phase); - if (!km) { + const uint8_t *key = this->_pp_key_info.decryption_key_for_hp(level); + if (!key) { Debug("quic_pne", "Failed to decrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } @@ -134,7 +167,7 @@ QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected } uint8_t mask[EVP_MAX_BLOCK_LENGTH]; - if (!this->_generate_mask(mask, protected_packet + sample_offset, km->hp, aead)) { + if (!this->_generate_mask(mask, protected_packet + sample_offset, key, aead)) { Debug("v_quic_pne", "Failed to generate a mask"); return false; } @@ -146,12 +179,6 @@ QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected return true; } -void -QUICPacketHeaderProtector::set_hs_protocol(const QUICHandshakeProtocol *hs_protocol) -{ - this->_hs_protocol = hs_protocol; -} - bool QUICPacketHeaderProtector::_calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len, int dcil) const diff --git a/iocore/net/quic/QUICPacketHeaderProtector.h b/iocore/net/quic/QUICPacketHeaderProtector.h index 94b490d2e4b..9fa8f3402ba 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.h +++ b/iocore/net/quic/QUICPacketHeaderProtector.h @@ -25,29 +25,23 @@ #include "QUICTypes.h" #include "QUICKeyGenerator.h" -#include "QUICHandshakeProtocol.h" class QUICPacketProtectionKeyInfo; class QUICPacketHeaderProtector { public: - QUICPacketHeaderProtector(QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {} + QUICPacketHeaderProtector(const QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {} bool unprotect(uint8_t *protected_packet, size_t protected_packet_len) const; bool protect(uint8_t *unprotected_packet, size_t unprotected_packet_len, int dcil) const; - // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICCryptoInfoProvider or somethign instead. - // For now it receives a CONST pointer so PacketNubmerProtector cannot bother handshake. - void set_hs_protocol(const QUICHandshakeProtocol *hs_protocol); - private: - QUICPacketProtectionKeyInfo &_pp_key_info; - const QUICHandshakeProtocol *_hs_protocol = nullptr; + const QUICPacketProtectionKeyInfo &_pp_key_info; bool _calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len, int dcil) const; - bool _generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *aead) const; + bool _generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const QUIC_EVP_CIPHER *aead) const; bool _unprotect(uint8_t *packet, size_t packet_len, const uint8_t *mask) const; bool _protect(uint8_t *packet, size_t packet_len, const uint8_t *mask, int dcil) const; diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.cc b/iocore/net/quic/QUICPacketProtectionKeyInfo.cc new file mode 100644 index 00000000000..a230e358313 --- /dev/null +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.cc @@ -0,0 +1,102 @@ +/** @file + * + * QUIC Packet Protection Key Info + * + * @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 "QUICPacketProtectionKeyInfo.h" + +void +QUICPacketProtectionKeyInfo::set_context(Context ctx) +{ + this->_ctx = ctx; +} + +const QUIC_EVP_CIPHER * +QUICPacketProtectionKeyInfo::get_cipher_for_hp(QUICEncryptionLevel level) const +{ + switch (level) { + case QUICEncryptionLevel::INITIAL: + return this->_cipher_for_hp_initial; + default: + return this->_cipher_for_hp; + } +} + +void +QUICPacketProtectionKeyInfo::set_cipher_for_hp_initial(const QUIC_EVP_CIPHER *cipher) +{ + this->_cipher_for_hp_initial = cipher; +} + +void +QUICPacketProtectionKeyInfo::set_cipher_for_hp(const QUIC_EVP_CIPHER *cipher) +{ + this->_cipher_for_hp = cipher; +} + +const uint8_t * +QUICPacketProtectionKeyInfo::encryption_key_for_hp(QUICEncryptionLevel level) const +{ + int index = static_cast(level); + if (this->_ctx == Context::SERVER) { + return this->_server_key_for_hp[index]; + } else { + return this->_client_key_for_hp[index]; + } +} + +uint8_t * +QUICPacketProtectionKeyInfo::encryption_key_for_hp(QUICEncryptionLevel level) +{ + int index = static_cast(level); + if (this->_ctx == Context::SERVER) { + return this->_server_key_for_hp[index]; + } else { + return this->_client_key_for_hp[index]; + } +} + +const uint8_t * +QUICPacketProtectionKeyInfo::decryption_key_for_hp(QUICEncryptionLevel level) const +{ + int index = static_cast(level); + if (this->_ctx == Context::SERVER) { + return this->_client_key_for_hp[index]; + } else { + return this->_server_key_for_hp[index]; + } +} + +uint8_t * +QUICPacketProtectionKeyInfo::decryption_key_for_hp(QUICEncryptionLevel level) +{ + int index = static_cast(level); + if (this->_ctx == Context::SERVER) { + return this->_client_key_for_hp[index]; + } else { + return this->_server_key_for_hp[index]; + } +} + +void +QUICPacketProtectionKeyInfo::decryption_key_for_pp(QUICEncryptionLevel level) const +{ +} diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.h b/iocore/net/quic/QUICPacketProtectionKeyInfo.h index 512a34a86c3..33090ffd0be 100644 --- a/iocore/net/quic/QUICPacketProtectionKeyInfo.h +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.h @@ -24,15 +24,44 @@ #pragma once #include "QUICTypes.h" +#include "QUICKeyGenerator.h" class QUICPacketProtectionKeyInfo { public: + enum class Context { SERVER, CLIENT }; + + // FIXME This should be passed to the constructor but NetVC cannot pass it because it has set_context too. + void set_context(Context ctx); + void add_key(QUICEncryptionLevel level, int key, QUICKeyPhase phase); void update_key(QUICEncryptionLevel level, int key); void remove_key(QUICEncryptionLevel level); void remove_key(QUICEncryptionLevel level, QUICKeyPhase phase); - void has_key_for(QUICKeyPhase phase); - void get_key(QUICEncryptionLevel level) const; + void encryption_key_for_pp(QUICEncryptionLevel level) const; + void decryption_key_for_pp(QUICEncryptionLevel level) const; + + // Header Protection + + const QUIC_EVP_CIPHER *get_cipher_for_hp_initial() const; + void set_cipher_for_hp_initial(const QUIC_EVP_CIPHER *cipher); + + const QUIC_EVP_CIPHER *get_cipher_for_hp(QUICEncryptionLevel level) const; + void set_cipher_for_hp(const QUIC_EVP_CIPHER *cipher); + + const uint8_t *encryption_key_for_hp(QUICEncryptionLevel level) const; + uint8_t *encryption_key_for_hp(QUICEncryptionLevel level); + + const uint8_t *decryption_key_for_hp(QUICEncryptionLevel level) const; + uint8_t *decryption_key_for_hp(QUICEncryptionLevel level); + +private: + Context _ctx = Context::SERVER; + + const QUIC_EVP_CIPHER *_cipher_for_hp_initial = nullptr; + const QUIC_EVP_CIPHER *_cipher_for_hp = nullptr; + + uint8_t _client_key_for_hp[4][512]; + uint8_t _server_key_for_hp[4][512]; }; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 06bf7dc3a5b..ad92be25120 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -27,6 +27,7 @@ #include #include +#include "QUICPacketProtectionKeyInfo.h" #include "QUICDebugNames.h" constexpr static char tag[] = "quic_tls"; @@ -104,17 +105,26 @@ QUICTLS::is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const int 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)); - std::unique_ptr km; + std::unique_ptr km_client; + std::unique_ptr km_server; + + if (this->_netvc_context == NET_VCONNECTION_IN) { + km_client = this->_keygen_for_client.generate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::INITIAL), cid); + km_server = this->_keygen_for_server.generate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::INITIAL), cid); + } else { + km_client = this->_keygen_for_client.generate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::INITIAL), cid); + km_server = this->_keygen_for_server.generate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::INITIAL), cid); + } - km = this->_keygen_for_client.generate(cid); - this->_print_km("initial - client", *km); - this->_client_pp->set_key(std::move(km), QUICKeyPhase::INITIAL); + this->_print_km("initial - client", *km_client); + this->_print_km("initial - server", *km_server); - km = this->_keygen_for_server.generate(cid); - this->_print_km("initial - server", *km); - this->_server_pp->set_key(std::move(km), QUICKeyPhase::INITIAL); + this->_client_pp->set_key(std::move(km_client), QUICKeyPhase::INITIAL); + this->_server_pp->set_key(std::move(km_server), QUICKeyPhase::INITIAL); return 1; } diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 65f3eaa64ba..e7a5479a22b 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -72,7 +72,6 @@ class QUICTLS : public QUICHandshakeProtocol void negotiated_application_name(const uint8_t **name, unsigned int *len) const override; const KeyMaterial *key_material_for_encryption(QUICKeyPhase phase) const override; const KeyMaterial *key_material_for_decryption(QUICKeyPhase phase) const override; - const QUIC_EVP_CIPHER *cipher_for_hp(QUICKeyPhase phase) const override; bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override; @@ -101,6 +100,7 @@ class QUICTLS : public QUICHandshakeProtocol int _process_post_handshake_messages(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in); void _generate_0rtt_key(); void _update_encryption_level(QUICEncryptionLevel level); + void _store_negotiated_cipher_for_hp(); void _print_km(const char *header, KeyMaterial &km, const uint8_t *secret = nullptr, size_t secret_len = 0); SSL *_ssl = nullptr; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 212ed2bfbc7..2b315104c88 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -21,6 +21,7 @@ * limitations under the License. */ #include "QUICGlobals.h" +#include "QUICPacketProtectionKeyInfo.h" #include "QUICTLS.h" #include @@ -190,7 +191,13 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t // this->_update_encryption_level(QUICEncryptionLevel::ZERO_RTT); phase = QUICKeyPhase::ZERO_RTT; cipher = this->_get_evp_aead(phase); - km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); + if (this->_netvc_context == NET_VCONNECTION_IN) { + km = this->_keygen_for_client.regenerate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::ZERO_RTT), secret, + secret_len, cipher, hkdf); + } else { + km = this->_keygen_for_client.regenerate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::ZERO_RTT), secret, + secret_len, cipher, hkdf); + } this->_print_km("update - client - 0rtt", *km, secret, secret_len); this->_client_pp->set_key(std::move(km), phase); break; @@ -198,7 +205,13 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); phase = QUICKeyPhase::HANDSHAKE; cipher = this->_get_evp_aead(phase); - km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); + if (this->_netvc_context == NET_VCONNECTION_IN) { + km = this->_keygen_for_client.regenerate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::HANDSHAKE), secret, + secret_len, cipher, hkdf); + } else { + km = this->_keygen_for_client.regenerate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::HANDSHAKE), secret, + secret_len, cipher, hkdf); + } this->_print_km("update - client - handshake", *km, secret, secret_len); this->_client_pp->set_key(std::move(km), phase); break; @@ -206,7 +219,13 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); phase = QUICKeyPhase::PHASE_0; cipher = this->_get_evp_aead(phase); - km = this->_keygen_for_client.regenerate(secret, secret_len, cipher, hkdf); + if (this->_netvc_context == NET_VCONNECTION_IN) { + km = this->_keygen_for_client.regenerate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::ONE_RTT), secret, + secret_len, cipher, hkdf); + } else { + km = this->_keygen_for_client.regenerate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::ONE_RTT), secret, + secret_len, cipher, hkdf); + } this->_print_km("update - client - 1rtt", *km, secret, secret_len); this->_client_pp->set_key(std::move(km), phase); break; @@ -214,7 +233,13 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); phase = QUICKeyPhase::HANDSHAKE; cipher = this->_get_evp_aead(phase); - km = this->_keygen_for_server.regenerate(secret, secret_len, cipher, hkdf); + if (this->_netvc_context == NET_VCONNECTION_IN) { + km = this->_keygen_for_server.regenerate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::HANDSHAKE), secret, + secret_len, cipher, hkdf); + } else { + km = this->_keygen_for_server.regenerate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::HANDSHAKE), secret, + secret_len, cipher, hkdf); + } this->_print_km("update - server - handshake", *km, secret, secret_len); this->_server_pp->set_key(std::move(km), phase); break; @@ -222,7 +247,13 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); phase = QUICKeyPhase::PHASE_0; cipher = this->_get_evp_aead(phase); - km = this->_keygen_for_server.regenerate(secret, secret_len, cipher, hkdf); + if (this->_netvc_context == NET_VCONNECTION_IN) { + km = this->_keygen_for_server.regenerate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::ONE_RTT), secret, + secret_len, cipher, hkdf); + } else { + km = this->_keygen_for_server.regenerate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::ONE_RTT), secret, + secret_len, cipher, hkdf); + } this->_print_km("update - server - 1rtt", *km, secret, secret_len); this->_server_pp->set_key(std::move(km), phase); break; @@ -230,6 +261,8 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t break; } + this->_store_negotiated_cipher_for_hp(); + return; } @@ -424,33 +457,38 @@ QUICTLS::reset() SSL_clear(this->_ssl); } -const EVP_CIPHER * -QUICTLS::cipher_for_hp(QUICKeyPhase phase) const +void +QUICTLS::_store_negotiated_cipher_for_hp() { - if (phase == QUICKeyPhase::INITIAL) { - return EVP_aes_128_ecb(); - } else { - const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); - if (cipher) { - switch (SSL_CIPHER_get_id(cipher)) { - case TLS1_3_CK_AES_128_GCM_SHA256: - return EVP_aes_128_ecb(); - case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_aes_256_ecb(); - case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_chacha20(); - case TLS1_3_CK_AES_128_CCM_SHA256: - case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_aes_128_ecb(); - default: - ink_assert(false); - return nullptr; - } - } else { + ink_assert(this->_ssl); + + const QUIC_EVP_CIPHER *cipher_for_hp = nullptr; + const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); + + if (cipher) { + switch (SSL_CIPHER_get_id(cipher)) { + case TLS1_3_CK_AES_128_GCM_SHA256: + cipher_for_hp = EVP_aes_128_ecb(); + break; + case TLS1_3_CK_AES_256_GCM_SHA384: + cipher_for_hp = EVP_aes_256_ecb(); + break; + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + cipher_for_hp = EVP_chacha20(); + break; + case TLS1_3_CK_AES_128_CCM_SHA256: + case TLS1_3_CK_AES_128_CCM_8_SHA256: + cipher_for_hp = EVP_aes_128_ecb(); + break; + default: ink_assert(false); - return nullptr; + break; } + } else { + ink_assert(false); } + + this->_pp_key_info.set_cipher_for_hp(cipher_for_hp); } int diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 44515814785..effeca7bdcb 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -54,7 +54,7 @@ constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { }; constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; -enum class QUICEncryptionLevel { +enum class QUICEncryptionLevel : int { NONE = -1, INITIAL = 0, ZERO_RTT = 1, From 14871688b56d9a9043d79db5bfd617b8310173b5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Feb 2019 12:21:30 +0900 Subject: [PATCH 1154/1313] Remove set_hs_protocol from QUICPacketFactory --- iocore/net/QUICNetVConnection.cc | 1 - iocore/net/quic/Makefile.am | 6 +- iocore/net/quic/QUICHandshakeProtocol.h | 11 +- iocore/net/quic/QUICKeyGenerator.cc | 12 +- iocore/net/quic/QUICKeyGenerator.h | 6 +- iocore/net/quic/QUICPacketFactory.cc | 44 ++- iocore/net/quic/QUICPacketFactory.h | 12 +- iocore/net/quic/QUICPacketHeaderProtector.cc | 8 +- iocore/net/quic/QUICPacketPayloadProtector.cc | 100 ++++++ iocore/net/quic/QUICPacketPayloadProtector.h | 52 ++++ .../QUICPacketPayloadProtector_openssl.cc | 132 ++++++++ .../net/quic/QUICPacketProtectionKeyInfo.cc | 210 ++++++++++++- iocore/net/quic/QUICPacketProtectionKeyInfo.h | 78 ++++- iocore/net/quic/QUICTLS.cc | 136 ++------- iocore/net/quic/QUICTLS.h | 22 +- iocore/net/quic/QUICTLS_openssl.cc | 284 ++++++------------ 16 files changed, 701 insertions(+), 413 deletions(-) create mode 100644 iocore/net/quic/QUICPacketPayloadProtector.cc create mode 100644 iocore/net/quic/QUICPacketPayloadProtector.h create mode 100644 iocore/net/quic/QUICPacketPayloadProtector_openssl.cc diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index bb9bdfa20b5..999e1cddd0f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -266,7 +266,6 @@ QUICNetVConnection::start() this->_application_map = new QUICApplicationMap(); this->_frame_dispatcher = new QUICFrameDispatcher(this); - this->_packet_factory.set_hs_protocol(this->_hs_protocol); // Create frame handlers this->_congestion_controller = new QUICCongestionController(this); diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index dfe5da76c83..5b23b8c8d0e 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -35,10 +35,12 @@ noinst_LIBRARIES = libquic.a if OPENSSL_IS_BORINGSSL QUICPHProtector_impl = QUICPacketHeaderProtector_boringssl.cc +QUICPPProtector_impl = QUICPacketPayloadProtector_boringssl.cc QUICTLS_impl = QUICTLS_boringssl.cc QUICKeyGenerator_impl = QUICKeyGenerator_boringssl.cc else QUICPHProtector_impl = QUICPacketHeaderProtector_openssl.cc +QUICPPProtector_impl = QUICPacketPayloadProtector_openssl.cc QUICTLS_impl = QUICTLS_openssl.cc QUICKeyGenerator_impl = QUICKeyGenerator_openssl.cc endif @@ -61,8 +63,10 @@ libquic_a_SOURCES = \ QUICHandshake.cc \ QUICHandshakeProtocol.cc \ QUICPacketHeaderProtector.cc \ - QUICPacketProtectionKeyInfo.cc \ $(QUICPHProtector_impl) \ + QUICPacketPayloadProtector.cc \ + $(QUICPPProtector_impl) \ + QUICPacketProtectionKeyInfo.cc \ QUICTLS.cc \ $(QUICTLS_impl) \ QUICKeyGenerator.cc \ diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 1421fd28afb..98a056519d7 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -62,24 +62,17 @@ class QUICHandshakeProtocol virtual void reset() = 0; virtual bool is_handshake_finished() const = 0; virtual bool is_ready_to_derive() const = 0; - virtual bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const = 0; virtual int initialize_key_materials(QUICConnectionId cid) = 0; virtual const char *negotiated_cipher_suite() const = 0; virtual void negotiated_application_name(const uint8_t **name, unsigned int *len) const = 0; - virtual const KeyMaterial *key_material_for_encryption(QUICKeyPhase phase) const = 0; - virtual const KeyMaterial *key_material_for_decryption(QUICKeyPhase phase) const = 0; virtual std::shared_ptr local_transport_parameters() = 0; virtual std::shared_ptr remote_transport_parameters() = 0; virtual void set_local_transport_parameters(std::shared_ptr tp) = 0; virtual void set_remote_transport_parameters(std::shared_ptr tp) = 0; - virtual bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0; - virtual bool decrypt(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, QUICKeyPhase phase) const = 0; - virtual QUICEncryptionLevel current_encryption_level() const = 0; - virtual void abort_handshake() = 0; + virtual QUICEncryptionLevel current_encryption_level() const = 0; + virtual void abort_handshake() = 0; protected: QUICPacketProtectionKeyInfo &_pp_key_info; diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 8db5ea72b49..2cb31b41f86 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -43,7 +43,7 @@ constexpr static std::string_view LABEL_FOR_IV("quic iv"sv); constexpr static std::string_view LABEL_FOR_HP("quic hp"sv); std::unique_ptr -QUICKeyGenerator::generate(uint8_t *hp_key, QUICConnectionId cid) +QUICKeyGenerator::generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, QUICConnectionId cid) { std::unique_ptr km = std::make_unique(); @@ -79,19 +79,25 @@ QUICKeyGenerator::generate(uint8_t *hp_key, QUICConnectionId cid) this->_generate(*km, hkdf, secret, secret_len, cipher); memcpy(hp_key, km->hp, 512); + memcpy(pp_key, km->key, 512); + memcpy(iv, km->iv, 512); + *iv_len = km->iv_len; return km; } std::unique_ptr -QUICKeyGenerator::regenerate(uint8_t *hp_key, const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher, - QUICHKDF &hkdf) +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) { std::unique_ptr km = std::make_unique(); this->_generate(*km, hkdf, secret, secret_len, cipher); memcpy(hp_key, km->hp, 512); + memcpy(pp_key, km->key, 512); + memcpy(iv, km->iv, 512); + *iv_len = km->iv_len; return km; } diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index 9891c40f7fe..118eb138971 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -55,10 +55,10 @@ class QUICKeyGenerator * Generate keys for Initial encryption level * The keys for the remaining encryption level are derived by TLS stack with "quic " prefix */ - std::unique_ptr generate(uint8_t *hp_key, QUICConnectionId cid); + std::unique_ptr generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, QUICConnectionId cid); - std::unique_ptr regenerate(uint8_t *hp_key, const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher, - QUICHKDF &hkdf); + std::unique_ptr 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); private: Context _ctx = Context::SERVER; diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc index 89dede48e88..bef0e0cd4b1 100644 --- a/iocore/net/quic/QUICPacketFactory.cc +++ b/iocore/net/quic/QUICPacketFactory.cc @@ -98,10 +98,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP result = QUICPacketCreationResult::SUCCESS; break; case QUICPacketType::PROTECTED: - if (this->_hs_protocol->is_key_derived(header->key_phase(), false)) { - if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - header->key_phase())) { + if (this->_pp_key_info.is_decryption_key_available(header->key_phase())) { + if (this->_pp_protector.unprotect(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + header->key_phase())) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -111,12 +111,11 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } break; case QUICPacketType::INITIAL: - this->_pp_key_info.decryption_key_for_pp(QUICEncryptionLevel::INITIAL); - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::INITIAL, false)) { + if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::INITIAL)) { if (QUICTypeUtil::is_supported_version(header->version())) { - if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::INITIAL)) { + if (this->_pp_protector.unprotect(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + QUICKeyPhase::INITIAL)) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -129,10 +128,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } break; case QUICPacketType::HANDSHAKE: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::HANDSHAKE, false)) { - if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::HANDSHAKE)) { + if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::HANDSHAKE)) { + if (this->_pp_protector.unprotect(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + QUICKeyPhase::HANDSHAKE)) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -142,10 +141,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP } break; case QUICPacketType::ZERO_RTT_PROTECTED: - if (this->_hs_protocol->is_key_derived(QUICKeyPhase::ZERO_RTT, false)) { - if (this->_hs_protocol->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::ZERO_RTT)) { + if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::ZERO_RTT)) { + if (this->_pp_protector.unprotect(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), + header->payload_size(), header->packet_number(), header->buf(), header->size(), + QUICKeyPhase::ZERO_RTT)) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::IGNORED; @@ -306,7 +305,7 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool re header->packet_number(), QUICDebugNames::key_phase(header->key_phase())); QUICPacket *packet = nullptr; - if (this->_hs_protocol->encrypt(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), + if (this->_pp_protector.protect(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable, probing, frames); @@ -323,16 +322,11 @@ QUICPacketFactory::set_version(QUICVersion negotiated_version) this->_version = negotiated_version; } -void -QUICPacketFactory::set_hs_protocol(const QUICHandshakeProtocol *hs_protocol) -{ - this->_hs_protocol = hs_protocol; -} - bool QUICPacketFactory::is_ready_to_create_protected_packet() { - return this->_hs_protocol->is_handshake_finished(); + return this->_pp_key_info.is_encryption_key_available(QUICKeyPhase::PHASE_0) || + this->_pp_key_info.is_encryption_key_available(QUICKeyPhase::PHASE_1); } void diff --git a/iocore/net/quic/QUICPacketFactory.h b/iocore/net/quic/QUICPacketFactory.h index c4201cd23ef..a62be5985f8 100644 --- a/iocore/net/quic/QUICPacketFactory.h +++ b/iocore/net/quic/QUICPacketFactory.h @@ -25,6 +25,7 @@ #include "QUICTypes.h" #include "QUICPacket.h" +#include "QUICPacketPayloadProtector.h" class QUICPacketProtectionKeyInfo; @@ -49,7 +50,7 @@ class QUICPacketFactory static QUICPacketUPtr create_retry_packet(QUICConnectionId destination_cid, QUICConnectionId source_cid, QUICConnectionId original_dcid, QUICRetryToken &token); - QUICPacketFactory(const QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {} + QUICPacketFactory(const QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info), _pp_protector(pp_key_info) {} QUICPacketUPtr create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result); @@ -68,17 +69,14 @@ class QUICPacketFactory std::vector &frames); void set_version(QUICVersion negotiated_version); - // FIXME We don't need QUICHandshakeProtocol here, and should pass QUICCryptoInfoProvider or somethign instead. - // For now it receives a CONST pointer so PacketFactory cannot bother handshake. - void set_hs_protocol(const QUICHandshakeProtocol *hs_protocol); - bool is_ready_to_create_protected_packet(); void reset(); private: - QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; - const QUICHandshakeProtocol *_hs_protocol = nullptr; + QUICVersion _version = QUIC_SUPPORTED_VERSIONS[0]; + const QUICPacketProtectionKeyInfo &_pp_key_info; + QUICPacketPayloadProtector _pp_protector; // Initial, 0/1-RTT, and Handshake QUICPacketNumberGenerator _packet_number_generator[3]; diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc index bbebc0ca408..de8ebd5f329 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -70,13 +70,13 @@ QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotect Debug("v_quic_pne", "Protecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), QUICDebugNames::key_phase(phase)); - const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher_for_hp(level); + const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher_for_hp(phase); if (!aead) { Debug("quic_pne", "Failed to encrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } - const uint8_t *key = this->_pp_key_info.encryption_key_for_hp(level); + const uint8_t *key = this->_pp_key_info.encryption_key_for_hp(phase); if (!key) { Debug("quic_pne", "Failed to encrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; @@ -148,13 +148,13 @@ QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected Debug("v_quic_pne", "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), QUICDebugNames::key_phase(phase)); - const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher_for_hp(level); + const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher_for_hp(phase); if (!aead) { Debug("quic_pne", "Failed to decrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; } - const uint8_t *key = this->_pp_key_info.decryption_key_for_hp(level); + const uint8_t *key = this->_pp_key_info.decryption_key_for_hp(phase); if (!key) { Debug("quic_pne", "Failed to decrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; diff --git a/iocore/net/quic/QUICPacketPayloadProtector.cc b/iocore/net/quic/QUICPacketPayloadProtector.cc new file mode 100644 index 00000000000..723fb1cc1ce --- /dev/null +++ b/iocore/net/quic/QUICPacketPayloadProtector.cc @@ -0,0 +1,100 @@ +/** @file + * + * QUIC Packet Header Protector + * + * @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 "QUICPacketProtectionKeyInfo.h" +#include "QUICPacketPayloadProtector.h" +#include "QUICDebugNames.h" + +static constexpr char tag[] = "quic_ppp"; + +bool +QUICPacketPayloadProtector::protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, + size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const +{ + size_t tag_len = this->_pp_key_info.get_tag_len(phase); + const uint8_t *key = this->_pp_key_info.encryption_key(phase); + const uint8_t *iv = this->_pp_key_info.encryption_iv(phase); + size_t iv_len = *this->_pp_key_info.encryption_iv_len(phase); + if (!key) { + Debug(tag, "Failed to encrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); + return false; + } + const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher(phase); + + bool ret = + this->_protect(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, key, iv, iv_len, aead, tag_len); + if (!ret) { + Debug(tag, "Failed to encrypt a packet #%" PRIu64, pkt_num); + } + return ret; +} + +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, + QUICKeyPhase phase) const +{ + size_t tag_len = this->_pp_key_info.get_tag_len(phase); + const uint8_t *key = this->_pp_key_info.decryption_key(phase); + const uint8_t *iv = this->_pp_key_info.decryption_iv(phase); + size_t iv_len = *this->_pp_key_info.decryption_iv_len(phase); + if (!key) { + Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); + return false; + } + const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher(phase); + bool ret = + this->_unprotect(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, key, iv, iv_len, aead, tag_len); + if (!ret) { + Debug(tag, "Failed to decrypt a packet #%" PRIu64, pkt_num); + } + return ret; +} + +/** + * Example iv_len = 12 + * + * 0 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 (byte) + * +-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | iv | // IV + * +-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0|0|0|0| pkt num | // network byte order & left-padded with zeros + * +-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | nonce | // nonce = iv xor pkt_num + * +-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +void +QUICPacketPayloadProtector::_gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const +{ + nonce_len = iv_len; + memcpy(nonce, iv, iv_len); + + pkt_num = htobe64(pkt_num); + uint8_t *p = reinterpret_cast(&pkt_num); + + for (size_t i = 0; i < 8; ++i) { + nonce[iv_len - 8 + i] ^= p[i]; + } +} diff --git a/iocore/net/quic/QUICPacketPayloadProtector.h b/iocore/net/quic/QUICPacketPayloadProtector.h new file mode 100644 index 00000000000..f5d2aab38c0 --- /dev/null +++ b/iocore/net/quic/QUICPacketPayloadProtector.h @@ -0,0 +1,52 @@ +/** @file + * + * QUIC Packet Payload Protector + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICTypes.h" +#include "QUICKeyGenerator.h" + +class QUICPacketProtectionKeyInfo; + +class QUICPacketPayloadProtector +{ +public: + QUICPacketPayloadProtector(const QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {} + + bool 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, QUICKeyPhase phase) const; + bool protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, + const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const; + +private: + const QUICPacketProtectionKeyInfo &_pp_key_info; + + bool _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 QUIC_EVP_CIPHER *aead, size_t tag_len) const; + bool _protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_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 QUIC_EVP_CIPHER *aead, size_t tag_len) const; + + void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; +}; diff --git a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc b/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc new file mode 100644 index 00000000000..5da9bd18b53 --- /dev/null +++ b/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc @@ -0,0 +1,132 @@ +/** @file + * + * QUIC Packet Header Protector + * + * @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 "QUICPacketProtectionKeyInfo.h" +#include "QUICPacketPayloadProtector.h" +#include "tscore/Diags.h" + +static constexpr char tag[] = "quic_ppp"; + +bool +QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, + size_t plain_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 +{ + uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; + size_t nonce_len = 0; + this->_gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); + + EVP_CIPHER_CTX *aead_ctx; + int 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; + } + if (!EVP_EncryptUpdate(aead_ctx, cipher, &len, plain, plain_len)) { + return false; + } + cipher_len = len; + + if (!EVP_EncryptFinal_ex(aead_ctx, 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 +{ + uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; + size_t nonce_len = 0; + _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); + + EVP_CIPHER_CTX *aead_ctx; + int 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(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/QUICPacketProtectionKeyInfo.cc b/iocore/net/quic/QUICPacketProtectionKeyInfo.cc index a230e358313..7f3986d4671 100644 --- a/iocore/net/quic/QUICPacketProtectionKeyInfo.cc +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.cc @@ -30,10 +30,193 @@ QUICPacketProtectionKeyInfo::set_context(Context ctx) } const QUIC_EVP_CIPHER * -QUICPacketProtectionKeyInfo::get_cipher_for_hp(QUICEncryptionLevel level) const +QUICPacketProtectionKeyInfo::get_cipher(QUICKeyPhase phase) const { - switch (level) { - case QUICEncryptionLevel::INITIAL: + switch (phase) { + case QUICKeyPhase::INITIAL: + return this->_cipher_initial; + default: + return this->_cipher; + } +} + +size_t +QUICPacketProtectionKeyInfo::get_tag_len(QUICKeyPhase phase) const +{ + switch (phase) { + case QUICKeyPhase::INITIAL: + return EVP_GCM_TLS_TAG_LEN; + default: + return this->_tag_len; + } +} + +bool +QUICPacketProtectionKeyInfo::is_encryption_key_available(QUICKeyPhase phase) const +{ + int index = static_cast(phase); + if (this->_ctx == Context::SERVER) { + return this->_is_server_key_available[index]; + } else { + return this->_is_client_key_available[index]; + } +} + +void +QUICPacketProtectionKeyInfo::set_encryption_key_available(QUICKeyPhase phase) +{ + int index = static_cast(phase); + if (this->_ctx == Context::SERVER) { + this->_is_server_key_available[index] = true; + } else { + this->_is_client_key_available[index] = true; + ; + } +} + +const uint8_t * +QUICPacketProtectionKeyInfo::encryption_key(QUICKeyPhase phase) const +{ + int index = static_cast(phase); + if (this->_ctx == Context::SERVER) { + return this->_server_key[index]; + } else { + return this->_client_key[index]; + } +} + +uint8_t * +QUICPacketProtectionKeyInfo::encryption_key(QUICKeyPhase phase) +{ + return const_cast(const_cast(this)->encryption_key(phase)); +} + +const uint8_t * +QUICPacketProtectionKeyInfo::encryption_iv(QUICKeyPhase phase) const +{ + int index = static_cast(phase); + if (this->_ctx == Context::SERVER) { + return this->_server_iv[index]; + } else { + return this->_client_iv[index]; + } +} + +uint8_t * +QUICPacketProtectionKeyInfo::encryption_iv(QUICKeyPhase phase) +{ + return const_cast(const_cast(this)->encryption_iv(phase)); +} + +const size_t * +QUICPacketProtectionKeyInfo::encryption_iv_len(QUICKeyPhase phase) const +{ + int index = static_cast(phase); + if (this->_ctx == Context::SERVER) { + return &this->_server_iv_len[index]; + } else { + return &this->_client_iv_len[index]; + } +} + +size_t * +QUICPacketProtectionKeyInfo::encryption_iv_len(QUICKeyPhase phase) +{ + return const_cast(const_cast(this)->encryption_iv_len(phase)); +} + +bool +QUICPacketProtectionKeyInfo::is_decryption_key_available(QUICKeyPhase phase) const +{ + int index = static_cast(phase); + if (this->_ctx == Context::SERVER) { + return this->_is_client_key_available[index]; + } else { + return this->_is_server_key_available[index]; + } +} + +void +QUICPacketProtectionKeyInfo::set_decryption_key_available(QUICKeyPhase phase) +{ + int index = static_cast(phase); + if (this->_ctx == Context::SERVER) { + this->_is_client_key_available[index] = true; + } else { + this->_is_server_key_available[index] = true; + ; + } +} + +const uint8_t * +QUICPacketProtectionKeyInfo::decryption_key(QUICKeyPhase phase) const +{ + int index = static_cast(phase); + if (this->_ctx == Context::SERVER) { + return this->_client_key[index]; + } else { + return this->_server_key[index]; + } +} + +uint8_t * +QUICPacketProtectionKeyInfo::decryption_key(QUICKeyPhase phase) +{ + return const_cast(const_cast(this)->decryption_key(phase)); +} + +const uint8_t * +QUICPacketProtectionKeyInfo::decryption_iv(QUICKeyPhase phase) const +{ + int index = static_cast(phase); + if (this->_ctx == Context::SERVER) { + return this->_client_iv[index]; + } else { + return this->_server_iv[index]; + } +} + +uint8_t * +QUICPacketProtectionKeyInfo::decryption_iv(QUICKeyPhase phase) +{ + return const_cast(const_cast(this)->decryption_iv(phase)); +} + +const size_t * +QUICPacketProtectionKeyInfo::decryption_iv_len(QUICKeyPhase phase) const +{ + int index = static_cast(phase); + if (this->_ctx == Context::SERVER) { + return &this->_client_iv_len[index]; + } else { + return &this->_server_iv_len[index]; + } +} + +size_t * +QUICPacketProtectionKeyInfo::decryption_iv_len(QUICKeyPhase phase) +{ + return const_cast(const_cast(this)->decryption_iv_len(phase)); +} + +void +QUICPacketProtectionKeyInfo::set_cipher_initial(const QUIC_EVP_CIPHER *cipher) +{ + this->_cipher_initial = cipher; +} + +void +QUICPacketProtectionKeyInfo::set_cipher(const QUIC_EVP_CIPHER *cipher, size_t tag_len) +{ + this->_cipher = cipher; + this->_tag_len = tag_len; +} + +const QUIC_EVP_CIPHER * +QUICPacketProtectionKeyInfo::get_cipher_for_hp(QUICKeyPhase phase) const +{ + switch (phase) { + case QUICKeyPhase::INITIAL: return this->_cipher_for_hp_initial; default: return this->_cipher_for_hp; @@ -53,9 +236,9 @@ QUICPacketProtectionKeyInfo::set_cipher_for_hp(const QUIC_EVP_CIPHER *cipher) } const uint8_t * -QUICPacketProtectionKeyInfo::encryption_key_for_hp(QUICEncryptionLevel level) const +QUICPacketProtectionKeyInfo::encryption_key_for_hp(QUICKeyPhase phase) const { - int index = static_cast(level); + int index = static_cast(phase); if (this->_ctx == Context::SERVER) { return this->_server_key_for_hp[index]; } else { @@ -64,9 +247,9 @@ QUICPacketProtectionKeyInfo::encryption_key_for_hp(QUICEncryptionLevel level) co } uint8_t * -QUICPacketProtectionKeyInfo::encryption_key_for_hp(QUICEncryptionLevel level) +QUICPacketProtectionKeyInfo::encryption_key_for_hp(QUICKeyPhase phase) { - int index = static_cast(level); + int index = static_cast(phase); if (this->_ctx == Context::SERVER) { return this->_server_key_for_hp[index]; } else { @@ -75,9 +258,9 @@ QUICPacketProtectionKeyInfo::encryption_key_for_hp(QUICEncryptionLevel level) } const uint8_t * -QUICPacketProtectionKeyInfo::decryption_key_for_hp(QUICEncryptionLevel level) const +QUICPacketProtectionKeyInfo::decryption_key_for_hp(QUICKeyPhase phase) const { - int index = static_cast(level); + int index = static_cast(phase); if (this->_ctx == Context::SERVER) { return this->_client_key_for_hp[index]; } else { @@ -86,17 +269,12 @@ QUICPacketProtectionKeyInfo::decryption_key_for_hp(QUICEncryptionLevel level) co } uint8_t * -QUICPacketProtectionKeyInfo::decryption_key_for_hp(QUICEncryptionLevel level) +QUICPacketProtectionKeyInfo::decryption_key_for_hp(QUICKeyPhase phase) { - int index = static_cast(level); + int index = static_cast(phase); if (this->_ctx == Context::SERVER) { return this->_client_key_for_hp[index]; } else { return this->_server_key_for_hp[index]; } } - -void -QUICPacketProtectionKeyInfo::decryption_key_for_pp(QUICEncryptionLevel level) const -{ -} diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.h b/iocore/net/quic/QUICPacketProtectionKeyInfo.h index 33090ffd0be..1011444c3be 100644 --- a/iocore/net/quic/QUICPacketProtectionKeyInfo.h +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.h @@ -34,34 +34,82 @@ class QUICPacketProtectionKeyInfo // FIXME This should be passed to the constructor but NetVC cannot pass it because it has set_context too. void set_context(Context ctx); - void add_key(QUICEncryptionLevel level, int key, QUICKeyPhase phase); - void update_key(QUICEncryptionLevel level, int key); - void remove_key(QUICEncryptionLevel level); - void remove_key(QUICEncryptionLevel level, QUICKeyPhase phase); + void add_key(QUICKeyPhase phase, int key); + void update_key(QUICKeyPhase phase, int key); + void remove_key(QUICKeyPhase phase); - void encryption_key_for_pp(QUICEncryptionLevel level) const; - void decryption_key_for_pp(QUICEncryptionLevel level) const; + // Payload Protection (common) + const QUIC_EVP_CIPHER *get_cipher(QUICKeyPhase phase) const; + size_t get_tag_len(QUICKeyPhase phase) const; + void set_cipher_initial(const QUIC_EVP_CIPHER *cipher); + void set_cipher(const QUIC_EVP_CIPHER *cipher, size_t tag_len); + + // Payload Protection (encryption) + + bool is_encryption_key_available(QUICKeyPhase phase) const; + void set_encryption_key_available(QUICKeyPhase phase); + + const uint8_t *encryption_key(QUICKeyPhase phase) const; + uint8_t *encryption_key(QUICKeyPhase phase); + + const uint8_t *encryption_iv(QUICKeyPhase phase) const; + uint8_t *encryption_iv(QUICKeyPhase phase); + + const size_t *encryption_iv_len(QUICKeyPhase phase) const; + size_t *encryption_iv_len(QUICKeyPhase phase); + + // Payload Protection (decryption) + + bool is_decryption_key_available(QUICKeyPhase phase) const; + void set_decryption_key_available(QUICKeyPhase phase); + + const uint8_t *decryption_key(QUICKeyPhase phase) const; + uint8_t *decryption_key(QUICKeyPhase phase); + + const uint8_t *decryption_iv(QUICKeyPhase phase) const; + uint8_t *decryption_iv(QUICKeyPhase phase); + + const size_t *decryption_iv_len(QUICKeyPhase phase) const; + size_t *decryption_iv_len(QUICKeyPhase phase); // Header Protection - const QUIC_EVP_CIPHER *get_cipher_for_hp_initial() const; + const QUIC_EVP_CIPHER *get_cipher_for_hp(QUICKeyPhase phase) const; void set_cipher_for_hp_initial(const QUIC_EVP_CIPHER *cipher); - - const QUIC_EVP_CIPHER *get_cipher_for_hp(QUICEncryptionLevel level) const; void set_cipher_for_hp(const QUIC_EVP_CIPHER *cipher); - const uint8_t *encryption_key_for_hp(QUICEncryptionLevel level) const; - uint8_t *encryption_key_for_hp(QUICEncryptionLevel level); + const uint8_t *encryption_key_for_hp(QUICKeyPhase phase) const; + uint8_t *encryption_key_for_hp(QUICKeyPhase phase); - const uint8_t *decryption_key_for_hp(QUICEncryptionLevel level) const; - uint8_t *decryption_key_for_hp(QUICEncryptionLevel level); + const uint8_t *decryption_key_for_hp(QUICKeyPhase phase) const; + uint8_t *decryption_key_for_hp(QUICKeyPhase phase); private: Context _ctx = Context::SERVER; + // Payload Protection + + const QUIC_EVP_CIPHER *_cipher_initial = nullptr; + const QUIC_EVP_CIPHER *_cipher = nullptr; + size_t _tag_len = 0; + + bool _is_client_key_available[5] = {false}; + bool _is_server_key_available[5] = {false}; + + uint8_t _client_key[5][512]; + uint8_t _server_key[5][512]; + + uint8_t _client_iv[5][512]; + uint8_t _server_iv[5][512]; + + size_t _client_iv_len[5]; + size_t _server_iv_len[5]; + + // Header Protection + const QUIC_EVP_CIPHER *_cipher_for_hp_initial = nullptr; const QUIC_EVP_CIPHER *_cipher_for_hp = nullptr; - uint8_t _client_key_for_hp[4][512]; - uint8_t _server_key_for_hp[4][512]; + uint8_t _client_key_for_hp[5][512]; + uint8_t _server_key_for_hp[5][512]; }; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index ad92be25120..b0176984d9a 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -92,19 +92,10 @@ QUICTLS::is_ready_to_derive() const } } -bool -QUICTLS::is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const -{ - if (key_phase == QUICKeyPhase::ZERO_RTT) { - return this->_client_pp->get_key(QUICKeyPhase::ZERO_RTT); - } else { - return this->_get_km(key_phase, for_encryption); - } -} - int QUICTLS::initialize_key_materials(QUICConnectionId cid) { + this->_pp_key_info.set_cipher_initial(EVP_aes_128_gcm()); this->_pp_key_info.set_cipher_for_hp_initial(EVP_aes_128_ecb()); // Generate keys @@ -113,11 +104,23 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) std::unique_ptr km_server; if (this->_netvc_context == NET_VCONNECTION_IN) { - km_client = this->_keygen_for_client.generate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::INITIAL), cid); - km_server = this->_keygen_for_server.generate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::INITIAL), cid); + km_client = this->_keygen_for_client.generate( + this->_pp_key_info.decryption_key_for_hp(QUICKeyPhase::INITIAL), this->_pp_key_info.decryption_key(QUICKeyPhase::INITIAL), + this->_pp_key_info.decryption_iv(QUICKeyPhase::INITIAL), this->_pp_key_info.decryption_iv_len(QUICKeyPhase::INITIAL), cid); + this->_pp_key_info.set_decryption_key_available(QUICKeyPhase::INITIAL); + km_server = this->_keygen_for_server.generate( + this->_pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL), this->_pp_key_info.encryption_key(QUICKeyPhase::INITIAL), + this->_pp_key_info.encryption_iv(QUICKeyPhase::INITIAL), this->_pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL), cid); + this->_pp_key_info.set_encryption_key_available(QUICKeyPhase::INITIAL); } else { - km_client = this->_keygen_for_client.generate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::INITIAL), cid); - km_server = this->_keygen_for_server.generate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::INITIAL), cid); + km_client = this->_keygen_for_client.generate( + this->_pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL), this->_pp_key_info.encryption_key(QUICKeyPhase::INITIAL), + this->_pp_key_info.encryption_iv(QUICKeyPhase::INITIAL), this->_pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL), cid); + this->_pp_key_info.set_encryption_key_available(QUICKeyPhase::INITIAL); + km_server = this->_keygen_for_server.generate( + this->_pp_key_info.decryption_key_for_hp(QUICKeyPhase::INITIAL), this->_pp_key_info.decryption_key(QUICKeyPhase::INITIAL), + this->_pp_key_info.decryption_iv(QUICKeyPhase::INITIAL), this->_pp_key_info.decryption_iv_len(QUICKeyPhase::INITIAL), cid); + this->_pp_key_info.set_decryption_key_available(QUICKeyPhase::INITIAL); } this->_print_km("initial - client", *km_client); @@ -129,18 +132,6 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) return 1; } -const KeyMaterial * -QUICTLS::key_material_for_encryption(QUICKeyPhase phase) const -{ - return this->_get_km(phase, true); -} - -const KeyMaterial * -QUICTLS::key_material_for_decryption(QUICKeyPhase phase) const -{ - return this->_get_km(phase, false); -} - const char * QUICTLS::negotiated_cipher_suite() const { @@ -177,99 +168,6 @@ QUICTLS::_update_encryption_level(QUICEncryptionLevel level) return; } -bool -QUICTLS::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const -{ - size_t tag_len = this->_get_aead_tag_len(phase); - const KeyMaterial *km = this->key_material_for_encryption(phase); - if (!km) { - Debug(tag, "Failed to encrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); - return false; - } - const QUIC_EVP_CIPHER *aead = this->_get_evp_aead(phase); - - bool ret = _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, *km, aead, tag_len); - if (!ret) { - Debug(tag, "Failed to encrypt a packet #%" PRIu64, pkt_num); - } - return ret; -} - -bool -QUICTLS::decrypt(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, QUICKeyPhase phase) const -{ - size_t tag_len = this->_get_aead_tag_len(phase); - const KeyMaterial *km = this->key_material_for_decryption(phase); - if (!km) { - Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); - return false; - } - const QUIC_EVP_CIPHER *aead = this->_get_evp_aead(phase); - bool ret = _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, *km, aead, tag_len); - if (!ret) { - Debug(tag, "Failed to decrypt a packet #%" PRIu64, pkt_num); - } - return ret; -} - -/** - * Example iv_len = 12 - * - * 0 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 (byte) - * +-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | iv | // IV - * +-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |0|0|0|0| pkt num | // network byte order & left-padded with zeros - * +-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | nonce | // nonce = iv xor pkt_num - * +-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - */ -void -QUICTLS::_gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const -{ - nonce_len = iv_len; - memcpy(nonce, iv, iv_len); - - pkt_num = htobe64(pkt_num); - uint8_t *p = reinterpret_cast(&pkt_num); - - for (size_t i = 0; i < 8; ++i) { - nonce[iv_len - 8 + i] ^= p[i]; - } -} - -const KeyMaterial * -QUICTLS::_get_km(QUICKeyPhase phase, bool for_encryption) const -{ - QUICPacketProtection *pp = nullptr; - - switch (this->_netvc_context) { - case NET_VCONNECTION_IN: - if (for_encryption) { - pp = this->_server_pp; - } else { - pp = this->_client_pp; - } - break; - case NET_VCONNECTION_OUT: - if (for_encryption) { - pp = this->_client_pp; - } else { - pp = this->_server_pp; - } - break; - default: - ink_assert(!"It should not happen"); - return nullptr; - } - - return pp->get_key(phase); -} - void QUICTLS::_print_km(const char *header, KeyMaterial &km, const uint8_t *secret, size_t secret_len) { diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index e7a5479a22b..5618d530f4c 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -65,42 +65,28 @@ class QUICTLS : public QUICHandshakeProtocol void reset() override; bool is_handshake_finished() const override; bool is_ready_to_derive() const override; - bool is_key_derived(QUICKeyPhase key_phase, bool for_encryption) const override; int initialize_key_materials(QUICConnectionId cid) override; void update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t secret_len); const char *negotiated_cipher_suite() const override; void negotiated_application_name(const uint8_t **name, unsigned int *len) const override; - const KeyMaterial *key_material_for_encryption(QUICKeyPhase phase) const override; - const KeyMaterial *key_material_for_decryption(QUICKeyPhase phase) const override; - - bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, - const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override; - bool decrypt(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, QUICKeyPhase phase) const override; QUICEncryptionLevel current_encryption_level() const override; void abort_handshake() override; private: QUICKeyGenerator _keygen_for_client = QUICKeyGenerator(QUICKeyGenerator::Context::CLIENT); QUICKeyGenerator _keygen_for_server = QUICKeyGenerator(QUICKeyGenerator::Context::SERVER); - void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; - const QUIC_EVP_CIPHER *_get_evp_aead(QUICKeyPhase phase) const; const EVP_MD *_get_handshake_digest() const; - size_t _get_aead_tag_len(QUICKeyPhase phase) const; - const KeyMaterial *_get_km(QUICKeyPhase phase, bool for_encryption) const; - - bool _encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const QUIC_EVP_CIPHER *aead, - size_t tag_len) const; - bool _decrypt(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 KeyMaterial &km, const QUIC_EVP_CIPHER *aead, size_t tag_len) const; + int _read_early_data(); int _write_early_data(); int _handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in); int _process_post_handshake_messages(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in); void _generate_0rtt_key(); void _update_encryption_level(QUICEncryptionLevel level); + + void _store_negotiated_cipher(); void _store_negotiated_cipher_for_hp(); + void _print_km(const char *header, KeyMaterial &km, const uint8_t *secret = nullptr, size_t secret_len = 0); SSL *_ssl = nullptr; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 2b315104c88..5ad6ee82b4b 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -186,17 +186,24 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t QUICHKDF hkdf(this->_get_handshake_digest()); std::unique_ptr km = nullptr; + this->_store_negotiated_cipher(); + this->_store_negotiated_cipher_for_hp(); + switch (name) { case SSL_KEY_CLIENT_EARLY_TRAFFIC: // this->_update_encryption_level(QUICEncryptionLevel::ZERO_RTT); phase = QUICKeyPhase::ZERO_RTT; - cipher = this->_get_evp_aead(phase); + cipher = this->_pp_key_info.get_cipher(phase); if (this->_netvc_context == NET_VCONNECTION_IN) { - km = this->_keygen_for_client.regenerate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::ZERO_RTT), secret, - secret_len, cipher, hkdf); + km = this->_keygen_for_client.regenerate(this->_pp_key_info.decryption_key_for_hp(phase), + this->_pp_key_info.decryption_key(phase), this->_pp_key_info.decryption_iv(phase), + this->_pp_key_info.decryption_iv_len(phase), secret, secret_len, cipher, hkdf); + this->_pp_key_info.set_decryption_key_available(phase); } else { - km = this->_keygen_for_client.regenerate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::ZERO_RTT), secret, - secret_len, cipher, hkdf); + km = this->_keygen_for_client.regenerate(this->_pp_key_info.encryption_key_for_hp(phase), + this->_pp_key_info.encryption_key(phase), this->_pp_key_info.encryption_iv(phase), + this->_pp_key_info.encryption_iv_len(phase), secret, secret_len, cipher, hkdf); + this->_pp_key_info.set_encryption_key_available(phase); } this->_print_km("update - client - 0rtt", *km, secret, secret_len); this->_client_pp->set_key(std::move(km), phase); @@ -204,13 +211,17 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); phase = QUICKeyPhase::HANDSHAKE; - cipher = this->_get_evp_aead(phase); + cipher = this->_pp_key_info.get_cipher(phase); if (this->_netvc_context == NET_VCONNECTION_IN) { - km = this->_keygen_for_client.regenerate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::HANDSHAKE), secret, - secret_len, cipher, hkdf); + km = this->_keygen_for_client.regenerate(this->_pp_key_info.decryption_key_for_hp(phase), + this->_pp_key_info.decryption_key(phase), this->_pp_key_info.decryption_iv(phase), + this->_pp_key_info.decryption_iv_len(phase), secret, secret_len, cipher, hkdf); + this->_pp_key_info.set_decryption_key_available(phase); } else { - km = this->_keygen_for_client.regenerate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::HANDSHAKE), secret, - secret_len, cipher, hkdf); + km = this->_keygen_for_client.regenerate(this->_pp_key_info.encryption_key_for_hp(phase), + this->_pp_key_info.encryption_key(phase), this->_pp_key_info.encryption_iv(phase), + this->_pp_key_info.encryption_iv_len(phase), secret, secret_len, cipher, hkdf); + this->_pp_key_info.set_encryption_key_available(phase); } this->_print_km("update - client - handshake", *km, secret, secret_len); this->_client_pp->set_key(std::move(km), phase); @@ -218,13 +229,17 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); phase = QUICKeyPhase::PHASE_0; - cipher = this->_get_evp_aead(phase); + cipher = this->_pp_key_info.get_cipher(phase); if (this->_netvc_context == NET_VCONNECTION_IN) { - km = this->_keygen_for_client.regenerate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::ONE_RTT), secret, - secret_len, cipher, hkdf); + km = this->_keygen_for_client.regenerate(this->_pp_key_info.decryption_key_for_hp(phase), + this->_pp_key_info.decryption_key(phase), this->_pp_key_info.decryption_iv(phase), + this->_pp_key_info.decryption_iv_len(phase), secret, secret_len, cipher, hkdf); + this->_pp_key_info.set_decryption_key_available(phase); } else { - km = this->_keygen_for_client.regenerate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::ONE_RTT), secret, - secret_len, cipher, hkdf); + km = this->_keygen_for_client.regenerate(this->_pp_key_info.encryption_key_for_hp(phase), + this->_pp_key_info.encryption_key(phase), this->_pp_key_info.encryption_iv(phase), + this->_pp_key_info.encryption_iv_len(phase), secret, secret_len, cipher, hkdf); + this->_pp_key_info.set_encryption_key_available(phase); } this->_print_km("update - client - 1rtt", *km, secret, secret_len); this->_client_pp->set_key(std::move(km), phase); @@ -232,13 +247,17 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); phase = QUICKeyPhase::HANDSHAKE; - cipher = this->_get_evp_aead(phase); + cipher = this->_pp_key_info.get_cipher(phase); if (this->_netvc_context == NET_VCONNECTION_IN) { - km = this->_keygen_for_server.regenerate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::HANDSHAKE), secret, - secret_len, cipher, hkdf); + km = this->_keygen_for_server.regenerate(this->_pp_key_info.encryption_key_for_hp(phase), + this->_pp_key_info.encryption_key(phase), this->_pp_key_info.encryption_iv(phase), + this->_pp_key_info.encryption_iv_len(phase), secret, secret_len, cipher, hkdf); + this->_pp_key_info.set_encryption_key_available(phase); } else { - km = this->_keygen_for_server.regenerate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::HANDSHAKE), secret, - secret_len, cipher, hkdf); + km = this->_keygen_for_server.regenerate(this->_pp_key_info.decryption_key_for_hp(phase), + this->_pp_key_info.decryption_key(phase), this->_pp_key_info.decryption_iv(phase), + this->_pp_key_info.decryption_iv_len(phase), secret, secret_len, cipher, hkdf); + this->_pp_key_info.set_decryption_key_available(phase); } this->_print_km("update - server - handshake", *km, secret, secret_len); this->_server_pp->set_key(std::move(km), phase); @@ -246,13 +265,17 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t case SSL_KEY_SERVER_APPLICATION_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); phase = QUICKeyPhase::PHASE_0; - cipher = this->_get_evp_aead(phase); + cipher = this->_pp_key_info.get_cipher(phase); if (this->_netvc_context == NET_VCONNECTION_IN) { - km = this->_keygen_for_server.regenerate(this->_pp_key_info.encryption_key_for_hp(QUICEncryptionLevel::ONE_RTT), secret, - secret_len, cipher, hkdf); + km = this->_keygen_for_server.regenerate(this->_pp_key_info.encryption_key_for_hp(phase), + this->_pp_key_info.encryption_key(phase), this->_pp_key_info.encryption_iv(phase), + this->_pp_key_info.encryption_iv_len(phase), secret, secret_len, cipher, hkdf); + this->_pp_key_info.set_encryption_key_available(phase); } else { - km = this->_keygen_for_server.regenerate(this->_pp_key_info.decryption_key_for_hp(QUICEncryptionLevel::ONE_RTT), secret, - secret_len, cipher, hkdf); + km = this->_keygen_for_server.regenerate(this->_pp_key_info.decryption_key_for_hp(phase), + this->_pp_key_info.decryption_key(phase), this->_pp_key_info.decryption_iv(phase), + this->_pp_key_info.decryption_iv_len(phase), secret, secret_len, cipher, hkdf); + this->_pp_key_info.set_decryption_key_available(phase); } this->_print_km("update - server - 1rtt", *km, secret, secret_len); this->_server_pp->set_key(std::move(km), phase); @@ -261,8 +284,6 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t break; } - this->_store_negotiated_cipher_for_hp(); - return; } @@ -457,16 +478,57 @@ QUICTLS::reset() SSL_clear(this->_ssl); } +void +QUICTLS::_store_negotiated_cipher() +{ + ink_assert(this->_ssl); + + const QUIC_EVP_CIPHER *cipher = nullptr; + size_t tag_len = 0; + const SSL_CIPHER *ssl_cipher = SSL_get_current_cipher(this->_ssl); + + if (ssl_cipher) { + switch (SSL_CIPHER_get_id(ssl_cipher)) { + case TLS1_3_CK_AES_128_GCM_SHA256: + cipher = EVP_aes_128_gcm(); + tag_len = EVP_GCM_TLS_TAG_LEN; + break; + case TLS1_3_CK_AES_256_GCM_SHA384: + cipher = EVP_aes_256_gcm(); + tag_len = EVP_GCM_TLS_TAG_LEN; + break; + case TLS1_3_CK_CHACHA20_POLY1305_SHA256: + cipher = EVP_chacha20_poly1305(); + tag_len = EVP_CHACHAPOLY_TLS_TAG_LEN; + break; + case TLS1_3_CK_AES_128_CCM_SHA256: + cipher = EVP_aes_128_ccm(); + tag_len = EVP_GCM_TLS_TAG_LEN; + break; + case TLS1_3_CK_AES_128_CCM_8_SHA256: + cipher = EVP_aes_128_ccm(); + tag_len = EVP_CCM8_TLS_TAG_LEN; + break; + default: + ink_assert(false); + } + } else { + ink_assert(false); + } + + this->_pp_key_info.set_cipher(cipher, tag_len); +} + void QUICTLS::_store_negotiated_cipher_for_hp() { ink_assert(this->_ssl); const QUIC_EVP_CIPHER *cipher_for_hp = nullptr; - const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); + const SSL_CIPHER *ssl_cipher = SSL_get_current_cipher(this->_ssl); - if (cipher) { - switch (SSL_CIPHER_get_id(cipher)) { + if (ssl_cipher) { + switch (SSL_CIPHER_get_id(ssl_cipher)) { case TLS1_3_CK_AES_128_GCM_SHA256: cipher_for_hp = EVP_aes_128_ecb(); break; @@ -516,64 +578,6 @@ QUICTLS::_write_early_data() return 1; } -const EVP_CIPHER * -QUICTLS::_get_evp_aead(QUICKeyPhase phase) const -{ - if (phase == QUICKeyPhase::INITIAL) { - return EVP_aes_128_gcm(); - } else { - const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); - if (cipher) { - switch (SSL_CIPHER_get_id(cipher)) { - case TLS1_3_CK_AES_128_GCM_SHA256: - return EVP_aes_128_gcm(); - case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_aes_256_gcm(); - case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_chacha20_poly1305(); - case TLS1_3_CK_AES_128_CCM_SHA256: - case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_aes_128_ccm(); - default: - ink_assert(false); - return nullptr; - } - } else { - ink_assert(false); - return nullptr; - } - } -} - -size_t -QUICTLS::_get_aead_tag_len(QUICKeyPhase phase) const -{ - if (phase == QUICKeyPhase::INITIAL) { - return EVP_GCM_TLS_TAG_LEN; - } else { - const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl); - if (cipher) { - switch (SSL_CIPHER_get_id(cipher)) { - case TLS1_3_CK_AES_128_GCM_SHA256: - case TLS1_3_CK_AES_256_GCM_SHA384: - return EVP_GCM_TLS_TAG_LEN; - case TLS1_3_CK_CHACHA20_POLY1305_SHA256: - return EVP_CHACHAPOLY_TLS_TAG_LEN; - case TLS1_3_CK_AES_128_CCM_SHA256: - return EVP_CCM_TLS_TAG_LEN; - case TLS1_3_CK_AES_128_CCM_8_SHA256: - return EVP_CCM8_TLS_TAG_LEN; - default: - ink_assert(false); - return -1; - } - } else { - ink_assert(false); - return -1; - } - } -} - const EVP_MD * QUICTLS::_get_handshake_digest() const { @@ -590,107 +594,3 @@ QUICTLS::_get_handshake_digest() const return nullptr; } } - -bool -QUICTLS::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, - uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, const EVP_CIPHER *aead, - size_t tag_len) const -{ - uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; - size_t nonce_len = 0; - _gen_nonce(nonce, nonce_len, pkt_num, km.iv, km.iv_len); - - EVP_CIPHER_CTX *aead_ctx; - int 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, km.key, nonce)) { - return false; - } - if (!EVP_EncryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) { - return false; - } - if (!EVP_EncryptUpdate(aead_ctx, cipher, &len, plain, plain_len)) { - return false; - } - cipher_len = len; - - if (!EVP_EncryptFinal_ex(aead_ctx, 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 -QUICTLS::_decrypt(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 KeyMaterial &km, const EVP_CIPHER *aead, - size_t tag_len) const -{ - uint8_t nonce[EVP_MAX_IV_LENGTH] = {0}; - size_t nonce_len = 0; - _gen_nonce(nonce, nonce_len, pkt_num, km.iv, km.iv_len); - - EVP_CIPHER_CTX *aead_ctx; - int 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, km.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(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; - } -} From 3968cf7b588449ef6cc1bf16ca3042c27067203a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Feb 2019 12:34:47 +0900 Subject: [PATCH 1155/1313] Remove QUICPacketProtection --- iocore/net/quic/Makefile.am | 1 - iocore/net/quic/QUICHandshakeProtocol.cc | 45 ------------------------ iocore/net/quic/QUICHandshakeProtocol.h | 15 -------- iocore/net/quic/QUICTLS.cc | 6 ---- iocore/net/quic/QUICTLS.h | 2 -- iocore/net/quic/QUICTLS_boringssl.cc | 3 -- iocore/net/quic/QUICTLS_openssl.cc | 8 ----- 7 files changed, 80 deletions(-) delete mode 100644 iocore/net/quic/QUICHandshakeProtocol.cc diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 5b23b8c8d0e..a480ecbef67 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -61,7 +61,6 @@ libquic_a_SOURCES = \ QUICStreamState.cc \ QUICStream.cc \ QUICHandshake.cc \ - QUICHandshakeProtocol.cc \ QUICPacketHeaderProtector.cc \ $(QUICPHProtector_impl) \ QUICPacketPayloadProtector.cc \ diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc deleted file mode 100644 index 9f65c1e307e..00000000000 --- a/iocore/net/quic/QUICHandshakeProtocol.cc +++ /dev/null @@ -1,45 +0,0 @@ -/** @file - * - * QUIC Handshake Protocol (TLS to Secure QUIC) - * - * @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 "QUICHandshakeProtocol.h" -#include "QUICTypes.h" -#include "QUICPacketProtectionKeyInfo.h" - -QUICPacketProtection::~QUICPacketProtection() {} - -void -QUICPacketProtection::set_key(std::unique_ptr km, QUICKeyPhase phase) -{ - this->_key_chain[static_cast(phase)] = std::move(km); -} - -const KeyMaterial * -QUICPacketProtection::get_key(QUICKeyPhase phase) const -{ - return this->_key_chain[static_cast(phase)].get(); -} - -QUICKeyPhase -QUICPacketProtection::key_phase() const -{ - return this->_key_phase; -} diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h index 98a056519d7..fd4c68b65c1 100644 --- a/iocore/net/quic/QUICHandshakeProtocol.h +++ b/iocore/net/quic/QUICHandshakeProtocol.h @@ -30,21 +30,6 @@ class QUICHandshakeProtocol; class QUICPacketProtectionKeyInfo; -class QUICPacketProtection -{ -public: - QUICPacketProtection(){}; - ~QUICPacketProtection(); - void set_key(std::unique_ptr km, QUICKeyPhase phase); - const KeyMaterial *get_key(QUICKeyPhase phase) const; - QUICKeyPhase key_phase() const; - -private: - // TODO: discard keys - std::unique_ptr _key_chain[5] = {nullptr}; - QUICKeyPhase _key_phase = QUICKeyPhase::INITIAL; -}; - struct QUICHandshakeMsgs { uint8_t *buf = nullptr; //< pointer to the buffer size_t max_buf_len = 0; //< size of buffer diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index b0176984d9a..cf7d61d83bb 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -65,9 +65,6 @@ QUICTLS::set_remote_transport_parameters(std::shared_ptr_ssl); - - delete this->_client_pp; - delete this->_server_pp; } uint16_t @@ -126,9 +123,6 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) this->_print_km("initial - client", *km_client); this->_print_km("initial - server", *km_server); - this->_client_pp->set_key(std::move(km_client), QUICKeyPhase::INITIAL); - this->_server_pp->set_key(std::move(km_server), QUICKeyPhase::INITIAL); - return 1; } diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 5618d530f4c..e7689ae9fbf 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -90,8 +90,6 @@ class QUICTLS : public QUICHandshakeProtocol void _print_km(const char *header, KeyMaterial &km, const uint8_t *secret = nullptr, size_t secret_len = 0); SSL *_ssl = nullptr; - QUICPacketProtection *_client_pp = nullptr; - QUICPacketProtection *_server_pp = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; bool _early_data_processed = false; bool _is_session_reused = false; diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc index 935ef4c7e7d..966d69a8f97 100644 --- a/iocore/net/quic/QUICTLS_boringssl.cc +++ b/iocore/net/quic/QUICTLS_boringssl.cc @@ -37,9 +37,6 @@ QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless) : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx), _stateless(stateless) { ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); - - this->_client_pp = new QUICPacketProtection(); - this->_server_pp = new QUICPacketProtection(); } int diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 5ad6ee82b4b..289631ab877 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -206,7 +206,6 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t this->_pp_key_info.set_encryption_key_available(phase); } this->_print_km("update - client - 0rtt", *km, secret, secret_len); - this->_client_pp->set_key(std::move(km), phase); break; case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); @@ -224,7 +223,6 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t this->_pp_key_info.set_encryption_key_available(phase); } this->_print_km("update - client - handshake", *km, secret, secret_len); - this->_client_pp->set_key(std::move(km), phase); break; case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); @@ -242,7 +240,6 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t this->_pp_key_info.set_encryption_key_available(phase); } this->_print_km("update - client - 1rtt", *km, secret, secret_len); - this->_client_pp->set_key(std::move(km), phase); break; case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); @@ -260,7 +257,6 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t this->_pp_key_info.set_decryption_key_available(phase); } this->_print_km("update - server - handshake", *km, secret, secret_len); - this->_server_pp->set_key(std::move(km), phase); break; case SSL_KEY_SERVER_APPLICATION_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); @@ -278,7 +274,6 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t this->_pp_key_info.set_decryption_key_available(phase); } this->_print_km("update - server - 1rtt", *km, secret, secret_len); - this->_server_pp->set_key(std::move(km), phase); break; default: break; @@ -298,9 +293,6 @@ QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, Net SSL_set_accept_state(this->_ssl); } - this->_client_pp = new QUICPacketProtection(); - this->_server_pp = new QUICPacketProtection(); - SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_tls_index, this); SSL_set_key_callback(this->_ssl, key_cb, this); From 5b5a16fdfb38096933239a0a4c66d80323524397 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Feb 2019 15:54:51 +0900 Subject: [PATCH 1156/1313] Remove KeyingMaterial --- iocore/net/quic/Mock.h | 12 -- iocore/net/quic/QUICKeyGenerator.cc | 37 ++---- iocore/net/quic/QUICKeyGenerator.h | 21 +--- .../net/quic/QUICPacketProtectionKeyInfo.cc | 68 ++++++++++ iocore/net/quic/QUICPacketProtectionKeyInfo.h | 10 ++ iocore/net/quic/QUICTLS.cc | 77 ++++++++---- iocore/net/quic/QUICTLS.h | 3 +- iocore/net/quic/QUICTLS_openssl.cc | 118 ++++++++++++------ 8 files changed, 230 insertions(+), 116 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index d552394f21b..e688f51b4a7 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -562,18 +562,6 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol *len = 2; } - const KeyMaterial * - key_material_for_encryption(QUICKeyPhase phase) const override - { - return nullptr; - } - - const KeyMaterial * - key_material_for_decryption(QUICKeyPhase phase) const override - { - return nullptr; - } - const QUIC_EVP_CIPHER * cipher_for_hp(QUICKeyPhase phase) const override { diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 2cb31b41f86..9b2a1d644e8 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -42,11 +42,9 @@ constexpr static std::string_view LABEL_FOR_KEY("quic key"sv); constexpr static std::string_view LABEL_FOR_IV("quic iv"sv); constexpr static std::string_view LABEL_FOR_HP("quic hp"sv); -std::unique_ptr +void QUICKeyGenerator::generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, QUICConnectionId cid) { - std::unique_ptr km = std::make_unique(); - const QUIC_EVP_CIPHER *cipher = this->_get_cipher_for_initial(); const EVP_MD *md = EVP_sha256(); uint8_t secret[512]; @@ -76,43 +74,28 @@ QUICKeyGenerator::generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t break; } - this->_generate(*km, hkdf, secret, secret_len, cipher); - - memcpy(hp_key, km->hp, 512); - memcpy(pp_key, km->key, 512); - memcpy(iv, km->iv, 512); - *iv_len = km->iv_len; - - return km; + this->_generate(hp_key, pp_key, iv, iv_len, hkdf, secret, secret_len, cipher); } -std::unique_ptr +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) { - std::unique_ptr km = std::make_unique(); - - this->_generate(*km, hkdf, secret, secret_len, cipher); - - memcpy(hp_key, km->hp, 512); - memcpy(pp_key, km->key, 512); - memcpy(iv, km->iv, 512); - *iv_len = km->iv_len; - - return km; + this->_generate(hp_key, pp_key, iv, iv_len, hkdf, secret, secret_len, cipher); } int -QUICKeyGenerator::_generate(KeyMaterial &km, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, - const QUIC_EVP_CIPHER *cipher) +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) { // Generate key, iv, and hp_key // key = HKDF-Expand-Label(S, "quic key", "", key_length) // iv = HKDF-Expand-Label(S, "quic iv", "", iv_length) // hp_key = HKDF-Expand-Label(S, "quic hp", "", hp_key_length) - this->_generate_key(km.key, &km.key_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); - this->_generate_iv(km.iv, &km.iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher)); - this->_generate_hp(km.hp, &km.hp_len, hkdf, secret, secret_len, this->_get_key_len(cipher)); + size_t dummy; + this->_generate_key(pp_key, &dummy, hkdf, secret, secret_len, this->_get_key_len(cipher)); + this->_generate_iv(iv, iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher)); + this->_generate_hp(hp_key, &dummy, hkdf, secret, secret_len, this->_get_key_len(cipher)); return 0; } diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h index 118eb138971..a82ad43a2a3 100644 --- a/iocore/net/quic/QUICKeyGenerator.h +++ b/iocore/net/quic/QUICKeyGenerator.h @@ -32,18 +32,6 @@ typedef EVP_AEAD QUIC_EVP_CIPHER; typedef EVP_CIPHER QUIC_EVP_CIPHER; #endif // OPENSSL_IS_BORINGSSL -struct KeyMaterial { - // These constant sizes are not enough somehow - // uint8_t key[EVP_MAX_KEY_LENGTH] = {0}; - // uint8_t iv[EVP_MAX_IV_LENGTH] = {0}; - uint8_t key[512] = {0}; - uint8_t iv[512] = {0}; - uint8_t hp[512] = {0}; - size_t key_len = 512; - size_t iv_len = 512; - size_t hp_len = 512; -}; - class QUICKeyGenerator { public: @@ -55,10 +43,10 @@ class QUICKeyGenerator * Generate keys for Initial encryption level * The keys for the remaining encryption level are derived by TLS stack with "quic " prefix */ - std::unique_ptr generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, QUICConnectionId cid); + void generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t *iv_len, QUICConnectionId cid); - std::unique_ptr 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); + 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); private: Context _ctx = Context::SERVER; @@ -66,7 +54,8 @@ class QUICKeyGenerator uint8_t _last_secret[256]; size_t _last_secret_len = 0; - int _generate(KeyMaterial &km, QUICHKDF &hkdf, const uint8_t *secret, size_t secret_len, const QUIC_EVP_CIPHER *cipher); + 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); 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, diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.cc b/iocore/net/quic/QUICPacketProtectionKeyInfo.cc index 7f3986d4671..a08230a7bff 100644 --- a/iocore/net/quic/QUICPacketProtectionKeyInfo.cc +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.cc @@ -91,6 +91,23 @@ QUICPacketProtectionKeyInfo::encryption_key(QUICKeyPhase phase) return const_cast(const_cast(this)->encryption_key(phase)); } +size_t +QUICPacketProtectionKeyInfo::encryption_key_len(QUICKeyPhase phase) const +{ + const QUIC_EVP_CIPHER *cipher; + + switch (phase) { + case QUICKeyPhase::INITIAL: + cipher = this->_cipher_initial; + break; + default: + cipher = this->_cipher; + break; + } + + return EVP_CIPHER_key_length(cipher); +} + const uint8_t * QUICPacketProtectionKeyInfo::encryption_iv(QUICKeyPhase phase) const { @@ -165,6 +182,23 @@ QUICPacketProtectionKeyInfo::decryption_key(QUICKeyPhase phase) return const_cast(const_cast(this)->decryption_key(phase)); } +size_t +QUICPacketProtectionKeyInfo::decryption_key_len(QUICKeyPhase phase) const +{ + const QUIC_EVP_CIPHER *cipher; + + switch (phase) { + case QUICKeyPhase::INITIAL: + cipher = this->_cipher_initial; + break; + default: + cipher = this->_cipher; + break; + } + + return EVP_CIPHER_key_length(cipher); +} + const uint8_t * QUICPacketProtectionKeyInfo::decryption_iv(QUICKeyPhase phase) const { @@ -257,6 +291,23 @@ QUICPacketProtectionKeyInfo::encryption_key_for_hp(QUICKeyPhase phase) } } +size_t +QUICPacketProtectionKeyInfo::encryption_key_for_hp_len(QUICKeyPhase phase) const +{ + const QUIC_EVP_CIPHER *cipher; + + switch (phase) { + case QUICKeyPhase::INITIAL: + cipher = this->_cipher_for_hp_initial; + break; + default: + cipher = this->_cipher_for_hp; + break; + } + + return EVP_CIPHER_key_length(cipher); +} + const uint8_t * QUICPacketProtectionKeyInfo::decryption_key_for_hp(QUICKeyPhase phase) const { @@ -278,3 +329,20 @@ QUICPacketProtectionKeyInfo::decryption_key_for_hp(QUICKeyPhase phase) return this->_server_key_for_hp[index]; } } + +size_t +QUICPacketProtectionKeyInfo::decryption_key_for_hp_len(QUICKeyPhase phase) const +{ + const QUIC_EVP_CIPHER *cipher; + + switch (phase) { + case QUICKeyPhase::INITIAL: + cipher = this->_cipher_for_hp_initial; + break; + default: + cipher = this->_cipher_for_hp; + break; + } + + return EVP_CIPHER_key_length(cipher); +} diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.h b/iocore/net/quic/QUICPacketProtectionKeyInfo.h index 1011444c3be..3dda8eac935 100644 --- a/iocore/net/quic/QUICPacketProtectionKeyInfo.h +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.h @@ -39,6 +39,7 @@ class QUICPacketProtectionKeyInfo void remove_key(QUICKeyPhase phase); // Payload Protection (common) + const QUIC_EVP_CIPHER *get_cipher(QUICKeyPhase phase) const; size_t get_tag_len(QUICKeyPhase phase) const; void set_cipher_initial(const QUIC_EVP_CIPHER *cipher); @@ -52,6 +53,8 @@ class QUICPacketProtectionKeyInfo const uint8_t *encryption_key(QUICKeyPhase phase) const; uint8_t *encryption_key(QUICKeyPhase phase); + size_t encryption_key_len(QUICKeyPhase phase) const; + const uint8_t *encryption_iv(QUICKeyPhase phase) const; uint8_t *encryption_iv(QUICKeyPhase phase); @@ -66,6 +69,8 @@ class QUICPacketProtectionKeyInfo const uint8_t *decryption_key(QUICKeyPhase phase) const; uint8_t *decryption_key(QUICKeyPhase phase); + size_t decryption_key_len(QUICKeyPhase phase) const; + const uint8_t *decryption_iv(QUICKeyPhase phase) const; uint8_t *decryption_iv(QUICKeyPhase phase); @@ -81,9 +86,13 @@ class QUICPacketProtectionKeyInfo const uint8_t *encryption_key_for_hp(QUICKeyPhase phase) const; uint8_t *encryption_key_for_hp(QUICKeyPhase phase); + size_t encryption_key_for_hp_len(QUICKeyPhase phase) const; + const uint8_t *decryption_key_for_hp(QUICKeyPhase phase) const; uint8_t *decryption_key_for_hp(QUICKeyPhase phase); + size_t decryption_key_for_hp_len(QUICKeyPhase phase) const; + private: Context _ctx = Context::SERVER; @@ -96,6 +105,7 @@ class QUICPacketProtectionKeyInfo bool _is_client_key_available[5] = {false}; bool _is_server_key_available[5] = {false}; + // FIXME EVP_MAX_KEY_LENGTH and EVP_MAX_IV_LENGTH are not enough somehow uint8_t _client_key[5][512]; uint8_t _server_key[5][512]; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index cf7d61d83bb..425a4f54265 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -97,31 +97,59 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) // Generate keys Debug(tag, "Generating %s keys", QUICDebugNames::key_phase(QUICKeyPhase::INITIAL)); - std::unique_ptr km_client; - std::unique_ptr km_server; + + uint8_t *client_key_for_hp; + uint8_t *client_key; + uint8_t *client_iv; + size_t client_key_for_hp_len; + size_t client_key_len; + size_t *client_iv_len; + + uint8_t *server_key_for_hp; + uint8_t *server_key; + uint8_t *server_iv; + size_t server_key_for_hp_len; + size_t server_key_len; + size_t *server_iv_len; if (this->_netvc_context == NET_VCONNECTION_IN) { - km_client = this->_keygen_for_client.generate( - this->_pp_key_info.decryption_key_for_hp(QUICKeyPhase::INITIAL), this->_pp_key_info.decryption_key(QUICKeyPhase::INITIAL), - this->_pp_key_info.decryption_iv(QUICKeyPhase::INITIAL), this->_pp_key_info.decryption_iv_len(QUICKeyPhase::INITIAL), cid); - this->_pp_key_info.set_decryption_key_available(QUICKeyPhase::INITIAL); - km_server = this->_keygen_for_server.generate( - this->_pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL), this->_pp_key_info.encryption_key(QUICKeyPhase::INITIAL), - this->_pp_key_info.encryption_iv(QUICKeyPhase::INITIAL), this->_pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL), cid); - this->_pp_key_info.set_encryption_key_available(QUICKeyPhase::INITIAL); + client_key_for_hp = this->_pp_key_info.decryption_key_for_hp(QUICKeyPhase::INITIAL); + client_key_for_hp_len = this->_pp_key_info.decryption_key_for_hp_len(QUICKeyPhase::INITIAL); + client_key = this->_pp_key_info.decryption_key(QUICKeyPhase::INITIAL); + client_key_len = this->_pp_key_info.decryption_key_len(QUICKeyPhase::INITIAL); + client_iv = this->_pp_key_info.decryption_iv(QUICKeyPhase::INITIAL); + client_iv_len = this->_pp_key_info.decryption_iv_len(QUICKeyPhase::INITIAL); + server_key_for_hp = this->_pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL); + server_key_for_hp_len = this->_pp_key_info.encryption_key_for_hp_len(QUICKeyPhase::INITIAL); + server_key = this->_pp_key_info.encryption_key(QUICKeyPhase::INITIAL); + server_key_len = this->_pp_key_info.encryption_key_len(QUICKeyPhase::INITIAL); + server_iv = this->_pp_key_info.encryption_iv(QUICKeyPhase::INITIAL); + server_iv_len = this->_pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL); } else { - km_client = this->_keygen_for_client.generate( - this->_pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL), this->_pp_key_info.encryption_key(QUICKeyPhase::INITIAL), - this->_pp_key_info.encryption_iv(QUICKeyPhase::INITIAL), this->_pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL), cid); - this->_pp_key_info.set_encryption_key_available(QUICKeyPhase::INITIAL); - km_server = this->_keygen_for_server.generate( - this->_pp_key_info.decryption_key_for_hp(QUICKeyPhase::INITIAL), this->_pp_key_info.decryption_key(QUICKeyPhase::INITIAL), - this->_pp_key_info.decryption_iv(QUICKeyPhase::INITIAL), this->_pp_key_info.decryption_iv_len(QUICKeyPhase::INITIAL), cid); - this->_pp_key_info.set_decryption_key_available(QUICKeyPhase::INITIAL); + client_key_for_hp = this->_pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL); + client_key_for_hp_len = this->_pp_key_info.encryption_key_for_hp_len(QUICKeyPhase::INITIAL); + client_key = this->_pp_key_info.encryption_key(QUICKeyPhase::INITIAL); + client_key_len = this->_pp_key_info.encryption_key_len(QUICKeyPhase::INITIAL); + client_iv = this->_pp_key_info.encryption_iv(QUICKeyPhase::INITIAL); + client_iv_len = this->_pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL); + server_key_for_hp = this->_pp_key_info.decryption_key_for_hp(QUICKeyPhase::INITIAL); + server_key_for_hp_len = this->_pp_key_info.decryption_key_for_hp_len(QUICKeyPhase::INITIAL); + server_key = this->_pp_key_info.decryption_key(QUICKeyPhase::INITIAL); + server_key_len = this->_pp_key_info.decryption_key_len(QUICKeyPhase::INITIAL); + server_iv = this->_pp_key_info.decryption_iv(QUICKeyPhase::INITIAL); + server_iv_len = this->_pp_key_info.decryption_iv_len(QUICKeyPhase::INITIAL); } - this->_print_km("initial - client", *km_client); - this->_print_km("initial - server", *km_server); + this->_keygen_for_client.generate(client_key_for_hp, client_key, client_iv, client_iv_len, cid); + this->_keygen_for_server.generate(server_key_for_hp, server_key, server_iv, server_iv_len, cid); + + this->_pp_key_info.set_decryption_key_available(QUICKeyPhase::INITIAL); + this->_pp_key_info.set_encryption_key_available(QUICKeyPhase::INITIAL); + + this->_print_km("initial - server", server_key_for_hp, server_key_for_hp_len, server_key, server_key_len, server_iv, + *server_iv_len); + this->_print_km("initial - client", client_key_for_hp, client_key_for_hp_len, client_key, server_key_len, client_iv, + *client_iv_len); return 1; } @@ -163,7 +191,8 @@ QUICTLS::_update_encryption_level(QUICEncryptionLevel level) } void -QUICTLS::_print_km(const char *header, KeyMaterial &km, const uint8_t *secret, size_t secret_len) +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) { if (is_debug_tag_set("vv_quic_crypto")) { Debug("vv_quic_crypto", "%s", header); @@ -172,11 +201,11 @@ QUICTLS::_print_km(const char *header, KeyMaterial &km, const uint8_t *secret, s QUICDebug::to_hex(print_buf, static_cast(secret), secret_len); Debug("vv_quic_crypto", "secret=%s", print_buf); } - QUICDebug::to_hex(print_buf, km.key, km.key_len); + QUICDebug::to_hex(print_buf, key, key_len); Debug("vv_quic_crypto", "key=%s", print_buf); - QUICDebug::to_hex(print_buf, km.iv, km.iv_len); + QUICDebug::to_hex(print_buf, iv, iv_len); Debug("vv_quic_crypto", "iv=%s", print_buf); - QUICDebug::to_hex(print_buf, km.hp, km.hp_len); + QUICDebug::to_hex(print_buf, key_for_hp, key_for_hp_len); Debug("vv_quic_crypto", "hp=%s", print_buf); } } diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index e7689ae9fbf..ee88bab4a8d 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -87,7 +87,8 @@ class QUICTLS : public QUICHandshakeProtocol void _store_negotiated_cipher(); void _store_negotiated_cipher_for_hp(); - void _print_km(const char *header, KeyMaterial &km, const uint8_t *secret = nullptr, size_t secret_len = 0); + void _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 = nullptr, size_t secret_len = 0); SSL *_ssl = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 289631ab877..5edf90ac72d 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -184,96 +184,142 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t QUICKeyPhase phase; const QUIC_EVP_CIPHER *cipher; QUICHKDF hkdf(this->_get_handshake_digest()); - std::unique_ptr km = nullptr; this->_store_negotiated_cipher(); this->_store_negotiated_cipher_for_hp(); + 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; + switch (name) { case SSL_KEY_CLIENT_EARLY_TRAFFIC: // this->_update_encryption_level(QUICEncryptionLevel::ZERO_RTT); phase = QUICKeyPhase::ZERO_RTT; cipher = this->_pp_key_info.get_cipher(phase); if (this->_netvc_context == NET_VCONNECTION_IN) { - km = this->_keygen_for_client.regenerate(this->_pp_key_info.decryption_key_for_hp(phase), - this->_pp_key_info.decryption_key(phase), this->_pp_key_info.decryption_iv(phase), - this->_pp_key_info.decryption_iv_len(phase), secret, secret_len, cipher, hkdf); + 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); + this->_keygen_for_client.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf); this->_pp_key_info.set_decryption_key_available(phase); } else { - km = this->_keygen_for_client.regenerate(this->_pp_key_info.encryption_key_for_hp(phase), - this->_pp_key_info.encryption_key(phase), this->_pp_key_info.encryption_iv(phase), - this->_pp_key_info.encryption_iv_len(phase), secret, secret_len, cipher, hkdf); + 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); + this->_keygen_for_client.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf); this->_pp_key_info.set_encryption_key_available(phase); } - this->_print_km("update - client - 0rtt", *km, secret, secret_len); + this->_print_km("update - client - 0rtt", key_for_hp, key_for_hp_len, key, key_len, iv, *iv_len, secret, secret_len); break; case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); phase = QUICKeyPhase::HANDSHAKE; cipher = this->_pp_key_info.get_cipher(phase); if (this->_netvc_context == NET_VCONNECTION_IN) { - km = this->_keygen_for_client.regenerate(this->_pp_key_info.decryption_key_for_hp(phase), - this->_pp_key_info.decryption_key(phase), this->_pp_key_info.decryption_iv(phase), - this->_pp_key_info.decryption_iv_len(phase), secret, secret_len, cipher, hkdf); + 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); + this->_keygen_for_client.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf); this->_pp_key_info.set_decryption_key_available(phase); } else { - km = this->_keygen_for_client.regenerate(this->_pp_key_info.encryption_key_for_hp(phase), - this->_pp_key_info.encryption_key(phase), this->_pp_key_info.encryption_iv(phase), - this->_pp_key_info.encryption_iv_len(phase), secret, secret_len, cipher, hkdf); + 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); + this->_keygen_for_client.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf); this->_pp_key_info.set_encryption_key_available(phase); } - this->_print_km("update - client - handshake", *km, secret, secret_len); + this->_print_km("update - client - handshake", key_for_hp, key_for_hp_len, key, key_len, iv, *iv_len, secret, secret_len); break; case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); phase = QUICKeyPhase::PHASE_0; cipher = this->_pp_key_info.get_cipher(phase); if (this->_netvc_context == NET_VCONNECTION_IN) { - km = this->_keygen_for_client.regenerate(this->_pp_key_info.decryption_key_for_hp(phase), - this->_pp_key_info.decryption_key(phase), this->_pp_key_info.decryption_iv(phase), - this->_pp_key_info.decryption_iv_len(phase), secret, secret_len, cipher, hkdf); + 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); + this->_keygen_for_client.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf); this->_pp_key_info.set_decryption_key_available(phase); } else { - km = this->_keygen_for_client.regenerate(this->_pp_key_info.encryption_key_for_hp(phase), - this->_pp_key_info.encryption_key(phase), this->_pp_key_info.encryption_iv(phase), - this->_pp_key_info.encryption_iv_len(phase), secret, secret_len, cipher, hkdf); + 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); + this->_keygen_for_client.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf); this->_pp_key_info.set_encryption_key_available(phase); } - this->_print_km("update - client - 1rtt", *km, secret, secret_len); + this->_print_km("update - client - 1rtt", key_for_hp, key_for_hp_len, key, key_len, iv, *iv_len, secret, secret_len); break; case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::HANDSHAKE); phase = QUICKeyPhase::HANDSHAKE; cipher = this->_pp_key_info.get_cipher(phase); if (this->_netvc_context == NET_VCONNECTION_IN) { - km = this->_keygen_for_server.regenerate(this->_pp_key_info.encryption_key_for_hp(phase), - this->_pp_key_info.encryption_key(phase), this->_pp_key_info.encryption_iv(phase), - this->_pp_key_info.encryption_iv_len(phase), secret, secret_len, cipher, hkdf); + 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); + this->_keygen_for_server.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf); this->_pp_key_info.set_encryption_key_available(phase); } else { - km = this->_keygen_for_server.regenerate(this->_pp_key_info.decryption_key_for_hp(phase), - this->_pp_key_info.decryption_key(phase), this->_pp_key_info.decryption_iv(phase), - this->_pp_key_info.decryption_iv_len(phase), secret, secret_len, cipher, hkdf); + 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); + this->_keygen_for_server.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf); this->_pp_key_info.set_decryption_key_available(phase); } - this->_print_km("update - server - handshake", *km, secret, secret_len); + this->_print_km("update - server - handshake", key_for_hp, key_for_hp_len, key, key_len, iv, *iv_len, secret, secret_len); break; case SSL_KEY_SERVER_APPLICATION_TRAFFIC: this->_update_encryption_level(QUICEncryptionLevel::ONE_RTT); phase = QUICKeyPhase::PHASE_0; cipher = this->_pp_key_info.get_cipher(phase); if (this->_netvc_context == NET_VCONNECTION_IN) { - km = this->_keygen_for_server.regenerate(this->_pp_key_info.encryption_key_for_hp(phase), - this->_pp_key_info.encryption_key(phase), this->_pp_key_info.encryption_iv(phase), - this->_pp_key_info.encryption_iv_len(phase), secret, secret_len, cipher, hkdf); + 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); + this->_keygen_for_server.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf); this->_pp_key_info.set_encryption_key_available(phase); } else { - km = this->_keygen_for_server.regenerate(this->_pp_key_info.decryption_key_for_hp(phase), - this->_pp_key_info.decryption_key(phase), this->_pp_key_info.decryption_iv(phase), - this->_pp_key_info.decryption_iv_len(phase), secret, secret_len, cipher, hkdf); + 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); + this->_keygen_for_server.regenerate(key_for_hp, key, iv, iv_len, secret, secret_len, cipher, hkdf); this->_pp_key_info.set_decryption_key_available(phase); } - this->_print_km("update - server - 1rtt", *km, secret, secret_len); + this->_print_km("update - server - 1rtt", key_for_hp, key_for_hp_len, key, key_len, iv, *iv_len, secret, secret_len); break; default: break; From d741a0dcc291bc34e5e73dd194799b8a2cf0f7d4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 21 Feb 2019 17:02:25 +0900 Subject: [PATCH 1157/1313] Remove unused code --- iocore/net/quic/QUICPacketHeaderProtector.cc | 16 ---------------- iocore/net/quic/QUICPacketProtectionKeyInfo.h | 4 +--- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc index de8ebd5f329..f0e88e69b17 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -120,7 +120,6 @@ QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected QUICKeyPhase phase; QUICPacketType type; - QUICEncryptionLevel level; if (QUICInvariants::is_long_header(protected_packet)) { QUICPacketLongHeader::key_phase(phase, protected_packet, protected_packet_len); QUICPacketLongHeader::type(type, protected_packet, protected_packet_len); @@ -129,21 +128,6 @@ QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected phase = QUICKeyPhase::PHASE_0; type = QUICPacketType::PROTECTED; } - switch (phase) { - case QUICKeyPhase::PHASE_0: - case QUICKeyPhase::PHASE_1: - level = QUICEncryptionLevel::ONE_RTT; - break; - case QUICKeyPhase::HANDSHAKE: - level = QUICEncryptionLevel::HANDSHAKE; - break; - case QUICKeyPhase::INITIAL: - level = QUICEncryptionLevel::INITIAL; - break; - case QUICKeyPhase::ZERO_RTT: - level = QUICEncryptionLevel::ZERO_RTT; - break; - } Debug("v_quic_pne", "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), QUICDebugNames::key_phase(phase)); diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.h b/iocore/net/quic/QUICPacketProtectionKeyInfo.h index 3dda8eac935..f18ecfcf65a 100644 --- a/iocore/net/quic/QUICPacketProtectionKeyInfo.h +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.h @@ -34,9 +34,7 @@ class QUICPacketProtectionKeyInfo // FIXME This should be passed to the constructor but NetVC cannot pass it because it has set_context too. void set_context(Context ctx); - void add_key(QUICKeyPhase phase, int key); - void update_key(QUICKeyPhase phase, int key); - void remove_key(QUICKeyPhase phase); + void drop_keys(QUICKeyPhase phase); // Payload Protection (common) From dac64b3b59707d983d5fd5982d27b51f70d570e0 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 22 Feb 2019 15:43:45 +0900 Subject: [PATCH 1158/1313] Make tests buildable --- iocore/net/quic/Mock.h | 35 ++-------------- .../quic/test/test_QUICHandshakeProtocol.cc | 41 +++++++++++++------ iocore/net/quic/test/test_QUICKeyGenerator.cc | 33 ++++++++------- iocore/net/quic/test/test_QUICLossDetector.cc | 5 +-- .../net/quic/test/test_QUICPacketFactory.cc | 21 ++++------ .../test/test_QUICPacketHeaderProtector.cc | 27 ++++++------ .../quic/test/test_QUICVersionNegotiator.cc | 11 +++-- 7 files changed, 80 insertions(+), 93 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index e688f51b4a7..58423f4d11f 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -513,7 +513,8 @@ class MockQUICStreamIO : public QUICStreamIO class MockQUICHandshakeProtocol : public QUICHandshakeProtocol { public: - MockQUICHandshakeProtocol() : QUICHandshakeProtocol() {} + MockQUICHandshakeProtocol(QUICPacketProtectionKeyInfo &pp_key_info) : QUICHandshakeProtocol(pp_key_info) {} + int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) override { @@ -537,12 +538,6 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol return true; } - bool - is_key_derived(QUICKeyPhase /* key_phase */, bool /* for_encryption */) const override - { - return true; - } - int initialize_key_materials(QUICConnectionId cid) override { @@ -562,28 +557,6 @@ class MockQUICHandshakeProtocol : public QUICHandshakeProtocol *len = 2; } - const QUIC_EVP_CIPHER * - cipher_for_hp(QUICKeyPhase phase) const override - { - return nullptr; - } - - bool - encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, - const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const override - { - memcpy(cipher, plain, plain_len); - return true; - } - - bool - decrypt(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, QUICKeyPhase phase) const override - { - memcpy(plain, cipher, cipher_len); - return true; - } - QUICEncryptionLevel current_encryption_level() const override { @@ -713,7 +686,7 @@ class MockQUICFrameGenerator : public QUICFrameGenerator } QUICFrame * - generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) + generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override { QUICFrame *frame = QUICFrameFactory::create_ping_frame(buf, 0, this); QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); @@ -725,7 +698,7 @@ class MockQUICFrameGenerator : public QUICFrameGenerator private: void - _on_frame_lost(QUICFrameInformationUPtr &info) + _on_frame_lost(QUICFrameInformationUPtr &info) override { lost_frame_count++; } diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index a4f51101ad7..91820c95f1d 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -35,6 +35,8 @@ // #include "Mock.h" #include "QUICPacketHeaderProtector.h" +#include "QUICPacketPayloadProtector.h" +#include "QUICPacketProtectionKeyInfo.h" #include "QUICTLS.h" // depends on size of cert @@ -95,8 +97,12 @@ TEST_CASE("QUICHandshakeProtocol") SECTION("Full Handshake", "[quic]") { - QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); - QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); + QUICPacketProtectionKeyInfo pp_key_info_client; + QUICPacketProtectionKeyInfo pp_key_info_server; + QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT); + QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN); + QUICPacketPayloadProtector ppp_client(pp_key_info_client); + QUICPacketPayloadProtector ppp_server(pp_key_info_server); CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); @@ -189,15 +195,16 @@ TEST_CASE("QUICHandshakeProtocol") uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead size_t cipher_len = 0; - CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), - QUICKeyPhase::PHASE_0)); + CHECK(ppp_client.protect(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), + QUICKeyPhase::PHASE_0)); std::cout << "### Encrypted Text" << std::endl; print_hex(cipher, cipher_len); uint8_t plain[128] = {0}; size_t plain_len = 0; - CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); + CHECK( + ppp_server.unprotect(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); std::cout << "### Decrypted Text" << std::endl; print_hex(plain, plain_len); @@ -217,8 +224,12 @@ TEST_CASE("QUICHandshakeProtocol") REQUIRE(false); } - QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); - QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); + QUICPacketProtectionKeyInfo pp_key_info_client; + QUICPacketProtectionKeyInfo pp_key_info_server; + QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT); + QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN); + QUICPacketPayloadProtector ppp_client(pp_key_info_client); + QUICPacketPayloadProtector ppp_server(pp_key_info_server); CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); @@ -323,15 +334,16 @@ TEST_CASE("QUICHandshakeProtocol") uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead size_t cipher_len = 0; - CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), - QUICKeyPhase::PHASE_0)); + CHECK(ppp_client.protect(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), + QUICKeyPhase::PHASE_0)); std::cout << "### Encrypted Text" << std::endl; print_hex(cipher, cipher_len); uint8_t plain[128] = {0}; size_t plain_len = 0; - CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); + CHECK( + ppp_server.unprotect(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); std::cout << "### Decrypted Text" << std::endl; print_hex(plain, plain_len); @@ -351,7 +363,8 @@ TEST_CASE("QUICHandshakeProtocol") SECTION("Alert", "[quic]") { - QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); + QUICPacketProtectionKeyInfo pp_key_info_server; + QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); // Malformed CH (finished) @@ -384,8 +397,10 @@ TEST_CASE("QUICHandshakeProtocol") SECTION("Full Handshake + Packet Number Protection", "[quic]") { - QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); - QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); + QUICPacketProtectionKeyInfo pp_key_info_client; + QUICPacketProtectionKeyInfo pp_key_info_server; + QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT); + QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN); CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index 73ea2440335..6f571b68804 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -33,6 +33,7 @@ #include #include "QUICKeyGenerator.h" +#include "QUICPacketProtectionKeyInfo.h" // https://github.com/quicwg/base-drafts/wiki/Test-Vector-for-the-Clear-Text-AEAD-key-derivation TEST_CASE("draft-17 Test Vectors", "[quic]") @@ -54,14 +55,16 @@ TEST_CASE("draft-17 Test Vectors", "[quic]") 0xcd, 0x25, 0x3a, 0x36, 0xff, 0x93, 0x93, 0x7c, 0x46, 0x93, 0x84, 0xa8, 0x23, 0xaf, 0x6c, 0x56, }; - std::unique_ptr actual_km = keygen.generate(cid); + QUICPacketProtectionKeyInfo pp_key_info; + keygen.generate(pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL), pp_key_info.encryption_key(QUICKeyPhase::INITIAL), + pp_key_info.encryption_iv(QUICKeyPhase::INITIAL), pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL), cid); - CHECK(actual_km->key_len == sizeof(expected_client_key)); - CHECK(memcmp(actual_km->key, expected_client_key, sizeof(expected_client_key)) == 0); - CHECK(actual_km->iv_len == sizeof(expected_client_iv)); - CHECK(memcmp(actual_km->iv, expected_client_iv, sizeof(expected_client_iv)) == 0); - CHECK(actual_km->hp_len == sizeof(expected_client_hp)); - CHECK(memcmp(actual_km->hp, expected_client_hp, sizeof(expected_client_hp)) == 0); + CHECK(pp_key_info.encryption_key_len(QUICKeyPhase::INITIAL) == sizeof(expected_client_key)); + CHECK(memcmp(pp_key_info.encryption_key(QUICKeyPhase::INITIAL), expected_client_key, sizeof(expected_client_key)) == 0); + CHECK(*pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL) == sizeof(expected_client_iv)); + CHECK(memcmp(pp_key_info.encryption_iv(QUICKeyPhase::INITIAL), expected_client_iv, sizeof(expected_client_iv)) == 0); + CHECK(pp_key_info.encryption_key_for_hp_len(QUICKeyPhase::INITIAL) == sizeof(expected_client_hp)); + CHECK(memcmp(pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL), expected_client_hp, sizeof(expected_client_hp)) == 0); } SECTION("SERVER Initial") @@ -80,13 +83,15 @@ TEST_CASE("draft-17 Test Vectors", "[quic]") 0x25, 0x79, 0xd8, 0x69, 0x6f, 0x85, 0xed, 0xa6, 0x8d, 0x35, 0x02, 0xb6, 0x55, 0x96, 0x58, 0x6b, }; - std::unique_ptr actual_km = keygen.generate(cid); + QUICPacketProtectionKeyInfo pp_key_info; + keygen.generate(pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL), pp_key_info.encryption_key(QUICKeyPhase::INITIAL), + pp_key_info.encryption_iv(QUICKeyPhase::INITIAL), pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL), cid); - CHECK(actual_km->key_len == sizeof(expected_server_key)); - CHECK(memcmp(actual_km->key, expected_server_key, sizeof(expected_server_key)) == 0); - CHECK(actual_km->iv_len == sizeof(expected_server_iv)); - CHECK(memcmp(actual_km->iv, expected_server_iv, sizeof(expected_server_iv)) == 0); - CHECK(actual_km->hp_len == sizeof(expected_server_hp)); - CHECK(memcmp(actual_km->hp, expected_server_hp, sizeof(expected_server_hp)) == 0); + CHECK(pp_key_info.encryption_key_len(QUICKeyPhase::INITIAL) == sizeof(expected_server_key)); + CHECK(memcmp(pp_key_info.encryption_key(QUICKeyPhase::INITIAL), expected_server_key, sizeof(expected_server_key)) == 0); + CHECK(*pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL) == sizeof(expected_server_iv)); + CHECK(memcmp(pp_key_info.encryption_iv(QUICKeyPhase::INITIAL), expected_server_iv, sizeof(expected_server_iv)) == 0); + CHECK(pp_key_info.encryption_key_for_hp_len(QUICKeyPhase::INITIAL) == sizeof(expected_server_hp)); + CHECK(memcmp(pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL), expected_server_hp, sizeof(expected_server_hp)) == 0); } } diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 46b66a6ac97..49b21ef501f 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -30,9 +30,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") { - MockQUICHandshakeProtocol hs_protocol; - QUICPacketFactory pf; - pf.set_hs_protocol(&hs_protocol); + QUICPacketProtectionKeyInfo pp_key_info; + QUICPacketFactory pf(pp_key_info); QUICRTTMeasure rtt_measure; QUICAckFrameManager afm; diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 35995f3d3db..504723b897a 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -28,9 +28,9 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") { - QUICPacketFactory factory; - MockQUICHandshakeProtocol hs_protocol; - factory.set_hs_protocol(&hs_protocol); + QUICPacketProtectionKeyInfo pp_key_info; + QUICPacketFactory factory(pp_key_info); + ; const uint8_t raw_dcid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; const uint8_t raw_scid[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; @@ -64,9 +64,8 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") { - QUICPacketFactory factory; - MockQUICHandshakeProtocol hs_protocol; - factory.set_hs_protocol(&hs_protocol); + QUICPacketProtectionKeyInfo pp_key_info; + QUICPacketFactory factory(pp_key_info); factory.set_version(0x11223344); uint8_t raw[] = {0xaa, 0xbb, 0xcc, 0xdd}; @@ -85,9 +84,8 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") { - QUICPacketFactory factory; - MockQUICHandshakeProtocol hs_protocol; - factory.set_hs_protocol(&hs_protocol); + QUICPacketProtectionKeyInfo pp_key_info; + QUICPacketFactory factory(pp_key_info); factory.set_version(0x11223344); std::vector dummy_frames; @@ -108,9 +106,8 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") { - QUICPacketFactory factory; - MockQUICHandshakeProtocol hs_protocol; - factory.set_hs_protocol(&hs_protocol); + QUICPacketProtectionKeyInfo pp_key_info; + QUICPacketFactory factory(pp_key_info); QUICStatelessResetToken token({reinterpret_cast("\x30\x39"), 2}, 67890); QUICPacketUPtr packet = diff --git a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc index 2c2e088dbcb..c0ed905e5df 100644 --- a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc @@ -23,6 +23,7 @@ #include "catch.hpp" +#include "QUICPacketProtectionKeyInfo.h" #include "QUICPacketHeaderProtector.h" #include "QUICTLS.h" @@ -68,17 +69,16 @@ TEST_CASE("QUICPacketHeaderProtector") uint8_t tmp[64]; memcpy(tmp, original, sizeof(tmp)); - QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); - QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); + QUICPacketProtectionKeyInfo pp_key_info_client; + QUICPacketProtectionKeyInfo pp_key_info_server; + QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT); + QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN); CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - QUICPacketHeaderProtector client_ph_protector; - QUICPacketHeaderProtector server_ph_protector; - - client_ph_protector.set_hs_protocol(client); - server_ph_protector.set_hs_protocol(server); + QUICPacketHeaderProtector client_ph_protector(pp_key_info_client); + QUICPacketHeaderProtector server_ph_protector(pp_key_info_server); // ## Client -> Server client_ph_protector.protect(tmp, sizeof(tmp), 18); @@ -102,17 +102,16 @@ TEST_CASE("QUICPacketHeaderProtector") uint8_t tmp[48]; memcpy(tmp, original, sizeof(tmp)); - QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT); - QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN); + QUICPacketProtectionKeyInfo pp_key_info_client; + QUICPacketProtectionKeyInfo pp_key_info_server; + QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT); + QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN); CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); - QUICPacketHeaderProtector client_ph_protector; - QUICPacketHeaderProtector server_ph_protector; - - client_ph_protector.set_hs_protocol(client); - server_ph_protector.set_hs_protocol(server); + QUICPacketHeaderProtector client_ph_protector(pp_key_info_client); + QUICPacketHeaderProtector server_ph_protector(pp_key_info_server); // Handshake // CH diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index d7230fb5d8d..52885af01da 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -24,13 +24,13 @@ #include "catch.hpp" #include "quic/QUICVersionNegotiator.h" +#include "quic/QUICPacketProtectionKeyInfo.h" #include "quic/Mock.h" TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") { - QUICPacketFactory packet_factory; - MockQUICHandshakeProtocol hs_protocol; - packet_factory.set_hs_protocol(&hs_protocol); + QUICPacketProtectionKeyInfo pp_key_info; + QUICPacketFactory packet_factory(pp_key_info); QUICVersionNegotiator vn; std::vector dummy_frames; @@ -94,9 +94,8 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") { - QUICPacketFactory packet_factory; - MockQUICHandshakeProtocol hs_protocol; - packet_factory.set_hs_protocol(&hs_protocol); + QUICPacketProtectionKeyInfo pp_key_info; + QUICPacketFactory packet_factory(pp_key_info); QUICVersionNegotiator vn; std::vector dummy_frames; From 2c6156c42220c1ceed347f719ecb87fa0034d42c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 25 Feb 2019 10:54:54 +0900 Subject: [PATCH 1159/1313] Update tests --- iocore/net/quic/Mock.h | 22 ++++++++++++++++ iocore/net/quic/QUICPacketProtectionKeyInfo.h | 26 +++++++++---------- iocore/net/quic/test/test_QUICKeyGenerator.cc | 4 +++ iocore/net/quic/test/test_QUICLossDetector.cc | 2 +- .../net/quic/test/test_QUICPacketFactory.cc | 10 +++---- .../quic/test/test_QUICVersionNegotiator.cc | 16 +++++++----- 6 files changed, 55 insertions(+), 25 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 58423f4d11f..bccd6d1c55f 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -510,6 +510,28 @@ class MockQUICStreamIO : public QUICStreamIO } }; +class MockQUICPacketProtectionKeyInfo : public QUICPacketProtectionKeyInfo +{ +public: + const QUIC_EVP_CIPHER * + get_cipher(QUICKeyPhase phase) const override + { + return EVP_aes_128_gcm(); + } + + size_t + get_tag_len(QUICKeyPhase phase) const override + { + return EVP_GCM_TLS_TAG_LEN; + } + + size_t *encryption_iv_len(QUICKeyPhase) const override + { + static size_t dummy = 12; + return &dummy; + } +}; + class MockQUICHandshakeProtocol : public QUICHandshakeProtocol { public: diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.h b/iocore/net/quic/QUICPacketProtectionKeyInfo.h index f18ecfcf65a..424c7c8c862 100644 --- a/iocore/net/quic/QUICPacketProtectionKeyInfo.h +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.h @@ -38,26 +38,26 @@ class QUICPacketProtectionKeyInfo // Payload Protection (common) - const QUIC_EVP_CIPHER *get_cipher(QUICKeyPhase phase) const; - size_t get_tag_len(QUICKeyPhase phase) const; - void set_cipher_initial(const QUIC_EVP_CIPHER *cipher); - void set_cipher(const QUIC_EVP_CIPHER *cipher, size_t tag_len); + virtual const QUIC_EVP_CIPHER *get_cipher(QUICKeyPhase phase) const; + virtual size_t get_tag_len(QUICKeyPhase phase) const; + virtual void set_cipher_initial(const QUIC_EVP_CIPHER *cipher); + virtual void set_cipher(const QUIC_EVP_CIPHER *cipher, size_t tag_len); // Payload Protection (encryption) - bool is_encryption_key_available(QUICKeyPhase phase) const; - void set_encryption_key_available(QUICKeyPhase phase); + virtual bool is_encryption_key_available(QUICKeyPhase phase) const; + virtual void set_encryption_key_available(QUICKeyPhase phase); - const uint8_t *encryption_key(QUICKeyPhase phase) const; - uint8_t *encryption_key(QUICKeyPhase phase); + virtual const uint8_t *encryption_key(QUICKeyPhase phase) const; + virtual uint8_t *encryption_key(QUICKeyPhase phase); - size_t encryption_key_len(QUICKeyPhase phase) const; + virtual size_t encryption_key_len(QUICKeyPhase phase) const; - const uint8_t *encryption_iv(QUICKeyPhase phase) const; - uint8_t *encryption_iv(QUICKeyPhase phase); + virtual const uint8_t *encryption_iv(QUICKeyPhase phase) const; + virtual uint8_t *encryption_iv(QUICKeyPhase phase); - const size_t *encryption_iv_len(QUICKeyPhase phase) const; - size_t *encryption_iv_len(QUICKeyPhase phase); + virtual const size_t *encryption_iv_len(QUICKeyPhase phase) const; + virtual size_t *encryption_iv_len(QUICKeyPhase phase); // Payload Protection (decryption) diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index 6f571b68804..dc152a297c1 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -56,6 +56,8 @@ TEST_CASE("draft-17 Test Vectors", "[quic]") }; QUICPacketProtectionKeyInfo pp_key_info; + pp_key_info.set_cipher_initial(EVP_aes_128_gcm()); + pp_key_info.set_cipher_for_hp_initial(EVP_aes_128_ecb()); keygen.generate(pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL), pp_key_info.encryption_key(QUICKeyPhase::INITIAL), pp_key_info.encryption_iv(QUICKeyPhase::INITIAL), pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL), cid); @@ -84,6 +86,8 @@ TEST_CASE("draft-17 Test Vectors", "[quic]") }; QUICPacketProtectionKeyInfo pp_key_info; + pp_key_info.set_cipher_initial(EVP_aes_128_gcm()); + pp_key_info.set_cipher_for_hp_initial(EVP_aes_128_ecb()); keygen.generate(pp_key_info.encryption_key_for_hp(QUICKeyPhase::INITIAL), pp_key_info.encryption_key(QUICKeyPhase::INITIAL), pp_key_info.encryption_iv(QUICKeyPhase::INITIAL), pp_key_info.encryption_iv_len(QUICKeyPhase::INITIAL), cid); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 49b21ef501f..bbdc59f7356 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -30,7 +30,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") { - QUICPacketProtectionKeyInfo pp_key_info; + MockQUICPacketProtectionKeyInfo pp_key_info; QUICPacketFactory pf(pp_key_info); QUICRTTMeasure rtt_measure; diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 504723b897a..40211c4fb81 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -28,7 +28,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") { - QUICPacketProtectionKeyInfo pp_key_info; + MockQUICPacketProtectionKeyInfo pp_key_info; QUICPacketFactory factory(pp_key_info); ; @@ -64,7 +64,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") { - QUICPacketProtectionKeyInfo pp_key_info; + MockQUICPacketProtectionKeyInfo pp_key_info; QUICPacketFactory factory(pp_key_info); factory.set_version(0x11223344); @@ -84,7 +84,7 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") { - QUICPacketProtectionKeyInfo pp_key_info; + MockQUICPacketProtectionKeyInfo pp_key_info; QUICPacketFactory factory(pp_key_info); factory.set_version(0x11223344); std::vector dummy_frames; @@ -99,14 +99,14 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") std::move(payload), sizeof(raw), true, false, true, dummy_frames); CHECK(packet->type() == QUICPacketType::HANDSHAKE); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); - CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); + CHECK(memcmp(packet->payload(), raw, sizeof(raw)) != 0); CHECK(packet->packet_number() <= 0xFFFFFBFF); CHECK(packet->version() == 0x11223344); } TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") { - QUICPacketProtectionKeyInfo pp_key_info; + MockQUICPacketProtectionKeyInfo pp_key_info; QUICPacketFactory factory(pp_key_info); QUICStatelessResetToken token({reinterpret_cast("\x30\x39"), 2}, 67890); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 52885af01da..2d3dbae9095 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -29,9 +29,11 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") { - QUICPacketProtectionKeyInfo pp_key_info; + MockQUICPacketProtectionKeyInfo pp_key_info; QUICPacketFactory packet_factory(pp_key_info); QUICVersionNegotiator vn; + ats_unique_buf dummy_payload = ats_unique_malloc(128); + size_t dummy_payload_len = 128; std::vector dummy_frames; SECTION("Normal case") @@ -42,7 +44,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, true, dummy_frames); + packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true, dummy_frames); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -61,7 +63,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, true, dummy_frames); + packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true, dummy_frames); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -80,7 +82,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, true, dummy_frames); + packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true, dummy_frames); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); @@ -94,9 +96,11 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") { - QUICPacketProtectionKeyInfo pp_key_info; + MockQUICPacketProtectionKeyInfo pp_key_info; QUICPacketFactory packet_factory(pp_key_info); QUICVersionNegotiator vn; + ats_unique_buf dummy_payload = ats_unique_malloc(128); + size_t dummy_payload_len = 128; std::vector dummy_frames; SECTION("Normal case") @@ -123,7 +127,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSIONS); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, ats_unique_malloc(0), 0, true, false, true, dummy_frames); + packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true, dummy_frames); // Server send VN packet based on Initial packet QUICPacketUPtr vn_packet = From 28617fe794ade3d0e3272cb22d228ba47898f1b1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 25 Feb 2019 11:07:20 +0900 Subject: [PATCH 1160/1313] Revert unnecessary changes --- iocore/net/quic/QUICPacketHeaderProtector.cc | 16 ---------------- iocore/net/quic/QUICTypes.h | 2 +- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc index f0e88e69b17..3acdef25585 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -42,7 +42,6 @@ QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotect QUICKeyPhase phase; QUICPacketType type; - QUICEncryptionLevel level; if (QUICInvariants::is_long_header(unprotected_packet)) { QUICPacketLongHeader::key_phase(phase, unprotected_packet, unprotected_packet_len); QUICPacketLongHeader::type(type, unprotected_packet, unprotected_packet_len); @@ -51,21 +50,6 @@ QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotect phase = QUICKeyPhase::PHASE_0; type = QUICPacketType::PROTECTED; } - switch (phase) { - case QUICKeyPhase::PHASE_0: - case QUICKeyPhase::PHASE_1: - level = QUICEncryptionLevel::ONE_RTT; - break; - case QUICKeyPhase::HANDSHAKE: - level = QUICEncryptionLevel::HANDSHAKE; - break; - case QUICKeyPhase::INITIAL: - level = QUICEncryptionLevel::INITIAL; - break; - case QUICKeyPhase::ZERO_RTT: - level = QUICEncryptionLevel::ZERO_RTT; - break; - } Debug("v_quic_pne", "Protecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), QUICDebugNames::key_phase(phase)); diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index effeca7bdcb..44515814785 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -54,7 +54,7 @@ constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { }; constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; -enum class QUICEncryptionLevel : int { +enum class QUICEncryptionLevel { NONE = -1, INITIAL = 0, ZERO_RTT = 1, From 10ebad1bab212ed4ecff77074c45030ad0d6e43d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 27 Feb 2019 10:44:58 +0900 Subject: [PATCH 1161/1313] Small cleanups --- .../QUICPacketPayloadProtector_openssl.cc | 12 +++---- iocore/net/quic/QUICPacketProtectionKeyInfo.h | 36 +++++++++---------- .../net/quic/test/test_QUICPacketFactory.cc | 1 - 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc b/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc index 5da9bd18b53..66342605708 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc +++ b/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc @@ -32,12 +32,12 @@ QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t size_t plain_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); - EVP_CIPHER_CTX *aead_ctx; - int len; + this->_gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); if (!(aead_ctx = EVP_CIPHER_CTX_new())) { return false; @@ -82,12 +82,12 @@ QUICPacketPayloadProtector::_unprotect(uint8_t *plain, size_t &plain_len, size_t 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; - _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); - EVP_CIPHER_CTX *aead_ctx; - int len; + this->_gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len); if (!(aead_ctx = EVP_CIPHER_CTX_new())) { return false; diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.h b/iocore/net/quic/QUICPacketProtectionKeyInfo.h index 424c7c8c862..de0385dee8b 100644 --- a/iocore/net/quic/QUICPacketProtectionKeyInfo.h +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.h @@ -61,35 +61,35 @@ class QUICPacketProtectionKeyInfo // Payload Protection (decryption) - bool is_decryption_key_available(QUICKeyPhase phase) const; - void set_decryption_key_available(QUICKeyPhase phase); + virtual bool is_decryption_key_available(QUICKeyPhase phase) const; + virtual void set_decryption_key_available(QUICKeyPhase phase); - const uint8_t *decryption_key(QUICKeyPhase phase) const; - uint8_t *decryption_key(QUICKeyPhase phase); + virtual const uint8_t *decryption_key(QUICKeyPhase phase) const; + virtual uint8_t *decryption_key(QUICKeyPhase phase); - size_t decryption_key_len(QUICKeyPhase phase) const; + virtual size_t decryption_key_len(QUICKeyPhase phase) const; - const uint8_t *decryption_iv(QUICKeyPhase phase) const; - uint8_t *decryption_iv(QUICKeyPhase phase); + virtual const uint8_t *decryption_iv(QUICKeyPhase phase) const; + virtual uint8_t *decryption_iv(QUICKeyPhase phase); - const size_t *decryption_iv_len(QUICKeyPhase phase) const; - size_t *decryption_iv_len(QUICKeyPhase phase); + virtual const size_t *decryption_iv_len(QUICKeyPhase phase) const; + virtual size_t *decryption_iv_len(QUICKeyPhase phase); // Header Protection - const QUIC_EVP_CIPHER *get_cipher_for_hp(QUICKeyPhase phase) const; - void set_cipher_for_hp_initial(const QUIC_EVP_CIPHER *cipher); - void set_cipher_for_hp(const QUIC_EVP_CIPHER *cipher); + virtual const QUIC_EVP_CIPHER *get_cipher_for_hp(QUICKeyPhase phase) const; + virtual void set_cipher_for_hp_initial(const QUIC_EVP_CIPHER *cipher); + virtual void set_cipher_for_hp(const QUIC_EVP_CIPHER *cipher); - const uint8_t *encryption_key_for_hp(QUICKeyPhase phase) const; - uint8_t *encryption_key_for_hp(QUICKeyPhase phase); + virtual const uint8_t *encryption_key_for_hp(QUICKeyPhase phase) const; + virtual uint8_t *encryption_key_for_hp(QUICKeyPhase phase); - size_t encryption_key_for_hp_len(QUICKeyPhase phase) const; + virtual size_t encryption_key_for_hp_len(QUICKeyPhase phase) const; - const uint8_t *decryption_key_for_hp(QUICKeyPhase phase) const; - uint8_t *decryption_key_for_hp(QUICKeyPhase phase); + virtual const uint8_t *decryption_key_for_hp(QUICKeyPhase phase) const; + virtual uint8_t *decryption_key_for_hp(QUICKeyPhase phase); - size_t decryption_key_for_hp_len(QUICKeyPhase phase) const; + virtual size_t decryption_key_for_hp_len(QUICKeyPhase phase) const; private: Context _ctx = Context::SERVER; diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 40211c4fb81..cd3bf33b9ae 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -30,7 +30,6 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") { MockQUICPacketProtectionKeyInfo pp_key_info; QUICPacketFactory factory(pp_key_info); - ; const uint8_t raw_dcid[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; const uint8_t raw_scid[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; From ba137ce1355a88e332db6e89b37d545fd861a708 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 27 Feb 2019 11:42:55 +0900 Subject: [PATCH 1162/1313] Fix a use of wrong key_len --- iocore/net/quic/QUICTLS.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 425a4f54265..7852596499a 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -148,7 +148,7 @@ QUICTLS::initialize_key_materials(QUICConnectionId cid) this->_print_km("initial - server", server_key_for_hp, server_key_for_hp_len, server_key, server_key_len, server_iv, *server_iv_len); - this->_print_km("initial - client", client_key_for_hp, client_key_for_hp_len, client_key, server_key_len, client_iv, + this->_print_km("initial - client", client_key_for_hp, client_key_for_hp_len, client_key, client_key_len, client_iv, *client_iv_len); return 1; From 503320547c873db3bc79c8b00eb9028379a91b24 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 27 Feb 2019 13:47:20 +0900 Subject: [PATCH 1163/1313] Removed a unused variable --- iocore/net/P_QUICNetVConnection.h | 1 - iocore/net/QUICNetVConnection.cc | 1 - 2 files changed, 2 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 4c18ac4c6a0..10509020396 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -233,7 +233,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub SLINK(QUICNetVConnection, closed_alink); private: - QUICPacketType _last_received_packet_type = QUICPacketType::UNINITIALIZED; std::random_device _rnd; QUICConnectionId _peer_quic_connection_id; // dst cid in local diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 999e1cddd0f..7e5093c9b5d 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1634,7 +1634,6 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) } } - this->_last_received_packet_type = packet->type(); if (!this->_verfied_state.is_verified()) { this->_verfied_state.fill(packet->size()); } From 22364902841f999e933c2439baa3491e24f507dd Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 27 Feb 2019 14:02:29 +0900 Subject: [PATCH 1164/1313] Drop keys for INITIAL on server side after processing the first HANDSHAKE packet --- iocore/net/QUICNetVConnection.cc | 3 +++ .../net/quic/QUICPacketProtectionKeyInfo.cc | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 7e5093c9b5d..4ce2d718a66 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -943,6 +943,9 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) break; case QUICPacketType::HANDSHAKE: error = this->_state_handshake_process_handshake_packet(std::move(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); + } break; case QUICPacketType::ZERO_RTT_PROTECTED: error = this->_state_handshake_process_zero_rtt_protected_packet(std::move(packet)); diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.cc b/iocore/net/quic/QUICPacketProtectionKeyInfo.cc index a08230a7bff..f782d357be2 100644 --- a/iocore/net/quic/QUICPacketProtectionKeyInfo.cc +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.cc @@ -29,6 +29,27 @@ QUICPacketProtectionKeyInfo::set_context(Context ctx) this->_ctx = ctx; } +void +QUICPacketProtectionKeyInfo::drop_keys(QUICKeyPhase phase) +{ + int index = static_cast(phase); + + this->_is_client_key_available[index] = false; + this->_is_server_key_available[index] = false; + + memset(this->_client_key[index], 0x00, sizeof(this->_client_key[index])); + memset(this->_server_key[index], 0x00, sizeof(this->_server_key[index])); + + memset(this->_client_iv[index], 0x00, sizeof(this->_client_iv[index])); + memset(this->_server_iv[index], 0x00, sizeof(this->_server_iv[index])); + + this->_client_iv_len[index] = 0; + this->_server_iv_len[index] = 0; + + memset(this->_client_key_for_hp[index], 0x00, sizeof(this->_client_key_for_hp[index])); + memset(this->_server_key_for_hp[index], 0x00, sizeof(this->_server_key_for_hp[index])); +} + const QUIC_EVP_CIPHER * QUICPacketProtectionKeyInfo::get_cipher(QUICKeyPhase phase) const { From 0636a4a6ffb51729354ea329a882b86eb4bd10e7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 27 Feb 2019 14:13:28 +0900 Subject: [PATCH 1165/1313] Drop keys for INITIAL on client side after sending the first HANDSHAKE packet --- iocore/net/QUICNetVConnection.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 4ce2d718a66..33f0e2c7524 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1275,6 +1275,11 @@ QUICNetVConnection::_state_common_send_packet() QUICConDebug("[TX] %s packet #%" PRIu64 " size=%zu", QUICDebugNames::packet_type(packet->type()), packet->packet_number(), len); + if (this->_pp_key_info.is_encryption_key_available(QUICKeyPhase::INITIAL) && packet->type() == QUICPacketType::HANDSHAKE && + this->netvc_context == NET_VCONNECTION_OUT) { + this->_pp_key_info.drop_keys(QUICKeyPhase::INITIAL); + } + int index = QUICTypeUtil::pn_space_index(level); this->_loss_detector[index]->on_packet_sent(std::move(packet)); packet_count++; From fc88686b10f94b33a4cdc5976f81b417889d2020 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 27 Feb 2019 15:21:47 +0900 Subject: [PATCH 1166/1313] Reduce duplicate code --- iocore/net/P_QUICNetVConnection.h | 2 + iocore/net/QUICNetVConnection.cc | 86 +++++++++++++------------------ 2 files changed, 37 insertions(+), 51 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 10509020396..f8a91323c76 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -304,6 +304,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _close_path_validation_timeout(Event *data); Event *_path_validation_timeout = nullptr; + void _schedule_ack_manager_periodic(ink_hrtime interval); void _unschedule_ack_manager_periodic(); Event *_ack_manager_periodic = nullptr; @@ -357,6 +358,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub bool _application_started = false; void _start_application(); + void _handle_periodic_ack_event(); void _handle_path_validation_timeout(Event *data); void _handle_idle_timeout(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 33f0e2c7524..d16542d6754 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -251,7 +251,7 @@ QUICNetVConnection::start() this->_hs_protocol = this->_setup_handshake_protocol(params->server_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol, this->_reset_token, params->stateless_retry()); this->_ack_frame_manager.set_max_ack_delay(params->max_ack_delay_in()); - this->_ack_manager_periodic = this->thread->schedule_every(this, params->max_ack_delay_in(), QUIC_EVENT_ACK_PERIODIC); + this->_schedule_ack_manager_periodic(params->max_ack_delay_in()); } else { this->_pp_key_info.set_context(QUICPacketProtectionKeyInfo::Context::CLIENT); this->_ack_frame_manager.set_ack_delay_exponent(params->ack_delay_exponent_out()); @@ -260,7 +260,7 @@ QUICNetVConnection::start() this->_handshake_handler->start(&this->_packet_factory, params->vn_exercise_enabled()); this->_handshake_handler->do_handshake(); this->_ack_frame_manager.set_max_ack_delay(params->max_ack_delay_out()); - this->_ack_manager_periodic = this->thread->schedule_every(this, params->max_ack_delay_out(), QUIC_EVENT_ACK_PERIODIC); + this->_schedule_ack_manager_periodic(params->max_ack_delay_out()); } this->_application_map = new QUICApplicationMap(); @@ -629,37 +629,16 @@ QUICNetVConnection::state_handshake(int event, Event *data) } while (error == nullptr && (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::IGNORED)); break; } - case QUIC_EVENT_ACK_PERIODIC: { - ink_hrtime timestamp = Thread::get_hrtime(); - bool need_schedule = false; - for (auto level : QUIC_ENCRYPTION_LEVELS) { - if (this->_ack_frame_manager.will_generate_frame(level, timestamp)) { - need_schedule = true; - break; - } - } - - if (!need_schedule) { - break; - } - - // we have ack to send - // FIXME: should sent depend on socket event. - this->_schedule_packet_write_ready(); + case QUIC_EVENT_ACK_PERIODIC: + this->_handle_periodic_ack_event(); break; - } - - case QUIC_EVENT_PACKET_WRITE_READY: { + case QUIC_EVENT_PACKET_WRITE_READY: this->_close_packet_write_ready(data); - // TODO: support RETRY packet error = this->_state_common_send_packet(); - // Reschedule WRITE_READY this->_schedule_packet_write_ready(true); - break; - } case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: this->_handle_path_validation_timeout(data); break; @@ -684,45 +663,25 @@ QUICNetVConnection::state_connection_established(int event, Event *data) SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); QUICConnectionErrorUPtr error = nullptr; switch (event) { - case QUIC_EVENT_PACKET_READ_READY: { + case QUIC_EVENT_PACKET_READ_READY: error = this->_state_connection_established_receive_packet(); break; - } - case QUIC_EVENT_ACK_PERIODIC: { - ink_hrtime timestamp = Thread::get_hrtime(); - bool need_schedule = false; - for (auto level : QUIC_ENCRYPTION_LEVELS) { - if (this->_ack_frame_manager.will_generate_frame(level, timestamp)) { - need_schedule = true; - break; - } - } - - if (!need_schedule) { - break; - } - - // we have ack to send - // FIXME: should sent depend on socket event. - this->_schedule_packet_write_ready(); + case QUIC_EVENT_ACK_PERIODIC: + this->_handle_periodic_ack_event(); break; - } - - case QUIC_EVENT_PACKET_WRITE_READY: { + case QUIC_EVENT_PACKET_WRITE_READY: this->_close_packet_write_ready(data); error = this->_state_common_send_packet(); // Reschedule WRITE_READY this->_schedule_packet_write_ready(true); break; - } case QUIC_EVENT_PATH_VALIDATION_TIMEOUT: this->_handle_path_validation_timeout(data); break; - case EVENT_IMMEDIATE: { + case EVENT_IMMEDIATE: // Start Immediate Close because of Idle Timeout this->_handle_idle_timeout(); break; - } default: QUICConDebug("Unexpected event: %s (%d)", QUICDebugNames::quic_event(event), event); } @@ -1728,6 +1687,12 @@ QUICNetVConnection::_unschedule_closing_timeout() } } +void +QUICNetVConnection::_schedule_ack_manager_periodic(ink_hrtime interval) +{ + this->_ack_manager_periodic = this->thread->schedule_every(this, interval, QUIC_EVENT_ACK_PERIODIC); +} + void QUICNetVConnection::_unschedule_ack_manager_periodic() { @@ -2133,6 +2098,25 @@ QUICNetVConnection::_state_connection_established_initiate_connection_migration( return error; } +void +QUICNetVConnection::_handle_periodic_ack_event() +{ + ink_hrtime timestamp = Thread::get_hrtime(); + bool need_schedule = false; + for (auto level : QUIC_ENCRYPTION_LEVELS) { + if (this->_ack_frame_manager.will_generate_frame(level, timestamp)) { + need_schedule = true; + break; + } + } + + if (need_schedule) { + // we have ack to send + // FIXME: should sent depend on socket event. + this->_schedule_packet_write_ready(); + } +} + void QUICNetVConnection::_handle_path_validation_timeout(Event *data) { From 7a3af4e1c3251dbd5467810b0d22ba75808e4024 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 27 Feb 2019 16:05:54 +0900 Subject: [PATCH 1167/1313] Remove QUICPacketTransmitter It's not used now. We might need it later but a fresh design would be better. --- iocore/net/P_QUICNetVConnection.h | 4 - iocore/net/QUICNetVConnection.cc | 24 +---- iocore/net/quic/Mock.h | 46 ++-------- iocore/net/quic/QUICConnection.h | 3 +- iocore/net/quic/QUICFrameHandler.h | 2 + iocore/net/quic/QUICLossDetector.cc | 15 +--- iocore/net/quic/QUICLossDetector.h | 13 ++- iocore/net/quic/QUICPacketTransmitter.h | 44 --------- .../net/quic/test/test_QUICAckFrameCreator.cc | 90 +++++++++---------- .../net/quic/test/test_QUICFlowController.cc | 56 ++++++------ .../net/quic/test/test_QUICFrameDispatcher.cc | 3 +- iocore/net/quic/test/test_QUICLossDetector.cc | 16 +--- iocore/net/quic/test/test_QUICStream.cc | 64 ++++++------- 13 files changed, 128 insertions(+), 252 deletions(-) delete mode 100644 iocore/net/quic/QUICPacketTransmitter.h diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index f8a91323c76..bdece52337b 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -212,10 +212,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub std::string_view negotiated_application_name() const override; bool is_closed() const override; - // QUICConnection (QUICPacketTransmitter) - virtual void retransmit_packet(const QUICPacket &packet) override; - virtual Ptr get_packet_transmitter_mutex() override; - // QUICConnection (QUICFrameHandler) std::vector interests() override; QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index d16542d6754..f2d3dfb5ceb 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -92,7 +92,6 @@ QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_ci QUICPacketHandler *packet_handler) { SET_HANDLER((NetVConnHandler)&QUICNetVConnection::startEvent); - this->_packet_transmitter_mutex = new_ProxyMutex(); this->_udp_con = udp_con; this->_packet_handler = packet_handler; this->_peer_quic_connection_id = peer_cid; @@ -117,7 +116,6 @@ QUICNetVConnection::init(QUICConnectionId peer_cid, QUICConnectionId original_ci UDPConnection *udp_con, QUICPacketHandler *packet_handler, QUICConnectionTable *ctable) { SET_HANDLER((NetVConnHandler)&QUICNetVConnection::acceptEvent); - this->_packet_transmitter_mutex = new_ProxyMutex(); this->_udp_con = udp_con; this->_packet_handler = packet_handler; this->_peer_quic_connection_id = peer_cid; @@ -271,7 +269,7 @@ QUICNetVConnection::start() this->_congestion_controller = new QUICCongestionController(this); for (auto s : QUIC_PN_SPACES) { int index = static_cast(s); - QUICLossDetector *ld = new QUICLossDetector(this, this, this->_congestion_controller, &this->_rtt_measure, index); + QUICLossDetector *ld = new QUICLossDetector(this, this->_congestion_controller, &this->_rtt_measure, index); this->_frame_dispatcher->add_handler(ld); this->_loss_detector[index] = ld; } @@ -480,18 +478,6 @@ QUICNetVConnection::stream_manager() return this->_stream_manager; } -void -QUICNetVConnection::retransmit_packet(const QUICPacket &packet) -{ - QUICConDebug("[NOP] Retransmit %s packet #%" PRIu64, QUICDebugNames::packet_type(packet.type()), packet.packet_number()); -} - -Ptr -QUICNetVConnection::get_packet_transmitter_mutex() -{ - return this->_packet_transmitter_mutex; -} - void QUICNetVConnection::handle_received_packet(UDPPacket *packet) { @@ -939,7 +925,6 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack this->_loss_detector[static_cast(s)]->reset(); } this->_congestion_controller->reset(); - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); // start handshake over this->_handshake_handler->reset(); @@ -1015,7 +1000,6 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) this->_loss_detector[static_cast(s)]->reset(); } this->_congestion_controller->reset(); - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); this->_packet_recv_queue.reset(); // Initialize Key Materials with peer CID. Because peer CID is DCID of (second) INITIAL packet from client which reply to RETRY @@ -1324,7 +1308,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa size_t len = 0; ats_unique_buf buf = ats_unique_malloc(max_packet_size); - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); std::vector frames; if (!this->_has_ack_eliciting_packet_out) { @@ -1420,8 +1403,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa void QUICNetVConnection::_packetize_closing_frame() { - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); - if (this->_connection_error == nullptr || this->_the_final_packet) { return; } @@ -1638,7 +1619,6 @@ QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result) void QUICNetVConnection::_schedule_packet_write_ready(bool delay) { - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); if (!this->_packet_write_ready) { QUICConVVVDebug("Schedule %s event", QUICDebugNames::quic_event(QUIC_EVENT_PACKET_WRITE_READY)); if (delay) { @@ -1652,7 +1632,6 @@ QUICNetVConnection::_schedule_packet_write_ready(bool delay) void QUICNetVConnection::_unschedule_packet_write_ready() { - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); if (this->_packet_write_ready) { this->_packet_write_ready->cancel(); this->_packet_write_ready = nullptr; @@ -1662,7 +1641,6 @@ QUICNetVConnection::_unschedule_packet_write_ready() void QUICNetVConnection::_close_packet_write_ready(Event *data) { - SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread()); ink_assert(this->_packet_write_ready == data); this->_packet_write_ready = nullptr; } diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index bccd6d1c55f..94c8c46d057 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -29,7 +29,6 @@ #include "QUICStreamManager.h" #include "QUICLossDetector.h" #include "QUICEvents.h" -#include "QUICPacketTransmitter.h" class MockQUICStreamManager : public QUICStreamManager { @@ -185,18 +184,6 @@ class MockQUICConnection : public QUICConnection return std::string_view("00000000-00000000"sv); } - void - retransmit_packet(const QUICPacket &packet) override - { - ++_retransmit_count; - } - - Ptr - get_packet_transmitter_mutex() override - { - return this->_mutex; - } - std::vector interests() override { @@ -350,29 +337,6 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider } }; -class MockQUICPacketTransmitter : public QUICPacketTransmitter -{ -public: - MockQUICPacketTransmitter() : QUICPacketTransmitter() { this->_mutex = new_ProxyMutex(); }; - - void - retransmit_packet(const QUICPacket &packet) override - { - this->retransmitted.insert(packet.packet_number()); - } - - Ptr - get_packet_transmitter_mutex() override - { - return this->_mutex; - } - - Ptr _mutex; - - std::set transmitted; - std::set retransmitted; -}; - class MockQUICCongestionController : public QUICCongestionController { public: @@ -421,9 +385,8 @@ class MockQUICCongestionController : public QUICCongestionController class MockQUICLossDetector : public QUICLossDetector { public: - MockQUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, QUICCongestionController *cc, - QUICRTTMeasure *rtt_measure, int index) - : QUICLossDetector(transmitter, info, cc, rtt_measure, index) + MockQUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, int index) + : QUICLossDetector(info, cc, rtt_measure, index) { } void @@ -702,13 +665,14 @@ class MockQUICFrameGenerator : public QUICFrameGenerator { public: bool - will_generate_frame(QUICEncryptionLevel level) override + will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override { return true; } QUICFrame * - generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size) override + generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override { QUICFrame *frame = QUICFrameFactory::create_ping_frame(buf, 0, this); QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 96efe4f2c0a..36cc5fb987e 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -25,7 +25,6 @@ #include "I_EventSystem.h" #include "I_NetVConnection.h" -#include "QUICPacketTransmitter.h" #include "QUICFrameHandler.h" class QUICApplication; @@ -50,7 +49,7 @@ class QUICConnectionInfoProvider virtual std::string_view negotiated_application_name() const = 0; }; -class QUICConnection : public QUICPacketTransmitter, public QUICFrameHandler, public QUICConnectionInfoProvider +class QUICConnection : public QUICFrameHandler, public QUICConnectionInfoProvider { public: virtual QUICStreamManager *stream_manager() = 0; diff --git a/iocore/net/quic/QUICFrameHandler.h b/iocore/net/quic/QUICFrameHandler.h index 12c3fc9e5e3..5a2870f9869 100644 --- a/iocore/net/quic/QUICFrameHandler.h +++ b/iocore/net/quic/QUICFrameHandler.h @@ -24,6 +24,8 @@ #pragma once #include +#include "QUICTypes.h" + class QUICFrame; class QUICFrameHandler diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index d15287e182a..337d9e867a7 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -37,9 +37,9 @@ Debug("v_quic_loss_detector", "[%s] [%s] " fmt, this->_info->cids().data(), QUICDebugNames::pn_space(this->_pn_space_index), \ ##__VA_ARGS__) -QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, - QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, int index) - : _transmitter(transmitter), _info(info), _cc(cc), _rtt_measure(rtt_measure), _pn_space_index(index) +QUICLossDetector::QUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, + int index) + : _info(info), _cc(cc), _rtt_measure(rtt_measure), _pn_space_index(index) { this->mutex = new_ProxyMutex(); this->_loss_detection_mutex = new_ProxyMutex(); @@ -64,8 +64,7 @@ QUICLossDetector::~QUICLossDetector() this->_sent_packets.clear(); - this->_transmitter = nullptr; - this->_cc = nullptr; + this->_cc = nullptr; } int @@ -202,7 +201,6 @@ QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool ack_elici void QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame) { - SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); this->_largest_acked_packet = std::max(this->_largest_acked_packet, ack_frame.largest_acknowledged()); @@ -285,7 +283,6 @@ QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay) void QUICLossDetector::_on_packet_acked(const PacketInfo &acked_packet) { - SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number); @@ -395,7 +392,6 @@ QUICLossDetector::_on_loss_detection_timeout() void QUICLossDetector::_detect_lost_packets() { - SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); this->_loss_time = 0; ink_hrtime loss_delay = this->_k_time_threshold * std::max(this->_latest_rtt, this->_smoothed_rtt); @@ -458,7 +454,6 @@ QUICLossDetector::_detect_lost_packets() void QUICLossDetector::_retransmit_all_unacked_crypto_data() { - SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); std::set retransmitted_crypto_packets; std::map lost_packets; @@ -480,7 +475,6 @@ QUICLossDetector::_retransmit_all_unacked_crypto_data() void QUICLossDetector::_send_two_packets() { - SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // TODO sent ping } @@ -490,7 +484,6 @@ QUICLossDetector::_send_two_packets() void QUICLossDetector::_retransmit_lost_packet(QUICPacketUPtr &packet) { - SCOPED_MUTEX_LOCK(transmitter_lock, this->_transmitter->get_packet_transmitter_mutex().get(), this_ethread()); SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); QUICLDDebug("[NOP] Retransmit %s packet #%" PRIu64, QUICDebugNames::packet_type(packet->type()), packet->packet_number()); diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 42a2102e229..8f69c953f3b 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -35,7 +35,6 @@ #include "QUICPacket.h" #include "QUICFrame.h" #include "QUICFrameHandler.h" -#include "QUICPacketTransmitter.h" #include "QUICConnection.h" class QUICLossDetector; @@ -119,8 +118,7 @@ class QUICCongestionController class QUICLossDetector : public Continuation, public QUICFrameHandler { public: - QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConnectionInfoProvider *info, QUICCongestionController *cc, - QUICRTTMeasure *rtt_measure, int index); + QUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, int index); ~QUICLossDetector(); int event_handler(int event, Event *edata); @@ -194,9 +192,8 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _send_one_packet(); void _send_two_packets(); - QUICPacketTransmitter *_transmitter = nullptr; - QUICConnectionInfoProvider *_info = nullptr; - QUICCongestionController *_cc = nullptr; - QUICRTTMeasure *_rtt_measure = nullptr; - int _pn_space_index = -1; + QUICConnectionInfoProvider *_info = nullptr; + QUICCongestionController *_cc = nullptr; + QUICRTTMeasure *_rtt_measure = nullptr; + int _pn_space_index = -1; }; diff --git a/iocore/net/quic/QUICPacketTransmitter.h b/iocore/net/quic/QUICPacketTransmitter.h deleted file mode 100644 index c60e55ca8d2..00000000000 --- a/iocore/net/quic/QUICPacketTransmitter.h +++ /dev/null @@ -1,44 +0,0 @@ -/** @file - * - * A brief file description - * - * @section license License - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "QUICPacket.h" -#include "I_EventSystem.h" - -class QUICPacketTransmitter -{ -public: - /* - * Enqueue a packet for retransmission - * All frames except ACK and PADDING frames in the original packet will be retransmitted on a new packet. - * This sends QUIC_PACKET_WRITE_READY event. - */ - virtual void retransmit_packet(const QUICPacket &packet) = 0; - - /* - * Returns a mutex for transmitter interfaces. - * You have to acquire a lock with this mutex before calling any methods provieded by QUICPacketTransmitter - */ - virtual Ptr get_packet_transmitter_mutex() = 0; -}; diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 7e0d4108e6e..48fc90f0108 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -34,13 +34,13 @@ TEST_CASE("QUICAckFrameManager", "[quic]") uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; // Initial state - QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); QUICAckFrame *frame = static_cast(ack_frame); CHECK(frame == nullptr); // One packet ack_manager.update(level, 1, 1, false); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -48,14 +48,14 @@ TEST_CASE("QUICAckFrameManager", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 0); // retry - CHECK(ack_manager.will_generate_frame(level) == false); + CHECK(ack_manager.will_generate_frame(level, 0) == false); // Not sequential ack_manager.update(level, 2, 1, false); ack_manager.update(level, 5, 1, false); ack_manager.update(level, 3, 1, false); ack_manager.update(level, 4, 1, false); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -66,7 +66,7 @@ TEST_CASE("QUICAckFrameManager", "[quic]") ack_manager.update(level, 6, 1, false); ack_manager.update(level, 7, 1, false); ack_manager.update(level, 10, 1, false); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); @@ -77,14 +77,14 @@ TEST_CASE("QUICAckFrameManager", "[quic]") // on frame acked ack_manager.on_frame_acked(frame->id()); - CHECK(ack_manager.will_generate_frame(level) == false); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + CHECK(ack_manager.will_generate_frame(level, 0) == false); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); CHECK(ack_frame == nullptr); ack_manager.update(level, 11, 1, false); ack_manager.update(level, 12, 1, false); ack_manager.update(level, 13, 1, false); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -98,11 +98,11 @@ TEST_CASE("QUICAckFrameManager", "[quic]") ack_manager.update(level, 14, 1, true); ack_manager.update(level, 15, 1, true); ack_manager.update(level, 16, 1, true); - CHECK(ack_manager.will_generate_frame(level) == false); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + CHECK(ack_manager.will_generate_frame(level, 0) == false); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); ack_manager.update(level, 17, 1, false); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -119,7 +119,7 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; ack_manager.update(level, 2, 1, false); - CHECK(ack_manager.will_generate_frame(level) == true); + CHECK(ack_manager.will_generate_frame(level, 0) == true); } SECTION("QUIC delay ack and unorder packet", "[quic]") @@ -128,13 +128,13 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; ack_manager.update(level, 0, 1, false); - CHECK(ack_manager.will_generate_frame(level) == false); + CHECK(ack_manager.will_generate_frame(level, 0) == false); ack_manager.update(level, 1, 1, false); - CHECK(ack_manager.will_generate_frame(level) == false); + CHECK(ack_manager.will_generate_frame(level, 0) == false); ack_manager.update(level, 3, 1, false); - CHECK(ack_manager.will_generate_frame(level) == true); + CHECK(ack_manager.will_generate_frame(level, 0) == true); } SECTION("QUIC delay too much time", "[quic]") @@ -144,12 +144,12 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; ack_manager.update(level, 0, 1, false); - CHECK(ack_manager.will_generate_frame(level) == false); + CHECK(ack_manager.will_generate_frame(level, 0) == false); sleep(1); Thread::get_hrtime_updated(); ack_manager.update(level, 1, 1, false); - CHECK(ack_manager.will_generate_frame(level) == true); + CHECK(ack_manager.will_generate_frame(level, 0) == true); } SECTION("QUIC intial packet", "[quic]") @@ -158,7 +158,7 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; ack_manager.update(level, 0, 1, false); - CHECK(ack_manager.will_generate_frame(level) == true); + CHECK(ack_manager.will_generate_frame(level, 0) == true); } SECTION("QUIC handshake packet", "[quic]") @@ -167,7 +167,7 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") QUICEncryptionLevel level = QUICEncryptionLevel::HANDSHAKE; ack_manager.update(level, 0, 1, false); - CHECK(ack_manager.will_generate_frame(level) == true); + CHECK(ack_manager.will_generate_frame(level, 0) == true); } SECTION("QUIC frame fired", "[quic]") @@ -176,11 +176,11 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; ack_manager.update(level, 0, 1, false); - CHECK(ack_manager.will_generate_frame(level) == false); + CHECK(ack_manager.will_generate_frame(level, 0) == false); sleep(1); Thread::get_hrtime_updated(); - CHECK(ack_manager.will_generate_frame(level) == true); + CHECK(ack_manager.will_generate_frame(level, 0) == true); } SECTION("QUIC refresh frame", "[quic]") @@ -189,21 +189,21 @@ TEST_CASE("QUICAckFrameManager should send", "[quic]") QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; - QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); QUICAckFrame *frame = static_cast(ack_frame); CHECK(frame == nullptr); // unorder frame should sent immediately ack_manager.update(level, 1, 1, false); - CHECK(ack_manager.will_generate_frame(level) == true); + CHECK(ack_manager.will_generate_frame(level, 0) == true); ack_manager.update(level, 2, 1, false); // Delay due to some reason, the frame is not valued any more, but still valued sleep(1); Thread::get_hrtime_updated(); - CHECK(ack_manager.will_generate_frame(level) == true); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + CHECK(ack_manager.will_generate_frame(level, 0) == true); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame->ack_block_count() == 0); @@ -220,7 +220,7 @@ TEST_CASE("QUICAckFrameManager_loss_recover", "[quic]") // Initial state uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; - QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); QUICAckFrame *frame = static_cast(ack_frame); CHECK(frame == nullptr); @@ -230,7 +230,7 @@ TEST_CASE("QUICAckFrameManager_loss_recover", "[quic]") ack_manager.update(level, 8, 1, false); ack_manager.update(level, 9, 1, false); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 2); @@ -238,11 +238,11 @@ TEST_CASE("QUICAckFrameManager_loss_recover", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 1); CHECK(frame->ack_block_section()->begin()->gap() == 0); - CHECK(ack_manager.will_generate_frame(level) == false); + CHECK(ack_manager.will_generate_frame(level, 0) == false); ack_manager.update(level, 7, 1, false); ack_manager.update(level, 4, 1, false); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); @@ -299,7 +299,7 @@ TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; // Initial state - QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); QUICAckFrame *frame = static_cast(ack_frame); CHECK(frame == nullptr); @@ -309,7 +309,7 @@ TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") ack_manager.update(level, 8, 1, false); ack_manager.update(level, 9, 1, false); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 2); @@ -318,8 +318,8 @@ TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") CHECK(frame->ack_block_section()->begin()->gap() == 0); ack_manager.on_frame_lost(frame->id()); - CHECK(ack_manager.will_generate_frame(level) == true); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + CHECK(ack_manager.will_generate_frame(level, 0) == true); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 2); @@ -327,13 +327,13 @@ TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 1); CHECK(frame->ack_block_section()->begin()->gap() == 0); - CHECK(ack_manager.will_generate_frame(level) == false); + CHECK(ack_manager.will_generate_frame(level, 0) == false); ack_manager.on_frame_lost(frame->id()); - CHECK(ack_manager.will_generate_frame(level) == true); + CHECK(ack_manager.will_generate_frame(level, 0) == true); ack_manager.update(level, 7, 1, false); ack_manager.update(level, 4, 1, false); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 1); @@ -341,7 +341,7 @@ TEST_CASE("QUICAckFrameManager lost_frame", "[quic]") CHECK(frame->ack_block_section()->first_ack_block() == 5); CHECK(frame->ack_block_section()->begin()->gap() == 0); - CHECK(ack_manager.will_generate_frame(level) == false); + CHECK(ack_manager.will_generate_frame(level, 0) == false); } TEST_CASE("QUICAckFrameManager ack only packet", "[quic]") @@ -353,7 +353,7 @@ TEST_CASE("QUICAckFrameManager ack only packet", "[quic]") uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; // Initial state - QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); QUICAckFrame *frame = static_cast(ack_frame); CHECK(frame == nullptr); @@ -363,9 +363,9 @@ TEST_CASE("QUICAckFrameManager ack only packet", "[quic]") ack_manager.update(level, 4, 1, false); ack_manager.update(level, 5, 1, false); - CHECK(ack_manager.will_generate_frame(level) == true); + CHECK(ack_manager.will_generate_frame(level, 0) == true); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -375,7 +375,7 @@ TEST_CASE("QUICAckFrameManager ack only packet", "[quic]") ack_manager.update(level, 6, 1, true); ack_manager.update(level, 7, 1, true); - CHECK(ack_manager.will_generate_frame(level) == false); + CHECK(ack_manager.will_generate_frame(level, 0) == false); } SECTION("ONE_RTT") @@ -385,7 +385,7 @@ TEST_CASE("QUICAckFrameManager ack only packet", "[quic]") uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; // Initial state - QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + QUICFrame *ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); QUICAckFrame *frame = static_cast(ack_frame); CHECK(frame == nullptr); @@ -395,9 +395,9 @@ TEST_CASE("QUICAckFrameManager ack only packet", "[quic]") ack_manager.update(level, 4, 1, false); ack_manager.update(level, 5, 1, false); - CHECK(ack_manager.will_generate_frame(level) == true); + CHECK(ack_manager.will_generate_frame(level, 0) == true); - ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX); + ack_frame = ack_manager.generate_frame(frame_buf, level, UINT16_MAX, UINT16_MAX, 0); frame = static_cast(ack_frame); CHECK(frame != nullptr); CHECK(frame->ack_block_count() == 0); @@ -407,6 +407,6 @@ TEST_CASE("QUICAckFrameManager ack only packet", "[quic]") ack_manager.update(level, 6, 1, true); ack_manager.update(level, 7, 1, true); - CHECK(ack_manager.will_generate_frame(level) == false); + CHECK(ack_manager.will_generate_frame(level, 0) == false); } } diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index 83335609f8c..a5120b11a38 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -98,7 +98,7 @@ TEST_CASE("QUICFlowController_Local_Connection", "[quic]") fc.forward_limit(2048); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 2048); - QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024); + QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024, 0); CHECK(frame); CHECK(frame->type() == QUICFrameType::MAX_DATA); @@ -150,7 +150,7 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]") CHECK(fc.current_offset() == 1000); CHECK(fc.current_limit() == 1024); CHECK(ret != 0); - QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024); + QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024, 0); CHECK(frame); CHECK(frame->type() == QUICFrameType::DATA_BLOCKED); @@ -181,9 +181,9 @@ TEST_CASE("QUICFlowController_Remote_Connection_ZERO_Credit", "[quic]") CHECK(fc.current_limit() == 1024); CHECK(ret == 0); - CHECK(fc.will_generate_frame(QUICEncryptionLevel::ONE_RTT)); + CHECK(fc.will_generate_frame(QUICEncryptionLevel::ONE_RTT, 0)); // if there're anything to send - QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024); + QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024, 0); CHECK(frame); CHECK(frame->type() == QUICFrameType::DATA_BLOCKED); @@ -247,7 +247,7 @@ TEST_CASE("QUICFlowController_Local_Stream", "[quic]") fc.forward_limit(2048); CHECK(fc.current_offset() == 1024); CHECK(fc.current_limit() == 2048); - QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024); + QUICFrame *frame = fc.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 0, 1024, 0); CHECK(frame); CHECK(frame->type() == QUICFrameType::MAX_STREAM_DATA); @@ -288,7 +288,7 @@ TEST_CASE("QUICFlowController_Remote_Stream", "[quic]") CHECK(ret == 0); CHECK(fc.credit() == 0); - CHECK(fc.will_generate_frame(QUICEncryptionLevel::ONE_RTT)); + CHECK(fc.will_generate_frame(QUICEncryptionLevel::ONE_RTT, 0)); // Delay ret = fc.update(512); @@ -324,23 +324,23 @@ TEST_CASE("Frame retransmission", "[quic]") QUICRemoteConnectionFlowController fc(1024); // Check initial state - auto frame = fc.generate_frame(frame_buf, level, 1024, 1024); + auto frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); CHECK(!frame); ret = fc.update(1024); CHECK(ret == 0); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(frame); CHECK(static_cast(frame)->offset() == 1024); QUICFrameId id = frame->id(); // Don't retransmit unless the frame is lost - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(!frame); // Retransmit fc.on_frame_lost(id); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(frame); CHECK(static_cast(frame)->offset() == 1024); @@ -348,12 +348,12 @@ TEST_CASE("Frame retransmission", "[quic]") fc.on_frame_lost(frame->id()); fc.forward_limit(2048); ret = fc.update(1536); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); CHECK(!frame); // This should not be retransmition ret = fc.update(2048); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(frame); CHECK(static_cast(frame)->offset() == 2048); } @@ -365,23 +365,23 @@ TEST_CASE("Frame retransmission", "[quic]") QUICRemoteStreamFlowController fc(1024, 0); // Check initial state - auto frame = fc.generate_frame(frame_buf, level, 1024, 1024); + auto frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); CHECK(!frame); ret = fc.update(1024); CHECK(ret == 0); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(frame); CHECK(static_cast(frame)->offset() == 1024); QUICFrameId id = frame->id(); // Don't retransmit unless the frame is lost - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(!frame); // Retransmit fc.on_frame_lost(id); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(frame); CHECK(static_cast(frame)->offset() == 1024); @@ -389,12 +389,12 @@ TEST_CASE("Frame retransmission", "[quic]") fc.on_frame_lost(frame->id()); fc.forward_limit(2048); ret = fc.update(1536); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); CHECK(!frame); // This should not be retransmition ret = fc.update(2048); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(frame); CHECK(static_cast(frame)->offset() == 2048); } @@ -407,23 +407,23 @@ TEST_CASE("Frame retransmission", "[quic]") QUICLocalConnectionFlowController fc(&rp, 1024); // Check initial state - auto frame = fc.generate_frame(frame_buf, level, 1024, 1024); + auto frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); CHECK(!frame); fc.update(1024); fc.forward_limit(1024); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(frame); CHECK(static_cast(frame)->maximum_data() == 1024); QUICFrameId id = frame->id(); // Don't retransmit unless the frame is lost - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(!frame); // Retransmit fc.on_frame_lost(id); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(frame); CHECK(static_cast(frame)->maximum_data() == 1024); @@ -431,7 +431,7 @@ TEST_CASE("Frame retransmission", "[quic]") fc.on_frame_lost(id); fc.forward_limit(2048); fc.update(2048); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(frame); CHECK(static_cast(frame)->maximum_data() == 2048); } @@ -444,23 +444,23 @@ TEST_CASE("Frame retransmission", "[quic]") QUICLocalStreamFlowController fc(&rp, 1024, 0); // Check initial state - auto frame = fc.generate_frame(frame_buf, level, 1024, 1024); + auto frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); CHECK(!frame); fc.update(1024); fc.forward_limit(1024); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(frame); CHECK(static_cast(frame)->maximum_stream_data() == 1024); QUICFrameId id = frame->id(); // Don't retransmit unless the frame is lost - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(!frame); // Retransmit fc.on_frame_lost(id); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(frame); CHECK(static_cast(frame)->maximum_stream_data() == 1024); @@ -468,7 +468,7 @@ TEST_CASE("Frame retransmission", "[quic]") fc.on_frame_lost(id); fc.forward_limit(2048); fc.update(2048); - frame = fc.generate_frame(frame_buf, level, 1024, 1024); + frame = fc.generate_frame(frame_buf, level, 1024, 1024, 0); REQUIRE(frame); CHECK(static_cast(frame)->maximum_stream_data() == 2048); } diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 501eaa96419..9f76b64f5db 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -38,11 +38,10 @@ TEST_CASE("QUICFrameHandler", "[quic]") MockQUICConnection connection; MockQUICStreamManager streamManager; - MockQUICPacketTransmitter tx; MockQUICConnectionInfoProvider info; MockQUICCongestionController cc(&info); QUICRTTMeasure rtt_measure; - MockQUICLossDetector lossDetector(&tx, &info, &cc, &rtt_measure, 0); + MockQUICLossDetector lossDetector(&info, &cc, &rtt_measure, 0); QUICFrameDispatcher quicFrameDispatcher(&info); quicFrameDispatcher.add_handler(&connection); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index bbdc59f7356..20748830223 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -36,10 +36,9 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") QUICAckFrameManager afm; QUICConnectionId connection_id = {reinterpret_cast("\x01"), 1}; - MockQUICPacketTransmitter tx; MockQUICConnectionInfoProvider info; MockQUICCongestionController cc(&info); - QUICLossDetector detector(&tx, &info, &cc, &rtt_measure, 0); + QUICLossDetector detector(&info, &cc, &rtt_measure, 0); ats_unique_buf payload = ats_unique_malloc(512); size_t payload_len = 512; QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); @@ -52,7 +51,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") // Check initial state uint8_t frame_buffer[1024] = {0}; CHECK(g.lost_frame_count == 0); - QUICFrame *ping_frame = g.generate_frame(frame_buffer, QUICEncryptionLevel::HANDSHAKE, 4, UINT16_MAX); + QUICFrame *ping_frame = g.generate_frame(frame_buffer, QUICEncryptionLevel::HANDSHAKE, 4, UINT16_MAX, 0); uint8_t raw[4]; size_t len; @@ -85,9 +84,6 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") SECTION("1-RTT") { - // Check initial state - CHECK(tx.retransmitted.size() == 0); - // Send packet (1) to (7) payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), @@ -152,7 +148,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") afm.update(QUICEncryptionLevel::INITIAL, pn9, payload_len, false); afm.update(QUICEncryptionLevel::INITIAL, pn10, payload_len, false); uint8_t buf[QUICFrame::MAX_INSTANCE_SIZE]; - QUICFrame *x = afm.generate_frame(buf, QUICEncryptionLevel::INITIAL, 2048, 2048); + QUICFrame *x = afm.generate_frame(buf, QUICEncryptionLevel::INITIAL, 2048, 2048, 0); frame = static_cast(x); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); detector.handle_frame(QUICEncryptionLevel::INITIAL, *frame); @@ -176,14 +172,10 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") TEST_CASE("QUICLossDetector_HugeGap", "[quic]") { uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; - MockQUICPacketTransmitter tx; MockQUICConnectionInfoProvider info; MockQUICCongestionController cc(&info); QUICRTTMeasure rtt_measure; - QUICLossDetector detector(&tx, &info, &cc, &rtt_measure, 0); - - // Check initial state - CHECK(tx.retransmitted.size() == 0); + QUICLossDetector detector(&info, &cc, &rtt_measure, 0); auto t1 = Thread::get_hrtime(); QUICAckFrame *ack = QUICFrameFactory::create_ack_frame(frame_buf, 100000000, 100, 10000000); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index bf6aadc37d0..e18eaf1e965 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -223,50 +223,50 @@ TEST_CASE("QUICStream", "[quic]") write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame(level) == false); + CHECK(stream->will_generate_frame(level, 0) == false); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame(level) == false); + CHECK(stream->will_generate_frame(level, 0) == false); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame(level) == false); + CHECK(stream->will_generate_frame(level, 0) == false); write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame(level) == false); + CHECK(stream->will_generate_frame(level, 0) == false); // This should not send a frame because of flow control write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); CHECK(frame); CHECK(frame->type() == QUICFrameType::STREAM_DATA_BLOCKED); - CHECK(stream->will_generate_frame(level) == true); + CHECK(stream->will_generate_frame(level, 0) == true); // Update window stream->recv(*std::make_shared(stream_id, 5120)); // This should send a frame stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame(level) == false); + CHECK(stream->will_generate_frame(level, 0) == false); // Update window stream->recv(*std::make_shared(stream_id, 5632)); @@ -274,24 +274,24 @@ TEST_CASE("QUICStream", "[quic]") // This should send a frame write_buffer->write(data, 1024); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame(level) == true); + CHECK(stream->will_generate_frame(level, 0) == true); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); CHECK(frame->type() == QUICFrameType::STREAM_DATA_BLOCKED); // Update window stream->recv(*std::make_shared(stream_id, 6144)); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream->will_generate_frame(level) == true); - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->will_generate_frame(level) == false); + CHECK(stream->will_generate_frame(level, 0) == false); } /* @@ -357,15 +357,15 @@ TEST_CASE("QUICStream", "[quic]") QUICFrame *frame = nullptr; stream->reset(QUICStreamErrorUPtr(new QUICStreamError(stream.get(), QUIC_APP_ERROR_CODE_STOPPING))); - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); REQUIRE(frame); CHECK(frame->type() == QUICFrameType::RESET_STREAM); // Don't send it again untill it is considers as lost - CHECK(stream->generate_frame(frame_buf, level, 4096, 4096) == nullptr); + CHECK(stream->generate_frame(frame_buf, level, 4096, 4096, 0) == nullptr); // Loss the frame stream->on_frame_lost(frame->id()); // After the loss the frame should be regenerated - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); REQUIRE(frame); CHECK(frame->type() == QUICFrameType::RESET_STREAM); } @@ -387,15 +387,15 @@ TEST_CASE("QUICStream", "[quic]") QUICFrame *frame = nullptr; stream->stop_sending(QUICStreamErrorUPtr(new QUICStreamError(stream.get(), QUIC_APP_ERROR_CODE_STOPPING))); - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); REQUIRE(frame); CHECK(frame->type() == QUICFrameType::STOP_SENDING); // Don't send it again untill it is considers as lost - CHECK(stream->generate_frame(frame_buf, level, 4096, 4096) == nullptr); + CHECK(stream->generate_frame(frame_buf, level, 4096, 4096, 0) == nullptr); // Loss the frame stream->on_frame_lost(frame->id()); // After the loss the frame should be regenerated - frame = stream->generate_frame(frame_buf, level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); REQUIRE(frame); CHECK(frame->type() == QUICFrameType::STOP_SENDING); } From 61f1631d42ccdf748f404b55d8c68a518b11dcef Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 27 Feb 2019 16:24:08 +0900 Subject: [PATCH 1168/1313] Removed unused code --- iocore/net/P_QUICNetVConnection.h | 23 ----------------------- iocore/net/QUICNetVConnection.cc | 3 --- 2 files changed, 26 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index bdece52337b..670aaff628c 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -62,32 +62,9 @@ #include "quic/QUICAddrVerifyState.h" #include "quic/QUICPacketProtectionKeyInfo.h" -// These are included here because older OpenQUIC libraries don't have them. -// Don't copy these defines, or use their values directly, they are merely -// here to avoid compiler errors. -#ifndef QUIC_TLSEXT_ERR_OK -#define QUIC_TLSEXT_ERR_OK 0 -#endif - -#ifndef QUIC_TLSEXT_ERR_NOACK -#define QUIC_TLSEXT_ERR_NOACK 3 -#endif - -#define QUIC_OP_HANDSHAKE 0x16 - // Size of connection ids for debug log : e.g. aaaaaaaa-bbbbbbbb\0 static constexpr size_t MAX_CIDS_SIZE = 8 + 1 + 8 + 1; -// class QUICNextProtocolSet; -// struct QUICCertLookup; - -typedef enum { - QUIC_HOOK_OP_DEFAULT, ///< Null / initialization value. Do normal processing. - QUIC_HOOK_OP_TUNNEL, ///< Switch to blind tunnel - QUIC_HOOK_OP_TERMINATE, ///< Termination connection / transaction. - QUIC_HOOK_OP_LAST = QUIC_HOOK_OP_TERMINATE ///< End marker value. -} QuicVConnOp; - ////////////////////////////////////////////////////////////////// // // class NetVConnection diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index f2d3dfb5ceb..549fd379d60 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -41,9 +41,6 @@ #include "QUICConfig.h" #include "QUICIntUtil.h" -#define STATE_FROM_VIO(_x) ((NetState *)(((char *)(_x)) - STATE_VIO_OFFSET)) -#define STATE_VIO_OFFSET ((uintptr_t) & ((NetState *)0)->vio) - using namespace std::literals; static constexpr std::string_view QUIC_DEBUG_TAG = "quic_net"sv; From a52ad8d59321536c380641039676fe97f0317108 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 1 Mar 2019 11:35:35 +0800 Subject: [PATCH 1169/1313] QUIC: Fixed warning in Mock.h --- iocore/net/quic/Mock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 94c8c46d057..3fc56b70da9 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -488,7 +488,7 @@ class MockQUICPacketProtectionKeyInfo : public QUICPacketProtectionKeyInfo return EVP_GCM_TLS_TAG_LEN; } - size_t *encryption_iv_len(QUICKeyPhase) const override + const size_t *encryption_iv_len(QUICKeyPhase) const override { static size_t dummy = 12; return &dummy; From 01ed38c1ac7cfaba5acc38b6066b534d6a80e38b Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 1 Mar 2019 15:26:20 +0800 Subject: [PATCH 1170/1313] QUIC: Fixed build error under ubuntu 16.04 --- src/traffic_quic/traffic_quic.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/traffic_quic/traffic_quic.cc b/src/traffic_quic/traffic_quic.cc index 358e7c07c04..551bb50f33c 100644 --- a/src/traffic_quic/traffic_quic.cc +++ b/src/traffic_quic/traffic_quic.cc @@ -230,6 +230,13 @@ StatPagesManager statPagesManager; #include "ProcessManager.h" inkcoreapi ProcessManager *pmgmt = nullptr; +int +BaseManager::registerMgmtCallback(int, const MgmtCallback &) +{ + ink_assert(false); + return 0; +} + void ProcessManager::signalManager(int, char const *, int) { From 7a20a2117dc73aaf2804d7180e3784b97278fa56 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 4 Mar 2019 10:27:35 +0900 Subject: [PATCH 1171/1313] Reduce dup code --- iocore/net/P_QUICPacketHandler.h | 26 +++++++------ iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/QUICPacketHandler.cc | 65 ++++++++++++-------------------- 3 files changed, 39 insertions(+), 54 deletions(-) diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index b24808ff55c..d7337e2d867 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -40,15 +40,19 @@ class QUICPacketHandler QUICPacketHandler(); ~QUICPacketHandler(); - virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketHeaderProtector &pn_protector) = 0; - virtual void send_packet(QUICNetVConnection *vc, Ptr udp_payload) = 0; + void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketHeaderProtector &pn_protector); + void send_packet(QUICNetVConnection *vc, Ptr udp_payload); - virtual void close_conenction(QUICNetVConnection *conn); + void close_connection(QUICNetVConnection *conn); protected: - static void _send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu, - const QUICPacketHeaderProtector *ph_protector, int dcil); - static void _send_packet(Continuation *c, QUICNetVConnection *vc, Ptr udp_payload); + 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 udp_payload); + + // FIXME Remove this + // QUICPacketHandler could be a continuation, but NetAccept is a contination too. + virtual Continuation *_get_continuation() = 0; Event *_collector_event = nullptr; QUICClosedConCollector *_closed_con_collector = nullptr; @@ -72,10 +76,9 @@ class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler virtual int acceptEvent(int event, void *e) override; void init_accept(EThread *t) override; +protected: // QUICPacketHandler - virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, - const QUICPacketHeaderProtector &ph_protector) override; - virtual void send_packet(QUICNetVConnection *vc, Ptr udp_payload) override; + Continuation *_get_continuation() override; private: void _recv_packet(int event, UDPPacket *udp_packet) override; @@ -98,10 +101,9 @@ class QUICPacketHandlerOut : public Continuation, public QUICPacketHandler void init(QUICNetVConnection *vc); int event_handler(int event, Event *data); +protected: // QUICPacketHandler - virtual void send_packet(const QUICPacket &packet, QUICNetVConnection *vc, - const QUICPacketHeaderProtector &pn_protector) override; - virtual void send_packet(QUICNetVConnection *vc, Ptr udp_payload) override; + Continuation *_get_continuation() override; private: void _recv_packet(int event, UDPPacket *udp_packet) override; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 549fd379d60..241952f7272 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -316,7 +316,7 @@ QUICNetVConnection::free(EThread *t) super::clear(); */ - this->_packet_handler->close_conenction(this); + this->_packet_handler->close_connection(this); } void diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 58e73c50d45..94939169d25 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -63,7 +63,7 @@ QUICPacketHandler::~QUICPacketHandler() } void -QUICPacketHandler::close_conenction(QUICNetVConnection *conn) +QUICPacketHandler::close_connection(QUICNetVConnection *conn) { int isin = ink_atomic_swap(&conn->in_closed_queue, 1); if (!isin) { @@ -72,7 +72,7 @@ QUICPacketHandler::close_conenction(QUICNetVConnection *conn) } void -QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu, +QUICPacketHandler::_send_packet(const QUICPacket &packet, UDPConnection *udp_con, IpEndpoint &addr, uint32_t pmtu, const QUICPacketHeaderProtector *ph_protector, int dcil) { size_t udp_len; @@ -85,30 +85,13 @@ QUICPacketHandler::_send_packet(Continuation *c, const QUICPacket &packet, UDPCo ph_protector->protect(reinterpret_cast(udp_payload->start()), udp_len, dcil); } - UDPPacket *udp_packet = new_UDPPacket(addr, 0, udp_payload); - - if (is_debug_tag_set(debug_tag)) { - ip_port_text_buffer ipb; - QUICConnectionId dcid = packet.destination_cid(); - QUICConnectionId scid = QUICConnectionId::ZERO(); - if (packet.type() != QUICPacketType::PROTECTED) { - scid = packet.source_cid(); - } - QUICDebugDS(dcid, scid, "send %s packet to %s size=%" PRId64, QUICDebugNames::packet_type(packet.type()), - ats_ip_nptop(&udp_packet->to.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); - } - - // NOTE: packet will be enqueued to udpOutQueue of UDPNetHandler - udp_con->send(c, udp_packet); - get_UDPNetHandler(static_cast(udp_con)->ethread)->signalActivity(); + this->_send_packet(udp_con, addr, udp_payload); } void -QUICPacketHandler::_send_packet(Continuation *c, QUICNetVConnection *vc, Ptr udp_payload) +QUICPacketHandler::_send_packet(UDPConnection *udp_con, IpEndpoint &addr, Ptr udp_payload) { - UDPConnection *udp_con = vc->get_udp_con(); - IpEndpoint addr = vc->con.addr; - UDPPacket *udp_packet = new_UDPPacket(addr, 0, udp_payload); + UDPPacket *udp_packet = new_UDPPacket(addr, 0, udp_payload); if (is_debug_tag_set(debug_tag)) { ip_port_text_buffer ipb; @@ -132,14 +115,14 @@ QUICPacketHandler::_send_packet(Continuation *c, QUICNetVConnection *vc, Ptrsend(c, udp_packet); + udp_con->send(this->_get_continuation(), udp_packet); get_UDPNetHandler(static_cast(udp_con)->ethread)->signalActivity(); } // // QUICPacketHandlerIn // -QUICPacketHandlerIn::QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt) : NetAccept(opt) +QUICPacketHandlerIn::QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt) : NetAccept(opt), QUICPacketHandler() { this->mutex = new_ProxyMutex(); // create Connection Table @@ -210,6 +193,12 @@ QUICPacketHandlerIn::init_accept(EThread *t = nullptr) SET_HANDLER(&QUICPacketHandlerIn::acceptEvent); } +Continuation * +QUICPacketHandlerIn::_get_continuation() +{ + return static_cast(this); +} + void QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) { @@ -257,7 +246,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) QUICDebugDS(scid, dcid, "Unsupported version: 0x%x", v); QUICPacketUPtr vn = QUICPacketFactory::create_version_negotiation_packet(scid, dcid); - this->_send_packet(this, *vn, udp_packet->getConnection(), udp_packet->from, 1200, nullptr, 0); + this->_send_packet(*vn, udp_packet->getConnection(), udp_packet->from, 1200, nullptr, 0); udp_packet->free(); return; } @@ -296,7 +285,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) QUICConfig::scoped_config params; QUICStatelessResetToken token(dcid, params->instance_id()); auto packet = QUICPacketFactory::create_stateless_reset_packet(dcid, token); - this->_send_packet(this, *packet, udp_packet->getConnection(), udp_packet->from, 1200, nullptr, 0); + this->_send_packet(*packet, udp_packet->getConnection(), udp_packet->from, 1200, nullptr, 0); udp_packet->free(); return; } @@ -346,15 +335,15 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // TODO: Should be called via eventProcessor? void -QUICPacketHandlerIn::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketHeaderProtector &ph_protector) +QUICPacketHandler::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketHeaderProtector &ph_protector) { - this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &ph_protector, vc->peer_connection_id().length()); + this->_send_packet(packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &ph_protector, vc->peer_connection_id().length()); } void -QUICPacketHandlerIn::send_packet(QUICNetVConnection *vc, Ptr udp_payload) +QUICPacketHandler::send_packet(QUICNetVConnection *vc, Ptr udp_payload) { - this->_send_packet(this, vc, udp_payload); + this->_send_packet(vc->get_udp_con(), vc->con.addr, udp_payload); } int @@ -381,7 +370,7 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC local_cid.randomize(); QUICPacketUPtr retry_packet = QUICPacketFactory::create_retry_packet(scid, local_cid, dcid, token); - this->_send_packet(this, *retry_packet, connection, from, 1200, nullptr, 0); + this->_send_packet(*retry_packet, connection, from, 1200, nullptr, 0); return -2; } else { @@ -410,7 +399,7 @@ QUICPacketHandlerIn::_stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPC // // QUICPacketHandlerOut // -QUICPacketHandlerOut::QUICPacketHandlerOut() : Continuation(new_ProxyMutex()) +QUICPacketHandlerOut::QUICPacketHandlerOut() : Continuation(new_ProxyMutex()), QUICPacketHandler() { SET_HANDLER(&QUICPacketHandlerOut::event_handler); } @@ -446,16 +435,10 @@ QUICPacketHandlerOut::event_handler(int event, Event *data) return EVENT_DONE; } -void -QUICPacketHandlerOut::send_packet(const QUICPacket &packet, QUICNetVConnection *vc, const QUICPacketHeaderProtector &ph_protector) -{ - this->_send_packet(this, packet, vc->get_udp_con(), vc->con.addr, vc->pmtu(), &ph_protector, vc->peer_connection_id().length()); -} - -void -QUICPacketHandlerOut::send_packet(QUICNetVConnection *vc, Ptr udp_payload) +Continuation * +QUICPacketHandlerOut::_get_continuation() { - this->_send_packet(this, vc, udp_payload); + return this; } void From 620c1fd73f0d4079c345da2555c2d90a2a66800c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 4 Mar 2019 10:55:45 +0900 Subject: [PATCH 1172/1313] Check local flow controller to send MAX_STREAM_DATA frame --- iocore/net/quic/QUICStream.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 401382c1660..a398e012d73 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -413,7 +413,7 @@ QUICStream::recv(const QUICRstStreamFrame &frame) bool QUICStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { - return this->_write_vio.get_reader()->read_avail() > 0; + return this->_local_flow_controller.will_generate_frame(level, timestamp) || (this->_write_vio.get_reader()->read_avail() > 0); } QUICFrame * From 73454c9be6bd9735ef787ab7227c3cdb590ad122 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 4 Mar 2019 11:08:17 +0900 Subject: [PATCH 1173/1313] Print stream id of MAX_STREAM_DATA and STREAM_DATA_BLOCKED on debug log --- iocore/net/quic/QUICFrame.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index c0924293224..13e8339f394 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1507,7 +1507,8 @@ QUICMaxStreamDataFrame::store(uint8_t *buf, size_t *len, size_t limit) const int QUICMaxStreamDataFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| MAX_STREAM_DATA size=%zu maximum=%" PRIu64, this->size(), this->maximum_stream_data()); + return snprintf(msg, msg_len, "| MAX_STREAM_DATA size=%zu id=%" PRIu64 " maximum=%" PRIu64, this->size(), this->stream_id(), + this->maximum_stream_data()); } QUICStreamId @@ -1729,7 +1730,8 @@ QUICStreamDataBlockedFrame::parse(const uint8_t *buf, size_t len) int QUICStreamDataBlockedFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| STREAM_DATA_BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset()); + return snprintf(msg, msg_len, "| STREAM_DATA_BLOCKED size=%zu id=%" PRIu64 " offset=%" PRIu64, this->size(), this->stream_id(), + this->offset()); } QUICFrameType From e9ad3d9c69020dde5e5e26d6cf9e451c7aeda101 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Mar 2019 11:12:37 +0900 Subject: [PATCH 1174/1313] Include a reserved version to Version Negotiation packet --- iocore/net/quic/QUICHandshake.cc | 2 +- iocore/net/quic/QUICPacketFactory.cc | 9 ++++++++- iocore/net/quic/QUICTypes.h | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 2a96af3bf63..c8507e94e80 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -110,7 +110,7 @@ QUICHandshake::start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled { QUICVersion initital_version = QUIC_SUPPORTED_VERSIONS[0]; if (vn_exercise_enabled) { - initital_version = QUIC_EXERCISE_VERSIONS; + initital_version = QUIC_EXERCISE_VERSION; } this->_load_local_client_transport_parameters(initital_version); diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc index bef0e0cd4b1..ec4c98fc6fa 100644 --- a/iocore/net/quic/QUICPacketFactory.cc +++ b/iocore/net/quic/QUICPacketFactory.cc @@ -171,7 +171,7 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP QUICPacketUPtr QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUICConnectionId scid) { - size_t len = sizeof(QUICVersion) * countof(QUIC_SUPPORTED_VERSIONS); + size_t len = sizeof(QUICVersion) * (countof(QUIC_SUPPORTED_VERSIONS) + 1); ats_unique_buf versions(reinterpret_cast(ats_malloc(len))); uint8_t *p = versions.get(); @@ -181,6 +181,13 @@ QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUIC 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(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); diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 44515814785..bf734d463b4 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -52,7 +52,7 @@ using QUICOffset = uint64_t; constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { 0xff000012, }; -constexpr QUICVersion QUIC_EXERCISE_VERSIONS = 0x1a2a3a4a; +constexpr QUICVersion QUIC_EXERCISE_VERSION = 0x1a2a3a4a; enum class QUICEncryptionLevel { NONE = -1, From 991a990549153ea4c62c38ee46ab26f33a000c49 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Mar 2019 13:59:23 +0900 Subject: [PATCH 1175/1313] Drop Initial packets with short DICL --- iocore/net/QUICPacketHandler.cc | 13 +++++++++++++ iocore/net/quic/QUICTypes.h | 5 +++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 94939169d25..6d693cd79f9 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -255,6 +255,19 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // TODO: lookup DCID by 5-tuple when ATS omits SCID return; } + + QUICPacketType type = QUICPacketType::UNINITIALIZED; + QUICPacketLongHeader::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 + // the Destination Connection ID field with an unpredictable value. This MUST be at least 8 bytes in length. + if (dcid != QUICConnectionId::ZERO() && dcid.length() < QUICConnectionId::MIN_LENGTH_FOR_INITIAL) { + QUICDebug("Ignore packet - DCIL is too small for Initial packet"); + udp_packet->free(); + return; + } + } } else { // TODO: lookup DCID by 5-tuple when ATS omits SCID if (is_debug_tag_set(debug_tag)) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index bf734d463b4..c376a2f5c4d 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -223,8 +223,9 @@ class QUICConnectionId public: static uint8_t SCID_LEN; - static const int MAX_LENGTH = 18; - static const size_t MAX_HEX_STR_LENGTH = MAX_LENGTH * 2 + 1; + static const int MIN_LENGTH_FOR_INITIAL = 8; + static const int MAX_LENGTH = 18; + static const size_t MAX_HEX_STR_LENGTH = MAX_LENGTH * 2 + 1; static QUICConnectionId ZERO(); QUICConnectionId(); QUICConnectionId(const uint8_t *buf, uint8_t len); From ac81d910e6d6aaf2bf00db81de44abf0c6a15d43 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 5 Mar 2019 16:07:42 +0900 Subject: [PATCH 1176/1313] Walk through loss detectors to get correct RTO --- iocore/net/QUICNetVConnection.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 241952f7272..c94f19d6d7e 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1918,8 +1918,15 @@ QUICNetVConnection::_validate_new_path() this->_path_validator->validate(); // Not sure how long we should wait. The spec says just "enough time". // Use the same time amount as the closing timeout. - int index = QUICTypeUtil::pn_space_index(this->_hs_protocol->current_encryption_level()); - ink_hrtime rto = this->_loss_detector[index]->current_rto_period(); + ink_hrtime rto = 0; + int current_level_index = QUICTypeUtil::pn_space_index(this->_hs_protocol->current_encryption_level()); + + // Workaround fix for #5111 - walk through PN Spaces to get correct RTO + // This could be removed when _loss_detectors are combined. + for (int i = 0; i <= current_level_index; ++i) { + rto = std::max(rto, this->_loss_detector[i]->current_rto_period()); + } + this->_schedule_path_validation_timeout(3 * rto); } From b9928bf5f6d8a7551917c2c70482dc0d861dd318 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Mar 2019 15:47:32 +0900 Subject: [PATCH 1177/1313] Remove an unneccessary function --- iocore/net/P_QUICNetVConnection.h | 2 -- iocore/net/QUICNetVConnection.cc | 8 +------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 670aaff628c..361d83b34cf 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -290,8 +290,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub std::vector &frames); QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size); void _packetize_closing_frame(); - QUICPacketUPtr _build_packet(ats_unique_buf buf, size_t len, bool retransmittable, bool probing, bool crypto, - std::vector &frames, QUICPacketType type = QUICPacketType::UNINITIALIZED); QUICPacketUPtr _build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing, bool crypto, std::vector &frames); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index c94f19d6d7e..410b2358160 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1469,13 +1469,7 @@ QUICPacketUPtr QUICNetVConnection::_build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool ack_eliciting, bool probing, bool crypto, std::vector &frames) { - return this->_build_packet(std::move(buf), len, ack_eliciting, probing, crypto, frames, QUICTypeUtil::packet_type(level)); -} - -QUICPacketUPtr -QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool ack_eliciting, bool probing, bool crypto, - std::vector &frames, QUICPacketType type) -{ + QUICPacketType type = QUICTypeUtil::packet_type(level); QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); switch (type) { From e0cc477c91851cfc095ebf84f2ee8aff62f7693f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Mar 2019 15:55:08 +0900 Subject: [PATCH 1178/1313] Fix tests --- iocore/net/quic/test/test_QUICPacketFactory.cc | 1 + iocore/net/quic/test/test_QUICVersionNegotiator.cc | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index cd3bf33b9ae..5b3936ca844 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -53,6 +53,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Destination Connection ID 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection ID 0xff, 0x00, 0x00, 0x12, // Supported Version + 0x1a, 0x2a, 0x3a, 0x4a, // Excercise Version }; uint8_t buf[1024] = {0}; size_t buf_len; diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 2d3dbae9095..24b607cfd07 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -68,7 +68,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); // Validate version - QUICTransportParametersInClientHello tp(QUIC_EXERCISE_VERSIONS); + QUICTransportParametersInClientHello tp(QUIC_EXERCISE_VERSION); vn.validate(&tp); CHECK(vn.status() == QUICVersionNegotiationStatus::VALIDATED); CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); @@ -80,7 +80,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); // Negotiate version - packet_factory.set_version(QUIC_EXERCISE_VERSIONS); + packet_factory.set_version(QUIC_EXERCISE_VERSION); QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true, dummy_frames); vn.negotiate(initial_packet.get()); @@ -125,7 +125,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); // Negotiate version - packet_factory.set_version(QUIC_EXERCISE_VERSIONS); + packet_factory.set_version(QUIC_EXERCISE_VERSION); QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true, dummy_frames); From 5e3ca198bc73f493c1df3b97aae6ecb058adf06f Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 20 Feb 2019 12:16:14 +0900 Subject: [PATCH 1179/1313] QUIC: Load multiple certs --- iocore/net/QUICNetProcessor.cc | 1 + iocore/net/QUICNetVConnection.cc | 4 +- iocore/net/SSLUtils.cc | 75 --------- iocore/net/quic/QUICConfig.cc | 255 +++++++++++++++++++++++++++---- iocore/net/quic/QUICConfig.h | 32 +++- iocore/net/quic/QUICGlobals.cc | 63 +++++++- iocore/net/quic/QUICGlobals.h | 2 + 7 files changed, 321 insertions(+), 111 deletions(-) diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 8c63668ffe7..5a2e373bb59 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -63,6 +63,7 @@ QUICNetProcessor::start(int, size_t stacksize) // This initialization order matters ... // QUICInitializeLibrary(); QUICConfig::startup(); + QUICCertConfig::startup(); #ifdef TLS1_3_VERSION_DRAFT_TXT // FIXME: remove this when TLS1_3_VERSION_DRAFT_TXT is removed diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 410b2358160..e8c7b5390e0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -240,10 +240,12 @@ QUICNetVConnection::start() this->_five_tuple.update(this->local_addr, this->remote_addr, SOCK_DGRAM); // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not if (this->direction() == NET_VCONNECTION_IN) { + QUICCertConfig::scoped_config server_cert; + this->_pp_key_info.set_context(QUICPacketProtectionKeyInfo::Context::SERVER); this->_ack_frame_manager.set_ack_delay_exponent(params->ack_delay_exponent_in()); this->_reset_token = QUICStatelessResetToken(this->_quic_connection_id, params->instance_id()); - this->_hs_protocol = this->_setup_handshake_protocol(params->server_ssl_ctx()); + this->_hs_protocol = this->_setup_handshake_protocol(server_cert->ssl_default); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol, this->_reset_token, params->stateless_retry()); this->_ack_frame_manager.set_max_ack_delay(params->max_ack_delay_in()); this->_schedule_ack_manager_periodic(params->max_ack_delay_in()); diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc index 7c7c7feceb6..c83b3143803 100644 --- a/iocore/net/SSLUtils.cc +++ b/iocore/net/SSLUtils.cc @@ -1557,81 +1557,6 @@ ssl_extract_certificate(const matcher_line *line_info, SSLMultiCertConfigParams return true; } -// TODO: remove this function and setup SSL_CTX for QUIC somehow -bool -SSLParseCertificateConfiguration(const SSLConfigParams *params, SSL_CTX *ssl_ctx) -{ - char *tok_state = nullptr; - char *line = nullptr; - ats_scoped_str file_buf; - unsigned line_num = 0; - matcher_line line_info; - - const matcher_tags sslCertTags = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, false}; - - Note("loading SSL certificate configuration from %s", params->configFilePath); - - if (params->configFilePath) { - file_buf = readIntoBuffer(params->configFilePath, __func__, nullptr); - } - - if (!file_buf) { - Error("failed to read SSL certificate configuration from %s", params->configFilePath); - return false; - } - - // Optionally elevate/allow file access to read root-only - // certificates. The destructor will drop privilege for us. - uint32_t elevate_setting = 0; - REC_ReadConfigInteger(elevate_setting, "proxy.config.ssl.cert.load_elevated"); - ElevateAccess elevate_access(elevate_setting ? ElevateAccess::FILE_PRIVILEGE : 0); - - line = tokLine(file_buf, &tok_state); - while (line != nullptr) { - line_num++; - - // Skip all blank spaces at beginning of line. - while (*line && isspace(*line)) { - line++; - } - - if (*line != '\0' && *line != '#') { - SSLMultiCertConfigParams sslMultiCertSettings; - const char *errPtr; - - errPtr = parseConfigLine(line, &line_info, &sslCertTags); - - if (errPtr != nullptr) { - RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "%s: discarding %s entry at line %d: %s", __func__, params->configFilePath, - line_num, errPtr); - } else { - if (ssl_extract_certificate(&line_info, sslMultiCertSettings)) { - // There must be a certificate specified unless the tunnel action is set - if (sslMultiCertSettings.cert || sslMultiCertSettings.opt != SSLCertContext::OPT_TUNNEL) { - if (SSL_CTX_use_PrivateKey_file(ssl_ctx, sslMultiCertSettings.key.get(), SSL_FILETYPE_PEM) != 1) { - Error("Couldn't load private_key: %s", sslMultiCertSettings.key.get()); - return false; - } - - if (SSL_CTX_use_certificate_chain_file(ssl_ctx, sslMultiCertSettings.cert.get()) != 1) { - Error("Couldn't load cert: %s", sslMultiCertSettings.cert.get()); - return false; - } - - return true; - - } else { - Warning("No ssl_cert_name specified and no tunnel action set"); - } - } - } - } - - line = tokLine(nullptr, &tok_state); - } - return true; -} - bool SSLMultiCertConfigLoader::load(SSLCertLookup *lookup) { diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 8ec9e4f8b24..139df1a4d6c 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -28,10 +28,13 @@ #include #include "P_SSLConfig.h" +#include "P_OCSPStapling.h" #include "QUICGlobals.h" #include "QUICTransportParameters.h" +#define QUICConfDebug(fmt, ...) Debug("quic_conf", fmt, ##__VA_ARGS__) + // OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings) // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html // Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? @@ -40,6 +43,7 @@ static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-18"sv); int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; +int QUICCertConfig::_config_id = 0; static SSL_CTX * quic_new_ssl_ctx() @@ -70,29 +74,6 @@ quic_new_ssl_ctx() return ssl_ctx; } -static SSL_CTX * -quic_init_server_ssl_ctx(const QUICConfigParams *params) -{ - SSL_CTX *ssl_ctx = quic_new_ssl_ctx(); - - SSLConfig::scoped_config ssl_params; - SSLParseCertificateConfiguration(ssl_params, ssl_ctx); - - if (SSL_CTX_check_private_key(ssl_ctx) != 1) { - Error("check private key failed"); - } - - SSL_CTX_set_alpn_select_cb(ssl_ctx, QUIC::ssl_select_next_protocol, nullptr); - - if (params->server_supported_groups() != nullptr) { - if (SSL_CTX_set1_groups_list(ssl_ctx, params->server_supported_groups()) != 1) { - Error("SSL_CTX_set1_groups_list failed"); - } - } - - return ssl_ctx; -} - static SSL_CTX * quic_init_client_ssl_ctx(const QUICConfigParams *params) { @@ -125,7 +106,6 @@ QUICConfigParams::~QUICConfigParams() this->_server_supported_groups = (char *)ats_free_null(this->_server_supported_groups); this->_client_supported_groups = (char *)ats_free_null(this->_client_supported_groups); - SSL_CTX_free(this->_server_ssl_ctx); SSL_CTX_free(this->_client_ssl_ctx); }; @@ -194,7 +174,6 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_cc_persistent_congestion_threshold, "proxy.config.quic.congestion_control.persistent_congestion_threshold"); - this->_server_ssl_ctx = quic_init_server_ssl_ctx(this); this->_client_ssl_ctx = quic_init_client_ssl_ctx(this); } @@ -374,12 +353,6 @@ QUICConfigParams::client_supported_groups() const return this->_client_supported_groups; } -SSL_CTX * -QUICConfigParams::server_ssl_ctx() const -{ - return this->_server_ssl_ctx; -} - SSL_CTX * QUICConfigParams::client_ssl_ctx() const { @@ -489,3 +462,223 @@ QUICConfig::release(QUICConfigParams *params) { configProcessor.release(_config_id, params); } + +// +// QUICCertConfig +// +void +QUICCertConfig::startup() +{ + reconfigure(); +} + +void +QUICCertConfig::reconfigure() +{ + SSLConfig::scoped_config params; + SSLCertLookup *lookup = new SSLCertLookup(); + + QUICMultiCertConfigLoader loader(params); + loader.load(lookup); + + _config_id = configProcessor.set(_config_id, lookup); +} + +SSLCertLookup * +QUICCertConfig::acquire() +{ + return static_cast(configProcessor.get(_config_id)); +} + +void +QUICCertConfig::release(SSLCertLookup *lookup) +{ + configProcessor.release(_config_id, lookup); +} + +// +// QUICMultiCertConfigLoader +// +SSL_CTX * +QUICMultiCertConfigLoader::default_server_ssl_ctx() +{ + return quic_new_ssl_ctx(); +} + +SSL_CTX * +QUICMultiCertConfigLoader::init_server_ssl_ctx(std::vector &cert_list, const SSLMultiCertConfigParams *multi_cert_params) +{ + const SSLConfigParams *params = this->_params; + + SSL_CTX *ctx = this->default_server_ssl_ctx(); + + if (multi_cert_params) { + if (multi_cert_params->dialog) { + // TODO: dialog support + } + + if (multi_cert_params->cert) { + if (!SSLMultiCertConfigLoader::load_certs(ctx, cert_list, params, multi_cert_params)) { + goto fail; + } + } + + // SSL_CTX_load_verify_locations() builds the cert chain from the + // serverCACertFilename if that is not nullptr. Otherwise, it uses the hashed + // symlinks in serverCACertPath. + // + // if ssl_ca_name is NOT configured for this cert in ssl_multicert.config + // AND + // if proxy.config.ssl.CA.cert.filename and proxy.config.ssl.CA.cert.path + // are configured + // pass that file as the chain (include all certs in that file) + // else if proxy.config.ssl.CA.cert.path is configured (and + // proxy.config.ssl.CA.cert.filename is nullptr) + // use the hashed symlinks in that directory to build the chain + if (!multi_cert_params->ca && params->serverCACertPath != nullptr) { + if ((!SSL_CTX_load_verify_locations(ctx, params->serverCACertFilename, params->serverCACertPath)) || + (!SSL_CTX_set_default_verify_paths(ctx))) { + Error("invalid CA Certificate file or CA Certificate path"); + goto fail; + } + } + } + + if (params->clientCertLevel != 0) { + // TODO: client cert support + } + + if (!SSLMultiCertConfigLoader::set_session_id_context(ctx, params, multi_cert_params)) { + goto fail; + } + + if (params->server_tls13_cipher_suites != nullptr) { + if (!SSL_CTX_set_ciphersuites(ctx, params->server_tls13_cipher_suites)) { + Error("invalid tls server cipher suites in records.config"); + goto fail; + } + } + + if (params->server_groups_list != nullptr) { + if (!SSL_CTX_set1_groups_list(ctx, params->server_groups_list)) { + Error("invalid groups list for server in records.config"); + goto fail; + } + } + + // SSL_CTX_set_info_callback(ctx, ssl_callback_info); + + SSL_CTX_set_alpn_select_cb(ctx, QUIC::ssl_select_next_protocol, nullptr); + + if (SSLConfigParams::ssl_ocsp_enabled) { + QUICConfDebug("SSL OCSP Stapling is enabled"); + SSL_CTX_set_tlsext_status_cb(ctx, ssl_callback_ocsp_stapling); + const char *cert_name = multi_cert_params ? multi_cert_params->cert.get() : nullptr; + + for (auto cert : cert_list) { + if (!ssl_stapling_init_cert(ctx, cert, cert_name)) { + Warning("failed to configure SSL_CTX for OCSP Stapling info for certificate at %s", cert_name); + } + } + } else { + QUICConfDebug("SSL OCSP Stapling is disabled"); + } + + if (SSLConfigParams::init_ssl_ctx_cb) { + SSLConfigParams::init_ssl_ctx_cb(ctx, true); + } + + return ctx; + +fail: + SSLReleaseContext(ctx); + for (auto cert : cert_list) { + X509_free(cert); + } + + return nullptr; +} + +SSL_CTX * +QUICMultiCertConfigLoader::_store_ssl_ctx(SSLCertLookup *lookup, const SSLMultiCertConfigParams *multi_cert_params) +{ + std::vector cert_list; + SSL_CTX *ctx = this->init_server_ssl_ctx(cert_list, multi_cert_params); + ssl_ticket_key_block *keyblock = nullptr; + bool inserted = false; + + if (!ctx || !multi_cert_params) { + lookup->is_valid = false; + return nullptr; + } + + const char *certname = multi_cert_params->cert.get(); + for (auto cert : cert_list) { + if (0 > SSLMultiCertConfigLoader::check_server_cert_now(cert, certname)) { + /* At this point, we know cert is bad, and we've already printed a + descriptive reason as to why cert is bad to the log file */ + QUICConfDebug("Marking certificate as NOT VALID: %s", certname); + lookup->is_valid = false; + } + } + + // Index this certificate by the specified IP(v6) address. If the address is "*", make it the default context. + if (multi_cert_params->addr) { + if (strcmp(multi_cert_params->addr, "*") == 0) { + if (lookup->insert(multi_cert_params->addr, SSLCertContext(ctx, multi_cert_params->opt, keyblock)) >= 0) { + inserted = true; + lookup->ssl_default = ctx; + this->_set_handshake_callbacks(ctx); + } + } else { + IpEndpoint ep; + + if (ats_ip_pton(multi_cert_params->addr, &ep) == 0) { + QUICConfDebug("mapping '%s' to certificate %s", (const char *)multi_cert_params->addr, (const char *)certname); + if (lookup->insert(ep, SSLCertContext(ctx, multi_cert_params->opt, keyblock)) >= 0) { + inserted = true; + } + } else { + Error("'%s' is not a valid IPv4 or IPv6 address", (const char *)multi_cert_params->addr); + lookup->is_valid = false; + } + } + } + + // Insert additional mappings. Note that this maps multiple keys to the same value, so when + // this code is updated to reconfigure the SSL certificates, it will need some sort of + // refcounting or alternate way of avoiding double frees. + QUICConfDebug("importing SNI names from %s", (const char *)certname); + for (auto cert : cert_list) { + if (SSLMultiCertConfigLoader::index_certificate(lookup, SSLCertContext(ctx, multi_cert_params->opt), cert, certname)) { + inserted = true; + } + } + + if (inserted) { + if (SSLConfigParams::init_ssl_ctx_cb) { + SSLConfigParams::init_ssl_ctx_cb(ctx, true); + } + } + + if (!inserted) { + SSLReleaseContext(ctx); + ctx = nullptr; + } + + for (auto &i : cert_list) { + X509_free(i); + } + + return ctx; +} + +void +QUICMultiCertConfigLoader::_set_handshake_callbacks(SSL_CTX *ssl_ctx) +{ + SSL_CTX_set_cert_cb(ssl_ctx, QUIC::ssl_cert_cb, nullptr); + SSL_CTX_set_tlsext_servername_callback(ssl_ctx, QUIC::ssl_sni_cb); + + // Set client hello callback if needed + // SSL_CTX_set_client_hello_cb(ctx, QUIC::ssl_client_hello_cb, nullptr); +} diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index f40e012bec9..4ab237a9b1b 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -26,6 +26,8 @@ #include #include "ProxyConfig.h" +#include "P_SSLCertLookup.h" +#include "P_SSLUtils.h" class QUICConfigParams : public ConfigInfo { @@ -45,7 +47,6 @@ class QUICConfigParams : public ConfigInfo const char *client_supported_groups() const; const char *session_file() const; - SSL_CTX *server_ssl_ctx() const; SSL_CTX *client_ssl_ctx() const; // Transport Parameters @@ -101,8 +102,6 @@ class QUICConfigParams : public ConfigInfo char *_client_supported_groups = nullptr; char *_session_file = nullptr; - // TODO: integrate with SSLCertLookup or SNIConfigParams - SSL_CTX *_server_ssl_ctx = nullptr; SSL_CTX *_client_ssl_ctx = nullptr; // Transport Parameters @@ -156,3 +155,30 @@ class QUICConfig private: static int _config_id; }; + +class QUICCertConfig +{ +public: + static void startup(); + static void reconfigure(); + static SSLCertLookup *acquire(); + static void release(SSLCertLookup *lookup); + + using scoped_config = ConfigProcessor::scoped_config; + +private: + static int _config_id; +}; + +class QUICMultiCertConfigLoader : public SSLMultiCertConfigLoader +{ +public: + QUICMultiCertConfigLoader(const SSLConfigParams *p) : SSLMultiCertConfigLoader(p) {} + + virtual SSL_CTX *default_server_ssl_ctx() override; + virtual SSL_CTX *init_server_ssl_ctx(std::vector &cert_list, const SSLMultiCertConfigParams *multi_cert_params) override; + +private: + virtual SSL_CTX *_store_ssl_ctx(SSLCertLookup *lookup, const SSLMultiCertConfigParams *multi_cert_params) override; + virtual void _set_handshake_callbacks(SSL_CTX *ssl_ctx) override; +}; diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index 0520f3ebfae..611bddb1447 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -26,10 +26,14 @@ #include #include "P_SSLNextProtocolSet.h" + #include "QUICStats.h" #include "QUICConfig.h" #include "QUICConnection.h" +#define QUICGlobalDebug(fmt, ...) Debug("quic_global", fmt, ##__VA_ARGS__) +#define QUICGlobalQCDebug(qc, fmt, ...) Debug("quic_global", "[%s] " fmt, qc->cids().data(), ##__VA_ARGS__) + RecRawStatBlock *quic_rsb; int QUIC::ssl_quic_qc_index = -1; @@ -67,7 +71,7 @@ QUIC::ssl_client_new_session(SSL *ssl, SSL_SESSION *session) QUICConfig::scoped_config params; auto file = BIO_new_file(params->session_file(), "w"); if (file == nullptr) { - Debug("quic_global", "Could not write TLS session in %s", params->session_file()); + QUICGlobalDebug("Could not write TLS session in %s", params->session_file()); return 0; } @@ -76,6 +80,63 @@ QUIC::ssl_client_new_session(SSL *ssl, SSL_SESSION *session) return 0; } +int +QUIC::ssl_cert_cb(SSL *ssl, void * /*arg*/) +{ + SSL_CTX *ctx = nullptr; + SSLCertContext *cc = nullptr; + QUICCertConfig::scoped_config lookup; + const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + QUICConnection *qc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); + + if (servername == nullptr) { + servername = ""; + } + QUICGlobalQCDebug(qc, "SNI=%s", servername); + + // The incoming SSL_CTX is either the one mapped from the inbound IP address or the default one. If we + // don't find a name-based match at this point, we *do not* want to mess with the context because we've + // already made a best effort to find the best match. + if (likely(servername)) { + cc = lookup->find((char *)servername); + if (cc && cc->ctx) { + ctx = cc->ctx; + } + } + + // If there's no match on the server name, try to match on the peer address. + if (ctx == nullptr) { + QUICFiveTuple five_tuple = qc->five_tuple(); + IpEndpoint ip = five_tuple.destination(); + cc = lookup->find(ip); + + if (cc && cc->ctx) { + ctx = cc->ctx; + } + } + + bool found = true; + if (ctx != nullptr) { + SSL_set_SSL_CTX(ssl, ctx); + } else { + found = false; + } + + ctx = SSL_get_SSL_CTX(ssl); + + QUICGlobalQCDebug(qc, "%s SSL_CTX %p for requested name '%s'", found ? "found" : "using", ctx, servername); + + return 1; +} + +int +QUIC::ssl_sni_cb(SSL *ssl, int * /*ad*/, void * /*arg*/) +{ + // XXX: add SNIConfig support ? + // XXX: add TRANSPORT_BLIND_TUNNEL support ? + return 1; +} + void QUIC::_register_stats() { diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h index 4da21d16045..cd4ac546f2a 100644 --- a/iocore/net/quic/QUICGlobals.h +++ b/iocore/net/quic/QUICGlobals.h @@ -34,6 +34,8 @@ class QUIC static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen, void *); static int ssl_client_new_session(SSL *ssl, SSL_SESSION *session); + static int ssl_cert_cb(SSL *ssl, void *arg); + static int ssl_sni_cb(SSL *ssl, int *ad, void *arg); static int ssl_quic_qc_index; static int ssl_quic_tls_index; From aa107296e9f49d9c12b87845364df637e3f2f79f Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 1 Mar 2019 17:27:25 +0800 Subject: [PATCH 1180/1313] QUIC: Introduce base stream class --- iocore/net/quic/Mock.h | 2 +- iocore/net/quic/QUICStream.cc | 554 ++++++++++++------------ iocore/net/quic/QUICStream.h | 149 ++++--- iocore/net/quic/QUICStreamManager.cc | 5 +- iocore/net/quic/QUICStreamManager.h | 2 +- iocore/net/quic/test/test_QUICStream.cc | 25 +- 6 files changed, 390 insertions(+), 347 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 3fc56b70da9..7cabff5e1dd 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -430,7 +430,7 @@ class MockQUICStream : public QUICStream public: MockQUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data) - : QUICStream(rtt_provider, info, sid, recv_max_stream_data, send_max_stream_data) + : QUICStream(info, sid) { } diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index a398e012d73..516d83ffcfc 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -43,24 +43,10 @@ static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; -QUICStream::QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, - uint64_t recv_max_stream_data, uint64_t send_max_stream_data) - : VConnection(nullptr), - _connection_info(cinfo), - _id(sid), - _remote_flow_controller(send_max_stream_data, _id), - _local_flow_controller(rtt_provider, recv_max_stream_data, _id), - _flow_control_buffer_size(recv_max_stream_data), - _received_stream_frame_buffer(), - _state(nullptr, &this->_progress_vio, this, nullptr) +QUICStream::QUICStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid) + : VConnection(nullptr), _connection_info(cinfo), _id(sid), _received_stream_frame_buffer() { - SET_HANDLER(&QUICStream::state_stream_open); mutex = new_ProxyMutex(); - - QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), - this->_local_flow_controller.current_limit()); - QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), - this->_remote_flow_controller.current_limit()); } QUICStream::~QUICStream() @@ -101,8 +87,154 @@ QUICStream::final_offset() const return 0; } +void +QUICStream::_write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin) +{ + SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); + + uint64_t bytes_added = this->_read_vio.buffer.writer()->write(data, data_length); + + // Until receive FIN flag, keep nbytes INT64_MAX + if (fin && bytes_added == data_length) { + this->_read_vio.nbytes = offset + data_length; + } +} + +/** + * Replace existing event only if the new event is different than the inprogress event + */ +Event * +QUICStream::_send_tracked_event(Event *event, int send_event, VIO *vio) +{ + if (event != nullptr) { + if (event->callback_event != send_event) { + event->cancel(); + event = nullptr; + } + } + + if (event == nullptr) { + event = this_ethread()->schedule_imm(this, send_event, vio); + } + + return event; +} + +/** + * @brief Signal event to this->_read_vio.cont + */ +void +QUICStream::_signal_read_event() +{ + if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { + return; + } + MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread()); + + int event = this->_read_vio.ntodo() ? VC_EVENT_READ_READY : VC_EVENT_READ_COMPLETE; + + if (lock.is_locked()) { + this->_read_vio.cont->handleEvent(event, &this->_read_vio); + } else { + this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio); + } +} + +/** + * @brief Signal event to this->_write_vio.cont + */ +void +QUICStream::_signal_write_event() +{ + if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { + return; + } + MUTEX_TRY_LOCK(lock, this->_write_vio.mutex, this_ethread()); + + int event = this->_write_vio.ntodo() ? VC_EVENT_WRITE_READY : VC_EVENT_WRITE_COMPLETE; + + if (lock.is_locked()) { + this->_write_vio.cont->handleEvent(event, &this->_write_vio); + } else { + this_ethread()->schedule_imm(this->_write_vio.cont, event, &this->_write_vio); + } +} + +/** + * @brief Signal event to this->_write_vio.cont + */ +void +QUICStream::_signal_read_eos_event() +{ + if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { + return; + } + MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread()); + + int event = VC_EVENT_EOS; + + if (lock.is_locked()) { + this->_write_vio.cont->handleEvent(event, &this->_write_vio); + } else { + this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio); + } +} + +int64_t +QUICStream::_process_read_vio() +{ + if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { + return 0; + } + + // Pass through. Read operation is done by QUICStream::recv(const std::shared_ptr frame) + // TODO: 1. pop frame from _received_stream_frame_buffer + // 2. write data to _read_vio + + return 0; +} + +/** + * @brief Send STREAM DATA from _response_buffer + * @detail Call _signal_write_event() to indicate event upper layer + */ +int64_t +QUICStream::_process_write_vio() +{ + if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { + return 0; + } + + return 0; +} + +QUICOffset +QUICStream::reordered_bytes() const +{ + return this->_reordered_bytes; +} + +// +// QUICBidirectionalStream +// +QUICBidirectionalStream::QUICBidirectionalStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, + uint64_t recv_max_stream_data, uint64_t send_max_stream_data) + : QUICStream(cinfo, sid), + _remote_flow_controller(send_max_stream_data, _id), + _local_flow_controller(rtt_provider, recv_max_stream_data, _id), + _flow_control_buffer_size(recv_max_stream_data), + _state(nullptr, &this->_progress_vio, this, nullptr) +{ + SET_HANDLER(&QUICBidirectionalStream::state_stream_open); + + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), + this->_local_flow_controller.current_limit()); + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); +} + int -QUICStream::state_stream_open(int event, void *data) +QUICBidirectionalStream::state_stream_open(int event, void *data) { QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); QUICErrorUPtr error = nullptr; @@ -163,7 +295,7 @@ QUICStream::state_stream_open(int event, void *data) } int -QUICStream::state_stream_closed(int event, void *data) +QUICBidirectionalStream::state_stream_closed(int event, void *data) { QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); @@ -193,117 +325,28 @@ QUICStream::state_stream_closed(int event, void *data) return EVENT_DONE; } -// this->_read_vio.nbytes should be INT64_MAX until receive FIN flag -VIO * -QUICStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) -{ - if (buf) { - this->_read_vio.buffer.writer_for(buf); - } else { - this->_read_vio.buffer.clear(); - } - - this->_read_vio.mutex = c ? c->mutex : this->mutex; - this->_read_vio.cont = c; - this->_read_vio.nbytes = nbytes; - this->_read_vio.ndone = 0; - this->_read_vio.vc_server = this; - this->_read_vio.op = VIO::READ; - - this->_process_read_vio(); - this->_send_tracked_event(this->_read_event, VC_EVENT_READ_READY, &this->_read_vio); - - return &this->_read_vio; -} - -VIO * -QUICStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) -{ - if (buf) { - this->_write_vio.buffer.reader_for(buf); - } else { - this->_write_vio.buffer.clear(); - } - - this->_write_vio.mutex = c ? c->mutex : this->mutex; - this->_write_vio.cont = c; - this->_write_vio.nbytes = nbytes; - this->_write_vio.ndone = 0; - this->_write_vio.vc_server = this; - this->_write_vio.op = VIO::WRITE; - - this->_process_write_vio(); - this->_send_tracked_event(this->_write_event, VC_EVENT_WRITE_READY, &this->_write_vio); - - return &this->_write_vio; -} - -void -QUICStream::do_io_close(int lerrno) -{ - SET_HANDLER(&QUICStream::state_stream_closed); - - this->_read_vio.buffer.clear(); - this->_read_vio.nbytes = 0; - this->_read_vio.op = VIO::NONE; - this->_read_vio.cont = nullptr; - - this->_write_vio.buffer.clear(); - this->_write_vio.nbytes = 0; - this->_write_vio.op = VIO::NONE; - this->_write_vio.cont = nullptr; -} - -void -QUICStream::do_io_shutdown(ShutdownHowTo_t howto) -{ - ink_assert(false); // unimplemented yet - return; -} - -void -QUICStream::reenable(VIO *vio) +bool +QUICBidirectionalStream::is_transfer_goal_set() const { - if (vio->op == VIO::READ) { - QUICVStreamDebug("read_vio reenabled"); - - int64_t len = this->_process_read_vio(); - if (len > 0) { - this->_signal_read_event(); - } - } else if (vio->op == VIO::WRITE) { - QUICVStreamDebug("write_vio reenabled"); - - int64_t len = this->_process_write_vio(); - if (len > 0) { - this->_signal_write_event(); - } - } + return this->_received_stream_frame_buffer.is_transfer_goal_set(); } -void -QUICStream::_write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin) +uint64_t +QUICBidirectionalStream::transfer_progress() const { - SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); - - uint64_t bytes_added = this->_read_vio.buffer.writer()->write(data, data_length); - - // Until receive FIN flag, keep nbytes INT64_MAX - if (fin && bytes_added == data_length) { - this->_read_vio.nbytes = offset + data_length; - } + return this->_received_stream_frame_buffer.transfer_progress(); } -void -QUICStream::on_read() +uint64_t +QUICBidirectionalStream::transfer_goal() const { - this->_state.update_on_read(); + return this->_received_stream_frame_buffer.transfer_goal(); } -void -QUICStream::on_eos() +bool +QUICBidirectionalStream::is_cancelled() const { - this->_state.update_on_eos(); + return this->_is_reset_complete; } /** @@ -313,7 +356,7 @@ QUICStream::on_eos() * which is called by application via do_io_read() or reenable(). */ QUICConnectionErrorUPtr -QUICStream::recv(const QUICStreamFrame &frame) +QUICBidirectionalStream::recv(const QUICStreamFrame &frame) { ink_assert(_id == frame.stream_id()); ink_assert(this->_read_vio.op == VIO::READ); @@ -372,7 +415,7 @@ QUICStream::recv(const QUICStreamFrame &frame) } QUICConnectionErrorUPtr -QUICStream::recv(const QUICMaxStreamDataFrame &frame) +QUICBidirectionalStream::recv(const QUICMaxStreamDataFrame &frame) { this->_remote_flow_controller.forward_limit(frame.maximum_stream_data()); QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), @@ -387,14 +430,21 @@ QUICStream::recv(const QUICMaxStreamDataFrame &frame) } QUICConnectionErrorUPtr -QUICStream::recv(const QUICStreamDataBlockedFrame &frame) +QUICBidirectionalStream::recv(const QUICCryptoFrame &frame) +{ + ink_assert(!"should not happen"); + return nullptr; +} + +QUICConnectionErrorUPtr +QUICBidirectionalStream::recv(const QUICStreamDataBlockedFrame &frame) { // STREAM_DATA_BLOCKED frames are for debugging. Nothing to do here. return nullptr; } QUICConnectionErrorUPtr -QUICStream::recv(const QUICStopSendingFrame &frame) +QUICBidirectionalStream::recv(const QUICStopSendingFrame &frame) { this->_state.update_with_receiving_frame(frame); this->_reset_reason = QUICStreamErrorUPtr(new QUICStreamError(this, QUIC_APP_ERROR_CODE_STOPPING)); @@ -403,22 +453,110 @@ QUICStream::recv(const QUICStopSendingFrame &frame) } QUICConnectionErrorUPtr -QUICStream::recv(const QUICRstStreamFrame &frame) +QUICBidirectionalStream::recv(const QUICRstStreamFrame &frame) { this->_state.update_with_receiving_frame(frame); this->_signal_read_eos_event(); return nullptr; } +// this->_read_vio.nbytes should be INT64_MAX until receive FIN flag +VIO * +QUICBidirectionalStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + if (buf) { + this->_read_vio.buffer.writer_for(buf); + } else { + this->_read_vio.buffer.clear(); + } + + this->_read_vio.mutex = c ? c->mutex : this->mutex; + this->_read_vio.cont = c; + this->_read_vio.nbytes = nbytes; + this->_read_vio.ndone = 0; + this->_read_vio.vc_server = this; + this->_read_vio.op = VIO::READ; + + this->_process_read_vio(); + this->_send_tracked_event(this->_read_event, VC_EVENT_READ_READY, &this->_read_vio); + + return &this->_read_vio; +} + +VIO * +QUICBidirectionalStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +{ + if (buf) { + this->_write_vio.buffer.reader_for(buf); + } else { + this->_write_vio.buffer.clear(); + } + + this->_write_vio.mutex = c ? c->mutex : this->mutex; + this->_write_vio.cont = c; + this->_write_vio.nbytes = nbytes; + this->_write_vio.ndone = 0; + this->_write_vio.vc_server = this; + this->_write_vio.op = VIO::WRITE; + + this->_process_write_vio(); + this->_send_tracked_event(this->_write_event, VC_EVENT_WRITE_READY, &this->_write_vio); + + return &this->_write_vio; +} + +void +QUICBidirectionalStream::do_io_close(int lerrno) +{ + SET_HANDLER(&QUICBidirectionalStream::state_stream_closed); + + this->_read_vio.buffer.clear(); + this->_read_vio.nbytes = 0; + this->_read_vio.op = VIO::NONE; + this->_read_vio.cont = nullptr; + + this->_write_vio.buffer.clear(); + this->_write_vio.nbytes = 0; + this->_write_vio.op = VIO::NONE; + this->_write_vio.cont = nullptr; +} + +void +QUICBidirectionalStream::do_io_shutdown(ShutdownHowTo_t howto) +{ + ink_assert(false); // unimplemented yet + return; +} + +void +QUICBidirectionalStream::reenable(VIO *vio) +{ + if (vio->op == VIO::READ) { + QUICVStreamDebug("read_vio reenabled"); + + int64_t len = this->_process_read_vio(); + if (len > 0) { + this->_signal_read_event(); + } + } else if (vio->op == VIO::WRITE) { + QUICVStreamDebug("write_vio reenabled"); + + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); + } + } +} + bool -QUICStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) +QUICBidirectionalStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { return this->_local_flow_controller.will_generate_frame(level, timestamp) || (this->_write_vio.get_reader()->read_avail() > 0); } QUICFrame * -QUICStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, - ink_hrtime timestamp) +QUICBidirectionalStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size, ink_hrtime timestamp) { SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); @@ -544,7 +682,7 @@ QUICStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t con } void -QUICStream::_records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame) +QUICBidirectionalStream::_records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame) { QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = frame.type(); @@ -558,7 +696,7 @@ QUICStream::_records_stream_frame(QUICEncryptionLevel level, const QUICStreamFra } void -QUICStream::_records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame) +QUICBidirectionalStream::_records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame) { QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = frame.type(); @@ -570,7 +708,7 @@ QUICStream::_records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstSt } void -QUICStream::_records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame) +QUICBidirectionalStream::_records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame) { QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); info->type = frame.type(); @@ -581,7 +719,7 @@ QUICStream::_records_stop_sending_frame(QUICEncryptionLevel level, const QUICSto } void -QUICStream::_on_frame_acked(QUICFrameInformationUPtr &info) +QUICBidirectionalStream::_on_frame_acked(QUICFrameInformationUPtr &info) { StreamFrameInfo *frame_info = nullptr; switch (info->type) { @@ -604,7 +742,7 @@ QUICStream::_on_frame_acked(QUICFrameInformationUPtr &info) } void -QUICStream::_on_frame_lost(QUICFrameInformationUPtr &info) +QUICBidirectionalStream::_on_frame_lost(QUICFrameInformationUPtr &info) { switch (info->type) { case QUICFrameType::RESET_STREAM: @@ -627,174 +765,42 @@ QUICStream::_on_frame_lost(QUICFrameInformationUPtr &info) } } -/** - * Replace existing event only if the new event is different than the inprogress event - */ -Event * -QUICStream::_send_tracked_event(Event *event, int send_event, VIO *vio) -{ - if (event != nullptr) { - if (event->callback_event != send_event) { - event->cancel(); - event = nullptr; - } - } - - if (event == nullptr) { - event = this_ethread()->schedule_imm(this, send_event, vio); - } - - return event; -} - -/** - * @brief Signal event to this->_read_vio.cont - */ -void -QUICStream::_signal_read_event() -{ - if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { - return; - } - MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread()); - - int event = this->_read_vio.ntodo() ? VC_EVENT_READ_READY : VC_EVENT_READ_COMPLETE; - - if (lock.is_locked()) { - this->_read_vio.cont->handleEvent(event, &this->_read_vio); - } else { - this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio); - } - - QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); -} - -/** - * @brief Signal event to this->_write_vio.cont - */ void -QUICStream::_signal_write_event() +QUICBidirectionalStream::stop_sending(QUICStreamErrorUPtr error) { - if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { - return; - } - MUTEX_TRY_LOCK(lock, this->_write_vio.mutex, this_ethread()); - - int event = this->_write_vio.ntodo() ? VC_EVENT_WRITE_READY : VC_EVENT_WRITE_COMPLETE; - - if (lock.is_locked()) { - this->_write_vio.cont->handleEvent(event, &this->_write_vio); - } else { - this_ethread()->schedule_imm(this->_write_vio.cont, event, &this->_write_vio); - } - - QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); + this->_stop_sending_reason = std::move(error); } -/** - * @brief Signal event to this->_write_vio.cont - */ void -QUICStream::_signal_read_eos_event() +QUICBidirectionalStream::reset(QUICStreamErrorUPtr error) { - if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { - return; - } - MUTEX_TRY_LOCK(lock, this->_read_vio.mutex, this_ethread()); - - int event = VC_EVENT_EOS; - - if (lock.is_locked()) { - this->_write_vio.cont->handleEvent(event, &this->_write_vio); - } else { - this_ethread()->schedule_imm(this->_read_vio.cont, event, &this->_read_vio); - } - - QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); -} - -int64_t -QUICStream::_process_read_vio() -{ - if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { - return 0; - } - - // Pass through. Read operation is done by QUICStream::recv(const std::shared_ptr frame) - // TODO: 1. pop frame from _received_stream_frame_buffer - // 2. write data to _read_vio - - return 0; -} - -/** - * @brief Send STREAM DATA from _response_buffer - * @detail Call _signal_write_event() to indicate event upper layer - */ -int64_t -QUICStream::_process_write_vio() -{ - if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { - return 0; - } - - return 0; + this->_reset_reason = std::move(error); } void -QUICStream::stop_sending(QUICStreamErrorUPtr error) +QUICBidirectionalStream::on_read() { - this->_stop_sending_reason = std::move(error); + this->_state.update_on_read(); } void -QUICStream::reset(QUICStreamErrorUPtr error) -{ - this->_reset_reason = std::move(error); -} - -QUICOffset -QUICStream::reordered_bytes() const +QUICBidirectionalStream::on_eos() { - return this->_reordered_bytes; + this->_state.update_on_eos(); } QUICOffset -QUICStream::largest_offset_received() const +QUICBidirectionalStream::largest_offset_received() const { return this->_local_flow_controller.current_offset(); } QUICOffset -QUICStream::largest_offset_sent() const +QUICBidirectionalStream::largest_offset_sent() const { return this->_remote_flow_controller.current_offset(); } -bool -QUICStream::is_transfer_goal_set() const -{ - return this->_received_stream_frame_buffer.is_transfer_goal_set(); -} - -uint64_t -QUICStream::transfer_progress() const -{ - return this->_received_stream_frame_buffer.transfer_progress(); -} - -uint64_t -QUICStream::transfer_goal() const -{ - return this->_received_stream_frame_buffer.transfer_goal(); -} - -bool -QUICStream::is_cancelled() const -{ - return this->_is_reset_complete; -} - // // QUICCryptoStream // diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index b40e47159b1..ac57b4fb37b 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -39,67 +39,39 @@ * @brief QUIC Stream * TODO: This is similar to Http2Stream. Need to think some integration. */ -class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTransferProgressProvider, public QUICFrameRetransmitter +class QUICStream : public VConnection, public QUICFrameGenerator, public QUICFrameRetransmitter { public: - QUICStream() - : VConnection(nullptr), - _remote_flow_controller(0, 0), - _local_flow_controller(nullptr, 0, 0), - _received_stream_frame_buffer(), - _state(nullptr, nullptr, nullptr, nullptr) - { - } - QUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t recv_max_stream_data, - uint64_t send_max_stream_data); - ~QUICStream(); - - int state_stream_open(int event, void *data); - int state_stream_closed(int event, void *data); + QUICStream() : VConnection(nullptr), _received_stream_frame_buffer() {} + QUICStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid); + virtual ~QUICStream(); QUICStreamId id() const; const QUICConnectionInfoProvider *connection_info() const; bool is_bidirectional() const; QUICOffset final_offset() const; - // Implement VConnection Interface. - VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; - VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; - void do_io_close(int lerrno = -1) override; - void do_io_shutdown(ShutdownHowTo_t howto) override; - void reenable(VIO *vio) override; - /* * QUICApplication need to call one of these functions when it process VC_EVENT_* */ - void on_read(); - void on_eos(); + virtual void on_read() = 0; + virtual void on_eos() = 0; - QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame); - QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame); - QUICConnectionErrorUPtr recv(const QUICStreamDataBlockedFrame &frame); - QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame); - QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame); - - void stop_sending(QUICStreamErrorUPtr error); - void reset(QUICStreamErrorUPtr error); + virtual QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame) = 0; + virtual QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame) = 0; + virtual QUICConnectionErrorUPtr recv(const QUICStreamDataBlockedFrame &frame) = 0; + virtual QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame) = 0; + virtual QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame) = 0; + virtual QUICConnectionErrorUPtr recv(const QUICCryptoFrame &frame) = 0; QUICOffset reordered_bytes() const; - QUICOffset largest_offset_received() const; - QUICOffset largest_offset_sent() const; + virtual QUICOffset largest_offset_received() const = 0; + virtual QUICOffset largest_offset_sent() const = 0; - LINK(QUICStream, link); - - // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, - ink_hrtime timestamp) override; + virtual void stop_sending(QUICStreamErrorUPtr error) = 0; + virtual void reset(QUICStreamErrorUPtr error) = 0; - // QUICTransferProgressProvider - bool is_transfer_goal_set() const override; - uint64_t transfer_progress() const override; - uint64_t transfer_goal() const override; - bool is_cancelled() const override; + LINK(QUICStream, link); protected: virtual int64_t _process_read_vio(); @@ -110,29 +82,14 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra Event *_send_tracked_event(Event *, int, VIO *); void _write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin); - void _records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame); - void _records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame); - void _records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame); - - QUICStreamErrorUPtr _reset_reason = nullptr; - bool _is_reset_sent = false; - QUICStreamErrorUPtr _stop_sending_reason = nullptr; - bool _is_stop_sending_sent = false; - QUICConnectionInfoProvider *_connection_info = nullptr; QUICStreamId _id = 0; QUICOffset _send_offset = 0; QUICOffset _reordered_bytes = 0; - QUICRemoteStreamFlowController _remote_flow_controller; - QUICLocalStreamFlowController _local_flow_controller; - uint64_t _flow_control_buffer_size = 1024; - VIO _read_vio; VIO _write_vio; - QUICTransferProgressProviderVIO _progress_vio = {this->_read_vio}; - Event *_read_event = nullptr; Event *_write_event = nullptr; @@ -143,12 +100,84 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICTra // TODO: Consider to replace with ts/RbTree.h or other data structure QUICIncomingStreamFrameBuffer _received_stream_frame_buffer; + // FIXME: should be removed + virtual void update() = 0; +}; + +class QUICBidirectionalStream : public QUICStream, public QUICTransferProgressProvider +{ +public: + QUICBidirectionalStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, + uint64_t recv_max_stream_data, uint64_t send_max_stream_data); + QUICBidirectionalStream() + : _remote_flow_controller(0, 0), _local_flow_controller(nullptr, 0, 0), _state(nullptr, nullptr, nullptr, nullptr) + { + } + + int state_stream_open(int event, void *data); + int state_stream_closed(int event, void *data); + + // QUICFrameGenerator + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; + + virtual QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame) override; + virtual QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame) override; + virtual QUICConnectionErrorUPtr recv(const QUICStreamDataBlockedFrame &frame) override; + virtual QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame) override; + virtual QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame) override; + virtual QUICConnectionErrorUPtr recv(const QUICCryptoFrame &frame) override; + + // Implement VConnection Interface. + VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; + VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; + void do_io_close(int lerrno = -1) override; + void do_io_shutdown(ShutdownHowTo_t howto) override; + void reenable(VIO *vio) override; + + void stop_sending(QUICStreamErrorUPtr error) override; + void reset(QUICStreamErrorUPtr error) override; + + // QUICTransferProgressProvider + bool is_transfer_goal_set() const override; + uint64_t transfer_progress() const override; + uint64_t transfer_goal() const override; + bool is_cancelled() const override; + + /* + * QUICApplication need to call one of these functions when it process VC_EVENT_* + */ + virtual void on_read() override; + virtual void on_eos() override; + + QUICOffset largest_offset_received() const override; + QUICOffset largest_offset_sent() const override; + +private: + QUICStreamErrorUPtr _reset_reason = nullptr; + bool _is_reset_sent = false; + QUICStreamErrorUPtr _stop_sending_reason = nullptr; + bool _is_stop_sending_sent = false; + + QUICTransferProgressProviderVIO _progress_vio = {this->_read_vio}; + + QUICRemoteStreamFlowController _remote_flow_controller; + QUICLocalStreamFlowController _local_flow_controller; + uint64_t _flow_control_buffer_size = 1024; + // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState QUICBidirectionalStreamStateMachine _state; + void _records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame); + void _records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame); + void _records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame); + // QUICFrameGenerator void _on_frame_acked(QUICFrameInformationUPtr &info) override; void _on_frame_lost(QUICFrameInformationUPtr &info) override; + + virtual void update(){}; }; /** diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 30d043dead2..bc1d641248f 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -30,7 +30,7 @@ static constexpr char tag[] = "quic_stream_manager"; static constexpr QUICStreamId QUIC_STREAM_TYPES = 4; ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); -ClassAllocator quicStreamAllocator("quicStreamAllocator"); +ClassAllocator quicStreamAllocator("quicStreamAllocator"); QUICStreamManager::QUICStreamManager(QUICConnectionInfoProvider *info, QUICRTTProvider *rtt_provider, QUICApplicationMap *app_map) : _info(info), _rtt_provider(rtt_provider), _app_map(app_map) @@ -324,7 +324,8 @@ QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) // TODO Free the stream somewhere stream = THREAD_ALLOC(quicStreamAllocator, this_ethread()); - new (stream) QUICStream(this->_rtt_provider, this->_info, stream_id, local_max_stream_data, remote_max_stream_data); + new (stream) + QUICBidirectionalStream(this->_rtt_provider, this->_info, stream_id, local_max_stream_data, remote_max_stream_data); this->stream_list.push(stream); } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index eeabf1d9417..6f0542967db 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -30,7 +30,7 @@ #include "QUICFrame.h" #include "QUICLossDetector.h" -extern ClassAllocator quicStreamAllocator; +extern ClassAllocator quicStreamAllocator; class QUICTransportParameters; diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index e18eaf1e965..468e73cfab8 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -85,7 +85,8 @@ TEST_CASE("QUICStream", "[quic]") MockQUICRTTProvider rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; - std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, 1024, 1024)); + std::unique_ptr stream( + new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, 1024, 1024)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); stream->recv(frame_1); @@ -112,7 +113,8 @@ TEST_CASE("QUICStream", "[quic]") MockQUICRTTProvider rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; - std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); + std::unique_ptr stream( + new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); stream->recv(frame_8); @@ -139,7 +141,8 @@ TEST_CASE("QUICStream", "[quic]") MockQUICRTTProvider rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; - std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); + std::unique_ptr stream( + new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); stream->recv(frame_8); @@ -169,7 +172,8 @@ TEST_CASE("QUICStream", "[quic]") MockQUICRTTProvider rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; - std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, 4096, 4096)); + std::unique_ptr stream( + new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, 4096, 4096)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); Ptr block = make_ptr(new_IOBufferBlock()); @@ -209,7 +213,8 @@ TEST_CASE("QUICStream", "[quic]") MockQUICRTTProvider rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; - std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, 4096, 4096)); + std::unique_ptr stream( + new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, 4096, 4096)); SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); MockContinuation mock_cont(stream->mutex); @@ -304,8 +309,8 @@ TEST_CASE("QUICStream", "[quic]") MockQUICRTTProvider rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; - std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); - SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); + std::unique_ptr stream(new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, + UINT64_MAX, UINT64_MAX)); SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); MockContinuation mock_cont(stream->mutex); stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); @@ -347,7 +352,8 @@ TEST_CASE("QUICStream", "[quic]") MockQUICRTTProvider rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; - std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); + std::unique_ptr stream( + new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); MockContinuation mock_cont(stream->mutex); @@ -377,7 +383,8 @@ TEST_CASE("QUICStream", "[quic]") MockQUICRTTProvider rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; - std::unique_ptr stream(new QUICStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); + std::unique_ptr stream( + new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); MockContinuation mock_cont(stream->mutex); From b0cd800ef0ac1a67c464b6ac88fcb8cc5718daf5 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 4 Mar 2019 09:54:18 +0800 Subject: [PATCH 1181/1313] QUIC: Use QUICStream as base class --- iocore/net/quic/QUICStream.cc | 124 ++++++++++++++++++++++++++++++++-- iocore/net/quic/QUICStream.h | 49 ++++++++------ 2 files changed, 144 insertions(+), 29 deletions(-) diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 516d83ffcfc..dd377055a47 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -214,6 +214,42 @@ QUICStream::reordered_bytes() const return this->_reordered_bytes; } +QUICConnectionErrorUPtr +QUICStream::recv(const QUICStreamFrame &frame) +{ + return nullptr; +} + +QUICConnectionErrorUPtr +QUICStream::recv(const QUICMaxStreamDataFrame &frame) +{ + return nullptr; +} + +QUICConnectionErrorUPtr +QUICStream::recv(const QUICStreamDataBlockedFrame &frame) +{ + return nullptr; +} + +QUICConnectionErrorUPtr +QUICStream::recv(const QUICStopSendingFrame &frame) +{ + return nullptr; +} + +QUICConnectionErrorUPtr +QUICStream::recv(const QUICRstStreamFrame &frame) +{ + return nullptr; +} + +QUICConnectionErrorUPtr +QUICStream::recv(const QUICCryptoFrame &frame) +{ + return nullptr; +} + // // QUICBidirectionalStream // @@ -429,17 +465,11 @@ QUICBidirectionalStream::recv(const QUICMaxStreamDataFrame &frame) return nullptr; } -QUICConnectionErrorUPtr -QUICBidirectionalStream::recv(const QUICCryptoFrame &frame) -{ - ink_assert(!"should not happen"); - return nullptr; -} - QUICConnectionErrorUPtr QUICBidirectionalStream::recv(const QUICStreamDataBlockedFrame &frame) { // STREAM_DATA_BLOCKED frames are for debugging. Nothing to do here. + QUICStreamFCDebug("[REMOTE] blocked %" PRIu64, frame.offset()); return nullptr; } @@ -953,3 +983,83 @@ QUICCryptoStream::_records_crypto_frame(QUICEncryptionLevel level, const QUICCry crypto_frame_info->block = frame.data(); this->_records_frame(frame.id(), std::move(info)); } + +QUICOffset +QUICCryptoStream::largest_offset_received() const +{ + // TODO: + ink_assert(!"unsupported"); + return 0; +} + +QUICOffset +QUICCryptoStream::largest_offset_sent() const +{ + // TODO + ink_assert(!"unsupported"); + return 0; +} + +void +QUICCryptoStream::stop_sending(QUICStreamErrorUPtr error) +{ + // TODO + ink_assert(!"unsupported"); + return; +} + +void +QUICCryptoStream::reset(QUICStreamErrorUPtr error) +{ + // TODO + ink_assert(!"unsupported"); + return; +} + +void +QUICCryptoStream::on_eos() +{ + return; +} + +void +QUICCryptoStream::on_read() +{ + return; +} + +// Implement VConnection Interface. +VIO * +QUICCryptoStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + ink_assert(!"unsupported"); + return nullptr; +} + +VIO * +QUICCryptoStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +{ + ink_assert(!"unsupported"); + return nullptr; +} + +void +QUICCryptoStream::do_io_close(int lerrno) +{ + ink_assert(!"unsupported"); + return; +} + +void +QUICCryptoStream::do_io_shutdown(ShutdownHowTo_t howto) +{ + ink_assert(!"unsupported"); + return; +} + +void +QUICCryptoStream::reenable(VIO *vio) +{ + ink_assert(!"unsupported"); + return; +} diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index ac57b4fb37b..7f41ebd6598 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -42,7 +42,7 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICFrameRetransmitter { public: - QUICStream() : VConnection(nullptr), _received_stream_frame_buffer() {} + QUICStream() : VConnection(nullptr) {} QUICStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid); virtual ~QUICStream(); @@ -57,12 +57,12 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICFra virtual void on_read() = 0; virtual void on_eos() = 0; - virtual QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame) = 0; - virtual QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame) = 0; - virtual QUICConnectionErrorUPtr recv(const QUICStreamDataBlockedFrame &frame) = 0; - virtual QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame) = 0; - virtual QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame) = 0; - virtual QUICConnectionErrorUPtr recv(const QUICCryptoFrame &frame) = 0; + virtual QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame); + virtual QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame); + virtual QUICConnectionErrorUPtr recv(const QUICStreamDataBlockedFrame &frame); + virtual QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame); + virtual QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame); + virtual QUICConnectionErrorUPtr recv(const QUICCryptoFrame &frame); QUICOffset reordered_bytes() const; virtual QUICOffset largest_offset_received() const = 0; @@ -93,15 +93,9 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICFra Event *_read_event = nullptr; Event *_write_event = nullptr; - bool _is_transfer_complete = false; - bool _is_reset_complete = false; - // Fragments of received STREAM frame (offset is unmatched) // TODO: Consider to replace with ts/RbTree.h or other data structure QUICIncomingStreamFrameBuffer _received_stream_frame_buffer; - - // FIXME: should be removed - virtual void update() = 0; }; class QUICBidirectionalStream : public QUICStream, public QUICTransferProgressProvider @@ -127,7 +121,6 @@ class QUICBidirectionalStream : public QUICStream, public QUICTransferProgressPr virtual QUICConnectionErrorUPtr recv(const QUICStreamDataBlockedFrame &frame) override; virtual QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame) override; virtual QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame) override; - virtual QUICConnectionErrorUPtr recv(const QUICCryptoFrame &frame) override; // Implement VConnection Interface. VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; @@ -160,6 +153,9 @@ class QUICBidirectionalStream : public QUICStream, public QUICTransferProgressPr QUICStreamErrorUPtr _stop_sending_reason = nullptr; bool _is_stop_sending_sent = false; + bool _is_transfer_complete = false; + bool _is_reset_complete = false; + QUICTransferProgressProviderVIO _progress_vio = {this->_read_vio}; QUICRemoteStreamFlowController _remote_flow_controller; @@ -176,8 +172,6 @@ class QUICBidirectionalStream : public QUICStream, public QUICTransferProgressPr // QUICFrameGenerator void _on_frame_acked(QUICFrameInformationUPtr &info) override; void _on_frame_lost(QUICFrameInformationUPtr &info) override; - - virtual void update(){}; }; /** @@ -188,7 +182,7 @@ class QUICBidirectionalStream : public QUICStream, public QUICTransferProgressPr * - no flow control * - no state (never closed) */ -class QUICCryptoStream : public QUICFrameGenerator, public QUICFrameRetransmitter +class QUICCryptoStream : public QUICStream { public: QUICCryptoStream(); @@ -201,16 +195,27 @@ class QUICCryptoStream : public QUICFrameGenerator, public QUICFrameRetransmitte void reset_send_offset(); void reset_recv_offset(); - QUICConnectionErrorUPtr recv(const QUICCryptoFrame &frame); + QUICConnectionErrorUPtr recv(const QUICCryptoFrame &frame) override; + int64_t read_avail(); int64_t read(uint8_t *buf, int64_t len); int64_t write(const uint8_t *buf, int64_t len); - void stop_sending(QUICStreamErrorUPtr error); - void reset(QUICStreamErrorUPtr error); + // Implement VConnection Interface. + VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; + VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; + void do_io_close(int lerrno = -1) override; + void do_io_shutdown(ShutdownHowTo_t howto) override; + void reenable(VIO *vio) override; + + void stop_sending(QUICStreamErrorUPtr error) override; + void reset(QUICStreamErrorUPtr error) override; + + QUICOffset largest_offset_received() const override; + QUICOffset largest_offset_sent() const override; - QUICOffset largest_offset_received(); - QUICOffset largest_offset_sent(); + void on_eos() override; + void on_read() override; LINK(QUICStream, link); From f6972d47db80a7e1a4b71f8b449abca43709d4b9 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 4 Mar 2019 14:49:45 +0800 Subject: [PATCH 1182/1313] QUIC: Introduce QUICStreamVConnection to process VIO --- iocore/net/quic/QUICApplication.cc | 30 ++--- iocore/net/quic/QUICApplication.h | 12 +- iocore/net/quic/QUICStream.cc | 168 +++++++++++---------------- iocore/net/quic/QUICStream.h | 53 +++++---- iocore/net/quic/QUICStreamManager.cc | 34 +++--- iocore/net/quic/QUICStreamManager.h | 6 +- 6 files changed, 141 insertions(+), 162 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 9e533be55f4..9b02b8caa74 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -27,14 +27,14 @@ static constexpr char tag_stream_io[] = "quic_stream_io"; static constexpr char tag_app[] = "quic_app"; -#define QUICStreamIODebug(fmt, ...) \ - Debug(tag_stream_io, "[%s] [%" PRIu64 "] " fmt, this->_stream->connection_info()->cids().data(), this->_stream->id(), \ +#define QUICStreamIODebug(fmt, ...) \ + Debug(tag_stream_io, "[%s] [%" PRIu64 "] " fmt, this->_stream_vc->connection_info()->cids().data(), this->_stream_vc->id(), \ ##__VA_ARGS__) // // QUICStreamIO // -QUICStreamIO::QUICStreamIO(QUICApplication *app, QUICStream *stream) : _stream(stream) +QUICStreamIO::QUICStreamIO(QUICApplication *app, QUICStreamVConnection *stream_vc) : _stream_vc(stream_vc) { this->_read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); this->_write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); @@ -42,8 +42,8 @@ QUICStreamIO::QUICStreamIO(QUICApplication *app, QUICStream *stream) : _stream(s this->_read_buffer_reader = this->_read_buffer->alloc_reader(); this->_write_buffer_reader = this->_write_buffer->alloc_reader(); - this->_read_vio = stream->do_io_read(app, INT64_MAX, this->_read_buffer); - this->_write_vio = stream->do_io_write(app, INT64_MAX, this->_write_buffer_reader); + this->_read_vio = stream_vc->do_io_read(app, INT64_MAX, this->_read_buffer); + this->_write_vio = stream_vc->do_io_write(app, INT64_MAX, this->_write_buffer_reader); } QUICStreamIO::~QUICStreamIO() @@ -56,13 +56,13 @@ QUICStreamIO::~QUICStreamIO() uint32_t QUICStreamIO::stream_id() const { - return this->_stream->id(); + return this->_stream_vc->id(); } bool QUICStreamIO::is_bidirectional() const { - return this->_stream->is_bidirectional(); + return this->_stream_vc->is_bidirectional(); } int64_t @@ -83,7 +83,7 @@ QUICStreamIO::read(uint8_t *buf, int64_t len) this->_read_vio->ndone += nread; } - this->_stream->on_read(); + this->_stream_vc->on_read(); return nread; } @@ -98,7 +98,7 @@ void QUICStreamIO::consume(int64_t len) { this->_read_buffer_reader->consume(len); - this->_stream->on_read(); + this->_stream_vc->on_read(); } bool @@ -194,12 +194,12 @@ QUICApplication::~QUICApplication() // @brief Bind stream and application void -QUICApplication::set_stream(QUICStream *stream, QUICStreamIO *stream_io) +QUICApplication::set_stream(QUICStreamVConnection *stream_vc, QUICStreamIO *stream_io) { if (stream_io == nullptr) { - stream_io = new QUICStreamIO(this, stream); + stream_io = new QUICStreamIO(this, stream_vc); } - this->_stream_map.insert(std::make_pair(stream->id(), stream_io)); + this->_stream_map.insert(std::make_pair(stream_vc->id(), stream_io)); } // @brief Bind stream and application @@ -210,7 +210,7 @@ QUICApplication::set_stream(QUICStreamIO *stream_io) } bool -QUICApplication::is_stream_set(QUICStream *stream) +QUICApplication::is_stream_set(QUICStreamVConnection *stream) { auto result = this->_stream_map.find(stream->id()); @@ -218,7 +218,7 @@ QUICApplication::is_stream_set(QUICStream *stream) } void -QUICApplication::reenable(QUICStream *stream) +QUICApplication::reenable(QUICStreamVConnection *stream) { QUICStreamIO *stream_io = this->_find_stream_io(stream->id()); if (stream_io) { @@ -232,7 +232,7 @@ QUICApplication::reenable(QUICStream *stream) } void -QUICApplication::unset_stream(QUICStream *stream) +QUICApplication::unset_stream(QUICStreamVConnection *stream) { QUICStreamIO *stream_io = this->_find_stream_io(stream->id()); if (stream_io) { diff --git a/iocore/net/quic/QUICApplication.h b/iocore/net/quic/QUICApplication.h index 8ebd9ccc8b1..dd6d52489bd 100644 --- a/iocore/net/quic/QUICApplication.h +++ b/iocore/net/quic/QUICApplication.h @@ -37,7 +37,7 @@ class QUICApplication; class QUICStreamIO { public: - QUICStreamIO(QUICApplication *app, QUICStream *stream); + QUICStreamIO(QUICApplication *app, QUICStreamVConnection *stream); virtual ~QUICStreamIO(); uint32_t stream_id() const; @@ -63,7 +63,7 @@ class QUICStreamIO IOBufferReader *_write_buffer_reader = nullptr; private: - QUICStream *_stream = nullptr; + QUICStreamVConnection *_stream_vc = nullptr; VIO *_read_vio = nullptr; VIO *_write_vio = nullptr; @@ -83,11 +83,11 @@ class QUICApplication : public Continuation QUICApplication(QUICConnection *qc); virtual ~QUICApplication(); - void set_stream(QUICStream *stream, QUICStreamIO *stream_io = nullptr); + void set_stream(QUICStreamVConnection *stream_vc, QUICStreamIO *stream_io = nullptr); void set_stream(QUICStreamIO *stream_io); - bool is_stream_set(QUICStream *stream); - void reenable(QUICStream *stream); - void unset_stream(QUICStream *stream); + bool is_stream_set(QUICStreamVConnection *stream_vc); + void reenable(QUICStreamVConnection *stream_vc); + void unset_stream(QUICStreamVConnection *stream_vc); protected: QUICStreamIO *_find_stream_io(QUICStreamId id); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index dd377055a47..1e977b7275f 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -44,23 +44,11 @@ static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; QUICStream::QUICStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid) - : VConnection(nullptr), _connection_info(cinfo), _id(sid), _received_stream_frame_buffer() + : _connection_info(cinfo), _id(sid), _received_stream_frame_buffer() { - mutex = new_ProxyMutex(); } -QUICStream::~QUICStream() -{ - if (this->_read_event) { - this->_read_event->cancel(); - this->_read_event = nullptr; - } - - if (this->_write_event) { - this->_write_event->cancel(); - this->_write_event = nullptr; - } -} +QUICStream::~QUICStream() {} QUICStreamId QUICStream::id() const @@ -87,8 +75,66 @@ QUICStream::final_offset() const return 0; } +QUICOffset +QUICStream::reordered_bytes() const +{ + return this->_reordered_bytes; +} + +QUICConnectionErrorUPtr +QUICStream::recv(const QUICStreamFrame &frame) +{ + return nullptr; +} + +QUICConnectionErrorUPtr +QUICStream::recv(const QUICMaxStreamDataFrame &frame) +{ + return nullptr; +} + +QUICConnectionErrorUPtr +QUICStream::recv(const QUICStreamDataBlockedFrame &frame) +{ + return nullptr; +} + +QUICConnectionErrorUPtr +QUICStream::recv(const QUICStopSendingFrame &frame) +{ + return nullptr; +} + +QUICConnectionErrorUPtr +QUICStream::recv(const QUICRstStreamFrame &frame) +{ + return nullptr; +} + +QUICConnectionErrorUPtr +QUICStream::recv(const QUICCryptoFrame &frame) +{ + return nullptr; +} + +// +// QUICStreamVConnection +// +QUICStreamVConnection::~QUICStreamVConnection() +{ + if (this->_read_event) { + this->_read_event->cancel(); + this->_read_event = nullptr; + } + + if (this->_write_event) { + this->_write_event->cancel(); + this->_write_event = nullptr; + } +} + void -QUICStream::_write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin) +QUICStreamVConnection::_write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin) { SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); @@ -104,7 +150,7 @@ QUICStream::_write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t * Replace existing event only if the new event is different than the inprogress event */ Event * -QUICStream::_send_tracked_event(Event *event, int send_event, VIO *vio) +QUICStreamVConnection::_send_tracked_event(Event *event, int send_event, VIO *vio) { if (event != nullptr) { if (event->callback_event != send_event) { @@ -124,7 +170,7 @@ QUICStream::_send_tracked_event(Event *event, int send_event, VIO *vio) * @brief Signal event to this->_read_vio.cont */ void -QUICStream::_signal_read_event() +QUICStreamVConnection::_signal_read_event() { if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return; @@ -144,7 +190,7 @@ QUICStream::_signal_read_event() * @brief Signal event to this->_write_vio.cont */ void -QUICStream::_signal_write_event() +QUICStreamVConnection::_signal_write_event() { if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { return; @@ -164,7 +210,7 @@ QUICStream::_signal_write_event() * @brief Signal event to this->_write_vio.cont */ void -QUICStream::_signal_read_eos_event() +QUICStreamVConnection::_signal_read_eos_event() { if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return; @@ -181,7 +227,7 @@ QUICStream::_signal_read_eos_event() } int64_t -QUICStream::_process_read_vio() +QUICStreamVConnection::_process_read_vio() { if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return 0; @@ -199,7 +245,7 @@ QUICStream::_process_read_vio() * @detail Call _signal_write_event() to indicate event upper layer */ int64_t -QUICStream::_process_write_vio() +QUICStreamVConnection::_process_write_vio() { if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { return 0; @@ -208,54 +254,12 @@ QUICStream::_process_write_vio() return 0; } -QUICOffset -QUICStream::reordered_bytes() const -{ - return this->_reordered_bytes; -} - -QUICConnectionErrorUPtr -QUICStream::recv(const QUICStreamFrame &frame) -{ - return nullptr; -} - -QUICConnectionErrorUPtr -QUICStream::recv(const QUICMaxStreamDataFrame &frame) -{ - return nullptr; -} - -QUICConnectionErrorUPtr -QUICStream::recv(const QUICStreamDataBlockedFrame &frame) -{ - return nullptr; -} - -QUICConnectionErrorUPtr -QUICStream::recv(const QUICStopSendingFrame &frame) -{ - return nullptr; -} - -QUICConnectionErrorUPtr -QUICStream::recv(const QUICRstStreamFrame &frame) -{ - return nullptr; -} - -QUICConnectionErrorUPtr -QUICStream::recv(const QUICCryptoFrame &frame) -{ - return nullptr; -} - // // QUICBidirectionalStream // QUICBidirectionalStream::QUICBidirectionalStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data) - : QUICStream(cinfo, sid), + : QUICStreamVConnection(cinfo, sid), _remote_flow_controller(send_max_stream_data, _id), _local_flow_controller(rtt_provider, recv_max_stream_data, _id), _flow_control_buffer_size(recv_max_stream_data), @@ -1027,39 +1031,3 @@ QUICCryptoStream::on_read() { return; } - -// Implement VConnection Interface. -VIO * -QUICCryptoStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) -{ - ink_assert(!"unsupported"); - return nullptr; -} - -VIO * -QUICCryptoStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) -{ - ink_assert(!"unsupported"); - return nullptr; -} - -void -QUICCryptoStream::do_io_close(int lerrno) -{ - ink_assert(!"unsupported"); - return; -} - -void -QUICCryptoStream::do_io_shutdown(ShutdownHowTo_t howto) -{ - ink_assert(!"unsupported"); - return; -} - -void -QUICCryptoStream::reenable(VIO *vio) -{ - ink_assert(!"unsupported"); - return; -} diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 7f41ebd6598..00b1a03e18c 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -39,10 +39,10 @@ * @brief QUIC Stream * TODO: This is similar to Http2Stream. Need to think some integration. */ -class QUICStream : public VConnection, public QUICFrameGenerator, public QUICFrameRetransmitter +class QUICStream : public QUICFrameGenerator, public QUICFrameRetransmitter { public: - QUICStream() : VConnection(nullptr) {} + QUICStream() {} QUICStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid); virtual ~QUICStream(); @@ -73,6 +73,31 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICFra LINK(QUICStream, link); +protected: + QUICConnectionInfoProvider *_connection_info = nullptr; + QUICStreamId _id = 0; + QUICOffset _send_offset = 0; + QUICOffset _reordered_bytes = 0; + + // Fragments of received STREAM frame (offset is unmatched) + // TODO: Consider to replace with ts/RbTree.h or other data structure + QUICIncomingStreamFrameBuffer _received_stream_frame_buffer; +}; + +// This is VConnection class for VIO operation. +class QUICStreamVConnection : public VConnection, public QUICStream +{ +public: + QUICStreamVConnection(QUICConnectionInfoProvider *cinfo, QUICStreamId sid) : VConnection(nullptr), QUICStream(cinfo, sid) + { + mutex = new_ProxyMutex(); + } + + QUICStreamVConnection() : VConnection(nullptr) {} + virtual ~QUICStreamVConnection(); + + LINK(QUICStreamVConnection, link); + protected: virtual int64_t _process_read_vio(); virtual int64_t _process_write_vio(); @@ -82,29 +107,24 @@ class QUICStream : public VConnection, public QUICFrameGenerator, public QUICFra Event *_send_tracked_event(Event *, int, VIO *); void _write_to_read_vio(QUICOffset offset, const uint8_t *data, uint64_t data_length, bool fin); - QUICConnectionInfoProvider *_connection_info = nullptr; - QUICStreamId _id = 0; - QUICOffset _send_offset = 0; - QUICOffset _reordered_bytes = 0; VIO _read_vio; VIO _write_vio; Event *_read_event = nullptr; Event *_write_event = nullptr; - - // Fragments of received STREAM frame (offset is unmatched) - // TODO: Consider to replace with ts/RbTree.h or other data structure - QUICIncomingStreamFrameBuffer _received_stream_frame_buffer; }; -class QUICBidirectionalStream : public QUICStream, public QUICTransferProgressProvider +class QUICBidirectionalStream : public QUICStreamVConnection, public QUICTransferProgressProvider { public: QUICBidirectionalStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data); QUICBidirectionalStream() - : _remote_flow_controller(0, 0), _local_flow_controller(nullptr, 0, 0), _state(nullptr, nullptr, nullptr, nullptr) + : QUICStreamVConnection(), + _remote_flow_controller(0, 0), + _local_flow_controller(nullptr, 0, 0), + _state(nullptr, nullptr, nullptr, nullptr) { } @@ -201,13 +221,6 @@ class QUICCryptoStream : public QUICStream int64_t read(uint8_t *buf, int64_t len); int64_t write(const uint8_t *buf, int64_t len); - // Implement VConnection Interface. - VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; - VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; - void do_io_close(int lerrno = -1) override; - void do_io_shutdown(ShutdownHowTo_t howto) override; - void reenable(VIO *vio) override; - void stop_sending(QUICStreamErrorUPtr error) override; void reset(QUICStreamErrorUPtr error) override; @@ -217,8 +230,6 @@ class QUICCryptoStream : public QUICStream void on_eos() override; void on_read() override; - LINK(QUICStream, link); - // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index bc1d641248f..8a7b952d134 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -90,16 +90,16 @@ QUICConnectionErrorUPtr QUICStreamManager::create_stream(QUICStreamId stream_id) { // TODO: check stream_id - QUICConnectionErrorUPtr error = nullptr; - QUICStream *stream = this->_find_or_create_stream(stream_id); - if (!stream) { + QUICConnectionErrorUPtr error = nullptr; + QUICStreamVConnection *stream_vc = this->_find_or_create_stream_vc(stream_id); + if (!stream_vc) { return std::make_unique(QUICTransErrorCode::STREAM_ID_ERROR); } QUICApplication *application = this->_app_map->get(stream_id); - if (!application->is_stream_set(stream)) { - application->set_stream(stream); + if (!application->is_stream_set(stream_vc)) { + application->set_stream(stream_vc); } return error; @@ -132,7 +132,7 @@ QUICStreamManager::create_bidi_stream(QUICStreamId &new_stream_id) void QUICStreamManager::reset_stream(QUICStreamId stream_id, QUICStreamErrorUPtr error) { - auto stream = this->_find_stream(stream_id); + auto stream = this->_find_stream_vc(stream_id); stream->reset(std::move(error)); } @@ -173,7 +173,7 @@ QUICStreamManager::handle_frame(QUICEncryptionLevel level, const QUICFrame &fram QUICConnectionErrorUPtr QUICStreamManager::_handle_frame(const QUICMaxStreamDataFrame &frame) { - QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); + QUICStreamVConnection *stream = this->_find_or_create_stream_vc(frame.stream_id()); if (stream) { return stream->recv(frame); } else { @@ -184,7 +184,7 @@ QUICStreamManager::_handle_frame(const QUICMaxStreamDataFrame &frame) QUICConnectionErrorUPtr QUICStreamManager::_handle_frame(const QUICStreamDataBlockedFrame &frame) { - QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); + QUICStreamVConnection *stream = this->_find_or_create_stream_vc(frame.stream_id()); if (stream) { return stream->recv(frame); } else { @@ -195,7 +195,7 @@ QUICStreamManager::_handle_frame(const QUICStreamDataBlockedFrame &frame) QUICConnectionErrorUPtr QUICStreamManager::_handle_frame(const QUICStreamFrame &frame) { - QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); + QUICStreamVConnection *stream = this->_find_or_create_stream_vc(frame.stream_id()); if (!stream) { return std::make_unique(QUICTransErrorCode::STREAM_ID_ERROR); } @@ -212,7 +212,7 @@ QUICStreamManager::_handle_frame(const QUICStreamFrame &frame) QUICConnectionErrorUPtr QUICStreamManager::_handle_frame(const QUICRstStreamFrame &frame) { - QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); + QUICStream *stream = this->_find_or_create_stream_vc(frame.stream_id()); if (stream) { return stream->recv(frame); } else { @@ -223,7 +223,7 @@ QUICStreamManager::_handle_frame(const QUICRstStreamFrame &frame) QUICConnectionErrorUPtr QUICStreamManager::_handle_frame(const QUICStopSendingFrame &frame) { - QUICStream *stream = this->_find_or_create_stream(frame.stream_id()); + QUICStream *stream = this->_find_or_create_stream_vc(frame.stream_id()); if (stream) { return stream->recv(frame); } else { @@ -243,10 +243,10 @@ QUICStreamManager::_handle_frame(const QUICMaxStreamsFrame &frame) return nullptr; } -QUICStream * -QUICStreamManager::_find_stream(QUICStreamId id) +QUICStreamVConnection * +QUICStreamManager::_find_stream_vc(QUICStreamId id) { - for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) { if (s->id() == id) { return s; } @@ -254,10 +254,10 @@ QUICStreamManager::_find_stream(QUICStreamId id) return nullptr; } -QUICStream * -QUICStreamManager::_find_or_create_stream(QUICStreamId stream_id) +QUICStreamVConnection * +QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id) { - QUICStream *stream = this->_find_stream(stream_id); + QUICStreamVConnection *stream = this->_find_stream_vc(stream_id); if (!stream) { if (!this->_local_tp) { return nullptr; diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 6f0542967db..5a9a285787f 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -57,7 +57,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator void set_default_application(QUICApplication *app); - DLL stream_list; + DLL stream_list; // QUICFrameHandler virtual std::vector interests() override; @@ -69,8 +69,8 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator ink_hrtime timestamp) override; private: - QUICStream *_find_stream(QUICStreamId id); - QUICStream *_find_or_create_stream(QUICStreamId stream_id); + QUICStreamVConnection *_find_stream_vc(QUICStreamId id); + QUICStreamVConnection *_find_or_create_stream_vc(QUICStreamId stream_id); QUICConnectionErrorUPtr _handle_frame(const QUICStreamFrame &frame); QUICConnectionErrorUPtr _handle_frame(const QUICRstStreamFrame &frame); QUICConnectionErrorUPtr _handle_frame(const QUICStopSendingFrame &frame); From 40882451978c2074837440135366637a6cb1fccc Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 4 Mar 2019 15:01:10 +0800 Subject: [PATCH 1183/1313] QUIC: Rename quicStreamAllocator to quicBidiStreamAllocator --- iocore/eventsystem/I_Thread.h | 2 +- iocore/net/quic/QUICStreamManager.cc | 4 ++-- iocore/net/quic/QUICStreamManager.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iocore/eventsystem/I_Thread.h b/iocore/eventsystem/I_Thread.h index fcc9b2b79a3..2a8397c13cd 100644 --- a/iocore/eventsystem/I_Thread.h +++ b/iocore/eventsystem/I_Thread.h @@ -123,7 +123,7 @@ class Thread ProxyAllocator http2StreamAllocator; ProxyAllocator quicClientSessionAllocator; ProxyAllocator quicHandshakeAllocator; - ProxyAllocator quicStreamAllocator; + ProxyAllocator quicBidiStreamAllocator; ProxyAllocator quicStreamManagerAllocator; ProxyAllocator httpServerSessionAllocator; ProxyAllocator hdrHeapAllocator; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 8a7b952d134..33d36b470db 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -30,7 +30,7 @@ static constexpr char tag[] = "quic_stream_manager"; static constexpr QUICStreamId QUIC_STREAM_TYPES = 4; ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); -ClassAllocator quicStreamAllocator("quicStreamAllocator"); +ClassAllocator quicBidiStreamAllocator("quicStreamAllocator"); QUICStreamManager::QUICStreamManager(QUICConnectionInfoProvider *info, QUICRTTProvider *rtt_provider, QUICApplicationMap *app_map) : _info(info), _rtt_provider(rtt_provider), _app_map(app_map) @@ -323,7 +323,7 @@ QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id) } // TODO Free the stream somewhere - stream = THREAD_ALLOC(quicStreamAllocator, this_ethread()); + stream = THREAD_ALLOC(quicBidiStreamAllocator, this_ethread()); new (stream) QUICBidirectionalStream(this->_rtt_provider, this->_info, stream_id, local_max_stream_data, remote_max_stream_data); diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 5a9a285787f..7612f3b1c67 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -30,7 +30,7 @@ #include "QUICFrame.h" #include "QUICLossDetector.h" -extern ClassAllocator quicStreamAllocator; +extern ClassAllocator quicBidiStreamAllocator; class QUICTransportParameters; From 8c157d759b5db530d15a342e7b234c33e961d5fb Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 7 Mar 2019 10:38:28 +0900 Subject: [PATCH 1184/1313] Remove test_QUICHandshake --- iocore/net/quic/Makefile.am | 8 -- iocore/net/quic/Mock.h | 48 ----------- iocore/net/quic/test/test_QUICHandshake.cc | 95 ---------------------- 3 files changed, 151 deletions(-) delete mode 100644 iocore/net/quic/test/test_QUICHandshake.cc diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index a480ecbef67..b5b571e04fa 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -181,14 +181,6 @@ test_QUICLossDetector_SOURCES = \ $(test_event_main_SOURCES) \ ./test/test_QUICLossDetector.cc -# TODO: fix unit test using QUICCryptoStream -# test_QUICHandshake_CPPFLAGS = $(test_CPPFLAGS) -# test_QUICHandshake_LDFLAGS = @AM_LDFLAGS@ -# test_QUICHandshake_LDADD = $(test_LDADD) -# test_QUICHandshake_SOURCES = \ -# $(test_event_main_SOURCES) \ -# ./test/test_QUICHandshake.cc - test_QUICHandshakeProtocol_CPPFLAGS = $(test_CPPFLAGS) test_QUICHandshakeProtocol_LDFLAGS = @AM_LDFLAGS@ test_QUICHandshakeProtocol_LDADD = $(test_LDADD) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 7cabff5e1dd..6d66dfa7d14 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -425,54 +425,6 @@ class MockQUICApplication : public QUICApplication } }; -class MockQUICStream : public QUICStream -{ -public: - MockQUICStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info, QUICStreamId sid, uint64_t recv_max_stream_data, - uint64_t send_max_stream_data) - : QUICStream(info, sid) - { - } - -private: - int64_t - _process_read_vio() override - { - return 0; - } - - int64_t - _process_write_vio() override - { - return 0; - } -}; - -class MockQUICStreamIO : public QUICStreamIO -{ -public: - MockQUICStreamIO(QUICApplication *app, QUICStream *stream) : QUICStreamIO(app, stream) {} - ~MockQUICStreamIO() {} - int64_t - transfer() - { - int64_t n = this->_write_buffer_reader->read_avail(); - this->_read_buffer->write(this->_write_buffer_reader, n); - this->_write_buffer_reader->consume(n); - return n; - } - -private: - void - read_reenable() override - { - } - void - write_reenable() override - { - } -}; - class MockQUICPacketProtectionKeyInfo : public QUICPacketProtectionKeyInfo { public: diff --git a/iocore/net/quic/test/test_QUICHandshake.cc b/iocore/net/quic/test/test_QUICHandshake.cc deleted file mode 100644 index 2043ce2b01a..00000000000 --- a/iocore/net/quic/test/test_QUICHandshake.cc +++ /dev/null @@ -1,95 +0,0 @@ -/** @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 "catch.hpp" - -#include "Mock.h" -#include "QUICHandshake.h" - -#include "./server_cert.h" - -TEST_CASE("1-RTT handshake ", "[quic]") -{ - // setup client - QUICConnection *client_qc = new MockQUICConnection(NET_VCONNECTION_OUT); - - SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - - QUICConnectionId client_conn_id = {reinterpret_cast("\x01\x23\x45"), 3}; - - QUICHandshake *client = new QUICHandshake(client_qc, client_ssl_ctx); - - // setup server - QUICConnection *server_qc = new MockQUICConnection(NET_VCONNECTION_IN); - - SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); - SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); - BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt))); - SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, nullptr, nullptr)); - BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key))); - SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr)); - - QUICConnectionId conn_id = QUICConnectionId::ZERO(); - QUICStatelessResetToken server_token; - server_token.generate(conn_id, 0); - - QUICHandshake *server = new QUICHandshake(server_qc, server_ssl_ctx, server_token, false); - - // setup stream 0 - MockQUICRTTProvider rtt; - MockQUICConnectionInfoProvider info; - QUICStream *stream = new MockQUICStream(&rtt, &info, 0, UINT64_MAX, UINT64_MAX); - MockQUICStreamIO *stream_io = new MockQUICStreamIO(nullptr, stream); - - client->set_stream(stream, stream_io); - server->set_stream(stream, stream_io); - - SECTION("Basic Full Handshake") - { - // ClientHello - client->handleEvent(VC_EVENT_WRITE_READY, nullptr); - CHECK(stream_io->transfer() > 0); - client->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); - - // ServerHello - server->handleEvent(VC_EVENT_READ_READY, nullptr); - CHECK(stream_io->transfer() > 0); - - client->handleEvent(VC_EVENT_READ_READY, nullptr); - CHECK(stream_io->transfer() > 0); - client->handleEvent(QUIC_EVENT_HANDSHAKE_PACKET_WRITE_COMPLETE, nullptr); - - // Finished - server->handleEvent(VC_EVENT_READ_READY, nullptr); - - CHECK(client->is_completed()); - CHECK(server->is_completed()); - } - - delete stream_io; -} From 13e12de1a4e9ad1df22557e9e1bf187cd275a688 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 7 Mar 2019 10:46:31 +0900 Subject: [PATCH 1185/1313] Fix unit tests using QUICBidirectionalStream --- iocore/net/quic/test/test_QUICFrame.cc | 2 +- iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 1f502736292..2ef3dcb353a 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1522,7 +1522,7 @@ TEST_CASE("QUICFrameFactory Create RESET_STREAM with a QUICStreamError", "[quic] uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; MockQUICRTTProvider mock_rtt; MockQUICConnection mock_connection; - QUICStream stream(&mock_rtt, &mock_connection, 0x1234, 0, 0); + QUICBidirectionalStream stream(&mock_rtt, &mock_connection, 0x1234, 0, 0); std::unique_ptr error = std::unique_ptr(new QUICStreamError(&stream, static_cast(0x01))); const QUICRstStreamFrame *rst_stream_frame1 = QUICFrameFactory::create_rst_stream_frame(frame_buf, *error); diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 7a5674325ef..32eee34291c 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -30,7 +30,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") { uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; - QUICStream *stream = new QUICStream(); + QUICBidirectionalStream *stream = new QUICBidirectionalStream(); QUICIncomingStreamFrameBuffer buffer; QUICErrorUPtr err = nullptr; @@ -122,7 +122,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") { - QUICStream *stream = new QUICStream(); + QUICBidirectionalStream *stream = new QUICBidirectionalStream(); QUICIncomingStreamFrameBuffer buffer; QUICErrorUPtr err = nullptr; @@ -195,7 +195,7 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") TEST_CASE("QUICIncomingStreamFrameBuffer_dup_frame", "[quic]") { - QUICStream *stream = new QUICStream(); + QUICBidirectionalStream *stream = new QUICBidirectionalStream(); QUICIncomingStreamFrameBuffer buffer; QUICErrorUPtr err = nullptr; From e5a65d77da2d2f3b50ca5be7930488352ae896bb Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 7 Mar 2019 11:16:54 +0900 Subject: [PATCH 1186/1313] Fix building unit tests for QUIC Prior this change, there're many undefined symbols comes from SSLMultiCertConfigLoader. As workaround fix, link unit tests to libinknet.a. --- iocore/net/Makefile.am | 1 + iocore/net/libinknet_stub.cc | 163 +++++++++++++++++++++++++++++++++++ iocore/net/quic/Makefile.am | 15 ++-- iocore/net/quic/test/stub.cc | 51 ----------- iocore/net/test_I_UDPNet.cc | 142 ------------------------------ 5 files changed, 173 insertions(+), 199 deletions(-) create mode 100644 iocore/net/libinknet_stub.cc delete mode 100644 iocore/net/quic/test/stub.cc diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am index 76a1bdc3530..dc0a3856173 100644 --- a/iocore/net/Makefile.am +++ b/iocore/net/Makefile.am @@ -83,6 +83,7 @@ test_UDPNet_LDADD = \ @HWLOC_LIBS@ @OPENSSL_LIBS@ @LIBPCRE@ @YAMLCPP_LIBS@ test_UDPNet_SOURCES = \ + libinknet_stub.cc \ test_I_UDPNet.cc libinknet_a_SOURCES = \ diff --git a/iocore/net/libinknet_stub.cc b/iocore/net/libinknet_stub.cc new file mode 100644 index 00000000000..91fbf1f8db4 --- /dev/null +++ b/iocore/net/libinknet_stub.cc @@ -0,0 +1,163 @@ +/** @file + + Stub file for linking libinknet.a from unit tests + + @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 "HttpSessionManager.h" + +void +initialize_thread_for_http_sessions(EThread *, int) +{ + ink_assert(false); +} + +#include "P_UnixNet.h" +#include "P_DNSConnection.h" +int +DNSConnection::close() +{ + ink_assert(false); + return 0; +} + +void +DNSConnection::trigger() +{ + ink_assert(false); +} + +#include "StatPages.h" +void +StatPagesManager::register_http(char const *, Action *(*)(Continuation *, HTTPHdr *)) +{ + ink_assert(false); +} + +#include "ParentSelection.h" +void +SocksServerConfig::startup() +{ + ink_assert(false); +} + +int SocksServerConfig::m_id = 0; + +void +ParentConfigParams::findParent(HttpRequestData *, ParentResult *, unsigned int, unsigned int) +{ + ink_assert(false); +} + +void +ParentConfigParams::nextParent(HttpRequestData *, ParentResult *, unsigned int, unsigned int) +{ + ink_assert(false); +} + +#include "Log.h" +void +Log::trace_in(sockaddr const *, unsigned short, char const *, ...) +{ + ink_assert(false); +} + +void +Log::trace_out(sockaddr const *, unsigned short, char const *, ...) +{ + ink_assert(false); +} + +#include "InkAPIInternal.h" +int +APIHook::invoke(int, void *) +{ + ink_assert(false); + return 0; +} + +APIHook * +APIHook::next() const +{ + ink_assert(false); + return nullptr; +} + +APIHook * +APIHooks::get() const +{ + ink_assert(false); + return nullptr; +} + +void +ConfigUpdateCbTable::invoke(const char * /* name ATS_UNUSED */) +{ + ink_release_assert(false); +} + +#include "ControlMatcher.h" +char * +HttpRequestData::get_string() +{ + ink_assert(false); + return nullptr; +} + +const char * +HttpRequestData::get_host() +{ + ink_assert(false); + return nullptr; +} + +sockaddr const * +HttpRequestData::get_ip() +{ + ink_assert(false); + return nullptr; +} + +sockaddr const * +HttpRequestData::get_client_ip() +{ + ink_assert(false); + return nullptr; +} + +SslAPIHooks *ssl_hooks = nullptr; +StatPagesManager statPagesManager; + +#include "ProcessManager.h" +inkcoreapi ProcessManager *pmgmt = nullptr; + +int +BaseManager::registerMgmtCallback(int, MgmtCallback const &) +{ + ink_assert(false); + return 0; +} + +void +ProcessManager::signalManager(int, char const *, int) +{ + ink_assert(false); + return; +} diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index b5b571e04fa..ceddc268b00 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -124,20 +124,23 @@ test_CPPFLAGS = \ test_LDADD = \ libquic.a \ $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/src/tscore/libtscore.la \ + $(top_builddir)/src/tscpp/util/libtscpputil.la \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/iocore/net/libinknet.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ - @OPENSSL_LIBS@ \ - @HWLOC_LIBS@ + $(top_builddir)/proxy/ParentSelectionStrategy.o \ + @HWLOC_LIBS@ @OPENSSL_LIBS@ @LIBPCRE@ @YAMLCPP_LIBS@ test_event_main_SOURCES = \ - ./test/event_processor_main.cc \ - ./test/stub.cc + ../libinknet_stub.cc \ + ./test/event_processor_main.cc test_main_SOURCES = \ - ./test/main.cc \ - ./test/stub.cc + ../libinknet_stub.cc \ + ./test/main.cc test_QUICAckFrameCreator_CPPFLAGS = $(test_CPPFLAGS) test_QUICAckFrameCreator_LDFLAGS = @AM_LDFLAGS@ diff --git a/iocore/net/quic/test/stub.cc b/iocore/net/quic/test/stub.cc deleted file mode 100644 index 4aaf60cea61..00000000000 --- a/iocore/net/quic/test/stub.cc +++ /dev/null @@ -1,51 +0,0 @@ -/** @file - * - * Stubs for QUICConfig - * - * @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/ink_assert.h" - -#include "P_SSLConfig.h" - -bool -SSLParseCertificateConfiguration(const SSLConfigParams *, SSL_CTX *) -{ - return false; -} - -SSLConfigParams * -SSLConfig::acquire() -{ - return nullptr; -} - -void -SSLConfig::release(SSLConfigParams *) -{ - return; -} - -#include "P_SSLNextProtocolSet.h" - -bool -SSLNextProtocolSet::advertiseProtocols(const unsigned char **out, unsigned *len) const -{ - return true; -} diff --git a/iocore/net/test_I_UDPNet.cc b/iocore/net/test_I_UDPNet.cc index 223ec71607e..2f57cf6f8c6 100644 --- a/iocore/net/test_I_UDPNet.cc +++ b/iocore/net/test_I_UDPNet.cc @@ -232,145 +232,3 @@ main(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */) RegressionTest::run("UDPNet", REGRESSION_TEST_QUICK); return RegressionTest::final_status == REGRESSION_TEST_PASSED ? 0 : 1; } - -// -// stub -// -void -initialize_thread_for_http_sessions(EThread *, int) -{ - ink_assert(false); -} - -#include "P_UnixNet.h" -#include "P_DNSConnection.h" -int -DNSConnection::close() -{ - ink_assert(false); - return 0; -} - -void -DNSConnection::trigger() -{ - ink_assert(false); -} - -#include "StatPages.h" -void -StatPagesManager::register_http(char const *, Action *(*)(Continuation *, HTTPHdr *)) -{ - ink_assert(false); -} - -#include "ParentSelection.h" -void -SocksServerConfig::startup() -{ - ink_assert(false); -} - -int SocksServerConfig::m_id = 0; - -void -ParentConfigParams::findParent(HttpRequestData *, ParentResult *, unsigned int, unsigned int) -{ - ink_assert(false); -} - -void -ParentConfigParams::nextParent(HttpRequestData *, ParentResult *, unsigned int, unsigned int) -{ - ink_assert(false); -} - -#include "Log.h" -void -Log::trace_in(sockaddr const *, unsigned short, char const *, ...) -{ - ink_assert(false); -} - -void -Log::trace_out(sockaddr const *, unsigned short, char const *, ...) -{ - ink_assert(false); -} - -#include "InkAPIInternal.h" -int -APIHook::invoke(int, void *) -{ - ink_assert(false); - return 0; -} - -APIHook * -APIHook::next() const -{ - ink_assert(false); - return nullptr; -} - -APIHook * -APIHooks::get() const -{ - ink_assert(false); - return nullptr; -} - -void -ConfigUpdateCbTable::invoke(const char * /* name ATS_UNUSED */) -{ - ink_release_assert(false); -} - -#include "ControlMatcher.h" -char * -HttpRequestData::get_string() -{ - ink_assert(false); - return nullptr; -} - -const char * -HttpRequestData::get_host() -{ - ink_assert(false); - return nullptr; -} - -sockaddr const * -HttpRequestData::get_ip() -{ - ink_assert(false); - return nullptr; -} - -sockaddr const * -HttpRequestData::get_client_ip() -{ - ink_assert(false); - return nullptr; -} - -SslAPIHooks *ssl_hooks = nullptr; -StatPagesManager statPagesManager; - -#include "ProcessManager.h" -inkcoreapi ProcessManager *pmgmt = nullptr; - -int -BaseManager::registerMgmtCallback(int, MgmtCallback const &) -{ - ink_assert(false); - return 0; -} - -void -ProcessManager::signalManager(int, char const *, int) -{ - ink_assert(false); - return; -} From ecc8f02e3ad988de7051c73d19a70892d55c81a1 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 7 Mar 2019 12:26:14 +0900 Subject: [PATCH 1187/1313] Fix QUICStreamManager to use QUICStreamVConnection --- iocore/net/quic/QUICStreamManager.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 33d36b470db..a4d3188052b 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -339,7 +339,7 @@ QUICStreamManager::total_reordered_bytes() const uint64_t total_bytes = 0; // FIXME Iterating all (open + closed) streams is expensive - for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) { total_bytes += s->reordered_bytes(); } return total_bytes; @@ -351,7 +351,7 @@ QUICStreamManager::total_offset_received() const uint64_t total_offset_received = 0; // FIXME Iterating all (open + closed) streams is expensive - for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) { total_offset_received += s->largest_offset_received(); } return total_offset_received; @@ -374,7 +374,7 @@ uint32_t QUICStreamManager::stream_count() const { uint32_t count = 0; - for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) { ++count; } return count; @@ -398,7 +398,7 @@ QUICStreamManager::will_generate_frame(QUICEncryptionLevel level, ink_hrtime tim return false; } - for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) { if (s->will_generate_frame(level, timestamp)) { return true; } @@ -423,7 +423,7 @@ QUICStreamManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint6 } // FIXME We should pick a stream based on priority - for (QUICStream *s = this->stream_list.head; s; s = s->link.next) { + for (QUICStreamVConnection *s = this->stream_list.head; s; s = s->link.next) { frame = s->generate_frame(buf, level, connection_credit, maximum_frame_size, timestamp); if (frame) { break; From 2c538479077a23a1e5c2d2cd54fee02e76c2ea16 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 7 Mar 2019 15:22:30 +0900 Subject: [PATCH 1188/1313] Rename QUICSimpleApp to Http09App --- proxy/http3/{QUICSimpleApp.cc => Http09App.cc} | 10 +++++----- proxy/http3/{QUICSimpleApp.h => Http09App.h} | 7 ++++--- proxy/http3/Http3SessionAccept.cc | 4 ++-- proxy/http3/Makefile.am | 4 ++-- 4 files changed, 13 insertions(+), 12 deletions(-) rename proxy/http3/{QUICSimpleApp.cc => Http09App.cc} (91%) rename proxy/http3/{QUICSimpleApp.h => Http09App.h} (86%) diff --git a/proxy/http3/QUICSimpleApp.cc b/proxy/http3/Http09App.cc similarity index 91% rename from proxy/http3/QUICSimpleApp.cc rename to proxy/http3/Http09App.cc index cbff21583cd..f89d0bb45b9 100644 --- a/proxy/http3/QUICSimpleApp.cc +++ b/proxy/http3/Http09App.cc @@ -21,7 +21,7 @@ * limitations under the License. */ -#include "QUICSimpleApp.h" +#include "Http09App.h" #include "P_Net.h" #include "P_VConnection.h" @@ -33,7 +33,7 @@ static constexpr char debug_tag[] = "quic_simple_app"; static constexpr char debug_tag_v[] = "v_quic_simple_app"; -QUICSimpleApp::QUICSimpleApp(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QUICApplication(client_vc) +Http09App::Http09App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QUICApplication(client_vc) { this->_client_session = new Http3ClientSession(client_vc); this->_client_session->acl = std::move(session_acl); @@ -41,16 +41,16 @@ QUICSimpleApp::QUICSimpleApp(QUICNetVConnection *client_vc, IpAllow::ACL session this->_qc->stream_manager()->set_default_application(this); - SET_HANDLER(&QUICSimpleApp::main_event_handler); + SET_HANDLER(&Http09App::main_event_handler); } -QUICSimpleApp::~QUICSimpleApp() +Http09App::~Http09App() { delete this->_client_session; } int -QUICSimpleApp::main_event_handler(int event, Event *data) +Http09App::main_event_handler(int event, Event *data) { Debug(debug_tag_v, "[%s] %s (%d)", this->_qc->cids().data(), get_vc_event_name(event), event); diff --git a/proxy/http3/QUICSimpleApp.h b/proxy/http3/Http09App.h similarity index 86% rename from proxy/http3/QUICSimpleApp.h rename to proxy/http3/Http09App.h index fcb9c9a131f..1132ef29eec 100644 --- a/proxy/http3/QUICSimpleApp.h +++ b/proxy/http3/Http09App.h @@ -33,13 +33,14 @@ class Http3ClientSession; /** * @brief A simple multi-streamed application. * @detail Response to simple HTTP/0.9 GETs + * This will be removed when HTTP/0.9 over QUIC support is dropped * */ -class QUICSimpleApp : public QUICApplication +class Http09App : public QUICApplication { public: - QUICSimpleApp(QUICNetVConnection *client_vc, IpAllow::ACL session_acl); - ~QUICSimpleApp(); + Http09App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl); + ~Http09App(); int main_event_handler(int event, Event *data); diff --git a/proxy/http3/Http3SessionAccept.cc b/proxy/http3/Http3SessionAccept.cc index c542abcdb01..6a12f3a667b 100644 --- a/proxy/http3/Http3SessionAccept.cc +++ b/proxy/http3/Http3SessionAccept.cc @@ -27,7 +27,7 @@ #include "I_Machine.h" #include "IPAllow.h" -#include "QUICSimpleApp.h" +#include "Http09App.h" #include "Http3App.h" Http3SessionAccept::Http3SessionAccept(const HttpSessionAccept::Options &_o) : SessionAccept(nullptr), options(_o) @@ -68,7 +68,7 @@ Http3SessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferRead Debug("http3", "[%s] start HTTP/0.9 app (ALPN=%s)", qvc->cids().data(), IP_PROTO_TAG_HTTP_QUIC.data()); } - new QUICSimpleApp(qvc, std::move(session_acl)); + new Http09App(qvc, std::move(session_acl)); } else if (IP_PROTO_TAG_HTTP_3.compare(alpn) == 0) { Debug("http3", "[%s] start HTTP/3 app (ALPN=%s)", qvc->cids().data(), IP_PROTO_TAG_HTTP_3.data()); diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index 50e51b8d898..b8d8920abe2 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -35,6 +35,7 @@ AM_CPPFLAGS += \ noinst_LIBRARIES = libhttp3.a libhttp3_a_SOURCES = \ + Http09App.cc \ Http3.cc \ Http3Config.cc \ Http3App.cc \ @@ -50,8 +51,7 @@ libhttp3_a_SOURCES = \ Http3DataFramer.cc \ Http3HeaderVIOAdaptor.cc \ Http3StreamDataVIOAdaptor.cc \ - QPACK.cc \ - QUICSimpleApp.cc + QPACK.cc # # Check Programs From 7532912c61b038cb45c8feddf6a5b6cb118ee196 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 7 Mar 2019 16:09:24 +0800 Subject: [PATCH 1189/1313] QUIC: recovery draft-18 --- iocore/net/quic/QUICLossDetector.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 337d9e867a7..4287eadd55b 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -187,12 +187,14 @@ QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool ack_elici PacketInfoUPtr packet_info = PacketInfoUPtr(new PacketInfo( {packet_number, now, ack_eliciting, is_crypto_packet, in_flight, ack_eliciting ? sent_bytes : 0, std::move(packet)})); this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); - if (ack_eliciting) { + if (in_flight) { if (is_crypto_packet) { this->_time_of_last_sent_crypto_packet = now; } - this->_time_of_last_sent_ack_eliciting_packet = now; + if (ack_eliciting) { + this->_time_of_last_sent_ack_eliciting_packet = now; + } this->_cc->on_packet_sent(sent_bytes); this->_set_loss_detection_timer(); } @@ -217,7 +219,6 @@ QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame) QUICLDVDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); - // TODO ECN // if (ACK frame contains ECN information): // ProcessECN(ack) if (ack_frame.ecn_section() != nullptr && pi != this->_sent_packets.end()) { @@ -242,14 +243,14 @@ QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame) return; } + this->_detect_lost_packets(); + this->_crypto_count = 0; this->_pto_count = 0; QUICLDVDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); - this->_detect_lost_packets(); - QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); From f9b26d2f52aae1aa50ecac68826733afc8f4ecae Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 8 Mar 2019 08:16:49 +0800 Subject: [PATCH 1190/1313] QUIC: Moving log in appropriate position --- iocore/net/quic/QUICLossDetector.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 4287eadd55b..7b3aef08fe2 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -243,14 +243,14 @@ QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame) return; } + QUICLDVDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), + this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); + this->_detect_lost_packets(); this->_crypto_count = 0; this->_pto_count = 0; - QUICLDVDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), - this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); - QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); From 0b492facbb9dcc9b14ee3cae63d741ab5628e45f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 6 Mar 2019 17:30:31 +0900 Subject: [PATCH 1191/1313] Don't keep packets sent --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICFrame.cc | 4 +-- iocore/net/quic/QUICFrame.h | 4 +-- iocore/net/quic/QUICLossDetector.cc | 35 ++++++++++--------- iocore/net/quic/QUICLossDetector.h | 9 ++--- iocore/net/quic/test/test_QUICLossDetector.cc | 22 ++++++------ 6 files changed, 39 insertions(+), 37 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e8c7b5390e0..6ff632c2f7a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1223,7 +1223,7 @@ QUICNetVConnection::_state_common_send_packet() } int index = QUICTypeUtil::pn_space_index(level); - this->_loss_detector[index]->on_packet_sent(std::move(packet)); + this->_loss_detector[index]->on_packet_sent(*packet); packet_count++; } } diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 13e8339f394..a9e2cbc7423 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -2702,13 +2702,13 @@ QUICFrameFactory::create_retire_connection_id_frame(uint8_t *buf, uint64_t seq_n } QUICFrameId -QUICFrameInfo::id() +QUICFrameInfo::id() const { return this->_id; } QUICFrameGenerator * -QUICFrameInfo::generated_by() +QUICFrameInfo::generated_by() const { return this->_generator; } diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index f2d9964d5e3..6379985f95c 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -853,8 +853,8 @@ class QUICFrameInfo { public: QUICFrameInfo(QUICFrameId id, QUICFrameGenerator *generator) : _id(id), _generator(generator) {} - QUICFrameId id(); - QUICFrameGenerator *generated_by(); + QUICFrameId id() const; + QUICFrameGenerator *generated_by() const; private: QUICFrameId _id = 0; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 7b3aef08fe2..169da3eb1c4 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -131,18 +131,20 @@ QUICLossDetector::largest_acked_packet_number() } void -QUICLossDetector::on_packet_sent(QUICPacketUPtr packet, bool in_flight) +QUICLossDetector::on_packet_sent(QUICPacket &packet, bool in_flight) { - if (packet->type() == QUICPacketType::VERSION_NEGOTIATION) { + if (packet.type() == QUICPacketType::VERSION_NEGOTIATION) { return; } this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); - auto packet_number = packet->packet_number(); - auto ack_eliciting = packet->is_ack_eliciting(); - auto crypto = packet->is_crypto_packet(); - auto sent_bytes = packet->size(); - this->_on_packet_sent(packet_number, ack_eliciting, in_flight, crypto, sent_bytes, std::move(packet)); + auto packet_number = packet.packet_number(); + auto ack_eliciting = packet.is_ack_eliciting(); + auto crypto = packet.is_crypto_packet(); + auto sent_bytes = packet.size(); + auto type = packet.type(); + auto frames = std::move(packet.frames()); + this->_on_packet_sent(packet_number, ack_eliciting, in_flight, crypto, sent_bytes, type, frames); } void @@ -177,15 +179,14 @@ QUICLossDetector::update_ack_delay_exponent(uint8_t ack_delay_exponent) void QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool ack_eliciting, bool in_flight, bool is_crypto_packet, - size_t sent_bytes, QUICPacketUPtr packet) + size_t sent_bytes, QUICPacketType type, std::vector &frames) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); ink_hrtime now = Thread::get_hrtime(); this->_largest_sent_packet = packet_number; - // FIXME Should we really keep actual packet object? - PacketInfoUPtr packet_info = PacketInfoUPtr(new PacketInfo( - {packet_number, now, ack_eliciting, is_crypto_packet, in_flight, ack_eliciting ? sent_bytes : 0, std::move(packet)})); + {packet_number, now, ack_eliciting, is_crypto_packet, in_flight, ack_eliciting ? sent_bytes : 0, type, std::move(frames)})); + this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); if (in_flight) { if (is_crypto_packet) { @@ -291,7 +292,7 @@ QUICLossDetector::_on_packet_acked(const PacketInfo &acked_packet) this->_cc->on_packet_acked(acked_packet); } - for (QUICFrameInfo &frame_info : acked_packet.packet->frames()) { + for (const QUICFrameInfo &frame_info : acked_packet.frames) { auto reactor = frame_info.generated_by(); if (reactor == nullptr) { continue; @@ -441,7 +442,7 @@ QUICLossDetector::_detect_lost_packets() // Not sure how we can get feedback from congestion control and when we should retransmit the lost packets but we need to send // them somewhere. // I couldn't find the place so just send them here for now. - this->_retransmit_lost_packet(lost_packet.second->packet); + this->_retransmit_lost_packet(*lost_packet.second); // -- END OF ADDITIONAL CODE -- // -- ADDITIONAL CODE -- this->_remove_from_sent_packet_list(lost_packet.first); @@ -462,7 +463,7 @@ QUICLossDetector::_retransmit_all_unacked_crypto_data() for (auto &info : this->_sent_packets) { if (info.second->is_crypto_packet) { retransmitted_crypto_packets.insert(info.first); - this->_retransmit_lost_packet(info.second->packet); + this->_retransmit_lost_packet(*info.second); lost_packets.insert({info.first, info.second.get()}); } } @@ -483,12 +484,12 @@ QUICLossDetector::_send_two_packets() // ===== Functions below are helper functions ===== void -QUICLossDetector::_retransmit_lost_packet(QUICPacketUPtr &packet) +QUICLossDetector::_retransmit_lost_packet(PacketInfo &packet_info) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - QUICLDDebug("[NOP] Retransmit %s packet #%" PRIu64, QUICDebugNames::packet_type(packet->type()), packet->packet_number()); - for (QUICFrameInfo &frame_info : packet->frames()) { + QUICLDDebug("Retransmit %s packet #%" PRIu64, QUICDebugNames::packet_type(packet_info.type), packet_info.packet_number); + for (QUICFrameInfo &frame_info : packet_info.frames) { auto reactor = frame_info.generated_by(); if (reactor == nullptr) { continue; diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 8f69c953f3b..63e344874f3 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -49,7 +49,8 @@ struct PacketInfo { size_t sent_bytes; // addition - QUICPacketUPtr packet; + QUICPacketType type; + std::vector frames; // end }; @@ -125,7 +126,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler std::vector interests() override; virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; - void on_packet_sent(QUICPacketUPtr packet, bool in_flight = true); + void on_packet_sent(QUICPacket &packet, bool in_flight = true); QUICPacketNumber largest_acked_packet_number(); void update_ack_delay_exponent(uint8_t ack_delay_exponent); void reset(); @@ -177,14 +178,14 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler ink_hrtime _loss_detection_alarm_at = 0; void _on_packet_sent(QUICPacketNumber packet_number, bool ack_eliciting, bool in_flight, bool is_crypto_packet, size_t sent_bytes, - QUICPacketUPtr packet); + QUICPacketType type, std::vector &frames); void _on_ack_received(const QUICAckFrame &ack_frame); void _on_packet_acked(const PacketInfo &acked_packet); void _update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay); void _detect_lost_packets(); void _set_loss_detection_timer(); void _on_loss_detection_timeout(); - void _retransmit_lost_packet(QUICPacketUPtr &packet); + void _retransmit_lost_packet(PacketInfo &packet_info); std::set _determine_newly_acked_packets(const QUICAckFrame &ack_frame); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 20748830223..05b8953780d 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -68,7 +68,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") false, std::move(payload), sizeof(raw)); QUICPacketUPtr packet = QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true, false), [](QUICPacket *p) { delete p; }); - detector.on_packet_sent(std::move(packet)); + detector.on_packet_sent(*packet); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); CHECK(g.lost_frame_count >= 0); @@ -127,16 +127,16 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") QUICPacketNumber pn9 = packet9->packet_number(); QUICPacketNumber pn10 = packet10->packet_number(); - detector.on_packet_sent(std::move(packet1)); - detector.on_packet_sent(std::move(packet2)); - detector.on_packet_sent(std::move(packet3)); - detector.on_packet_sent(std::move(packet4)); - detector.on_packet_sent(std::move(packet5)); - detector.on_packet_sent(std::move(packet6)); - detector.on_packet_sent(std::move(packet7)); - detector.on_packet_sent(std::move(packet8)); - detector.on_packet_sent(std::move(packet9)); - detector.on_packet_sent(std::move(packet10)); + detector.on_packet_sent(*packet1); + detector.on_packet_sent(*packet2); + detector.on_packet_sent(*packet3); + detector.on_packet_sent(*packet4); + detector.on_packet_sent(*packet5); + detector.on_packet_sent(*packet6); + detector.on_packet_sent(*packet7); + detector.on_packet_sent(*packet8); + detector.on_packet_sent(*packet9); + detector.on_packet_sent(*packet10); ink_hrtime_sleep(HRTIME_MSECONDS(2000)); // Receive an ACK for (1) (4) (5) (7) (8) (9) From 49251b9f4a40326af4974348b929c310c957a992 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 8 Mar 2019 10:45:06 +0900 Subject: [PATCH 1192/1313] Pass QUICPacketInfoUPtr to on_packet_sent instead of QUICPacketUPtr --- iocore/net/P_QUICNetVConnection.h | 4 +- iocore/net/QUICNetVConnection.cc | 35 +++-- iocore/net/quic/Mock.h | 2 +- iocore/net/quic/QUICCongestionController.cc | 6 +- iocore/net/quic/QUICLossDetector.cc | 75 +++++------ iocore/net/quic/QUICLossDetector.h | 28 ++-- iocore/net/quic/QUICPacket.cc | 33 ----- iocore/net/quic/QUICPacket.h | 14 +- iocore/net/quic/QUICPacketFactory.cc | 23 ++-- iocore/net/quic/QUICPacketFactory.h | 14 +- iocore/net/quic/test/test_QUICLossDetector.cc | 121 ++++++++++++++---- .../net/quic/test/test_QUICPacketFactory.cc | 3 +- .../quic/test/test_QUICVersionNegotiator.cc | 10 +- 13 files changed, 196 insertions(+), 172 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 361d83b34cf..b90d3d4cc23 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -288,10 +288,10 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrame &frame, std::vector &frames); - QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size); + QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size, std::vector &frames); void _packetize_closing_frame(); QUICPacketUPtr _build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing, - bool crypto, std::vector &frames); + bool crypto); QUICConnectionErrorUPtr _recv_and_ack(QUICPacket &packet, bool *has_non_probing_frame = nullptr); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6ff632c2f7a..db860466f1f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1196,7 +1196,20 @@ QUICNetVConnection::_state_common_send_packet() max_packet_size = std::min(max_packet_size, this->_verfied_state.windows()); } - QUICPacketUPtr packet = this->_packetize_frames(level, max_packet_size); + QUICPacketInfoUPtr packet_info = std::make_unique(); + QUICPacketUPtr packet = this->_packetize_frames(level, max_packet_size, packet_info->frames); + + 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; + if (packet_info->ack_eliciting) { + packet_info->sent_bytes = packet->size(); + } else { + packet_info->sent_bytes = 0; + } + packet_info->type = packet->type(); if (packet) { if (this->netvc_context == NET_VCONNECTION_IN && !this->_verfied_state.is_verified()) { @@ -1223,7 +1236,7 @@ QUICNetVConnection::_state_common_send_packet() } int index = QUICTypeUtil::pn_space_index(level); - this->_loss_detector[index]->on_packet_sent(*packet); + this->_loss_detector[index]->on_packet_sent(std::move(packet_info)); packet_count++; } } @@ -1286,7 +1299,7 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t & } QUICPacketUPtr -QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size) +QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size, std::vector &frames) { ink_hrtime timestamp = Thread::get_hrtime(); @@ -1307,8 +1320,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa size_t len = 0; ats_unique_buf buf = ats_unique_malloc(max_packet_size); - std::vector frames; - if (!this->_has_ack_eliciting_packet_out) { // Sent too much ack_only packet. At this moment we need to packetize a ping frame // to force peer send ack frame. @@ -1392,7 +1403,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } // Packet is retransmittable if it's not ack only packet - packet = this->_build_packet(level, std::move(buf), len, ack_eliciting, probing, crypto, frames); + packet = this->_build_packet(level, std::move(buf), len, ack_eliciting, probing, crypto); this->_has_ack_eliciting_packet_out = ack_eliciting; } @@ -1422,7 +1433,7 @@ QUICNetVConnection::_packetize_closing_frame() QUICEncryptionLevel level = this->_hs_protocol->current_encryption_level(); ink_assert(level != QUICEncryptionLevel::ZERO_RTT); - this->_the_final_packet = this->_build_packet(level, std::move(buf), len, true, false, false, frames); + this->_the_final_packet = this->_build_packet(level, std::move(buf), len, true, false, false); } QUICConnectionErrorUPtr @@ -1469,7 +1480,7 @@ QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_fram QUICPacketUPtr QUICNetVConnection::_build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool ack_eliciting, bool probing, - bool crypto, std::vector &frames) + bool crypto) { QUICPacketType type = QUICTypeUtil::packet_type(level); QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); @@ -1493,25 +1504,25 @@ QUICNetVConnection::_build_packet(QUICEncryptionLevel level, ats_unique_buf buf, 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, frames, std::move(token), token_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, this->_largest_acked_packet_number(QUICEncryptionLevel::HANDSHAKE), - std::move(buf), len, ack_eliciting, probing, crypto, frames); + std::move(buf), 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, this->_largest_acked_packet_number(QUICEncryptionLevel::ZERO_RTT), - std::move(buf), len, ack_eliciting, probing, frames); + std::move(buf), 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, frames); + std::move(buf), len, ack_eliciting, probing); break; } default: diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 6d66dfa7d14..c764cfa8084 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -343,7 +343,7 @@ class MockQUICCongestionController : public QUICCongestionController MockQUICCongestionController(QUICConnectionInfoProvider *info) : QUICCongestionController(info) {} // Override virtual void - on_packets_lost(const std::map &packets, uint32_t pto_count) override + on_packets_lost(const std::map &packets, uint32_t pto_count) override { for (auto &p : packets) { lost_packets.insert(p.first); diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 53ab1f55486..e863d8d36cd 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -66,7 +66,7 @@ QUICCongestionController::_in_recovery(ink_hrtime sent_time) } void -QUICCongestionController::on_packet_acked(const PacketInfo &acked_packet) +QUICCongestionController::on_packet_acked(const QUICPacketInfo &acked_packet) { // Remove from bytes_in_flight. SCOPED_MUTEX_LOCK(lock, this->_cc_mutex, this_ethread()); @@ -109,7 +109,7 @@ QUICCongestionController::_congestion_event(ink_hrtime sent_time, uint32_t pto_c // the original one is: // ProcessECN(ack): void -QUICCongestionController::process_ecn(const PacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section, +QUICCongestionController::process_ecn(const QUICPacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section, uint32_t pto_count) { // If the ECN-CE counter reported by the peer has increased, @@ -127,7 +127,7 @@ QUICCongestionController::process_ecn(const PacketInfo &acked_largest_packet, co // the original one is: // OnPacketsLost(lost_packets): void -QUICCongestionController::on_packets_lost(const std::map &lost_packets, uint32_t pto_count) +QUICCongestionController::on_packets_lost(const std::map &lost_packets, uint32_t pto_count) { if (lost_packets.empty()) { return; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 169da3eb1c4..4cb727c6094 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -131,20 +131,35 @@ QUICLossDetector::largest_acked_packet_number() } void -QUICLossDetector::on_packet_sent(QUICPacket &packet, bool in_flight) +QUICLossDetector::on_packet_sent(QUICPacketInfoUPtr packet_info, bool in_flight) { - if (packet.type() == QUICPacketType::VERSION_NEGOTIATION) { + if (packet_info->type == QUICPacketType::VERSION_NEGOTIATION) { return; } this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); - auto packet_number = packet.packet_number(); - auto ack_eliciting = packet.is_ack_eliciting(); - auto crypto = packet.is_crypto_packet(); - auto sent_bytes = packet.size(); - auto type = packet.type(); - auto frames = std::move(packet.frames()); - this->_on_packet_sent(packet_number, ack_eliciting, in_flight, crypto, sent_bytes, type, frames); + + SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); + + bool ack_eliciting = packet_info->ack_eliciting; + bool is_crypto_packet = packet_info->is_crypto_packet; + ink_hrtime now = packet_info->time_sent; + size_t sent_bytes = packet_info->sent_bytes; + this->_largest_sent_packet = packet_info->packet_number; + + this->_add_to_sent_packet_list(packet_info->packet_number, std::move(packet_info)); + + if (in_flight) { + if (is_crypto_packet) { + this->_time_of_last_sent_crypto_packet = now; + } + + if (ack_eliciting) { + this->_time_of_last_sent_ack_eliciting_packet = now; + } + this->_cc->on_packet_sent(sent_bytes); + this->_set_loss_detection_timer(); + } } void @@ -177,30 +192,6 @@ QUICLossDetector::update_ack_delay_exponent(uint8_t ack_delay_exponent) this->_ack_delay_exponent = ack_delay_exponent; } -void -QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool ack_eliciting, bool in_flight, bool is_crypto_packet, - size_t sent_bytes, QUICPacketType type, std::vector &frames) -{ - SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - ink_hrtime now = Thread::get_hrtime(); - this->_largest_sent_packet = packet_number; - PacketInfoUPtr packet_info = PacketInfoUPtr(new PacketInfo( - {packet_number, now, ack_eliciting, is_crypto_packet, in_flight, ack_eliciting ? sent_bytes : 0, type, std::move(frames)})); - - this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); - if (in_flight) { - if (is_crypto_packet) { - this->_time_of_last_sent_crypto_packet = now; - } - - if (ack_eliciting) { - this->_time_of_last_sent_ack_eliciting_packet = now; - } - this->_cc->on_packet_sent(sent_bytes); - this->_set_loss_detection_timer(); - } -} - void QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame) { @@ -283,7 +274,7 @@ QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay) } void -QUICLossDetector::_on_packet_acked(const PacketInfo &acked_packet) +QUICLossDetector::_on_packet_acked(const QUICPacketInfo &acked_packet) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number); @@ -397,7 +388,7 @@ QUICLossDetector::_detect_lost_packets() SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); this->_loss_time = 0; ink_hrtime loss_delay = this->_k_time_threshold * std::max(this->_latest_rtt, this->_smoothed_rtt); - std::map lost_packets; + std::map lost_packets; // Packets sent before this time are deemed lost. ink_hrtime lost_send_time = Thread::get_hrtime() - loss_delay; @@ -458,7 +449,7 @@ QUICLossDetector::_retransmit_all_unacked_crypto_data() { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); std::set retransmitted_crypto_packets; - std::map lost_packets; + std::map lost_packets; for (auto &info : this->_sent_packets) { if (info.second->is_crypto_packet) { @@ -484,7 +475,7 @@ QUICLossDetector::_send_two_packets() // ===== Functions below are helper functions ===== void -QUICLossDetector::_retransmit_lost_packet(PacketInfo &packet_info) +QUICLossDetector::_retransmit_lost_packet(QUICPacketInfo &packet_info) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); @@ -516,12 +507,12 @@ QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame) } void -QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, PacketInfoUPtr packet_info) +QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, QUICPacketInfoUPtr packet_info) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // Add to the list - this->_sent_packets.insert(std::pair(packet_number, std::move(packet_info))); + this->_sent_packets.insert(std::pair(packet_number, std::move(packet_info))); // Increment counters auto ite = this->_sent_packets.find(packet_number); @@ -547,8 +538,8 @@ QUICLossDetector::_remove_from_sent_packet_list(QUICPacketNumber packet_number) this->_sent_packets.erase(packet_number); } -std::map::iterator -QUICLossDetector::_remove_from_sent_packet_list(std::map::iterator it) +std::map::iterator +QUICLossDetector::_remove_from_sent_packet_list(std::map::iterator it) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); @@ -557,7 +548,7 @@ QUICLossDetector::_remove_from_sent_packet_list(std::map::iterator it) +QUICLossDetector::_decrement_outstanding_counters(std::map::iterator it) { if (it != this->_sent_packets.end()) { // Decrement counters diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 63e344874f3..10610236ac9 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -39,7 +39,7 @@ class QUICLossDetector; -struct PacketInfo { +struct QUICPacketInfo { // 6.3.1. Sent Packet Fields QUICPacketNumber packet_number; ink_hrtime time_sent; @@ -54,7 +54,7 @@ struct PacketInfo { // end }; -using PacketInfoUPtr = std::unique_ptr; +using QUICPacketInfoUPtr = std::unique_ptr; class QUICRTTProvider { @@ -78,10 +78,10 @@ class QUICCongestionController QUICCongestionController(QUICConnectionInfoProvider *info); virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); - void on_packet_acked(const PacketInfo &acked_packet); - virtual void on_packets_lost(const std::map &packets, uint32_t pto_count); + void on_packet_acked(const QUICPacketInfo &acked_packet); + virtual void on_packets_lost(const std::map &packets, uint32_t pto_count); void on_retransmission_timeout_verified(); - void process_ecn(const PacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section, uint32_t pto_count); + void process_ecn(const QUICPacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section, uint32_t pto_count); bool check_credit() const; uint32_t open_window() const; void reset(); @@ -126,7 +126,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler std::vector interests() override; virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; - void on_packet_sent(QUICPacket &packet, bool in_flight = true); + void on_packet_sent(QUICPacketInfoUPtr packet_info, bool in_flight = true); QUICPacketNumber largest_acked_packet_number(); void update_ack_delay_exponent(uint8_t ack_delay_exponent); void reset(); @@ -159,17 +159,17 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler ink_hrtime _min_rtt = INT64_MAX; ink_hrtime _max_ack_delay = 0; ink_hrtime _loss_time = 0; - std::map _sent_packets; + std::map _sent_packets; // These are not defined on the spec but expected to be count // These counter have to be updated when inserting / erasing packets from _sent_packets with following functions. std::atomic _crypto_outstanding; std::atomic _ack_eliciting_outstanding; - void _add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr packet_info); + void _add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr packet_info); void _remove_from_sent_packet_list(QUICPacketNumber packet_number); - std::map::iterator _remove_from_sent_packet_list( - std::map::iterator it); - void _decrement_outstanding_counters(std::map::iterator it); + std::map::iterator _remove_from_sent_packet_list( + std::map::iterator it); + void _decrement_outstanding_counters(std::map::iterator it); /* * Because this alarm will be reset on every packet transmission, to reduce number of events, @@ -177,15 +177,13 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler */ ink_hrtime _loss_detection_alarm_at = 0; - void _on_packet_sent(QUICPacketNumber packet_number, bool ack_eliciting, bool in_flight, bool is_crypto_packet, size_t sent_bytes, - QUICPacketType type, std::vector &frames); void _on_ack_received(const QUICAckFrame &ack_frame); - void _on_packet_acked(const PacketInfo &acked_packet); + void _on_packet_acked(const QUICPacketInfo &acked_packet); void _update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay); void _detect_lost_packets(); void _set_loss_detection_timer(); void _on_loss_detection_timeout(); - void _retransmit_lost_packet(PacketInfo &packet_info); + void _retransmit_lost_packet(QUICPacketInfo &packet_info); std::set _determine_newly_acked_packets(const QUICAckFrame &ack_frame); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index c5e640aeae5..a78351ce2f5 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -776,20 +776,6 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const QUICTypeUtil::write_QUICPacketNumberLen(n, buf); } -// -// QUICTrackablePacket -// -QUICTrackablePacket::QUICTrackablePacket(std::vector &frames) -{ - this->_frames = std::move(frames); -} - -std::vector & -QUICTrackablePacket::frames() -{ - return this->_frames; -} - // // QUICPacket // @@ -803,14 +789,6 @@ QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size this->_payload_size = payload_len; } -QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, std::vector &frames) - : QUICTrackablePacket(frames) -{ - this->_header = std::move(header); - this->_payload = std::move(payload); - this->_payload_size = payload_len; -} - QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool ack_eliciting, bool probing) { this->_header = std::move(header); @@ -820,17 +798,6 @@ QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size this->_is_probing_packet = probing; } -QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, bool ack_eliciting, bool probing, - std::vector &frames) - : QUICTrackablePacket(frames) -{ - this->_header = std::move(header); - this->_payload = std::move(payload); - this->_payload_size = payload_len; - this->_is_ack_eliciting = ack_eliciting; - this->_is_probing_packet = probing; -} - QUICPacket::~QUICPacket() { this->_header = nullptr; diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 3b1bd6d9fbc..09d5ce3d949 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -51,18 +51,6 @@ extern ClassAllocator quicPacketShortHeaderAllocator; using QUICPacketHeaderDeleterFunc = void (*)(QUICPacketHeader *p); using QUICPacketHeaderUPtr = std::unique_ptr; -class QUICTrackablePacket -{ -public: - virtual ~QUICTrackablePacket() {} - std::vector &frames(); - -protected: - QUICTrackablePacket() {} - QUICTrackablePacket(std::vector &frames); - std::vector _frames; -}; - class QUICPacketHeader { public: @@ -321,7 +309,7 @@ class QUICPacketHeaderDeleter } }; -class QUICPacket : public QUICTrackablePacket +class QUICPacket { public: QUICPacket(); diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc index ec4c98fc6fa..19587d35866 100644 --- a/iocore/net/quic/QUICPacketFactory.cc +++ b/iocore/net/quic/QUICPacketFactory.cc @@ -198,15 +198,14 @@ QUICPacketFactory::create_version_negotiation_packet(QUICConnectionId dcid, QUIC 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, std::vector &frames, - ats_unique_buf token, size_t token_len) + bool retransmittable, bool probing, bool crypto, ats_unique_buf token, size_t token_len) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); QUICPacketNumber pn = this->_packet_number_generator[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, frames); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing); } QUICPacketUPtr @@ -225,40 +224,39 @@ QUICPacketFactory::create_retry_packet(QUICConnectionId destination_cid, QUICCon 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, std::vector &frames) + bool retransmittable, bool probing, bool crypto) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::HANDSHAKE); QUICPacketNumber pn = this->_packet_number_generator[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, frames); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing); } 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, std::vector &frames) + bool retransmittable, bool probing) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ZERO_RTT); QUICPacketNumber pn = this->_packet_number_generator[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, frames); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing); } QUICPacketUPtr QUICPacketFactory::create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, - ats_unique_buf payload, size_t len, bool retransmittable, bool probing, - std::vector &frames) + ats_unique_buf payload, size_t len, bool retransmittable, bool probing) { int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ONE_RTT); QUICPacketNumber pn = this->_packet_number_generator[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, frames); + return this->_create_encrypted_packet(std::move(header), retransmittable, probing); } QUICPacketUPtr @@ -298,8 +296,7 @@ QUICPacketFactory::_create_unprotected_packet(QUICPacketHeaderUPtr header) } QUICPacketUPtr -QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing, - std::vector &frames) +QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing) { // TODO: use pmtu of UnixNetVConnection size_t max_cipher_txt_len = 2048; @@ -315,7 +312,7 @@ QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool re if (this->_pp_protector.protect(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), header->packet_number(), header->buf(), header->size(), header->key_phase())) { packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable, probing, frames); + new (packet) QUICPacket(std::move(header), std::move(cipher_txt), cipher_txt_len, retransmittable, probing); } else { QUICDebug(dcid, scid, "Failed to encrypt a packet"); } diff --git a/iocore/net/quic/QUICPacketFactory.h b/iocore/net/quic/QUICPacketFactory.h index a62be5985f8..ec4b42f4934 100644 --- a/iocore/net/quic/QUICPacketFactory.h +++ b/iocore/net/quic/QUICPacketFactory.h @@ -56,17 +56,16 @@ class QUICPacketFactory 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, std::vector &frame, - ats_unique_buf token = ats_unique_buf(nullptr), size_t token_len = 0); + 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, - bool ack_eliciting, bool probing, bool crypto, std::vector &frames); + 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, std::vector &frames); + 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, - std::vector &frames); + ats_unique_buf payload, size_t len, bool ack_eliciting, bool probing); void set_version(QUICVersion negotiated_version); bool is_ready_to_create_protected_packet(); @@ -82,6 +81,5 @@ class QUICPacketFactory QUICPacketNumberGenerator _packet_number_generator[3]; static QUICPacketUPtr _create_unprotected_packet(QUICPacketHeaderUPtr header); - QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool ack_eliciting, bool probing, - std::vector &frames); + QUICPacketUPtr _create_encrypted_packet(QUICPacketHeaderUPtr header, bool ack_eliciting, bool probing); }; diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 05b8953780d..814e94fb9e5 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -43,7 +43,6 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") size_t payload_len = 512; QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); QUICAckFrame *frame = nullptr; - std::vector dummy_frames; SECTION("Handshake") { @@ -68,7 +67,14 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") false, std::move(payload), sizeof(raw)); QUICPacketUPtr packet = QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true, false), [](QUICPacket *p) { delete p; }); - detector.on_packet_sent(*packet); + detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet->packet_number(), + Thread::get_hrtime(), + packet->is_ack_eliciting(), + packet->is_crypto_packet(), + true, + packet->size(), + packet->type(), + {}})); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); CHECK(g.lost_frame_count >= 0); @@ -87,34 +93,34 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") // Send packet (1) to (7) payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false, dummy_frames); + payload_len, true, false); payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet2 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false, dummy_frames); + payload_len, true, false); payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet3 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false, dummy_frames); + payload_len, true, false); payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet4 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false, dummy_frames); + payload_len, true, false); payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet5 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false, dummy_frames); + payload_len, true, false); payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet6 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false, dummy_frames); + payload_len, true, false); payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet7 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false, dummy_frames); + payload_len, true, false); payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet8 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false, dummy_frames); + payload_len, true, false); payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet9 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false, dummy_frames); + payload_len, true, false); payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet10 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false, dummy_frames); + payload_len, true, false); QUICPacketNumber pn1 = packet1->packet_number(); QUICPacketNumber pn2 = packet2->packet_number(); @@ -127,16 +133,87 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") QUICPacketNumber pn9 = packet9->packet_number(); QUICPacketNumber pn10 = packet10->packet_number(); - detector.on_packet_sent(*packet1); - detector.on_packet_sent(*packet2); - detector.on_packet_sent(*packet3); - detector.on_packet_sent(*packet4); - detector.on_packet_sent(*packet5); - detector.on_packet_sent(*packet6); - detector.on_packet_sent(*packet7); - detector.on_packet_sent(*packet8); - detector.on_packet_sent(*packet9); - detector.on_packet_sent(*packet10); + QUICPacketInfoUPtr packet_info = nullptr; + detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet1->packet_number(), + Thread::get_hrtime(), + packet1->is_ack_eliciting(), + packet1->is_crypto_packet(), + true, + packet1->size(), + packet1->type(), + {}})); + detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet2->packet_number(), + Thread::get_hrtime(), + packet2->is_ack_eliciting(), + packet2->is_crypto_packet(), + true, + packet2->size(), + packet2->type(), + {}})); + detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet3->packet_number(), + Thread::get_hrtime(), + packet3->is_ack_eliciting(), + packet3->is_crypto_packet(), + true, + packet3->size(), + packet3->type(), + {}})); + detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet4->packet_number(), + Thread::get_hrtime(), + packet4->is_ack_eliciting(), + packet4->is_crypto_packet(), + true, + packet4->size(), + packet4->type(), + {}})); + detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet5->packet_number(), + Thread::get_hrtime(), + packet5->is_ack_eliciting(), + packet5->is_crypto_packet(), + true, + packet5->size(), + packet5->type(), + {}})); + detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet6->packet_number(), + Thread::get_hrtime(), + packet6->is_ack_eliciting(), + packet6->is_crypto_packet(), + true, + packet6->size(), + packet6->type(), + {}})); + detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet7->packet_number(), + Thread::get_hrtime(), + packet6->is_ack_eliciting(), + packet7->is_crypto_packet(), + true, + packet7->size(), + packet7->type(), + {}})); + detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet8->packet_number(), + Thread::get_hrtime(), + packet6->is_ack_eliciting(), + packet8->is_crypto_packet(), + true, + packet8->size(), + packet8->type(), + {}})); + detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet9->packet_number(), + Thread::get_hrtime(), + packet6->is_ack_eliciting(), + packet9->is_crypto_packet(), + true, + packet9->size(), + packet9->type(), + {}})); + detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet10->packet_number(), + Thread::get_hrtime(), + packet10->is_ack_eliciting(), + packet10->is_crypto_packet(), + true, + packet10->size(), + packet10->type(), + {}})); ink_hrtime_sleep(HRTIME_MSECONDS(2000)); // Receive an ACK for (1) (4) (5) (7) (8) (9) diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 5b3936ca844..c93870a5590 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -87,7 +87,6 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") MockQUICPacketProtectionKeyInfo pp_key_info; QUICPacketFactory factory(pp_key_info); factory.set_version(0x11223344); - std::vector dummy_frames; uint8_t raw[] = {0xaa, 0xbb, 0xcc, 0xdd}; ats_unique_buf payload = ats_unique_malloc(sizeof(raw)); @@ -96,7 +95,7 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") QUICPacketUPtr packet = factory.create_handshake_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), 0, - std::move(payload), sizeof(raw), true, false, true, dummy_frames); + std::move(payload), sizeof(raw), true, false, true); CHECK(packet->type() == QUICPacketType::HANDSHAKE); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) != 0); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 24b607cfd07..9a1b9c8b660 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -34,7 +34,6 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") QUICVersionNegotiator vn; ats_unique_buf dummy_payload = ats_unique_malloc(128); size_t dummy_payload_len = 128; - std::vector dummy_frames; SECTION("Normal case") { @@ -44,7 +43,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true, dummy_frames); + packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -63,7 +62,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true, dummy_frames); + packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -82,7 +81,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSION); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true, dummy_frames); + packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true); vn.negotiate(initial_packet.get()); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); @@ -101,7 +100,6 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") QUICVersionNegotiator vn; ats_unique_buf dummy_payload = ats_unique_malloc(128); size_t dummy_payload_len = 128; - std::vector dummy_frames; SECTION("Normal case") { @@ -127,7 +125,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") // Negotiate version packet_factory.set_version(QUIC_EXERCISE_VERSION); QUICPacketUPtr initial_packet = - packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true, dummy_frames); + packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true); // Server send VN packet based on Initial packet QUICPacketUPtr vn_packet = From c5c1378ce20cd7b092dcd51ba31509e086445bb5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 8 Mar 2019 11:28:20 +0900 Subject: [PATCH 1193/1313] Fix a nullptr dereference --- iocore/net/QUICNetVConnection.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index db860466f1f..3b7245244c0 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1199,19 +1199,19 @@ QUICNetVConnection::_state_common_send_packet() QUICPacketInfoUPtr packet_info = std::make_unique(); QUICPacketUPtr packet = this->_packetize_frames(level, max_packet_size, packet_info->frames); - 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; - if (packet_info->ack_eliciting) { - packet_info->sent_bytes = packet->size(); - } else { - packet_info->sent_bytes = 0; - } - packet_info->type = packet->type(); - 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; + if (packet_info->ack_eliciting) { + packet_info->sent_bytes = packet->size(); + } else { + packet_info->sent_bytes = 0; + } + packet_info->type = packet->type(); + 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()); From e8eb00b0ce9987f4538542edfad111240853400d Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 11 Mar 2019 10:23:04 +0800 Subject: [PATCH 1194/1313] QUIC: Fixed compiler error in test_QUICStream --- iocore/net/quic/Makefile.am | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index ceddc268b00..ae4a93a68c8 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -122,15 +122,14 @@ test_CPPFLAGS = \ -I$(abs_top_srcdir)/tests/include test_LDADD = \ + $(top_builddir)/iocore/net/libinknet.a \ libquic.a \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/src/tscore/libtscore.la \ $(top_builddir)/src/tscpp/util/libtscpputil.la \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/iocore/net/libinknet.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a \ + $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ @HWLOC_LIBS@ @OPENSSL_LIBS@ @LIBPCRE@ @YAMLCPP_LIBS@ From 9533aede1b808ba16d3b31d4af78a0cf465adff2 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 11 Mar 2019 10:43:36 +0800 Subject: [PATCH 1195/1313] QUIC: Fixed test_QUICLossDetector crash --- iocore/net/quic/QUICLossDetector.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 4cb727c6094..7f9915e5e82 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -141,13 +141,14 @@ QUICLossDetector::on_packet_sent(QUICPacketInfoUPtr packet_info, bool in_flight) SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - bool ack_eliciting = packet_info->ack_eliciting; - bool is_crypto_packet = packet_info->is_crypto_packet; - ink_hrtime now = packet_info->time_sent; - size_t sent_bytes = packet_info->sent_bytes; - this->_largest_sent_packet = packet_info->packet_number; - - this->_add_to_sent_packet_list(packet_info->packet_number, std::move(packet_info)); + QUICPacketNumber packet_number = packet_info->packet_number; + bool ack_eliciting = packet_info->ack_eliciting; + bool is_crypto_packet = packet_info->is_crypto_packet; + ink_hrtime now = packet_info->time_sent; + size_t sent_bytes = packet_info->sent_bytes; + this->_largest_sent_packet = packet_info->packet_number; + + this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); if (in_flight) { if (is_crypto_packet) { From d0c9aed68f83519b8b9c9a385f031089bdbf8eed Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 11 Mar 2019 11:16:15 +0800 Subject: [PATCH 1196/1313] QUIC: Bring back retransmittion test case --- iocore/net/quic/QUICFrameRetransmitter.cc | 6 ++++ iocore/net/quic/QUICFrameRetransmitter.h | 1 + iocore/net/quic/QUICStream.cc | 5 +-- iocore/net/quic/test/test_QUICStream.cc | 40 +++++++++++++---------- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/iocore/net/quic/QUICFrameRetransmitter.cc b/iocore/net/quic/QUICFrameRetransmitter.cc index 008b72c161b..bedc6548bcb 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.cc +++ b/iocore/net/quic/QUICFrameRetransmitter.cc @@ -175,3 +175,9 @@ QUICFrameRetransmitter::_create_crypto_frame(uint8_t *buf, QUICFrameInformationU ink_assert(frame != nullptr); return frame; } + +bool +QUICFrameRetransmitter::is_retransmited_frame_queue_empty() const +{ + return this->_lost_frame_info_queue.empty(); +} diff --git a/iocore/net/quic/QUICFrameRetransmitter.h b/iocore/net/quic/QUICFrameRetransmitter.h index bbd53c3bec9..9f45dd5b959 100644 --- a/iocore/net/quic/QUICFrameRetransmitter.h +++ b/iocore/net/quic/QUICFrameRetransmitter.h @@ -74,6 +74,7 @@ class QUICFrameRetransmitter virtual QUICFrame *create_retransmitted_frame(uint8_t *buf, QUICEncryptionLevel level, uint16_t maximum_frame_size, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr); virtual void save_frame_info(QUICFrameInformationUPtr info); + bool is_retransmited_frame_queue_empty() const; private: QUICFrame *_create_stream_frame(uint8_t *buf, QUICFrameInformationUPtr &info, uint16_t maximum_frame_size, diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 1e977b7275f..9c087658256 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -585,7 +585,8 @@ QUICBidirectionalStream::reenable(VIO *vio) bool QUICBidirectionalStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { - return this->_local_flow_controller.will_generate_frame(level, timestamp) || (this->_write_vio.get_reader()->read_avail() > 0); + return this->_local_flow_controller.will_generate_frame(level, timestamp) || !this->is_retransmited_frame_queue_empty() || + (this->_write_vio.get_reader()->read_avail() > 0); } QUICFrame * @@ -914,7 +915,7 @@ QUICCryptoStream::write(const uint8_t *buf, int64_t len) bool QUICCryptoStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { - return this->_write_buffer_reader->is_read_avail_more_than(0); + return this->_write_buffer_reader->is_read_avail_more_than(0) || !this->is_retransmited_frame_queue_empty(); } /** diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 468e73cfab8..46374d0e45e 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -301,49 +301,55 @@ TEST_CASE("QUICStream", "[quic]") /* * This test does not pass now - * + */ SECTION("Retransmit STREAM frame") { - MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); + MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); MockQUICRTTProvider rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; - std::unique_ptr stream(new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, - UINT64_MAX, UINT64_MAX)); SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); + std::unique_ptr stream( + new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); + SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); MockContinuation mock_cont(stream->mutex); stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; - const char data1[] = "this is a test data"; - const char data2[] = "THIS IS ANOTHER TEST DATA"; - QUICFrameUPtr frame = QUICFrameFactory::create_null_frame(); - - QUICFrameUPtr frame1 = QUICFrameFactory::create_null_frame(); - QUICFrameUPtr frame2 = QUICFrameFactory::create_null_frame(); + const char data1[] = "this is a test data"; + const char data2[] = "THIS IS ANOTHER TEST DATA"; + QUICFrame *frame = nullptr; + QUICStreamFrame *frame1 = nullptr; + QUICStreamFrame *frame2 = nullptr; + uint8_t frame_buf2[QUICFrame::MAX_INSTANCE_SIZE]; // Write data1 - write_buffer->write(data1, 1024); + write_buffer->write(data1, sizeof(data1)); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); // Generate STREAM frame - frame1 = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + frame1 = static_cast(frame); CHECK(frame->type() == QUICFrameType::STREAM); - CHECK(stream->generate_frame(level, 4096, 4096) == nullptr); + CHECK(stream->generate_frame(frame_buf, level, 4096, 4096, 0) == nullptr); + CHECK(stream->will_generate_frame(level, 0) == false); + stream->on_frame_lost(frame->id()); + CHECK(stream->will_generate_frame(level, 0) == true); + // Write data2 - write_buffer->write(data1, 1024); + write_buffer->write(data2, sizeof(data2)); stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); // Lost the frame stream->on_frame_lost(frame->id()); // Regenerate a frame - frame2 = stream->generate_frame(level, 4096, 4096); + frame = stream->generate_frame(frame_buf2, level, 4096, 4096, 0); // Lost data should be resent first + frame2 = static_cast(frame); CHECK(frame->type() == QUICFrameType::STREAM); CHECK(frame1->offset() == frame2->offset()); CHECK(frame1->data_length() == frame2->data_length()); - CHECK(memcmp(frame1->data(), frame2->data(), frame1->data_length()); + CHECK(memcmp(frame1->data(), frame2->data(), frame1->data_length())); } - */ SECTION("Retransmit RESET_STREAM frame") { From 2f0858e06d40d8315daad4b556eb5727295060fa Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 11 Mar 2019 13:27:57 +0900 Subject: [PATCH 1197/1313] Fix unit tests for HTTP/3 --- proxy/http3/Makefile.am | 56 +++++++++----------- proxy/http3/test/stub.cc | 94 ---------------------------------- proxy/http3/test/test_QPACK.cc | 6 ++- 3 files changed, 27 insertions(+), 129 deletions(-) delete mode 100644 proxy/http3/test/stub.cc diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index b8d8920abe2..324d88ece2e 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -62,57 +62,47 @@ check_PROGRAMS = \ TESTS = $(check_PROGRAMS) -test_libhttp3_CPPFLAGS = \ +test_CPPFLAGS = \ $(AM_CPPFLAGS) \ + -I$(abs_top_srcdir)/proxy/logging \ -I$(abs_top_srcdir)/tests/include -test_libhttp3_LDFLAGS = \ - @AM_LDFLAGS@ +test_LDADD = \ + libhttp3.a \ + $(top_builddir)/iocore/net/libinknet.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/src/tscore/libtscore.la \ + $(top_builddir)/src/tscpp/util/libtscpputil.la \ + $(top_builddir)/lib/tsconfig/libtsconfig.la \ + $(top_builddir)/proxy/ParentSelectionStrategy.o \ + $(top_builddir)/proxy/libproxy.a \ + $(top_builddir)/proxy/hdrs/libhdrs.a +test_libhttp3_CPPFLAGS = $(test_CPPFLAGS) +test_libhttp3_LDFLAGS = @AM_LDFLAGS@ +test_libhttp3_LDADD = $(test_LDADD) test_libhttp3_SOURCES = \ ./test/main.cc \ ./test/test_Http3Frame.cc \ ../http/HttpConfig.cc \ ../http/HttpConnectionCount.cc \ ../http/ForwardedConfig.cc \ - ./test/stub.cc - -test_libhttp3_LDADD = \ - libhttp3.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/src/tscore/libtscore.la \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/proxy/libproxy.a \ - $(top_builddir)/proxy/hdrs/libhdrs.a \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a - -test_qpack_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - -I$(abs_top_srcdir)/tests/include - -test_qpack_LDFLAGS = \ - @AM_LDFLAGS@ + ../../iocore/net/libinknet_stub.cc +test_qpack_CPPFLAGS = $(test_CPPFLAGS) +test_qpack_LDFLAGS = @AM_LDFLAGS@ +test_qpack_LDADD = $(test_LDADD) test_qpack_SOURCES = \ ./test/main_qpack.cc \ ./test/test_QPACK.cc \ ../http/HttpConfig.cc \ ../http/HttpConnectionCount.cc \ ../http/ForwardedConfig.cc \ - ./test/stub.cc + ../../iocore/net/libinknet_stub.cc -test_qpack_LDADD = \ - libhttp3.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/src/tscore/libtscore.la \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/proxy/libproxy.a \ - $(top_builddir)/proxy/hdrs/libhdrs.a \ - $(top_builddir)/proxy/shared/libUglyLogStubs.a # # clang-tidy diff --git a/proxy/http3/test/stub.cc b/proxy/http3/test/stub.cc deleted file mode 100644 index 6e821003a93..00000000000 --- a/proxy/http3/test/stub.cc +++ /dev/null @@ -1,94 +0,0 @@ -/** @file - * - * Stubs for QUICConfig - * - * @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/ink_assert.h" - -#include "P_SSLConfig.h" - -void -SSLConfigInit(IpMap *) -{ - return; -} - -bool -SSLParseCertificateConfiguration(const SSLConfigParams *, SSL_CTX *) -{ - return false; -} - -SSLConfigParams * -SSLConfig::acquire() -{ - return nullptr; -} - -void -SSLConfig::release(SSLConfigParams *) -{ - return; -} - -#include "P_SSLNextProtocolSet.h" - -bool -SSLNextProtocolSet::advertiseProtocols(const unsigned char **out, unsigned *len) const -{ - return true; -} - -#include "InkAPIInternal.h" -int -APIHook::invoke(int, void *) -{ - ink_assert(false); - return 0; -} - -APIHook * -APIHook::next() const -{ - ink_assert(false); - return nullptr; -} - -APIHook * -APIHooks::get() const -{ - ink_assert(false); - return nullptr; -} - -void -APIHooks::clear() -{ -} - -void -APIHooks::prepend(INKContInternal *cont) -{ -} - -void -APIHooks::append(INKContInternal *cont) -{ -} diff --git a/proxy/http3/test/test_QPACK.cc b/proxy/http3/test/test_QPACK.cc index c2a1311c8ce..1d076fbc6e6 100644 --- a/proxy/http3/test/test_QPACK.cc +++ b/proxy/http3/test/test_QPACK.cc @@ -64,10 +64,12 @@ class QUICApplicationDriver TestQUICConnection _connection; }; -class TestQUICStream : public QUICStream +// TODO: QUICUnidirectionalStream should be used if there +class TestQUICStream : public QUICBidirectionalStream { public: - TestQUICStream(QUICStreamId sid) : QUICStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), sid, 65536, 65536) + TestQUICStream(QUICStreamId sid) + : QUICBidirectionalStream(new MockQUICRTTProvider(), new MockQUICConnectionInfoProvider(), sid, 65536, 65536) { } From 24df75e9748f73a4cb8858f6c552909e0406da01 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 11 Mar 2019 11:20:14 +0900 Subject: [PATCH 1198/1313] Decouple HTTP/0.9 and HTTP/3 Add Http09ClientSession and Http09ClientTransaction to clarify HTTP/0.9 and HTTP/3 code. HTTP/0.9 and HTTP/3 is completely switched by ALPN (hq-* vs h3-*). --- proxy/http3/Http09App.cc | 8 +- proxy/http3/Http09App.h | 4 +- proxy/http3/Http3App.cc | 4 +- proxy/http3/Http3ClientSession.cc | 146 ++++-- proxy/http3/Http3ClientSession.h | 64 ++- proxy/http3/Http3ClientTransaction.cc | 724 ++++++++++++++++---------- proxy/http3/Http3ClientTransaction.h | 92 +++- 7 files changed, 666 insertions(+), 376 deletions(-) diff --git a/proxy/http3/Http09App.cc b/proxy/http3/Http09App.cc index f89d0bb45b9..1168b5a022e 100644 --- a/proxy/http3/Http09App.cc +++ b/proxy/http3/Http09App.cc @@ -35,7 +35,7 @@ static constexpr char debug_tag_v[] = "v_quic_simple_app"; Http09App::Http09App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QUICApplication(client_vc) { - this->_client_session = new Http3ClientSession(client_vc); + this->_client_session = new Http09ClientSession(client_vc); this->_client_session->acl = std::move(session_acl); this->_client_session->new_connection(client_vc, nullptr, nullptr); @@ -62,8 +62,8 @@ Http09App::main_event_handler(int event, Event *data) return -1; } - QUICStreamId stream_id = stream_io->stream_id(); - Http3ClientTransaction *txn = this->_client_session->get_transaction(stream_id); + QUICStreamId stream_id = stream_io->stream_id(); + Http09ClientTransaction *txn = static_cast(this->_client_session->get_transaction(stream_id)); uint8_t dummy; switch (event) { @@ -75,7 +75,7 @@ Http09App::main_event_handler(int event, Event *data) } if (stream_io->peek(&dummy, 1)) { if (txn == nullptr) { - txn = new Http3ClientTransaction(this->_client_session, stream_io); + txn = new Http09ClientTransaction(this->_client_session, stream_io); SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); txn->new_transaction(); diff --git a/proxy/http3/Http09App.h b/proxy/http3/Http09App.h index 1132ef29eec..b3356a0549f 100644 --- a/proxy/http3/Http09App.h +++ b/proxy/http3/Http09App.h @@ -28,7 +28,7 @@ #include "QUICApplication.h" class QUICNetVConnection; -class Http3ClientSession; +class Http09ClientSession; /** * @brief A simple multi-streamed application. @@ -45,5 +45,5 @@ class Http09App : public QUICApplication int main_event_handler(int event, Event *data); private: - Http3ClientSession *_client_session = nullptr; + Http09ClientSession *_client_session = nullptr; }; diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 9b034b66078..7b34fa2ef59 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -196,7 +196,7 @@ Http3App::_handle_bidi_stream_on_read_ready(int event, QUICStreamIO *stream_io) uint8_t dummy; if (stream_io->peek(&dummy, 1)) { QUICStreamId stream_id = stream_io->stream_id(); - Http3ClientTransaction *txn = this->_client_session->get_transaction(stream_id); + Http3ClientTransaction *txn = static_cast(this->_client_session->get_transaction(stream_id)); if (txn == nullptr) { txn = new Http3ClientTransaction(this->_client_session, stream_io); @@ -261,7 +261,7 @@ void Http3App::_handle_bidi_stream_on_write_ready(int event, QUICStreamIO *stream_io) { QUICStreamId stream_id = stream_io->stream_id(); - Http3ClientTransaction *txn = this->_client_session->get_transaction(stream_id); + Http3ClientTransaction *txn = static_cast(this->_client_session->get_transaction(stream_id)); if (txn != nullptr) { SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); txn->handleEvent(event); diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3ClientSession.cc index 2038e780322..3fdd13d2a0f 100644 --- a/proxy/http3/Http3ClientSession.cc +++ b/proxy/http3/Http3ClientSession.cc @@ -25,103 +25,134 @@ #include "Http3.h" -Http3ClientSession::Http3ClientSession(NetVConnection *vc) : _client_vc(vc) +// +// HQClientSession +// +HQClientSession ::~HQClientSession() { - this->_local_qpack = new QPACK(static_cast(vc), HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE, - HTTP3_DEFAULT_HEADER_TABLE_SIZE, HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS); - this->_remote_qpack = new QPACK(static_cast(vc), HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE, - HTTP3_DEFAULT_HEADER_TABLE_SIZE, HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS); + for (HQClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { + delete t; + } } -Http3ClientSession::~Http3ClientSession() +void +HQClientSession::add_transaction(HQClientTransaction *trans) { - this->_client_vc = nullptr; - for (Http3ClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { - delete t; + this->_transaction_list.enqueue(trans); + + return; +} + +HQClientTransaction * +HQClientSession::get_transaction(QUICStreamId id) +{ + for (HQClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { + if (t->get_transaction_id() == static_cast(id)) { + return t; + } } - delete this->_local_qpack; - delete this->_remote_qpack; + + return nullptr; } VIO * -Http3ClientSession::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +HQClientSession::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) { ink_assert(false); return nullptr; } VIO * -Http3ClientSession::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +HQClientSession::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) { ink_assert(false); return nullptr; } void -Http3ClientSession::do_io_close(int lerrno) +HQClientSession::do_io_close(int lerrno) { // TODO return; } void -Http3ClientSession::do_io_shutdown(ShutdownHowTo_t howto) +HQClientSession::do_io_shutdown(ShutdownHowTo_t howto) { ink_assert(false); return; } void -Http3ClientSession::reenable(VIO *vio) +HQClientSession::reenable(VIO *vio) { ink_assert(false); return; } void -Http3ClientSession::destroy() +HQClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reade) { - ink_assert(false); + this->con_id = static_cast(reinterpret_cast(new_vc))->connection_id(); + return; } void -Http3ClientSession::start() +HQClientSession::start() { ink_assert(false); return; } void -Http3ClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reade) +HQClientSession::destroy() { - this->con_id = static_cast(reinterpret_cast(new_vc))->connection_id(); + ink_assert(false); + return; +} +void +HQClientSession::release(ProxyClientTransaction *trans) +{ return; } NetVConnection * -Http3ClientSession::get_netvc() const +HQClientSession::get_netvc() const { return this->_client_vc; } int -Http3ClientSession::get_transact_count() const +HQClientSession::get_transact_count() const { return 0; } -const char * -Http3ClientSession::get_protocol_string() const +// +// Http3ClientSession +// +Http3ClientSession::Http3ClientSession(NetVConnection *vc) : HQClientSession(vc) { - return IP_PROTO_TAG_HTTP_QUIC.data(); + this->_local_qpack = new QPACK(static_cast(vc), HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE, + HTTP3_DEFAULT_HEADER_TABLE_SIZE, HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS); + this->_remote_qpack = new QPACK(static_cast(vc), HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE, + HTTP3_DEFAULT_HEADER_TABLE_SIZE, HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS); } -void -Http3ClientSession::release(ProxyClientTransaction *trans) +Http3ClientSession::~Http3ClientSession() { - return; + this->_client_vc = nullptr; + delete this->_local_qpack; + delete this->_remote_qpack; + super::~HQClientSession(); +} + +const char * +Http3ClientSession::get_protocol_string() const +{ + return IP_PROTO_TAG_HTTP_3.data(); } int @@ -129,7 +160,7 @@ Http3ClientSession::populate_protocol(std::string_view *result, int size) const { int retval = 0; if (size > retval) { - result[retval++] = IP_PROTO_TAG_HTTP_QUIC; + result[retval++] = IP_PROTO_TAG_HTTP_3; if (size > retval) { retval += super::populate_protocol(result + retval, size - retval); } @@ -149,33 +180,54 @@ Http3ClientSession::decrement_current_active_client_connections_stat() // TODO Implement stats } -void -Http3ClientSession::add_transaction(Http3ClientTransaction *trans) +QPACK * +Http3ClientSession::local_qpack() { - this->_transaction_list.enqueue(trans); - return; + return this->_local_qpack; } -// this->_transaction_list should be map? -Http3ClientTransaction * -Http3ClientSession::get_transaction(QUICStreamId id) +QPACK * +Http3ClientSession::remote_qpack() { - for (Http3ClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { - if (t->get_transaction_id() == static_cast(id)) { - return t; + return this->_remote_qpack; +} + +// +// Http09ClientSession +// +Http09ClientSession::~Http09ClientSession() +{ + this->_client_vc = nullptr; + super::~HQClientSession(); +} + +const char * +Http09ClientSession::get_protocol_string() const +{ + return IP_PROTO_TAG_HTTP_QUIC.data(); +} + +int +Http09ClientSession::populate_protocol(std::string_view *result, int size) const +{ + int retval = 0; + if (size > retval) { + result[retval++] = IP_PROTO_TAG_HTTP_QUIC; + if (size > retval) { + retval += super::populate_protocol(result + retval, size - retval); } } - return nullptr; + return retval; } -QPACK * -Http3ClientSession::local_qpack() +void +Http09ClientSession::increment_current_active_client_connections_stat() { - return this->_local_qpack; + // TODO Implement stats } -QPACK * -Http3ClientSession::remote_qpack() +void +Http09ClientSession::decrement_current_active_client_connections_stat() { - return this->_remote_qpack; + // TODO Implement stats } diff --git a/proxy/http3/Http3ClientSession.h b/proxy/http3/Http3ClientSession.h index 8af10b0a739..996de11299e 100644 --- a/proxy/http3/Http3ClientSession.h +++ b/proxy/http3/Http3ClientSession.h @@ -27,13 +27,13 @@ #include "Http3ClientTransaction.h" #include "QPACK.h" -class Http3ClientSession : public ProxyClientSession +class HQClientSession : public ProxyClientSession { public: - typedef ProxyClientSession super; ///< Parent type. + using super = ProxyClientSession; ///< Parent type - Http3ClientSession(NetVConnection *vc); - ~Http3ClientSession(); + HQClientSession(NetVConnection *vc) : _client_vc(vc){}; + ~HQClientSession(); // Implement VConnection interface VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) override; @@ -43,27 +43,63 @@ class Http3ClientSession : public ProxyClientSession void reenable(VIO *vio) override; // Implement ProxyClienSession interface + void new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader) override; void start() override; void destroy() override; - void new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader) override; + void release(ProxyClientTransaction *trans) override; NetVConnection *get_netvc() const override; int get_transact_count() const override; + + // HQClientSession + void add_transaction(HQClientTransaction *); + HQClientTransaction *get_transaction(QUICStreamId); + +protected: + NetVConnection *_client_vc = nullptr; + +private: + // this should be unordered map? + Queue _transaction_list; +}; + +class Http3ClientSession : public HQClientSession +{ +public: + using super = HQClientSession; ///< Parent type + + Http3ClientSession(NetVConnection *vc); + ~Http3ClientSession(); + + // ProxyClienSession interface const char *get_protocol_string() const override; - void release(ProxyClientTransaction *trans) override; int populate_protocol(std::string_view *result, int size) const override; void increment_current_active_client_connections_stat() override; void decrement_current_active_client_connections_stat() override; - // Http3ClientSession specific methods - void add_transaction(Http3ClientTransaction *); - Http3ClientTransaction *get_transaction(QUICStreamId); - QPACK *local_qpack(); QPACK *remote_qpack(); private: - NetVConnection *_client_vc = nullptr; - QPACK *_remote_qpack = nullptr; // QPACK for decoding - QPACK *_local_qpack = nullptr; // QPACK for encoding - Queue _transaction_list; + QPACK *_remote_qpack = nullptr; // QPACK for decoding + QPACK *_local_qpack = nullptr; // QPACK for encoding +}; + +/** + Only for interop. Will be removed. + */ +class Http09ClientSession : public HQClientSession +{ +public: + using super = HQClientSession; ///< Parent type + + Http09ClientSession(NetVConnection *vc) : HQClientSession(vc) {} + ~Http09ClientSession(); + + // ProxyClienSession interface + const char *get_protocol_string() const override; + int populate_protocol(std::string_view *result, int size) const override; + void increment_current_active_client_connections_stat() override; + void decrement_current_active_client_connections_stat() override; + +private: }; diff --git a/proxy/http3/Http3ClientTransaction.cc b/proxy/http3/Http3ClientTransaction.cc index 849a132d37c..228621b020d 100644 --- a/proxy/http3/Http3ClientTransaction.cc +++ b/proxy/http3/Http3ClientTransaction.cc @@ -53,45 +53,27 @@ // Debug("v_http3_trans", "len=%" PRId64 "\n%s\n", read_len, msg); // } -Http3ClientTransaction::Http3ClientTransaction(Http3ClientSession *session, QUICStreamIO *stream_io) - : super(), _stream_io(stream_io) +// +// HQClientTransaction +// +HQClientTransaction::HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) { this->mutex = new_ProxyMutex(); this->_thread = this_ethread(); this->set_parent(session); - this->sm_reader = this->_read_vio_buf.alloc_reader(); - static_cast(this->parent)->add_transaction(this); - - this->_header_framer = new Http3HeaderFramer(this, &this->_write_vio, session->local_qpack(), stream_io->stream_id()); - this->_data_framer = new Http3DataFramer(this, &this->_write_vio); - this->_frame_collector.add_generator(this->_header_framer); - this->_frame_collector.add_generator(this->_data_framer); - // this->_frame_collector.add_generator(this->_push_controller); - - this->_header_handler = new Http3HeaderVIOAdaptor(&this->_request_header, session->remote_qpack(), this, stream_io->stream_id()); - this->_data_handler = new Http3StreamDataVIOAdaptor(&this->_read_vio); - - this->_frame_dispatcher.add_handler(this->_header_handler); - this->_frame_dispatcher.add_handler(this->_data_handler); + this->sm_reader = this->_read_vio_buf.alloc_reader(); this->_request_header.create(HTTP_TYPE_REQUEST); - - SET_HANDLER(&Http3ClientTransaction::state_stream_open); } -Http3ClientTransaction::~Http3ClientTransaction() +HQClientTransaction::~HQClientTransaction() { this->_request_header.destroy(); - - delete this->_header_framer; - delete this->_data_framer; - delete this->_header_handler; - delete this->_data_handler; } void -Http3ClientTransaction::set_active_timeout(ink_hrtime timeout_in) +HQClientTransaction::set_active_timeout(ink_hrtime timeout_in) { if (parent) { parent->set_active_timeout(timeout_in); @@ -99,7 +81,7 @@ Http3ClientTransaction::set_active_timeout(ink_hrtime timeout_in) } void -Http3ClientTransaction::set_inactivity_timeout(ink_hrtime timeout_in) +HQClientTransaction::set_inactivity_timeout(ink_hrtime timeout_in) { if (parent) { parent->set_inactivity_timeout(timeout_in); @@ -107,7 +89,7 @@ Http3ClientTransaction::set_inactivity_timeout(ink_hrtime timeout_in) } void -Http3ClientTransaction::cancel_inactivity_timeout() +HQClientTransaction::cancel_inactivity_timeout() { if (parent) { parent->cancel_inactivity_timeout(); @@ -115,121 +97,20 @@ Http3ClientTransaction::cancel_inactivity_timeout() } void -Http3ClientTransaction::release(IOBufferReader *r) +HQClientTransaction::release(IOBufferReader *r) { super::release(r); this->current_reader = nullptr; } bool -Http3ClientTransaction::allow_half_open() const +HQClientTransaction::allow_half_open() const { return false; } -int -Http3ClientTransaction::state_stream_open(int event, void *edata) -{ - // TODO: should check recursive call? - Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); - - if (this->_thread != this_ethread()) { - // Send on to the owning thread - if (this->_cross_thread_event == nullptr) { - this->_cross_thread_event = this->_thread->schedule_imm(this, event, edata); - } - return 0; - } - - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - - Event *e = static_cast(edata); - if (e == this->_cross_thread_event) { - this->_cross_thread_event = nullptr; - } - - switch (event) { - case VC_EVENT_READ_READY: - case VC_EVENT_READ_COMPLETE: { - int64_t len = this->_process_read_vio(); - // if no progress, don't need to signal - if (len > 0) { - this->_signal_read_event(); - } - this->_stream_io->read_reenable(); - - break; - } - case VC_EVENT_WRITE_READY: - case VC_EVENT_WRITE_COMPLETE: { - int64_t len = this->_process_write_vio(); - if (len > 0) { - this->_signal_write_event(); - } - this->_stream_io->write_reenable(); - - break; - } - case VC_EVENT_EOS: - case VC_EVENT_ERROR: - case VC_EVENT_INACTIVITY_TIMEOUT: - case VC_EVENT_ACTIVE_TIMEOUT: { - ink_assert(false); - break; - } - case QPACK_EVENT_DECODE_COMPLETE: { - int res = this->_on_qpack_decode_complete(); - if (res) { - // If READ_READY event is scheduled, should it be canceled? - this->_signal_read_event(); - } - break; - } - case QPACK_EVENT_DECODE_FAILED: { - // FIXME: handle error - break; - } - default: - Http3TransDebug("Unknown event %d", event); - ink_assert(false); - } - - return EVENT_DONE; -} - -int -Http3ClientTransaction::state_stream_closed(int event, void *data) -{ - Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); - - switch (event) { - case VC_EVENT_READ_READY: - case VC_EVENT_READ_COMPLETE: { - // ignore - break; - } - case VC_EVENT_WRITE_READY: - case VC_EVENT_WRITE_COMPLETE: { - // ignore - break; - } - case VC_EVENT_EOS: - case VC_EVENT_ERROR: - case VC_EVENT_INACTIVITY_TIMEOUT: - case VC_EVENT_ACTIVE_TIMEOUT: { - // TODO - ink_assert(false); - break; - } - default: - ink_assert(false); - } - - return EVENT_DONE; -} - VIO * -Http3ClientTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +HQClientTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) { if (buf) { this->_read_vio.buffer.writer_for(buf); @@ -251,7 +132,7 @@ Http3ClientTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *b } VIO * -Http3ClientTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +HQClientTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) { if (buf) { this->_write_vio.buffer.reader_for(buf); @@ -273,10 +154,8 @@ Http3ClientTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferRea } void -Http3ClientTransaction::do_io_close(int lerrno) +HQClientTransaction::do_io_close(int lerrno) { - SET_HANDLER(&Http3ClientTransaction::state_stream_closed); - if (this->_read_event) { this->_read_event->cancel(); this->_read_event = nullptr; @@ -301,13 +180,13 @@ Http3ClientTransaction::do_io_close(int lerrno) } void -Http3ClientTransaction::do_io_shutdown(ShutdownHowTo_t howto) +HQClientTransaction::do_io_shutdown(ShutdownHowTo_t howto) { return; } void -Http3ClientTransaction::reenable(VIO *vio) +HQClientTransaction::reenable(VIO *vio) { if (vio->op == VIO::READ) { int64_t len = this->_process_read_vio(); @@ -326,11 +205,42 @@ Http3ClientTransaction::reenable(VIO *vio) } } +void +HQClientTransaction::destroy() +{ + current_reader = nullptr; +} + +void +HQClientTransaction::transaction_done() +{ + // TODO: start closing transaction + return; +} + +int +HQClientTransaction::get_transaction_id() const +{ + return this->_stream_io->stream_id(); +} + +void +HQClientTransaction::increment_client_transactions_stat() +{ + // TODO +} + +void +HQClientTransaction::decrement_client_transactions_stat() +{ + // TODO +} + /** * @brief Replace existing event only if the new event is different than the inprogress event */ Event * -Http3ClientTransaction::_send_tracked_event(Event *event, int send_event, VIO *vio) +HQClientTransaction::_send_tracked_event(Event *event, int send_event, VIO *vio) { if (event != nullptr) { if (event->callback_event != send_event) { @@ -346,29 +256,11 @@ Http3ClientTransaction::_send_tracked_event(Event *event, int send_event, VIO *v return event; } -void -Http3ClientTransaction::set_read_vio_nbytes(int64_t nbytes) -{ - this->_read_vio.nbytes = nbytes; -} - -void -Http3ClientTransaction::set_write_vio_nbytes(int64_t nbytes) -{ - this->_write_vio.nbytes = nbytes; -} - -void -Http3ClientTransaction::destroy() -{ - current_reader = nullptr; -} - /** * @brief Signal event to this->_read_vio.cont */ void -Http3ClientTransaction::_signal_read_event() +HQClientTransaction::_signal_read_event() { if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return; @@ -389,7 +281,7 @@ Http3ClientTransaction::_signal_read_event() * @brief Signal event to this->_write_vio.cont */ void -Http3ClientTransaction::_signal_write_event() +HQClientTransaction::_signal_write_event() { if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { return; @@ -406,93 +298,159 @@ Http3ClientTransaction::_signal_write_event() Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); } -// Convert HTTP/0.9 to HTTP/1.1 -int64_t -Http3ClientTransaction::_process_read_vio() +// +// Http3ClientTransaction +// +Http3ClientTransaction::Http3ClientTransaction(Http3ClientSession *session, QUICStreamIO *stream_io) : super(session, stream_io) { - if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { - return 0; - } + static_cast(this->parent)->add_transaction(static_cast(this)); + + this->_header_framer = new Http3HeaderFramer(this, &this->_write_vio, session->local_qpack(), stream_io->stream_id()); + this->_data_framer = new Http3DataFramer(this, &this->_write_vio); + this->_frame_collector.add_generator(this->_header_framer); + this->_frame_collector.add_generator(this->_data_framer); + // this->_frame_collector.add_generator(this->_push_controller); + + this->_header_handler = new Http3HeaderVIOAdaptor(&this->_request_header, session->remote_qpack(), this, stream_io->stream_id()); + this->_data_handler = new Http3StreamDataVIOAdaptor(&this->_read_vio); + + this->_frame_dispatcher.add_handler(this->_header_handler); + this->_frame_dispatcher.add_handler(this->_data_handler); + + SET_HANDLER(&Http3ClientTransaction::state_stream_open); +} + +Http3ClientTransaction::~Http3ClientTransaction() +{ + delete this->_header_framer; + delete this->_data_framer; + delete this->_header_handler; + delete this->_data_handler; +} + +int +Http3ClientTransaction::state_stream_open(int event, void *edata) +{ + // TODO: should check recursive call? + Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); if (this->_thread != this_ethread()) { - SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + // Send on to the owning thread if (this->_cross_thread_event == nullptr) { - // Send to the right thread - this->_cross_thread_event = this->_thread->schedule_imm(this, VC_EVENT_READ_READY, nullptr); + this->_cross_thread_event = this->_thread->schedule_imm(this, event, edata); } return 0; } - SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); - // Nuke this block when we drop 0.9 support - if (!this->_protocol_detected) { - uint8_t start[3]; - if (this->_stream_io->peek(start, 3) < 3) { - return 0; - } - // If the first two bit are 0 and 1, the 3rd byte is type field. - // Because there is no type value larger than 0x20, we can assume that the - // request is HTTP/0.9 if the value is larger than 0x20. - if (0x40 <= start[0] && start[0] < 0x80 && start[2] > 0x20) { - this->_legacy_request = true; - } - this->_protocol_detected = true; + Event *e = static_cast(edata); + if (e == this->_cross_thread_event) { + this->_cross_thread_event = nullptr; } - if (this->_legacy_request) { - uint64_t nread = 0; - MIOBuffer *writer = this->_read_vio.get_writer(); + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + int64_t len = this->_process_read_vio(); + // if no progress, don't need to signal + if (len > 0) { + this->_signal_read_event(); + } + this->_stream_io->read_reenable(); - // Nuke this branch when we drop 0.9 support - if (!this->_client_req_header_complete) { - uint8_t buf[4096]; - int len = this->_stream_io->peek(buf, 4096); - // Check client request is complete or not - if (len < 2 || buf[len - 1] != '\n') { - return 0; - } - this->_stream_io->consume(len); - nread += len; - this->_client_req_header_complete = true; + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); + } + this->_stream_io->write_reenable(); - // Check "CRLF" or "LF" - int n = 2; - if (buf[len - 2] != '\r') { - n = 1; - } - - writer->write(buf, len - n); - // FIXME: Get hostname from SNI? - const char version[] = " HTTP/1.1\r\nHost: localhost\r\n\r\n"; - writer->write(version, sizeof(version)); - } else { - uint8_t buf[4096]; - int len; - while ((len = this->_stream_io->read(buf, 4096)) > 0) { - nread += len; - writer->write(buf, len); - } + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); + break; + } + case QPACK_EVENT_DECODE_COMPLETE: { + int res = this->_on_qpack_decode_complete(); + if (res) { + // If READ_READY event is scheduled, should it be canceled? + this->_signal_read_event(); } + break; + } + case QPACK_EVENT_DECODE_FAILED: { + // FIXME: handle error + break; + } + default: + Http3TransDebug("Unknown event %d", event); + } - return nread; - // End of code for HTTP/0.9 - } else { - // This branch is for HTTP/3 - uint64_t nread = 0; - this->_frame_dispatcher.on_read_ready(*this->_stream_io, nread); - return nread; + return EVENT_DONE; +} + +int +Http3ClientTransaction::state_stream_closed(int event, void *data) +{ + Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + // ignore + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + // ignore + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + // TODO + Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); + break; + } + default: + Http3TransDebug("Unknown event %d", event); } + + return EVENT_DONE; } -// FIXME: already defined somewhere? -static constexpr char http_1_1_version[] = "HTTP/1.1"; +void +Http3ClientTransaction::do_io_close(int lerrno) +{ + SET_HANDLER(&Http3ClientTransaction::state_stream_closed); + super::do_io_close(lerrno); +} + +bool +Http3ClientTransaction::is_response_header_sent() const +{ + return this->_header_framer->is_done(); +} + +bool +Http3ClientTransaction::is_response_body_sent() const +{ + return this->_data_framer->is_done(); +} -// Convert HTTP/1.1 to HTTP/0.9 int64_t -Http3ClientTransaction::_process_write_vio() +Http3ClientTransaction::_process_read_vio() { - if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { + if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return 0; } @@ -500,57 +458,40 @@ Http3ClientTransaction::_process_write_vio() SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); if (this->_cross_thread_event == nullptr) { // Send to the right thread - this->_cross_thread_event = this->_thread->schedule_imm(this, VC_EVENT_WRITE_READY, nullptr); + this->_cross_thread_event = this->_thread->schedule_imm(this, VC_EVENT_READ_READY, nullptr); } return 0; } - SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); + SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); - IOBufferReader *reader = this->_write_vio.get_reader(); + uint64_t nread = 0; + this->_frame_dispatcher.on_read_ready(*this->_stream_io, nread); + return nread; +} - if (this->_legacy_request) { - // This branch is for HTTP/0.9 - int64_t http_1_1_version_len = sizeof(http_1_1_version) - 1; +int64_t +Http3ClientTransaction::_process_write_vio() +{ + if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { + return 0; + } - if (reader->is_read_avail_more_than(http_1_1_version_len) && - memcmp(reader->start(), http_1_1_version, http_1_1_version_len) == 0) { - // Skip HTTP/1.1 response headers - IOBufferBlock *headers = reader->get_current_block(); - int64_t headers_size = headers->read_avail(); - reader->consume(headers_size); - this->_write_vio.ndone += headers_size; + if (this->_thread != this_ethread()) { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + if (this->_cross_thread_event == nullptr) { + // Send to the right thread + this->_cross_thread_event = this->_thread->schedule_imm(this, VC_EVENT_WRITE_READY, nullptr); } + return 0; + } - // Write HTTP/1.1 response body - int64_t bytes_avail = reader->read_avail(); - int64_t total_written = 0; - - while (total_written < bytes_avail) { - int64_t data_len = reader->block_read_avail(); - int64_t bytes_written = this->_stream_io->write(reader, data_len); - if (bytes_written <= 0) { - break; - } - - reader->consume(bytes_written); - this->_write_vio.ndone += bytes_written; - total_written += bytes_written; - } + SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); - // NOTE: When Chunked Transfer Coding is supported, check ChunkedState of ChunkedHandler - // is CHUNK_READ_DONE and set FIN flag - if (this->_write_vio.ntodo() == 0) { - // The size of respons to client - this->_stream_io->write_done(); - } + size_t nwritten = 0; + this->_frame_collector.on_write_ready(this->_stream_io, nwritten); - return total_written; - } else { - size_t nwritten = 0; - this->_frame_collector.on_write_ready(this->_stream_io, nwritten); - return nwritten; - } + return nwritten; } // Constant strings for pseudo headers @@ -624,39 +565,260 @@ Http3ClientTransaction::_on_qpack_decode_complete() return 1; } -void -Http3ClientTransaction::transaction_done() +// +// Http09ClientTransaction +// +Http09ClientTransaction::Http09ClientTransaction(Http09ClientSession *session, QUICStreamIO *stream_io) : super(session, stream_io) { - // TODO: start closing transaction - return; + static_cast(this->parent)->add_transaction(static_cast(this)); + + SET_HANDLER(&Http09ClientTransaction::state_stream_open); } +Http09ClientTransaction::~Http09ClientTransaction() {} + int -Http3ClientTransaction::get_transaction_id() const +Http09ClientTransaction::state_stream_open(int event, void *edata) { - return this->_stream_io->stream_id(); + // TODO: should check recursive call? + Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); + + if (this->_thread != this_ethread()) { + // Send on to the owning thread + if (this->_cross_thread_event == nullptr) { + this->_cross_thread_event = this->_thread->schedule_imm(this, event, edata); + } + return 0; + } + + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + + Event *e = static_cast(edata); + if (e == this->_cross_thread_event) { + this->_cross_thread_event = nullptr; + } + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + int64_t len = this->_process_read_vio(); + // if no progress, don't need to signal + if (len > 0) { + this->_signal_read_event(); + } + this->_stream_io->read_reenable(); + + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); + } + this->_stream_io->write_reenable(); + + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + Http3TransDebug("%d", event); + break; + } + default: + Http3TransDebug("Unknown event %d", event); + } + + return EVENT_DONE; } void -Http3ClientTransaction::increment_client_transactions_stat() +Http09ClientTransaction::do_io_close(int lerrno) { - // TODO + SET_HANDLER(&Http09ClientTransaction::state_stream_closed); + super::do_io_close(lerrno); } -void -Http3ClientTransaction::decrement_client_transactions_stat() +int +Http09ClientTransaction::state_stream_closed(int event, void *data) { - // TODO + Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + // ignore + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + // ignore + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + // TODO + break; + } + default: + Http3TransDebug("Unknown event %d", event); + } + + return EVENT_DONE; } -bool -Http3ClientTransaction::is_response_header_sent() const +// Convert HTTP/0.9 to HTTP/1.1 +int64_t +Http09ClientTransaction::_process_read_vio() { - return this->_header_framer->is_done(); + if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { + return 0; + } + + if (this->_thread != this_ethread()) { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + if (this->_cross_thread_event == nullptr) { + // Send to the right thread + this->_cross_thread_event = this->_thread->schedule_imm(this, VC_EVENT_READ_READY, nullptr); + } + return 0; + } + + SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); + + // Nuke this block when we drop 0.9 support + if (!this->_protocol_detected) { + uint8_t start[3]; + if (this->_stream_io->peek(start, 3) < 3) { + return 0; + } + // If the first two bit are 0 and 1, the 3rd byte is type field. + // Because there is no type value larger than 0x20, we can assume that the + // request is HTTP/0.9 if the value is larger than 0x20. + if (0x40 <= start[0] && start[0] < 0x80 && start[2] > 0x20) { + this->_legacy_request = true; + } + this->_protocol_detected = true; + } + + if (this->_legacy_request) { + uint64_t nread = 0; + MIOBuffer *writer = this->_read_vio.get_writer(); + + // Nuke this branch when we drop 0.9 support + if (!this->_client_req_header_complete) { + uint8_t buf[4096]; + int len = this->_stream_io->peek(buf, 4096); + // Check client request is complete or not + if (len < 2 || buf[len - 1] != '\n') { + return 0; + } + this->_stream_io->consume(len); + nread += len; + this->_client_req_header_complete = true; + + // Check "CRLF" or "LF" + int n = 2; + if (buf[len - 2] != '\r') { + n = 1; + } + + writer->write(buf, len - n); + // FIXME: Get hostname from SNI? + const char version[] = " HTTP/1.1\r\nHost: localhost\r\n\r\n"; + writer->write(version, sizeof(version)); + } else { + uint8_t buf[4096]; + int len; + while ((len = this->_stream_io->read(buf, 4096)) > 0) { + nread += len; + writer->write(buf, len); + } + } + + return nread; + // End of code for HTTP/0.9 + } else { + // Ignore malformed data + uint8_t buf[4096]; + int len; + uint64_t nread = 0; + + while ((len = this->_stream_io->read(buf, 4096)) > 0) { + nread += len; + } + + return nread; + } } -bool -Http3ClientTransaction::is_response_body_sent() const +// FIXME: already defined somewhere? +static constexpr char http_1_1_version[] = "HTTP/1.1"; + +// Convert HTTP/1.1 to HTTP/0.9 +int64_t +Http09ClientTransaction::_process_write_vio() { - return this->_data_framer->is_done(); + if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { + return 0; + } + + if (this->_thread != this_ethread()) { + SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); + if (this->_cross_thread_event == nullptr) { + // Send to the right thread + this->_cross_thread_event = this->_thread->schedule_imm(this, VC_EVENT_WRITE_READY, nullptr); + } + return 0; + } + + SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); + + IOBufferReader *reader = this->_write_vio.get_reader(); + + if (this->_legacy_request) { + // This branch is for HTTP/0.9 + int64_t http_1_1_version_len = sizeof(http_1_1_version) - 1; + + if (reader->is_read_avail_more_than(http_1_1_version_len) && + memcmp(reader->start(), http_1_1_version, http_1_1_version_len) == 0) { + // Skip HTTP/1.1 response headers + IOBufferBlock *headers = reader->get_current_block(); + int64_t headers_size = headers->read_avail(); + reader->consume(headers_size); + this->_write_vio.ndone += headers_size; + } + + // Write HTTP/1.1 response body + int64_t bytes_avail = reader->read_avail(); + int64_t total_written = 0; + + while (total_written < bytes_avail) { + int64_t data_len = reader->block_read_avail(); + int64_t bytes_written = this->_stream_io->write(reader, data_len); + if (bytes_written <= 0) { + break; + } + + reader->consume(bytes_written); + this->_write_vio.ndone += bytes_written; + total_written += bytes_written; + } + + // NOTE: When Chunked Transfer Coding is supported, check ChunkedState of ChunkedHandler + // is CHUNK_READ_DONE and set FIN flag + if (this->_write_vio.ntodo() == 0) { + // The size of respons to client + this->_stream_io->write_done(); + } + + return total_written; + } else { + // nothing to do + return 0; + } } diff --git a/proxy/http3/Http3ClientTransaction.h b/proxy/http3/Http3ClientTransaction.h index 32297d5ad5b..9d415ad6e4f 100644 --- a/proxy/http3/Http3ClientTransaction.h +++ b/proxy/http3/Http3ClientTransaction.h @@ -29,17 +29,19 @@ #include "Http3FrameCollector.h" class QUICStreamIO; +class HQClientSession; +class Http09ClientSession; class Http3ClientSession; class Http3HeaderFramer; class Http3DataFramer; -class Http3ClientTransaction : public ProxyClientTransaction +class HQClientTransaction : public ProxyClientTransaction { public: using super = ProxyClientTransaction; - Http3ClientTransaction(Http3ClientSession *session, QUICStreamIO *stream_io); - ~Http3ClientTransaction(); + HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io); + ~HQClientTransaction(); // Implement ProxyClienTransaction interface void set_active_timeout(ink_hrtime timeout_in) override; @@ -54,30 +56,23 @@ class Http3ClientTransaction : public ProxyClientTransaction void decrement_client_transactions_stat() override; // VConnection interface - VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; - VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; - void do_io_close(int lerrno = -1) override; - void do_io_shutdown(ShutdownHowTo_t) override; - void reenable(VIO *) override; - - void set_read_vio_nbytes(int64_t nbytes); - void set_write_vio_nbytes(int64_t nbytes); - - // Http3ClientTransaction specific methods - int state_stream_open(int, void *); - int state_stream_closed(int event, void *data); - bool is_response_header_sent() const; - bool is_response_body_sent() const; - -private: + virtual VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; + virtual VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, + bool owner = false) override; + virtual void do_io_close(int lerrno = -1) override; + virtual void do_io_shutdown(ShutdownHowTo_t) override; + virtual void reenable(VIO *) override; + + // HQClientTransaction + virtual int state_stream_open(int, void *) = 0; + virtual int state_stream_closed(int event, void *data) = 0; + +protected: + virtual int64_t _process_read_vio() = 0; + virtual int64_t _process_write_vio() = 0; Event *_send_tracked_event(Event *, int, VIO *); void _signal_read_event(); void _signal_write_event(); - int64_t _process_read_vio(); - int64_t _process_write_vio(); - - ParseResult _convert_header_from_3_to_1_1(HTTPHdr *hdr); - int _on_qpack_decode_complete(); EThread *_thread = nullptr; Event *_cross_thread_event = nullptr; @@ -91,16 +86,61 @@ class Http3ClientTransaction : public ProxyClientTransaction Event *_write_event = nullptr; HTTPHdr _request_header; +}; + +class Http3ClientTransaction : public HQClientTransaction +{ +public: + using super = HQClientTransaction; - // These are for Http3 + Http3ClientTransaction(Http3ClientSession *session, QUICStreamIO *stream_io); + ~Http3ClientTransaction(); + + int state_stream_open(int event, void *data) override; + int state_stream_closed(int event, void *data) override; + + void do_io_close(int lerrno = -1) override; + + bool is_response_header_sent() const; + bool is_response_body_sent() const; + +private: + int64_t _process_read_vio() override; + int64_t _process_write_vio() override; + + ParseResult _convert_header_from_3_to_1_1(HTTPHdr *hdr); + int _on_qpack_decode_complete(); + + // These are for HTTP/3 Http3FrameDispatcher _frame_dispatcher; Http3FrameCollector _frame_collector; Http3FrameGenerator *_header_framer = nullptr; Http3FrameGenerator *_data_framer = nullptr; Http3FrameHandler *_header_handler = nullptr; Http3FrameHandler *_data_handler = nullptr; +}; + +/** + Only for interop. Will be removed. + */ +class Http09ClientTransaction : public HQClientTransaction +{ +public: + using super = HQClientTransaction; + + Http09ClientTransaction(Http09ClientSession *session, QUICStreamIO *stream_io); + ~Http09ClientTransaction(); + + int state_stream_open(int event, void *data) override; + int state_stream_closed(int event, void *data) override; + + void do_io_close(int lerrno = -1) override; + +private: + int64_t _process_read_vio() override; + int64_t _process_write_vio() override; - // These are for 0.9 support + // These are for HTTP/0.9 bool _protocol_detected = false; bool _legacy_request = false; bool _client_req_header_complete = false; From 11e1159a3470615e5db4077315a30ca4727f48fb Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 7 Mar 2019 16:31:00 +0900 Subject: [PATCH 1199/1313] Reduce use of QUICConfig::scoped_config --- iocore/net/QUICNetVConnection.cc | 202 +++++++++++++++++- iocore/net/quic/Mock.h | 70 +++++- iocore/net/quic/QUICCongestionController.cc | 15 +- iocore/net/quic/QUICGlobals.cc | 6 +- iocore/net/quic/QUICHandshake.cc | 73 ++++--- iocore/net/quic/QUICHandshake.h | 9 +- iocore/net/quic/QUICLossDetector.cc | 11 +- iocore/net/quic/QUICLossDetector.h | 5 +- iocore/net/quic/QUICTLS.h | 3 +- iocore/net/quic/QUICTLS_openssl.cc | 16 +- iocore/net/quic/QUICTypes.h | 35 +++ .../net/quic/test/test_QUICFrameDispatcher.cc | 6 +- iocore/net/quic/test/test_QUICLossDetector.cc | 12 +- 13 files changed, 379 insertions(+), 84 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 3b7245244c0..0b8ce4eddbc 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -71,6 +71,190 @@ static constexpr uint32_t STATE_CLOSING_MAX_RECV_PKT_WIND = 1 << STATE_CLOSING_M ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); +class QUICTPConfigQCP : public QUICTPConfig +{ +public: + QUICTPConfigQCP(const QUICConfigParams *params, NetVConnectionContext_t ctx) : _params(params), _ctx(ctx) {} + + uint32_t + no_activity_timeout() const override + { + if (this->_ctx == NET_VCONNECTION_IN) { + return this->_params->no_activity_timeout_in(); + } else { + return this->_params->no_activity_timeout_out(); + } + } + + const IpEndpoint * + preferred_address_ipv4() const override + { + return this->_params->preferred_address_ipv4(); + } + + const IpEndpoint * + preferred_address_ipv6() const override + { + return this->_params->preferred_address_ipv6(); + } + + uint32_t + initial_max_data() const override + { + if (this->_ctx == NET_VCONNECTION_IN) { + return this->_params->initial_max_data_in(); + } else { + return this->_params->initial_max_data_out(); + } + } + + uint32_t + initial_max_stream_data_bidi_local() const override + { + if (this->_ctx == NET_VCONNECTION_IN) { + return this->_params->initial_max_stream_data_bidi_local_in(); + } else { + return this->_params->initial_max_stream_data_bidi_local_out(); + } + } + + uint32_t + initial_max_stream_data_bidi_remote() const override + { + if (this->_ctx == NET_VCONNECTION_IN) { + return this->_params->initial_max_stream_data_bidi_remote_in(); + } else { + return this->_params->initial_max_stream_data_bidi_remote_out(); + } + } + + uint32_t + initial_max_stream_data_uni() const override + { + if (this->_ctx == NET_VCONNECTION_IN) { + return this->_params->initial_max_stream_data_uni_in(); + } else { + return this->_params->initial_max_stream_data_uni_out(); + } + } + + uint64_t + initial_max_streams_bidi() const override + { + if (this->_ctx == NET_VCONNECTION_IN) { + return this->_params->initial_max_streams_bidi_in(); + } else { + return this->_params->initial_max_streams_bidi_out(); + } + } + + uint64_t + initial_max_streams_uni() const override + { + if (this->_ctx == NET_VCONNECTION_IN) { + return this->_params->initial_max_streams_uni_in(); + } else { + return this->_params->initial_max_streams_uni_out(); + } + } + + uint8_t + ack_delay_exponent() const override + { + if (this->_ctx == NET_VCONNECTION_IN) { + return this->_params->ack_delay_exponent_in(); + } else { + return this->_params->ack_delay_exponent_out(); + } + } + + uint8_t + max_ack_delay() const override + { + if (this->_ctx == NET_VCONNECTION_IN) { + return this->_params->max_ack_delay_in(); + } else { + return this->_params->max_ack_delay_out(); + } + } + +private: + const QUICConfigParams *_params; + NetVConnectionContext_t _ctx; +}; + +class QUICCCConfigQCP : public QUICCCConfig +{ +public: + QUICCCConfigQCP(const QUICConfigParams *params) : _params(params) {} + + uint32_t + max_datagram_size() const override + { + return this->_params->cc_max_datagram_size(); + } + + uint32_t + initial_window() const override + { + return this->_params->cc_initial_window(); + } + + uint32_t + minimum_window() const override + { + return this->_params->cc_minimum_window(); + } + + float + loss_reduction_factor() const override + { + return this->_params->cc_loss_reduction_factor(); + } + + uint32_t + persistent_congestion_threshold() const override + { + return this->_params->cc_persistent_congestion_threshold(); + } + +private: + const QUICConfigParams *_params; +}; + +class QUICLDConfigQCP : public QUICLDConfig +{ +public: + QUICLDConfigQCP(const QUICConfigParams *params) : _params(params) {} + + uint32_t + packet_threshold() const override + { + return this->_params->ld_packet_threshold(); + } + + float + time_threshold() const override + { + return this->_params->ld_time_threshold(); + } + + ink_hrtime + granularity() const override + { + return this->_params->ld_granularity(); + } + + ink_hrtime + initial_rtt() const override + { + return this->_params->ld_initial_rtt(); + } + +private: + const QUICConfigParams *_params; +}; + QUICNetVConnection::QUICNetVConnection() : _packet_factory(this->_pp_key_info), _ph_protector(this->_pp_key_info) {} QUICNetVConnection::~QUICNetVConnection() @@ -250,11 +434,12 @@ QUICNetVConnection::start() this->_ack_frame_manager.set_max_ack_delay(params->max_ack_delay_in()); this->_schedule_ack_manager_periodic(params->max_ack_delay_in()); } else { + QUICTPConfigQCP tp_config(params, NET_VCONNECTION_OUT); this->_pp_key_info.set_context(QUICPacketProtectionKeyInfo::Context::CLIENT); this->_ack_frame_manager.set_ack_delay_exponent(params->ack_delay_exponent_out()); this->_hs_protocol = this->_setup_handshake_protocol(params->client_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol); - this->_handshake_handler->start(&this->_packet_factory, params->vn_exercise_enabled()); + this->_handshake_handler->start(tp_config, &this->_packet_factory, params->vn_exercise_enabled()); this->_handshake_handler->do_handshake(); this->_ack_frame_manager.set_max_ack_delay(params->max_ack_delay_out()); this->_schedule_ack_manager_periodic(params->max_ack_delay_out()); @@ -265,10 +450,12 @@ QUICNetVConnection::start() this->_frame_dispatcher = new QUICFrameDispatcher(this); // Create frame handlers - this->_congestion_controller = new QUICCongestionController(this); + QUICCCConfigQCP cc_config(params); + QUICLDConfigQCP ld_config(params); + this->_congestion_controller = new QUICCongestionController(this, cc_config); for (auto s : QUIC_PN_SPACES) { int index = static_cast(s); - QUICLossDetector *ld = new QUICLossDetector(this, this->_congestion_controller, &this->_rtt_measure, index); + QUICLossDetector *ld = new QUICLossDetector(this, this->_congestion_controller, &this->_rtt_measure, index, ld_config); this->_frame_dispatcher->add_handler(ld); this->_loss_detector[index] = ld; } @@ -948,15 +1135,17 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe // Start handshake if (this->netvc_context == NET_VCONNECTION_IN) { + QUICConfig::scoped_config params; if (!this->_alt_con_manager) { - QUICConfig::scoped_config params; this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, params->instance_id(), params->num_alt_connection_ids(), params->preferred_address_ipv4(), params->preferred_address_ipv6()); this->_frame_generators.push_back(this->_alt_con_manager); this->_frame_dispatcher->add_handler(this->_alt_con_manager); } - error = this->_handshake_handler->start(packet.get(), &this->_packet_factory, this->_alt_con_manager->preferred_address()); + QUICTPConfigQCP tp_config(params, NET_VCONNECTION_IN); + error = + this->_handshake_handler->start(tp_config, packet.get(), &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()) { @@ -2000,7 +2189,8 @@ QUICNetVConnection::_setup_handshake_protocol(SSL_CTX *ctx) { // Initialize handshake protocol specific stuff // For QUICv1 TLS is the only option - QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx, this->direction()); + QUICConfig::scoped_config params; + QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx, this->direction(), params->session_file()); SSL_set_ex_data(tls->ssl_handle(), QUIC::ssl_quic_qc_index, static_cast(this)); return tls; } diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index c764cfa8084..7e73fffdb5f 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -340,7 +340,10 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider class MockQUICCongestionController : public QUICCongestionController { public: - MockQUICCongestionController(QUICConnectionInfoProvider *info) : QUICCongestionController(info) {} + MockQUICCongestionController(QUICConnectionInfoProvider *info, const QUICCCConfig &cc_config) + : QUICCongestionController(info, cc_config) + { + } // Override virtual void on_packets_lost(const std::map &packets, uint32_t pto_count) override @@ -385,8 +388,9 @@ class MockQUICCongestionController : public QUICCongestionController class MockQUICLossDetector : public QUICLossDetector { public: - MockQUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, int index) - : QUICLossDetector(info, cc, rtt_measure, index) + MockQUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, int index, + const QUICLDConfig &ld_config) + : QUICLossDetector(info, cc, rtt_measure, index, ld_config) { } void @@ -641,3 +645,63 @@ class MockQUICFrameGenerator : public QUICFrameGenerator lost_frame_count++; } }; + +class MockQUICLDConfig : public QUICLDConfig +{ + uint32_t + packet_threshold() const + { + return 3; + } + + float + time_threshold() const + { + return 1.25; + } + + ink_hrtime + granularity() const + { + return HRTIME_MSECONDS(1); + } + + ink_hrtime + initial_rtt() const + { + return HRTIME_MSECONDS(100); + } +}; + +class MockQUICCCConfig : public QUICCCConfig +{ + uint32_t + max_datagram_size() const + { + return 1200; + } + + uint32_t + initial_window() const + { + return 10; + } + + uint32_t + minimum_window() const + { + return 2; + } + + float + loss_reduction_factor() const + { + return 0.5; + } + + uint32_t + persistent_congestion_threshold() const + { + return 2; + } +}; diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index e863d8d36cd..93ff5497277 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -24,8 +24,6 @@ #include #include -#include "QUICConfig.h" - #define QUICCCDebug(fmt, ...) \ Debug("quic_cc", \ "[%s] " \ @@ -38,16 +36,15 @@ "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ this->_info->cids().data(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, ##__VA_ARGS__) -QUICCongestionController::QUICCongestionController(QUICConnectionInfoProvider *info) : _info(info) +QUICCongestionController::QUICCongestionController(QUICConnectionInfoProvider *info, const QUICCCConfig &cc_config) : _info(info) { this->_cc_mutex = new_ProxyMutex(); - QUICConfig::scoped_config params; - this->_k_max_datagram_size = params->cc_max_datagram_size(); - this->_k_initial_window = params->cc_initial_window(); - this->_k_minimum_window = params->cc_minimum_window(); - this->_k_loss_reduction_factor = params->cc_loss_reduction_factor(); - this->_k_persistent_congestion_threshold = params->cc_persistent_congestion_threshold(); + this->_k_max_datagram_size = cc_config.max_datagram_size(); + this->_k_initial_window = cc_config.initial_window(); + this->_k_minimum_window = cc_config.minimum_window(); + this->_k_loss_reduction_factor = cc_config.loss_reduction_factor(); + this->_k_persistent_congestion_threshold = cc_config.persistent_congestion_threshold(); this->reset(); } diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index 611bddb1447..2033959094a 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -69,9 +69,11 @@ int QUIC::ssl_client_new_session(SSL *ssl, SSL_SESSION *session) { QUICConfig::scoped_config params; - auto file = BIO_new_file(params->session_file(), "w"); + const char *session_file = params->session_file(); + auto file = BIO_new_file(session_file, "w"); + if (file == nullptr) { - QUICGlobalDebug("Could not write TLS session in %s", params->session_file()); + QUICGlobalDebug("Could not write TLS session in %s", session_file); return 0; } diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index c8507e94e80..9b088d5607d 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -106,21 +106,22 @@ QUICHandshake::~QUICHandshake() } QUICConnectionErrorUPtr -QUICHandshake::start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled) +QUICHandshake::start(const QUICTPConfig &tp_config, QUICPacketFactory *packet_factory, bool vn_exercise_enabled) { QUICVersion initital_version = QUIC_SUPPORTED_VERSIONS[0]; if (vn_exercise_enabled) { initital_version = QUIC_EXERCISE_VERSION; } - this->_load_local_client_transport_parameters(initital_version); + this->_load_local_client_transport_parameters(tp_config, initital_version); packet_factory->set_version(initital_version); return nullptr; } QUICConnectionErrorUPtr -QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory, const QUICPreferredAddress *pref_addr) +QUICHandshake::start(const QUICTPConfig &tp_config, const QUICPacket *initial_packet, QUICPacketFactory *packet_factory, + const QUICPreferredAddress *pref_addr) { // Negotiate version if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) { @@ -130,7 +131,7 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet if (initial_packet->version()) { if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { QUICHSDebug("Version negotiation succeeded: %x", initial_packet->version()); - this->_load_local_server_transport_parameters(initial_packet->version(), pref_addr); + this->_load_local_server_transport_parameters(tp_config, initial_packet->version(), pref_addr); packet_factory->set_version(this->_version_negotiator->negotiated_version()); } else { ink_assert(!"Unsupported version initial packet should be droped QUICPakcetHandler"); @@ -361,36 +362,36 @@ QUICHandshake::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t } void -QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_version, const QUICPreferredAddress *pref_addr) +QUICHandshake::_load_local_server_transport_parameters(const QUICTPConfig &tp_config, QUICVersion negotiated_version, + const QUICPreferredAddress *pref_addr) { - QUICConfig::scoped_config params; QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(negotiated_version); // MUSTs - tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_in())); + tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(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()); } // MAYs - if (params->initial_max_data_in() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data_in()); + if (tp_config.initial_max_data() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, tp_config.initial_max_data()); } - if (params->initial_max_streams_bidi_in() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, params->initial_max_streams_bidi_in()); + if (tp_config.initial_max_streams_bidi() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, tp_config.initial_max_streams_bidi()); } - if (params->initial_max_streams_uni_in() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, params->initial_max_streams_uni_in()); + if (tp_config.initial_max_streams_uni() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, tp_config.initial_max_streams_uni()); } - if (params->initial_max_stream_data_bidi_local_in() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, params->initial_max_stream_data_bidi_local_in()); + if (tp_config.initial_max_stream_data_bidi_local() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, tp_config.initial_max_stream_data_bidi_local()); } - if (params->initial_max_stream_data_bidi_remote_in() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, params->initial_max_stream_data_bidi_remote_in()); + if (tp_config.initial_max_stream_data_bidi_remote() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, tp_config.initial_max_stream_data_bidi_remote()); } - if (params->initial_max_stream_data_uni_in() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, params->initial_max_stream_data_uni_in()); + 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 (pref_addr != nullptr) { uint8_t pref_addr_buf[QUICPreferredAddress::MAX_LEN]; @@ -401,7 +402,7 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve // MAYs (server) tp->set(QUICTransportParameterId::STATELESS_RESET_TOKEN, this->_reset_token.buf(), QUICStatelessResetToken::LEN); - tp->set(QUICTransportParameterId::ACK_DELAY_EXPONENT, params->ack_delay_exponent_in()); + tp->set(QUICTransportParameterId::ACK_DELAY_EXPONENT, tp_config.ack_delay_exponent()); tp->add_version(QUIC_SUPPORTED_VERSIONS[0]); @@ -410,35 +411,33 @@ QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_ve } void -QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_version) +QUICHandshake::_load_local_client_transport_parameters(const QUICTPConfig &tp_config, QUICVersion initial_version) { - QUICConfig::scoped_config params; - QUICTransportParametersInClientHello *tp = new QUICTransportParametersInClientHello(initial_version); // MUSTs - tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(params->no_activity_timeout_out())); + tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(tp_config.no_activity_timeout())); // MAYs - if (params->initial_max_data_out() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, params->initial_max_data_out()); + if (tp_config.initial_max_data() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_DATA, tp_config.initial_max_data()); } - if (params->initial_max_streams_bidi_out() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, params->initial_max_streams_bidi_out()); + if (tp_config.initial_max_streams_bidi() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_BIDI, tp_config.initial_max_streams_bidi()); } - if (params->initial_max_streams_uni_out() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, params->initial_max_streams_uni_out()); + if (tp_config.initial_max_streams_uni() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAMS_UNI, tp_config.initial_max_streams_uni()); } - if (params->initial_max_stream_data_bidi_local_out() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, params->initial_max_stream_data_bidi_local_out()); + if (tp_config.initial_max_stream_data_bidi_local() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, tp_config.initial_max_stream_data_bidi_local()); } - if (params->initial_max_stream_data_bidi_remote_out() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, params->initial_max_stream_data_bidi_remote_out()); + if (tp_config.initial_max_stream_data_bidi_remote() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, tp_config.initial_max_stream_data_bidi_remote()); } - if (params->initial_max_stream_data_uni_out() != 0) { - tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, params->initial_max_stream_data_uni_out()); + if (tp_config.initial_max_stream_data_uni() != 0) { + tp->set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI, tp_config.initial_max_stream_data_uni()); } - tp->set(QUICTransportParameterId::ACK_DELAY_EXPONENT, params->ack_delay_exponent_out()); + tp->set(QUICTransportParameterId::ACK_DELAY_EXPONENT, tp_config.ack_delay_exponent()); this->_local_transport_parameters = std::shared_ptr(tp); this->_hs_protocol->set_local_transport_parameters(std::unique_ptr(tp)); diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index e97eea386c4..a02f3a84611 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -56,12 +56,12 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator ink_hrtime timestamp) override; // for client side - QUICConnectionErrorUPtr start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled); + QUICConnectionErrorUPtr start(const QUICTPConfig &tp_config, QUICPacketFactory *packet_factory, bool vn_exercise_enabled); QUICConnectionErrorUPtr negotiate_version(const QUICPacket *packet, QUICPacketFactory *packet_factory); void reset(); // for server side - QUICConnectionErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory, + QUICConnectionErrorUPtr start(const QUICTPConfig &tp_config, const QUICPacket *initial_packet, QUICPacketFactory *packet_factory, const QUICPreferredAddress *pref_addr); QUICConnectionErrorUPtr do_handshake(); @@ -101,8 +101,9 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator QUICEncryptionLevel::ONE_RTT, }; } - void _load_local_server_transport_parameters(QUICVersion negotiated_version, const QUICPreferredAddress *pref_addr); - void _load_local_client_transport_parameters(QUICVersion initial_version); + void _load_local_server_transport_parameters(const QUICTPConfig &tp_config, QUICVersion negotiated_version, + const QUICPreferredAddress *pref_addr); + void _load_local_client_transport_parameters(const QUICTPConfig &tp_config, QUICVersion initial_version); bool _check_remote_transport_parameters(std::shared_ptr tp); bool _check_remote_transport_parameters(std::shared_ptr tp); std::shared_ptr _local_transport_parameters = nullptr; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 7f9915e5e82..0e3a8b9b1df 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -38,17 +38,16 @@ ##__VA_ARGS__) QUICLossDetector::QUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, - int index) + int index, const QUICLDConfig &ld_config) : _info(info), _cc(cc), _rtt_measure(rtt_measure), _pn_space_index(index) { this->mutex = new_ProxyMutex(); this->_loss_detection_mutex = new_ProxyMutex(); - QUICConfig::scoped_config params; - this->_k_packet_threshold = params->ld_packet_threshold(); - this->_k_time_threshold = params->ld_time_threshold(); - this->_k_granularity = params->ld_granularity(); - this->_k_initial_rtt = params->ld_initial_rtt(); + this->_k_packet_threshold = ld_config.packet_threshold(); + this->_k_time_threshold = ld_config.time_threshold(); + this->_k_granularity = ld_config.granularity(); + this->_k_initial_rtt = ld_config.initial_rtt(); this->reset(); diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 10610236ac9..56787e75318 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -75,7 +75,7 @@ class QUICRTTMeasure : public QUICRTTProvider class QUICCongestionController { public: - QUICCongestionController(QUICConnectionInfoProvider *info); + QUICCongestionController(QUICConnectionInfoProvider *info, const QUICCCConfig &cc_config); virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); void on_packet_acked(const QUICPacketInfo &acked_packet); @@ -119,7 +119,8 @@ class QUICCongestionController class QUICLossDetector : public Continuation, public QUICFrameHandler { public: - QUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, int index); + QUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, int index, + const QUICLDConfig &ld_config); ~QUICLossDetector(); int event_handler(int event, Event *edata); diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index ee88bab4a8d..8fda0f39ee8 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -39,7 +39,8 @@ class QUICTLS : public QUICHandshakeProtocol { public: - QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx); + QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx, + const char *session_file = nullptr); ~QUICTLS(); // TODO: integrate with _early_data_processed diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 5edf90ac72d..824cd600384 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -328,7 +328,8 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t return; } -QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx) +QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx, + const char *session_file) : QUICHandshakeProtocol(pp_key_info), _ssl(SSL_new(ssl_ctx)), _netvc_context(nvc_ctx) { ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); @@ -342,22 +343,21 @@ QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, Net SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_tls_index, this); SSL_set_key_callback(this->_ssl, key_cb, this); - QUICConfig::scoped_config params; - if (params->session_file() && this->_netvc_context == NET_VCONNECTION_OUT) { - auto file = BIO_new_file(params->session_file(), "r"); + if (session_file && this->_netvc_context == NET_VCONNECTION_OUT) { + auto file = BIO_new_file(session_file, "r"); if (file == nullptr) { - Debug(tag, "Could not read tls session file %s", params->session_file()); + Debug(tag, "Could not read tls session file %s", session_file); return; } auto session = PEM_read_bio_SSL_SESSION(file, nullptr, 0, nullptr); if (session == nullptr) { - Debug(tag, "Could not read tls session file %s", params->session_file()); + Debug(tag, "Could not read tls session file %s", session_file); } else { if (!SSL_set_session(this->_ssl, session)) { - Debug(tag, "Session resumption failed : %s", params->session_file()); + Debug(tag, "Session resumption failed : %s", session_file); } else { - Debug(tag, "Session resumption success : %s", params->session_file()); + Debug(tag, "Session resumption success : %s", session_file); this->_is_session_reused = true; } SSL_SESSION_free(session); diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index c376a2f5c4d..fba82097dd2 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -448,6 +448,41 @@ class QUICFiveTuple uint64_t _hash_code = 0; }; +class QUICTPConfig +{ +public: + virtual uint32_t no_activity_timeout() const = 0; + virtual const IpEndpoint *preferred_address_ipv4() const = 0; + virtual const IpEndpoint *preferred_address_ipv6() const = 0; + virtual uint32_t initial_max_data() const = 0; + virtual uint32_t initial_max_stream_data_bidi_local() const = 0; + virtual uint32_t initial_max_stream_data_bidi_remote() const = 0; + virtual uint32_t initial_max_stream_data_uni() const = 0; + virtual uint64_t initial_max_streams_bidi() const = 0; + virtual uint64_t initial_max_streams_uni() const = 0; + virtual uint8_t ack_delay_exponent() const = 0; + virtual uint8_t max_ack_delay() const = 0; +}; + +class QUICLDConfig +{ +public: + virtual uint32_t packet_threshold() const = 0; + virtual float time_threshold() const = 0; + virtual ink_hrtime granularity() const = 0; + virtual ink_hrtime initial_rtt() const = 0; +}; + +class QUICCCConfig +{ +public: + virtual uint32_t max_datagram_size() const = 0; + virtual uint32_t initial_window() const = 0; + virtual uint32_t minimum_window() const = 0; + virtual float loss_reduction_factor() const = 0; + virtual uint32_t persistent_congestion_threshold() const = 0; +}; + // TODO: move version independent functions to QUICInvariants class QUICTypeUtil { diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 9f76b64f5db..dd8d6c3f218 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -36,12 +36,14 @@ TEST_CASE("QUICFrameHandler", "[quic]") QUICStreamFrame streamFrame(block, 0x03, 0); + MockQUICLDConfig ld_config; + MockQUICCCConfig cc_config; MockQUICConnection connection; MockQUICStreamManager streamManager; MockQUICConnectionInfoProvider info; - MockQUICCongestionController cc(&info); + MockQUICCongestionController cc(&info, cc_config); QUICRTTMeasure rtt_measure; - MockQUICLossDetector lossDetector(&info, &cc, &rtt_measure, 0); + MockQUICLossDetector lossDetector(&info, &cc, &rtt_measure, 0, ld_config); QUICFrameDispatcher quicFrameDispatcher(&info); quicFrameDispatcher.add_handler(&connection); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 814e94fb9e5..096c7f4817f 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -36,9 +36,11 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") QUICAckFrameManager afm; QUICConnectionId connection_id = {reinterpret_cast("\x01"), 1}; + MockQUICCCConfig cc_config; + MockQUICLDConfig ld_config; MockQUICConnectionInfoProvider info; - MockQUICCongestionController cc(&info); - QUICLossDetector detector(&info, &cc, &rtt_measure, 0); + MockQUICCongestionController cc(&info, cc_config); + QUICLossDetector detector(&info, &cc, &rtt_measure, 0, ld_config); ats_unique_buf payload = ats_unique_malloc(512); size_t payload_len = 512; QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); @@ -250,9 +252,11 @@ TEST_CASE("QUICLossDetector_HugeGap", "[quic]") { uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; MockQUICConnectionInfoProvider info; - MockQUICCongestionController cc(&info); + MockQUICCCConfig cc_config; + MockQUICLDConfig ld_config; + MockQUICCongestionController cc(&info, cc_config); QUICRTTMeasure rtt_measure; - QUICLossDetector detector(&info, &cc, &rtt_measure, 0); + QUICLossDetector detector(&info, &cc, &rtt_measure, 0, ld_config); auto t1 = Thread::get_hrtime(); QUICAckFrame *ack = QUICFrameFactory::create_ack_frame(frame_buf, 100000000, 100, 10000000); From f69fb7e42bc8815aff032b5018c84133b8c29fef Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 11 Mar 2019 13:56:28 +0900 Subject: [PATCH 1200/1313] Have a QUICConfigParams as a member of QNetVC --- iocore/net/P_QUICNetVConnection.h | 3 ++ iocore/net/QUICNetVConnection.cc | 55 ++++++++++++++----------------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index b90d3d4cc23..160ddbe5af3 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -40,6 +40,7 @@ #include "tscore/ink_apidefs.h" #include "tscore/List.h" +#include "quic/QUICConfig.h" #include "quic/QUICConnection.h" #include "quic/QUICConnectionTable.h" #include "quic/QUICVersionNegotiator.h" @@ -208,6 +209,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub private: std::random_device _rnd; + QUICConfig::scoped_config _quic_config; + QUICConnectionId _peer_quic_connection_id; // dst cid in local QUICConnectionId _peer_old_quic_connection_id; // dst previous cid in local QUICConnectionId _original_quic_connection_id; // dst cid of initial packet from client diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 0b8ce4eddbc..810120c132a 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -419,7 +419,6 @@ void QUICNetVConnection::start() { ink_release_assert(this->thread != nullptr); - QUICConfig::scoped_config params; this->_five_tuple.update(this->local_addr, this->remote_addr, SOCK_DGRAM); // Version 0x00000001 uses stream 0 for cryptographic handshake with TLS 1.3, but newer version may not @@ -427,22 +426,23 @@ QUICNetVConnection::start() QUICCertConfig::scoped_config server_cert; this->_pp_key_info.set_context(QUICPacketProtectionKeyInfo::Context::SERVER); - this->_ack_frame_manager.set_ack_delay_exponent(params->ack_delay_exponent_in()); - this->_reset_token = QUICStatelessResetToken(this->_quic_connection_id, params->instance_id()); - this->_hs_protocol = this->_setup_handshake_protocol(server_cert->ssl_default); - this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol, this->_reset_token, params->stateless_retry()); - this->_ack_frame_manager.set_max_ack_delay(params->max_ack_delay_in()); - this->_schedule_ack_manager_periodic(params->max_ack_delay_in()); + this->_ack_frame_manager.set_ack_delay_exponent(this->_quic_config->ack_delay_exponent_in()); + this->_reset_token = QUICStatelessResetToken(this->_quic_connection_id, this->_quic_config->instance_id()); + this->_hs_protocol = this->_setup_handshake_protocol(server_cert->ssl_default); + this->_handshake_handler = + new QUICHandshake(this, this->_hs_protocol, this->_reset_token, this->_quic_config->stateless_retry()); + this->_ack_frame_manager.set_max_ack_delay(this->_quic_config->max_ack_delay_in()); + this->_schedule_ack_manager_periodic(this->_quic_config->max_ack_delay_in()); } else { - QUICTPConfigQCP tp_config(params, NET_VCONNECTION_OUT); + QUICTPConfigQCP tp_config(this->_quic_config, NET_VCONNECTION_OUT); this->_pp_key_info.set_context(QUICPacketProtectionKeyInfo::Context::CLIENT); - this->_ack_frame_manager.set_ack_delay_exponent(params->ack_delay_exponent_out()); - this->_hs_protocol = this->_setup_handshake_protocol(params->client_ssl_ctx()); + this->_ack_frame_manager.set_ack_delay_exponent(this->_quic_config->ack_delay_exponent_out()); + this->_hs_protocol = this->_setup_handshake_protocol(this->_quic_config->client_ssl_ctx()); this->_handshake_handler = new QUICHandshake(this, this->_hs_protocol); - this->_handshake_handler->start(tp_config, &this->_packet_factory, params->vn_exercise_enabled()); + this->_handshake_handler->start(tp_config, &this->_packet_factory, this->_quic_config->vn_exercise_enabled()); this->_handshake_handler->do_handshake(); - this->_ack_frame_manager.set_max_ack_delay(params->max_ack_delay_out()); - this->_schedule_ack_manager_periodic(params->max_ack_delay_out()); + 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->_application_map = new QUICApplicationMap(); @@ -450,8 +450,8 @@ QUICNetVConnection::start() this->_frame_dispatcher = new QUICFrameDispatcher(this); // Create frame handlers - QUICCCConfigQCP cc_config(params); - QUICLDConfigQCP ld_config(params); + QUICCCConfigQCP cc_config(this->_quic_config); + QUICLDConfigQCP ld_config(this->_quic_config); this->_congestion_controller = new QUICCongestionController(this, cc_config); for (auto s : QUIC_PN_SPACES) { int index = static_cast(s); @@ -747,12 +747,10 @@ QUICNetVConnection::state_pre_handshake(int event, Event *data) } // FIXME: Should be accept_no_activity_timeout? - QUICConfig::scoped_config params; - if (this->get_context() == NET_VCONNECTION_IN) { - this->set_inactivity_timeout(HRTIME_SECONDS(params->no_activity_timeout_in())); + this->set_inactivity_timeout(HRTIME_SECONDS(this->_quic_config->no_activity_timeout_in())); } else { - this->set_inactivity_timeout(HRTIME_SECONDS(params->no_activity_timeout_out())); + this->set_inactivity_timeout(HRTIME_SECONDS(this->_quic_config->no_activity_timeout_out())); } this->add_to_active_queue(); @@ -1135,15 +1133,15 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe // Start handshake if (this->netvc_context == NET_VCONNECTION_IN) { - QUICConfig::scoped_config params; if (!this->_alt_con_manager) { - this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, - params->instance_id(), params->num_alt_connection_ids(), - params->preferred_address_ipv4(), params->preferred_address_ipv6()); + this->_alt_con_manager = + new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, this->_quic_config->instance_id(), + this->_quic_config->num_alt_connection_ids(), this->_quic_config->preferred_address_ipv4(), + this->_quic_config->preferred_address_ipv6()); this->_frame_generators.push_back(this->_alt_con_manager); this->_frame_dispatcher->add_handler(this->_alt_con_manager); } - QUICTPConfigQCP tp_config(params, NET_VCONNECTION_IN); + QUICTPConfigQCP tp_config(this->_quic_config, NET_VCONNECTION_IN); error = this->_handshake_handler->start(tp_config, packet.get(), &this->_packet_factory, this->_alt_con_manager->preferred_address()); @@ -1250,8 +1248,7 @@ QUICNetVConnection::_state_connection_established_process_protected_packet(QUICP } // For Connection Migration excercise - QUICConfig::scoped_config params; - if (this->netvc_context == NET_VCONNECTION_OUT && params->cm_exercise_enabled()) { + if (this->netvc_context == NET_VCONNECTION_OUT && this->_quic_config->cm_exercise_enabled()) { this->_state_connection_established_initiate_connection_migration(); } @@ -2010,10 +2007,9 @@ QUICNetVConnection::_switch_to_established_state() std::shared_ptr remote_tp = this->_handshake_handler->remote_transport_parameters(); const uint8_t *pref_addr_buf; uint16_t len; - QUICConfig::scoped_config params; pref_addr_buf = remote_tp->getAsBytes(QUICTransportParameterId::PREFERRED_ADDRESS, len); this->_alt_con_manager = new QUICAltConnectionManager(this, *this->_ctable, this->_peer_quic_connection_id, - params->instance_id(), 1, {pref_addr_buf, len}); + this->_quic_config->instance_id(), 1, {pref_addr_buf, len}); this->_frame_generators.push_back(this->_alt_con_manager); this->_frame_dispatcher->add_handler(this->_alt_con_manager); } @@ -2189,8 +2185,7 @@ QUICNetVConnection::_setup_handshake_protocol(SSL_CTX *ctx) { // Initialize handshake protocol specific stuff // For QUICv1 TLS is the only option - QUICConfig::scoped_config params; - QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx, this->direction(), params->session_file()); + QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx, this->direction(), this->_quic_config->session_file()); SSL_set_ex_data(tls->ssl_handle(), QUIC::ssl_quic_qc_index, static_cast(this)); return tls; } From a311a79516e41a70a72d5bcb757b5ac9f46a5edb Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 11 Mar 2019 14:10:35 +0900 Subject: [PATCH 1201/1313] Get session filename from QUICTLS --- iocore/net/quic/QUICGlobals.cc | 7 +++++-- iocore/net/quic/QUICTLS.cc | 6 ++++++ iocore/net/quic/QUICTLS.h | 5 ++++- iocore/net/quic/QUICTLS_openssl.cc | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index 2033959094a..0798020d165 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -31,6 +31,9 @@ #include "QUICConfig.h" #include "QUICConnection.h" +#include "QUICTLS.h" +#include + #define QUICGlobalDebug(fmt, ...) Debug("quic_global", fmt, ##__VA_ARGS__) #define QUICGlobalQCDebug(qc, fmt, ...) Debug("quic_global", "[%s] " fmt, qc->cids().data(), ##__VA_ARGS__) @@ -68,8 +71,8 @@ QUIC::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned cha int QUIC::ssl_client_new_session(SSL *ssl, SSL_SESSION *session) { - QUICConfig::scoped_config params; - const char *session_file = params->session_file(); + QUICTLS *qtls = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_tls_index)); + const char *session_file = qtls->session_file(); auto file = BIO_new_file(session_file, "w"); if (file == nullptr) { diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index 7852596499a..de11e02ebd7 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -62,6 +62,12 @@ QUICTLS::set_remote_transport_parameters(std::shared_ptr_remote_transport_parameters = tp; } +const char * +QUICTLS::session_file() const +{ + return this->_session_file; +} + QUICTLS::~QUICTLS() { SSL_free(this->_ssl); diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 8fda0f39ee8..5e8d13d984c 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -57,11 +57,12 @@ class QUICTLS : public QUICHandshakeProtocol void set_local_transport_parameters(std::shared_ptr tp) override; void set_remote_transport_parameters(std::shared_ptr tp) override; + const char *session_file() const; + // FIXME Should not exist SSL *ssl_handle(); // QUICHandshakeProtocol - int handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in) override; void reset() override; bool is_handshake_finished() const override; @@ -78,6 +79,8 @@ class QUICTLS : public QUICHandshakeProtocol QUICKeyGenerator _keygen_for_server = QUICKeyGenerator(QUICKeyGenerator::Context::SERVER); const EVP_MD *_get_handshake_digest() const; + const char *_session_file; + int _read_early_data(); int _write_early_data(); int _handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in); diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 824cd600384..d9951fe7b59 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -330,7 +330,7 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx, const char *session_file) - : QUICHandshakeProtocol(pp_key_info), _ssl(SSL_new(ssl_ctx)), _netvc_context(nvc_ctx) + : QUICHandshakeProtocol(pp_key_info), _session_file(session_file), _ssl(SSL_new(ssl_ctx)), _netvc_context(nvc_ctx) { ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); From 96f0032edfd255033a448b9aa7175bf234a6a8ab Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 11 Mar 2019 14:16:36 +0900 Subject: [PATCH 1202/1313] Remove redundant QUICConfig::scoped_config --- iocore/net/QUICPacketHandler.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 6d693cd79f9..0e1b32917b4 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -295,7 +295,6 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // 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)) { - QUICConfig::scoped_config params; 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); From 08bcbdc5f8656df6d36119f13ed862c8444b07c9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 11 Mar 2019 16:11:34 +0900 Subject: [PATCH 1203/1313] Add virtual destructor to HQClientSession / HQClientTransaction --- proxy/http3/Http3ClientSession.cc | 2 -- proxy/http3/Http3ClientSession.h | 2 +- proxy/http3/Http3ClientTransaction.h | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3ClientSession.cc index 3fdd13d2a0f..d1d4e2afbd0 100644 --- a/proxy/http3/Http3ClientSession.cc +++ b/proxy/http3/Http3ClientSession.cc @@ -146,7 +146,6 @@ Http3ClientSession::~Http3ClientSession() this->_client_vc = nullptr; delete this->_local_qpack; delete this->_remote_qpack; - super::~HQClientSession(); } const char * @@ -198,7 +197,6 @@ Http3ClientSession::remote_qpack() Http09ClientSession::~Http09ClientSession() { this->_client_vc = nullptr; - super::~HQClientSession(); } const char * diff --git a/proxy/http3/Http3ClientSession.h b/proxy/http3/Http3ClientSession.h index 996de11299e..190726a6afa 100644 --- a/proxy/http3/Http3ClientSession.h +++ b/proxy/http3/Http3ClientSession.h @@ -33,7 +33,7 @@ class HQClientSession : public ProxyClientSession using super = ProxyClientSession; ///< Parent type HQClientSession(NetVConnection *vc) : _client_vc(vc){}; - ~HQClientSession(); + virtual ~HQClientSession(); // Implement VConnection interface VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) override; diff --git a/proxy/http3/Http3ClientTransaction.h b/proxy/http3/Http3ClientTransaction.h index 9d415ad6e4f..2d166635ef3 100644 --- a/proxy/http3/Http3ClientTransaction.h +++ b/proxy/http3/Http3ClientTransaction.h @@ -41,7 +41,7 @@ class HQClientTransaction : public ProxyClientTransaction using super = ProxyClientTransaction; HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io); - ~HQClientTransaction(); + virtual ~HQClientTransaction(); // Implement ProxyClienTransaction interface void set_active_timeout(ink_hrtime timeout_in) override; From 0f10526fa786bf11c24c585e44d399c504ea669d Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 11 Mar 2019 15:38:23 +0800 Subject: [PATCH 1204/1313] QUIC: split out QUICBidiredirectionalStream --- iocore/net/quic/Makefile.am | 3 +- iocore/net/quic/QUICBidirectionalStream.cc | 606 +++++++++++++++++++++ iocore/net/quic/QUICBidirectionalStream.h | 105 ++++ iocore/net/quic/QUICStream.cc | 601 +------------------- iocore/net/quic/QUICStream.h | 98 +--- iocore/net/quic/QUICStreamManager.h | 2 +- 6 files changed, 734 insertions(+), 681 deletions(-) create mode 100644 iocore/net/quic/QUICBidirectionalStream.cc create mode 100644 iocore/net/quic/QUICBidirectionalStream.h diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index ae4a93a68c8..66743febf19 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -86,7 +86,8 @@ libquic_a_SOURCES = \ QUICPinger.cc \ QUICFrameGenerator.cc \ QUICFrameRetransmitter.cc \ - QUICAddrVerifyState.cc + QUICAddrVerifyState.cc \ + QUICBidirectionalStream.cc # # Check Programs diff --git a/iocore/net/quic/QUICBidirectionalStream.cc b/iocore/net/quic/QUICBidirectionalStream.cc new file mode 100644 index 00000000000..8cc183fddfc --- /dev/null +++ b/iocore/net/quic/QUICBidirectionalStream.cc @@ -0,0 +1,606 @@ +/** @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 "QUICBidirectionalStream.h" + +// +// QUICBidirectionalStream +// +QUICBidirectionalStream::QUICBidirectionalStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, + uint64_t recv_max_stream_data, uint64_t send_max_stream_data) + : QUICStreamVConnection(cinfo, sid), + _remote_flow_controller(send_max_stream_data, _id), + _local_flow_controller(rtt_provider, recv_max_stream_data, _id), + _flow_control_buffer_size(recv_max_stream_data), + _state(nullptr, &this->_progress_vio, this, nullptr) +{ + SET_HANDLER(&QUICBidirectionalStream::state_stream_open); + + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), + this->_local_flow_controller.current_limit()); + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); +} + +int +QUICBidirectionalStream::state_stream_open(int event, void *data) +{ + QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); + QUICErrorUPtr error = nullptr; + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + int64_t len = this->_process_read_vio(); + if (len > 0) { + this->_signal_read_event(); + } + + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); + } + + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + // TODO + ink_assert(false); + break; + } + default: + QUICStreamDebug("unknown event"); + ink_assert(false); + } + + // FIXME error is always nullptr + if (error != nullptr) { + if (error->cls == QUICErrorClass::TRANSPORT) { + QUICStreamDebug("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), QUICDebugNames::error_code(error->code), + static_cast(error->code)); + } else { + QUICStreamDebug("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), static_cast(error->code)); + } + if (dynamic_cast(error.get()) != nullptr) { + // Stream Error + QUICStreamErrorUPtr serror = QUICStreamErrorUPtr(static_cast(error.get())); + this->reset(std::move(serror)); + } else { + // Connection Error + // TODO Close connection (Does this really happen?) + } + } + + return EVENT_DONE; +} + +int +QUICBidirectionalStream::state_stream_closed(int event, void *data) +{ + QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + // ignore + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + // ignore + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + // TODO + ink_assert(false); + break; + } + default: + ink_assert(false); + } + + return EVENT_DONE; +} + +bool +QUICBidirectionalStream::is_transfer_goal_set() const +{ + return this->_received_stream_frame_buffer.is_transfer_goal_set(); +} + +uint64_t +QUICBidirectionalStream::transfer_progress() const +{ + return this->_received_stream_frame_buffer.transfer_progress(); +} + +uint64_t +QUICBidirectionalStream::transfer_goal() const +{ + return this->_received_stream_frame_buffer.transfer_goal(); +} + +bool +QUICBidirectionalStream::is_cancelled() const +{ + return this->_is_reset_complete; +} + +/** + * @brief Receive STREAM frame + * @detail When receive STREAM frame, reorder frames and write to buffer of read_vio. + * If the reordering or writting operation is heavy, split out them to read function, + * which is called by application via do_io_read() or reenable(). + */ +QUICConnectionErrorUPtr +QUICBidirectionalStream::recv(const QUICStreamFrame &frame) +{ + ink_assert(_id == frame.stream_id()); + ink_assert(this->_read_vio.op == VIO::READ); + + // Check stream state - Do this first before accept the frame + if (!this->_state.is_allowed_to_receive(frame)) { + QUICStreamDebug("Canceled receiving %s frame due to the stream state", QUICDebugNames::frame_type(frame.type())); + return std::make_unique(QUICTransErrorCode::STREAM_STATE_ERROR); + } + + // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit + int ret = this->_local_flow_controller.update(frame.offset() + frame.data_length()); + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), + this->_local_flow_controller.current_limit()); + if (ret != 0) { + return std::make_unique(QUICTransErrorCode::FLOW_CONTROL_ERROR); + } + + // Make a copy and insert it into the receive buffer because the frame passed is temporal + QUICFrame *cloned = new QUICStreamFrame(frame); + QUICConnectionErrorUPtr error = this->_received_stream_frame_buffer.insert(cloned); + if (error != nullptr) { + this->_received_stream_frame_buffer.clear(); + return error; + } + + auto new_frame = this->_received_stream_frame_buffer.pop(); + const QUICStreamFrame *stream_frame = nullptr; + uint64_t last_offset = 0; + uint64_t last_length = 0; + + while (new_frame != nullptr) { + stream_frame = static_cast(new_frame); + last_offset = stream_frame->offset(); + last_length = stream_frame->data_length(); + + this->_write_to_read_vio(stream_frame->offset(), reinterpret_cast(stream_frame->data()->start()), + stream_frame->data_length(), stream_frame->has_fin_flag()); + this->_state.update_with_receiving_frame(*new_frame); + + delete new_frame; + new_frame = this->_received_stream_frame_buffer.pop(); + } + + // Forward limit of local flow controller with the largest reordered stream frame + if (stream_frame) { + this->_reordered_bytes = last_offset + last_length; + this->_local_flow_controller.forward_limit(this->_reordered_bytes + this->_flow_control_buffer_size); + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), + this->_local_flow_controller.current_limit()); + } + + this->_signal_read_event(); + + return nullptr; +} + +QUICConnectionErrorUPtr +QUICBidirectionalStream::recv(const QUICMaxStreamDataFrame &frame) +{ + this->_remote_flow_controller.forward_limit(frame.maximum_stream_data()); + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); + + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); + } + + return nullptr; +} + +QUICConnectionErrorUPtr +QUICBidirectionalStream::recv(const QUICStreamDataBlockedFrame &frame) +{ + // STREAM_DATA_BLOCKED frames are for debugging. Nothing to do here. + QUICStreamFCDebug("[REMOTE] blocked %" PRIu64, frame.offset()); + return nullptr; +} + +QUICConnectionErrorUPtr +QUICBidirectionalStream::recv(const QUICStopSendingFrame &frame) +{ + this->_state.update_with_receiving_frame(frame); + this->_reset_reason = QUICStreamErrorUPtr(new QUICStreamError(this, QUIC_APP_ERROR_CODE_STOPPING)); + // We received and processed STOP_SENDING frame, so return NO_ERROR here + return nullptr; +} + +QUICConnectionErrorUPtr +QUICBidirectionalStream::recv(const QUICRstStreamFrame &frame) +{ + this->_state.update_with_receiving_frame(frame); + this->_signal_read_eos_event(); + return nullptr; +} + +// this->_read_vio.nbytes should be INT64_MAX until receive FIN flag +VIO * +QUICBidirectionalStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + if (buf) { + this->_read_vio.buffer.writer_for(buf); + } else { + this->_read_vio.buffer.clear(); + } + + this->_read_vio.mutex = c ? c->mutex : this->mutex; + this->_read_vio.cont = c; + this->_read_vio.nbytes = nbytes; + this->_read_vio.ndone = 0; + this->_read_vio.vc_server = this; + this->_read_vio.op = VIO::READ; + + this->_process_read_vio(); + this->_send_tracked_event(this->_read_event, VC_EVENT_READ_READY, &this->_read_vio); + + return &this->_read_vio; +} + +VIO * +QUICBidirectionalStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +{ + if (buf) { + this->_write_vio.buffer.reader_for(buf); + } else { + this->_write_vio.buffer.clear(); + } + + this->_write_vio.mutex = c ? c->mutex : this->mutex; + this->_write_vio.cont = c; + this->_write_vio.nbytes = nbytes; + this->_write_vio.ndone = 0; + this->_write_vio.vc_server = this; + this->_write_vio.op = VIO::WRITE; + + this->_process_write_vio(); + this->_send_tracked_event(this->_write_event, VC_EVENT_WRITE_READY, &this->_write_vio); + + return &this->_write_vio; +} + +void +QUICBidirectionalStream::do_io_close(int lerrno) +{ + SET_HANDLER(&QUICBidirectionalStream::state_stream_closed); + + this->_read_vio.buffer.clear(); + this->_read_vio.nbytes = 0; + this->_read_vio.op = VIO::NONE; + this->_read_vio.cont = nullptr; + + this->_write_vio.buffer.clear(); + this->_write_vio.nbytes = 0; + this->_write_vio.op = VIO::NONE; + this->_write_vio.cont = nullptr; +} + +void +QUICBidirectionalStream::do_io_shutdown(ShutdownHowTo_t howto) +{ + ink_assert(false); // unimplemented yet + return; +} + +void +QUICBidirectionalStream::reenable(VIO *vio) +{ + if (vio->op == VIO::READ) { + QUICVStreamDebug("read_vio reenabled"); + + int64_t len = this->_process_read_vio(); + if (len > 0) { + this->_signal_read_event(); + } + } else if (vio->op == VIO::WRITE) { + QUICVStreamDebug("write_vio reenabled"); + + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); + } + } +} + +bool +QUICBidirectionalStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) +{ + return this->_local_flow_controller.will_generate_frame(level, timestamp) || !this->is_retransmited_frame_queue_empty() || + (this->_write_vio.get_reader()->read_avail() > 0); +} + +QUICFrame * +QUICBidirectionalStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, + uint16_t maximum_frame_size, ink_hrtime timestamp) +{ + SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); + + QUICFrame *frame = this->create_retransmitted_frame(buf, level, maximum_frame_size, this->_issue_frame_id(), this); + if (frame != nullptr) { + ink_assert(frame->type() == QUICFrameType::STREAM); + this->_records_stream_frame(level, *static_cast(frame)); + return frame; + } + + // RESET_STREAM + if (this->_reset_reason && !this->_is_reset_sent) { + frame = QUICFrameFactory::create_rst_stream_frame(buf, *this->_reset_reason, this->_issue_frame_id(), this); + this->_records_rst_stream_frame(level, *static_cast(frame)); + this->_state.update_with_sending_frame(*frame); + this->_is_reset_sent = true; + return frame; + } + + // STOP_SENDING + if (this->_stop_sending_reason && !this->_is_stop_sending_sent) { + frame = + QUICFrameFactory::create_stop_sending_frame(buf, this->id(), this->_stop_sending_reason->code, this->_issue_frame_id(), this); + this->_records_stop_sending_frame(level, *static_cast(frame)); + this->_state.update_with_sending_frame(*frame); + this->_is_stop_sending_sent = true; + return frame; + } + + // MAX_STREAM_DATA + frame = this->_local_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size, timestamp); + if (frame) { + return frame; + } + + if (!this->_state.is_allowed_to_send(QUICFrameType::STREAM)) { + return frame; + } + + uint64_t maximum_data_size = 0; + if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) { + return frame; + } + maximum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD; + + bool pure_fin = false; + bool fin = false; + if ((this->_write_vio.nbytes != 0 || this->_write_vio.nbytes != INT64_MAX) && + this->_write_vio.nbytes == static_cast(this->_send_offset)) { + // Pure FIN stream should be sent regardless status of remote flow controller, because the length is zero. + pure_fin = true; + fin = true; + } + + uint64_t len = 0; + IOBufferReader *reader = this->_write_vio.get_reader(); + if (!pure_fin) { + uint64_t data_len = reader->block_read_avail(); + if (data_len == 0) { + return frame; + } + + // Check Connection/Stream level credit only if the generating STREAM frame is not pure fin + uint64_t stream_credit = this->_remote_flow_controller.credit(); + if (stream_credit == 0) { + // STREAM_DATA_BLOCKED + frame = this->_remote_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size, timestamp); + return frame; + } + + if (connection_credit == 0) { + // BLOCKED - BLOCKED frame will be sent by connection level remote flow controller + return frame; + } + + len = std::min(data_len, std::min(maximum_data_size, std::min(stream_credit, connection_credit))); + + // data_len, maximum_data_size, stream_credit and connection_credit are already checked they're larger than 0 + ink_assert(len != 0); + + if (this->_write_vio.nbytes == static_cast(this->_send_offset + len)) { + fin = true; + } + } + + Ptr block = make_ptr(reader->get_current_block()->clone()); + block->consume(reader->start_offset); + block->_end = std::min(block->start() + len, block->_buf_end); + ink_assert(static_cast(block->read_avail()) == len); + + // STREAM - Pure FIN or data length is lager than 0 + // FIXME has_length_flag and has_offset_flag should be configurable + frame = QUICFrameFactory::create_stream_frame(buf, block, this->_id, this->_send_offset, fin, true, true, this->_issue_frame_id(), + this); + if (!this->_state.is_allowed_to_send(*frame)) { + QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); + return frame; + } + + if (!pure_fin) { + int ret = this->_remote_flow_controller.update(this->_send_offset + len); + // We cannot cancel sending the frame after updating the flow controller + + // Calling update always success, because len is always less than stream_credit + ink_assert(ret == 0); + + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); + if (this->_remote_flow_controller.current_offset() == this->_remote_flow_controller.current_limit()) { + QUICStreamDebug("Flow Controller will block sending a STREAM frame"); + } + + reader->consume(len); + this->_send_offset += len; + this->_write_vio.ndone += len; + } + this->_records_stream_frame(level, *static_cast(frame)); + + this->_signal_write_event(); + this->_state.update_with_sending_frame(*frame); + + return frame; +} + +void +QUICBidirectionalStream::_records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame) +{ + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = frame.type(); + info->level = level; + StreamFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->stream_id = frame.stream_id(); + frame_info->offset = frame.offset(); + frame_info->has_fin = frame.has_fin_flag(); + frame_info->block = frame.data(); + this->_records_frame(frame.id(), std::move(info)); +} + +void +QUICBidirectionalStream::_records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame) +{ + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = frame.type(); + info->level = level; + RstStreamFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->error_code = frame.error_code(); + frame_info->final_offset = frame.final_offset(); + this->_records_frame(frame.id(), std::move(info)); +} + +void +QUICBidirectionalStream::_records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame) +{ + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = frame.type(); + info->level = level; + StopSendingFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->error_code = frame.error_code(); + this->_records_frame(frame.id(), std::move(info)); +} + +void +QUICBidirectionalStream::_on_frame_acked(QUICFrameInformationUPtr &info) +{ + StreamFrameInfo *frame_info = nullptr; + switch (info->type) { + case QUICFrameType::RESET_STREAM: + this->_is_reset_complete = true; + break; + case QUICFrameType::STREAM: + frame_info = reinterpret_cast(info->data); + frame_info->block = nullptr; + if (false) { + this->_is_transfer_complete = true; + } + break; + case QUICFrameType::STOP_SENDING: + default: + break; + } + + this->_state.update_on_ack(); +} + +void +QUICBidirectionalStream::_on_frame_lost(QUICFrameInformationUPtr &info) +{ + switch (info->type) { + case QUICFrameType::RESET_STREAM: + // [draft-16] 13.2. Retransmission of Information + // Cancellation of stream transmission, as carried in a RESET_STREAM + // frame, is sent until acknowledged or until all stream data is + // acknowledged by the peer (that is, either the "Reset Recvd" or + // "Data Recvd" state is reached on the send stream). The content of + // a RESET_STREAM frame MUST NOT change when it is sent again. + this->_is_reset_sent = false; + break; + case QUICFrameType::STREAM: + this->save_frame_info(std::move(info)); + break; + case QUICFrameType::STOP_SENDING: + this->_is_stop_sending_sent = false; + break; + default: + break; + } +} + +void +QUICBidirectionalStream::stop_sending(QUICStreamErrorUPtr error) +{ + this->_stop_sending_reason = std::move(error); +} + +void +QUICBidirectionalStream::reset(QUICStreamErrorUPtr error) +{ + this->_reset_reason = std::move(error); +} + +void +QUICBidirectionalStream::on_read() +{ + this->_state.update_on_read(); +} + +void +QUICBidirectionalStream::on_eos() +{ + this->_state.update_on_eos(); +} + +QUICOffset +QUICBidirectionalStream::largest_offset_received() const +{ + return this->_local_flow_controller.current_offset(); +} + +QUICOffset +QUICBidirectionalStream::largest_offset_sent() const +{ + return this->_remote_flow_controller.current_offset(); +} diff --git a/iocore/net/quic/QUICBidirectionalStream.h b/iocore/net/quic/QUICBidirectionalStream.h new file mode 100644 index 00000000000..aa75536497a --- /dev/null +++ b/iocore/net/quic/QUICBidirectionalStream.h @@ -0,0 +1,105 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICStream.h" + +class QUICBidirectionalStream : public QUICStreamVConnection, public QUICTransferProgressProvider +{ +public: + QUICBidirectionalStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, + uint64_t recv_max_stream_data, uint64_t send_max_stream_data); + QUICBidirectionalStream() + : QUICStreamVConnection(), + _remote_flow_controller(0, 0), + _local_flow_controller(nullptr, 0, 0), + _state(nullptr, nullptr, nullptr, nullptr) + { + } + + int state_stream_open(int event, void *data); + int state_stream_closed(int event, void *data); + + // QUICFrameGenerator + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; + + virtual QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame) override; + virtual QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame) override; + virtual QUICConnectionErrorUPtr recv(const QUICStreamDataBlockedFrame &frame) override; + virtual QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame) override; + virtual QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame) override; + + // Implement VConnection Interface. + VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; + VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; + void do_io_close(int lerrno = -1) override; + void do_io_shutdown(ShutdownHowTo_t howto) override; + void reenable(VIO *vio) override; + + void stop_sending(QUICStreamErrorUPtr error) override; + void reset(QUICStreamErrorUPtr error) override; + + // QUICTransferProgressProvider + bool is_transfer_goal_set() const override; + uint64_t transfer_progress() const override; + uint64_t transfer_goal() const override; + bool is_cancelled() const override; + + /* + * QUICApplication need to call one of these functions when it process VC_EVENT_* + */ + virtual void on_read() override; + virtual void on_eos() override; + + QUICOffset largest_offset_received() const override; + QUICOffset largest_offset_sent() const override; + +private: + QUICStreamErrorUPtr _reset_reason = nullptr; + bool _is_reset_sent = false; + QUICStreamErrorUPtr _stop_sending_reason = nullptr; + bool _is_stop_sending_sent = false; + + bool _is_transfer_complete = false; + bool _is_reset_complete = false; + + QUICTransferProgressProviderVIO _progress_vio = {this->_read_vio}; + + QUICRemoteStreamFlowController _remote_flow_controller; + QUICLocalStreamFlowController _local_flow_controller; + uint64_t _flow_control_buffer_size = 1024; + + // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState + QUICBidirectionalStreamStateMachine _state; + + void _records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame); + void _records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame); + void _records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame); + + // QUICFrameGenerator + void _on_frame_acked(QUICFrameInformationUPtr &info) override; + void _on_frame_lost(QUICFrameInformationUPtr &info) override; +}; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 9c087658256..cf75c8c0a90 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -23,25 +23,10 @@ #include "QUICStream.h" -#include "I_Event.h" -#include "P_VConnection.h" #include "QUICStreamManager.h" -#include "QUICDebugNames.h" -#define QUICStreamDebug(fmt, ...) \ - Debug("quic_stream", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ - QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__) - -#define QUICVStreamDebug(fmt, ...) \ - Debug("v_quic_stream", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ - QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__) - -#define QUICStreamFCDebug(fmt, ...) \ - Debug("quic_flow_ctrl", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ - QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__) - -static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; -static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; +constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; +constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; QUICStream::QUICStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid) : _connection_info(cinfo), _id(sid), _received_stream_frame_buffer() @@ -254,588 +239,6 @@ QUICStreamVConnection::_process_write_vio() return 0; } -// -// QUICBidirectionalStream -// -QUICBidirectionalStream::QUICBidirectionalStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, - uint64_t recv_max_stream_data, uint64_t send_max_stream_data) - : QUICStreamVConnection(cinfo, sid), - _remote_flow_controller(send_max_stream_data, _id), - _local_flow_controller(rtt_provider, recv_max_stream_data, _id), - _flow_control_buffer_size(recv_max_stream_data), - _state(nullptr, &this->_progress_vio, this, nullptr) -{ - SET_HANDLER(&QUICBidirectionalStream::state_stream_open); - - QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), - this->_local_flow_controller.current_limit()); - QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), - this->_remote_flow_controller.current_limit()); -} - -int -QUICBidirectionalStream::state_stream_open(int event, void *data) -{ - QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); - QUICErrorUPtr error = nullptr; - - switch (event) { - case VC_EVENT_READ_READY: - case VC_EVENT_READ_COMPLETE: { - int64_t len = this->_process_read_vio(); - if (len > 0) { - this->_signal_read_event(); - } - - break; - } - case VC_EVENT_WRITE_READY: - case VC_EVENT_WRITE_COMPLETE: { - int64_t len = this->_process_write_vio(); - if (len > 0) { - this->_signal_write_event(); - } - - break; - } - case VC_EVENT_EOS: - case VC_EVENT_ERROR: - case VC_EVENT_INACTIVITY_TIMEOUT: - case VC_EVENT_ACTIVE_TIMEOUT: { - // TODO - ink_assert(false); - break; - } - default: - QUICStreamDebug("unknown event"); - ink_assert(false); - } - - // FIXME error is always nullptr - if (error != nullptr) { - if (error->cls == QUICErrorClass::TRANSPORT) { - QUICStreamDebug("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), - static_cast(error->cls), QUICDebugNames::error_code(error->code), - static_cast(error->code)); - } else { - QUICStreamDebug("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls), - static_cast(error->cls), static_cast(error->code)); - } - if (dynamic_cast(error.get()) != nullptr) { - // Stream Error - QUICStreamErrorUPtr serror = QUICStreamErrorUPtr(static_cast(error.get())); - this->reset(std::move(serror)); - } else { - // Connection Error - // TODO Close connection (Does this really happen?) - } - } - - return EVENT_DONE; -} - -int -QUICBidirectionalStream::state_stream_closed(int event, void *data) -{ - QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); - - switch (event) { - case VC_EVENT_READ_READY: - case VC_EVENT_READ_COMPLETE: { - // ignore - break; - } - case VC_EVENT_WRITE_READY: - case VC_EVENT_WRITE_COMPLETE: { - // ignore - break; - } - case VC_EVENT_EOS: - case VC_EVENT_ERROR: - case VC_EVENT_INACTIVITY_TIMEOUT: - case VC_EVENT_ACTIVE_TIMEOUT: { - // TODO - ink_assert(false); - break; - } - default: - ink_assert(false); - } - - return EVENT_DONE; -} - -bool -QUICBidirectionalStream::is_transfer_goal_set() const -{ - return this->_received_stream_frame_buffer.is_transfer_goal_set(); -} - -uint64_t -QUICBidirectionalStream::transfer_progress() const -{ - return this->_received_stream_frame_buffer.transfer_progress(); -} - -uint64_t -QUICBidirectionalStream::transfer_goal() const -{ - return this->_received_stream_frame_buffer.transfer_goal(); -} - -bool -QUICBidirectionalStream::is_cancelled() const -{ - return this->_is_reset_complete; -} - -/** - * @brief Receive STREAM frame - * @detail When receive STREAM frame, reorder frames and write to buffer of read_vio. - * If the reordering or writting operation is heavy, split out them to read function, - * which is called by application via do_io_read() or reenable(). - */ -QUICConnectionErrorUPtr -QUICBidirectionalStream::recv(const QUICStreamFrame &frame) -{ - ink_assert(_id == frame.stream_id()); - ink_assert(this->_read_vio.op == VIO::READ); - - // Check stream state - Do this first before accept the frame - if (!this->_state.is_allowed_to_receive(frame)) { - QUICStreamDebug("Canceled receiving %s frame due to the stream state", QUICDebugNames::frame_type(frame.type())); - return std::make_unique(QUICTransErrorCode::STREAM_STATE_ERROR); - } - - // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit - int ret = this->_local_flow_controller.update(frame.offset() + frame.data_length()); - QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), - this->_local_flow_controller.current_limit()); - if (ret != 0) { - return std::make_unique(QUICTransErrorCode::FLOW_CONTROL_ERROR); - } - - // Make a copy and insert it into the receive buffer because the frame passed is temporal - QUICFrame *cloned = new QUICStreamFrame(frame); - QUICConnectionErrorUPtr error = this->_received_stream_frame_buffer.insert(cloned); - if (error != nullptr) { - this->_received_stream_frame_buffer.clear(); - return error; - } - - auto new_frame = this->_received_stream_frame_buffer.pop(); - const QUICStreamFrame *stream_frame = nullptr; - uint64_t last_offset = 0; - uint64_t last_length = 0; - - while (new_frame != nullptr) { - stream_frame = static_cast(new_frame); - last_offset = stream_frame->offset(); - last_length = stream_frame->data_length(); - - this->_write_to_read_vio(stream_frame->offset(), reinterpret_cast(stream_frame->data()->start()), - stream_frame->data_length(), stream_frame->has_fin_flag()); - this->_state.update_with_receiving_frame(*new_frame); - - delete new_frame; - new_frame = this->_received_stream_frame_buffer.pop(); - } - - // Forward limit of local flow controller with the largest reordered stream frame - if (stream_frame) { - this->_reordered_bytes = last_offset + last_length; - this->_local_flow_controller.forward_limit(this->_reordered_bytes + this->_flow_control_buffer_size); - QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), - this->_local_flow_controller.current_limit()); - } - - this->_signal_read_event(); - - return nullptr; -} - -QUICConnectionErrorUPtr -QUICBidirectionalStream::recv(const QUICMaxStreamDataFrame &frame) -{ - this->_remote_flow_controller.forward_limit(frame.maximum_stream_data()); - QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), - this->_remote_flow_controller.current_limit()); - - int64_t len = this->_process_write_vio(); - if (len > 0) { - this->_signal_write_event(); - } - - return nullptr; -} - -QUICConnectionErrorUPtr -QUICBidirectionalStream::recv(const QUICStreamDataBlockedFrame &frame) -{ - // STREAM_DATA_BLOCKED frames are for debugging. Nothing to do here. - QUICStreamFCDebug("[REMOTE] blocked %" PRIu64, frame.offset()); - return nullptr; -} - -QUICConnectionErrorUPtr -QUICBidirectionalStream::recv(const QUICStopSendingFrame &frame) -{ - this->_state.update_with_receiving_frame(frame); - this->_reset_reason = QUICStreamErrorUPtr(new QUICStreamError(this, QUIC_APP_ERROR_CODE_STOPPING)); - // We received and processed STOP_SENDING frame, so return NO_ERROR here - return nullptr; -} - -QUICConnectionErrorUPtr -QUICBidirectionalStream::recv(const QUICRstStreamFrame &frame) -{ - this->_state.update_with_receiving_frame(frame); - this->_signal_read_eos_event(); - return nullptr; -} - -// this->_read_vio.nbytes should be INT64_MAX until receive FIN flag -VIO * -QUICBidirectionalStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) -{ - if (buf) { - this->_read_vio.buffer.writer_for(buf); - } else { - this->_read_vio.buffer.clear(); - } - - this->_read_vio.mutex = c ? c->mutex : this->mutex; - this->_read_vio.cont = c; - this->_read_vio.nbytes = nbytes; - this->_read_vio.ndone = 0; - this->_read_vio.vc_server = this; - this->_read_vio.op = VIO::READ; - - this->_process_read_vio(); - this->_send_tracked_event(this->_read_event, VC_EVENT_READ_READY, &this->_read_vio); - - return &this->_read_vio; -} - -VIO * -QUICBidirectionalStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) -{ - if (buf) { - this->_write_vio.buffer.reader_for(buf); - } else { - this->_write_vio.buffer.clear(); - } - - this->_write_vio.mutex = c ? c->mutex : this->mutex; - this->_write_vio.cont = c; - this->_write_vio.nbytes = nbytes; - this->_write_vio.ndone = 0; - this->_write_vio.vc_server = this; - this->_write_vio.op = VIO::WRITE; - - this->_process_write_vio(); - this->_send_tracked_event(this->_write_event, VC_EVENT_WRITE_READY, &this->_write_vio); - - return &this->_write_vio; -} - -void -QUICBidirectionalStream::do_io_close(int lerrno) -{ - SET_HANDLER(&QUICBidirectionalStream::state_stream_closed); - - this->_read_vio.buffer.clear(); - this->_read_vio.nbytes = 0; - this->_read_vio.op = VIO::NONE; - this->_read_vio.cont = nullptr; - - this->_write_vio.buffer.clear(); - this->_write_vio.nbytes = 0; - this->_write_vio.op = VIO::NONE; - this->_write_vio.cont = nullptr; -} - -void -QUICBidirectionalStream::do_io_shutdown(ShutdownHowTo_t howto) -{ - ink_assert(false); // unimplemented yet - return; -} - -void -QUICBidirectionalStream::reenable(VIO *vio) -{ - if (vio->op == VIO::READ) { - QUICVStreamDebug("read_vio reenabled"); - - int64_t len = this->_process_read_vio(); - if (len > 0) { - this->_signal_read_event(); - } - } else if (vio->op == VIO::WRITE) { - QUICVStreamDebug("write_vio reenabled"); - - int64_t len = this->_process_write_vio(); - if (len > 0) { - this->_signal_write_event(); - } - } -} - -bool -QUICBidirectionalStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) -{ - return this->_local_flow_controller.will_generate_frame(level, timestamp) || !this->is_retransmited_frame_queue_empty() || - (this->_write_vio.get_reader()->read_avail() > 0); -} - -QUICFrame * -QUICBidirectionalStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, - uint16_t maximum_frame_size, ink_hrtime timestamp) -{ - SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); - - QUICFrame *frame = this->create_retransmitted_frame(buf, level, maximum_frame_size, this->_issue_frame_id(), this); - if (frame != nullptr) { - ink_assert(frame->type() == QUICFrameType::STREAM); - this->_records_stream_frame(level, *static_cast(frame)); - return frame; - } - - // RESET_STREAM - if (this->_reset_reason && !this->_is_reset_sent) { - frame = QUICFrameFactory::create_rst_stream_frame(buf, *this->_reset_reason, this->_issue_frame_id(), this); - this->_records_rst_stream_frame(level, *static_cast(frame)); - this->_state.update_with_sending_frame(*frame); - this->_is_reset_sent = true; - return frame; - } - - // STOP_SENDING - if (this->_stop_sending_reason && !this->_is_stop_sending_sent) { - frame = - QUICFrameFactory::create_stop_sending_frame(buf, this->id(), this->_stop_sending_reason->code, this->_issue_frame_id(), this); - this->_records_stop_sending_frame(level, *static_cast(frame)); - this->_state.update_with_sending_frame(*frame); - this->_is_stop_sending_sent = true; - return frame; - } - - // MAX_STREAM_DATA - frame = this->_local_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size, timestamp); - if (frame) { - return frame; - } - - if (!this->_state.is_allowed_to_send(QUICFrameType::STREAM)) { - return frame; - } - - uint64_t maximum_data_size = 0; - if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) { - return frame; - } - maximum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD; - - bool pure_fin = false; - bool fin = false; - if ((this->_write_vio.nbytes != 0 || this->_write_vio.nbytes != INT64_MAX) && - this->_write_vio.nbytes == static_cast(this->_send_offset)) { - // Pure FIN stream should be sent regardless status of remote flow controller, because the length is zero. - pure_fin = true; - fin = true; - } - - uint64_t len = 0; - IOBufferReader *reader = this->_write_vio.get_reader(); - if (!pure_fin) { - uint64_t data_len = reader->block_read_avail(); - if (data_len == 0) { - return frame; - } - - // Check Connection/Stream level credit only if the generating STREAM frame is not pure fin - uint64_t stream_credit = this->_remote_flow_controller.credit(); - if (stream_credit == 0) { - // STREAM_DATA_BLOCKED - frame = this->_remote_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size, timestamp); - return frame; - } - - if (connection_credit == 0) { - // BLOCKED - BLOCKED frame will be sent by connection level remote flow controller - return frame; - } - - len = std::min(data_len, std::min(maximum_data_size, std::min(stream_credit, connection_credit))); - - // data_len, maximum_data_size, stream_credit and connection_credit are already checked they're larger than 0 - ink_assert(len != 0); - - if (this->_write_vio.nbytes == static_cast(this->_send_offset + len)) { - fin = true; - } - } - - Ptr block = make_ptr(reader->get_current_block()->clone()); - block->consume(reader->start_offset); - block->_end = std::min(block->start() + len, block->_buf_end); - ink_assert(static_cast(block->read_avail()) == len); - - // STREAM - Pure FIN or data length is lager than 0 - // FIXME has_length_flag and has_offset_flag should be configurable - frame = QUICFrameFactory::create_stream_frame(buf, block, this->_id, this->_send_offset, fin, true, true, this->_issue_frame_id(), - this); - if (!this->_state.is_allowed_to_send(*frame)) { - QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); - return frame; - } - - if (!pure_fin) { - int ret = this->_remote_flow_controller.update(this->_send_offset + len); - // We cannot cancel sending the frame after updating the flow controller - - // Calling update always success, because len is always less than stream_credit - ink_assert(ret == 0); - - QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), - this->_remote_flow_controller.current_limit()); - if (this->_remote_flow_controller.current_offset() == this->_remote_flow_controller.current_limit()) { - QUICStreamDebug("Flow Controller will block sending a STREAM frame"); - } - - reader->consume(len); - this->_send_offset += len; - this->_write_vio.ndone += len; - } - this->_records_stream_frame(level, *static_cast(frame)); - - this->_signal_write_event(); - this->_state.update_with_sending_frame(*frame); - - return frame; -} - -void -QUICBidirectionalStream::_records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame) -{ - QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - info->type = frame.type(); - info->level = level; - StreamFrameInfo *frame_info = reinterpret_cast(info->data); - frame_info->stream_id = frame.stream_id(); - frame_info->offset = frame.offset(); - frame_info->has_fin = frame.has_fin_flag(); - frame_info->block = frame.data(); - this->_records_frame(frame.id(), std::move(info)); -} - -void -QUICBidirectionalStream::_records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame) -{ - QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - info->type = frame.type(); - info->level = level; - RstStreamFrameInfo *frame_info = reinterpret_cast(info->data); - frame_info->error_code = frame.error_code(); - frame_info->final_offset = frame.final_offset(); - this->_records_frame(frame.id(), std::move(info)); -} - -void -QUICBidirectionalStream::_records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame) -{ - QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - info->type = frame.type(); - info->level = level; - StopSendingFrameInfo *frame_info = reinterpret_cast(info->data); - frame_info->error_code = frame.error_code(); - this->_records_frame(frame.id(), std::move(info)); -} - -void -QUICBidirectionalStream::_on_frame_acked(QUICFrameInformationUPtr &info) -{ - StreamFrameInfo *frame_info = nullptr; - switch (info->type) { - case QUICFrameType::RESET_STREAM: - this->_is_reset_complete = true; - break; - case QUICFrameType::STREAM: - frame_info = reinterpret_cast(info->data); - frame_info->block = nullptr; - if (false) { - this->_is_transfer_complete = true; - } - break; - case QUICFrameType::STOP_SENDING: - default: - break; - } - - this->_state.update_on_ack(); -} - -void -QUICBidirectionalStream::_on_frame_lost(QUICFrameInformationUPtr &info) -{ - switch (info->type) { - case QUICFrameType::RESET_STREAM: - // [draft-16] 13.2. Retransmission of Information - // Cancellation of stream transmission, as carried in a RESET_STREAM - // frame, is sent until acknowledged or until all stream data is - // acknowledged by the peer (that is, either the "Reset Recvd" or - // "Data Recvd" state is reached on the send stream). The content of - // a RESET_STREAM frame MUST NOT change when it is sent again. - this->_is_reset_sent = false; - break; - case QUICFrameType::STREAM: - this->save_frame_info(std::move(info)); - break; - case QUICFrameType::STOP_SENDING: - this->_is_stop_sending_sent = false; - break; - default: - break; - } -} - -void -QUICBidirectionalStream::stop_sending(QUICStreamErrorUPtr error) -{ - this->_stop_sending_reason = std::move(error); -} - -void -QUICBidirectionalStream::reset(QUICStreamErrorUPtr error) -{ - this->_reset_reason = std::move(error); -} - -void -QUICBidirectionalStream::on_read() -{ - this->_state.update_on_read(); -} - -void -QUICBidirectionalStream::on_eos() -{ - this->_state.update_on_eos(); -} - -QUICOffset -QUICBidirectionalStream::largest_offset_received() const -{ - return this->_local_flow_controller.current_offset(); -} - -QUICOffset -QUICBidirectionalStream::largest_offset_sent() const -{ - return this->_remote_flow_controller.current_offset(); -} - // // QUICCryptoStream // diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 00b1a03e18c..c04985be28b 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -25,7 +25,8 @@ #include "tscore/List.h" -#include "I_VConnection.h" +#include "P_VConnection.h" +#include "I_Event.h" #include "QUICFrame.h" #include "QUICStreamState.h" @@ -34,6 +35,7 @@ #include "QUICFrameGenerator.h" #include "QUICConnection.h" #include "QUICFrameRetransmitter.h" +#include "QUICDebugNames.h" /** * @brief QUIC Stream @@ -115,85 +117,6 @@ class QUICStreamVConnection : public VConnection, public QUICStream Event *_write_event = nullptr; }; -class QUICBidirectionalStream : public QUICStreamVConnection, public QUICTransferProgressProvider -{ -public: - QUICBidirectionalStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, - uint64_t recv_max_stream_data, uint64_t send_max_stream_data); - QUICBidirectionalStream() - : QUICStreamVConnection(), - _remote_flow_controller(0, 0), - _local_flow_controller(nullptr, 0, 0), - _state(nullptr, nullptr, nullptr, nullptr) - { - } - - int state_stream_open(int event, void *data); - int state_stream_closed(int event, void *data); - - // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, - ink_hrtime timestamp) override; - - virtual QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame) override; - virtual QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame) override; - virtual QUICConnectionErrorUPtr recv(const QUICStreamDataBlockedFrame &frame) override; - virtual QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame) override; - virtual QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame) override; - - // Implement VConnection Interface. - VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; - VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; - void do_io_close(int lerrno = -1) override; - void do_io_shutdown(ShutdownHowTo_t howto) override; - void reenable(VIO *vio) override; - - void stop_sending(QUICStreamErrorUPtr error) override; - void reset(QUICStreamErrorUPtr error) override; - - // QUICTransferProgressProvider - bool is_transfer_goal_set() const override; - uint64_t transfer_progress() const override; - uint64_t transfer_goal() const override; - bool is_cancelled() const override; - - /* - * QUICApplication need to call one of these functions when it process VC_EVENT_* - */ - virtual void on_read() override; - virtual void on_eos() override; - - QUICOffset largest_offset_received() const override; - QUICOffset largest_offset_sent() const override; - -private: - QUICStreamErrorUPtr _reset_reason = nullptr; - bool _is_reset_sent = false; - QUICStreamErrorUPtr _stop_sending_reason = nullptr; - bool _is_stop_sending_sent = false; - - bool _is_transfer_complete = false; - bool _is_reset_complete = false; - - QUICTransferProgressProviderVIO _progress_vio = {this->_read_vio}; - - QUICRemoteStreamFlowController _remote_flow_controller; - QUICLocalStreamFlowController _local_flow_controller; - uint64_t _flow_control_buffer_size = 1024; - - // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState - QUICBidirectionalStreamStateMachine _state; - - void _records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame); - void _records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame); - void _records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame); - - // QUICFrameGenerator - void _on_frame_acked(QUICFrameInformationUPtr &info) override; - void _on_frame_lost(QUICFrameInformationUPtr &info) override; -}; - /** * @brief QUIC Crypto stream * Differences from QUICStream are below @@ -254,3 +177,18 @@ class QUICCryptoStream : public QUICStream IOBufferReader *_read_buffer_reader = nullptr; IOBufferReader *_write_buffer_reader = nullptr; }; + +#define QUICStreamDebug(fmt, ...) \ + Debug("quic_stream", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ + QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__) + +#define QUICVStreamDebug(fmt, ...) \ + Debug("v_quic_stream", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ + QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__) + +#define QUICStreamFCDebug(fmt, ...) \ + Debug("quic_flow_ctrl", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ + QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__) + +extern const uint32_t MAX_STREAM_FRAME_OVERHEAD; +extern const uint32_t MAX_CRYPTO_FRAME_OVERHEAD; diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 7612f3b1c67..26e4396c649 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -24,7 +24,7 @@ #pragma once #include "QUICTypes.h" -#include "QUICStream.h" +#include "QUICBidirectionalStream.h" #include "QUICApplicationMap.h" #include "QUICFrameHandler.h" #include "QUICFrame.h" From f93d4920c4cb851237d5abdd491517dbc5b7c9ee Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 11 Mar 2019 15:49:43 +0800 Subject: [PATCH 1205/1313] QUIC: Split out QUICCryptoStream --- iocore/net/QUICNetVConnection.cc | 10 +- iocore/net/quic/Makefile.am | 3 +- iocore/net/quic/QUICCryptoStream.cc | 221 ++++++++++++++++++++++++++++ iocore/net/quic/QUICCryptoStream.h | 87 +++++++++++ iocore/net/quic/QUICHandshake.cc | 1 - iocore/net/quic/QUICHandshake.h | 2 +- iocore/net/quic/QUICStream.cc | 197 ------------------------- iocore/net/quic/QUICStream.h | 61 -------- 8 files changed, 315 insertions(+), 267 deletions(-) create mode 100644 iocore/net/quic/QUICCryptoStream.cc create mode 100644 iocore/net/quic/QUICCryptoStream.h diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 810120c132a..ff03ca8ab7b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -55,12 +55,10 @@ static constexpr std::string_view QUIC_DEBUG_TAG = "quic_net"sv; Debug("quic_net", "[%s] " fmt, this->cids().data(), ##__VA_ARGS__); \ Error("quic_net [%s] " fmt, this->cids().data(), ##__VA_ARGS__) -static constexpr uint32_t IPV4_HEADER_SIZE = 20; -static constexpr uint32_t IPV6_HEADER_SIZE = 40; -static constexpr uint32_t UDP_HEADER_SIZE = 8; -static constexpr uint32_t MAX_PACKET_OVERHEAD = 62; // Max long header len without length of token field of Initial packet -static constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; -// static constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; +static constexpr uint32_t IPV4_HEADER_SIZE = 20; +static constexpr uint32_t IPV6_HEADER_SIZE = 40; +static constexpr uint32_t UDP_HEADER_SIZE = 8; +static constexpr uint32_t MAX_PACKET_OVERHEAD = 62; // Max long header len without length of token field of Initial packet static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(2); static constexpr uint32_t PACKET_PER_EVENT = 256; diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 66743febf19..83799d4d9d7 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -87,7 +87,8 @@ libquic_a_SOURCES = \ QUICFrameGenerator.cc \ QUICFrameRetransmitter.cc \ QUICAddrVerifyState.cc \ - QUICBidirectionalStream.cc + QUICBidirectionalStream.cc \ + QUICCryptoStream.cc # # Check Programs diff --git a/iocore/net/quic/QUICCryptoStream.cc b/iocore/net/quic/QUICCryptoStream.cc new file mode 100644 index 00000000000..3c60f571653 --- /dev/null +++ b/iocore/net/quic/QUICCryptoStream.cc @@ -0,0 +1,221 @@ +/** @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 "QUICCryptoStream.h" + +// +// QUICCryptoStream +// +QUICCryptoStream::QUICCryptoStream() : _received_stream_frame_buffer() +{ + this->_read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); + this->_write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); + + this->_read_buffer_reader = this->_read_buffer->alloc_reader(); + this->_write_buffer_reader = this->_write_buffer->alloc_reader(); +} + +QUICCryptoStream::~QUICCryptoStream() +{ + // All readers will be deallocated + free_MIOBuffer(this->_read_buffer); + free_MIOBuffer(this->_write_buffer); +} + +/** + * Reset send/recv offset of stream + */ +void +QUICCryptoStream::reset_send_offset() +{ + this->_send_offset = 0; +} + +void +QUICCryptoStream::reset_recv_offset() +{ + this->_received_stream_frame_buffer.clear(); +} + +QUICConnectionErrorUPtr +QUICCryptoStream::recv(const QUICCryptoFrame &frame) +{ + // Make a copy and insert it into the receive buffer because the frame passed is temporal + QUICFrame *cloned = new QUICCryptoFrame(frame); + QUICConnectionErrorUPtr error = this->_received_stream_frame_buffer.insert(cloned); + if (error != nullptr) { + this->_received_stream_frame_buffer.clear(); + return error; + } + + auto new_frame = this->_received_stream_frame_buffer.pop(); + while (new_frame != nullptr) { + const QUICCryptoFrame *crypto_frame = static_cast(new_frame); + + this->_read_buffer->write(reinterpret_cast(crypto_frame->data()->start()), crypto_frame->data_length()); + + delete new_frame; + new_frame = this->_received_stream_frame_buffer.pop(); + } + + return nullptr; +} + +int64_t +QUICCryptoStream::read_avail() +{ + return this->_read_buffer_reader->read_avail(); +} + +int64_t +QUICCryptoStream::read(uint8_t *buf, int64_t len) +{ + return this->_read_buffer_reader->read(buf, len); +} + +int64_t +QUICCryptoStream::write(const uint8_t *buf, int64_t len) +{ + return this->_write_buffer->write(buf, len); +} + +bool +QUICCryptoStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) +{ + return this->_write_buffer_reader->is_read_avail_more_than(0) || !this->is_retransmited_frame_queue_empty(); +} + +/** + * @param connection_credit This is not used. Because CRYPTO frame is not flow-controlled + */ +QUICFrame * +QUICCryptoStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, + uint16_t maximum_frame_size, ink_hrtime timestamp) +{ + QUICConnectionErrorUPtr error = nullptr; + + if (this->_reset_reason) { + return QUICFrameFactory::create_rst_stream_frame(buf, *this->_reset_reason); + } + + QUICFrame *frame = this->create_retransmitted_frame(buf, level, maximum_frame_size, this->_issue_frame_id(), this); + if (frame != nullptr) { + ink_assert(frame->type() == QUICFrameType::CRYPTO); + this->_records_crypto_frame(level, *static_cast(frame)); + return frame; + } + + if (maximum_frame_size <= MAX_CRYPTO_FRAME_OVERHEAD) { + return frame; + } + + uint64_t frame_payload_size = maximum_frame_size - MAX_CRYPTO_FRAME_OVERHEAD; + uint64_t bytes_avail = this->_write_buffer_reader->read_avail(); + frame_payload_size = std::min(bytes_avail, frame_payload_size); + if (frame_payload_size == 0) { + return frame; + } + + Ptr block = make_ptr(this->_write_buffer_reader->get_current_block()->clone()); + block->consume(this->_write_buffer_reader->start_offset); + block->_end = std::min(block->start() + frame_payload_size, block->_buf_end); + ink_assert(static_cast(block->read_avail()) == frame_payload_size); + + frame = QUICFrameFactory::create_crypto_frame(buf, block, this->_send_offset, this->_issue_frame_id(), this); + this->_send_offset += frame_payload_size; + this->_write_buffer_reader->consume(frame_payload_size); + this->_records_crypto_frame(level, *static_cast(frame)); + + return frame; +} + +void +QUICCryptoStream::_on_frame_acked(QUICFrameInformationUPtr &info) +{ + ink_assert(info->type == QUICFrameType::CRYPTO); + CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); + crypto_frame_info->block = nullptr; +} + +void +QUICCryptoStream::_on_frame_lost(QUICFrameInformationUPtr &info) +{ + ink_assert(info->type == QUICFrameType::CRYPTO); + this->save_frame_info(std::move(info)); +} + +void +QUICCryptoStream::_records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFrame &frame) +{ + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = QUICFrameType::CRYPTO; + info->level = level; + CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); + crypto_frame_info->offset = frame.offset(); + crypto_frame_info->block = frame.data(); + this->_records_frame(frame.id(), std::move(info)); +} + +QUICOffset +QUICCryptoStream::largest_offset_received() const +{ + // TODO: + ink_assert(!"unsupported"); + return 0; +} + +QUICOffset +QUICCryptoStream::largest_offset_sent() const +{ + // TODO + ink_assert(!"unsupported"); + return 0; +} + +void +QUICCryptoStream::stop_sending(QUICStreamErrorUPtr error) +{ + // TODO + ink_assert(!"unsupported"); + return; +} + +void +QUICCryptoStream::reset(QUICStreamErrorUPtr error) +{ + // TODO + ink_assert(!"unsupported"); + return; +} + +void +QUICCryptoStream::on_eos() +{ + return; +} + +void +QUICCryptoStream::on_read() +{ + return; +} diff --git a/iocore/net/quic/QUICCryptoStream.h b/iocore/net/quic/QUICCryptoStream.h new file mode 100644 index 00000000000..1fbb3ecce3f --- /dev/null +++ b/iocore/net/quic/QUICCryptoStream.h @@ -0,0 +1,87 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICStream.h" + +/** + * @brief QUIC Crypto stream + * Differences from QUICStream are below + * - this doesn't have VConnection interface + * - no stream id + * - no flow control + * - no state (never closed) + */ +class QUICCryptoStream : public QUICStream +{ +public: + QUICCryptoStream(); + ~QUICCryptoStream(); + + int state_stream_open(int event, void *data); + + const QUICConnectionInfoProvider *info() const; + QUICOffset final_offset() const; + void reset_send_offset(); + void reset_recv_offset(); + + QUICConnectionErrorUPtr recv(const QUICCryptoFrame &frame) override; + + int64_t read_avail(); + int64_t read(uint8_t *buf, int64_t len); + int64_t write(const uint8_t *buf, int64_t len); + + void stop_sending(QUICStreamErrorUPtr error) override; + void reset(QUICStreamErrorUPtr error) override; + + QUICOffset largest_offset_received() const override; + QUICOffset largest_offset_sent() const override; + + void on_eos() override; + void on_read() override; + + // QUICFrameGenerator + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; + +private: + void _on_frame_acked(QUICFrameInformationUPtr &info) override; + void _on_frame_lost(QUICFrameInformationUPtr &info) override; + + void _records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFrame &frame); + + QUICStreamErrorUPtr _reset_reason = nullptr; + QUICOffset _send_offset = 0; + + // Fragments of received STREAM frame (offset is unmatched) + // TODO: Consider to replace with ts/RbTree.h or other data structure + QUICIncomingCryptoFrameBuffer _received_stream_frame_buffer; + + MIOBuffer *_read_buffer = nullptr; + MIOBuffer *_write_buffer = nullptr; + + IOBufferReader *_read_buffer_reader = nullptr; + IOBufferReader *_write_buffer_reader = nullptr; +}; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 9b088d5607d..475112c03b3 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -30,7 +30,6 @@ #include "QUICPacketFactory.h" #include "QUICVersionNegotiator.h" #include "QUICConfig.h" -#include "QUICStream.h" #define QUICHSDebug(fmt, ...) Debug("quic_handshake", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index a02f3a84611..0cdb94d7736 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -27,7 +27,7 @@ #include "QUICTransportParameters.h" #include "QUICFrameHandler.h" #include "QUICFrameGenerator.h" -#include "QUICStream.h" +#include "QUICCryptoStream.h" /** * @class QUICHandshake diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index cf75c8c0a90..70367d0df82 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -238,200 +238,3 @@ QUICStreamVConnection::_process_write_vio() return 0; } - -// -// QUICCryptoStream -// -QUICCryptoStream::QUICCryptoStream() : _received_stream_frame_buffer() -{ - this->_read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); - this->_write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); - - this->_read_buffer_reader = this->_read_buffer->alloc_reader(); - this->_write_buffer_reader = this->_write_buffer->alloc_reader(); -} - -QUICCryptoStream::~QUICCryptoStream() -{ - // All readers will be deallocated - free_MIOBuffer(this->_read_buffer); - free_MIOBuffer(this->_write_buffer); -} - -/** - * Reset send/recv offset of stream - */ -void -QUICCryptoStream::reset_send_offset() -{ - this->_send_offset = 0; -} - -void -QUICCryptoStream::reset_recv_offset() -{ - this->_received_stream_frame_buffer.clear(); -} - -QUICConnectionErrorUPtr -QUICCryptoStream::recv(const QUICCryptoFrame &frame) -{ - // Make a copy and insert it into the receive buffer because the frame passed is temporal - QUICFrame *cloned = new QUICCryptoFrame(frame); - QUICConnectionErrorUPtr error = this->_received_stream_frame_buffer.insert(cloned); - if (error != nullptr) { - this->_received_stream_frame_buffer.clear(); - return error; - } - - auto new_frame = this->_received_stream_frame_buffer.pop(); - while (new_frame != nullptr) { - const QUICCryptoFrame *crypto_frame = static_cast(new_frame); - - this->_read_buffer->write(reinterpret_cast(crypto_frame->data()->start()), crypto_frame->data_length()); - - delete new_frame; - new_frame = this->_received_stream_frame_buffer.pop(); - } - - return nullptr; -} - -int64_t -QUICCryptoStream::read_avail() -{ - return this->_read_buffer_reader->read_avail(); -} - -int64_t -QUICCryptoStream::read(uint8_t *buf, int64_t len) -{ - return this->_read_buffer_reader->read(buf, len); -} - -int64_t -QUICCryptoStream::write(const uint8_t *buf, int64_t len) -{ - return this->_write_buffer->write(buf, len); -} - -bool -QUICCryptoStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) -{ - return this->_write_buffer_reader->is_read_avail_more_than(0) || !this->is_retransmited_frame_queue_empty(); -} - -/** - * @param connection_credit This is not used. Because CRYPTO frame is not flow-controlled - */ -QUICFrame * -QUICCryptoStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t /* connection_credit */, - uint16_t maximum_frame_size, ink_hrtime timestamp) -{ - QUICConnectionErrorUPtr error = nullptr; - - if (this->_reset_reason) { - return QUICFrameFactory::create_rst_stream_frame(buf, *this->_reset_reason); - } - - QUICFrame *frame = this->create_retransmitted_frame(buf, level, maximum_frame_size, this->_issue_frame_id(), this); - if (frame != nullptr) { - ink_assert(frame->type() == QUICFrameType::CRYPTO); - this->_records_crypto_frame(level, *static_cast(frame)); - return frame; - } - - if (maximum_frame_size <= MAX_CRYPTO_FRAME_OVERHEAD) { - return frame; - } - - uint64_t frame_payload_size = maximum_frame_size - MAX_CRYPTO_FRAME_OVERHEAD; - uint64_t bytes_avail = this->_write_buffer_reader->read_avail(); - frame_payload_size = std::min(bytes_avail, frame_payload_size); - if (frame_payload_size == 0) { - return frame; - } - - Ptr block = make_ptr(this->_write_buffer_reader->get_current_block()->clone()); - block->consume(this->_write_buffer_reader->start_offset); - block->_end = std::min(block->start() + frame_payload_size, block->_buf_end); - ink_assert(static_cast(block->read_avail()) == frame_payload_size); - - frame = QUICFrameFactory::create_crypto_frame(buf, block, this->_send_offset, this->_issue_frame_id(), this); - this->_send_offset += frame_payload_size; - this->_write_buffer_reader->consume(frame_payload_size); - this->_records_crypto_frame(level, *static_cast(frame)); - - return frame; -} - -void -QUICCryptoStream::_on_frame_acked(QUICFrameInformationUPtr &info) -{ - ink_assert(info->type == QUICFrameType::CRYPTO); - CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); - crypto_frame_info->block = nullptr; -} - -void -QUICCryptoStream::_on_frame_lost(QUICFrameInformationUPtr &info) -{ - ink_assert(info->type == QUICFrameType::CRYPTO); - this->save_frame_info(std::move(info)); -} - -void -QUICCryptoStream::_records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFrame &frame) -{ - QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - info->type = QUICFrameType::CRYPTO; - info->level = level; - CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); - crypto_frame_info->offset = frame.offset(); - crypto_frame_info->block = frame.data(); - this->_records_frame(frame.id(), std::move(info)); -} - -QUICOffset -QUICCryptoStream::largest_offset_received() const -{ - // TODO: - ink_assert(!"unsupported"); - return 0; -} - -QUICOffset -QUICCryptoStream::largest_offset_sent() const -{ - // TODO - ink_assert(!"unsupported"); - return 0; -} - -void -QUICCryptoStream::stop_sending(QUICStreamErrorUPtr error) -{ - // TODO - ink_assert(!"unsupported"); - return; -} - -void -QUICCryptoStream::reset(QUICStreamErrorUPtr error) -{ - // TODO - ink_assert(!"unsupported"); - return; -} - -void -QUICCryptoStream::on_eos() -{ - return; -} - -void -QUICCryptoStream::on_read() -{ - return; -} diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index c04985be28b..9bed1caec01 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -117,67 +117,6 @@ class QUICStreamVConnection : public VConnection, public QUICStream Event *_write_event = nullptr; }; -/** - * @brief QUIC Crypto stream - * Differences from QUICStream are below - * - this doesn't have VConnection interface - * - no stream id - * - no flow control - * - no state (never closed) - */ -class QUICCryptoStream : public QUICStream -{ -public: - QUICCryptoStream(); - ~QUICCryptoStream(); - - int state_stream_open(int event, void *data); - - const QUICConnectionInfoProvider *info() const; - QUICOffset final_offset() const; - void reset_send_offset(); - void reset_recv_offset(); - - QUICConnectionErrorUPtr recv(const QUICCryptoFrame &frame) override; - - int64_t read_avail(); - int64_t read(uint8_t *buf, int64_t len); - int64_t write(const uint8_t *buf, int64_t len); - - void stop_sending(QUICStreamErrorUPtr error) override; - void reset(QUICStreamErrorUPtr error) override; - - QUICOffset largest_offset_received() const override; - QUICOffset largest_offset_sent() const override; - - void on_eos() override; - void on_read() override; - - // QUICFrameGenerator - bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; - QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, - ink_hrtime timestamp) override; - -private: - void _on_frame_acked(QUICFrameInformationUPtr &info) override; - void _on_frame_lost(QUICFrameInformationUPtr &info) override; - - void _records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFrame &frame); - - QUICStreamErrorUPtr _reset_reason = nullptr; - QUICOffset _send_offset = 0; - - // Fragments of received STREAM frame (offset is unmatched) - // TODO: Consider to replace with ts/RbTree.h or other data structure - QUICIncomingCryptoFrameBuffer _received_stream_frame_buffer; - - MIOBuffer *_read_buffer = nullptr; - MIOBuffer *_write_buffer = nullptr; - - IOBufferReader *_read_buffer_reader = nullptr; - IOBufferReader *_write_buffer_reader = nullptr; -}; - #define QUICStreamDebug(fmt, ...) \ Debug("quic_stream", "[%s] [%" PRIu64 "] [%s] " fmt, this->_connection_info->cids().data(), this->_id, \ QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__) From dc9485e2d9e11e4b422ebe206b26ee464545d91a Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 12 Mar 2019 08:41:22 +0800 Subject: [PATCH 1206/1313] QUIC: Sink records_xxx_frame function to QUICStream --- iocore/net/quic/QUICBidirectionalStream.cc | 37 ---------------- iocore/net/quic/QUICBidirectionalStream.h | 4 -- iocore/net/quic/QUICCryptoStream.cc | 12 ------ iocore/net/quic/QUICCryptoStream.h | 2 - iocore/net/quic/QUICStream.cc | 49 ++++++++++++++++++++++ iocore/net/quic/QUICStream.h | 5 +++ 6 files changed, 54 insertions(+), 55 deletions(-) diff --git a/iocore/net/quic/QUICBidirectionalStream.cc b/iocore/net/quic/QUICBidirectionalStream.cc index 8cc183fddfc..891e58e774b 100644 --- a/iocore/net/quic/QUICBidirectionalStream.cc +++ b/iocore/net/quic/QUICBidirectionalStream.cc @@ -485,43 +485,6 @@ QUICBidirectionalStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, return frame; } -void -QUICBidirectionalStream::_records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame) -{ - QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - info->type = frame.type(); - info->level = level; - StreamFrameInfo *frame_info = reinterpret_cast(info->data); - frame_info->stream_id = frame.stream_id(); - frame_info->offset = frame.offset(); - frame_info->has_fin = frame.has_fin_flag(); - frame_info->block = frame.data(); - this->_records_frame(frame.id(), std::move(info)); -} - -void -QUICBidirectionalStream::_records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame) -{ - QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - info->type = frame.type(); - info->level = level; - RstStreamFrameInfo *frame_info = reinterpret_cast(info->data); - frame_info->error_code = frame.error_code(); - frame_info->final_offset = frame.final_offset(); - this->_records_frame(frame.id(), std::move(info)); -} - -void -QUICBidirectionalStream::_records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame) -{ - QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - info->type = frame.type(); - info->level = level; - StopSendingFrameInfo *frame_info = reinterpret_cast(info->data); - frame_info->error_code = frame.error_code(); - this->_records_frame(frame.id(), std::move(info)); -} - void QUICBidirectionalStream::_on_frame_acked(QUICFrameInformationUPtr &info) { diff --git a/iocore/net/quic/QUICBidirectionalStream.h b/iocore/net/quic/QUICBidirectionalStream.h index aa75536497a..39cfaaeeed5 100644 --- a/iocore/net/quic/QUICBidirectionalStream.h +++ b/iocore/net/quic/QUICBidirectionalStream.h @@ -95,10 +95,6 @@ class QUICBidirectionalStream : public QUICStreamVConnection, public QUICTransfe // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState QUICBidirectionalStreamStateMachine _state; - void _records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame); - void _records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame); - void _records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame); - // QUICFrameGenerator void _on_frame_acked(QUICFrameInformationUPtr &info) override; void _on_frame_lost(QUICFrameInformationUPtr &info) override; diff --git a/iocore/net/quic/QUICCryptoStream.cc b/iocore/net/quic/QUICCryptoStream.cc index 3c60f571653..579fdf58aa3 100644 --- a/iocore/net/quic/QUICCryptoStream.cc +++ b/iocore/net/quic/QUICCryptoStream.cc @@ -164,18 +164,6 @@ QUICCryptoStream::_on_frame_lost(QUICFrameInformationUPtr &info) this->save_frame_info(std::move(info)); } -void -QUICCryptoStream::_records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFrame &frame) -{ - QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); - info->type = QUICFrameType::CRYPTO; - info->level = level; - CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); - crypto_frame_info->offset = frame.offset(); - crypto_frame_info->block = frame.data(); - this->_records_frame(frame.id(), std::move(info)); -} - QUICOffset QUICCryptoStream::largest_offset_received() const { diff --git a/iocore/net/quic/QUICCryptoStream.h b/iocore/net/quic/QUICCryptoStream.h index 1fbb3ecce3f..97c0292fa7e 100644 --- a/iocore/net/quic/QUICCryptoStream.h +++ b/iocore/net/quic/QUICCryptoStream.h @@ -70,8 +70,6 @@ class QUICCryptoStream : public QUICStream void _on_frame_acked(QUICFrameInformationUPtr &info) override; void _on_frame_lost(QUICFrameInformationUPtr &info) override; - void _records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFrame &frame); - QUICStreamErrorUPtr _reset_reason = nullptr; QUICOffset _send_offset = 0; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 70367d0df82..00534c14daa 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -102,6 +102,55 @@ QUICStream::recv(const QUICCryptoFrame &frame) return nullptr; } +void +QUICStream::_records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame) +{ + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = frame.type(); + info->level = level; + StreamFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->stream_id = frame.stream_id(); + frame_info->offset = frame.offset(); + frame_info->has_fin = frame.has_fin_flag(); + frame_info->block = frame.data(); + this->_records_frame(frame.id(), std::move(info)); +} + +void +QUICStream::_records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame) +{ + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = frame.type(); + info->level = level; + RstStreamFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->error_code = frame.error_code(); + frame_info->final_offset = frame.final_offset(); + this->_records_frame(frame.id(), std::move(info)); +} + +void +QUICStream::_records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame) +{ + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = frame.type(); + info->level = level; + StopSendingFrameInfo *frame_info = reinterpret_cast(info->data); + frame_info->error_code = frame.error_code(); + this->_records_frame(frame.id(), std::move(info)); +} + +void +QUICStream::_records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFrame &frame) +{ + QUICFrameInformationUPtr info = QUICFrameInformationUPtr(quicFrameInformationAllocator.alloc()); + info->type = QUICFrameType::CRYPTO; + info->level = level; + CryptoFrameInfo *crypto_frame_info = reinterpret_cast(info->data); + crypto_frame_info->offset = frame.offset(); + crypto_frame_info->block = frame.data(); + this->_records_frame(frame.id(), std::move(info)); +} + // // QUICStreamVConnection // diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 9bed1caec01..a065f28d6e3 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -84,6 +84,11 @@ class QUICStream : public QUICFrameGenerator, public QUICFrameRetransmitter // Fragments of received STREAM frame (offset is unmatched) // TODO: Consider to replace with ts/RbTree.h or other data structure QUICIncomingStreamFrameBuffer _received_stream_frame_buffer; + + void _records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame); + void _records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame); + void _records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame); + void _records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFrame &frame); }; // This is VConnection class for VIO operation. From cb279cfc646763f92e66070ae088cac9669a0074 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 12 Mar 2019 08:44:33 +0800 Subject: [PATCH 1207/1313] QUIC: Moves some functions to base QUICStream structure --- iocore/net/quic/QUICCryptoStream.cc | 44 ----------------------------- iocore/net/quic/QUICCryptoStream.h | 9 ------ iocore/net/quic/QUICStream.cc | 32 +++++++++++++++++++++ iocore/net/quic/QUICStream.h | 12 ++++---- 4 files changed, 38 insertions(+), 59 deletions(-) diff --git a/iocore/net/quic/QUICCryptoStream.cc b/iocore/net/quic/QUICCryptoStream.cc index 579fdf58aa3..034873fef05 100644 --- a/iocore/net/quic/QUICCryptoStream.cc +++ b/iocore/net/quic/QUICCryptoStream.cc @@ -163,47 +163,3 @@ QUICCryptoStream::_on_frame_lost(QUICFrameInformationUPtr &info) ink_assert(info->type == QUICFrameType::CRYPTO); this->save_frame_info(std::move(info)); } - -QUICOffset -QUICCryptoStream::largest_offset_received() const -{ - // TODO: - ink_assert(!"unsupported"); - return 0; -} - -QUICOffset -QUICCryptoStream::largest_offset_sent() const -{ - // TODO - ink_assert(!"unsupported"); - return 0; -} - -void -QUICCryptoStream::stop_sending(QUICStreamErrorUPtr error) -{ - // TODO - ink_assert(!"unsupported"); - return; -} - -void -QUICCryptoStream::reset(QUICStreamErrorUPtr error) -{ - // TODO - ink_assert(!"unsupported"); - return; -} - -void -QUICCryptoStream::on_eos() -{ - return; -} - -void -QUICCryptoStream::on_read() -{ - return; -} diff --git a/iocore/net/quic/QUICCryptoStream.h b/iocore/net/quic/QUICCryptoStream.h index 97c0292fa7e..6da3b2fcd2b 100644 --- a/iocore/net/quic/QUICCryptoStream.h +++ b/iocore/net/quic/QUICCryptoStream.h @@ -52,15 +52,6 @@ class QUICCryptoStream : public QUICStream int64_t read(uint8_t *buf, int64_t len); int64_t write(const uint8_t *buf, int64_t len); - void stop_sending(QUICStreamErrorUPtr error) override; - void reset(QUICStreamErrorUPtr error) override; - - QUICOffset largest_offset_received() const override; - QUICOffset largest_offset_sent() const override; - - void on_eos() override; - void on_read() override; - // QUICFrameGenerator bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 00534c14daa..7086198847d 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -151,6 +151,38 @@ QUICStream::_records_crypto_frame(QUICEncryptionLevel level, const QUICCryptoFra this->_records_frame(frame.id(), std::move(info)); } +void +QUICStream::reset(QUICStreamErrorUPtr error) +{ +} + +void +QUICStream::stop_sending(QUICStreamErrorUPtr error) +{ +} + +QUICOffset +QUICStream::largest_offset_received() const +{ + return 0; +} + +QUICOffset +QUICStream::largest_offset_sent() const +{ + return 0; +} + +void +QUICStream::on_eos() +{ +} + +void +QUICStream::on_read() +{ +} + // // QUICStreamVConnection // diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index a065f28d6e3..8d451c042ef 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -56,8 +56,8 @@ class QUICStream : public QUICFrameGenerator, public QUICFrameRetransmitter /* * QUICApplication need to call one of these functions when it process VC_EVENT_* */ - virtual void on_read() = 0; - virtual void on_eos() = 0; + virtual void on_read(); + virtual void on_eos(); virtual QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame); virtual QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame); @@ -67,11 +67,11 @@ class QUICStream : public QUICFrameGenerator, public QUICFrameRetransmitter virtual QUICConnectionErrorUPtr recv(const QUICCryptoFrame &frame); QUICOffset reordered_bytes() const; - virtual QUICOffset largest_offset_received() const = 0; - virtual QUICOffset largest_offset_sent() const = 0; + virtual QUICOffset largest_offset_received() const; + virtual QUICOffset largest_offset_sent() const; - virtual void stop_sending(QUICStreamErrorUPtr error) = 0; - virtual void reset(QUICStreamErrorUPtr error) = 0; + virtual void stop_sending(QUICStreamErrorUPtr error); + virtual void reset(QUICStreamErrorUPtr error); LINK(QUICStream, link); From 4adefcc846268814e375e219cadbb3bac3aa4c6d Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 12 Mar 2019 09:37:37 +0800 Subject: [PATCH 1208/1313] QUIC: Add Send only stream --- iocore/net/quic/Makefile.am | 3 +- iocore/net/quic/QUICUnbidirectionalStream.cc | 392 +++++++++++++++++++ iocore/net/quic/QUICUnbidirectionalStream.h | 69 ++++ 3 files changed, 463 insertions(+), 1 deletion(-) create mode 100644 iocore/net/quic/QUICUnbidirectionalStream.cc create mode 100644 iocore/net/quic/QUICUnbidirectionalStream.h diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 83799d4d9d7..c03eca0d73f 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -88,7 +88,8 @@ libquic_a_SOURCES = \ QUICFrameRetransmitter.cc \ QUICAddrVerifyState.cc \ QUICBidirectionalStream.cc \ - QUICCryptoStream.cc + QUICCryptoStream.cc \ + QUICUnbidirectionalStream.cc # # Check Programs diff --git a/iocore/net/quic/QUICUnbidirectionalStream.cc b/iocore/net/quic/QUICUnbidirectionalStream.cc new file mode 100644 index 00000000000..09848e21992 --- /dev/null +++ b/iocore/net/quic/QUICUnbidirectionalStream.cc @@ -0,0 +1,392 @@ +/** @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 "QUICUnbidirectionalStream.h" + +// +// QUICSendStream +// +QUICSendStream::QUICSendStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t send_max_stream_data) + : QUICStreamVConnection(cinfo, sid), _remote_flow_controller(send_max_stream_data, _id), _state(nullptr, &this->_progress_vio) +{ + SET_HANDLER(&QUICSendStream::state_stream_open); + + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); +} + +int +QUICSendStream::state_stream_open(int event, void *data) +{ + QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); + QUICErrorUPtr error = nullptr; + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + // should not schedule read event. + ink_assert(0); + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); + } + + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + // TODO + ink_assert(false); + break; + } + default: + QUICStreamDebug("unknown event"); + ink_assert(false); + } + + // FIXME error is always nullptr + if (error != nullptr) { + if (error->cls == QUICErrorClass::TRANSPORT) { + QUICStreamDebug("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), QUICDebugNames::error_code(error->code), + static_cast(error->code)); + } else { + QUICStreamDebug("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), static_cast(error->code)); + } + if (dynamic_cast(error.get()) != nullptr) { + // Stream Error + QUICStreamErrorUPtr serror = QUICStreamErrorUPtr(static_cast(error.get())); + this->reset(std::move(serror)); + } else { + // Connection Error + // TODO Close connection (Does this really happen?) + } + } + + return EVENT_DONE; +} + +int +QUICSendStream::state_stream_closed(int event, void *data) +{ + QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + // ignore + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + // ignore + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + // TODO + ink_assert(false); + break; + } + default: + ink_assert(false); + } + + return EVENT_DONE; +} + +bool +QUICSendStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) +{ + return this->_remote_flow_controller.will_generate_frame(level, timestamp) || !this->is_retransmited_frame_queue_empty() || + (this->_write_vio.get_reader()->read_avail() > 0); +} + +QUICFrame * +QUICSendStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) +{ + SCOPED_MUTEX_LOCK(lock, this->_write_vio.mutex, this_ethread()); + + QUICFrame *frame = this->create_retransmitted_frame(buf, level, maximum_frame_size, this->_issue_frame_id(), this); + if (frame != nullptr) { + ink_assert(frame->type() == QUICFrameType::STREAM); + this->_records_stream_frame(level, *static_cast(frame)); + return frame; + } + + // RESET_STREAM + if (this->_reset_reason && !this->_is_reset_sent) { + frame = QUICFrameFactory::create_rst_stream_frame(buf, *this->_reset_reason, this->_issue_frame_id(), this); + this->_records_rst_stream_frame(level, *static_cast(frame)); + this->_state.update_with_sending_frame(*frame); + this->_is_reset_sent = true; + return frame; + } + + if (!this->_state.is_allowed_to_send(QUICFrameType::STREAM)) { + return frame; + } + + uint64_t maximum_data_size = 0; + if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) { + return frame; + } + maximum_data_size = maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD; + + bool pure_fin = false; + bool fin = false; + if ((this->_write_vio.nbytes != 0 || this->_write_vio.nbytes != INT64_MAX) && + this->_write_vio.nbytes == static_cast(this->_send_offset)) { + // Pure FIN stream should be sent regardless status of remote flow controller, because the length is zero. + pure_fin = true; + fin = true; + } + + uint64_t len = 0; + IOBufferReader *reader = this->_write_vio.get_reader(); + if (!pure_fin) { + uint64_t data_len = reader->block_read_avail(); + if (data_len == 0) { + return frame; + } + + // Check Connection/Stream level credit only if the generating STREAM frame is not pure fin + uint64_t stream_credit = this->_remote_flow_controller.credit(); + if (stream_credit == 0) { + // STREAM_DATA_BLOCKED + frame = this->_remote_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size, timestamp); + return frame; + } + + if (connection_credit == 0) { + // BLOCKED - BLOCKED frame will be sent by connection level remote flow controller + return frame; + } + + len = std::min(data_len, std::min(maximum_data_size, std::min(stream_credit, connection_credit))); + + // data_len, maximum_data_size, stream_credit and connection_credit are already checked they're larger than 0 + ink_assert(len != 0); + + if (this->_write_vio.nbytes == static_cast(this->_send_offset + len)) { + fin = true; + } + } + + Ptr block = make_ptr(reader->get_current_block()->clone()); + block->consume(reader->start_offset); + block->_end = std::min(block->start() + len, block->_buf_end); + ink_assert(static_cast(block->read_avail()) == len); + + // STREAM - Pure FIN or data length is lager than 0 + // FIXME has_length_flag and has_offset_flag should be configurable + frame = QUICFrameFactory::create_stream_frame(buf, block, this->_id, this->_send_offset, fin, true, true, this->_issue_frame_id(), + this); + if (!this->_state.is_allowed_to_send(*frame)) { + QUICStreamDebug("Canceled sending %s frame due to the stream state", QUICDebugNames::frame_type(frame->type())); + return frame; + } + + if (!pure_fin) { + int ret = this->_remote_flow_controller.update(this->_send_offset + len); + // We cannot cancel sending the frame after updating the flow controller + + // Calling update always success, because len is always less than stream_credit + ink_assert(ret == 0); + + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); + if (this->_remote_flow_controller.current_offset() == this->_remote_flow_controller.current_limit()) { + QUICStreamDebug("Flow Controller will block sending a STREAM frame"); + } + + reader->consume(len); + this->_send_offset += len; + this->_write_vio.ndone += len; + } + this->_records_stream_frame(level, *static_cast(frame)); + + this->_signal_write_event(); + this->_state.update_with_sending_frame(*frame); + + return frame; +} + +QUICConnectionErrorUPtr +QUICSendStream::recv(const QUICStopSendingFrame &frame) +{ + this->_state.update_with_receiving_frame(frame); + this->reset(QUICStreamErrorUPtr(new QUICStreamError(this, QUIC_APP_ERROR_CODE_STOPPING))); + // We received and processed STOP_SENDING frame, so return NO_ERROR here + return nullptr; +} + +QUICConnectionErrorUPtr +QUICSendStream::recv(const QUICMaxStreamDataFrame &frame) +{ + this->_remote_flow_controller.forward_limit(frame.maximum_stream_data()); + QUICStreamFCDebug("[REMOTE] %" PRIu64 "/%" PRIu64, this->_remote_flow_controller.current_offset(), + this->_remote_flow_controller.current_limit()); + + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); + } + + return nullptr; +} + +VIO * +QUICSendStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + QUICStreamDebug("Warning wants to read from send only stream ignore"); + // FIXME: should not assert here + ink_assert(!"read from send only stream"); + return nullptr; +} + +VIO * +QUICSendStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +{ + if (buf) { + this->_write_vio.buffer.reader_for(buf); + } else { + this->_write_vio.buffer.clear(); + } + + this->_write_vio.mutex = c ? c->mutex : this->mutex; + this->_write_vio.cont = c; + this->_write_vio.nbytes = nbytes; + this->_write_vio.ndone = 0; + this->_write_vio.vc_server = this; + this->_write_vio.op = VIO::WRITE; + + this->_process_write_vio(); + this->_send_tracked_event(this->_write_event, VC_EVENT_WRITE_READY, &this->_write_vio); + + return &this->_write_vio; +} + +void +QUICSendStream::do_io_close(int lerrno) +{ + SET_HANDLER(&QUICSendStream::state_stream_closed); + + ink_assert(this->_read_vio.nbytes == 0); + ink_assert(this->_read_vio.op == VIO::NONE); + ink_assert(this->_read_vio.cont == nullptr); + this->_read_vio.buffer.clear(); + + this->_write_vio.buffer.clear(); + this->_write_vio.nbytes = 0; + this->_write_vio.op = VIO::NONE; + this->_write_vio.cont = nullptr; +} + +void +QUICSendStream::do_io_shutdown(ShutdownHowTo_t howto) +{ + switch (howto) { + case IO_SHUTDOWN_READ: + // ignore + break; + case IO_SHUTDOWN_WRITE: + case IO_SHUTDOWN_READWRITE: + this->do_io_close(); + break; + default: + ink_assert(0); + break; + } +} + +void +QUICSendStream::reenable(VIO *vio) +{ + ink_assert(vio == &this->_write_vio); + ink_assert(vio->op == VIO::WRITE); + + int64_t len = this->_process_write_vio(); + if (len > 0) { + this->_signal_write_event(); + } +} + +void +QUICSendStream::reset(QUICStreamErrorUPtr error) +{ + this->_reset_reason = std::move(error); +} + +void +QUICSendStream::_on_frame_acked(QUICFrameInformationUPtr &info) +{ + StreamFrameInfo *frame_info = nullptr; + switch (info->type) { + case QUICFrameType::RESET_STREAM: + this->_is_reset_complete = true; + break; + case QUICFrameType::STREAM: + frame_info = reinterpret_cast(info->data); + frame_info->block = nullptr; + if (false) { + this->_is_transfer_complete = true; + } + break; + default: + ink_assert(!"unexpected frame type"); + break; + } +} + +void +QUICSendStream::_on_frame_lost(QUICFrameInformationUPtr &info) +{ + switch (info->type) { + case QUICFrameType::RESET_STREAM: + // [draft-16] 13.2. Retransmission of Information + // Cancellation of stream transmission, as carried in a RESET_STREAM + // frame, is sent until acknowledged or until all stream data is + // acknowledged by the peer (that is, either the "Reset Recvd" or + // "Data Recvd" state is reached on the send stream). The content of + // a RESET_STREAM frame MUST NOT change when it is sent again. + this->_is_reset_sent = false; + break; + case QUICFrameType::STREAM: + this->save_frame_info(std::move(info)); + break; + default: + ink_assert(!"unexpected frame type"); + break; + } +} diff --git a/iocore/net/quic/QUICUnbidirectionalStream.h b/iocore/net/quic/QUICUnbidirectionalStream.h new file mode 100644 index 00000000000..ce53479ba68 --- /dev/null +++ b/iocore/net/quic/QUICUnbidirectionalStream.h @@ -0,0 +1,69 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICStream.h" + +class QUICSendStream : public QUICStreamVConnection +{ +public: + QUICSendStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t send_max_stream_data); + QUICSendStream() : _remote_flow_controller(0, 0), _state(nullptr, nullptr) {} + int state_stream_open(int event, void *data); + int state_stream_closed(int event, void *data); + + // QUICFrameGenerator + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; + + virtual QUICConnectionErrorUPtr recv(const QUICMaxStreamDataFrame &frame) override; + virtual QUICConnectionErrorUPtr recv(const QUICStopSendingFrame &frame) override; + + // Implement VConnection Interface. + VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; + VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; + void do_io_close(int lerrno = -1) override; + void do_io_shutdown(ShutdownHowTo_t howto) override; + void reenable(VIO *vio) override; + + void reset(QUICStreamErrorUPtr error) override; + +private: + QUICStreamErrorUPtr _reset_reason = nullptr; + bool _is_reset_sent = false; + + bool _is_transfer_complete = false; + bool _is_reset_complete = false; + + QUICTransferProgressProviderVIO _progress_vio = {this->_read_vio}; + + QUICRemoteStreamFlowController _remote_flow_controller; + + QUICSendStreamStateMachine _state; + + // QUICFrameGenerator + void _on_frame_acked(QUICFrameInformationUPtr &info) override; + void _on_frame_lost(QUICFrameInformationUPtr &info) override; +}; From 2db36132a039e69418fbefb440fb6a0e0c6a013d Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 12 Mar 2019 10:32:37 +0800 Subject: [PATCH 1209/1313] QUIC: Add receive only stream --- iocore/net/quic/QUICBidirectionalStream.h | 4 + iocore/net/quic/QUICStream.cc | 5 +- iocore/net/quic/QUICStream.h | 4 - iocore/net/quic/QUICUnbidirectionalStream.cc | 363 +++++++++++++++++++ iocore/net/quic/QUICUnbidirectionalStream.h | 63 ++++ 5 files changed, 431 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/QUICBidirectionalStream.h b/iocore/net/quic/QUICBidirectionalStream.h index 39cfaaeeed5..b756f21c90f 100644 --- a/iocore/net/quic/QUICBidirectionalStream.h +++ b/iocore/net/quic/QUICBidirectionalStream.h @@ -92,6 +92,10 @@ class QUICBidirectionalStream : public QUICStreamVConnection, public QUICTransfe QUICLocalStreamFlowController _local_flow_controller; uint64_t _flow_control_buffer_size = 1024; + // Fragments of received STREAM frame (offset is unmatched) + // TODO: Consider to replace with ts/RbTree.h or other data structure + QUICIncomingStreamFrameBuffer _received_stream_frame_buffer; + // FIXME Unidirectional streams should use either ReceiveStreamState or SendStreamState QUICBidirectionalStreamStateMachine _state; diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 7086198847d..f4d75dcdc20 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -28,10 +28,7 @@ constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; -QUICStream::QUICStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid) - : _connection_info(cinfo), _id(sid), _received_stream_frame_buffer() -{ -} +QUICStream::QUICStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid) : _connection_info(cinfo), _id(sid) {} QUICStream::~QUICStream() {} diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index 8d451c042ef..e9a87e852f2 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -81,10 +81,6 @@ class QUICStream : public QUICFrameGenerator, public QUICFrameRetransmitter QUICOffset _send_offset = 0; QUICOffset _reordered_bytes = 0; - // Fragments of received STREAM frame (offset is unmatched) - // TODO: Consider to replace with ts/RbTree.h or other data structure - QUICIncomingStreamFrameBuffer _received_stream_frame_buffer; - void _records_rst_stream_frame(QUICEncryptionLevel level, const QUICRstStreamFrame &frame); void _records_stream_frame(QUICEncryptionLevel level, const QUICStreamFrame &frame); void _records_stop_sending_frame(QUICEncryptionLevel level, const QUICStopSendingFrame &frame); diff --git a/iocore/net/quic/QUICUnbidirectionalStream.cc b/iocore/net/quic/QUICUnbidirectionalStream.cc index 09848e21992..0b55fed034b 100644 --- a/iocore/net/quic/QUICUnbidirectionalStream.cc +++ b/iocore/net/quic/QUICUnbidirectionalStream.cc @@ -390,3 +390,366 @@ QUICSendStream::_on_frame_lost(QUICFrameInformationUPtr &info) break; } } + +QUICOffset +QUICSendStream::largest_offset_sent() const +{ + return this->_remote_flow_controller.current_offset(); +} + +// +// QUICReceiveStream +// +QUICReceiveStream::QUICReceiveStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, + uint64_t recv_max_stream_data) + : QUICStreamVConnection(cinfo, sid), + _local_flow_controller(rtt_provider, recv_max_stream_data, _id), + _flow_control_buffer_size(recv_max_stream_data), + _state(this, nullptr) +{ + SET_HANDLER(&QUICReceiveStream::state_stream_open); + + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), + this->_local_flow_controller.current_limit()); +} + +int +QUICReceiveStream::state_stream_open(int event, void *data) +{ + QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); + QUICErrorUPtr error = nullptr; + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + int64_t len = this->_process_read_vio(); + if (len > 0) { + this->_signal_read_event(); + } + + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + // should not schedule write event + ink_assert(!"should not schedule write even"); + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + // TODO + ink_assert(false); + break; + } + default: + QUICStreamDebug("unknown event"); + ink_assert(false); + } + + // FIXME error is always nullptr + if (error != nullptr) { + if (error->cls == QUICErrorClass::TRANSPORT) { + QUICStreamDebug("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), QUICDebugNames::error_code(error->code), + static_cast(error->code)); + } else { + QUICStreamDebug("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls), + static_cast(error->cls), static_cast(error->code)); + } + if (dynamic_cast(error.get()) != nullptr) { + // Stream Error + QUICStreamErrorUPtr serror = QUICStreamErrorUPtr(static_cast(error.get())); + this->reset(std::move(serror)); + } else { + // Connection Error + // TODO Close connection (Does this really happen?) + } + } + + return EVENT_DONE; +} + +int +QUICReceiveStream::state_stream_closed(int event, void *data) +{ + QUICVStreamDebug("%s (%d)", get_vc_event_name(event), event); + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + // ignore + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: { + // ignore + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: { + // TODO + ink_assert(false); + break; + } + default: + ink_assert(false); + } + + return EVENT_DONE; +} + +bool +QUICReceiveStream::is_transfer_goal_set() const +{ + return this->_received_stream_frame_buffer.is_transfer_goal_set(); +} + +uint64_t +QUICReceiveStream::transfer_progress() const +{ + return this->_received_stream_frame_buffer.transfer_progress(); +} + +uint64_t +QUICReceiveStream::transfer_goal() const +{ + return this->_received_stream_frame_buffer.transfer_goal(); +} + +bool +QUICReceiveStream::is_cancelled() const +{ + return this->_is_stop_sending_complete; +} + +bool +QUICReceiveStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) +{ + return this->_local_flow_controller.will_generate_frame(level, timestamp) || + (this->_stop_sending_reason != nullptr && this->_is_stop_sending_sent == false); +} + +QUICFrame * +QUICReceiveStream::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) +{ + QUICFrame *frame = nullptr; + // STOP_SENDING + if (this->_stop_sending_reason && !this->_is_stop_sending_sent) { + frame = + QUICFrameFactory::create_stop_sending_frame(buf, this->id(), this->_stop_sending_reason->code, this->_issue_frame_id(), this); + this->_records_stop_sending_frame(level, *static_cast(frame)); + this->_state.update_with_sending_frame(*frame); + this->_is_stop_sending_sent = true; + return frame; + } + + // MAX_STREAM_DATA + frame = this->_local_flow_controller.generate_frame(buf, level, UINT16_MAX, maximum_frame_size, timestamp); + return frame; +} + +QUICConnectionErrorUPtr +QUICReceiveStream::recv(const QUICRstStreamFrame &frame) +{ + this->_state.update_with_receiving_frame(frame); + this->_signal_read_eos_event(); + return nullptr; +} + +QUICConnectionErrorUPtr +QUICReceiveStream::recv(const QUICStreamDataBlockedFrame &frame) +{ + // STREAM_DATA_BLOCKED frames are for debugging. Nothing to do here. + QUICStreamFCDebug("[REMOTE] blocked %" PRIu64, frame.offset()); + return nullptr; +} + +/** + * @brief Receive STREAM frame + * @detail When receive STREAM frame, reorder frames and write to buffer of read_vio. + * If the reordering or writting operation is heavy, split out them to read function, + * which is called by application via do_io_read() or reenable(). + */ +QUICConnectionErrorUPtr +QUICReceiveStream::recv(const QUICStreamFrame &frame) +{ + ink_assert(_id == frame.stream_id()); + ink_assert(this->_read_vio.op == VIO::READ); + + // Check stream state - Do this first before accept the frame + if (!this->_state.is_allowed_to_receive(frame)) { + QUICStreamDebug("Canceled receiving %s frame due to the stream state", QUICDebugNames::frame_type(frame.type())); + return std::make_unique(QUICTransErrorCode::STREAM_STATE_ERROR); + } + + // Flow Control - Even if it's allowed to receive on the state, it may exceed the limit + int ret = this->_local_flow_controller.update(frame.offset() + frame.data_length()); + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), + this->_local_flow_controller.current_limit()); + if (ret != 0) { + return std::make_unique(QUICTransErrorCode::FLOW_CONTROL_ERROR); + } + + // Make a copy and insert it into the receive buffer because the frame passed is temporal + QUICFrame *cloned = new QUICStreamFrame(frame); + QUICConnectionErrorUPtr error = this->_received_stream_frame_buffer.insert(cloned); + if (error != nullptr) { + this->_received_stream_frame_buffer.clear(); + return error; + } + + auto new_frame = this->_received_stream_frame_buffer.pop(); + const QUICStreamFrame *stream_frame = nullptr; + uint64_t last_offset = 0; + uint64_t last_length = 0; + + while (new_frame != nullptr) { + stream_frame = static_cast(new_frame); + last_offset = stream_frame->offset(); + last_length = stream_frame->data_length(); + + this->_write_to_read_vio(stream_frame->offset(), reinterpret_cast(stream_frame->data()->start()), + stream_frame->data_length(), stream_frame->has_fin_flag()); + this->_state.update_with_receiving_frame(*new_frame); + + delete new_frame; + new_frame = this->_received_stream_frame_buffer.pop(); + } + + // Forward limit of local flow controller with the largest reordered stream frame + if (stream_frame) { + this->_reordered_bytes = last_offset + last_length; + this->_local_flow_controller.forward_limit(this->_reordered_bytes + this->_flow_control_buffer_size); + QUICStreamFCDebug("[LOCAL] %" PRIu64 "/%" PRIu64, this->_local_flow_controller.current_offset(), + this->_local_flow_controller.current_limit()); + } + + this->_signal_read_event(); + + return nullptr; +} + +VIO * +QUICReceiveStream::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + if (buf) { + this->_read_vio.buffer.writer_for(buf); + } else { + this->_read_vio.buffer.clear(); + } + + this->_read_vio.mutex = c ? c->mutex : this->mutex; + this->_read_vio.cont = c; + this->_read_vio.nbytes = nbytes; + this->_read_vio.ndone = 0; + this->_read_vio.vc_server = this; + this->_read_vio.op = VIO::READ; + + this->_process_read_vio(); + this->_send_tracked_event(this->_read_event, VC_EVENT_READ_READY, &this->_read_vio); + + return &this->_read_vio; +} + +VIO * +QUICReceiveStream::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +{ + QUICStreamDebug("Warning wants to write to send only stream ignore"); + // FIXME: should not assert here + ink_assert(!"write to send only stream"); + return nullptr; +} + +void +QUICReceiveStream::do_io_close(int lerrno) +{ + SET_HANDLER(&QUICReceiveStream::state_stream_closed); + + ink_assert(this->_write_vio.nbytes == 0); + ink_assert(this->_write_vio.op == VIO::NONE); + ink_assert(this->_write_vio.cont == nullptr); + this->_write_vio.buffer.clear(); + + this->_read_vio.buffer.clear(); + this->_read_vio.nbytes = 0; + this->_read_vio.op = VIO::NONE; + this->_read_vio.cont = nullptr; +} + +void +QUICReceiveStream::do_io_shutdown(ShutdownHowTo_t howto) +{ + switch (howto) { + case IO_SHUTDOWN_WRITE: + // ignore + break; + case IO_SHUTDOWN_READ: + case IO_SHUTDOWN_READWRITE: + this->do_io_close(); + break; + default: + ink_assert(0); + break; + } +} + +void +QUICReceiveStream::reenable(VIO *vio) +{ + ink_assert(vio == &this->_read_vio); + ink_assert(vio->op == VIO::READ); + + int64_t len = this->_process_read_vio(); + if (len > 0) { + this->_signal_read_event(); + } +} + +void +QUICReceiveStream::on_read() +{ + this->_state.update_on_read(); +} + +void +QUICReceiveStream::on_eos() +{ + this->_state.update_on_eos(); +} + +QUICOffset +QUICReceiveStream::largest_offset_received() const +{ + return this->_local_flow_controller.current_offset(); +} + +void +QUICReceiveStream::_on_frame_lost(QUICFrameInformationUPtr &info) +{ + switch (info->type) { + case QUICFrameType::STOP_SENDING: + this->_is_stop_sending_sent = false; + break; + default: + ink_assert(!"unknown frame type"); + break; + } +} + +void +QUICReceiveStream::_on_frame_acked(QUICFrameInformationUPtr &info) +{ + switch (info->type) { + case QUICFrameType::STOP_SENDING: + this->_is_stop_sending_complete = true; + break; + default: + ink_assert(!"unknown frame type"); + break; + } +} diff --git a/iocore/net/quic/QUICUnbidirectionalStream.h b/iocore/net/quic/QUICUnbidirectionalStream.h index ce53479ba68..2dd551d881e 100644 --- a/iocore/net/quic/QUICUnbidirectionalStream.h +++ b/iocore/net/quic/QUICUnbidirectionalStream.h @@ -50,6 +50,8 @@ class QUICSendStream : public QUICStreamVConnection void reset(QUICStreamErrorUPtr error) override; + QUICOffset largest_offset_sent() const override; + private: QUICStreamErrorUPtr _reset_reason = nullptr; bool _is_reset_sent = false; @@ -67,3 +69,64 @@ class QUICSendStream : public QUICStreamVConnection void _on_frame_acked(QUICFrameInformationUPtr &info) override; void _on_frame_lost(QUICFrameInformationUPtr &info) override; }; + +class QUICReceiveStream : public QUICStreamVConnection, public QUICTransferProgressProvider +{ +public: + QUICReceiveStream(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *cinfo, QUICStreamId sid, + uint64_t recv_max_stream_data); + QUICReceiveStream() : _local_flow_controller(nullptr, 0, 0), _state(nullptr, nullptr) {} + + int state_stream_open(int event, void *data); + int state_stream_closed(int event, void *data); + + // QUICFrameGenerator + bool will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) override; + QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, + ink_hrtime timestamp) override; + + virtual QUICConnectionErrorUPtr recv(const QUICStreamFrame &frame) override; + virtual QUICConnectionErrorUPtr recv(const QUICStreamDataBlockedFrame &frame) override; + virtual QUICConnectionErrorUPtr recv(const QUICRstStreamFrame &frame) override; + + // Implement VConnection Interface. + VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) override; + VIO *do_io_write(Continuation *c = nullptr, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) override; + void do_io_close(int lerrno = -1) override; + void do_io_shutdown(ShutdownHowTo_t howto) override; + void reenable(VIO *vio) override; + + void stop_sending(QUICStreamErrorUPtr error) override; + + // QUICTransferProgressProvider + bool is_transfer_goal_set() const override; + uint64_t transfer_progress() const override; + uint64_t transfer_goal() const override; + bool is_cancelled() const override; + + /* + * QUICApplication need to call one of these functions when it process VC_EVENT_* + */ + virtual void on_read() override; + virtual void on_eos() override; + + QUICOffset largest_offset_received() const override; + +private: + QUICStreamErrorUPtr _stop_sending_reason = nullptr; + bool _is_stop_sending_sent = false; + bool _is_stop_sending_complete = false; + + QUICLocalStreamFlowController _local_flow_controller; + uint64_t _flow_control_buffer_size = 1024; + + // Fragments of received STREAM frame (offset is unmatched) + // TODO: Consider to replace with ts/RbTree.h or other data structure + QUICIncomingStreamFrameBuffer _received_stream_frame_buffer; + + QUICReceiveStreamStateMachine _state; + + // QUICFrameGenerator + void _on_frame_acked(QUICFrameInformationUPtr &info) override; + void _on_frame_lost(QUICFrameInformationUPtr &info) override; +}; From 2bf10ce6deb2b66dfb995b1f57ced985ffb21684 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 12 Mar 2019 13:54:54 +0800 Subject: [PATCH 1210/1313] QUIC: Adds unbidirectional stream test --- iocore/net/quic/QUICUnbidirectionalStream.cc | 9 +- iocore/net/quic/QUICUnbidirectionalStream.h | 4 +- iocore/net/quic/test/test_QUICStream.cc | 438 ++++++++++++++++++- 3 files changed, 445 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICUnbidirectionalStream.cc b/iocore/net/quic/QUICUnbidirectionalStream.cc index 0b55fed034b..cec961758c0 100644 --- a/iocore/net/quic/QUICUnbidirectionalStream.cc +++ b/iocore/net/quic/QUICUnbidirectionalStream.cc @@ -127,8 +127,7 @@ QUICSendStream::state_stream_closed(int event, void *data) bool QUICSendStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { - return this->_remote_flow_controller.will_generate_frame(level, timestamp) || !this->is_retransmited_frame_queue_empty() || - (this->_write_vio.get_reader()->read_avail() > 0); + return !this->is_retransmited_frame_queue_empty() || (this->_write_vio.get_reader()->read_avail() > 0); } QUICFrame * @@ -753,3 +752,9 @@ QUICReceiveStream::_on_frame_acked(QUICFrameInformationUPtr &info) break; } } + +void +QUICReceiveStream::stop_sending(QUICStreamErrorUPtr error) +{ + this->_stop_sending_reason = std::move(error); +} diff --git a/iocore/net/quic/QUICUnbidirectionalStream.h b/iocore/net/quic/QUICUnbidirectionalStream.h index 2dd551d881e..6c324a7ea77 100644 --- a/iocore/net/quic/QUICUnbidirectionalStream.h +++ b/iocore/net/quic/QUICUnbidirectionalStream.h @@ -96,8 +96,6 @@ class QUICReceiveStream : public QUICStreamVConnection, public QUICTransferProgr void do_io_shutdown(ShutdownHowTo_t howto) override; void reenable(VIO *vio) override; - void stop_sending(QUICStreamErrorUPtr error) override; - // QUICTransferProgressProvider bool is_transfer_goal_set() const override; uint64_t transfer_progress() const override; @@ -112,6 +110,8 @@ class QUICReceiveStream : public QUICStreamVConnection, public QUICTransferProgr QUICOffset largest_offset_received() const override; + void stop_sending(QUICStreamErrorUPtr error) override; + private: QUICStreamErrorUPtr _stop_sending_reason = nullptr; bool _is_stop_sending_sent = false; diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 46374d0e45e..14faae892b9 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -23,10 +23,11 @@ #include "catch.hpp" -#include "quic/QUICStream.h" +#include "quic/QUICBidirectionalStream.h" +#include "quic/QUICUnbidirectionalStream.h" #include "quic/Mock.h" -TEST_CASE("QUICStream", "[quic]") +TEST_CASE("QUICBidiStream", "[quic]") { // Test Data uint8_t payload[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; @@ -413,3 +414,436 @@ TEST_CASE("QUICStream", "[quic]") CHECK(frame->type() == QUICFrameType::STOP_SENDING); } } + +TEST_CASE("QUIC receive only stream", "[quic]") +{ + // Test Data + uint8_t payload[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; + uint32_t stream_id = 0x03; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), payload, sizeof(payload)); + block->fill(sizeof(payload)); + + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + + Ptr new_block = make_ptr(block->clone()); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_1(new_block, stream_id, 0); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_2(new_block, stream_id, 2); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_3(new_block, stream_id, 4); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_4(new_block, stream_id, 6); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_5(new_block, stream_id, 8); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_6(new_block, stream_id, 10); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_7(new_block, stream_id, 12); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_8(new_block, stream_id, 14); + block->consume(2); + + SECTION("QUICStream_assembling_byte_stream_1") + { + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + IOBufferReader *reader = read_buffer->alloc_reader(); + + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, 1024)); + stream->do_io_read(nullptr, INT64_MAX, read_buffer); + + stream->recv(frame_1); + stream->recv(frame_2); + stream->recv(frame_3); + stream->recv(frame_4); + stream->recv(frame_5); + stream->recv(frame_6); + stream->recv(frame_7); + stream->recv(frame_8); + + uint8_t buf[32]; + int64_t len = reader->read_avail(); + reader->read(buf, len); + + CHECK(len == 16); + CHECK(memcmp(buf, payload, len) == 0); + } + + SECTION("QUICStream_assembling_byte_stream_2") + { + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + IOBufferReader *reader = read_buffer->alloc_reader(); + + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX)); + stream->do_io_read(nullptr, INT64_MAX, read_buffer); + + stream->recv(frame_8); + stream->recv(frame_7); + stream->recv(frame_6); + stream->recv(frame_5); + stream->recv(frame_4); + stream->recv(frame_3); + stream->recv(frame_2); + stream->recv(frame_1); + + uint8_t buf[32]; + int64_t len = reader->read_avail(); + reader->read(buf, len); + + CHECK(len == 16); + CHECK(memcmp(buf, payload, len) == 0); + } + + SECTION("QUICStream_assembling_byte_stream_3") + { + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + IOBufferReader *reader = read_buffer->alloc_reader(); + + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX)); + stream->do_io_read(nullptr, INT64_MAX, read_buffer); + + stream->recv(frame_8); + stream->recv(frame_7); + stream->recv(frame_6); + stream->recv(frame_7); // duplicated frame + stream->recv(frame_5); + stream->recv(frame_3); + stream->recv(frame_1); + stream->recv(frame_2); + stream->recv(frame_4); + stream->recv(frame_5); // duplicated frame + + uint8_t buf[32]; + int64_t len = reader->read_avail(); + reader->read(buf, len); + + CHECK(len == 16); + CHECK(memcmp(buf, payload, len) == 0); + } + + SECTION("QUICStream_flow_control_local", "[quic]") + { + std::unique_ptr error = nullptr; + + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, 4096)); + stream->do_io_read(nullptr, INT64_MAX, read_buffer); + + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + block->fill(1024); + + // Start with 1024 but not 0 so received frames won't be processed + error = stream->recv(*std::make_shared(block, stream_id, 1024)); + CHECK(error == nullptr); + // duplicate + error = stream->recv(*std::make_shared(block, stream_id, 1024)); + CHECK(error == nullptr); + error = stream->recv(*std::make_shared(block, stream_id, 3072)); + CHECK(error == nullptr); + // delay + error = stream->recv(*std::make_shared(block, stream_id, 2048)); + CHECK(error == nullptr); + // all frames should be processed + error = stream->recv(*std::make_shared(block, stream_id, 0)); + CHECK(error == nullptr); + // start again without the first block + error = stream->recv(*std::make_shared(block, stream_id, 5120)); + CHECK(error == nullptr); + // this should exceed the limit + error = stream->recv(*std::make_shared(block, stream_id, 8192)); + CHECK(error->cls == QUICErrorClass::TRANSPORT); + CHECK(error->code == static_cast(QUICTransErrorCode::FLOW_CONTROL_ERROR)); + } + + SECTION("Retransmit STOP_SENDING frame") + { + MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); + IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); + + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX)); + SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); + + MockContinuation mock_cont(stream->mutex); + // stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); + + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + QUICFrame *frame = nullptr; + + stream->stop_sending(QUICStreamErrorUPtr(new QUICStreamError(stream.get(), QUIC_APP_ERROR_CODE_STOPPING))); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + REQUIRE(frame); + CHECK(frame->type() == QUICFrameType::STOP_SENDING); + // Don't send it again untill it is considers as lost + CHECK(stream->generate_frame(frame_buf, level, 4096, 4096, 0) == nullptr); + // Loss the frame + stream->on_frame_lost(frame->id()); + // After the loss the frame should be regenerated + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + REQUIRE(frame); + CHECK(frame->type() == QUICFrameType::STOP_SENDING); + } +} + +TEST_CASE("QUIC send only stream", "[quic]") +{ + // Test Data + uint8_t payload[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; + uint32_t stream_id = 0x03; + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(); + memcpy(block->start(), payload, sizeof(payload)); + block->fill(sizeof(payload)); + + uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; + + Ptr new_block = make_ptr(block->clone()); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_1(new_block, stream_id, 0); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_2(new_block, stream_id, 2); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_3(new_block, stream_id, 4); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_4(new_block, stream_id, 6); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_5(new_block, stream_id, 8); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_6(new_block, stream_id, 10); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_7(new_block, stream_id, 12); + block->consume(2); + + new_block = block->clone(); + new_block->_end = new_block->_start + 2; + QUICStreamFrame frame_8(new_block, stream_id, 14); + block->consume(2); + + SECTION("QUICStream_flow_control_remote", "[quic]") + { + std::unique_ptr error = nullptr; + + MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); + + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICSendStream(&cinfo_provider, stream_id, 4096)); + SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); + + MockContinuation mock_cont(stream->mutex); + // stream->do_io_read(nullptr, INT64_MAX, read_buffer); + stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); + + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + + const char data[1024] = {0}; + QUICFrame *frame = nullptr; + + write_buffer->write(data, 1024); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame(level, 0) == false); + + write_buffer->write(data, 1024); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame(level, 0) == false); + + write_buffer->write(data, 1024); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame(level, 0) == false); + + write_buffer->write(data, 1024); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame(level, 0) == false); + + // This should not send a frame because of flow control + write_buffer->write(data, 1024); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + CHECK(frame); + CHECK(frame->type() == QUICFrameType::STREAM_DATA_BLOCKED); + CHECK(stream->will_generate_frame(level, 0) == true); + + // Update window + stream->recv(*std::make_shared(stream_id, 5120)); + + // This should send a frame + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame(level, 0) == false); + + // Update window + stream->recv(*std::make_shared(stream_id, 5632)); + + // This should send a frame + write_buffer->write(data, 1024); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame(level, 0) == true); + + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + CHECK(frame->type() == QUICFrameType::STREAM_DATA_BLOCKED); + + // Update window + stream->recv(*std::make_shared(stream_id, 6144)); + + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + CHECK(stream->will_generate_frame(level, 0) == true); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->will_generate_frame(level, 0) == false); + } + + /* + * This test does not pass now + */ + SECTION("Retransmit STREAM frame") + { + MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); + IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); + + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICSendStream(&cinfo_provider, stream_id, UINT64_MAX)); + SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); + + MockContinuation mock_cont(stream->mutex); + stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); + + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + const char data1[] = "this is a test data"; + const char data2[] = "THIS IS ANOTHER TEST DATA"; + QUICFrame *frame = nullptr; + QUICStreamFrame *frame1 = nullptr; + QUICStreamFrame *frame2 = nullptr; + uint8_t frame_buf2[QUICFrame::MAX_INSTANCE_SIZE]; + + // Write data1 + write_buffer->write(data1, sizeof(data1)); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + // Generate STREAM frame + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + frame1 = static_cast(frame); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(stream->generate_frame(frame_buf, level, 4096, 4096, 0) == nullptr); + CHECK(stream->will_generate_frame(level, 0) == false); + stream->on_frame_lost(frame->id()); + CHECK(stream->will_generate_frame(level, 0) == true); + + // Write data2 + write_buffer->write(data2, sizeof(data2)); + stream->handleEvent(VC_EVENT_WRITE_READY, nullptr); + // Lost the frame + stream->on_frame_lost(frame->id()); + // Regenerate a frame + frame = stream->generate_frame(frame_buf2, level, 4096, 4096, 0); + // Lost data should be resent first + frame2 = static_cast(frame); + CHECK(frame->type() == QUICFrameType::STREAM); + CHECK(frame1->offset() == frame2->offset()); + CHECK(frame1->data_length() == frame2->data_length()); + CHECK(memcmp(frame1->data(), frame2->data(), frame1->data_length())); + } + + SECTION("Retransmit RESET_STREAM frame") + { + MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); + IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); + + MockQUICRTTProvider rtt_provider; + MockQUICConnectionInfoProvider cinfo_provider; + std::unique_ptr stream(new QUICSendStream(&cinfo_provider, stream_id, UINT64_MAX)); + SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); + + MockContinuation mock_cont(stream->mutex); + stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); + + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; + QUICFrame *frame = nullptr; + + stream->reset(QUICStreamErrorUPtr(new QUICStreamError(stream.get(), QUIC_APP_ERROR_CODE_STOPPING))); + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + REQUIRE(frame); + CHECK(frame->type() == QUICFrameType::RESET_STREAM); + // Don't send it again untill it is considers as lost + CHECK(stream->generate_frame(frame_buf, level, 4096, 4096, 0) == nullptr); + // Loss the frame + stream->on_frame_lost(frame->id()); + // After the loss the frame should be regenerated + frame = stream->generate_frame(frame_buf, level, 4096, 4096, 0); + REQUIRE(frame); + CHECK(frame->type() == QUICFrameType::RESET_STREAM); + } +} From 4aaae87ca6b86e88ba48191c1bbe45cbadd0c8bd Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 13 Mar 2019 09:21:13 +0800 Subject: [PATCH 1211/1313] QUIC: Move max_crypto_frame into QUICCryptoStream.cc --- iocore/net/quic/QUICCryptoStream.cc | 2 ++ iocore/net/quic/QUICStream.cc | 1 - iocore/net/quic/QUICStream.h | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICCryptoStream.cc b/iocore/net/quic/QUICCryptoStream.cc index 034873fef05..f3b702cc487 100644 --- a/iocore/net/quic/QUICCryptoStream.cc +++ b/iocore/net/quic/QUICCryptoStream.cc @@ -23,6 +23,8 @@ #include "QUICCryptoStream.h" +constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; + // // QUICCryptoStream // diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index f4d75dcdc20..3c98ef4d61b 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -26,7 +26,6 @@ #include "QUICStreamManager.h" constexpr uint32_t MAX_STREAM_FRAME_OVERHEAD = 24; -constexpr uint32_t MAX_CRYPTO_FRAME_OVERHEAD = 16; QUICStream::QUICStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid) : _connection_info(cinfo), _id(sid) {} diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index e9a87e852f2..fda00bf1404 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -131,4 +131,3 @@ class QUICStreamVConnection : public VConnection, public QUICStream QUICDebugNames::stream_state(this->_state.get()), ##__VA_ARGS__) extern const uint32_t MAX_STREAM_FRAME_OVERHEAD; -extern const uint32_t MAX_CRYPTO_FRAME_OVERHEAD; From fd6b9c91c4ccc769acb313ab02d2da26c3443407 Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 13 Mar 2019 09:52:54 +0800 Subject: [PATCH 1212/1313] QUIC Rename unbidirectional to unidirectional and fixed test --- ...QUICUnbidirectionalStream.cc => QUICUnidirectionalStream.cc} | 0 .../{QUICUnbidirectionalStream.h => QUICUnidirectionalStream.h} | 0 iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename iocore/net/quic/{QUICUnbidirectionalStream.cc => QUICUnidirectionalStream.cc} (100%) rename iocore/net/quic/{QUICUnbidirectionalStream.h => QUICUnidirectionalStream.h} (100%) diff --git a/iocore/net/quic/QUICUnbidirectionalStream.cc b/iocore/net/quic/QUICUnidirectionalStream.cc similarity index 100% rename from iocore/net/quic/QUICUnbidirectionalStream.cc rename to iocore/net/quic/QUICUnidirectionalStream.cc diff --git a/iocore/net/quic/QUICUnbidirectionalStream.h b/iocore/net/quic/QUICUnidirectionalStream.h similarity index 100% rename from iocore/net/quic/QUICUnbidirectionalStream.h rename to iocore/net/quic/QUICUnidirectionalStream.h diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 32eee34291c..6d8c9f55646 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -24,7 +24,7 @@ #include "catch.hpp" #include "quic/QUICIncomingFrameBuffer.h" -#include "quic/QUICStream.h" +#include "quic/QUICBidirectionalStream.h" #include TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]") From eb2a9ff588f948d97da06dc2f9f59e198454d5e2 Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 13 Mar 2019 10:03:48 +0800 Subject: [PATCH 1213/1313] QUIC: Fixed building and test_QUICStream --- iocore/net/quic/Makefile.am | 2 +- iocore/net/quic/QUICUnidirectionalStream.cc | 2 +- iocore/net/quic/test/test_QUICStream.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index c03eca0d73f..4a806975136 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -89,7 +89,7 @@ libquic_a_SOURCES = \ QUICAddrVerifyState.cc \ QUICBidirectionalStream.cc \ QUICCryptoStream.cc \ - QUICUnbidirectionalStream.cc + QUICUnidirectionalStream.cc # # Check Programs diff --git a/iocore/net/quic/QUICUnidirectionalStream.cc b/iocore/net/quic/QUICUnidirectionalStream.cc index cec961758c0..2cd27d9b7a0 100644 --- a/iocore/net/quic/QUICUnidirectionalStream.cc +++ b/iocore/net/quic/QUICUnidirectionalStream.cc @@ -21,7 +21,7 @@ * limitations under the License. */ -#include "QUICUnbidirectionalStream.h" +#include "QUICUnidirectionalStream.h" // // QUICSendStream diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 14faae892b9..4f2553ed4a2 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -24,7 +24,7 @@ #include "catch.hpp" #include "quic/QUICBidirectionalStream.h" -#include "quic/QUICUnbidirectionalStream.h" +#include "quic/QUICUnidirectionalStream.h" #include "quic/Mock.h" TEST_CASE("QUICBidiStream", "[quic]") From 3effcc011fa0ab7c4f3fbb17b0822009226fb905 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Mar 2019 12:29:53 +0900 Subject: [PATCH 1214/1313] Fix test_QUICStream --- iocore/net/quic/test/test_QUICStream.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 4f2553ed4a2..dc3b619a792 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -349,7 +349,7 @@ TEST_CASE("QUICBidiStream", "[quic]") CHECK(frame->type() == QUICFrameType::STREAM); CHECK(frame1->offset() == frame2->offset()); CHECK(frame1->data_length() == frame2->data_length()); - CHECK(memcmp(frame1->data(), frame2->data(), frame1->data_length())); + CHECK(memcmp(frame1->data()->buf(), frame2->data()->buf(), frame1->data_length()) == 0); } SECTION("Retransmit RESET_STREAM frame") @@ -814,7 +814,7 @@ TEST_CASE("QUIC send only stream", "[quic]") CHECK(frame->type() == QUICFrameType::STREAM); CHECK(frame1->offset() == frame2->offset()); CHECK(frame1->data_length() == frame2->data_length()); - CHECK(memcmp(frame1->data(), frame2->data(), frame1->data_length())); + CHECK(memcmp(frame1->data()->buf(), frame2->data()->buf(), frame1->data_length()) == 0); } SECTION("Retransmit RESET_STREAM frame") From f04325d63d067b9d3fbdf43f5b3d58ce939abee3 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 13 Mar 2019 14:31:38 +0900 Subject: [PATCH 1215/1313] Change interface of QUICPacketPayloadProtector to IOBufferBlock from uint8_t array --- iocore/net/quic/QUICPacketFactory.cc | 59 ++++++++++++------- iocore/net/quic/QUICPacketPayloadProtector.cc | 55 ++++++++++++----- iocore/net/quic/QUICPacketPayloadProtector.h | 15 ++--- .../QUICPacketPayloadProtector_openssl.cc | 19 +++--- 4 files changed, 98 insertions(+), 50 deletions(-) diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc index 19587d35866..14a8f930a33 100644 --- a/iocore/net/quic/QUICPacketFactory.cc +++ b/iocore/net/quic/QUICPacketFactory.cc @@ -89,6 +89,14 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP result = QUICPacketCreationResult::UNSUPPORTED; } } else { + Ptr plain = make_ptr(new_IOBufferBlock()); + Ptr protected_ibb = make_ptr(new_IOBufferBlock()); + protected_ibb->set_internal(reinterpret_cast(const_cast(header->payload())), header->payload_size(), + BUFFER_SIZE_NOT_ALLOCATED); + Ptr header_ibb = make_ptr(new_IOBufferBlock()); + header_ibb->set_internal(reinterpret_cast(const_cast(header->buf())), header->size(), + BUFFER_SIZE_NOT_ALLOCATED); + switch (header->type()) { case QUICPacketType::STATELESS_RESET: case QUICPacketType::RETRY: @@ -99,9 +107,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP break; case QUICPacketType::PROTECTED: if (this->_pp_key_info.is_decryption_key_available(header->key_phase())) { - if (this->_pp_protector.unprotect(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - header->key_phase())) { + plain = this->_pp_protector.unprotect(header_ibb, protected_ibb, header->packet_number(), header->key_phase()); + memcpy(plain_txt.get(), plain->buf(), plain->size()); + plain_txt_len = plain->size(); + if (plain != nullptr) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -113,9 +122,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP case QUICPacketType::INITIAL: if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::INITIAL)) { if (QUICTypeUtil::is_supported_version(header->version())) { - if (this->_pp_protector.unprotect(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::INITIAL)) { + plain = this->_pp_protector.unprotect(header_ibb, protected_ibb, header->packet_number(), header->key_phase()); + memcpy(plain_txt.get(), plain->buf(), plain->size()); + plain_txt_len = plain->size(); + if (plain != nullptr) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -129,9 +139,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP break; case QUICPacketType::HANDSHAKE: if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::HANDSHAKE)) { - if (this->_pp_protector.unprotect(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::HANDSHAKE)) { + plain = this->_pp_protector.unprotect(header_ibb, protected_ibb, header->packet_number(), header->key_phase()); + memcpy(plain_txt.get(), plain->buf(), plain->size()); + plain_txt_len = plain->size(); + if (plain != nullptr) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; @@ -142,9 +153,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP break; case QUICPacketType::ZERO_RTT_PROTECTED: if (this->_pp_key_info.is_decryption_key_available(QUICKeyPhase::ZERO_RTT)) { - if (this->_pp_protector.unprotect(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), - header->payload_size(), header->packet_number(), header->buf(), header->size(), - QUICKeyPhase::ZERO_RTT)) { + plain = this->_pp_protector.unprotect(header_ibb, protected_ibb, header->packet_number(), header->key_phase()); + memcpy(plain_txt.get(), plain->buf(), plain->size()); + plain_txt_len = plain->size(); + if (plain != nullptr) { result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::IGNORED; @@ -298,21 +310,28 @@ QUICPacketFactory::_create_unprotected_packet(QUICPacketHeaderUPtr header) QUICPacketUPtr QUICPacketFactory::_create_encrypted_packet(QUICPacketHeaderUPtr header, bool retransmittable, bool probing) { - // TODO: use pmtu of UnixNetVConnection - size_t max_cipher_txt_len = 2048; - ats_unique_buf cipher_txt = ats_unique_malloc(max_cipher_txt_len); - size_t cipher_txt_len = 0; - 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; - if (this->_pp_protector.protect(cipher_txt.get(), cipher_txt_len, max_cipher_txt_len, header->payload(), header->payload_size(), - header->packet_number(), header->buf(), header->size(), header->key_phase())) { + + Ptr payload_ibb = make_ptr(new_IOBufferBlock()); + payload_ibb->set_internal(reinterpret_cast(const_cast(header->payload())), header->payload_size(), + BUFFER_SIZE_NOT_ALLOCATED); + + Ptr header_ibb = make_ptr(new_IOBufferBlock()); + header_ibb->set_internal(reinterpret_cast(const_cast(header->buf())), header->size(), + BUFFER_SIZE_NOT_ALLOCATED); + + Ptr protected_payload = + this->_pp_protector.protect(header_ibb, payload_ibb, header->packet_number(), header->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), cipher_txt_len, retransmittable, probing); + new (packet) QUICPacket(std::move(header), std::move(cipher_txt), protected_payload->size(), retransmittable, probing); } else { QUICDebug(dcid, scid, "Failed to encrypt a packet"); } diff --git a/iocore/net/quic/QUICPacketPayloadProtector.cc b/iocore/net/quic/QUICPacketPayloadProtector.cc index 723fb1cc1ce..cb342945bdc 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector.cc +++ b/iocore/net/quic/QUICPacketPayloadProtector.cc @@ -27,48 +27,71 @@ static constexpr char tag[] = "quic_ppp"; -bool -QUICPacketPayloadProtector::protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, - size_t plain_len, uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const +Ptr +QUICPacketPayloadProtector::protect(Ptr unprotected_header, Ptr unprotected_payload, uint64_t pkt_num, + QUICKeyPhase phase) const { + Ptr protected_payload; + protected_payload = nullptr; + size_t tag_len = this->_pp_key_info.get_tag_len(phase); const uint8_t *key = this->_pp_key_info.encryption_key(phase); const uint8_t *iv = this->_pp_key_info.encryption_iv(phase); size_t iv_len = *this->_pp_key_info.encryption_iv_len(phase); if (!key) { Debug(tag, "Failed to encrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); - return false; + return protected_payload; } + const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher(phase); - bool ret = - this->_protect(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, key, iv, iv_len, aead, tag_len); - if (!ret) { + protected_payload = make_ptr(new_IOBufferBlock()); + protected_payload->alloc(iobuffer_size_to_index(unprotected_payload->size() + tag_len)); + + size_t written_len = 0; + if (!this->_protect(reinterpret_cast(protected_payload->start()), written_len, protected_payload->write_avail(), + unprotected_payload, pkt_num, reinterpret_cast(unprotected_header->buf()), + unprotected_header->size(), key, iv, iv_len, aead, tag_len)) { Debug(tag, "Failed to encrypt a packet #%" PRIu64, pkt_num); + protected_payload = nullptr; + } else { + protected_payload->fill(written_len); } - return ret; + + return protected_payload; } -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, +Ptr +QUICPacketPayloadProtector::unprotect(Ptr unprotected_header, Ptr protected_payload, uint64_t pkt_num, QUICKeyPhase phase) const { + Ptr unprotected_payload; + unprotected_payload = nullptr; + size_t tag_len = this->_pp_key_info.get_tag_len(phase); const uint8_t *key = this->_pp_key_info.decryption_key(phase); const uint8_t *iv = this->_pp_key_info.decryption_iv(phase); size_t iv_len = *this->_pp_key_info.decryption_iv_len(phase); if (!key) { Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); - return false; + return unprotected_payload; } const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher(phase); - bool ret = - this->_unprotect(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, key, iv, iv_len, aead, tag_len); - if (!ret) { + + unprotected_payload = make_ptr(new_IOBufferBlock()); + unprotected_payload->alloc(iobuffer_size_to_index(protected_payload->size())); + + size_t written_len = 0; + if (!this->_unprotect(reinterpret_cast(unprotected_payload->start()), written_len, unprotected_payload->write_avail(), + reinterpret_cast(protected_payload->buf()), protected_payload->size(), pkt_num, + reinterpret_cast(unprotected_header->buf()), unprotected_header->size(), key, iv, iv_len, aead, + tag_len)) { Debug(tag, "Failed to decrypt a packet #%" PRIu64, pkt_num); + unprotected_header = nullptr; + } else { + unprotected_payload->fill(written_len); } - return ret; + return unprotected_payload; } /** diff --git a/iocore/net/quic/QUICPacketPayloadProtector.h b/iocore/net/quic/QUICPacketPayloadProtector.h index f5d2aab38c0..38ffde00a19 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector.h +++ b/iocore/net/quic/QUICPacketPayloadProtector.h @@ -23,6 +23,7 @@ #pragma once +#include "I_IOBuffer.h" #include "QUICTypes.h" #include "QUICKeyGenerator.h" @@ -33,10 +34,10 @@ class QUICPacketPayloadProtector public: QUICPacketPayloadProtector(const QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {} - bool 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, QUICKeyPhase phase) const; - bool protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num, - const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const; + Ptr protect(Ptr unprotected_header, Ptr unprotected_payload, uint64_t pkt_num, + QUICKeyPhase phase) const; + Ptr unprotect(Ptr unprotected_header, Ptr protected_payload, uint64_t pkt_num, + QUICKeyPhase phase) const; private: const QUICPacketProtectionKeyInfo &_pp_key_info; @@ -44,9 +45,9 @@ class QUICPacketPayloadProtector bool _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 QUIC_EVP_CIPHER *aead, size_t tag_len) const; - bool _protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_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 QUIC_EVP_CIPHER *aead, size_t tag_len) const; + bool _protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, Ptr 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 QUIC_EVP_CIPHER *aead, + size_t tag_len) const; void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; }; diff --git a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc b/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc index 66342605708..dbfd69b4ec8 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc +++ b/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc @@ -28,9 +28,9 @@ static constexpr char tag[] = "quic_ppp"; bool -QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, - size_t plain_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 +QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, Ptr 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; @@ -54,12 +54,17 @@ QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t if (!EVP_EncryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) { return false; } - if (!EVP_EncryptUpdate(aead_ctx, cipher, &len, plain, plain_len)) { - return false; + + cipher_len = 0; + while (plain) { + if (!EVP_EncryptUpdate(aead_ctx, cipher + cipher_len, &len, reinterpret_cast(plain->buf()), plain->size())) { + return false; + } + cipher_len += len; + plain = plain->next; } - cipher_len = len; - if (!EVP_EncryptFinal_ex(aead_ctx, cipher + len, &len)) { + if (!EVP_EncryptFinal_ex(aead_ctx, cipher + cipher_len, &len)) { return false; } cipher_len += len; From 3059b853f424ff813834c700f3a5d328fc68dd9a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Mar 2019 10:16:15 +0900 Subject: [PATCH 1216/1313] Add QUICFrame::to_io_buffer_block() and use it instead of store() --- iocore/net/P_QUICNetVConnection.h | 6 +-- iocore/net/QUICNetVConnection.cc | 88 +++++++++++++++++++++++-------- iocore/net/quic/QUICFrame.cc | 16 ++++++ iocore/net/quic/QUICFrame.h | 1 + 4 files changed, 85 insertions(+), 26 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 160ddbe5af3..18c207bf012 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -289,11 +289,11 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub uint32_t _minimum_quic_packet_size(); uint64_t _maximum_stream_frame_data_size(); - void _store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrame &frame, - std::vector &frames); + Ptr _store_frame(Ptr parent_block, size_t &size_added, uint64_t &max_frame_size, QUICFrame &frame, + std::vector &frames); QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size, std::vector &frames); void _packetize_closing_frame(); - QUICPacketUPtr _build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool retransmittable, bool probing, + QUICPacketUPtr _build_packet(QUICEncryptionLevel level, Ptr parent_block, bool retransmittable, bool probing, bool crypto); QUICConnectionErrorUPtr _recv_and_ack(QUICPacket &packet, bool *has_non_probing_frame = nullptr); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index ff03ca8ab7b..b7067f25ee7 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1460,18 +1460,29 @@ QUICNetVConnection::_state_closing_send_packet() return nullptr; } -void -QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t &max_frame_size, QUICFrame &frame, +Ptr +QUICNetVConnection::_store_frame(Ptr parent_block, size_t &size_added, uint64_t &max_frame_size, QUICFrame &frame, std::vector &frames) { - size_t l = 0; - frame.store(buf.get() + offset, &l, max_frame_size); + Ptr new_block = frame.to_io_buffer_block(max_frame_size); + + size_added = 0; + Ptr tmp = new_block; + while (tmp) { + size_added += new_block->size(); + tmp = new_block->next; + } + + if (parent_block == nullptr) { + parent_block = new_block; + } else { + parent_block->next = new_block; + } // frame should be stored because it's created with max_frame_size - ink_assert(l != 0); + ink_assert(size_added != 0); - offset += l; - max_frame_size -= l; + max_frame_size -= size_added; if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) { char msg[1024]; @@ -1480,6 +1491,11 @@ QUICNetVConnection::_store_frame(ats_unique_buf &buf, size_t &offset, uint64_t & } frames.emplace_back(frame.id(), frame.generated_by()); + + while (parent_block->next) { + parent_block = parent_block->next; + } + return parent_block; } QUICPacketUPtr @@ -1499,10 +1515,11 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } max_frame_size = std::min(max_frame_size, this->_maximum_stream_frame_data_size()); - bool probing = false; - int frame_count = 0; - size_t len = 0; - ats_unique_buf buf = ats_unique_malloc(max_packet_size); + bool probing = false; + int frame_count = 0; + size_t len = 0; + Ptr first_block; + Ptr last_block; if (!this->_has_ack_eliciting_packet_out) { // Sent too much ack_only packet. At this moment we need to packetize a ping frame @@ -1510,6 +1527,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa this->_pinger.request(level); } + size_t size_added = 0; bool ack_eliciting = false; bool crypto = false; uint8_t frame_instance_buffer[QUICFrame::MAX_INSTANCE_SIZE]; // This is for a frame instance but not serialized frame data @@ -1535,7 +1553,12 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa this->_remote_flow_controller->current_limit()); ink_assert(ret == 0); } - this->_store_frame(buf, len, max_frame_size, *frame, frames); + last_block = this->_store_frame(last_block, size_added, max_frame_size, *frame, frames); + len += size_added; + + if (first_block == nullptr) { + first_block = last_block; + } // FIXME ACK frame should have priority if (frame->type() == QUICFrameType::STREAM) { @@ -1574,20 +1597,27 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa if (min_size > len) { // FIXME QUICNetVConnection should not know the actual type value of PADDING frame - memset(buf.get() + len, 0, min_size - len); - len += min_size - len; + Ptr pad_block = make_ptr(new_IOBufferBlock()); + pad_block->alloc(iobuffer_size_to_index(min_size - len)); + memset(pad_block->start(), 0, pad_block->size()); + last_block->next = pad_block; + len += pad_block->size(); } } else { // Pad with PADDING frames to make sure payload length satisfy the minimum length for sampling for header protection if (3 > len) { // FIXME QUICNetVConnection should not know the actual type value of PADDING frame - memset(buf.get() + len, 0, 3 - len); - len += 3 - len; + Ptr pad_block = make_ptr(new_IOBufferBlock()); + ; + pad_block->alloc(iobuffer_size_to_index(3 - len)); + memset(pad_block->start(), 0, pad_block->size()); + last_block->next = pad_block; + len += pad_block->size(); } } // Packet is retransmittable if it's not ack only packet - packet = this->_build_packet(level, std::move(buf), len, ack_eliciting, probing, crypto); + packet = this->_build_packet(level, first_block, ack_eliciting, probing, crypto); this->_has_ack_eliciting_packet_out = ack_eliciting; } @@ -1607,17 +1637,18 @@ QUICNetVConnection::_packetize_closing_frame() uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; frame = QUICFrameFactory::create_connection_close_frame(frame_buf, *this->_connection_error); - uint32_t max_size = this->_maximum_quic_packet_size(); - ats_unique_buf buf = ats_unique_malloc(max_size); + uint32_t max_size = this->_maximum_quic_packet_size(); - size_t len = 0; + size_t size_added = 0; uint64_t max_frame_size = static_cast(max_size); std::vector frames; - this->_store_frame(buf, len, max_frame_size, *frame, frames); + Ptr parent_block; + parent_block = nullptr; + parent_block = this->_store_frame(parent_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, std::move(buf), len, true, false, false); + this->_the_final_packet = this->_build_packet(level, parent_block, true, false, false); } QUICConnectionErrorUPtr @@ -1663,12 +1694,23 @@ QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_fram } QUICPacketUPtr -QUICNetVConnection::_build_packet(QUICEncryptionLevel level, ats_unique_buf buf, size_t len, bool ack_eliciting, bool probing, +QUICNetVConnection::_build_packet(QUICEncryptionLevel level, Ptr 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->buf(), parent_block->size()); + len += parent_block->size(); + parent_block = parent_block->next; + } + switch (type) { case QUICPacketType::INITIAL: { QUICConnectionId dcid = this->_peer_quic_connection_id; diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index a9e2cbc7423..f0046231560 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -105,6 +105,22 @@ QUICFrame::type(const uint8_t *buf) } } +Ptr +QUICFrame::to_io_buffer_block(size_t limit) const +{ + // FIXME Each classes should override this and drop store(). + // This just wraps store() for now. + + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(iobuffer_size_to_index(limit)); + + size_t written_len = 0; + this->store(reinterpret_cast(block->start()), &written_len, limit); + block->fill(written_len); + + return block; +} + int QUICFrame::debug_msg(char *msg, size_t msg_len) const { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 6379985f95c..08f77bffd43 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -56,6 +56,7 @@ class QUICFrame virtual bool is_probing_frame() const; virtual bool is_flow_controlled() const; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const = 0; + virtual Ptr to_io_buffer_block(size_t limit) const; virtual int debug_msg(char *msg, size_t msg_len) const; virtual void parse(const uint8_t *buf, size_t len){}; virtual QUICFrameGenerator *generated_by(); From 98e1ec33f4dcbc70553e1536296b82dd63f4be3b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 14 Mar 2019 12:31:29 +0900 Subject: [PATCH 1217/1313] Update tests to catch up interface changes --- .../quic/test/test_QUICHandshakeProtocol.cc | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 91820c95f1d..53b32d9c3da 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -193,24 +193,24 @@ TEST_CASE("QUICHandshakeProtocol") std::cout << "### Original Text" << std::endl; print_hex(original, sizeof(original)); - uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead - size_t cipher_len = 0; - CHECK(ppp_client.protect(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), - QUICKeyPhase::PHASE_0)); + Ptr original_ibb = make_ptr(new_IOBufferBlock()); + original_ibb->set_internal(const_cast(original), sizeof(original), BUFFER_SIZE_NOT_ALLOCATED); + Ptr header_ibb = make_ptr(new_IOBufferBlock()); + header_ibb->set_internal(const_cast(ad), sizeof(ad), BUFFER_SIZE_NOT_ALLOCATED); + Ptr cipher = ppp_client.protect(header_ibb, original_ibb, pkt_num, QUICKeyPhase::PHASE_0); + CHECK(cipher); std::cout << "### Encrypted Text" << std::endl; - print_hex(cipher, cipher_len); + print_hex(reinterpret_cast(cipher->buf()), cipher->size()); - uint8_t plain[128] = {0}; - size_t plain_len = 0; - CHECK( - ppp_server.unprotect(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); + Ptr plain = ppp_server.unprotect(header_ibb, cipher, pkt_num, QUICKeyPhase::PHASE_0); + CHECK(plain); std::cout << "### Decrypted Text" << std::endl; - print_hex(plain, plain_len); + print_hex(reinterpret_cast(plain->buf()), plain->size()); - CHECK(sizeof(original) == (plain_len)); - CHECK(memcmp(original, plain, plain_len) == 0); + CHECK(sizeof(original) == (plain->size())); + CHECK(memcmp(original, plain->buf(), plain->size()) == 0); // Teardown delete client; @@ -327,29 +327,30 @@ TEST_CASE("QUICHandshakeProtocol") std::cout << "### Messages from server" << std::endl; print_hex(msg6.buf, msg6.offsets[4]); + Ptr original_ibb = make_ptr(new_IOBufferBlock()); + original_ibb->set_internal(const_cast(original), sizeof(original), BUFFER_SIZE_NOT_ALLOCATED); + Ptr header_ibb = make_ptr(new_IOBufferBlock()); + header_ibb->set_internal(const_cast(ad), sizeof(ad), BUFFER_SIZE_NOT_ALLOCATED); + // encrypt - decrypt // client (encrypt) - server (decrypt) std::cout << "### Original Text" << std::endl; print_hex(original, sizeof(original)); - uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead - size_t cipher_len = 0; - CHECK(ppp_client.protect(cipher, cipher_len, sizeof(cipher), original, sizeof(original), pkt_num, ad, sizeof(ad), - QUICKeyPhase::PHASE_0)); + Ptr cipher = ppp_client.protect(header_ibb, original_ibb, pkt_num, QUICKeyPhase::PHASE_0); + CHECK(cipher); std::cout << "### Encrypted Text" << std::endl; - print_hex(cipher, cipher_len); + print_hex(reinterpret_cast(cipher->buf()), cipher->size()); - uint8_t plain[128] = {0}; - size_t plain_len = 0; - CHECK( - ppp_server.unprotect(plain, plain_len, sizeof(plain), cipher, cipher_len, pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0)); + Ptr plain = ppp_server.unprotect(header_ibb, cipher, pkt_num, QUICKeyPhase::PHASE_0); + CHECK(plain); std::cout << "### Decrypted Text" << std::endl; - print_hex(plain, plain_len); + print_hex(reinterpret_cast(plain->buf()), plain->size()); - CHECK(sizeof(original) == (plain_len)); - CHECK(memcmp(original, plain, plain_len) == 0); + CHECK(sizeof(original) == plain->size()); + CHECK(memcmp(original, plain->buf(), plain->size()) == 0); // Teardown // Make it back to the default settings From d64938e0c6ca46757aeb3e8ff2e67cb8c09cae6f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 15 Mar 2019 12:11:06 +0900 Subject: [PATCH 1218/1313] Add const qualifiers --- iocore/net/quic/QUICPacketPayloadProtector.cc | 10 +++++----- iocore/net/quic/QUICPacketPayloadProtector.h | 10 +++++----- iocore/net/quic/QUICPacketPayloadProtector_openssl.cc | 11 ++++++----- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/iocore/net/quic/QUICPacketPayloadProtector.cc b/iocore/net/quic/QUICPacketPayloadProtector.cc index cb342945bdc..d0b9eb53c7a 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector.cc +++ b/iocore/net/quic/QUICPacketPayloadProtector.cc @@ -28,8 +28,8 @@ static constexpr char tag[] = "quic_ppp"; Ptr -QUICPacketPayloadProtector::protect(Ptr unprotected_header, Ptr unprotected_payload, uint64_t pkt_num, - QUICKeyPhase phase) const +QUICPacketPayloadProtector::protect(const Ptr unprotected_header, const Ptr unprotected_payload, + uint64_t pkt_num, QUICKeyPhase phase) const { Ptr protected_payload; protected_payload = nullptr; @@ -62,8 +62,8 @@ QUICPacketPayloadProtector::protect(Ptr unprotected_header, Ptr -QUICPacketPayloadProtector::unprotect(Ptr unprotected_header, Ptr protected_payload, uint64_t pkt_num, - QUICKeyPhase phase) const +QUICPacketPayloadProtector::unprotect(const Ptr unprotected_header, const Ptr protected_payload, + uint64_t pkt_num, QUICKeyPhase phase) const { Ptr unprotected_payload; unprotected_payload = nullptr; @@ -87,7 +87,7 @@ QUICPacketPayloadProtector::unprotect(Ptr unprotected_header, Ptr reinterpret_cast(unprotected_header->buf()), unprotected_header->size(), key, iv, iv_len, aead, tag_len)) { Debug(tag, "Failed to decrypt a packet #%" PRIu64, pkt_num); - unprotected_header = nullptr; + unprotected_payload = nullptr; } else { unprotected_payload->fill(written_len); } diff --git a/iocore/net/quic/QUICPacketPayloadProtector.h b/iocore/net/quic/QUICPacketPayloadProtector.h index 38ffde00a19..5083d37e0e0 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector.h +++ b/iocore/net/quic/QUICPacketPayloadProtector.h @@ -34,10 +34,10 @@ class QUICPacketPayloadProtector public: QUICPacketPayloadProtector(const QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {} - Ptr protect(Ptr unprotected_header, Ptr unprotected_payload, uint64_t pkt_num, - QUICKeyPhase phase) const; - Ptr unprotect(Ptr unprotected_header, Ptr protected_payload, uint64_t pkt_num, - QUICKeyPhase phase) const; + Ptr protect(const Ptr unprotected_header, const Ptr unprotected_payload, + uint64_t pkt_num, QUICKeyPhase phase) const; + Ptr unprotect(const Ptr unprotected_header, const Ptr protected_payload, + uint64_t pkt_num, QUICKeyPhase phase) const; private: const QUICPacketProtectionKeyInfo &_pp_key_info; @@ -45,7 +45,7 @@ class QUICPacketPayloadProtector bool _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 QUIC_EVP_CIPHER *aead, size_t tag_len) const; - bool _protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, Ptr plain, uint64_t pkt_num, + bool _protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const Ptr 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 QUIC_EVP_CIPHER *aead, size_t tag_len) const; diff --git a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc b/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc index dbfd69b4ec8..d33c2bda7ac 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc +++ b/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc @@ -28,7 +28,7 @@ static constexpr char tag[] = "quic_ppp"; bool -QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, Ptr plain, +QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const Ptr 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 { @@ -55,13 +55,14 @@ QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t return false; } - cipher_len = 0; - while (plain) { - if (!EVP_EncryptUpdate(aead_ctx, cipher + cipher_len, &len, reinterpret_cast(plain->buf()), plain->size())) { + cipher_len = 0; + Ptr b = plain; + while (b) { + if (!EVP_EncryptUpdate(aead_ctx, cipher + cipher_len, &len, reinterpret_cast(b->buf()), b->size())) { return false; } cipher_len += len; - plain = plain->next; + b = b->next; } if (!EVP_EncryptFinal_ex(aead_ctx, cipher + cipher_len, &len)) { From 6f409c2ef37ae8cec5b3049387c12da610b8b7ac Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 15 Mar 2019 13:52:41 +0900 Subject: [PATCH 1219/1313] Use const references instead of moving QUICPacketUPtr --- iocore/net/P_QUICNetVConnection.h | 20 +++--- iocore/net/QUICNetVConnection.cc | 68 +++++++++---------- iocore/net/quic/QUICHandshake.cc | 14 ++-- iocore/net/quic/QUICHandshake.h | 4 +- iocore/net/quic/QUICVersionNegotiator.cc | 12 ++-- iocore/net/quic/QUICVersionNegotiator.h | 2 +- .../quic/test/test_QUICVersionNegotiator.cc | 8 +-- 7 files changed, 64 insertions(+), 64 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 18c207bf012..59432ac2042 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -296,17 +296,17 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub QUICPacketUPtr _build_packet(QUICEncryptionLevel level, Ptr parent_block, bool retransmittable, bool probing, bool crypto); - QUICConnectionErrorUPtr _recv_and_ack(QUICPacket &packet, bool *has_non_probing_frame = nullptr); - - QUICConnectionErrorUPtr _state_handshake_process_packet(QUICPacketUPtr packet); - QUICConnectionErrorUPtr _state_handshake_process_version_negotiation_packet(QUICPacketUPtr packet); - QUICConnectionErrorUPtr _state_handshake_process_initial_packet(QUICPacketUPtr packet); - QUICConnectionErrorUPtr _state_handshake_process_retry_packet(QUICPacketUPtr packet); - QUICConnectionErrorUPtr _state_handshake_process_handshake_packet(QUICPacketUPtr packet); - QUICConnectionErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet); + QUICConnectionErrorUPtr _recv_and_ack(const QUICPacket &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_connection_established_receive_packet(); - QUICConnectionErrorUPtr _state_connection_established_process_protected_packet(QUICPacketUPtr packet); - QUICConnectionErrorUPtr _state_connection_established_migrate_connection(const QUICPacket &p); + QUICConnectionErrorUPtr _state_connection_established_process_protected_packet(const QUICPacket &packet); + QUICConnectionErrorUPtr _state_connection_established_migrate_connection(const QUICPacket &packet); QUICConnectionErrorUPtr _state_connection_established_initiate_connection_migration(); QUICConnectionErrorUPtr _state_closing_receive_packet(); QUICConnectionErrorUPtr _state_draining_receive_packet(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b7067f25ee7..40ef0bf0b94 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -785,7 +785,7 @@ QUICNetVConnection::state_handshake(int event, Event *data) // - It could be just an errora on lower layer error = nullptr; } else if (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::UNSUPPORTED) { - error = this->_state_handshake_process_packet(std::move(packet)); + error = this->_state_handshake_process_packet(*packet); } // if we complete handshake, switch to establish state @@ -1055,31 +1055,31 @@ QUICNetVConnection::negotiated_application_name() const } QUICConnectionErrorUPtr -QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) +QUICNetVConnection::_state_handshake_process_packet(const QUICPacket &packet) { QUICConnectionErrorUPtr error = nullptr; - switch (packet->type()) { + switch (packet.type()) { case QUICPacketType::VERSION_NEGOTIATION: - error = this->_state_handshake_process_version_negotiation_packet(std::move(packet)); + error = this->_state_handshake_process_version_negotiation_packet(packet); break; case QUICPacketType::INITIAL: - error = this->_state_handshake_process_initial_packet(std::move(packet)); + error = this->_state_handshake_process_initial_packet(packet); break; case QUICPacketType::RETRY: - error = this->_state_handshake_process_retry_packet(std::move(packet)); + error = this->_state_handshake_process_retry_packet(packet); break; case QUICPacketType::HANDSHAKE: - error = this->_state_handshake_process_handshake_packet(std::move(packet)); + error = this->_state_handshake_process_handshake_packet(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); } break; case QUICPacketType::ZERO_RTT_PROTECTED: - error = this->_state_handshake_process_zero_rtt_protected_packet(std::move(packet)); + error = this->_state_handshake_process_zero_rtt_protected_packet(packet); break; case QUICPacketType::PROTECTED: default: - QUICConDebug("Ignore %s(%" PRIu8 ") packet", QUICDebugNames::packet_type(packet->type()), static_cast(packet->type())); + QUICConDebug("Ignore %s(%" PRIu8 ") packet", QUICDebugNames::packet_type(packet.type()), static_cast(packet.type())); error = std::make_unique(QUICTransErrorCode::INTERNAL_ERROR); break; @@ -1088,11 +1088,11 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) } QUICConnectionErrorUPtr -QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPacketUPtr packet) +QUICNetVConnection::_state_handshake_process_version_negotiation_packet(const QUICPacket &packet) { QUICConnectionErrorUPtr error = nullptr; - if (packet->destination_cid() != this->connection_id()) { + if (packet.destination_cid() != this->connection_id()) { QUICConDebug("Ignore Version Negotiation packet"); return error; } @@ -1100,7 +1100,7 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack if (this->_handshake_handler->is_version_negotiated()) { QUICConDebug("ignore VN - already negotiated"); } else { - error = this->_handshake_handler->negotiate_version(packet.get(), &this->_packet_factory); + error = this->_handshake_handler->negotiate_version(packet, &this->_packet_factory); // discard all transport state except packet number for (auto s : QUIC_PN_SPACES) { @@ -1118,7 +1118,7 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPack } QUICConnectionErrorUPtr -QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packet) +QUICNetVConnection::_state_handshake_process_initial_packet(const QUICPacket &packet) { // QUIC packet could be smaller than MINIMUM_INITIAL_PACKET_SIZE when coalescing packets // if (packet->size() < MINIMUM_INITIAL_PACKET_SIZE) { @@ -1140,12 +1140,11 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe this->_frame_dispatcher->add_handler(this->_alt_con_manager); } QUICTPConfigQCP tp_config(this->_quic_config, NET_VCONNECTION_IN); - error = - this->_handshake_handler->start(tp_config, packet.get(), &this->_packet_factory, this->_alt_con_manager->preferred_address()); + 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); + error = this->_recv_and_ack(packet); if (error == nullptr && !this->_handshake_handler->has_remote_tp()) { error = std::make_unique(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR); @@ -1153,7 +1152,7 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe } } else { // on client side, _handshake_handler is already started. Just process packet like _state_handshake_process_handshake_packet() - error = this->_recv_and_ack(*packet); + error = this->_recv_and_ack(packet); } return error; @@ -1163,7 +1162,7 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe This doesn't call this->_recv_and_ack(), because RETRY packet doesn't have any frames. */ QUICConnectionErrorUPtr -QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) +QUICNetVConnection::_state_handshake_process_retry_packet(const QUICPacket &packet) { ink_assert(this->netvc_context == NET_VCONNECTION_OUT); @@ -1173,9 +1172,9 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) } // TODO: move packet->payload to _av_token - this->_av_token_len = packet->payload_length(); + this->_av_token_len = packet.payload_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.payload(), this->_av_token_len); // discard all transport state this->_handshake_handler->reset(); @@ -1198,32 +1197,32 @@ QUICNetVConnection::_state_handshake_process_retry_packet(QUICPacketUPtr packet) } QUICConnectionErrorUPtr -QUICNetVConnection::_state_handshake_process_handshake_packet(QUICPacketUPtr packet) +QUICNetVConnection::_state_handshake_process_handshake_packet(const QUICPacket &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(); } - return this->_recv_and_ack(*packet); + return this->_recv_and_ack(packet); } QUICConnectionErrorUPtr -QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet) +QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(const QUICPacket &packet) { this->_stream_manager->init_flow_control_params(this->_handshake_handler->local_transport_parameters(), this->_handshake_handler->remote_transport_parameters()); this->_start_application(); - return this->_recv_and_ack(*packet); + return this->_recv_and_ack(packet); } QUICConnectionErrorUPtr -QUICNetVConnection::_state_connection_established_process_protected_packet(QUICPacketUPtr packet) +QUICNetVConnection::_state_connection_established_process_protected_packet(const QUICPacket &packet) { QUICConnectionErrorUPtr error = nullptr; bool has_non_probing_frame = false; - error = this->_recv_and_ack(*packet, &has_non_probing_frame); + error = this->_recv_and_ack(packet, &has_non_probing_frame); if (error != nullptr) { return error; } @@ -1234,11 +1233,11 @@ QUICNetVConnection::_state_connection_established_process_protected_packet(QUICP // on the old path until they initiate migration. // if (packet.destination_cid() == this->_quic_connection_id && has_non_probing_frame) { 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 (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"); } - error = this->_state_connection_established_migrate_connection(*packet); + error = this->_state_connection_established_migrate_connection(packet); if (error != nullptr) { return error; } @@ -1262,7 +1261,7 @@ QUICNetVConnection::_state_connection_established_receive_packet() // Receive a QUIC packet net_activity(this, this_ethread()); do { - QUICPacketUPtr p = this->_dequeue_recv_packet(result); + QUICPacketUPtr packet = this->_dequeue_recv_packet(result); if (result == QUICPacketCreationResult::FAILED) { // Don't make this error, and discard the packet. // Because: @@ -1278,18 +1277,19 @@ QUICNetVConnection::_state_connection_established_receive_packet() } // Process the packet - switch (p->type()) { + switch (packet->type()) { case QUICPacketType::PROTECTED: - error = this->_state_connection_established_process_protected_packet(std::move(p)); + error = this->_state_connection_established_process_protected_packet(*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(*p); + error = this->_recv_and_ack(*packet); break; default: - QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(p->type()), static_cast(p->type())); + QUICConDebug("Unknown packet type: %s(%" PRIu8 ")", QUICDebugNames::packet_type(packet->type()), + static_cast(packet->type())); error = std::make_unique(QUICTransErrorCode::INTERNAL_ERROR); break; @@ -1652,7 +1652,7 @@ QUICNetVConnection::_packetize_closing_frame() } QUICConnectionErrorUPtr -QUICNetVConnection::_recv_and_ack(QUICPacket &packet, bool *has_non_probing_frame) +QUICNetVConnection::_recv_and_ack(const QUICPacket &packet, bool *has_non_probing_frame) { ink_assert(packet.type() != QUICPacketType::RETRY); diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index 475112c03b3..ca8d1204057 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -119,18 +119,18 @@ 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 QUICPacket &initial_packet, QUICPacketFactory *packet_factory, const QUICPreferredAddress *pref_addr) { // Negotiate version if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED) { - if (initial_packet->type() != QUICPacketType::INITIAL) { + if (initial_packet.type() != QUICPacketType::INITIAL) { return std::make_unique(QUICTransErrorCode::PROTOCOL_VIOLATION); } - if (initial_packet->version()) { + if (initial_packet.version()) { if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { - QUICHSDebug("Version negotiation succeeded: %x", initial_packet->version()); - this->_load_local_server_transport_parameters(tp_config, initial_packet->version(), pref_addr); + QUICHSDebug("Version negotiation succeeded: %x", initial_packet.version()); + this->_load_local_server_transport_parameters(tp_config, initial_packet.version(), pref_addr); packet_factory->set_version(this->_version_negotiator->negotiated_version()); } else { ink_assert(!"Unsupported version initial packet should be droped QUICPakcetHandler"); @@ -143,7 +143,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 QUICPacket &vn, QUICPacketFactory *packet_factory) { // Client side only ink_assert(this->_qc->direction() == NET_VCONNECTION_OUT); @@ -155,7 +155,7 @@ QUICHandshake::negotiate_version(const QUICPacket *vn, QUICPacketFactory *packet return nullptr; } - if (vn->version() != 0x00) { + if (vn.version() != 0x00) { QUICHSDebug("Version field must be 0x00000000"); return std::make_unique(QUICTransErrorCode::PROTOCOL_VIOLATION); } diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 0cdb94d7736..5ce46b9bc48 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -57,11 +57,11 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator // 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 QUICPacket &packet, QUICPacketFactory *packet_factory); void reset(); // for server side - QUICConnectionErrorUPtr start(const QUICTPConfig &tp_config, const QUICPacket *initial_packet, QUICPacketFactory *packet_factory, + QUICConnectionErrorUPtr start(const QUICTPConfig &tp_config, const QUICPacket &initial_packet, QUICPacketFactory *packet_factory, const QUICPreferredAddress *pref_addr); QUICConnectionErrorUPtr do_handshake(); diff --git a/iocore/net/quic/QUICVersionNegotiator.cc b/iocore/net/quic/QUICVersionNegotiator.cc index f325fd05fb7..677c134e3d6 100644 --- a/iocore/net/quic/QUICVersionNegotiator.cc +++ b/iocore/net/quic/QUICVersionNegotiator.cc @@ -31,20 +31,20 @@ QUICVersionNegotiator::status() } QUICVersionNegotiationStatus -QUICVersionNegotiator::negotiate(const QUICPacket *packet) +QUICVersionNegotiator::negotiate(const QUICPacket &packet) { - switch (packet->type()) { + switch (packet.type()) { case QUICPacketType::INITIAL: { - if (QUICTypeUtil::is_supported_version(packet->version())) { + if (QUICTypeUtil::is_supported_version(packet.version())) { this->_status = QUICVersionNegotiationStatus::NEGOTIATED; - this->_negotiated_version = packet->version(); + this->_negotiated_version = packet.version(); } break; } case QUICPacketType::VERSION_NEGOTIATION: { - const uint8_t *supported_versions = packet->payload(); - uint16_t supported_versions_len = packet->payload_length(); + const uint8_t *supported_versions = packet.payload(); + uint16_t supported_versions_len = packet.payload_length(); uint16_t len = 0; while (len < supported_versions_len) { diff --git a/iocore/net/quic/QUICVersionNegotiator.h b/iocore/net/quic/QUICVersionNegotiator.h index c59d59e90b4..a931e05f63d 100644 --- a/iocore/net/quic/QUICVersionNegotiator.h +++ b/iocore/net/quic/QUICVersionNegotiator.h @@ -35,7 +35,7 @@ class QUICVersionNegotiator { public: QUICVersionNegotiationStatus status(); - QUICVersionNegotiationStatus negotiate(const QUICPacket *initial_packet); + QUICVersionNegotiationStatus negotiate(const QUICPacket &initial_packet); QUICVersionNegotiationStatus validate(const QUICTransportParametersInClientHello *tp); QUICVersionNegotiationStatus validate(const QUICTransportParametersInEncryptedExtensions *tp); QUICVersion negotiated_version(); diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 9a1b9c8b660..174d50c08c6 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -44,7 +44,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true); - vn.negotiate(initial_packet.get()); + vn.negotiate(*initial_packet); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); // Validate version @@ -63,7 +63,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true); - vn.negotiate(initial_packet.get()); + vn.negotiate(*initial_packet); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); // Validate version @@ -82,7 +82,7 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") packet_factory.set_version(QUIC_EXERCISE_VERSION); QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true); - vn.negotiate(initial_packet.get()); + vn.negotiate(*initial_packet); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); // Validate version @@ -132,7 +132,7 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") packet_factory.create_version_negotiation_packet(initial_packet->source_cid(), initial_packet->destination_cid()); // Negotiate version - vn.negotiate(vn_packet.get()); + vn.negotiate(*vn_packet); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); From 150adcce36456a3f0f8feaf8708fdb55e839f0b9 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 18 Mar 2019 11:00:43 +0900 Subject: [PATCH 1220/1313] Don't create packets on encryption levels already done --- iocore/net/P_QUICNetVConnection.h | 2 ++ iocore/net/QUICNetVConnection.cc | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 59432ac2042..68266bac3f9 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -284,6 +284,8 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _unschedule_ack_manager_periodic(); Event *_ack_manager_periodic = nullptr; + QUICEncryptionLevel _minimum_encryption_level = QUICEncryptionLevel::INITIAL; + QUICPacketNumber _largest_acked_packet_number(QUICEncryptionLevel level) const; uint32_t _maximum_quic_packet_size() const; uint32_t _minimum_quic_packet_size(); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 40ef0bf0b94..0106c75509b 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1072,6 +1072,7 @@ QUICNetVConnection::_state_handshake_process_packet(const QUICPacket &packet) error = this->_state_handshake_process_handshake_packet(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: @@ -1370,7 +1371,8 @@ QUICNetVConnection::_state_common_send_packet() udp_payload->alloc(iobuffer_size_to_index(udp_payload_len)); uint32_t written = 0; - for (auto level : QUIC_ENCRYPTION_LEVELS) { + for (int i = static_cast(this->_minimum_encryption_level); i <= static_cast(QUICEncryptionLevel::ONE_RTT); ++i) { + auto level = QUIC_ENCRYPTION_LEVELS[i]; if (level == QUICEncryptionLevel::ONE_RTT && !this->_handshake_handler->is_completed()) { continue; } @@ -1417,6 +1419,7 @@ QUICNetVConnection::_state_common_send_packet() if (this->_pp_key_info.is_encryption_key_available(QUICKeyPhase::INITIAL) && packet->type() == QUICPacketType::HANDSHAKE && this->netvc_context == NET_VCONNECTION_OUT) { this->_pp_key_info.drop_keys(QUICKeyPhase::INITIAL); + this->_minimum_encryption_level = QUICEncryptionLevel::HANDSHAKE; } int index = QUICTypeUtil::pn_space_index(level); @@ -2317,8 +2320,8 @@ QUICNetVConnection::_handle_periodic_ack_event() { ink_hrtime timestamp = Thread::get_hrtime(); bool need_schedule = false; - for (auto level : QUIC_ENCRYPTION_LEVELS) { - if (this->_ack_frame_manager.will_generate_frame(level, timestamp)) { + for (int i = static_cast(this->_minimum_encryption_level); i <= static_cast(QUICEncryptionLevel::ONE_RTT); ++i) { + if (this->_ack_frame_manager.will_generate_frame(QUIC_ENCRYPTION_LEVELS[i], timestamp)) { need_schedule = true; break; } From c9b1db22c01da93d258b38b434246d9c40dc7fb3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 25 Mar 2019 10:49:47 +0900 Subject: [PATCH 1221/1313] Check fist byte to make sure key is derived --- iocore/net/quic/QUICPacketPayloadProtector.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICPacketPayloadProtector.cc b/iocore/net/quic/QUICPacketPayloadProtector.cc index d0b9eb53c7a..f79e2efabe4 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector.cc +++ b/iocore/net/quic/QUICPacketPayloadProtector.cc @@ -38,7 +38,7 @@ QUICPacketPayloadProtector::protect(const Ptr unprotected_header, const uint8_t *key = this->_pp_key_info.encryption_key(phase); const uint8_t *iv = this->_pp_key_info.encryption_iv(phase); size_t iv_len = *this->_pp_key_info.encryption_iv_len(phase); - if (!key) { + if (!key || key[0] == 0x00) { Debug(tag, "Failed to encrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return protected_payload; } @@ -52,7 +52,7 @@ QUICPacketPayloadProtector::protect(const Ptr unprotected_header, if (!this->_protect(reinterpret_cast(protected_payload->start()), written_len, protected_payload->write_avail(), unprotected_payload, pkt_num, reinterpret_cast(unprotected_header->buf()), unprotected_header->size(), key, iv, iv_len, aead, tag_len)) { - Debug(tag, "Failed to encrypt a packet #%" PRIu64, pkt_num); + Debug(tag, "Failed to encrypt a packet #%" PRIu64 " with keys for %s", pkt_num, QUICDebugNames::key_phase(phase)); protected_payload = nullptr; } else { protected_payload->fill(written_len); From f53f6e52f99f0032dfc972b74d3b5c530f66e3d5 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 25 Mar 2019 10:50:19 +0900 Subject: [PATCH 1222/1313] Fix adding Padding Frame --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 38 +++++++++++++++++++------------ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 68266bac3f9..fc86bc872d1 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -295,6 +295,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub std::vector &frames); QUICPacketUPtr _packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size, std::vector &frames); void _packetize_closing_frame(); + Ptr _generate_padding_frame(size_t frame_size); QUICPacketUPtr _build_packet(QUICEncryptionLevel level, Ptr parent_block, bool retransmittable, bool probing, bool crypto); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 0106c75509b..a06c2bd63ba 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -58,13 +58,14 @@ static constexpr std::string_view QUIC_DEBUG_TAG = "quic_net"sv; static constexpr uint32_t IPV4_HEADER_SIZE = 20; static constexpr uint32_t IPV6_HEADER_SIZE = 40; static constexpr uint32_t UDP_HEADER_SIZE = 8; -static constexpr uint32_t MAX_PACKET_OVERHEAD = 62; // Max long header len without length of token field of Initial packet +static constexpr uint32_t MAX_PACKET_OVERHEAD = 62; ///< Max long header len without length of token field of Initial packet static constexpr uint32_t MINIMUM_INITIAL_PACKET_SIZE = 1200; static constexpr ink_hrtime WRITE_READY_INTERVAL = HRTIME_MSECONDS(2); static constexpr uint32_t PACKET_PER_EVENT = 256; -static constexpr uint32_t MAX_CONSECUTIVE_STREAMS = 8; //< Interrupt sending STREAM frames to send ACK frame +static constexpr uint32_t MAX_CONSECUTIVE_STREAMS = 8; ///< Interrupt sending STREAM frames to send ACK frame +static constexpr uint32_t MIN_PKT_PAYLOAD_LEN = 3; ///< Minimum payload length for sampling for header protection -static constexpr uint32_t STATE_CLOSING_MAX_SEND_PKT_NUM = 8; // Max number of sending packets which contain a closing frame. +static constexpr uint32_t STATE_CLOSING_MAX_SEND_PKT_NUM = 8; ///< Max number of sending packets which contain a closing frame. static constexpr uint32_t STATE_CLOSING_MAX_RECV_PKT_WIND = 1 << STATE_CLOSING_MAX_SEND_PKT_NUM; ClassAllocator quicNetVCAllocator("quicNetVCAllocator"); @@ -1501,6 +1502,20 @@ QUICNetVConnection::_store_frame(Ptr parent_block, size_t &size_a return parent_block; } +// FIXME QUICNetVConnection should not know the actual type value of PADDING frame +Ptr +QUICNetVConnection::_generate_padding_frame(size_t frame_size) +{ + Ptr block = make_ptr(new_IOBufferBlock()); + block->alloc(iobuffer_size_to_index(frame_size)); + memset(block->start(), 0, frame_size); + block->fill(frame_size); + + ink_assert(frame_size == static_cast(block->size())); + + return block; +} + QUICPacketUPtr QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_packet_size, std::vector &frames) { @@ -1599,22 +1614,15 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa min_size = std::min(min_size, max_packet_size); if (min_size > len) { - // FIXME QUICNetVConnection should not know the actual type value of PADDING frame - Ptr pad_block = make_ptr(new_IOBufferBlock()); - pad_block->alloc(iobuffer_size_to_index(min_size - len)); - memset(pad_block->start(), 0, pad_block->size()); - last_block->next = pad_block; + Ptr pad_block = _generate_padding_frame(min_size - len); + last_block->next = pad_block; len += pad_block->size(); } } else { // Pad with PADDING frames to make sure payload length satisfy the minimum length for sampling for header protection - if (3 > len) { - // FIXME QUICNetVConnection should not know the actual type value of PADDING frame - Ptr pad_block = make_ptr(new_IOBufferBlock()); - ; - pad_block->alloc(iobuffer_size_to_index(3 - len)); - memset(pad_block->start(), 0, pad_block->size()); - last_block->next = pad_block; + if (MIN_PKT_PAYLOAD_LEN > len) { + Ptr pad_block = _generate_padding_frame(MIN_PKT_PAYLOAD_LEN - len); + last_block->next = pad_block; len += pad_block->size(); } } From 2df6d5c7dca88649ab3c999b138e145441f0c457 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 26 Mar 2019 11:15:45 +0900 Subject: [PATCH 1223/1313] Fix QPACK::_encode_prefix() Prior this change, the allocated IOBufferData for Header Block Prefix was not initialized. This made random value in S and Delta Base (7+) fields in Header Block Prefix. --- proxy/http3/QPACK.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/proxy/http3/QPACK.cc b/proxy/http3/QPACK.cc index bd8f51dc698..a2d205409ac 100644 --- a/proxy/http3/QPACK.cc +++ b/proxy/http3/QPACK.cc @@ -297,15 +297,17 @@ QPACK::_encode_prefix(uint16_t largest_reference, uint16_t base_index, IOBufferB prefix->fill(ret); uint16_t delta; + prefix->end()[0] = 0x0; if (base_index < largest_reference) { prefix->end()[0] |= 0x80; delta = largest_reference - base_index; } else { delta = base_index - largest_reference; } + if ((ret = xpack_encode_integer(reinterpret_cast(prefix->end()), reinterpret_cast(prefix->end() + prefix->write_avail()), delta, 7)) < 0) { - return -1; + return -2; } prefix->fill(ret); @@ -872,11 +874,12 @@ QPACK::_decode_header(const uint8_t *header_block, size_t header_block_len, HTTP uint64_t delta_base_index; uint16_t base_index; if ((ret = xpack_decode_integer(delta_base_index, pos, pos + remain_len, 7)) < 0 && delta_base_index < 0xFFFF) { - return -1; + return -2; } + if (pos[0] & 0x80) { if (delta_base_index == 0) { - return -1; + return -3; } base_index = largest_reference - delta_base_index; } else { @@ -923,8 +926,10 @@ QPACK::_decode(EThread *ethread, Continuation *cont, uint64_t stream_id, const u HTTPHdr &hdr) { int event; - if (this->_decode_header(header_block, header_block_len, hdr) < 0) { + int res = this->_decode_header(header_block, header_block_len, hdr); + if (res < 0) { event = QPACK_EVENT_DECODE_FAILED; + QPACKDebug("decoding header failed (%d)", res); } else { event = QPACK_EVENT_DECODE_COMPLETE; this->_write_header_acknowledgement(stream_id); From 788e27e4389261bca6a2deb4af4ac1f15aedfff9 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 1 Apr 2019 15:35:45 +0900 Subject: [PATCH 1224/1313] Add debug_msg on QUICRstStreamFrame --- iocore/net/quic/QUICFrame.cc | 7 +++++++ iocore/net/quic/QUICFrame.h | 1 + 2 files changed, 8 insertions(+) diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index f0046231560..5b11035ee3e 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -1040,6 +1040,13 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len, size_t limit) const return *len; } +int +QUICRstStreamFrame::debug_msg(char *msg, size_t msg_len) const +{ + return snprintf(msg, msg_len, "| RESET_STREAM size=%zu stream_id=%" PRIu64 " code=0x%" PRIx16, this->size(), this->stream_id(), + this->error_code()); +} + QUICStreamId QUICRstStreamFrame::stream_id() const { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 08f77bffd43..e9e63ee321a 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -291,6 +291,7 @@ class QUICRstStreamFrame : public QUICFrame virtual QUICFrameType type() const override; virtual size_t size() const override; virtual size_t store(uint8_t *buf, size_t *len, 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) override; QUICStreamId stream_id() const; From 51c65a85cc290db14e79034be0b83b26c7ea0407 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 3 Apr 2019 15:35:52 +0900 Subject: [PATCH 1225/1313] Fix setting NUM_PLACEHOLDERS --- proxy/http3/Http3App.cc | 11 +++++++---- proxy/http3/Http3App.h | 3 ++- proxy/http3/test/test_Http3Frame.cc | 21 +++++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 7b34fa2ef59..8b53cbd2168 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -46,7 +46,7 @@ Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QU this->_settings_handler = new Http3SettingsHandler(this->_client_session); this->_control_stream_dispatcher.add_handler(this->_settings_handler); - this->_settings_framer = new Http3SettingsFramer(); + this->_settings_framer = new Http3SettingsFramer(client_vc->get_context()); this->_control_stream_collector.add_generator(this->_settings_framer); SET_HANDLER(&Http3App::main_event_handler); @@ -343,15 +343,18 @@ Http3SettingsFramer::generate_frame(uint16_t max_size) } if (params->max_header_list_size() != HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE) { - frame->set(Http3SettingsId::NUM_PLACEHOLDERS, params->max_header_list_size()); + frame->set(Http3SettingsId::MAX_HEADER_LIST_SIZE, params->max_header_list_size()); } if (params->qpack_blocked_streams() != HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS) { frame->set(Http3SettingsId::QPACK_BLOCKED_STREAMS, params->qpack_blocked_streams()); } - if (params->num_placeholders() != HTTP3_DEFAULT_NUM_PLACEHOLDERS) { - frame->set(Http3SettingsId::NUM_PLACEHOLDERS, params->num_placeholders()); + // Server side only + if (this->_context == NET_VCONNECTION_IN) { + if (params->num_placeholders() != HTTP3_DEFAULT_NUM_PLACEHOLDERS) { + frame->set(Http3SettingsId::NUM_PLACEHOLDERS, params->num_placeholders()); + } } return Http3SettingsFrameUPtr(frame, &Http3FrameDeleter::delete_settings_frame); diff --git a/proxy/http3/Http3App.h b/proxy/http3/Http3App.h index 959ad2e037f..87d2f26647f 100644 --- a/proxy/http3/Http3App.h +++ b/proxy/http3/Http3App.h @@ -91,13 +91,14 @@ class Http3SettingsHandler : public Http3FrameHandler class Http3SettingsFramer : public Http3FrameGenerator { public: - Http3SettingsFramer(){}; + Http3SettingsFramer(NetVConnectionContext_t context) : _context(context) {}; // Http3FrameGenerator Http3FrameUPtr generate_frame(uint16_t max_size) override; bool is_done() const override; private: + NetVConnectionContext_t _context; bool _is_done = false; ///< Becarefull when set FIN flag on CONTROL stream. Maybe never? bool _is_sent = false; ///< Send SETTINGS frame only once }; diff --git a/proxy/http3/test/test_Http3Frame.cc b/proxy/http3/test/test_Http3Frame.cc index 321b62ece3d..48f02aec2c3 100644 --- a/proxy/http3/test/test_Http3Frame.cc +++ b/proxy/http3/test/test_Http3Frame.cc @@ -173,6 +173,27 @@ TEST_CASE("Store SETTINGS Frame", "[http3]") CHECK(len == sizeof(expected)); CHECK(memcmp(buf, expected, len) == 0); } + + SECTION("Normal from Client") + { + uint8_t expected[] = { + 0x07, // Length + 0x04, // Type + 0x00, 0x06, // Identifier + 0x44, 0x00, // Value + 0x0a, 0x0a, // Identifier + 0x00, // Value + }; + + Http3SettingsFrame settings_frame; + settings_frame.set(Http3SettingsId::MAX_HEADER_LIST_SIZE, 0x0400); + + uint8_t buf[32] = {0}; + size_t len; + settings_frame.store(buf, &len); + CHECK(len == sizeof(expected)); + CHECK(memcmp(buf, expected, len) == 0); + } } TEST_CASE("Http3FrameFactory Create Unknown Frame", "[http3]") From 42349cfd459dc57b236180c153abb2351c0e1a59 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 4 Apr 2019 10:53:30 +0900 Subject: [PATCH 1226/1313] Send NEW_TOKEN frame from server side only --- iocore/net/QUICNetVConnection.cc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a06c2bd63ba..548ca36fc9f 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -2384,15 +2384,17 @@ QUICNetVConnection::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint return frame; } - // TODO Make expiration period configurable - QUICResumptionToken token(this->get_remote_endpoint(), this->connection_id(), Thread::get_hrtime() + HRTIME_HOURS(24)); - frame = QUICFrameFactory::create_new_token_frame(buf, token, this->_issue_frame_id(), this); - if (frame) { - if (frame->size() < maximum_frame_size) { - this->_is_resumption_token_sent = true; - } else { - // Cancel generating frame - frame = nullptr; + if (this->direction() == NET_VCONNECTION_IN) { + // TODO Make expiration period configurable + QUICResumptionToken token(this->get_remote_endpoint(), this->connection_id(), Thread::get_hrtime() + HRTIME_HOURS(24)); + frame = QUICFrameFactory::create_new_token_frame(buf, token, this->_issue_frame_id(), this); + if (frame) { + if (frame->size() < maximum_frame_size) { + this->_is_resumption_token_sent = true; + } else { + // Cancel generating frame + frame = nullptr; + } } } From 22ef4573bfca24cf17459e5364d901b1cc91ed51 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 4 Apr 2019 14:04:08 +0900 Subject: [PATCH 1227/1313] Fix QUICDebugNames::key_phase() --- iocore/net/quic/QUICDebugNames.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 0b06e5b9fda..47e5e1b51d3 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -286,9 +286,9 @@ QUICDebugNames::key_phase(QUICKeyPhase phase) case QUICKeyPhase::PHASE_1: return "PHASE_1"; case QUICKeyPhase::INITIAL: - return "CLEARTEXT"; + return "INITIAL"; case QUICKeyPhase::ZERO_RTT: - return "ZERORTT"; + return "ZERO_RTT"; case QUICKeyPhase::HANDSHAKE: return "HANDSHAKE"; default: From 70397c521d33ffcaa52b70f11ee56907d74b22d2 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 8 Apr 2019 11:58:17 +0900 Subject: [PATCH 1228/1313] Cleanup frame debug msg --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICFrame.cc | 26 +++++++++++++------------- iocore/net/quic/QUICFrameDispatcher.cc | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 548ca36fc9f..1e2517156b3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1491,7 +1491,7 @@ QUICNetVConnection::_store_frame(Ptr parent_block, size_t &size_a if (is_debug_tag_set(QUIC_DEBUG_TAG.data())) { char msg[1024]; frame.debug_msg(msg, sizeof(msg)); - QUICConDebug("[TX] %s", msg); + QUICConDebug("[TX] | %s", msg); } frames.emplace_back(frame.id(), frame.generated_by()); diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index 5b11035ee3e..b585460b5ef 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -124,7 +124,7 @@ QUICFrame::to_io_buffer_block(size_t limit) const int QUICFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| %s size=%zu", QUICDebugNames::frame_type(this->type()), this->size()); + return snprintf(msg, msg_len, "%s size=%zu", QUICDebugNames::frame_type(this->type()), this->size()); } bool @@ -270,7 +270,7 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, size_t limit) const int QUICStreamFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| STREAM size=%zu id=%" PRIu64 " offset=%" PRIu64 " data_len=%" PRIu64 " fin=%d", this->size(), + return snprintf(msg, msg_len, "STREAM size=%zu id=%" PRIu64 " offset=%" PRIu64 " data_len=%" PRIu64 " fin=%d", this->size(), this->stream_id(), this->offset(), this->data_length(), this->has_fin_flag()); } @@ -461,7 +461,7 @@ QUICCryptoFrame::size() const int QUICCryptoFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| CRYPTO size=%zu offset=%" PRIu64 " data_len=%" PRIu64, this->size(), this->offset(), + return snprintf(msg, msg_len, "CRYPTO size=%zu offset=%" PRIu64 " data_len=%" PRIu64, this->size(), this->offset(), this->data_length()); } @@ -675,7 +675,7 @@ QUICAckFrame::store(uint8_t *buf, size_t *len, size_t limit) const int QUICAckFrame::debug_msg(char *msg, size_t msg_len) const { - int len = snprintf(msg, msg_len, "| ACK size=%zu largest_acked=%" PRIu64 " delay=%" PRIu64 " block_count=%" PRIu64, this->size(), + int len = snprintf(msg, msg_len, "ACK size=%zu largest_acked=%" PRIu64 " delay=%" PRIu64 " block_count=%" PRIu64, this->size(), this->largest_acknowledged(), this->ack_delay(), this->ack_block_count()); msg_len -= len; @@ -1043,7 +1043,7 @@ QUICRstStreamFrame::store(uint8_t *buf, size_t *len, size_t limit) const int QUICRstStreamFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| RESET_STREAM size=%zu stream_id=%" PRIu64 " code=0x%" PRIx16, this->size(), this->stream_id(), + return snprintf(msg, msg_len, "RESET_STREAM size=%zu stream_id=%" PRIu64 " code=0x%" PRIx16, this->size(), this->stream_id(), this->error_code()); } @@ -1313,11 +1313,11 @@ QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const int len; if (this->_type == 0x1c) { len = - snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=%s (0x%" PRIx16 ") frame=%s", this->size(), + snprintf(msg, msg_len, "CONNECTION_CLOSE size=%zu code=%s (0x%" PRIx16 ") frame=%s", this->size(), QUICDebugNames::error_code(this->error_code()), this->error_code(), QUICDebugNames::frame_type(this->frame_type())); } else { // Application-specific error. It doesn't have a frame type and we don't know string representations of error codes. - len = snprintf(msg, msg_len, "| CONNECTION_CLOSE size=%zu code=0x%" PRIx16 " ", this->size(), this->error_code()); + len = snprintf(msg, msg_len, "CONNECTION_CLOSE size=%zu code=0x%" PRIx16 " ", this->size(), this->error_code()); } if (this->reason_phrase_length() != 0 && this->reason_phrase() != nullptr) { @@ -1435,7 +1435,7 @@ QUICMaxDataFrame::store(uint8_t *buf, size_t *len, size_t limit) const int QUICMaxDataFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| MAX_DATA size=%zu maximum=%" PRIu64, this->size(), this->maximum_data()); + return snprintf(msg, msg_len, "MAX_DATA size=%zu maximum=%" PRIu64, this->size(), this->maximum_data()); } uint64_t @@ -1530,7 +1530,7 @@ QUICMaxStreamDataFrame::store(uint8_t *buf, size_t *len, size_t limit) const int QUICMaxStreamDataFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| MAX_STREAM_DATA size=%zu id=%" PRIu64 " maximum=%" PRIu64, this->size(), this->stream_id(), + return snprintf(msg, msg_len, "MAX_STREAM_DATA size=%zu id=%" PRIu64 " maximum=%" PRIu64, this->size(), this->stream_id(), this->maximum_stream_data()); } @@ -1665,7 +1665,7 @@ QUICDataBlockedFrame::parse(const uint8_t *buf, size_t len) int QUICDataBlockedFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| DATA_BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset()); + return snprintf(msg, msg_len, "DATA_BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset()); } QUICFrameType @@ -1753,7 +1753,7 @@ QUICStreamDataBlockedFrame::parse(const uint8_t *buf, size_t len) int QUICStreamDataBlockedFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| STREAM_DATA_BLOCKED size=%zu id=%" PRIu64 " offset=%" PRIu64, this->size(), this->stream_id(), + return snprintf(msg, msg_len, "STREAM_DATA_BLOCKED size=%zu id=%" PRIu64 " offset=%" PRIu64, this->size(), this->stream_id(), this->offset()); } @@ -1983,7 +1983,7 @@ 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 " cid=0x%s", this->size(), this->sequence(), cid_str); + return snprintf(msg, msg_len, "NEW_CONNECTION_ID size=%zu seq=%" PRIu64 " cid=0x%s", this->size(), this->sequence(), cid_str); } uint64_t @@ -2422,7 +2422,7 @@ QUICRetireConnectionIdFrame::store(uint8_t *buf, size_t *len, size_t limit) cons int QUICRetireConnectionIdFrame::debug_msg(char *msg, size_t msg_len) const { - return snprintf(msg, msg_len, "| RETIRE_CONNECTION_ID size=%zu seq_num=%" PRIu64, this->size(), this->seq_num()); + return snprintf(msg, msg_len, "RETIRE_CONNECTION_ID size=%zu seq_num=%" PRIu64, this->size(), this->seq_num()); } uint64_t diff --git a/iocore/net/quic/QUICFrameDispatcher.cc b/iocore/net/quic/QUICFrameDispatcher.cc index 990cdea6a16..c2f3d1f7757 100644 --- a/iocore/net/quic/QUICFrameDispatcher.cc +++ b/iocore/net/quic/QUICFrameDispatcher.cc @@ -70,7 +70,7 @@ QUICFrameDispatcher::receive_frames(QUICEncryptionLevel level, const uint8_t *pa if (is_debug_tag_set(tag) && type != QUICFrameType::PADDING) { char msg[1024]; frame.debug_msg(msg, sizeof(msg)); - QUICDebug("[RX] %s", msg); + QUICDebug("[RX] | %s", msg); } if (type != QUICFrameType::PADDING && type != QUICFrameType::ACK) { From 83bc8289e3de15bc3bb036d2a103ddc21b4f7d6a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 8 Apr 2019 14:36:22 +0900 Subject: [PATCH 1229/1313] Fix test_QUICLossDetector --- iocore/net/quic/QUICPacketPayloadProtector.cc | 9 +++++---- iocore/net/quic/QUICPacketProtectionKeyInfo.cc | 1 - iocore/net/quic/test/test_QUICKeyGenerator.cc | 1 - iocore/net/quic/test/test_QUICLossDetector.cc | 3 +++ 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/iocore/net/quic/QUICPacketPayloadProtector.cc b/iocore/net/quic/QUICPacketPayloadProtector.cc index f79e2efabe4..35c44b51b4a 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector.cc +++ b/iocore/net/quic/QUICPacketPayloadProtector.cc @@ -34,14 +34,15 @@ QUICPacketPayloadProtector::protect(const Ptr unprotected_header, Ptr protected_payload; protected_payload = nullptr; + if (!this->_pp_key_info.is_encryption_key_available(phase)) { + Debug(tag, "Failed to encrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); + return protected_payload; + } + size_t tag_len = this->_pp_key_info.get_tag_len(phase); const uint8_t *key = this->_pp_key_info.encryption_key(phase); const uint8_t *iv = this->_pp_key_info.encryption_iv(phase); size_t iv_len = *this->_pp_key_info.encryption_iv_len(phase); - if (!key || key[0] == 0x00) { - Debug(tag, "Failed to encrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); - return protected_payload; - } const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher(phase); diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.cc b/iocore/net/quic/QUICPacketProtectionKeyInfo.cc index f782d357be2..2f791cb2c03 100644 --- a/iocore/net/quic/QUICPacketProtectionKeyInfo.cc +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.cc @@ -91,7 +91,6 @@ QUICPacketProtectionKeyInfo::set_encryption_key_available(QUICKeyPhase phase) this->_is_server_key_available[index] = true; } else { this->_is_client_key_available[index] = true; - ; } } diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc index dc152a297c1..e24d3dbb711 100644 --- a/iocore/net/quic/test/test_QUICKeyGenerator.cc +++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc @@ -46,7 +46,6 @@ TEST_CASE("draft-17 Test Vectors", "[quic]") uint8_t expected_client_key[] = { 0x86, 0xd1, 0x83, 0x04, 0x80, 0xb4, 0x0f, 0x86, 0xcf, 0x9d, 0x68, 0xdc, 0xad, 0xf3, 0x5d, 0xfe, - }; uint8_t expected_client_iv[] = { 0x12, 0xf3, 0x93, 0x8a, 0xca, 0x34, 0xaa, 0x02, 0x54, 0x31, 0x63, 0xd4, diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 096c7f4817f..c0c2b29cbcb 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -31,6 +31,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") { MockQUICPacketProtectionKeyInfo pp_key_info; + pp_key_info.set_encryption_key_available(QUICKeyPhase::PHASE_0); + QUICPacketFactory pf(pp_key_info); QUICRTTMeasure rtt_measure; @@ -96,6 +98,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); + REQUIRE(packet1 != nullptr); payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet2 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); From 2d2b4a32cbbc53c209cb29b105bd6dd02bf6feb8 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 8 Apr 2019 14:58:47 +0900 Subject: [PATCH 1230/1313] Fix test_QUICPacketFactory & test_QUICVersionNegotiator --- iocore/net/quic/test/test_QUICPacketFactory.cc | 9 ++++++++- iocore/net/quic/test/test_QUICVersionNegotiator.cc | 12 ++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index c93870a5590..ba2c1f0871f 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -37,8 +37,9 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") QUICConnectionId scid(raw_scid, 8); QUICPacketUPtr vn_packet = factory.create_version_negotiation_packet(scid, dcid); - CHECK(vn_packet->type() == QUICPacketType::VERSION_NEGOTIATION); + REQUIRE(vn_packet != nullptr); + CHECK(vn_packet->type() == QUICPacketType::VERSION_NEGOTIATION); CHECK(vn_packet->destination_cid() == scid); CHECK(vn_packet->source_cid() == dcid); CHECK(vn_packet->version() == 0x00); @@ -75,6 +76,8 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") factory.create_retry_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), QUICConnectionId(reinterpret_cast("\x04\x03\x02\x01"), 4), token); + + REQUIRE(packet != nullptr); CHECK(packet->type() == QUICPacketType::RETRY); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) == 0); @@ -85,6 +88,7 @@ TEST_CASE("QUICPacketFactory_Create_Retry", "[quic]") TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") { MockQUICPacketProtectionKeyInfo pp_key_info; + pp_key_info.set_encryption_key_available(QUICKeyPhase::HANDSHAKE); QUICPacketFactory factory(pp_key_info); factory.set_version(0x11223344); @@ -96,6 +100,7 @@ TEST_CASE("QUICPacketFactory_Create_Handshake", "[quic]") factory.create_handshake_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), QUICConnectionId(reinterpret_cast("\x11\x12\x13\x14"), 4), 0, std::move(payload), sizeof(raw), true, false, true); + REQUIRE(packet != nullptr); CHECK(packet->type() == QUICPacketType::HANDSHAKE); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); CHECK(memcmp(packet->payload(), raw, sizeof(raw)) != 0); @@ -111,6 +116,8 @@ TEST_CASE("QUICPacketFactory_Create_StatelessResetPacket", "[quic]") QUICPacketUPtr packet = factory.create_stateless_reset_packet(QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4), token); + + REQUIRE(packet != nullptr); CHECK(packet->type() == QUICPacketType::STATELESS_RESET); CHECK((packet->destination_cid() == QUICConnectionId(reinterpret_cast("\x01\x02\x03\x04"), 4))); } diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 174d50c08c6..59d3796da5a 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -30,6 +30,8 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") { MockQUICPacketProtectionKeyInfo pp_key_info; + pp_key_info.set_encryption_key_available(QUICKeyPhase::INITIAL); + QUICPacketFactory packet_factory(pp_key_info); QUICVersionNegotiator vn; ats_unique_buf dummy_payload = ats_unique_malloc(128); @@ -44,6 +46,8 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true); + + REQUIRE(initial_packet != nullptr); vn.negotiate(*initial_packet); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -63,6 +67,8 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") packet_factory.set_version(QUIC_SUPPORTED_VERSIONS[0]); QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true); + + REQUIRE(initial_packet != nullptr); vn.negotiate(*initial_packet); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); @@ -82,6 +88,8 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") packet_factory.set_version(QUIC_EXERCISE_VERSION); QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true); + + REQUIRE(initial_packet != nullptr); vn.negotiate(*initial_packet); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); @@ -96,6 +104,8 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") { MockQUICPacketProtectionKeyInfo pp_key_info; + pp_key_info.set_encryption_key_available(QUICKeyPhase::INITIAL); + QUICPacketFactory packet_factory(pp_key_info); QUICVersionNegotiator vn; ats_unique_buf dummy_payload = ats_unique_malloc(128); @@ -126,10 +136,12 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") packet_factory.set_version(QUIC_EXERCISE_VERSION); QUICPacketUPtr initial_packet = packet_factory.create_initial_packet({}, {}, 0, std::move(dummy_payload), dummy_payload_len, true, false, true); + REQUIRE(initial_packet != nullptr); // Server send VN packet based on Initial packet QUICPacketUPtr vn_packet = packet_factory.create_version_negotiation_packet(initial_packet->source_cid(), initial_packet->destination_cid()); + REQUIRE(vn_packet != nullptr); // Negotiate version vn.negotiate(*vn_packet); From 41c06df698844c80d2dd146b8ce5fb7cc5853c91 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 5 Apr 2019 10:12:57 +0900 Subject: [PATCH 1231/1313] Add HTTP/3 support to traffic_quic cmd --- iocore/net/I_NetVConnection.h | 6 + iocore/net/QUICNetVConnection.cc | 3 +- iocore/net/quic/QUICConfig.cc | 13 +- iocore/net/quic/QUICTLS.h | 2 +- iocore/net/quic/QUICTLS_openssl.cc | 5 +- proxy/http2/HTTP2.cc | 8 + proxy/http3/Http3App.cc | 59 ++++--- proxy/http3/Http3App.h | 16 +- proxy/http3/Http3ClientTransaction.cc | 60 ++++--- proxy/http3/Http3ClientTransaction.h | 3 +- proxy/http3/Http3HeaderFramer.cc | 52 ++---- proxy/http3/Http3HeaderVIOAdaptor.cc | 7 +- src/traffic_quic/Makefile.inc | 66 +++---- src/traffic_quic/quic_client.cc | 237 ++++++++++++++++++++------ src/traffic_quic/quic_client.h | 47 ++++- src/traffic_quic/traffic_quic.cc | 105 +++++++++++- 16 files changed, 489 insertions(+), 200 deletions(-) diff --git a/iocore/net/I_NetVConnection.h b/iocore/net/I_NetVConnection.h index 786c7afe708..1dedc0da7f7 100644 --- a/iocore/net/I_NetVConnection.h +++ b/iocore/net/I_NetVConnection.h @@ -179,6 +179,10 @@ struct NetVCOptions { EventType etype; + /** ALPN protocol-lists. The format is OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings) + https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html + */ + std::string_view alpn_protos; /** Server name to use for SNI data on an outbound connection. */ ats_scoped_str sni_servername; @@ -224,6 +228,7 @@ struct NetVCOptions { NetVCOptions() { reset(); } ~NetVCOptions() {} + /** Set the SNI server name. A local copy is made of @a name. */ @@ -240,6 +245,7 @@ struct NetVCOptions { } return *this; } + self & set_ssl_servername(const char *name) { diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 1e2517156b3..bcc581d103c 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -2236,7 +2236,8 @@ QUICNetVConnection::_setup_handshake_protocol(SSL_CTX *ctx) { // Initialize handshake protocol specific stuff // For QUICv1 TLS is the only option - QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx, this->direction(), this->_quic_config->session_file()); + QUICTLS *tls = + new QUICTLS(this->_pp_key_info, ctx, this->direction(), this->options, this->_quic_config->session_file()); SSL_set_ex_data(tls->ssl_handle(), QUIC::ssl_quic_qc_index, static_cast(this)); return tls; } diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 139df1a4d6c..4314caa0964 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -35,11 +35,6 @@ #define QUICConfDebug(fmt, ...) Debug("quic_conf", fmt, ##__VA_ARGS__) -// OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings) -// https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html -// Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? -using namespace std::literals; -static constexpr std::string_view QUIC_ALPN_PROTO_LIST("\5hq-18"sv); int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; @@ -74,16 +69,14 @@ quic_new_ssl_ctx() return ssl_ctx; } +/** + ALPN and SNI should be set to SSL object with NETVC_OPTIONS + **/ static SSL_CTX * quic_init_client_ssl_ctx(const QUICConfigParams *params) { SSL_CTX *ssl_ctx = quic_new_ssl_ctx(); - if (SSL_CTX_set_alpn_protos(ssl_ctx, reinterpret_cast(QUIC_ALPN_PROTO_LIST.data()), - QUIC_ALPN_PROTO_LIST.size()) != 0) { - Error("SSL_CTX_set_alpn_protos failed"); - } - if (params->client_supported_groups() != nullptr) { if (SSL_CTX_set1_groups_list(ssl_ctx, params->client_supported_groups()) != 1) { Error("SSL_CTX_set1_groups_list failed"); diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 5e8d13d984c..5a2ac563ba0 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -40,7 +40,7 @@ class QUICTLS : public QUICHandshakeProtocol { public: QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx, - const char *session_file = nullptr); + const NetVCOptions &netvc_options, const char *session_file = nullptr); ~QUICTLS(); // TODO: integrate with _early_data_processed diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index d9951fe7b59..d6d98420f07 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -329,13 +329,16 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t } QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx, - const char *session_file) + const NetVCOptions &netvc_options, const char *session_file) : QUICHandshakeProtocol(pp_key_info), _session_file(session_file), _ssl(SSL_new(ssl_ctx)), _netvc_context(nvc_ctx) { ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); if (this->_netvc_context == NET_VCONNECTION_OUT) { SSL_set_connect_state(this->_ssl); + + SSL_set_alpn_protos(this->_ssl, reinterpret_cast(netvc_options.alpn_protos.data()), netvc_options.alpn_protos.size()); + SSL_set_tlsext_host_name(this->_ssl, netvc_options.sni_servername.get()); } else { SSL_set_accept_state(this->_ssl); } diff --git a/proxy/http2/HTTP2.cc b/proxy/http2/HTTP2.cc index e1a0a4e62e8..b5c1e81b873 100644 --- a/proxy/http2/HTTP2.cc +++ b/proxy/http2/HTTP2.cc @@ -477,6 +477,11 @@ http2_convert_header_from_2_to_1_1(HTTPHdr *headers) headers->field_delete(HTTP2_VALUE_AUTHORITY, HTTP2_LEN_AUTHORITY); headers->field_delete(HTTP2_VALUE_PATH, HTTP2_LEN_PATH); } else { + // Set HTTP Version 1.1 + int32_t version = HTTP_VERSION(1, 1); + http_hdr_version_set(headers->m_http, version); + + // Set status from :status int status_len; const char *status; @@ -521,6 +526,9 @@ http2_generate_h2_header_from_1_1(HTTPHdr *headers, HTTPHdr *h2_headers) int value_len; // Add ':authority' header field + // TODO: remove host/Host header + // [RFC 7540] 8.1.2.3. Clients that generate HTTP/2 requests directly SHOULD use the ":authority" pseudo-header field instead of + // the Host header field. field = h2_headers->field_create(HTTP2_VALUE_AUTHORITY, HTTP2_LEN_AUTHORITY); value = headers->host_get(&value_len); if (headers->is_port_in_header()) { diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 8b53cbd2168..1174e39f7f6 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -37,13 +37,13 @@ static constexpr char debug_tag_v[] = "v_http3"; Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QUICApplication(client_vc) { - this->_client_session = new Http3ClientSession(client_vc); - this->_client_session->acl = std::move(session_acl); - this->_client_session->new_connection(client_vc, nullptr, nullptr); + this->_ssn = new Http3ClientSession(client_vc); + this->_ssn->acl = std::move(session_acl); + this->_ssn->new_connection(client_vc, nullptr, nullptr); this->_qc->stream_manager()->set_default_application(this); - this->_settings_handler = new Http3SettingsHandler(this->_client_session); + this->_settings_handler = new Http3SettingsHandler(this->_ssn); this->_control_stream_dispatcher.add_handler(this->_settings_handler); this->_settings_framer = new Http3SettingsFramer(client_vc->get_context()); @@ -54,7 +54,7 @@ Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QU Http3App::~Http3App() { - delete this->_client_session; + delete this->_ssn; delete this->_settings_handler; delete this->_settings_framer; } @@ -71,15 +71,16 @@ Http3App::start() this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_local_control_stream); } - error = this->create_uni_stream(stream_id, Http3StreamType::QPACK_ENCODER); - if (error == nullptr) { - this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_find_stream_io(stream_id)); - } + // TODO: Open uni streams for QPACK when dynamic table is used + // error = this->create_uni_stream(stream_id, Http3StreamType::QPACK_ENCODER); + // if (error == nullptr) { + // this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_find_stream_io(stream_id)); + // } - error = this->create_uni_stream(stream_id, Http3StreamType::QPACK_DECODER); - if (error == nullptr) { - this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_find_stream_io(stream_id)); - } + // error = this->create_uni_stream(stream_id, Http3StreamType::QPACK_DECODER); + // if (error == nullptr) { + // this->_handle_uni_stream_on_write_ready(VC_EVENT_WRITE_READY, this->_find_stream_io(stream_id)); + // } } int @@ -113,6 +114,12 @@ Http3App::main_event_handler(int event, Event *data) } break; case VC_EVENT_EOS: + if (stream_io->is_bidirectional()) { + this->_handle_bidi_stream_on_eos(event, stream_io); + } else { + this->_handle_uni_stream_on_eos(event, stream_io); + } + break; case VC_EVENT_ERROR: case VC_EVENT_INACTIVITY_TIMEOUT: case VC_EVENT_ACTIVE_TIMEOUT: @@ -196,10 +203,10 @@ Http3App::_handle_bidi_stream_on_read_ready(int event, QUICStreamIO *stream_io) uint8_t dummy; if (stream_io->peek(&dummy, 1)) { QUICStreamId stream_id = stream_io->stream_id(); - Http3ClientTransaction *txn = static_cast(this->_client_session->get_transaction(stream_id)); + Http3ClientTransaction *txn = static_cast(this->_ssn->get_transaction(stream_id)); if (txn == nullptr) { - txn = new Http3ClientTransaction(this->_client_session, stream_io); + txn = new Http3ClientTransaction(this->_ssn, stream_io); SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); txn->new_transaction(); @@ -236,21 +243,33 @@ Http3App::_handle_uni_stream_on_write_ready(int /* event */, QUICStreamIO *strea } } +void +Http3App::_handle_bidi_stream_on_eos(int /* event */, QUICStreamIO *stream_io) +{ + // TODO: handle eos +} + +void +Http3App::_handle_uni_stream_on_eos(int /* event */, QUICStreamIO *stream_io) +{ + // TODO: handle eos +} + void Http3App::_set_qpack_stream(Http3StreamType type, QUICStreamIO *stream_io) { // Change app to QPACK from Http3 if (type == Http3StreamType::QPACK_ENCODER) { if (this->_qc->direction() == NET_VCONNECTION_IN) { - this->_client_session->remote_qpack()->set_encoder_stream(stream_io); + this->_ssn->remote_qpack()->set_encoder_stream(stream_io); } else { - this->_client_session->local_qpack()->set_encoder_stream(stream_io); + this->_ssn->local_qpack()->set_encoder_stream(stream_io); } } else if (type == Http3StreamType::QPACK_DECODER) { if (this->_qc->direction() == NET_VCONNECTION_IN) { - this->_client_session->local_qpack()->set_decoder_stream(stream_io); + this->_ssn->local_qpack()->set_decoder_stream(stream_io); } else { - this->_client_session->remote_qpack()->set_decoder_stream(stream_io); + this->_ssn->remote_qpack()->set_decoder_stream(stream_io); } } else { ink_abort("unkown stream type"); @@ -261,7 +280,7 @@ void Http3App::_handle_bidi_stream_on_write_ready(int event, QUICStreamIO *stream_io) { QUICStreamId stream_id = stream_io->stream_id(); - Http3ClientTransaction *txn = static_cast(this->_client_session->get_transaction(stream_id)); + Http3ClientTransaction *txn = static_cast(this->_ssn->get_transaction(stream_id)); if (txn != nullptr) { SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); txn->handleEvent(event); diff --git a/proxy/http3/Http3App.h b/proxy/http3/Http3App.h index 87d2f26647f..e4a31c0c2a3 100644 --- a/proxy/http3/Http3App.h +++ b/proxy/http3/Http3App.h @@ -44,23 +44,29 @@ class Http3App : public QUICApplication { public: Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl); - ~Http3App(); + virtual ~Http3App(); - void start(); - int main_event_handler(int event, Event *data); + virtual void start(); + virtual int main_event_handler(int event, Event *data); // TODO: Return StreamIO. It looks bother that coller have to look up StreamIO by stream id. // Why not create_bidi_stream ? QUICConnectionErrorUPtr create_uni_stream(QUICStreamId &new_stream_id, Http3StreamType type); +protected: + // TODO: create Http3Session + Http3ClientSession *_ssn = nullptr; + private: void _handle_uni_stream_on_read_ready(int event, QUICStreamIO *stream_io); - void _handle_bidi_stream_on_read_ready(int event, QUICStreamIO *stream_io); void _handle_uni_stream_on_write_ready(int event, QUICStreamIO *stream_io); + void _handle_uni_stream_on_eos(int event, QUICStreamIO *stream_io); + void _handle_bidi_stream_on_read_ready(int event, QUICStreamIO *stream_io); void _handle_bidi_stream_on_write_ready(int event, QUICStreamIO *stream_io); + void _handle_bidi_stream_on_eos(int event, QUICStreamIO *stream_io); + void _set_qpack_stream(Http3StreamType type, QUICStreamIO *stream_io); - Http3ClientSession *_client_session = nullptr; Http3FrameHandler *_settings_handler = nullptr; Http3FrameGenerator *_settings_framer = nullptr; diff --git a/proxy/http3/Http3ClientTransaction.cc b/proxy/http3/Http3ClientTransaction.cc index 228621b020d..42467c0fdcf 100644 --- a/proxy/http3/Http3ClientTransaction.cc +++ b/proxy/http3/Http3ClientTransaction.cc @@ -64,12 +64,20 @@ HQClientTransaction::HQClientTransaction(HQClientSession *session, QUICStreamIO this->set_parent(session); this->sm_reader = this->_read_vio_buf.alloc_reader(); - this->_request_header.create(HTTP_TYPE_REQUEST); + + HTTPType http_type = HTTP_TYPE_UNKNOWN; + if (this->direction() == NET_VCONNECTION_OUT) { + http_type = HTTP_TYPE_RESPONSE; + } else { + http_type = HTTP_TYPE_REQUEST; + } + + this->_header.create(http_type); } HQClientTransaction::~HQClientTransaction() { - this->_request_header.destroy(); + this->_header.destroy(); } void @@ -236,6 +244,12 @@ HQClientTransaction::decrement_client_transactions_stat() // TODO } +NetVConnectionContext_t +HQClientTransaction::direction() const +{ + return this->parent->get_netvc()->get_context(); +} + /** * @brief Replace existing event only if the new event is different than the inprogress event */ @@ -311,7 +325,7 @@ Http3ClientTransaction::Http3ClientTransaction(Http3ClientSession *session, QUIC this->_frame_collector.add_generator(this->_data_framer); // this->_frame_collector.add_generator(this->_push_controller); - this->_header_handler = new Http3HeaderVIOAdaptor(&this->_request_header, session->remote_qpack(), this, stream_io->stream_id()); + this->_header_handler = new Http3HeaderVIOAdaptor(&this->_header, session->remote_qpack(), this, stream_io->stream_id()); this->_data_handler = new Http3StreamDataVIOAdaptor(&this->_read_vio); this->_frame_dispatcher.add_handler(this->_header_handler); @@ -332,8 +346,6 @@ int Http3ClientTransaction::state_stream_open(int event, void *edata) { // TODO: should check recursive call? - Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); - if (this->_thread != this_ethread()) { // Send on to the owning thread if (this->_cross_thread_event == nullptr) { @@ -352,6 +364,7 @@ Http3ClientTransaction::state_stream_open(int event, void *edata) switch (event) { case VC_EVENT_READ_READY: case VC_EVENT_READ_COMPLETE: { + Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); int64_t len = this->_process_read_vio(); // if no progress, don't need to signal if (len > 0) { @@ -363,7 +376,9 @@ Http3ClientTransaction::state_stream_open(int event, void *edata) } case VC_EVENT_WRITE_READY: case VC_EVENT_WRITE_COMPLETE: { + Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); int64_t len = this->_process_write_vio(); + // if no progress, don't need to signal if (len > 0) { this->_signal_write_event(); } @@ -379,6 +394,7 @@ Http3ClientTransaction::state_stream_open(int event, void *edata) break; } case QPACK_EVENT_DECODE_COMPLETE: { + Http3TransVDebug("%s (%d)", "QPACK_EVENT_DECODE_COMPLETE", event); int res = this->_on_qpack_decode_complete(); if (res) { // If READ_READY event is scheduled, should it be canceled? @@ -387,6 +403,7 @@ Http3ClientTransaction::state_stream_open(int event, void *edata) break; } case QPACK_EVENT_DECODE_FAILED: { + Http3TransVDebug("%s (%d)", "QPACK_EVENT_DECODE_FAILED", event); // FIXME: handle error break; } @@ -506,20 +523,22 @@ Http3ClientTransaction::_convert_header_from_3_to_1_1(HTTPHdr *hdrs) { // TODO: do HTTP/3 specific convert, if there - // Dirty hack to bypass checks - MIMEField *field; - if ((field = hdrs->field_find(HTTP3_VALUE_SCHEME, HTTP3_LEN_SCHEME)) == nullptr) { - char value_s[] = "https"; - MIMEField *scheme_field = hdrs->field_create(HTTP3_VALUE_SCHEME, HTTP3_LEN_SCHEME); - scheme_field->value_set(hdrs->m_heap, hdrs->m_mime, value_s, sizeof(value_s) - 1); - hdrs->field_attach(scheme_field); - } + if (http_hdr_type_get(hdrs->m_http) == HTTP_TYPE_REQUEST) { + // Dirty hack to bypass checks + MIMEField *field; + if ((field = hdrs->field_find(HTTP3_VALUE_SCHEME, HTTP3_LEN_SCHEME)) == nullptr) { + char value_s[] = "https"; + MIMEField *scheme_field = hdrs->field_create(HTTP3_VALUE_SCHEME, HTTP3_LEN_SCHEME); + scheme_field->value_set(hdrs->m_heap, hdrs->m_mime, value_s, sizeof(value_s) - 1); + hdrs->field_attach(scheme_field); + } - if ((field = hdrs->field_find(HTTP3_VALUE_AUTHORITY, HTTP3_LEN_AUTHORITY)) == nullptr) { - char value_a[] = "localhost"; - MIMEField *authority_field = hdrs->field_create(HTTP3_VALUE_AUTHORITY, HTTP3_LEN_AUTHORITY); - authority_field->value_set(hdrs->m_heap, hdrs->m_mime, value_a, sizeof(value_a) - 1); - hdrs->field_attach(authority_field); + if ((field = hdrs->field_find(HTTP3_VALUE_AUTHORITY, HTTP3_LEN_AUTHORITY)) == nullptr) { + char value_a[] = "localhost"; + MIMEField *authority_field = hdrs->field_create(HTTP3_VALUE_AUTHORITY, HTTP3_LEN_AUTHORITY); + authority_field->value_set(hdrs->m_heap, hdrs->m_mime, value_a, sizeof(value_a) - 1); + hdrs->field_attach(authority_field); + } } return http2_convert_header_from_2_to_1_1(hdrs); @@ -528,8 +547,9 @@ Http3ClientTransaction::_convert_header_from_3_to_1_1(HTTPHdr *hdrs) int Http3ClientTransaction::_on_qpack_decode_complete() { - ParseResult res = this->_convert_header_from_3_to_1_1(&this->_request_header); + ParseResult res = this->_convert_header_from_3_to_1_1(&this->_header); if (res == PARSE_RESULT_ERROR) { + Http3TransDebug("PARSE_RESULT_ERROR"); return -1; } @@ -554,7 +574,7 @@ Http3ClientTransaction::_on_qpack_decode_complete() writer->add_block(); block = writer->get_current_block(); } - done = this->_request_header.print(block->start(), block->write_avail(), &bufindex, &tmp); + done = this->_header.print(block->end(), block->write_avail(), &bufindex, &tmp); dumpoffset += bufindex; writer->fill(bufindex); if (!done) { diff --git a/proxy/http3/Http3ClientTransaction.h b/proxy/http3/Http3ClientTransaction.h index 2d166635ef3..a6fe36b9cff 100644 --- a/proxy/http3/Http3ClientTransaction.h +++ b/proxy/http3/Http3ClientTransaction.h @@ -66,6 +66,7 @@ class HQClientTransaction : public ProxyClientTransaction // HQClientTransaction virtual int state_stream_open(int, void *) = 0; virtual int state_stream_closed(int event, void *data) = 0; + NetVConnectionContext_t direction() const; protected: virtual int64_t _process_read_vio() = 0; @@ -85,7 +86,7 @@ class HQClientTransaction : public ProxyClientTransaction Event *_read_event = nullptr; Event *_write_event = nullptr; - HTTPHdr _request_header; + HTTPHdr _header; ///< HTTP header buffer for decoding }; class Http3ClientTransaction : public HQClientTransaction diff --git a/proxy/http3/Http3HeaderFramer.cc b/proxy/http3/Http3HeaderFramer.cc index 6bda091473b..1d493f5848a 100644 --- a/proxy/http3/Http3HeaderFramer.cc +++ b/proxy/http3/Http3HeaderFramer.cc @@ -70,60 +70,31 @@ Http3HeaderFramer::is_done() const return this->_sent_all_data; } -const char *HTTP3_VALUE_STATUS = ":status"; -const unsigned HTTP3_LEN_STATUS = countof(":status") - 1; -static size_t HTTP3_LEN_STATUS_VALUE_STR = 3; - -// Copy code from http2_generate_h2_header_from_1_1(h1_hdrs, h3_hdrs); void Http3HeaderFramer::_convert_header_from_1_1_to_3(HTTPHdr *h3_hdrs, HTTPHdr *h1_hdrs) { - // Add ':status' header field - char status_str[HTTP3_LEN_STATUS_VALUE_STR + 1]; - snprintf(status_str, sizeof(status_str), "%d", h1_hdrs->status_get()); - MIMEField *status_field = h3_hdrs->field_create(HTTP3_VALUE_STATUS, HTTP3_LEN_STATUS); - status_field->value_set(h3_hdrs->m_heap, h3_hdrs->m_mime, status_str, HTTP3_LEN_STATUS_VALUE_STR); - h3_hdrs->field_attach(status_field); - - // Copy headers - // Intermediaries SHOULD remove connection-specific header fields. - MIMEFieldIter field_iter; - for (MIMEField *field = h1_hdrs->iter_get_first(&field_iter); field != nullptr; field = h1_hdrs->iter_get_next(&field_iter)) { - const char *name; - int name_len; - const char *value; - int value_len; - name = field->name_get(&name_len); - if ((name_len == MIME_LEN_CONNECTION && strncasecmp(name, MIME_FIELD_CONNECTION, name_len) == 0) || - (name_len == MIME_LEN_KEEP_ALIVE && strncasecmp(name, MIME_FIELD_KEEP_ALIVE, name_len) == 0) || - (name_len == MIME_LEN_PROXY_CONNECTION && strncasecmp(name, MIME_FIELD_PROXY_CONNECTION, name_len) == 0) || - (name_len == MIME_LEN_TRANSFER_ENCODING && strncasecmp(name, MIME_FIELD_TRANSFER_ENCODING, name_len) == 0) || - (name_len == MIME_LEN_UPGRADE && strncasecmp(name, MIME_FIELD_UPGRADE, name_len) == 0)) { - continue; - } - MIMEField *newfield; - name = field->name_get(&name_len); - newfield = h3_hdrs->field_create(name, name_len); - value = field->value_get(&value_len); - newfield->value_set(h3_hdrs->m_heap, h3_hdrs->m_mime, value, value_len); - h3_hdrs->field_attach(newfield); - } + http2_generate_h2_header_from_1_1(h1_hdrs, h3_hdrs); } void Http3HeaderFramer::_generate_header_block() { // Prase response header and generate header block - int bytes_used = 0; - // TODO Use HTTP_TYPE_REQUEST if this is for requests - this->_header.create(HTTP_TYPE_RESPONSE); - int parse_result = this->_header.parse_resp(&this->_http_parser, this->_source_vio->get_reader(), &bytes_used, false); + int bytes_used = 0; + ParseResult parse_result = PARSE_RESULT_ERROR; + + if (this->_transaction->direction() == NET_VCONNECTION_OUT) { + this->_header.create(HTTP_TYPE_REQUEST); + parse_result = this->_header.parse_req(&this->_http_parser, this->_source_vio->get_reader(), &bytes_used, false); + } else { + this->_header.create(HTTP_TYPE_RESPONSE); + parse_result = this->_header.parse_resp(&this->_http_parser, this->_source_vio->get_reader(), &bytes_used, false); + } this->_source_vio->ndone += this->_header.length_get(); switch (parse_result) { case PARSE_RESULT_DONE: { HTTPHdr h3_hdr; - h3_hdr.create(HTTP_TYPE_RESPONSE); this->_convert_header_from_1_1_to_3(&h3_hdr, &this->_header); this->_header_block = new_MIOBuffer(); @@ -135,6 +106,7 @@ Http3HeaderFramer::_generate_header_block() case PARSE_RESULT_CONT: break; default: + Debug("http3_trans", "Ignore ivalid headers"); break; } } diff --git a/proxy/http3/Http3HeaderVIOAdaptor.cc b/proxy/http3/Http3HeaderVIOAdaptor.cc index c2e4414151c..6a55ae7a6e3 100644 --- a/proxy/http3/Http3HeaderVIOAdaptor.cc +++ b/proxy/http3/Http3HeaderVIOAdaptor.cc @@ -49,11 +49,12 @@ Http3HeaderVIOAdaptor::handle_frame(std::shared_ptr frame) if (res == 0) { // When decoding is not blocked, continuation should be called directly? } else if (res == 1) { - // Decoding is blocked. Callback will be fired. + // Decoding is blocked. + Debug("http3", "Decoding is blocked. DecodeRequest is scheduled"); } else if (res < 0) { - // error + Debug("http3", "Error on decoding header (%d)", res); } else { - // should not be here + ink_abort("should not be here"); } return Http3ErrorUPtr(new Http3NoError()); diff --git a/src/traffic_quic/Makefile.inc b/src/traffic_quic/Makefile.inc index b9291dbd516..18b466fae4e 100644 --- a/src/traffic_quic/Makefile.inc +++ b/src/traffic_quic/Makefile.inc @@ -19,39 +19,45 @@ bin_PROGRAMS += traffic_quic/traffic_quic traffic_quic_traffic_quic_CPPFLAGS = \ $(AM_CPPFLAGS) \ - $(iocore_include_dirs) \ - -I$(abs_top_srcdir)/lib \ - -I$(abs_top_srcdir)/lib/records \ - -I$(abs_top_srcdir)/mgmt \ - -I$(abs_top_srcdir)/mgmt/utils \ - -I$(abs_top_srcdir)/proxy \ - -I$(abs_top_srcdir)/proxy/hdrs \ - -I$(abs_top_srcdir)/proxy/http \ - -I$(abs_top_srcdir)/proxy/logging \ - -I$(abs_top_srcdir)/proxy/shared \ - $(TS_INCLUDES) \ - @OPENSSL_INCLUDES@ + $(iocore_include_dirs) \ + -I$(abs_top_srcdir)/lib \ + -I$(abs_top_srcdir)/lib/records \ + -I$(abs_top_srcdir)/mgmt \ + -I$(abs_top_srcdir)/mgmt/utils \ + -I$(abs_top_srcdir)/proxy \ + -I$(abs_top_srcdir)/proxy/hdrs \ + -I$(abs_top_srcdir)/proxy/http \ + -I$(abs_top_srcdir)/proxy/http/remap \ + -I$(abs_top_srcdir)/proxy/http3 \ + -I$(abs_top_srcdir)/proxy/logging \ + -I$(abs_top_srcdir)/proxy/shared \ + $(TS_INCLUDES) \ + @OPENSSL_INCLUDES@ traffic_quic_traffic_quic_LDFLAGS = \ - $(AM_LDFLAGS) \ - @OPENSSL_LDFLAGS@ + $(AM_LDFLAGS) \ + @OPENSSL_LDFLAGS@ traffic_quic_traffic_quic_SOURCES = \ - traffic_quic/quic_client.cc \ - traffic_quic/traffic_quic.cc + traffic_quic/quic_client.cc \ + traffic_quic/traffic_quic.cc traffic_quic_traffic_quic_LDADD = \ - $(top_builddir)/iocore/net/libinknet.a \ - $(top_builddir)/iocore/aio/libinkaio.a \ - $(top_builddir)/iocore/net/quic/libquic.a \ - $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ - $(top_builddir)/lib/records/librecords_p.a \ - $(top_builddir)/src/tscore/libtscore.la \ - $(top_builddir)/src/tscpp/util/libtscpputil.la \ - $(top_builddir)/lib/tsconfig/libtsconfig.la \ - $(top_builddir)/proxy/ParentSelectionStrategy.o \ - @HWLOC_LIBS@ \ - @YAMLCPP_LIBS@ \ - @OPENSSL_LIBS@ \ - @LIBPCRE@ + $(top_builddir)/iocore/net/libinknet.a \ + $(top_builddir)/iocore/aio/libinkaio.a \ + $(top_builddir)/iocore/net/quic/libquic.a \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/src/tscore/libtscore.la \ + $(top_builddir)/src/tscpp/util/libtscpputil.la \ + $(top_builddir)/lib/tsconfig/libtsconfig.la \ + $(top_builddir)/proxy/ParentSelectionStrategy.o \ + $(top_builddir)/proxy/libproxy.a \ + $(top_builddir)/proxy/hdrs/libhdrs.a \ + $(top_builddir)/proxy/http2/libhttp2.a \ + $(top_builddir)/proxy/http3/libhttp3.a \ + @HWLOC_LIBS@ \ + @YAMLCPP_LIBS@ \ + @OPENSSL_LIBS@ \ + @LIBPCRE@ diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc index d2eb7e0dd17..47560fc6d8a 100644 --- a/src/traffic_quic/quic_client.cc +++ b/src/traffic_quic/quic_client.cc @@ -25,6 +25,17 @@ #include #include +#include + +#include "Http3ClientSession.h" +#include "Http3ClientTransaction.h" + +// OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings) +// https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html +// Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? +using namespace std::literals; +static constexpr std::string_view HQ_ALPN_PROTO_LIST("\5hq-18"sv); +static constexpr std::string_view H3_ALPN_PROTO_LIST("\5h3-18"sv); QUICClient::QUICClient(const QUICClientConfig *config) : Continuation(new_ProxyMutex()), _config(config) { @@ -55,6 +66,13 @@ QUICClient::start(int, void *) return EVENT_DONE; } + std::string_view alpn_protos; + if (this->_config->http3) { + alpn_protos = H3_ALPN_PROTO_LIST; + } else { + alpn_protos = HQ_ALPN_PROTO_LIST; + } + for (struct addrinfo *info = this->_remote_addr_info; info != nullptr; info = info->ai_next) { NetVCOptions opt; opt.ip_proto = NetVCOptions::USE_UDP; @@ -62,6 +80,8 @@ QUICClient::start(int, void *) opt.etype = ET_NET; opt.socket_recv_bufsize = 1048576; opt.socket_send_bufsize = 1048576; + opt.alpn_protos = alpn_protos; + opt.set_sni_servername(this->_config->addr, strnlen(this->_config->addr, 1023)); SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread()); @@ -83,8 +103,19 @@ QUICClient::state_http_server_open(int event, void *data) Debug("quic_client", "start proxy server ssn/txn"); QUICNetVConnection *conn = static_cast(data); - QUICClientApp *app = new QUICClientApp(conn, this->_config); - app->start(this->_config->path); + + if (this->_config->http0_9) { + Http09ClientApp *app = new Http09ClientApp(conn, this->_config); + app->start(); + } else if (this->_config->http3) { + // TODO: see what server session is doing with IpAllow::ACL + IpAllow::ACL session_acl; + Http3ClientApp *app = new Http3ClientApp(conn, std::move(session_acl), this->_config); + SCOPED_MUTEX_LOCK(lock, app->mutex, this_ethread()); + app->start(); + } else { + ink_abort("invalid config"); + } break; } @@ -104,20 +135,20 @@ QUICClient::state_http_server_open(int event, void *data) } // -// QUICClientApp +// Http09ClientApp // -#define QUICClientAppDebug(fmt, ...) Debug("quic_client_app", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) -#define QUICClientAppVDebug(fmt, ...) Debug("v_quic_client_app", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) +#define Http09ClientAppDebug(fmt, ...) Debug("quic_client_app", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) +#define Http09ClientAppVDebug(fmt, ...) Debug("v_quic_client_app", "[%s] " fmt, this->_qc->cids().data(), ##__VA_ARGS__) -QUICClientApp::QUICClientApp(QUICNetVConnection *qvc, const QUICClientConfig *config) : QUICApplication(qvc), _config(config) +Http09ClientApp::Http09ClientApp(QUICNetVConnection *qvc, const QUICClientConfig *config) : QUICApplication(qvc), _config(config) { this->_qc->stream_manager()->set_default_application(this); - SET_HANDLER(&QUICClientApp::main_event_handler); + SET_HANDLER(&Http09ClientApp::main_event_handler); } void -QUICClientApp::start(const char *path) +Http09ClientApp::start() { if (this->_config->output[0] != 0x0) { this->_filename = this->_config->output; @@ -128,15 +159,11 @@ QUICClientApp::start(const char *path) std::ofstream f_stream(this->_filename, std::ios::binary | std::ios::trunc); } - if (this->_config->http3) { - this->_start_http_3_session(path); - } else { - this->_start_http_09_session(path); - } + this->_do_http_request(); } void -QUICClientApp::_start_http_09_session(const char *path) +Http09ClientApp::_do_http_request() { QUICStreamId stream_id; QUICConnectionErrorUPtr error = this->_qc->stream_manager()->create_bidi_stream(stream_id); @@ -148,44 +175,9 @@ QUICClientApp::_start_http_09_session(const char *path) // TODO: move to transaction char request[1024] = {0}; - int request_len = snprintf(request, sizeof(request), "GET %s\r\n", path); - - QUICClientAppDebug("\n%s", request); - - QUICStreamIO *stream_io = this->_find_stream_io(stream_id); - - stream_io->write(reinterpret_cast(request), request_len); - stream_io->write_done(); - stream_io->write_reenable(); -} - -void -QUICClientApp::_start_http_3_session(const char *path) -{ - QUICConnectionErrorUPtr error; - - QUICStreamId settings_stream_id; - error = this->_qc->stream_manager()->create_uni_stream(settings_stream_id); - - if (error != nullptr) { - Error("%s", error->msg); - ink_abort("Could not create uni stream : %s", error->msg); - } - // TODO: send settings frame - - QUICStreamId stream_id; - error = this->_qc->stream_manager()->create_bidi_stream(stream_id); - - if (error != nullptr) { - Error("%s", error->msg); - ink_abort("Could not create bidi stream : %s", error->msg); - } - - // TODO: move to transaction - char request[1024] = {0}; - int request_len = snprintf(request, sizeof(request), "GET %s\r\n", path); + int request_len = snprintf(request, sizeof(request), "GET %s\r\n", this->_config->path); - QUICClientAppDebug("\n%s", request); + Http09ClientAppDebug("\n%s", request); QUICStreamIO *stream_io = this->_find_stream_io(stream_id); @@ -195,15 +187,15 @@ QUICClientApp::_start_http_3_session(const char *path) } int -QUICClientApp::main_event_handler(int event, Event *data) +Http09ClientApp::main_event_handler(int event, Event *data) { - QUICClientAppVDebug("%s (%d)", get_vc_event_name(event), event); + Http09ClientAppVDebug("%s (%d)", get_vc_event_name(event), event); VIO *vio = reinterpret_cast(data); QUICStreamIO *stream_io = this->_find_stream_io(vio); if (stream_io == nullptr) { - QUICClientAppDebug("Unknown Stream"); + Http09ClientAppDebug("Unknown Stream"); return -1; } @@ -253,3 +245,140 @@ QUICClientApp::main_event_handler(int event, Event *data) return EVENT_CONT; } + +// +// Http3ClientApp +// +Http3ClientApp::Http3ClientApp(QUICNetVConnection *qvc, IpAllow::ACL session_acl, const QUICClientConfig *config) + : super(qvc, std::move(session_acl)), _config(config) +{ +} + +Http3ClientApp::~Http3ClientApp() +{ + free_MIOBuffer(this->_req_buf); + this->_req_buf = nullptr; + + free_MIOBuffer(this->_resp_buf); + this->_resp_buf = nullptr; + + delete this->_resp_handler; +} + +void +Http3ClientApp::start() +{ + this->_req_buf = new_MIOBuffer(); + this->_resp_buf = new_MIOBuffer(); + IOBufferReader *resp_buf_reader = _resp_buf->alloc_reader(); + + this->_resp_handler = new RespHandler(this->_config, resp_buf_reader); + + super::start(); + this->_do_http_request(); +} + +void +Http3ClientApp::_do_http_request() +{ + QUICConnectionErrorUPtr error; + QUICStreamId stream_id; + error = this->_qc->stream_manager()->create_bidi_stream(stream_id); + if (error != nullptr) { + Error("%s", error->msg); + ink_abort("Could not create bidi stream : %s", error->msg); + } + + QUICStreamIO *stream_io = this->_find_stream_io(stream_id); + + // TODO: create Http3ServerTransaction + Http3ClientTransaction *txn = new Http3ClientTransaction(this->_ssn, stream_io); + SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); + + // TODO: fix below issue with H2 origin conn stuff + // Do not call ProxyClientTransaction::new_transaction(), but need to setup txn - e.g. do_io_write / do_io_read + VIO *read_vio = txn->do_io_read(this->_resp_handler, INT64_MAX, this->_resp_buf); + this->_resp_handler->set_read_vio(read_vio); + + // Write HTTP Request to write_vio + char request[1024] = {0}; + std::string format; + if (this->_config->path[0] == '/') { + format = "GET https://%s%s HTTP/1.1\r\n\r\n"; + } else { + format = "GET https://%s/%s HTTP/1.1\r\n\r\n"; + } + + int request_len = snprintf(request, sizeof(request), format.c_str(), this->_config->addr, this->_config->path); + + Http09ClientAppDebug("\n%s", request); + + // TODO: check write avail size + int64_t nbytes = this->_req_buf->write(request, request_len); + IOBufferReader *buf_start = this->_req_buf->alloc_reader(); + txn->do_io_write(this, nbytes, buf_start); +} + +// +// Response Handler +// +RespHandler::RespHandler(const QUICClientConfig *config, IOBufferReader *reader) + : Continuation(new_ProxyMutex()), _config(config), _reader(reader) +{ + if (this->_config->output[0] != 0x0) { + this->_filename = this->_config->output; + } + + if (this->_filename) { + // Destroy contents if file already exists + std::ofstream f_stream(this->_filename, std::ios::binary | std::ios::trunc); + } + + SET_HANDLER(&RespHandler::main_event_handler); +} + +void +RespHandler::set_read_vio(VIO *vio) +{ + this->_read_vio = vio; +} + +int +RespHandler::main_event_handler(int event, Event *data) +{ + Debug("v_http3", "%s", get_vc_event_name(event)); + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: { + std::streambuf *default_stream = nullptr; + std::ofstream f_stream; + + if (this->_filename) { + default_stream = std::cout.rdbuf(); + f_stream = std::ofstream(this->_filename, std::ios::binary | std::ios::app); + std::cout.rdbuf(f_stream.rdbuf()); + } + + uint8_t buf[8192] = {0}; + int64_t nread; + while ((nread = this->_reader->read(buf, sizeof(buf))) > 0) { + std::cout.write(reinterpret_cast(buf), nread); + this->_read_vio->ndone += nread; + } + std::cout.flush(); + + if (this->_filename) { + f_stream.close(); + std::cout.rdbuf(default_stream); + } + + break; + } + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: + default: + break; + } + + return EVENT_CONT; +} diff --git a/src/traffic_quic/quic_client.h b/src/traffic_quic/quic_client.h index fe66740d5b7..5a2a950aafe 100644 --- a/src/traffic_quic/quic_client.h +++ b/src/traffic_quic/quic_client.h @@ -29,19 +29,35 @@ #include "P_QUICNetProcessor.h" #include "QUICApplication.h" +#include "Http3App.h" // TODO: add quic version option +// TODO: add host header option (also should be used for SNI) struct QUICClientConfig { char addr[1024] = "127.0.0.1"; char output[1024] = {0}; char port[16] = "4433"; char path[1018] = "/"; - char debug_tags[1024] = "quic|vv_quic_crypto"; + char debug_tags[1024] = "quic|vv_quic_crypto|http3|qpack"; int close = false; int http0_9 = true; int http3 = false; }; +class RespHandler : public Continuation +{ +public: + RespHandler(const QUICClientConfig *config, IOBufferReader *reader); + int main_event_handler(int event, Event *data); + void set_read_vio(VIO *vio); + +private: + const QUICClientConfig *_config = nullptr; + const char *_filename = nullptr; + IOBufferReader *_reader = nullptr; + VIO *_read_vio = nullptr; +}; + class QUICClient : public Continuation { public: @@ -56,18 +72,37 @@ class QUICClient : public Continuation struct addrinfo *_remote_addr_info = nullptr; }; -class QUICClientApp : public QUICApplication +class Http09ClientApp : public QUICApplication { public: - QUICClientApp(QUICNetVConnection *qvc, const QUICClientConfig *config); + Http09ClientApp(QUICNetVConnection *qvc, const QUICClientConfig *config); - void start(const char *path); + void start(); int main_event_handler(int event, Event *data); private: - void _start_http_09_session(const char *path); - void _start_http_3_session(const char *path); + void _do_http_request(); const QUICClientConfig *_config = nullptr; const char *_filename = nullptr; }; + +class Http3ClientApp : public Http3App +{ +public: + using super = Http3App; + + Http3ClientApp(QUICNetVConnection *qvc, IpAllow::ACL session_acl, const QUICClientConfig *config); + ~Http3ClientApp(); + + void start() override; + +private: + void _do_http_request(); + + RespHandler *_resp_handler = nullptr; + const QUICClientConfig *_config = nullptr; + + MIOBuffer *_req_buf = nullptr; + MIOBuffer *_resp_buf = nullptr; +}; diff --git a/src/traffic_quic/traffic_quic.cc b/src/traffic_quic/traffic_quic.cc index 551bb50f33c..9ac59b5c64d 100644 --- a/src/traffic_quic/traffic_quic.cc +++ b/src/traffic_quic/traffic_quic.cc @@ -27,6 +27,11 @@ #include "tscore/I_Version.h" #include "RecordsConfig.h" +#include "URL.h" +#include "MIME.h" +#include "HTTP.h" +#include "HuffmanCodec.h" +#include "Http3Config.h" #include "diags.h" #include "quic_client.h" @@ -95,6 +100,14 @@ main(int argc, const char **argv) udpNet.start(1, stacksize); quic_NetProcessor.start(-1, stacksize); + // Same to init_http_header(); in traffic_server.cc + url_init(); + mime_init(); + http_init(); + hpack_huffman_init(); + + Http3Config::startup(); + QUICClient client(&config); eventProcessor.schedule_in(&client, 1, ET_NET); @@ -168,6 +181,7 @@ Log::trace_out(sockaddr const *, unsigned short, char const *, ...) } #include "InkAPIInternal.h" + int APIHook::invoke(int, void *) { @@ -189,6 +203,24 @@ APIHooks::get() const return nullptr; } +void +APIHooks::clear() +{ + ink_abort("do not call stub"); +} + +void +APIHooks::append(INKContInternal *) +{ + ink_abort("do not call stub"); +} + +void +APIHooks::prepend(INKContInternal *) +{ + ink_abort("do not call stub"); +} + void ConfigUpdateCbTable::invoke(const char * /* name ATS_UNUSED */) { @@ -227,19 +259,76 @@ HttpRequestData::get_client_ip() SslAPIHooks *ssl_hooks = nullptr; StatPagesManager statPagesManager; -#include "ProcessManager.h" -inkcoreapi ProcessManager *pmgmt = nullptr; +#include "HttpDebugNames.h" +const char * +HttpDebugNames::get_api_hook_name(TSHttpHookID t) +{ + return "dummy"; +} + +#include "HttpSM.h" +HttpSM::HttpSM() : Continuation(nullptr), vc_table(this) {} + +void +HttpSM::cleanup() +{ + ink_abort("do not call stub"); +} + +void +HttpSM::destroy() +{ + ink_abort("do not call stub"); +} + +void +HttpSM::set_next_state() +{ + ink_abort("do not call stub"); +} + +void +HttpSM::handle_api_return() +{ + ink_abort("do not call stub"); +} int -BaseManager::registerMgmtCallback(int, const MgmtCallback &) +HttpSM::kill_this_async_hook(int /* event ATS_UNUSED */, void * /* data ATS_UNUSED */) { - ink_assert(false); - return 0; + return EVENT_DONE; } void -ProcessManager::signalManager(int, char const *, int) +HttpSM::attach_client_session(ProxyClientTransaction *, IOBufferReader *) +{ + ink_abort("do not call stub"); +} + +void +HttpSM::init() +{ + ink_abort("do not call stub"); +} + +ClassAllocator httpSMAllocator("httpSMAllocator"); +HttpAPIHooks *http_global_hooks; + +HttpVCTable::HttpVCTable(HttpSM *) {} + +PostDataBuffers::~PostDataBuffers() {} + +#include "HttpTunnel.h" +HttpTunnel::HttpTunnel() : Continuation(nullptr) {} +HttpTunnelConsumer::HttpTunnelConsumer() {} +HttpTunnelProducer::HttpTunnelProducer() {} +ChunkedHandler::ChunkedHandler() {} + +#include "HttpCacheSM.h" +HttpCacheSM::HttpCacheSM() {} + +HttpCacheAction::HttpCacheAction() : sm(nullptr) {} +void +HttpCacheAction::cancel(Continuation *c) { - ink_assert(false); - return; } From 039e4a0e850f0bbcf17a98505455486cf10c4810 Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 9 Apr 2019 09:11:43 +0000 Subject: [PATCH 1232/1313] Fixed compilation with ubuntu 18.04 --- src/traffic_quic/Makefile.inc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/traffic_quic/Makefile.inc b/src/traffic_quic/Makefile.inc index 18b466fae4e..4b2dbe6f4be 100644 --- a/src/traffic_quic/Makefile.inc +++ b/src/traffic_quic/Makefile.inc @@ -47,17 +47,18 @@ traffic_quic_traffic_quic_LDADD = \ $(top_builddir)/iocore/aio/libinkaio.a \ $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/src/tscore/libtscore.la \ $(top_builddir)/src/tscpp/util/libtscpputil.la \ $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ + $(top_builddir)/proxy/http3/libhttp3.a \ + $(top_builddir)/proxy/http2/libhttp2.a \ $(top_builddir)/proxy/libproxy.a \ $(top_builddir)/proxy/hdrs/libhdrs.a \ - $(top_builddir)/proxy/http2/libhttp2.a \ - $(top_builddir)/proxy/http3/libhttp3.a \ @HWLOC_LIBS@ \ @YAMLCPP_LIBS@ \ @OPENSSL_LIBS@ \ @LIBPCRE@ + From 2fe722da117beb99a1f22e918a3ef1c3060f1450 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 10 Apr 2019 13:52:24 +0900 Subject: [PATCH 1233/1313] Fix unit tests using QUICTLS --- .../quic/test/test_QUICHandshakeProtocol.cc | 18 +++++++++++------- .../test/test_QUICPacketHeaderProtector.cc | 10 ++++++---- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index 53b32d9c3da..aac2e6cd298 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -99,8 +99,9 @@ TEST_CASE("QUICHandshakeProtocol") { QUICPacketProtectionKeyInfo pp_key_info_client; QUICPacketProtectionKeyInfo pp_key_info_server; - QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT); - QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN); + NetVCOptions netvc_options; + QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT, netvc_options); + QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN, netvc_options); QUICPacketPayloadProtector ppp_client(pp_key_info_client); QUICPacketPayloadProtector ppp_server(pp_key_info_server); @@ -226,8 +227,9 @@ TEST_CASE("QUICHandshakeProtocol") QUICPacketProtectionKeyInfo pp_key_info_client; QUICPacketProtectionKeyInfo pp_key_info_server; - QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT); - QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN); + NetVCOptions netvc_options; + QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT, netvc_options); + QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN, netvc_options); QUICPacketPayloadProtector ppp_client(pp_key_info_client); QUICPacketPayloadProtector ppp_server(pp_key_info_server); @@ -365,7 +367,8 @@ TEST_CASE("QUICHandshakeProtocol") SECTION("Alert", "[quic]") { QUICPacketProtectionKeyInfo pp_key_info_server; - QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN); + NetVCOptions netvc_options; + QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN, netvc_options); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); // Malformed CH (finished) @@ -400,8 +403,9 @@ TEST_CASE("QUICHandshakeProtocol") { QUICPacketProtectionKeyInfo pp_key_info_client; QUICPacketProtectionKeyInfo pp_key_info_server; - QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT); - QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN); + NetVCOptions netvc_options; + QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT, netvc_options); + QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN, netvc_options); CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); diff --git a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc index c0ed905e5df..52aed26d906 100644 --- a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc @@ -71,8 +71,9 @@ TEST_CASE("QUICPacketHeaderProtector") QUICPacketProtectionKeyInfo pp_key_info_client; QUICPacketProtectionKeyInfo pp_key_info_server; - QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT); - QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN); + NetVCOptions netvc_options; + QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT, netvc_options); + QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN, netvc_options); CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); @@ -104,8 +105,9 @@ TEST_CASE("QUICPacketHeaderProtector") QUICPacketProtectionKeyInfo pp_key_info_client; QUICPacketProtectionKeyInfo pp_key_info_server; - QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT); - QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN); + NetVCOptions netvc_options; + QUICHandshakeProtocol *client = new QUICTLS(pp_key_info_client, client_ssl_ctx, NET_VCONNECTION_OUT, netvc_options); + QUICHandshakeProtocol *server = new QUICTLS(pp_key_info_server, server_ssl_ctx, NET_VCONNECTION_IN, netvc_options); CHECK(client->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); CHECK(server->initialize_key_materials({reinterpret_cast("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8})); From 3c27f603b86a1d8ddf851a767b5b30762b86ec12 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 10 Apr 2019 13:59:18 +0900 Subject: [PATCH 1234/1313] Ran clang-format --- iocore/net/QUICNetVConnection.cc | 3 +-- iocore/net/quic/QUICConfig.cc | 1 - iocore/net/quic/QUICTLS_openssl.cc | 3 ++- iocore/net/quic/test/test_QUICLossDetector.cc | 4 ++-- proxy/http3/Http3App.cc | 4 ++-- proxy/http3/Http3App.h | 2 +- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index bcc581d103c..6a2312821f3 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -2236,8 +2236,7 @@ QUICNetVConnection::_setup_handshake_protocol(SSL_CTX *ctx) { // Initialize handshake protocol specific stuff // For QUICv1 TLS is the only option - QUICTLS *tls = - new QUICTLS(this->_pp_key_info, ctx, this->direction(), this->options, this->_quic_config->session_file()); + QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx, this->direction(), this->options, this->_quic_config->session_file()); SSL_set_ex_data(tls->ssl_handle(), QUIC::ssl_quic_qc_index, static_cast(this)); return tls; } diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 4314caa0964..0213cee9b1e 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -35,7 +35,6 @@ #define QUICConfDebug(fmt, ...) Debug("quic_conf", fmt, ##__VA_ARGS__) - int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; int QUICCertConfig::_config_id = 0; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index d6d98420f07..94e1867307f 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -337,7 +337,8 @@ QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, Net if (this->_netvc_context == NET_VCONNECTION_OUT) { SSL_set_connect_state(this->_ssl); - SSL_set_alpn_protos(this->_ssl, reinterpret_cast(netvc_options.alpn_protos.data()), netvc_options.alpn_protos.size()); + SSL_set_alpn_protos(this->_ssl, reinterpret_cast(netvc_options.alpn_protos.data()), + netvc_options.alpn_protos.size()); SSL_set_tlsext_host_name(this->_ssl, netvc_options.sni_servername.get()); } else { SSL_set_accept_state(this->_ssl); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index c0c2b29cbcb..9c5dbb025c8 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -95,8 +95,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") SECTION("1-RTT") { // Send packet (1) to (7) - payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), + payload = ats_unique_malloc(payload_len); + QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), payload_len, true, false); REQUIRE(packet1 != nullptr); payload = ats_unique_malloc(payload_len); diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 1174e39f7f6..9d4b1f782f8 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -371,8 +371,8 @@ Http3SettingsFramer::generate_frame(uint16_t max_size) // Server side only if (this->_context == NET_VCONNECTION_IN) { - if (params->num_placeholders() != HTTP3_DEFAULT_NUM_PLACEHOLDERS) { - frame->set(Http3SettingsId::NUM_PLACEHOLDERS, params->num_placeholders()); + if (params->num_placeholders() != HTTP3_DEFAULT_NUM_PLACEHOLDERS) { + frame->set(Http3SettingsId::NUM_PLACEHOLDERS, params->num_placeholders()); } } diff --git a/proxy/http3/Http3App.h b/proxy/http3/Http3App.h index e4a31c0c2a3..67bd7f09b90 100644 --- a/proxy/http3/Http3App.h +++ b/proxy/http3/Http3App.h @@ -97,7 +97,7 @@ class Http3SettingsHandler : public Http3FrameHandler class Http3SettingsFramer : public Http3FrameGenerator { public: - Http3SettingsFramer(NetVConnectionContext_t context) : _context(context) {}; + Http3SettingsFramer(NetVConnectionContext_t context) : _context(context){}; // Http3FrameGenerator Http3FrameUPtr generate_frame(uint16_t max_size) override; From f607cac2ac67bff68af9d7babfdf9b965ffe2119 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 8 Apr 2019 16:55:31 +0900 Subject: [PATCH 1235/1313] Update QUIC draft numbers to 19 --- iocore/net/quic/Mock.h | 4 ++-- iocore/net/quic/QUICTypes.h | 2 +- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- src/traffic_quic/quic_client.cc | 4 ++-- src/tscore/ink_inet.cc | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 7e73fffdb5f..11d85b7631e 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -253,7 +253,7 @@ class MockQUICConnection : public QUICConnection std::string_view negotiated_application_name() const override { - return "h3-18"; + return "h3-19"; } int _transmit_count = 0; @@ -333,7 +333,7 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider std::string_view negotiated_application_name() const override { - return "h3-18"; + return "h3-19"; } }; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index fba82097dd2..3369854ed4b 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -50,7 +50,7 @@ using QUICOffset = uint64_t; // Note: Fix QUIC_ALPN_PROTO_LIST in QUICConfig.cc // Note: Change ExtensionType (QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID) if it's changed constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff000012, + 0xff000013, }; constexpr QUICVersion QUIC_EXERCISE_VERSION = 0x1a2a3a4a; diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index ba2c1f0871f..7c04a7055fe 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -53,7 +53,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x55, // DCIL/SCIL 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Destination Connection ID 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection ID - 0xff, 0x00, 0x00, 0x12, // Supported Version + 0xff, 0x00, 0x00, 0x13, // Supported Version 0x1a, 0x2a, 0x3a, 0x4a, // Excercise Version }; uint8_t buf[1024] = {0}; diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc index 47560fc6d8a..ffd1e66af12 100644 --- a/src/traffic_quic/quic_client.cc +++ b/src/traffic_quic/quic_client.cc @@ -34,8 +34,8 @@ // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html // Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? using namespace std::literals; -static constexpr std::string_view HQ_ALPN_PROTO_LIST("\5hq-18"sv); -static constexpr std::string_view H3_ALPN_PROTO_LIST("\5h3-18"sv); +static constexpr std::string_view HQ_ALPN_PROTO_LIST("\5hq-19"sv); +static constexpr std::string_view H3_ALPN_PROTO_LIST("\5h3-19"sv); QUICClient::QUICClient(const QUICClientConfig *config) : Continuation(new_ProxyMutex()), _config(config) { diff --git a/src/tscore/ink_inet.cc b/src/tscore/ink_inet.cc index 709bc96eccf..80d80eee321 100644 --- a/src/tscore/ink_inet.cc +++ b/src/tscore/ink_inet.cc @@ -50,8 +50,8 @@ const std::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"sv); const std::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"sv); const std::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"sv); const std::string_view IP_PROTO_TAG_HTTP_2_0("h2"sv); // HTTP/2 over TLS -const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-18"sv); // HTTP/0.9 over QUIC -const std::string_view IP_PROTO_TAG_HTTP_3("h3-18"sv); // HTTP/3 over QUIC +const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-19"sv); // HTTP/0.9 over QUIC +const std::string_view IP_PROTO_TAG_HTTP_3("h3-19"sv); // HTTP/3 over QUIC const std::string_view UNIX_PROTO_TAG{"unix"sv}; From 7af17709e049f782f102633495f2b2255c9f7257 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 9 Apr 2019 14:30:04 +0900 Subject: [PATCH 1236/1313] Update TransportParameter format to draft-19 --- iocore/net/quic/QUICTransportParameters.cc | 27 ++-------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 8fe99cbe16d..eb9c09482a0 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -81,7 +81,7 @@ void QUICTransportParameters::_load(const uint8_t *buf, size_t len) { bool has_error = false; - const uint8_t *p = buf + this->_parameters_offset(buf); + const uint8_t *p = buf; // Read size of parameters field uint16_t nbytes = (p[0] << 8) + p[1]; @@ -320,7 +320,6 @@ QUICTransportParameters::_print() const QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const uint8_t *buf, size_t len) { - this->_initial_version = QUICTypeUtil::read_QUICVersion(buf); this->_load(buf, len); if (is_debug_tag_set(tag)) { this->_print(); @@ -330,10 +329,7 @@ QUICTransportParametersInClientHello::QUICTransportParametersInClientHello(const void QUICTransportParametersInClientHello::_store(uint8_t *buf, uint16_t *len) const { - size_t l; *len = 0; - QUICTypeUtil::write_QUICVersion(this->_initial_version, buf, &l); - *len += l; } std::ptrdiff_t @@ -376,11 +372,6 @@ QUICTransportParametersInClientHello::initial_version() const QUICTransportParametersInEncryptedExtensions::QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len) { - this->_negotiated_version = QUICTypeUtil::read_QUICVersion(buf); - this->_n_versions = buf[4] / 4; - for (int i = 0; i < this->_n_versions; ++i) { - this->_versions[i] = QUICTypeUtil::read_QUICVersion(buf + 5 + (i * 4)); - } this->_load(buf, len); if (is_debug_tag_set(tag)) { this->_print(); @@ -390,21 +381,7 @@ QUICTransportParametersInEncryptedExtensions::QUICTransportParametersInEncrypted void QUICTransportParametersInEncryptedExtensions::_store(uint8_t *buf, uint16_t *len) const { - uint8_t *p = buf; - size_t l; - - // negotiated_version - QUICTypeUtil::write_QUICVersion(this->_negotiated_version, buf, &l); - p += l; - - // supported_versions - p[0] = this->_n_versions * sizeof(uint32_t); - ++p; - for (int i = 0; i < this->_n_versions; ++i) { - QUICTypeUtil::write_QUICVersion(this->_versions[i], p, &l); - p += l; - } - *len = p - buf; + *len = 0; } QUICVersion From c3fcccb6bfb016f06aaddd731734d9e37f2437ea Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 9 Apr 2019 17:35:03 +0900 Subject: [PATCH 1237/1313] Remove version related fields from TP and version validation logic --- iocore/net/quic/QUICHandshake.cc | 28 ++----- iocore/net/quic/QUICHandshake.h | 5 +- iocore/net/quic/QUICTransportParameters.cc | 24 ------ iocore/net/quic/QUICTransportParameters.h | 15 +--- iocore/net/quic/QUICVersionNegotiator.cc | 39 +--------- iocore/net/quic/QUICVersionNegotiator.h | 3 +- .../net/quic/test/test_QUICStreamManager.cc | 75 ++++++++----------- .../quic/test/test_QUICTransportParameters.cc | 37 ++------- .../quic/test/test_QUICVersionNegotiator.cc | 33 -------- 9 files changed, 53 insertions(+), 206 deletions(-) diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index ca8d1204057..d666fb8bcd6 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -112,7 +112,7 @@ QUICHandshake::start(const QUICTPConfig &tp_config, QUICPacketFactory *packet_fa initital_version = QUIC_EXERCISE_VERSION; } - this->_load_local_client_transport_parameters(tp_config, initital_version); + this->_load_local_client_transport_parameters(tp_config); packet_factory->set_version(initital_version); return nullptr; @@ -130,7 +130,7 @@ QUICHandshake::start(const QUICTPConfig &tp_config, const QUICPacket &initial_pa if (initial_packet.version()) { if (this->_version_negotiator->negotiate(initial_packet) == QUICVersionNegotiationStatus::NEGOTIATED) { QUICHSDebug("Version negotiation succeeded: %x", initial_packet.version()); - this->_load_local_server_transport_parameters(tp_config, initial_packet.version(), pref_addr); + this->_load_local_server_transport_parameters(tp_config, pref_addr); packet_factory->set_version(this->_version_negotiator->negotiated_version()); } else { ink_assert(!"Unsupported version initial packet should be droped QUICPakcetHandler"); @@ -246,14 +246,6 @@ QUICHandshake::_check_remote_transport_parameters(std::shared_ptr_remote_transport_parameters = tp; - // Version revalidation - if (this->_version_negotiator->validate(tp.get()) != QUICVersionNegotiationStatus::VALIDATED) { - QUICHSDebug("Version revalidation failed"); - this->_abort_handshake(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR); - return false; - } - - QUICHSDebug("Version negotiation validated: %x", tp->initial_version()); return true; } @@ -269,13 +261,6 @@ QUICHandshake::_check_remote_transport_parameters(std::shared_ptr_remote_transport_parameters = tp; - // Version revalidation - if (this->_version_negotiator->validate(tp.get()) != QUICVersionNegotiationStatus::VALIDATED) { - QUICHSDebug("Version revalidation failed"); - this->_abort_handshake(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR); - return false; - } - return true; } @@ -361,10 +346,9 @@ QUICHandshake::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t } void -QUICHandshake::_load_local_server_transport_parameters(const QUICTPConfig &tp_config, QUICVersion negotiated_version, - const QUICPreferredAddress *pref_addr) +QUICHandshake::_load_local_server_transport_parameters(const QUICTPConfig &tp_config, const QUICPreferredAddress *pref_addr) { - QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(negotiated_version); + QUICTransportParametersInEncryptedExtensions *tp = new QUICTransportParametersInEncryptedExtensions(); // MUSTs tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(tp_config.no_activity_timeout())); @@ -410,9 +394,9 @@ QUICHandshake::_load_local_server_transport_parameters(const QUICTPConfig &tp_co } void -QUICHandshake::_load_local_client_transport_parameters(const QUICTPConfig &tp_config, QUICVersion initial_version) +QUICHandshake::_load_local_client_transport_parameters(const QUICTPConfig &tp_config) { - QUICTransportParametersInClientHello *tp = new QUICTransportParametersInClientHello(initial_version); + QUICTransportParametersInClientHello *tp = new QUICTransportParametersInClientHello(); // MUSTs tp->set(QUICTransportParameterId::IDLE_TIMEOUT, static_cast(tp_config.no_activity_timeout())); diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 5ce46b9bc48..10202f63b8c 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -101,9 +101,8 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator QUICEncryptionLevel::ONE_RTT, }; } - void _load_local_server_transport_parameters(const QUICTPConfig &tp_config, QUICVersion negotiated_version, - const QUICPreferredAddress *pref_addr); - void _load_local_client_transport_parameters(const QUICTPConfig &tp_config, QUICVersion initial_version); + void _load_local_server_transport_parameters(const QUICTPConfig &tp_config, const QUICPreferredAddress *pref_addr); + void _load_local_client_transport_parameters(const QUICTPConfig &tp_config); bool _check_remote_transport_parameters(std::shared_ptr tp); bool _check_remote_transport_parameters(std::shared_ptr tp); std::shared_ptr _local_transport_parameters = nullptr; diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index eb9c09482a0..4d3bc7dae4c 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -360,12 +360,6 @@ QUICTransportParametersInClientHello::_validate_parameters() const return 0; } -QUICVersion -QUICTransportParametersInClientHello::initial_version() const -{ - return this->_initial_version; -} - // // QUICTransportParametersInEncryptedExtensions // @@ -384,30 +378,12 @@ QUICTransportParametersInEncryptedExtensions::_store(uint8_t *buf, uint16_t *len *len = 0; } -QUICVersion -QUICTransportParametersInEncryptedExtensions::negotiated_version() const -{ - return this->_negotiated_version; -} - void QUICTransportParametersInEncryptedExtensions::add_version(QUICVersion version) { this->_versions[this->_n_versions++] = version; } -bool -QUICTransportParametersInEncryptedExtensions::is_valid_negotiated_version() const -{ - for (int i = 0; QUICVersion v = this->_versions[i]; i++) { - if (this->_negotiated_version == v) { - return true; - } - } - - return false; -} - std::ptrdiff_t QUICTransportParametersInEncryptedExtensions::_parameters_offset(const uint8_t *buf) const { diff --git a/iocore/net/quic/QUICTransportParameters.h b/iocore/net/quic/QUICTransportParameters.h index f9e2722866a..6886bd09af0 100644 --- a/iocore/net/quic/QUICTransportParameters.h +++ b/iocore/net/quic/QUICTransportParameters.h @@ -117,10 +117,8 @@ class QUICTransportParameters class QUICTransportParametersInClientHello : public QUICTransportParameters { public: - QUICTransportParametersInClientHello(QUICVersion initial_version) - : QUICTransportParameters(), _initial_version(initial_version){}; + QUICTransportParametersInClientHello() : QUICTransportParameters(){}; QUICTransportParametersInClientHello(const uint8_t *buf, size_t len); - QUICVersion initial_version() const; protected: std::ptrdiff_t _parameters_offset(const uint8_t *buf) const override; @@ -128,27 +126,22 @@ class QUICTransportParametersInClientHello : public QUICTransportParameters void _store(uint8_t *buf, uint16_t *len) const override; private: - QUICVersion _initial_version = 0; }; class QUICTransportParametersInEncryptedExtensions : public QUICTransportParameters { public: - QUICTransportParametersInEncryptedExtensions(QUICVersion negotiated_version) - : QUICTransportParameters(), _negotiated_version(negotiated_version){}; + QUICTransportParametersInEncryptedExtensions() : QUICTransportParameters(){}; QUICTransportParametersInEncryptedExtensions(const uint8_t *buf, size_t len); - QUICVersion negotiated_version() const; void add_version(QUICVersion version); - bool is_valid_negotiated_version() const; protected: std::ptrdiff_t _parameters_offset(const uint8_t *buf) const override; int _validate_parameters() const override; void _store(uint8_t *buf, uint16_t *len) const override; - QUICVersion _negotiated_version = 0; - uint8_t _n_versions = 0; - QUICVersion _versions[256] = {}; + uint8_t _n_versions = 0; + QUICVersion _versions[256] = {}; }; class QUICTransportParametersHandler diff --git a/iocore/net/quic/QUICVersionNegotiator.cc b/iocore/net/quic/QUICVersionNegotiator.cc index 677c134e3d6..ec1dc7938d6 100644 --- a/iocore/net/quic/QUICVersionNegotiator.cc +++ b/iocore/net/quic/QUICVersionNegotiator.cc @@ -69,45 +69,8 @@ QUICVersionNegotiator::negotiate(const QUICPacket &packet) } QUICVersionNegotiationStatus -QUICVersionNegotiator::validate(const QUICTransportParametersInClientHello *tp) +QUICVersionNegotiator::validate() { - if (this->_negotiated_version == tp->initial_version()) { - this->_status = QUICVersionNegotiationStatus::VALIDATED; - } else { - // Version negotiation was performed - if (QUICTypeUtil::is_supported_version(tp->initial_version())) { - this->_status = QUICVersionNegotiationStatus::FAILED; - this->_negotiated_version = 0; - } else { - this->_status = QUICVersionNegotiationStatus::VALIDATED; - } - } - return this->_status; -} - -QUICVersionNegotiationStatus -QUICVersionNegotiator::validate(const QUICTransportParametersInEncryptedExtensions *tp) -{ - if (!tp->is_valid_negotiated_version()) { - this->_status = QUICVersionNegotiationStatus::FAILED; - this->_negotiated_version = 0; - - return this->_status; - } - - if (this->_status == QUICVersionNegotiationStatus::NEGOTIATED) { - // Version negotiation was performed - if (this->_negotiated_version == tp->negotiated_version()) { - this->_status = QUICVersionNegotiationStatus::VALIDATED; - } else { - this->_status = QUICVersionNegotiationStatus::FAILED; - this->_negotiated_version = 0; - } - } else { - this->_status = QUICVersionNegotiationStatus::VALIDATED; - this->_negotiated_version = tp->negotiated_version(); - } - return this->_status; } diff --git a/iocore/net/quic/QUICVersionNegotiator.h b/iocore/net/quic/QUICVersionNegotiator.h index a931e05f63d..6b86d7f73a5 100644 --- a/iocore/net/quic/QUICVersionNegotiator.h +++ b/iocore/net/quic/QUICVersionNegotiator.h @@ -36,8 +36,7 @@ class QUICVersionNegotiator public: QUICVersionNegotiationStatus status(); QUICVersionNegotiationStatus negotiate(const QUICPacket &initial_packet); - QUICVersionNegotiationStatus validate(const QUICTransportParametersInClientHello *tp); - QUICVersionNegotiationStatus validate(const QUICTransportParametersInEncryptedExtensions *tp); + QUICVersionNegotiationStatus validate(); QUICVersion negotiated_version(); private: diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 31e3a5a7db4..d42fdd8ba5a 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -41,22 +41,19 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") QUICStreamManager sm(&cinfo_provider, &rtt_provider, &app_map); uint8_t local_tp_buf[] = { - 0x00, 0x00, 0x00, 0x00, // initial version - 0x00, // size of supported versions - 0x00, 0x06, // size of parameters - 0x00, 0x08, // parameter id - initial_max_streams_bidi - 0x00, 0x02, // length of value - 0x40, 0x10 // value + 0x00, 0x06, // size of parameters + 0x00, 0x08, // parameter id - initial_max_streams_bidi + 0x00, 0x02, // length of value + 0x40, 0x10 // value }; std::shared_ptr local_tp = std::make_shared(local_tp_buf, sizeof(local_tp_buf)); uint8_t remote_tp_buf[] = { - 0x00, 0x00, 0x00, 0x00, // initial version - 0x00, 0x06, // size of parameters - 0x00, 0x08, // parameter id - initial_max_streams_bidi - 0x00, 0x02, // length of value - 0x40, 0x10 // value + 0x00, 0x06, // size of parameters + 0x00, 0x08, // parameter id - initial_max_streams_bidi + 0x00, 0x02, // length of value + 0x40, 0x10 // value }; std::shared_ptr remote_tp = std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); @@ -116,10 +113,8 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") MockQUICConnectionInfoProvider cinfo_provider; MockQUICRTTProvider rtt_provider; QUICStreamManager sm(&cinfo_provider, &rtt_provider, &app_map); - std::shared_ptr local_tp = - std::make_shared(static_cast(0)); - std::shared_ptr remote_tp = - std::make_shared(static_cast(0)); + std::shared_ptr local_tp = std::make_shared(); + std::shared_ptr remote_tp = std::make_shared(); sm.init_flow_control_params(local_tp, remote_tp); // STREAM frames create new streams @@ -145,28 +140,25 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); uint8_t local_tp_buf[] = { - 0x00, 0x00, 0x00, 0x00, // initial version - 0x00, // size of supported versions - 0x00, 0x0e, // size of parameters - 0x00, 0x08, // parameter id - initial_max_streams_bidi - 0x00, 0x02, // length of value - 0x40, 0x10, // value - 0x00, 0x05, // parameter id - initial_max_stream_data_bidi_local - 0x00, 0x04, // length of value - 0xbf, 0xff, 0xff, 0xff // value + 0x00, 0x0e, // size of parameters + 0x00, 0x08, // parameter id - initial_max_streams_bidi + 0x00, 0x02, // length of value + 0x40, 0x10, // value + 0x00, 0x05, // parameter id - initial_max_stream_data_bidi_local + 0x00, 0x04, // length of value + 0xbf, 0xff, 0xff, 0xff // value }; std::shared_ptr local_tp = std::make_shared(local_tp_buf, sizeof(local_tp_buf)); uint8_t remote_tp_buf[] = { - 0x00, 0x00, 0x00, 0x00, // initial version - 0x00, 0x0e, // size of parameters - 0x00, 0x08, // parameter id - initial_max_streams_bidi - 0x00, 0x02, // length of value - 0x40, 0x10, // value - 0x00, 0x06, // parameter id - initial_max_stream_data_bidi_remote - 0x00, 0x04, // length of value - 0xbf, 0xff, 0xff, 0xff // value + 0x00, 0x0e, // size of parameters + 0x00, 0x08, // parameter id - initial_max_streams_bidi + 0x00, 0x02, // length of value + 0x40, 0x10, // value + 0x00, 0x06, // parameter id - initial_max_stream_data_bidi_remote + 0x00, 0x04, // length of value + 0xbf, 0xff, 0xff, 0xff // value }; std::shared_ptr remote_tp = std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); @@ -205,22 +197,19 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); uint8_t local_tp_buf[] = { - 0x00, 0x00, 0x00, 0x00, // initial version - 0x00, // size of supported versions - 0x00, 0x06, // size of parameters - 0x00, 0x08, // parameter id - initial_max_streams_bidi - 0x00, 0x02, // length of value - 0x40, 0x10 // value + 0x00, 0x06, // size of parameters + 0x00, 0x08, // parameter id - initial_max_streams_bidi + 0x00, 0x02, // length of value + 0x40, 0x10 // value }; std::shared_ptr local_tp = std::make_shared(local_tp_buf, sizeof(local_tp_buf)); uint8_t remote_tp_buf[] = { - 0x00, 0x00, 0x00, 0x00, // initial version - 0x00, 0x06, // size of parameters - 0x00, 0x08, // parameter id - initial_max_streams_bidi - 0x00, 0x02, // length of value - 0x40, 0x10 // value + 0x00, 0x06, // size of parameters + 0x00, 0x08, // parameter id - initial_max_streams_bidi + 0x00, 0x02, // length of value + 0x40, 0x10 // value }; std::shared_ptr remote_tp = std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); diff --git a/iocore/net/quic/test/test_QUICTransportParameters.cc b/iocore/net/quic/test/test_QUICTransportParameters.cc index 41a4eb949c8..d60e2606790 100644 --- a/iocore/net/quic/test/test_QUICTransportParameters.cc +++ b/iocore/net/quic/test/test_QUICTransportParameters.cc @@ -30,7 +30,6 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") SECTION("OK") { uint8_t buf[] = { - 0x05, 0x06, 0x07, 0x08, // initial version 0x00, 0x1c, // size of parameters 0x00, 0x00, // parameter id 0x00, 0x04, // length of value @@ -48,7 +47,6 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") QUICTransportParametersInClientHello params_in_ch(buf, sizeof(buf)); CHECK(params_in_ch.is_valid()); - CHECK(params_in_ch.initial_version() == 0x05060708); uint16_t len = 0; const uint8_t *data = nullptr; @@ -77,7 +75,6 @@ TEST_CASE("QUICTransportParametersInClientHello_read", "[quic]") SECTION("Duplicate parameters") { uint8_t buf[] = { - 0x05, 0x06, 0x07, 0x08, // initial version 0x00, 0x10, // size of parameters 0x00, 0x00, // parameter id 0x00, 0x04, // length of value @@ -98,7 +95,6 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") uint16_t len; uint8_t expected[] = { - 0x05, 0x06, 0x07, 0x08, // initial version 0x00, 0x22, // size of parameters 0x00, 0x02, // parameter id 0x00, 0x10, // length of value @@ -112,7 +108,7 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") 0x91, 0x22, 0x33, 0x44, // value }; - QUICTransportParametersInClientHello params_in_ch(0x05060708); + QUICTransportParametersInClientHello params_in_ch; uint32_t max_stream_data = 0x11223344; params_in_ch.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, max_stream_data); @@ -125,7 +121,7 @@ TEST_CASE("QUICTransportParametersInClientHello_write", "[quic]") params_in_ch.set(QUICTransportParameterId::STATELESS_RESET_TOKEN, stateless_reset_token, 16); params_in_ch.store(buf, &len); - CHECK(len == 40); + CHECK(len == 36); CHECK(memcmp(buf, expected, len) == 0); } @@ -134,9 +130,6 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") SECTION("OK case") { uint8_t buf[] = { - 0x01, 0x02, 0x03, 0x04, // negotiated version - 0x04, // size of supported versions - 0x01, 0x02, 0x03, 0x04, // 0x00, 0x2a, // size of parameters 0x00, 0x01, // parameter id 0x00, 0x02, // length of value @@ -154,8 +147,6 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") QUICTransportParametersInEncryptedExtensions params_in_ee(buf, sizeof(buf)); CHECK(params_in_ee.is_valid()); - CHECK(params_in_ee.is_valid_negotiated_version()); - CHECK(params_in_ee.negotiated_version() == 0x01020304); uint16_t len = 0; const uint8_t *data = nullptr; @@ -174,7 +165,7 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") data = params_in_ee.getAsBytes(QUICTransportParameterId::STATELESS_RESET_TOKEN, len); CHECK(len == 16); - CHECK(memcmp(data, buf + 21, 16) == 0); + CHECK(memcmp(data, buf + 12, 16) == 0); CHECK(!params_in_ee.contains(QUICTransportParameterId::DISABLE_MIGRATION)); } @@ -182,9 +173,6 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") SECTION("OK case - zero length value") { uint8_t buf[] = { - 0x01, 0x02, 0x03, 0x04, // negotiated version - 0x04, // size of supported versions - 0x01, 0x02, 0x03, 0x04, // 0x00, 0x1a, // size of parameters 0x00, 0x01, // parameter id 0x00, 0x02, // length of value @@ -223,9 +211,6 @@ TEST_CASE("QUICTransportParametersInEncryptedExtensions_read", "[quic]") SECTION("Duplicate parameters") { uint8_t buf[] = { - 0x01, 0x02, 0x03, 0x04, // negotiated version - 0x04, // size of supported versions - 0x01, 0x02, 0x03, 0x04, // 0x00, 0x1e, // size of parameters 0x00, 0x00, // parameter id 0x00, 0x04, // length of value @@ -248,10 +233,6 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") uint16_t len; uint8_t expected[] = { - 0x01, 0x02, 0x03, 0x04, // negotiated version - 0x08, // size of supported versions - 0x01, 0x02, 0x03, 0x04, // version 1 - 0x05, 0x06, 0x07, 0x08, // version 2 0x00, 0x0e, // size of parameters 0x00, 0x03, // parameter id 0x00, 0x02, // length of value @@ -261,7 +242,7 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") 0x91, 0x22, 0x33, 0x44, // value }; - QUICTransportParametersInEncryptedExtensions params_in_ee(0x01020304); + QUICTransportParametersInEncryptedExtensions params_in_ee; uint32_t max_stream_data = 0x11223344; params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, max_stream_data); @@ -272,7 +253,7 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") params_in_ee.add_version(0x01020304); params_in_ee.add_version(0x05060708); params_in_ee.store(buf, &len); - CHECK(len == 29); + CHECK(len == 16); CHECK(memcmp(buf, expected, len) == 0); } @@ -282,10 +263,6 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") uint16_t len; uint8_t expected[] = { - 0x01, 0x02, 0x03, 0x04, // negotiated version - 0x08, // size of supported versions - 0x01, 0x02, 0x03, 0x04, // version 1 - 0x05, 0x06, 0x07, 0x08, // version 2 0x00, 0x12, // size of parameters 0x00, 0x03, // parameter id 0x00, 0x02, // length of value @@ -297,7 +274,7 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") 0x00, 0x00, // length of value }; - QUICTransportParametersInEncryptedExtensions params_in_ee(0x01020304); + QUICTransportParametersInEncryptedExtensions params_in_ee; uint32_t max_stream_data = 0x11223344; params_in_ee.set(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, max_stream_data); @@ -309,7 +286,7 @@ TEST_CASE("QUICTransportParametersEncryptedExtensions_write", "[quic]") params_in_ee.add_version(0x01020304); params_in_ee.add_version(0x05060708); params_in_ee.store(buf, &len); - CHECK(len == 33); + CHECK(len == 20); CHECK(memcmp(buf, expected, len) == 0); } } diff --git a/iocore/net/quic/test/test_QUICVersionNegotiator.cc b/iocore/net/quic/test/test_QUICVersionNegotiator.cc index 59d3796da5a..be76949a89d 100644 --- a/iocore/net/quic/test/test_QUICVersionNegotiator.cc +++ b/iocore/net/quic/test/test_QUICVersionNegotiator.cc @@ -50,12 +50,6 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") REQUIRE(initial_packet != nullptr); vn.negotiate(*initial_packet); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); - - // Validate version - QUICTransportParametersInClientHello tp(QUIC_SUPPORTED_VERSIONS[0]); - vn.validate(&tp); - CHECK(vn.status() == QUICVersionNegotiationStatus::VALIDATED); - CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); } SECTION("Negotiation case") @@ -71,12 +65,6 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") REQUIRE(initial_packet != nullptr); vn.negotiate(*initial_packet); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); - - // Validate version - QUICTransportParametersInClientHello tp(QUIC_EXERCISE_VERSION); - vn.validate(&tp); - CHECK(vn.status() == QUICVersionNegotiationStatus::VALIDATED); - CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); } SECTION("Downgrade case") @@ -92,12 +80,6 @@ TEST_CASE("QUICVersionNegotiator - Server Side", "[quic]") REQUIRE(initial_packet != nullptr); vn.negotiate(*initial_packet); CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); - - // Validate version - QUICTransportParametersInClientHello tp(QUIC_SUPPORTED_VERSIONS[0]); - vn.validate(&tp); - CHECK(vn.status() == QUICVersionNegotiationStatus::FAILED); - CHECK(vn.negotiated_version() != QUIC_SUPPORTED_VERSIONS[0]); } } @@ -117,14 +99,6 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") CHECK(vn.status() == QUICVersionNegotiationStatus::NOT_NEGOTIATED); // No Version Negotiation packet from server - - // Validate version - QUICTransportParametersInEncryptedExtensions tp(QUIC_SUPPORTED_VERSIONS[0]); - tp.add_version(QUIC_SUPPORTED_VERSIONS[0]); - - vn.validate(&tp); - CHECK(vn.status() == QUICVersionNegotiationStatus::VALIDATED); - CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); } SECTION("Negotiation case") @@ -147,12 +121,5 @@ TEST_CASE("QUICVersionNegotiator - Client Side", "[quic]") vn.negotiate(*vn_packet); CHECK(vn.status() == QUICVersionNegotiationStatus::NEGOTIATED); CHECK(vn.negotiated_version() == QUIC_SUPPORTED_VERSIONS[0]); - - // Validate version - QUICTransportParametersInEncryptedExtensions tp(QUIC_SUPPORTED_VERSIONS[0]); - tp.add_version(QUIC_SUPPORTED_VERSIONS[0]); - - vn.validate(&tp); - CHECK(vn.status() == QUICVersionNegotiationStatus::VALIDATED); } } From 3459e0822a67fdeabda76aacfc289fa8bde0e4ed Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 12 Apr 2019 15:07:41 +0900 Subject: [PATCH 1238/1313] Update H3 Frame header format to draft-19 --- proxy/http3/Http3Frame.cc | 46 ++++++++++------- proxy/http3/Http3FrameDispatcher.cc | 79 +++++++++++++++++------------ proxy/http3/Http3FrameDispatcher.h | 4 +- proxy/http3/Http3Types.h | 12 ++--- 4 files changed, 83 insertions(+), 58 deletions(-) diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc index f704b3d9cd2..06153138a63 100644 --- a/proxy/http3/Http3Frame.cc +++ b/proxy/http3/Http3Frame.cc @@ -44,12 +44,12 @@ Http3Frame::length(const uint8_t *buf, size_t buf_len, uint64_t &length) Http3FrameType Http3Frame::type(const uint8_t *buf, size_t buf_len) { - uint64_t length = 0; - size_t length_field_length = 0; - int ret = QUICVariableInt::decode(length, length_field_length, buf, buf_len); + uint64_t type = 0; + size_t type_field_length = 0; + int ret = QUICVariableInt::decode(type, type_field_length, buf, buf_len); ink_assert(ret != 1); - if (buf[length_field_length] <= static_cast(Http3FrameType::X_MAX_DEFINED)) { - return static_cast(buf[length_field_length]); + if (type <= static_cast(Http3FrameType::X_MAX_DEFINED)) { + return static_cast(type); } else { return Http3FrameType::UNKNOWN; } @@ -61,16 +61,18 @@ Http3Frame::type(const uint8_t *buf, size_t buf_len) Http3Frame::Http3Frame(const uint8_t *buf, size_t buf_len) { + // Type + size_t type_field_length = 0; + int ret = QUICVariableInt::decode(reinterpret_cast(this->_type), type_field_length, buf, buf_len); + ink_assert(ret != 1); + // Length size_t length_field_length = 0; - int ret = QUICVariableInt::decode(this->_length, length_field_length, buf, buf_len); + ret = QUICVariableInt::decode(this->_length, length_field_length, buf + type_field_length, buf_len - type_field_length); ink_assert(ret != 1); - // Type - this->_type = Http3FrameType(buf[length_field_length]); - // Payload offset - this->_payload_offset = length_field_length + 1; + this->_payload_offset = type_field_length + length_field_length; } Http3Frame::Http3Frame(Http3FrameType type) : _type(type) {} @@ -139,8 +141,11 @@ void Http3DataFrame::store(uint8_t *buf, size_t *len) const { size_t written = 0; - QUICVariableInt::encode(buf, UINT64_MAX, written, this->_length); - buf[written++] = static_cast(this->_type); + size_t n; + QUICVariableInt::encode(buf, UINT64_MAX, n, static_cast(this->_type)); + written += n; + QUICVariableInt::encode(buf + written, UINT64_MAX, n, this->_length); + written += n; memcpy(buf + written, this->_payload, this->_payload_len); written += this->_payload_len; *len = written; @@ -185,8 +190,11 @@ void Http3HeadersFrame::store(uint8_t *buf, size_t *len) const { size_t written = 0; - QUICVariableInt::encode(buf, UINT64_MAX, written, this->_length); - buf[written++] = static_cast(this->_type); + size_t n; + QUICVariableInt::encode(buf, UINT64_MAX, n, static_cast(this->_type)); + written += n; + QUICVariableInt::encode(buf + written, UINT64_MAX, n, this->_length); + written += n; memcpy(buf + written, this->_header_block, this->_header_block_len); written += this->_header_block_len; *len = written; @@ -271,11 +279,11 @@ Http3SettingsFrame::store(uint8_t *buf, size_t *len) const size_t written = 0; size_t payload_len = p - payload; - // Length - QUICVariableInt::encode(buf, UINT64_MAX, written, payload_len); - - // Type - buf[written++] = static_cast(this->_type); + size_t n; + QUICVariableInt::encode(buf, UINT64_MAX, n, static_cast(this->_type)); + written += n; + QUICVariableInt::encode(buf + written, UINT64_MAX, n, payload_len); + written += n; // Payload memcpy(buf + written, payload, payload_len); diff --git a/proxy/http3/Http3FrameDispatcher.cc b/proxy/http3/Http3FrameDispatcher.cc index 24a56c412d7..14bd0769a8e 100644 --- a/proxy/http3/Http3FrameDispatcher.cc +++ b/proxy/http3/Http3FrameDispatcher.cc @@ -48,52 +48,67 @@ Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) nread = 0; while (true) { + // Read a length of Type field and hopefully a length of Length field too + uint8_t head[16]; + int64_t read_len = stream_io.peek(head, 16); + Debug("v_http3", "reading H3 frame: state=%d read_len=%" PRId64, this->_reading_state, read_len); + + if (this->_reading_state == READING_TYPE_LEN) { + if (read_len >= 1) { + this->_reading_frame_type_len = QUICVariableInt::size(head); + this->_reading_state = READING_LENGTH_LEN; + Debug("v_http3", "type_len=%" PRId64, this->_reading_frame_type_len); + } else { + break; + } + } + if (this->_reading_state == READING_LENGTH_LEN) { - // Read a length of Length field - uint8_t head; - if (stream_io.peek(&head, 1) <= 0) { + if (read_len >= this->_reading_frame_type_len + 1) { + this->_reading_frame_length_len = QUICVariableInt::size(head + this->_reading_frame_type_len); + this->_reading_state = READING_PAYLOAD_LEN; + Debug("v_http3", "length_len=%" PRId64, this->_reading_frame_length_len); + } else { break; } - this->_reading_frame_length_len = QUICVariableInt::size(&head); - this->_reading_state = READING_PAYLOAD_LEN; } if (this->_reading_state == READING_PAYLOAD_LEN) { - // Read a payload length - uint8_t length_buf[8]; - if (stream_io.peek(length_buf, this->_reading_frame_length_len) != this->_reading_frame_length_len) { + if (read_len >= this->_reading_frame_type_len + this->_reading_frame_length_len) { + size_t dummy; + QUICVariableInt::decode(this->_reading_frame_payload_len, dummy, head + this->_reading_frame_type_len); + Debug("v_http3", "payload_len=%" PRId64, this->_reading_frame_payload_len); + this->_reading_state = READING_PAYLOAD; + } else { break; } - size_t dummy; - if (QUICVariableInt::decode(this->_reading_frame_payload_len, dummy, length_buf, sizeof(length_buf)) < 0) { - error = Http3ErrorUPtr(new Http3StreamError()); - } - this->_reading_state = READING_PAYLOAD; } - // Create a frame - // Length field length + Type field length (1) + Payload length - size_t frame_len = this->_reading_frame_length_len + 1 + this->_reading_frame_payload_len; - frame = this->_frame_factory.fast_create(stream_io, frame_len); - if (frame == nullptr) { - break; - } + if (this->_reading_state == READING_PAYLOAD) { + // Create a frame + // Type field length + Length field length + Payload length + size_t frame_len = this->_reading_frame_type_len + this->_reading_frame_length_len + this->_reading_frame_payload_len; + frame = this->_frame_factory.fast_create(stream_io, frame_len); + if (frame == nullptr) { + break; + } - // Consume buffer if frame is created - nread += frame_len; - stream_io.consume(nread); + // Consume buffer if frame is created + nread += frame_len; + stream_io.consume(frame_len); - // Dispatch - Http3FrameType type = frame->type(); - Debug("http3", "[RX] [%d] | %s", stream_io.stream_id(), Http3DebugNames::frame_type(type)); - std::vector handlers = this->_handlers[static_cast(type)]; - for (auto h : handlers) { - error = h->handle_frame(frame); - if (error->cls != Http3ErrorClass::NONE) { - return error; + // Dispatch + Http3FrameType type = frame->type(); + Debug("http3", "[RX] [%d] | %s", stream_io.stream_id(), Http3DebugNames::frame_type(type)); + std::vector handlers = this->_handlers[static_cast(type)]; + for (auto h : handlers) { + error = h->handle_frame(frame); + if (error->cls != Http3ErrorClass::NONE) { + return error; + } } + this->_reading_state = READING_TYPE_LEN; } - this->_reading_state = READING_LENGTH_LEN; } return error; diff --git a/proxy/http3/Http3FrameDispatcher.h b/proxy/http3/Http3FrameDispatcher.h index beaad0de543..fae5121755b 100644 --- a/proxy/http3/Http3FrameDispatcher.h +++ b/proxy/http3/Http3FrameDispatcher.h @@ -37,10 +37,12 @@ class Http3FrameDispatcher private: enum READING_STATE { + READING_TYPE_LEN, READING_LENGTH_LEN, READING_PAYLOAD_LEN, READING_PAYLOAD, - } _reading_state = READING_LENGTH_LEN; + } _reading_state = READING_TYPE_LEN; + int64_t _reading_frame_type_len; int64_t _reading_frame_length_len; uint64_t _reading_frame_payload_len; Http3FrameFactory _frame_factory; diff --git a/proxy/http3/Http3Types.h b/proxy/http3/Http3Types.h index c37ea628626..1ebbe8c3445 100644 --- a/proxy/http3/Http3Types.h +++ b/proxy/http3/Http3Types.h @@ -28,11 +28,11 @@ #include enum class Http3StreamType : uint8_t { - CONTROL = 0x43, ///< HTTP/3 - QPACK_ENCODER = 0x48, ///< QPACK : encoder -> decoder - PUSH = 0x50, ///< HTTP/3 - QPACK_DECODER = 0x68, ///< QPACK : decoder -> encoder - RESERVED = 0x1F, + CONTROL = 0x00, ///< HTTP/3 + PUSH = 0x01, ///< HTTP/3 + QPACK_ENCODER = 0x02, ///< QPACK : encoder -> decoder + QPACK_DECODER = 0x03, ///< QPACK : decoder -> encoder + RESERVED = 0x21, UNKOWN = 0xFF, }; @@ -49,7 +49,7 @@ enum class Http3SettingsId : uint16_t { }; // Update Http3Frame::type(const uint8_t *) too when you modify this list -enum class Http3FrameType : uint8_t { +enum class Http3FrameType : uint64_t { DATA = 0x00, HEADERS = 0x01, PRIORITY = 0x02, From 6395120efa06258b8009d319a66f18d307e007ce Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 12 Apr 2019 15:33:39 +0900 Subject: [PATCH 1239/1313] Update H3 SETTINGS frame format to draft-19 --- proxy/http3/Http3Frame.cc | 11 ++++++----- proxy/http3/Http3Types.h | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc index 06153138a63..446387dc05d 100644 --- a/proxy/http3/Http3Frame.cc +++ b/proxy/http3/Http3Frame.cc @@ -228,8 +228,9 @@ Http3SettingsFrame::Http3SettingsFrame(const uint8_t *buf, size_t buf_len) : Htt size_t len = this->_payload_offset; while (len < buf_len) { - uint16_t id = QUICIntUtil::read_nbytes_as_uint(buf + len, 2); - len += 2; + size_t id_len = QUICVariableInt::size(buf + len); + uint16_t id = QUICIntUtil::read_QUICVariableInt(buf + len); + len += id_len; size_t value_len = QUICVariableInt::size(buf + len); uint64_t value = QUICIntUtil::read_QUICVariableInt(buf + len); @@ -238,7 +239,7 @@ Http3SettingsFrame::Http3SettingsFrame(const uint8_t *buf, size_t buf_len) : Htt // Ignore any SETTINGS identifier it does not understand. bool ignore = true; for (const auto &known_id : Http3SettingsFrame::VALID_SETTINGS_IDS) { - if (id == static_cast(known_id)) { + if (id == static_cast(known_id)) { ignore = false; break; } @@ -264,14 +265,14 @@ Http3SettingsFrame::store(uint8_t *buf, size_t *len) const size_t l = 0; for (auto &it : this->_settings) { - QUICIntUtil::write_uint_as_nbytes(static_cast(it.first), sizeof(uint16_t), p, &l); + QUICIntUtil::write_QUICVariableInt(static_cast(it.first), p, &l); p += l; QUICIntUtil::write_QUICVariableInt(it.second, p, &l); p += l; } // Exercise the requirement that unknown identifiers be ignored. - 4.2.5.1. - QUICIntUtil::write_uint_as_nbytes(static_cast(Http3SettingsId::UNKNOWN), sizeof(uint16_t), p, &l); + QUICIntUtil::write_QUICVariableInt(static_cast(Http3SettingsId::UNKNOWN), p, &l); p += l; QUICIntUtil::write_QUICVariableInt(0, p, &l); p += l; diff --git a/proxy/http3/Http3Types.h b/proxy/http3/Http3Types.h index 1ebbe8c3445..d753edbc3e0 100644 --- a/proxy/http3/Http3Types.h +++ b/proxy/http3/Http3Types.h @@ -36,7 +36,7 @@ enum class Http3StreamType : uint8_t { UNKOWN = 0xFF, }; -enum class Http3SettingsId : uint16_t { +enum class Http3SettingsId : uint64_t { HEADER_TABLE_SIZE = 0x01, ///< QPACK Settings RESERVED_1 = 0x02, ///< HTTP/3 Settings RESERVED_2 = 0x03, ///< HTTP/3 Settings From 31f60ade6cb8293e1b943b0b4afdddc7422890fb Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 12 Apr 2019 16:05:04 +0900 Subject: [PATCH 1240/1313] Update tests for H3 --- proxy/http3/Http3Frame.cc | 8 ++++-- proxy/http3/test/test_Http3Frame.cc | 40 ++++++++++++++--------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc index 446387dc05d..2f56b3fdb70 100644 --- a/proxy/http3/Http3Frame.cc +++ b/proxy/http3/Http3Frame.cc @@ -48,7 +48,7 @@ Http3Frame::type(const uint8_t *buf, size_t buf_len) size_t type_field_length = 0; int ret = QUICVariableInt::decode(type, type_field_length, buf, buf_len); ink_assert(ret != 1); - if (type <= static_cast(Http3FrameType::X_MAX_DEFINED)) { + if (type <= static_cast(Http3FrameType::X_MAX_DEFINED)) { return static_cast(type); } else { return Http3FrameType::UNKNOWN; @@ -92,7 +92,11 @@ Http3Frame::length() const Http3FrameType Http3Frame::type() const { - return this->_type; + if (static_cast(this->_type) <= static_cast(Http3FrameType::X_MAX_DEFINED)) { + return this->_type; + } else { + return Http3FrameType::UNKNOWN; + } } void diff --git a/proxy/http3/test/test_Http3Frame.cc b/proxy/http3/test/test_Http3Frame.cc index 48f02aec2c3..c9a606ab3df 100644 --- a/proxy/http3/test/test_Http3Frame.cc +++ b/proxy/http3/test/test_Http3Frame.cc @@ -30,8 +30,8 @@ TEST_CASE("Http3Frame Type", "[http3]") { CHECK(Http3Frame::type(reinterpret_cast("\x00\x00"), 2) == Http3FrameType::DATA); // Undefined ragne - CHECK(Http3Frame::type(reinterpret_cast("\x00\x0f"), 2) == Http3FrameType::UNKNOWN); - CHECK(Http3Frame::type(reinterpret_cast("\x00\xff"), 2) == Http3FrameType::UNKNOWN); + CHECK(Http3Frame::type(reinterpret_cast("\x0f\x00"), 2) == Http3FrameType::UNKNOWN); + CHECK(Http3Frame::type(reinterpret_cast("\xff\xff\xff\xff\xff\xff\xff\x00"), 9) == Http3FrameType::UNKNOWN); } TEST_CASE("Load DATA Frame", "[http3]") @@ -39,8 +39,8 @@ TEST_CASE("Load DATA Frame", "[http3]") SECTION("No flags") { uint8_t buf1[] = { - 0x04, // Length 0x00, // Type + 0x04, // Length 0x11, 0x22, 0x33, 0x44, // Payload }; std::shared_ptr frame1 = Http3FrameFactory::create(buf1, sizeof(buf1)); @@ -56,8 +56,8 @@ TEST_CASE("Load DATA Frame", "[http3]") SECTION("Have flags (invalid)") { uint8_t buf1[] = { - 0x04, // Length 0x00, // Type + 0x04, // Length 0x11, 0x22, 0x33, 0x44, // Payload }; std::shared_ptr frame1 = Http3FrameFactory::create(buf1, sizeof(buf1)); @@ -78,8 +78,8 @@ TEST_CASE("Store DATA Frame", "[http3]") uint8_t buf[32] = {0}; size_t len; uint8_t expected1[] = { - 0x04, // Length 0x00, // Type + 0x04, // Length 0x11, 0x22, 0x33, 0x44, // Payload }; @@ -103,8 +103,8 @@ TEST_CASE("Store HEADERS Frame", "[http3]") uint8_t buf[32] = {0}; size_t len; uint8_t expected1[] = { - 0x04, // Length 0x01, // Type + 0x04, // Length 0x11, 0x22, 0x33, 0x44, // Payload }; @@ -126,13 +126,13 @@ TEST_CASE("Load SETTINGS Frame", "[http3]") SECTION("Normal") { uint8_t buf[] = { - 0x0a, // Length 0x04, // Type - 0x00, 0x06, // Identifier + 0x08, // Length + 0x06, // Identifier 0x44, 0x00, // Value - 0x00, 0x08, // Identifier + 0x08, // Identifier 0x0f, // Value - 0xba, 0xba, // Identifier + 0x4a, 0xba, // Identifier 0x00, // Value }; @@ -153,13 +153,13 @@ TEST_CASE("Store SETTINGS Frame", "[http3]") SECTION("Normal") { uint8_t expected[] = { - 0x0a, // Length 0x04, // Type - 0x00, 0x06, // Identifier + 0x08, // Length + 0x06, // Identifier 0x44, 0x00, // Value - 0x00, 0x08, // Identifier + 0x08, // Identifier 0x0f, // Value - 0x0a, 0x0a, // Identifier + 0x4a, 0x0a, // Identifier 0x00, // Value }; @@ -177,11 +177,11 @@ TEST_CASE("Store SETTINGS Frame", "[http3]") SECTION("Normal from Client") { uint8_t expected[] = { - 0x07, // Length 0x04, // Type - 0x00, 0x06, // Identifier + 0x06, // Length + 0x06, // Identifier 0x44, 0x00, // Value - 0x0a, 0x0a, // Identifier + 0x4a, 0x0a, // Identifier 0x00, // Value }; @@ -199,8 +199,8 @@ TEST_CASE("Store SETTINGS Frame", "[http3]") TEST_CASE("Http3FrameFactory Create Unknown Frame", "[http3]") { uint8_t buf1[] = { + 0x0f, // Type 0x00, // Length - 0xff, // Type }; std::shared_ptr frame1 = Http3FrameFactory::create(buf1, sizeof(buf1)); CHECK(frame1); @@ -213,13 +213,13 @@ TEST_CASE("Http3FrameFactory Fast Create Frame", "[http3]") Http3FrameFactory factory; uint8_t buf1[] = { - 0x04, // Length 0x00, // Type + 0x04, // Length 0x11, 0x22, 0x33, 0x44, // Payload }; uint8_t buf2[] = { - 0x04, // Length 0x00, // Type + 0x04, // Length 0xaa, 0xbb, 0xcc, 0xdd, // Payload }; std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); From d57c17c83cb5e1de59d61d73221c6a223cae385b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 14 Feb 2019 16:18:09 +0900 Subject: [PATCH 1241/1313] Add keylog support on QUIC client --- iocore/net/QUICNetVConnection.cc | 4 +- iocore/net/quic/QUICConfig.cc | 21 +++++-- iocore/net/quic/QUICConfig.h | 6 +- iocore/net/quic/QUICGlobals.cc | 18 ++++++ iocore/net/quic/QUICGlobals.h | 1 + iocore/net/quic/QUICTLS.cc | 6 ++ iocore/net/quic/QUICTLS.h | 7 ++- iocore/net/quic/QUICTLS_openssl.cc | 90 ++++++++++++++++++++++++++---- mgmt/RecordsConfig.cc | 2 + 9 files changed, 133 insertions(+), 22 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 6a2312821f3..799b9946eea 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -2236,8 +2236,10 @@ QUICNetVConnection::_setup_handshake_protocol(SSL_CTX *ctx) { // Initialize handshake protocol specific stuff // For QUICv1 TLS is the only option - QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx, this->direction(), this->options, this->_quic_config->session_file()); + QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx, 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(this)); + return tls; } diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 0213cee9b1e..86e97070366 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -82,11 +82,17 @@ quic_init_client_ssl_ctx(const QUICConfigParams *params) } } - if (params->session_file() != nullptr) { + if (params->client_session_file() != nullptr) { SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE); SSL_CTX_sess_set_new_cb(ssl_ctx, QUIC::ssl_client_new_session); } +#ifdef SSL_MODE_QUIC_HACK + if (params->client_keylog_file() != nullptr) { + SSL_CTX_set_keylog_callback(ssl_ctx, QUIC::ssl_client_keylog_cb); + } +#endif + return ssl_ctx; } @@ -113,7 +119,8 @@ QUICConfigParams::initialize() 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->_session_file, "proxy.config.quic.client.session_file"); + REC_ReadConfigStringAlloc(this->_client_session_file, "proxy.config.quic.client.session_file"); + REC_ReadConfigStringAlloc(this->_client_keylog_file, "proxy.config.quic.client.keylog_file"); // Transport Parameters REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_in, "proxy.config.quic.no_activity_timeout_in"); @@ -417,9 +424,15 @@ QUICConfigParams::scid_len() } const char * -QUICConfigParams::session_file() const +QUICConfigParams::client_session_file() const +{ + return this->_client_session_file; +} + +const char * +QUICConfigParams::client_keylog_file() const { - return _session_file; + return this->_client_keylog_file; } // diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index 4ab237a9b1b..c56d74f76bf 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -45,7 +45,8 @@ class QUICConfigParams : public ConfigInfo const char *server_supported_groups() const; const char *client_supported_groups() const; - const char *session_file() const; + const char *client_session_file() const; + const char *client_keylog_file() const; SSL_CTX *client_ssl_ctx() const; @@ -100,7 +101,8 @@ class QUICConfigParams : public ConfigInfo char *_server_supported_groups = nullptr; char *_client_supported_groups = nullptr; - char *_session_file = nullptr; + char *_client_session_file = nullptr; + char *_client_keylog_file = nullptr; SSL_CTX *_client_ssl_ctx = nullptr; diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index 0798020d165..661f816a57e 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -24,6 +24,7 @@ #include "QUICGlobals.h" #include +#include #include "P_SSLNextProtocolSet.h" @@ -85,6 +86,23 @@ QUIC::ssl_client_new_session(SSL *ssl, SSL_SESSION *session) return 0; } +void +QUIC::ssl_client_keylog_cb(const SSL *ssl, const char *line) +{ + QUICTLS *qtls = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_tls_index)); + const char *keylog_file = qtls->keylog_file(); + std::ofstream file(keylog_file, std::ios_base::app); + + if (!file.is_open()) { + QUICGlobalDebug("could not open keylog file: %s", keylog_file); + return; + } + + file.write(line, strlen(line)); + file.put('\n'); + file.flush(); +} + int QUIC::ssl_cert_cb(SSL *ssl, void * /*arg*/) { diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h index cd4ac546f2a..0bbde28373d 100644 --- a/iocore/net/quic/QUICGlobals.h +++ b/iocore/net/quic/QUICGlobals.h @@ -34,6 +34,7 @@ class QUIC static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen, void *); static int ssl_client_new_session(SSL *ssl, SSL_SESSION *session); + static void ssl_client_keylog_cb(const SSL *ssl, const char *line); static int ssl_cert_cb(SSL *ssl, void *arg); static int ssl_sni_cb(SSL *ssl, int *ad, void *arg); diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index de11e02ebd7..f03a5a7bac3 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -68,6 +68,12 @@ QUICTLS::session_file() const return this->_session_file; } +const char * +QUICTLS::keylog_file() const +{ + return this->_keylog_file; +} + QUICTLS::~QUICTLS() { SSL_free(this->_ssl); diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h index 5a2ac563ba0..7bba45aff38 100644 --- a/iocore/net/quic/QUICTLS.h +++ b/iocore/net/quic/QUICTLS.h @@ -40,7 +40,7 @@ class QUICTLS : public QUICHandshakeProtocol { public: QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx, - const NetVCOptions &netvc_options, const char *session_file = nullptr); + const NetVCOptions &netvc_options, const char *session_file = nullptr, const char *keylog_file = nullptr); ~QUICTLS(); // TODO: integrate with _early_data_processed @@ -58,6 +58,7 @@ class QUICTLS : public QUICHandshakeProtocol void set_remote_transport_parameters(std::shared_ptr tp) override; const char *session_file() const; + const char *keylog_file() const; // FIXME Should not exist SSL *ssl_handle(); @@ -79,8 +80,6 @@ class QUICTLS : public QUICHandshakeProtocol QUICKeyGenerator _keygen_for_server = QUICKeyGenerator(QUICKeyGenerator::Context::SERVER); const EVP_MD *_get_handshake_digest() const; - const char *_session_file; - int _read_early_data(); int _write_early_data(); int _handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in); @@ -94,6 +93,8 @@ class QUICTLS : public QUICHandshakeProtocol void _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 = nullptr, size_t secret_len = 0); + const char *_session_file = nullptr; + const char *_keylog_file = nullptr; SSL *_ssl = nullptr; NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET; bool _early_data_processed = false; diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 94e1867307f..7f7c9613459 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -20,8 +20,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "QUICGlobals.h" -#include "QUICPacketProtectionKeyInfo.h" #include "QUICTLS.h" #include @@ -31,11 +29,21 @@ #include #include "QUICConfig.h" - +#include "QUICGlobals.h" #include "QUICDebugNames.h" +#include "QUICPacketProtectionKeyInfo.h" static constexpr char tag[] = "quic_tls"; +using namespace std::literals; + +static constexpr std::string_view QUIC_CLIENT_EARLY_TRAFFIC_SECRET_LABEL("QUIC_CLIENT_EARLY_TRAFFIC_SECRET"sv); +static constexpr std::string_view QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET_LABEL("QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET"sv); +static constexpr std::string_view QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET_LABEL("QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET"sv); +// TODO: support key update +static constexpr std::string_view QUIC_CLIENT_TRAFFIC_SECRET_LABEL("QUIC_CLIENT_TRAFFIC_SECRET_0"sv); +static constexpr std::string_view QUIC_SERVER_TRAFFIC_SECRET_LABEL("QUIC_SERVER_TRAFFIC_SECRET_0"sv); + static const char * content_type_str(int type) { @@ -139,6 +147,58 @@ msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, return; } +/** + This is very inspired from writting keylog format of ngtcp2's examples + https://github.com/ngtcp2/ngtcp2/blob/894ed23c970d61eede74f69d9178090af63fdf70/examples/keylog.cc + */ +static void +log_secret(SSL *ssl, int name, const unsigned char *secret, size_t secretlen) +{ + if (auto keylog_cb = SSL_CTX_get_keylog_callback(SSL_get_SSL_CTX(ssl))) { + unsigned char crandom[32]; + if (SSL_get_client_random(ssl, crandom, sizeof(crandom)) != sizeof(crandom)) { + return; + } + uint8_t line[256] = {0}; + size_t len = 0; + switch (name) { + case SSL_KEY_CLIENT_EARLY_TRAFFIC: + memcpy(line, QUIC_CLIENT_EARLY_TRAFFIC_SECRET_LABEL.data(), QUIC_CLIENT_EARLY_TRAFFIC_SECRET_LABEL.size()); + len += QUIC_CLIENT_EARLY_TRAFFIC_SECRET_LABEL.size(); + break; + case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: + memcpy(line, QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET_LABEL.data(), QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET_LABEL.size()); + len += QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET_LABEL.size(); + break; + case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC: + memcpy(line, QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET_LABEL.data(), QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET_LABEL.size()); + len += QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET_LABEL.size(); + break; + case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: + memcpy(line, QUIC_CLIENT_TRAFFIC_SECRET_LABEL.data(), QUIC_CLIENT_TRAFFIC_SECRET_LABEL.size()); + len += QUIC_CLIENT_TRAFFIC_SECRET_LABEL.size(); + break; + case SSL_KEY_SERVER_APPLICATION_TRAFFIC: + memcpy(line, QUIC_SERVER_TRAFFIC_SECRET_LABEL.data(), QUIC_SERVER_TRAFFIC_SECRET_LABEL.size()); + len += QUIC_SERVER_TRAFFIC_SECRET_LABEL.size(); + break; + + default: + return; + } + + line[len] = ' '; + ++len; + QUICDebug::to_hex(line + len, crandom, sizeof(crandom)); + len += sizeof(crandom) * 2; + line[len] = ' '; + ++len; + QUICDebug::to_hex(line + len, secret, secretlen); + + keylog_cb(ssl, reinterpret_cast(line)); + } +} + static int key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, void *arg) { @@ -149,6 +209,8 @@ key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, void QUICTLS *qtls = reinterpret_cast(arg); qtls->update_key_materials_on_key_cb(name, secret, secret_len); + log_secret(ssl, name, secret, secret_len); + return 1; } @@ -158,19 +220,19 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t if (is_debug_tag_set("vv_quic_crypto")) { switch (name) { case SSL_KEY_CLIENT_EARLY_TRAFFIC: - Debug("vv_quic_crypto", "client_early_traffic"); + Debug("vv_quic_crypto", "%s", QUIC_CLIENT_EARLY_TRAFFIC_SECRET_LABEL.data()); break; case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC: - Debug("vv_quic_crypto", "client_handshake_traffic"); - break; - case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: - Debug("vv_quic_crypto", "client_application_traffic"); + Debug("vv_quic_crypto", "%s", QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET_LABEL.data()); break; case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC: - Debug("vv_quic_crypto", "server_handshake_traffic"); + Debug("vv_quic_crypto", "%s", QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET_LABEL.data()); + break; + case SSL_KEY_CLIENT_APPLICATION_TRAFFIC: + Debug("vv_quic_crypto", "%s", QUIC_CLIENT_TRAFFIC_SECRET_LABEL.data()); break; case SSL_KEY_SERVER_APPLICATION_TRAFFIC: - Debug("vv_quic_crypto", "server_application_traffic"); + Debug("vv_quic_crypto", "%s", QUIC_SERVER_TRAFFIC_SECRET_LABEL.data()); break; default: break; @@ -329,8 +391,12 @@ QUICTLS::update_key_materials_on_key_cb(int name, const uint8_t *secret, size_t } QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx, - const NetVCOptions &netvc_options, const char *session_file) - : QUICHandshakeProtocol(pp_key_info), _session_file(session_file), _ssl(SSL_new(ssl_ctx)), _netvc_context(nvc_ctx) + const NetVCOptions &netvc_options, const char *session_file, const char *keylog_file) + : QUICHandshakeProtocol(pp_key_info), + _session_file(session_file), + _keylog_file(keylog_file), + _ssl(SSL_new(ssl_ctx)), + _netvc_context(nvc_ctx) { ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 982bb8a7388..5094613aa3c 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1372,6 +1372,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.client.session_file", RECD_STRING, nullptr , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.client.keylog_file", RECD_STRING, nullptr , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} + , // Transport Parameters {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_in", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , From 033ec0e42cb1ba5cef670c0f2ebe384efa3180c3 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 15 Apr 2019 09:29:17 +0900 Subject: [PATCH 1242/1313] Add @HWLOC_LIBS@ to LDADD for HTTP/3 check programs --- proxy/http3/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index 324d88ece2e..5132e4564e0 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -79,7 +79,8 @@ test_LDADD = \ $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ $(top_builddir)/proxy/libproxy.a \ - $(top_builddir)/proxy/hdrs/libhdrs.a + $(top_builddir)/proxy/hdrs/libhdrs.a \ + @HWLOC_LIBS@ test_libhttp3_CPPFLAGS = $(test_CPPFLAGS) test_libhttp3_LDFLAGS = @AM_LDFLAGS@ From 4180a956490350c9fb4ab2a9f07224b989cc1a59 Mon Sep 17 00:00:00 2001 From: scw00 Date: Wed, 10 Apr 2019 06:50:29 +0000 Subject: [PATCH 1243/1313] QUIC: Uses unidirectional stream to send HTTP3 SETTINGS frames --- iocore/eventsystem/I_Thread.h | 2 + iocore/net/quic/Makefile.am | 3 +- iocore/net/quic/QUICApplication.cc | 17 ++++- iocore/net/quic/QUICBidirectionalStream.h | 2 + iocore/net/quic/QUICStream.cc | 8 ++- iocore/net/quic/QUICStream.h | 1 + iocore/net/quic/QUICStreamFactory.cc | 84 ++++++++++++++++++++++ iocore/net/quic/QUICStreamFactory.h | 46 ++++++++++++ iocore/net/quic/QUICStreamManager.cc | 15 ++-- iocore/net/quic/QUICStreamManager.h | 9 +-- iocore/net/quic/QUICTypes.cc | 22 ++++++ iocore/net/quic/QUICTypes.h | 12 ++++ iocore/net/quic/QUICUnidirectionalStream.h | 5 ++ 13 files changed, 209 insertions(+), 17 deletions(-) create mode 100644 iocore/net/quic/QUICStreamFactory.cc create mode 100644 iocore/net/quic/QUICStreamFactory.h diff --git a/iocore/eventsystem/I_Thread.h b/iocore/eventsystem/I_Thread.h index 86912063089..8153acf786b 100644 --- a/iocore/eventsystem/I_Thread.h +++ b/iocore/eventsystem/I_Thread.h @@ -125,6 +125,8 @@ class Thread ProxyAllocator quicClientSessionAllocator; ProxyAllocator quicHandshakeAllocator; ProxyAllocator quicBidiStreamAllocator; + ProxyAllocator quicSendStreamAllocator; + ProxyAllocator quicReceiveStreamAllocator; ProxyAllocator quicStreamManagerAllocator; ProxyAllocator httpServerSessionAllocator; ProxyAllocator hdrHeapAllocator; diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 4a806975136..9fd6b2761c3 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -89,7 +89,8 @@ libquic_a_SOURCES = \ QUICAddrVerifyState.cc \ QUICBidirectionalStream.cc \ QUICCryptoStream.cc \ - QUICUnidirectionalStream.cc + QUICUnidirectionalStream.cc \ + QUICStreamFactory.cc # # Check Programs diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 9b02b8caa74..9039b998f3f 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -42,8 +42,21 @@ QUICStreamIO::QUICStreamIO(QUICApplication *app, QUICStreamVConnection *stream_v this->_read_buffer_reader = this->_read_buffer->alloc_reader(); this->_write_buffer_reader = this->_write_buffer->alloc_reader(); - this->_read_vio = stream_vc->do_io_read(app, INT64_MAX, this->_read_buffer); - this->_write_vio = stream_vc->do_io_write(app, INT64_MAX, this->_write_buffer_reader); + switch (stream_vc->direction()) { + case QUICStreamDirection::BIDIRECTIONAL: + this->_read_vio = stream_vc->do_io_read(app, INT64_MAX, this->_read_buffer); + this->_write_vio = stream_vc->do_io_write(app, INT64_MAX, this->_write_buffer_reader); + break; + case QUICStreamDirection::SEND: + this->_write_vio = stream_vc->do_io_write(app, INT64_MAX, this->_write_buffer_reader); + break; + case QUICStreamDirection::RECEIVE: + this->_read_vio = stream_vc->do_io_read(app, INT64_MAX, this->_read_buffer); + break; + default: + ink_assert(false); + break; + } } QUICStreamIO::~QUICStreamIO() diff --git a/iocore/net/quic/QUICBidirectionalStream.h b/iocore/net/quic/QUICBidirectionalStream.h index b756f21c90f..ed583bdee8c 100644 --- a/iocore/net/quic/QUICBidirectionalStream.h +++ b/iocore/net/quic/QUICBidirectionalStream.h @@ -38,6 +38,8 @@ class QUICBidirectionalStream : public QUICStreamVConnection, public QUICTransfe { } + ~QUICBidirectionalStream() {} + int state_stream_open(int event, void *data); int state_stream_closed(int event, void *data); diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc index 3c98ef4d61b..334b9f41bca 100644 --- a/iocore/net/quic/QUICStream.cc +++ b/iocore/net/quic/QUICStream.cc @@ -37,6 +37,12 @@ QUICStream::id() const return this->_id; } +QUICStreamDirection +QUICStream::direction() const +{ + return QUICTypeUtil::detect_stream_direction(this->_id, this->_connection_info->direction()); +} + const QUICConnectionInfoProvider * QUICStream::connection_info() const { @@ -46,7 +52,7 @@ QUICStream::connection_info() const bool QUICStream::is_bidirectional() const { - return (this->_id & 0x03) < 0x02; + return ((this->_id & 0x03) < 0x02); } QUICOffset diff --git a/iocore/net/quic/QUICStream.h b/iocore/net/quic/QUICStream.h index fda00bf1404..bff660a0b6d 100644 --- a/iocore/net/quic/QUICStream.h +++ b/iocore/net/quic/QUICStream.h @@ -49,6 +49,7 @@ class QUICStream : public QUICFrameGenerator, public QUICFrameRetransmitter virtual ~QUICStream(); QUICStreamId id() const; + QUICStreamDirection direction() const; const QUICConnectionInfoProvider *connection_info() const; bool is_bidirectional() const; QUICOffset final_offset() const; diff --git a/iocore/net/quic/QUICStreamFactory.cc b/iocore/net/quic/QUICStreamFactory.cc new file mode 100644 index 00000000000..9762895eb78 --- /dev/null +++ b/iocore/net/quic/QUICStreamFactory.cc @@ -0,0 +1,84 @@ +/** @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 "QUICStream.h" +#include "QUICBidirectionalStream.h" +#include "QUICUnidirectionalStream.h" +#include "QUICStreamFactory.h" + +ClassAllocator quicBidiStreamAllocator("quicBidiStreamAllocator"); +ClassAllocator quicSendStreamAllocator("quicSendStreamAllocator"); +ClassAllocator quicReceiveStreamAllocator("quicReceiveStreamAllocator"); + +QUICStreamVConnection * +QUICStreamFactory::create(QUICStreamId sid, uint64_t local_max_stream_data, uint64_t remote_max_stream_data) +{ + QUICStreamVConnection *stream = nullptr; + switch (QUICTypeUtil::detect_stream_direction(sid, this->_info->direction())) { + case QUICStreamDirection::BIDIRECTIONAL: + // TODO Free the stream somewhere + stream = THREAD_ALLOC(quicBidiStreamAllocator, this_ethread()); + new (stream) QUICBidirectionalStream(this->_rtt_provider, this->_info, sid, local_max_stream_data, remote_max_stream_data); + break; + case QUICStreamDirection::SEND: + // TODO Free the stream somewhere + stream = THREAD_ALLOC(quicSendStreamAllocator, this_ethread()); + new (stream) QUICSendStream(this->_info, sid, remote_max_stream_data); + break; + case QUICStreamDirection::RECEIVE: + // server side + // TODO Free the stream somewhere + stream = THREAD_ALLOC(quicReceiveStreamAllocator, this_ethread()); + new (stream) QUICReceiveStream(this->_rtt_provider, this->_info, sid, local_max_stream_data); + break; + default: + ink_assert(false); + break; + } + + return stream; +} + +void +QUICStreamFactory::delete_stream(QUICStreamVConnection *stream) +{ + if (!stream) { + return; + } + + stream->~QUICStreamVConnection(); + switch (stream->direction()) { + case QUICStreamDirection::BIDIRECTIONAL: + THREAD_FREE(static_cast(stream), quicBidiStreamAllocator, this_thread()); + break; + case QUICStreamDirection::SEND: + THREAD_FREE(static_cast(stream), quicSendStreamAllocator, this_thread()); + break; + case QUICStreamDirection::RECEIVE: + THREAD_FREE(static_cast(stream), quicReceiveStreamAllocator, this_thread()); + break; + default: + ink_assert(false); + break; + } +} diff --git a/iocore/net/quic/QUICStreamFactory.h b/iocore/net/quic/QUICStreamFactory.h new file mode 100644 index 00000000000..fd497bf2b1a --- /dev/null +++ b/iocore/net/quic/QUICStreamFactory.h @@ -0,0 +1,46 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "QUICTypes.h" + +class QUICStreamVConnection; + +// PS: this class function should not static because of THREAD_ALLOC and THREAD_FREE +class QUICStreamFactory +{ +public: + QUICStreamFactory(QUICRTTProvider *rtt_provider, QUICConnectionInfoProvider *info) : _rtt_provider(rtt_provider), _info(info) {} + ~QUICStreamFactory() {} + + // create a bidistream, send only stream or receive only stream + QUICStreamVConnection *create(QUICStreamId sid, uint64_t recv_max_stream_data, uint64_t send_max_stream_data); + + // delete stream by stream type + void delete_stream(QUICStreamVConnection *stream); + +private: + QUICRTTProvider *_rtt_provider = nullptr; + QUICConnectionInfoProvider *_info = nullptr; +}; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index a4d3188052b..22e6c2fed67 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -30,10 +30,9 @@ static constexpr char tag[] = "quic_stream_manager"; static constexpr QUICStreamId QUIC_STREAM_TYPES = 4; ClassAllocator quicStreamManagerAllocator("quicStreamManagerAllocator"); -ClassAllocator quicBidiStreamAllocator("quicStreamAllocator"); QUICStreamManager::QUICStreamManager(QUICConnectionInfoProvider *info, QUICRTTProvider *rtt_provider, QUICApplicationMap *app_map) - : _info(info), _rtt_provider(rtt_provider), _app_map(app_map) + : _stream_factory(rtt_provider, info), _info(info), _app_map(app_map) { if (this->_info->direction() == NET_VCONNECTION_OUT) { this->_next_stream_id_bidi = static_cast(QUICStreamType::CLIENT_BIDI); @@ -309,7 +308,6 @@ QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id) local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); } - break; case QUICStreamType::SERVER_UNI: if (this->_remote_max_streams_uni == 0 || stream_id > this->_remote_max_streams_uni) { @@ -318,15 +316,14 @@ QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id) local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); - + break; + default: + ink_release_assert(false); break; } - // TODO Free the stream somewhere - stream = THREAD_ALLOC(quicBidiStreamAllocator, this_ethread()); - new (stream) - QUICBidirectionalStream(this->_rtt_provider, this->_info, stream_id, local_max_stream_data, remote_max_stream_data); - + stream = this->_stream_factory.create(stream_id, local_max_stream_data, remote_max_stream_data); + ink_assert(stream != nullptr); this->stream_list.push(stream); } diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 26e4396c649..d618afb7f35 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -25,19 +25,19 @@ #include "QUICTypes.h" #include "QUICBidirectionalStream.h" +#include "QUICUnidirectionalStream.h" #include "QUICApplicationMap.h" #include "QUICFrameHandler.h" #include "QUICFrame.h" +#include "QUICStreamFactory.h" #include "QUICLossDetector.h" -extern ClassAllocator quicBidiStreamAllocator; - class QUICTransportParameters; class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator { public: - QUICStreamManager(){}; + QUICStreamManager() : _stream_factory(nullptr, nullptr){}; QUICStreamManager(QUICConnectionInfoProvider *info, QUICRTTProvider *rtt_provider, QUICApplicationMap *app_map); void init_flow_control_params(const std::shared_ptr &local_tp, @@ -86,8 +86,9 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator }; } + QUICStreamFactory _stream_factory; + QUICConnectionInfoProvider *_info = nullptr; - QUICRTTProvider *_rtt_provider = nullptr; QUICApplicationMap *_app_map = nullptr; std::shared_ptr _local_tp = nullptr; std::shared_ptr _remote_tp = nullptr; diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 85dedd61f4e..28c363ad1b0 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -68,6 +68,28 @@ QUICTypeUtil::detect_stream_type(QUICStreamId id) return static_cast(type); } +QUICStreamDirection +QUICTypeUtil::detect_stream_direction(QUICStreamId id, NetVConnectionContext_t context) +{ + switch (QUICTypeUtil::detect_stream_type(id)) { + case QUICStreamType::CLIENT_BIDI: + case QUICStreamType::SERVER_BIDI: + return QUICStreamDirection::BIDIRECTIONAL; + case QUICStreamType::CLIENT_UNI: + if (context == NET_VCONNECTION_OUT) { + return QUICStreamDirection::SEND; + } + return QUICStreamDirection::RECEIVE; + case QUICStreamType::SERVER_UNI: + if (context == NET_VCONNECTION_IN) { + return QUICStreamDirection::SEND; + } + return QUICStreamDirection::RECEIVE; + default: + return QUICStreamDirection::UNKNOWN; + } +} + QUICEncryptionLevel QUICTypeUtil::encryption_level(QUICPacketType type) { diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 3369854ed4b..76d087477e0 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -26,6 +26,10 @@ #include #include "tscore/ink_endian.h" #include "tscore/ink_hrtime.h" +#include "tscore/Ptr.h" +#include "I_EventSystem.h" + +#include "I_NetVConnection.h" #include #include @@ -431,6 +435,13 @@ enum class QUICStreamType : uint8_t { SERVER_UNI, }; +enum class QUICStreamDirection : uint8_t { + UNKNOWN = 0, + SEND, + RECEIVE, + BIDIRECTIONAL, +}; + class QUICFiveTuple { public: @@ -489,6 +500,7 @@ class QUICTypeUtil public: static bool is_supported_version(QUICVersion version); static QUICStreamType detect_stream_type(QUICStreamId id); + static QUICStreamDirection detect_stream_direction(QUICStreamId id, NetVConnectionContext_t context); static QUICEncryptionLevel encryption_level(QUICPacketType type); static QUICPacketType packet_type(QUICEncryptionLevel level); static QUICKeyPhase key_phase(QUICPacketType type); diff --git a/iocore/net/quic/QUICUnidirectionalStream.h b/iocore/net/quic/QUICUnidirectionalStream.h index 6c324a7ea77..0c7162742a6 100644 --- a/iocore/net/quic/QUICUnidirectionalStream.h +++ b/iocore/net/quic/QUICUnidirectionalStream.h @@ -30,6 +30,9 @@ class QUICSendStream : public QUICStreamVConnection public: QUICSendStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid, uint64_t send_max_stream_data); QUICSendStream() : _remote_flow_controller(0, 0), _state(nullptr, nullptr) {} + + ~QUICSendStream() {} + int state_stream_open(int event, void *data); int state_stream_closed(int event, void *data); @@ -77,6 +80,8 @@ class QUICReceiveStream : public QUICStreamVConnection, public QUICTransferProgr uint64_t recv_max_stream_data); QUICReceiveStream() : _local_flow_controller(nullptr, 0, 0), _state(nullptr, nullptr) {} + ~QUICReceiveStream() {} + int state_stream_open(int event, void *data); int state_stream_closed(int event, void *data); From 4738bef618c38015b25ac1f74a805fb6f989ed52 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 15 Apr 2019 11:49:04 +0900 Subject: [PATCH 1244/1313] Fix a strange link issue in unit tests on release build --- iocore/net/quic/test/test_QUICHandshakeProtocol.cc | 6 ++++++ iocore/net/quic/test/test_QUICPacketHeaderProtector.cc | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index aac2e6cd298..fa13302038a 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -39,6 +39,12 @@ #include "QUICPacketProtectionKeyInfo.h" #include "QUICTLS.h" +// XXX For NetVCOptions::reset +struct PollCont; +#include "P_UDPConnection.h" +#include "P_UnixNet.h" +#include "P_UnixNetVConnection.h" + // depends on size of cert static constexpr uint32_t MAX_HANDSHAKE_MSG_LEN = 8192; diff --git a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc index 52aed26d906..9b7c0c4114d 100644 --- a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc @@ -27,6 +27,11 @@ #include "QUICPacketHeaderProtector.h" #include "QUICTLS.h" +struct PollCont; +#include "P_UDPConnection.h" +#include "P_UnixNet.h" +#include "P_UnixNetVConnection.h" + // depends on size of cert static constexpr uint32_t MAX_HANDSHAKE_MSG_LEN = 8192; From c0d60aa4b387410152e15f07b37453c49c96270d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 15 Apr 2019 16:16:25 +0900 Subject: [PATCH 1245/1313] Add stubs for http3 unit tests --- iocore/net/libinknet_stub.cc | 7 +++ proxy/http3/Makefile.am | 5 ++ proxy/http3/test/stub.cc | 117 +++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 proxy/http3/test/stub.cc diff --git a/iocore/net/libinknet_stub.cc b/iocore/net/libinknet_stub.cc index 91fbf1f8db4..d821cf80b7a 100644 --- a/iocore/net/libinknet_stub.cc +++ b/iocore/net/libinknet_stub.cc @@ -161,3 +161,10 @@ ProcessManager::signalManager(int, char const *, int) ink_assert(false); return; } + +void +ProcessManager::signalManager(int, char const *) +{ + ink_assert(false); + return; +} diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index 5132e4564e0..bccc2d9e181 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -78,8 +78,11 @@ test_LDADD = \ $(top_builddir)/src/tscpp/util/libtscpputil.la \ $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ + $(top_builddir)/proxy/libhttp2.a \ $(top_builddir)/proxy/libproxy.a \ $(top_builddir)/proxy/hdrs/libhdrs.a \ + @LIBPCRE@ \ + @OPENSSL_LIBS@ \ @HWLOC_LIBS@ test_libhttp3_CPPFLAGS = $(test_CPPFLAGS) @@ -88,6 +91,7 @@ test_libhttp3_LDADD = $(test_LDADD) test_libhttp3_SOURCES = \ ./test/main.cc \ ./test/test_Http3Frame.cc \ + ./test/stub.cc \ ../http/HttpConfig.cc \ ../http/HttpConnectionCount.cc \ ../http/ForwardedConfig.cc \ @@ -99,6 +103,7 @@ test_qpack_LDADD = $(test_LDADD) test_qpack_SOURCES = \ ./test/main_qpack.cc \ ./test/test_QPACK.cc \ + ./test/stub.cc \ ../http/HttpConfig.cc \ ../http/HttpConnectionCount.cc \ ../http/ForwardedConfig.cc \ diff --git a/proxy/http3/test/stub.cc b/proxy/http3/test/stub.cc new file mode 100644 index 00000000000..cfbf5fba875 --- /dev/null +++ b/proxy/http3/test/stub.cc @@ -0,0 +1,117 @@ +/** @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. + */ + +// FIXME: remove stub + +#include "I_EventSystem.h" +#include "InkAPIInternal.h" + +void +APIHooks::clear() +{ + ink_abort("do not call stub"); +} + +void +APIHooks::append(INKContInternal *) +{ + ink_abort("do not call stub"); +} + +void +APIHooks::prepend(INKContInternal *) +{ + ink_abort("do not call stub"); +} + +#include "HttpDebugNames.h" +const char * +HttpDebugNames::get_api_hook_name(TSHttpHookID t) +{ + return "dummy"; +} + +#include "HttpSM.h" +HttpSM::HttpSM() : Continuation(nullptr), vc_table(this) {} + +void +HttpSM::cleanup() +{ + ink_abort("do not call stub"); +} + +void +HttpSM::destroy() +{ + ink_abort("do not call stub"); +} + +void +HttpSM::set_next_state() +{ + ink_abort("do not call stub"); +} + +void +HttpSM::handle_api_return() +{ + ink_abort("do not call stub"); +} + +int +HttpSM::kill_this_async_hook(int /* event ATS_UNUSED */, void * /* data ATS_UNUSED */) +{ + return EVENT_DONE; +} + +void +HttpSM::attach_client_session(ProxyClientTransaction *, IOBufferReader *) +{ + ink_abort("do not call stub"); +} + +void +HttpSM::init() +{ + ink_abort("do not call stub"); +} + +ClassAllocator httpSMAllocator("httpSMAllocator"); +HttpAPIHooks *http_global_hooks; + +HttpVCTable::HttpVCTable(HttpSM *) {} + +PostDataBuffers::~PostDataBuffers() {} + +HttpTunnel::HttpTunnel() : Continuation(nullptr) {} +HttpTunnelConsumer::HttpTunnelConsumer() {} +HttpTunnelProducer::HttpTunnelProducer() {} +ChunkedHandler::ChunkedHandler() {} + +HttpCacheSM::HttpCacheSM() {} + +HttpCacheAction::HttpCacheAction() : sm(nullptr) {} +void +HttpCacheAction::cancel(Continuation *c) +{ +} From 22b77e9f04d2f6033661eb98a6739ca249ba45c4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 15 Apr 2019 16:25:39 +0900 Subject: [PATCH 1246/1313] Fix a wrong path for libhttp2.a --- proxy/http3/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index bccc2d9e181..2d01a1fc23a 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -78,7 +78,7 @@ test_LDADD = \ $(top_builddir)/src/tscpp/util/libtscpputil.la \ $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ - $(top_builddir)/proxy/libhttp2.a \ + $(top_builddir)/proxy/http2/libhttp2.a \ $(top_builddir)/proxy/libproxy.a \ $(top_builddir)/proxy/hdrs/libhdrs.a \ @LIBPCRE@ \ From a41605abef9b88cdd06aded881921434bd258c80 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 16 Apr 2019 12:44:32 +0900 Subject: [PATCH 1247/1313] Add stateless reset reasons on debug log --- iocore/net/QUICPacketHandler.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 0e1b32917b4..f75e3955af3 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -295,6 +295,17 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // 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)) { + 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); + } + } + 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); From 897f6922c304e15c9eea31d7b52c0b986b0f5fd7 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 17 Apr 2019 16:03:24 +0900 Subject: [PATCH 1248/1313] Print destination addresses and ports of received packets --- iocore/net/P_UDPPacket.h | 6 ++- iocore/net/QUICPacketHandler.cc | 24 ++++++---- iocore/net/UnixUDPNet.cc | 80 +++++++++++++++++++++++++++++++-- 3 files changed, 96 insertions(+), 14 deletions(-) diff --git a/iocore/net/P_UDPPacket.h b/iocore/net/P_UDPPacket.h index 80426caa2fc..d6747de397a 100644 --- a/iocore/net/P_UDPPacket.h +++ b/iocore/net/P_UDPPacket.h @@ -226,7 +226,7 @@ new_UDPPacket(ink_hrtime when, Ptr buf) } TS_INLINE UDPPacket * -new_incoming_UDPPacket(struct sockaddr *from, char *buf, int len) +new_incoming_UDPPacket(struct sockaddr *from, struct sockaddr *to, char *buf, int len) { UDPPacketInternal *p = udpPacketAllocator.alloc(); @@ -234,6 +234,7 @@ new_incoming_UDPPacket(struct sockaddr *from, char *buf, int len) p->in_heap = 0; p->delivery_time = 0; ats_ip_copy(&p->from, from); + ats_ip_copy(&p->to, to); IOBufferBlock *body = new_IOBufferBlock(); body->alloc(iobuffer_size_to_index(len)); @@ -245,7 +246,7 @@ new_incoming_UDPPacket(struct sockaddr *from, char *buf, int len) } TS_INLINE UDPPacket * -new_incoming_UDPPacket(struct sockaddr *from, Ptr &block) +new_incoming_UDPPacket(struct sockaddr *from, struct sockaddr *to, Ptr &block) { UDPPacketInternal *p = udpPacketAllocator.alloc(); @@ -253,6 +254,7 @@ new_incoming_UDPPacket(struct sockaddr *from, Ptr &block) p->in_heap = 0; p->delivery_time = 0; ats_ip_copy(&p->from, from); + ats_ip_copy(&p->to, to); p->chain = block; return p; diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index f75e3955af3..611023cb5de 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -230,9 +230,11 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) } if (is_debug_tag_set(debug_tag)) { - ip_port_text_buffer ipb; - QUICDebugDS(scid, dcid, "recv LH packet from %s size=%" PRId64, ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), - udp_packet->getPktLength()); + ip_port_text_buffer ipb_from; + ip_port_text_buffer ipb_to; + QUICDebugDS(scid, dcid, "recv LH packet from %s to %s size=%" PRId64, + ats_ip_nptop(&udp_packet->from.sa, ipb_from, sizeof(ipb_from)), + ats_ip_nptop(&udp_packet->to.sa, ipb_to, sizeof(ipb_to)), udp_packet->getPktLength()); } QUICVersion v; @@ -271,9 +273,11 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) } else { // TODO: lookup DCID by 5-tuple when ATS omits SCID if (is_debug_tag_set(debug_tag)) { - ip_port_text_buffer ipb; - QUICDebugDS(scid, dcid, "recv SH packet from %s size=%" PRId64, ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), - udp_packet->getPktLength()); + ip_port_text_buffer ipb_from; + ip_port_text_buffer ipb_to; + QUICDebugDS(scid, dcid, "recv SH packet from %s to %s size=%" PRId64, + ats_ip_nptop(&udp_packet->from.sa, ipb_from, sizeof(ipb_from)), + ats_ip_nptop(&udp_packet->to.sa, ipb_to, sizeof(ipb_to)), udp_packet->getPktLength()); } } @@ -471,9 +475,11 @@ QUICPacketHandlerOut::_recv_packet(int event, UDPPacket *udp_packet) IOBufferBlock *block = udp_packet->getIOBlockChain(); const uint8_t *buf = reinterpret_cast(block->buf()); - ip_port_text_buffer ipb; - QUICDebugQC(this->_vc, "recv %s packet from %s size=%" PRId64, (QUICInvariants::is_long_header(buf) ? "LH" : "SH"), - ats_ip_nptop(&udp_packet->from.sa, ipb, sizeof(ipb)), udp_packet->getPktLength()); + 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"), + ats_ip_nptop(&udp_packet->from.sa, ipb_from, sizeof(ipb_from)), + ats_ip_nptop(&udp_packet->to.sa, ipb_to, sizeof(ipb_to)), udp_packet->getPktLength()); } this->_vc->handle_received_packet(udp_packet); diff --git a/iocore/net/UnixUDPNet.cc b/iocore/net/UnixUDPNet.cc index 49a6d5288b8..fb4cfc499df 100644 --- a/iocore/net/UnixUDPNet.cc +++ b/iocore/net/UnixUDPNet.cc @@ -29,6 +29,11 @@ ****************************************************************************/ +#if defined(darwin) +/* This is for IPV6_PKTINFO and IPV6_RECVPKTINFO */ +#define __APPLE_USE_RFC_3542 +#endif + #include "P_Net.h" #include "P_UDPNet.h" @@ -164,12 +169,15 @@ UDPNetProcessorInternal::udp_read_from_net(UDPNetHandler *nh, UDPConnection *xuc // build struct msghdr sockaddr_in6 fromaddr; + sockaddr_in6 toaddr; + int toaddr_len = sizeof(toaddr); + char *cbuf[1024]; msg.msg_name = &fromaddr; msg.msg_namelen = sizeof(fromaddr); msg.msg_iov = tiovec; msg.msg_iovlen = niov; - msg.msg_control = nullptr; - msg.msg_controllen = 0; + msg.msg_control = cbuf; + msg.msg_controllen = sizeof(cbuf); // receive data by recvmsg r = socketManager.recvmsg(uc->getFd(), &msg, 0); @@ -199,8 +207,38 @@ UDPNetProcessorInternal::udp_read_from_net(UDPNetHandler *nh, UDPConnection *xuc } } + safe_getsockname(xuc->getFd(), reinterpret_cast(&toaddr), &toaddr_len); + for (auto cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + switch (cmsg->cmsg_type) { +#ifdef IP_PKTINFO + case IP_PKTINFO: + if (cmsg->cmsg_level == IPPROTO_IP) { + struct in_pktinfo *pktinfo = reinterpret_cast(CMSG_DATA(cmsg)); + reinterpret_cast(&toaddr)->sin_addr.s_addr = pktinfo->ipi_addr.s_addr; + } + break; +#endif +#ifdef IP_RECVDSTADDR + case IP_RECVDSTADDR: + if (cmsg->cmsg_level == IPPROTO_IP) { + struct in_addr *addr = reinterpret_cast(CMSG_DATA(cmsg)); + reinterpret_cast(&toaddr)->sin_addr.s_addr = addr->s_addr; + } + break; +#endif +#if defined(IPV6_PKTINFO) || defined(IPV6_RECVPKTINFO) + case IPV6_PKTINFO: // IPV6_RECVPKTINFO uses IPV6_PKTINFO too + if (cmsg->cmsg_level == IPPROTO_IPV6) { + struct in6_pktinfo *pktinfo = reinterpret_cast(CMSG_DATA(cmsg)); + memcpy(toaddr.sin6_addr.s6_addr, &pktinfo->ipi6_addr, 16); + } + break; +#endif + } + } + // create packet - UDPPacket *p = new_incoming_UDPPacket(ats_ip_sa_cast(&fromaddr), chain); + UDPPacket *p = new_incoming_UDPPacket(ats_ip_sa_cast(&fromaddr), ats_ip_sa_cast(&toaddr), chain); p->setConnection(uc); // queue onto the UDPConnection uc->inQueue.push((UDPPacketInternal *)p); @@ -630,6 +668,24 @@ UDPNetProcessor::CreateUDPSocket(int *resfd, sockaddr const *remote_addr, Action } } + if (opt.ip_family == AF_INET) { + int enable = 1; +#ifdef IP_PKTINFO + safe_setsockopt(fd, IPPROTO_IP, IP_PKTINFO, reinterpret_cast(&enable), sizeof(enable)); +#endif +#ifdef IP_RECVDSTADDR + safe_setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, reinterpret_cast(&enable), sizeof(enable)); +#endif + } else if (opt.ip_family == AF_INET6) { + int enable = 1; +#ifdef IPV6_PKTINFO + safe_setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, reinterpret_cast(&enable), sizeof(enable)); +#endif +#ifdef IPV6_RECVPKTINFO + safe_setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, reinterpret_cast(&enable), sizeof(enable)); +#endif + } + if (local_addr.port() || !is_any_address) { if (-1 == socketManager.ink_bind(fd, &local_addr.sa, ats_ip_size(&local_addr.sa))) { char buff[INET6_ADDRPORTSTRLEN]; @@ -685,6 +741,24 @@ UDPNetProcessor::UDPBind(Continuation *cont, sockaddr const *addr, int send_bufs goto Lerror; } + if (addr->sa_family == AF_INET) { + int enable = 1; +#ifdef IP_PKTINFO + safe_setsockopt(fd, IPPROTO_IP, IP_PKTINFO, reinterpret_cast(&enable), sizeof(enable)); +#endif +#ifdef IP_RECVDSTADDR + safe_setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, reinterpret_cast(&enable), sizeof(enable)); +#endif + } else if (addr->sa_family == AF_INET6) { + int enable = 1; +#ifdef IPV6_PKTINFO + safe_setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, reinterpret_cast(&enable), sizeof(enable)); +#endif +#ifdef IPV6_RECVPKTINFO + safe_setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, reinterpret_cast(&enable), sizeof(enable)); +#endif + } + // If this is a class D address (i.e. multicast address), use REUSEADDR. if (ats_is_ip_multicast(addr)) { int enable_reuseaddr = 1; From 2a2107c11af28726bc568512c185b26b2b782ef6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 30 Apr 2019 21:59:52 +0900 Subject: [PATCH 1249/1313] Update clang-tidy target --- iocore/net/quic/Makefile.am | 2 +- proxy/http3/Makefile.am | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 9fd6b2761c3..d0fbc3360ab 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -304,5 +304,5 @@ test_QUICAddrVerifyState_SOURCES = \ # include $(top_srcdir)/build/tidy.mk -tidy-local: $(DIST_SOURCES) +clang-tidy-local: $(DIST_SOURCES) $(CXX_Clang_Tidy) diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index 2d01a1fc23a..789b05ec77a 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -115,5 +115,5 @@ test_qpack_SOURCES = \ # include $(top_srcdir)/build/tidy.mk -tidy-local: $(libhttp3_a_SOURCES) \ +clang-tidy-local: $(libhttp3_a_SOURCES) \ $(CXX_Clang_Tidy) From d067d3eb321fb0660384a7e9435539583a25c673 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 30 Apr 2019 22:43:08 +0900 Subject: [PATCH 1250/1313] Add missing files for BoringSSL --- .../QUICPacketHeaderProtector_boringssl.cc | 31 +++++++++++++ .../quic/QUICPacketHeaderProtector_openssl.cc | 2 +- .../QUICPacketPayloadProtector_boringssl.cc | 46 +++++++++++++++++++ .../QUICPacketPayloadProtector_openssl.cc | 2 +- src/tscore/HKDF_boringssl.cc | 44 ++++++++++++++++++ 5 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 iocore/net/quic/QUICPacketHeaderProtector_boringssl.cc create mode 100644 iocore/net/quic/QUICPacketPayloadProtector_boringssl.cc create mode 100644 src/tscore/HKDF_boringssl.cc diff --git a/iocore/net/quic/QUICPacketHeaderProtector_boringssl.cc b/iocore/net/quic/QUICPacketHeaderProtector_boringssl.cc new file mode 100644 index 00000000000..999ebda830d --- /dev/null +++ b/iocore/net/quic/QUICPacketHeaderProtector_boringssl.cc @@ -0,0 +1,31 @@ +/** @file + * + * QUIC Packet Header Protector (BoringSSL specific code) + * + * @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 "QUICPacketHeaderProtector.h" + +bool +QUICPacketHeaderProtector::_generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *aead) const +{ + ink_assert(!"not implemented"); + return false; +} diff --git a/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc b/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc index 0a5e3dc0ac5..5039638332a 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc @@ -1,6 +1,6 @@ /** @file * - * QUIC Handshake Protocol (OpenSSL specific code) + * QUIC Packet Header Protector (OpenSSL specific code) * * @section license License * diff --git a/iocore/net/quic/QUICPacketPayloadProtector_boringssl.cc b/iocore/net/quic/QUICPacketPayloadProtector_boringssl.cc new file mode 100644 index 00000000000..eeedab1143e --- /dev/null +++ b/iocore/net/quic/QUICPacketPayloadProtector_boringssl.cc @@ -0,0 +1,46 @@ +/** @file + * + * QUIC Packet Payload Protector (BoringSSL specific code) + * + * @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 "QUICPacketProtectionKeyInfo.h" +#include "QUICPacketPayloadProtector.h" +#include "tscore/Diags.h" + +static constexpr char tag[] = "quic_ppp"; + +bool +QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const Ptr 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; +} + +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 +{ + ink_assert(!"not implemented"); + return false; +} diff --git a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc b/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc index d33c2bda7ac..b25f099051e 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc +++ b/iocore/net/quic/QUICPacketPayloadProtector_openssl.cc @@ -1,6 +1,6 @@ /** @file * - * QUIC Packet Header Protector + * QUIC Packet Payload Protector (OpenSSL specific code) * * @section license License * diff --git a/src/tscore/HKDF_boringssl.cc b/src/tscore/HKDF_boringssl.cc new file mode 100644 index 00000000000..08fcd66ea89 --- /dev/null +++ b/src/tscore/HKDF_boringssl.cc @@ -0,0 +1,44 @@ +/** @file + * + * HKDF utility (BoringSSL version) + * + * @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/HKDF.h" +#include + +HKDF::HKDF(const EVP_MD *digest) : _digest(digest) +{ + ink_assert(!"not implemented"); +} + +int +HKDF::extract(uint8_t *dst, size_t *dst_len, const uint8_t *salt, size_t salt_len, const uint8_t *ikm, size_t ikm_len) +{ + ink_assert(!"not implemented"); + return 0; +} + +int +HKDF::expand(uint8_t *dst, size_t *dst_len, const uint8_t *prk, size_t prk_len, const uint8_t *info, size_t info_len, + uint16_t length) +{ + ink_assert(!"not implemented"); + return 0; +} From 5a77a807942e8ef5eb4f0b844bcc881e0367375d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 1 May 2019 14:31:44 +0900 Subject: [PATCH 1251/1313] Fix stack-buffer-overflow on storing data frame --- proxy/http3/Http3DataFramer.cc | 19 ++++++++++++++----- proxy/http3/Http3Frame.h | 2 ++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/proxy/http3/Http3DataFramer.cc b/proxy/http3/Http3DataFramer.cc index 5f58e9297e9..491210e0521 100644 --- a/proxy/http3/Http3DataFramer.cc +++ b/proxy/http3/Http3DataFramer.cc @@ -38,11 +38,20 @@ Http3DataFramer::generate_frame(uint16_t max_size) Http3FrameUPtr frame = Http3FrameFactory::create_null_frame(); IOBufferReader *reader = this->_source_vio->get_reader(); - size_t len = std::min(reader->read_avail(), static_cast(max_size)); - if (len) { - frame = Http3FrameFactory::create_data_frame(reinterpret_cast(reader->start()), len); - reader->consume(len); - this->_source_vio->ndone += len; + + if (max_size <= Http3Frame::MAX_FRAM_HEADER_OVERHEAD) { + return frame; + } + + size_t payload_len = max_size - Http3Frame::MAX_FRAM_HEADER_OVERHEAD; + if (!reader->is_read_avail_more_than(payload_len)) { + payload_len = reader->read_avail(); + } + + if (payload_len) { + frame = Http3FrameFactory::create_data_frame(reinterpret_cast(reader->start()), payload_len); + reader->consume(payload_len); + this->_source_vio->ndone += payload_len; } return frame; diff --git a/proxy/http3/Http3Frame.h b/proxy/http3/Http3Frame.h index be0b48e540a..48ead5f31ce 100644 --- a/proxy/http3/Http3Frame.h +++ b/proxy/http3/Http3Frame.h @@ -32,6 +32,8 @@ class Http3Frame { public: + constexpr static size_t MAX_FRAM_HEADER_OVERHEAD = 128; ///< Type (i) + Length (i) + Http3Frame() {} Http3Frame(const uint8_t *buf, size_t len); Http3Frame(Http3FrameType type); From d4d3fc02ef5a95f16ecefd2d4107db8cacdb43bb Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 25 Apr 2019 11:55:38 +0800 Subject: [PATCH 1252/1313] Check QUIC availability with SSL_MODE_QUIC_HACK --- configure.ac | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 667e02d23df..0c760e90d39 100644 --- a/configure.ac +++ b/configure.ac @@ -1200,12 +1200,19 @@ TS_CHECK_CRYPTO_TLS13 # Check for QUIC support enable_quic=no -AS_IF([test "x$enable_tls13" = "xyes"], [ - enable_quic=yes -]) +AC_MSG_CHECKING([whether APIs for QUIC are available]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[ + #ifndef SSL_MODE_QUIC_HACK + # error no hack for quic + #endif + ]]) + ], + [AC_MSG_RESULT([yes]); enable_quic=yes], + [AC_MSG_RESULT([no])]) +AM_CONDITIONAL([ENABLE_QUIC], [test "x$enable_quic" = "xyes"]) TS_ARG_ENABLE_VAR([use], [quic]) AC_SUBST(use_quic) -AM_CONDITIONAL([ENABLE_QUIC], [test "x$enable_quic" = "xyes"]) # Check for OCSP TS_CHECK_CRYPTO_OCSP From 42b5fdfe2fc786e4a14f13319f690b07523923bb Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 1 May 2019 16:49:21 +0900 Subject: [PATCH 1253/1313] Fix BAD_ACCESS in Http3FrameFactory::create_data_frame() --- proxy/http3/Http3DataFramer.cc | 3 +-- proxy/http3/Http3Frame.cc | 27 +++++++++++++++++++++++++++ proxy/http3/Http3Frame.h | 1 + 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/proxy/http3/Http3DataFramer.cc b/proxy/http3/Http3DataFramer.cc index 491210e0521..af547733881 100644 --- a/proxy/http3/Http3DataFramer.cc +++ b/proxy/http3/Http3DataFramer.cc @@ -49,8 +49,7 @@ Http3DataFramer::generate_frame(uint16_t max_size) } if (payload_len) { - frame = Http3FrameFactory::create_data_frame(reinterpret_cast(reader->start()), payload_len); - reader->consume(payload_len); + frame = Http3FrameFactory::create_data_frame(reader, payload_len); this->_source_vio->ndone += payload_len; } diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc index 2f56b3fdb70..f60b530fb8d 100644 --- a/proxy/http3/Http3Frame.cc +++ b/proxy/http3/Http3Frame.cc @@ -453,3 +453,30 @@ Http3FrameFactory::create_data_frame(const uint8_t *payload, size_t payload_len) new (frame) Http3DataFrame(std::move(buf), payload_len); return Http3DataFrameUPtr(frame, &Http3FrameDeleter::delete_data_frame); } + +// TODO: This should clone IOBufferBlock chain to avoid memcpy +Http3DataFrameUPtr +Http3FrameFactory::create_data_frame(IOBufferReader *reader, size_t payload_len) +{ + ats_unique_buf buf = ats_unique_malloc(payload_len); + size_t written = 0; + + while (written < payload_len) { + int64_t len = reader->block_read_avail(); + + if (written + len > payload_len) { + len = payload_len - written; + } + + memcpy(buf.get() + written, reinterpret_cast(reader->start()), len); + reader->consume(len); + written += len; + } + + ink_assert(written == payload_len); + + Http3DataFrame *frame = http3DataFrameAllocator.alloc(); + new (frame) Http3DataFrame(std::move(buf), payload_len); + + return Http3DataFrameUPtr(frame, &Http3FrameDeleter::delete_data_frame); +} diff --git a/proxy/http3/Http3Frame.h b/proxy/http3/Http3Frame.h index 48ead5f31ce..adc2fae7a3a 100644 --- a/proxy/http3/Http3Frame.h +++ b/proxy/http3/Http3Frame.h @@ -233,6 +233,7 @@ class Http3FrameFactory * Creates a DATA frame. */ static Http3DataFrameUPtr create_data_frame(const uint8_t *data, size_t data_len); + static Http3DataFrameUPtr create_data_frame(IOBufferReader *reader, size_t data_len); private: std::shared_ptr _unknown_frame = nullptr; From fd33307a3b4d6bff9577641ae9b20fd8f4ef6b4a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 1 May 2019 16:50:17 +0900 Subject: [PATCH 1254/1313] Print size of HTTP/3 frame on debug log --- proxy/http3/Http3FrameCollector.cc | 2 +- proxy/http3/Http3FrameDispatcher.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/http3/Http3FrameCollector.cc b/proxy/http3/Http3FrameCollector.cc index 7ee5afeee7d..213a1e3e113 100644 --- a/proxy/http3/Http3FrameCollector.cc +++ b/proxy/http3/Http3FrameCollector.cc @@ -42,7 +42,7 @@ Http3FrameCollector::on_write_ready(QUICStreamIO *stream_io, size_t &nwritten) frame->store(tmp + nwritten, &len); nwritten += len; - Debug("http3", "[TX] [%d] | %s", stream_io->stream_id(), Http3DebugNames::frame_type(frame->type())); + Debug("http3", "[TX] [%d] | %s size=%zu", stream_io->stream_id(), Http3DebugNames::frame_type(frame->type()), len); } all_done &= g->is_done(); diff --git a/proxy/http3/Http3FrameDispatcher.cc b/proxy/http3/Http3FrameDispatcher.cc index 14bd0769a8e..64df8d5a5ed 100644 --- a/proxy/http3/Http3FrameDispatcher.cc +++ b/proxy/http3/Http3FrameDispatcher.cc @@ -99,7 +99,7 @@ Http3FrameDispatcher::on_read_ready(QUICStreamIO &stream_io, uint64_t &nread) // Dispatch Http3FrameType type = frame->type(); - Debug("http3", "[RX] [%d] | %s", stream_io.stream_id(), Http3DebugNames::frame_type(type)); + Debug("http3", "[RX] [%d] | %s size=%zu", stream_io.stream_id(), Http3DebugNames::frame_type(type), frame_len); std::vector handlers = this->_handlers[static_cast(type)]; for (auto h : handlers) { error = h->handle_frame(frame); From c9e367a5f3cef855f64f047d61447d04300fe13d Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 1 May 2019 16:53:56 +0900 Subject: [PATCH 1255/1313] Add workaround fix for mixed response header and body --- proxy/http3/Http3ClientTransaction.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/proxy/http3/Http3ClientTransaction.cc b/proxy/http3/Http3ClientTransaction.cc index 42467c0fdcf..1f70d0f0931 100644 --- a/proxy/http3/Http3ClientTransaction.cc +++ b/proxy/http3/Http3ClientTransaction.cc @@ -553,6 +553,12 @@ Http3ClientTransaction::_on_qpack_decode_complete() return -1; } + // FIXME: response header might be delayed from first response body because of callback from QPACK + // Workaround fix for mixed response header and body + if (http_hdr_type_get(this->_header.m_http) == HTTP_TYPE_RESPONSE) { + return 0; + } + SCOPED_MUTEX_LOCK(lock, this->_read_vio.mutex, this_ethread()); MIOBuffer *writer = this->_read_vio.get_writer(); From 3cf90685a87494b47a6d4d56383f8735e27f6129 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 1 May 2019 18:37:47 +0900 Subject: [PATCH 1256/1313] Remove unused defines --- iocore/net/quic/QUICTypes.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 76d087477e0..c9273c8c9d5 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -38,11 +38,6 @@ #include "tscore/ink_inet.h" #include "openssl/evp.h" -// These magical defines should be removed when we implement seriously -#define MAGIC_NUMBER_0 0 -#define MAGIC_NUMBER_1 1 -#define MAGIC_NUMBER_TRUE true - using QUICPacketNumber = uint64_t; using QUICVersion = uint32_t; using QUICStreamId = uint64_t; From f879f87155af0a2f1f81568cfe80f4757787252a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 7 May 2019 14:05:36 +0900 Subject: [PATCH 1257/1313] Follow changes of master branch Signatures changes of ssl_stapling_init_cert() Delete copy constructor of IpAllow::ACL --- iocore/net/quic/QUICConfig.cc | 2 +- proxy/http3/Http09App.cc | 2 +- proxy/http3/Http09App.h | 2 +- proxy/http3/Http3App.cc | 2 +- proxy/http3/Http3App.h | 2 +- src/traffic_quic/quic_client.cc | 2 +- src/traffic_quic/quic_client.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 86e97070366..ee6c477012b 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -581,7 +581,7 @@ QUICMultiCertConfigLoader::init_server_ssl_ctx(std::vector &cert_list, c const char *cert_name = multi_cert_params ? multi_cert_params->cert.get() : nullptr; for (auto cert : cert_list) { - if (!ssl_stapling_init_cert(ctx, cert, cert_name)) { + if (!ssl_stapling_init_cert(ctx, cert, cert_name, nullptr)) { Warning("failed to configure SSL_CTX for OCSP Stapling info for certificate at %s", cert_name); } } diff --git a/proxy/http3/Http09App.cc b/proxy/http3/Http09App.cc index 1168b5a022e..0d70afd3b80 100644 --- a/proxy/http3/Http09App.cc +++ b/proxy/http3/Http09App.cc @@ -33,7 +33,7 @@ static constexpr char debug_tag[] = "quic_simple_app"; static constexpr char debug_tag_v[] = "v_quic_simple_app"; -Http09App::Http09App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QUICApplication(client_vc) +Http09App::Http09App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl) : QUICApplication(client_vc) { this->_client_session = new Http09ClientSession(client_vc); this->_client_session->acl = std::move(session_acl); diff --git a/proxy/http3/Http09App.h b/proxy/http3/Http09App.h index b3356a0549f..85f9afd923e 100644 --- a/proxy/http3/Http09App.h +++ b/proxy/http3/Http09App.h @@ -39,7 +39,7 @@ class Http09ClientSession; class Http09App : public QUICApplication { public: - Http09App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl); + Http09App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl); ~Http09App(); int main_event_handler(int event, Event *data); diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 9d4b1f782f8..f4cd6e3a6a7 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -35,7 +35,7 @@ static constexpr char debug_tag[] = "http3"; static constexpr char debug_tag_v[] = "v_http3"; -Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl) : QUICApplication(client_vc) +Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl) : QUICApplication(client_vc) { this->_ssn = new Http3ClientSession(client_vc); this->_ssn->acl = std::move(session_acl); diff --git a/proxy/http3/Http3App.h b/proxy/http3/Http3App.h index 67bd7f09b90..4deff20fe72 100644 --- a/proxy/http3/Http3App.h +++ b/proxy/http3/Http3App.h @@ -43,7 +43,7 @@ class Http3ClientSession; class Http3App : public QUICApplication { public: - Http3App(QUICNetVConnection *client_vc, IpAllow::ACL session_acl); + Http3App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl); virtual ~Http3App(); virtual void start(); diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc index ffd1e66af12..344028ff085 100644 --- a/src/traffic_quic/quic_client.cc +++ b/src/traffic_quic/quic_client.cc @@ -249,7 +249,7 @@ Http09ClientApp::main_event_handler(int event, Event *data) // // Http3ClientApp // -Http3ClientApp::Http3ClientApp(QUICNetVConnection *qvc, IpAllow::ACL session_acl, const QUICClientConfig *config) +Http3ClientApp::Http3ClientApp(QUICNetVConnection *qvc, IpAllow::ACL &&session_acl, const QUICClientConfig *config) : super(qvc, std::move(session_acl)), _config(config) { } diff --git a/src/traffic_quic/quic_client.h b/src/traffic_quic/quic_client.h index 5a2a950aafe..0097ff078e9 100644 --- a/src/traffic_quic/quic_client.h +++ b/src/traffic_quic/quic_client.h @@ -92,7 +92,7 @@ class Http3ClientApp : public Http3App public: using super = Http3App; - Http3ClientApp(QUICNetVConnection *qvc, IpAllow::ACL session_acl, const QUICClientConfig *config); + Http3ClientApp(QUICNetVConnection *qvc, IpAllow::ACL &&session_acl, const QUICClientConfig *config); ~Http3ClientApp(); void start() override; From 709a9973f4f6e601ff7a2e25b9cd4c206c92a710 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 9 May 2019 10:35:53 +0900 Subject: [PATCH 1258/1313] Revert wrong conflicts fix in HPACK.cc and HTTP2.cc Merging master branch (8deca1c320f89f4a9109e9f87d3d99b5e7e17157) had some conflicts and they were fixed wrongly. - HTTP2.cc status_len and status were moved to narrow down their scope. - HPACK.cc encode_integer() and encode_string() were moved to XPACK.cc. --- proxy/hdrs/XPACK.cc | 2 +- proxy/http2/HPACK.cc | 86 -------------------------------------------- proxy/http2/HTTP2.cc | 3 -- 3 files changed, 1 insertion(+), 90 deletions(-) diff --git a/proxy/hdrs/XPACK.cc b/proxy/hdrs/XPACK.cc index cbf2215a468..e987479b933 100644 --- a/proxy/hdrs/XPACK.cc +++ b/proxy/hdrs/XPACK.cc @@ -154,7 +154,7 @@ xpack_encode_string(uint8_t *buf_start, const uint8_t *buf_end, const char *valu int64_t data_len = 0; // TODO Choose whether to use Huffman encoding wisely - + // cppcheck-suppress knownConditionTrueFalse; leaving "use_huffman" for wise huffman usage in the future if (use_huffman && value_len) { data = static_cast(ats_malloc(value_len * 4)); if (data == nullptr) { diff --git a/proxy/http2/HPACK.cc b/proxy/http2/HPACK.cc index 4fe0d331ae1..cb286932544 100644 --- a/proxy/http2/HPACK.cc +++ b/proxy/http2/HPACK.cc @@ -409,92 +409,6 @@ HpackDynamicTable::length() const return _headers.size(); } -// -// [RFC 7541] 5.1. Integer representation -// -int64_t -encode_integer(uint8_t *buf_start, const uint8_t *buf_end, uint32_t value, uint8_t n) -{ - if (buf_start >= buf_end) { - return -1; - } - - uint8_t *p = buf_start; - - if (value < (static_cast(1 << n) - 1)) { - *(p++) = value; - } else { - *(p++) = (1 << n) - 1; - value -= (1 << n) - 1; - while (value >= 128) { - if (p >= buf_end) { - return -1; - } - *(p++) = (value & 0x7F) | 0x80; - value = value >> 7; - } - if (p + 1 >= buf_end) { - return -1; - } - *(p++) = value; - } - return p - buf_start; -} - -int64_t -encode_string(uint8_t *buf_start, const uint8_t *buf_end, const char *value, size_t value_len) -{ - uint8_t *p = buf_start; - bool use_huffman = true; - char *data = nullptr; - int64_t data_len = 0; - - // TODO Choose whether to use Huffman encoding wisely - // cppcheck-suppress knownConditionTrueFalse; leaving "use_huffman" for wise huffman usage in the future - if (use_huffman && value_len) { - data = static_cast(ats_malloc(value_len * 4)); - if (data == nullptr) { - return -1; - } - data_len = huffman_encode(reinterpret_cast(data), reinterpret_cast(value), value_len); - } - - // Length - const int64_t len = encode_integer(p, buf_end, data_len, 7); - if (len == -1) { - if (use_huffman) { - ats_free(data); - } - - return -1; - } - - if (use_huffman) { - *p |= 0x80; - } - p += len; - - if (buf_end < p || buf_end - p < data_len) { - if (use_huffman) { - ats_free(data); - } - - return -1; - } - - // Value - if (data_len) { - memcpy(p, data, data_len); - p += data_len; - } - - if (use_huffman) { - ats_free(data); - } - - return p - buf_start; -} - int64_t encode_indexed_header_field(uint8_t *buf_start, const uint8_t *buf_end, uint32_t index) { diff --git a/proxy/http2/HTTP2.cc b/proxy/http2/HTTP2.cc index 290127e0759..971b185d5e5 100644 --- a/proxy/http2/HTTP2.cc +++ b/proxy/http2/HTTP2.cc @@ -486,9 +486,6 @@ http2_convert_header_from_2_to_1_1(HTTPHdr *headers) http_hdr_version_set(headers->m_http, version); // Set status from :status - int status_len; - const char *status; - if ((field = headers->field_find(HTTP2_VALUE_STATUS, HTTP2_LEN_STATUS)) != nullptr) { int status_len; const char *status = field->value_get(&status_len); From 8251867b18de6a0c472f4b25e5f999e7d3edd95f Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 1 May 2019 22:56:04 +0900 Subject: [PATCH 1259/1313] Add docs for QUIC configuration --- doc/admin-guide/files/records.config.en.rst | 253 +++++++++++++++++++- 1 file changed, 250 insertions(+), 3 deletions(-) diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst index b0d3c974dfb..1a724e494e0 100644 --- a/doc/admin-guide/files/records.config.en.rst +++ b/doc/admin-guide/files/records.config.en.rst @@ -612,6 +612,7 @@ HTTP Engine proto Value List of supported session protocols. pp Enable Proxy Protocol. ssl SSL terminated. + quic QUIC terminated. tr-full Fully transparent (inbound and outbound) tr-in Inbound transparent. tr-out Outbound transparent. @@ -625,7 +626,7 @@ HTTP Engine blind Accept only the ``CONNECT`` method on this port. - Not compatible with: ``tr-in``, ``ssl``. + Not compatible with: ``tr-in``, ``ssl`` and ``quic``. compress Compress the connection. Retained only by inertia, should be considered "not implemented". @@ -639,13 +640,19 @@ ipv6 ssl Require SSL termination for inbound connections. SSL :ref:`must be configured ` for this option to provide a functional server port. - Not compatible with: ``blind``. + Not compatible with: ``blind`` and ``quic``. + +quic + Require QUIC termination for inbound connections. SSL :ref:`must be configured ` for this option to provide a functional server port. + **THIS IS EXPERIMENTAL SUPPORT AND NOT READY FOR PRODUCTION USE.** + + Not compatible with: ``blind`` and ``ssl``. proto Specify the :ref:`session level protocols ` supported. These should be separated by semi-colons. For TLS proxy ports the default value is all available protocols. For non-TLS proxy ports the default is HTTP - only. + only. HTTP/3 is only available on QUIC ports. pp Enables Proxy Protocol on the port. If Proxy Protocol is enabled on the @@ -725,6 +732,12 @@ mptcp 9090:proto=http:ssl +.. topic:: Example + + Listen on port 4433 for QUIC connections.:: + + 4433:quic + .. ts:cv:: CONFIG proxy.config.http.connect_ports STRING 443 The range of origin server ports that can be used for tunneling via ``CONNECT``. @@ -3632,6 +3645,240 @@ HTTP/2 Configuration |TS| gracefully closes connections that have stream error rates above this setting by sending GOAWAY frames. +HTTP/3 Configuration +==================== + +There is no configuration available yet on this release. + +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.instance_id INT 0 + :reloadable: + + A static key used for calculating Stateless Reset Token. All instances in a + cluster need to share the same value. + +.. ts:cv:: CONFIG proxy.config.quic.connection_table.size INT 65521 + + A size of hash table that stores connection information. + +.. ts:cv:: CONFIG proxy.config.quic.proxy.config.quic.num_alt_connection_ids INT 65521 + :reloadable: + + A number of alternate Connection IDs that |TS| provides to a peer. It has to + be at least 8. + +.. ts:cv:: CONFIG proxy.config.quic.stateless_retry_enabled INT 0 + :reloadable: + + Enables Stateless Retry. + +.. ts:cv:: CONFIG proxy.config.quic.client.vn_exercise_enabled INT 0 + :reloadable: + + Enables version negotiation exercise on origin server connections. + +.. ts:cv:: CONFIG proxy.config.quic.client.cm_exercise_enabled INT 0 + :reloadable: + + Enables connection migration exercise on origin server connections. + +.. ts:cv:: CONFIG proxy.config.quic.server.supported_groups STRING "P-256:X25519:P-384:P-521" + :reloadable: + + Configures the list of supported groups provided by OpenSSL which will be + used to determine the set of shared groups on QUIC origin server connections. + +.. ts:cv:: CONFIG proxy.config.quic.client.supported_groups STRING "P-256:X25519:P-384:P-521" + :reloadable: + + Configures the list of supported groups provided by OpenSSL which will be + used to determine the set of shared groups on QUIC client connections. + +.. ts:cv:: CONFIG proxy.config.quic.client.session_file STRING "" + :reloadable: + + Only available for :program:`traffic_quic`. + If specified, TLS session data will be stored to the file, and will be used + for resuming a session. + +.. ts:cv:: CONFIG proxy.config.quic.client.keylog_file STRING "" + :reloadable: + + Only available for :program:`traffic_quic`. + If specified, key information will be stored to the file. + +.. ts:cv:: CONFIG proxy.config.quic.no_activity_timeout_in INT 30 + :reloadable: + + This value will be advertised as ``idle_timeout`` Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.no_activity_timeout_out INT 30 + :reloadable: + + This value will be advertised as ``idle_timeout`` Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.preferred_address_ipv4 STRING "" + :reloadable: + + This value will be advertised as a part of ``preferred_address`` + Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.preferred_address_ipv6 STRING "" + :reloadable: + + This value will be advertised as a part of ``preferred_address`` + Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.initial_max_data_in INT 65536 + :reloadable: + + This value will be advertised as ``initial_max_data`` Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.initial_max_data_out INT 65536 + :reloadable: + + This value will be advertised as ``initial_max_data`` Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.max_stream_data_bidi_local_in INT 0 + :reloadable: + + This value will be advertised as ``initial_max_stream_data_bidi_local`` + Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.max_stream_data_bidi_local_out INT 4096 + :reloadable: + + This value will be advertised as ``initial_max_stream_data_bidi_local`` + Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.max_stream_data_bidi_remote_in INT 4096 + :reloadable: + + This value will be advertised as ``initial_max_stream_data_bidi_remote`` + Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.max_stream_data_bidi_remote_out INT 0 + :reloadable: + + This value will be advertised as ``initial_max_stream_data_bidi_remote`` + Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.max_stream_data_uni_in INT 4096 + :reloadable: + + This value will be advertised as ``initial_max_stream_data_uni`` + Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.max_stream_data_uni_out INT 0 + :reloadable: + + This value will be advertised as ``initial_max_stream_data_uni`` + Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.max_streams_bidi_in INT 100 + :reloadable: + + This value will be advertised as ``initial_max_streams_bidi`` + Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.max_streams_bidi_out INT 100 + :reloadable: + + This value will be advertised as ``initial_max_streams_bidi`` + Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.max_streams_uni_in INT 100 + :reloadable: + + This value will be advertised as ``initial_max_streams_uni`` + Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.max_streams_uni_out INT 100 + :reloadable: + + This value will be advertised as ``initial_max_streams_uni`` + Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.ack_delay_exponent_in INT 3 + :reloadable: + + This value will be advertised as ``ack_delay_exponent`` Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.ack_delay_exponent_out INT 3 + :reloadable: + + This value will be advertised as ``ack_delay_exponent`` Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.max_ack_delay_in INT 25 + :reloadable: + + This value will be advertised as ``max_ack_delay`` Transport Parameter. + +.. ts:cv:: CONFIG proxy.config.quic.max_ack_delay_out INT 25 + :reloadable: + + This value will be advertised as ``max_ack_delay`` Transport Parameter. + + +.. ts:cv:: CONFIG proxy.config.quic.loss_detection.packet_threshold INT 3 + :reloadable: + + This is just for debugging. Do not change it from the default value unless + you really understand what this is. + +.. ts:cv:: CONFIG proxy.config.quic.loss_detection.time_threshold FLOAT 1.25 + :reloadable: + + This is just for debugging. Do not change it from the default value unless + you really understand what this is. + +.. ts:cv:: CONFIG proxy.config.quic.loss_detection.granularity INT 1 + :reloadable: + + This is just for debugging. Do not change it from the default value unless + you really understand what this is. + +.. ts:cv:: CONFIG proxy.config.quic.loss_detection.initial_rtt INT 1 + :reloadable: + + This is just for debugging. Do not change it from the default value unless + you really understand what this is. + +.. ts:cv:: CONFIG proxy.config.quic.congestion_control.max_datagram_size INT 1200 + :reloadable: + + This is just for debugging. Do not change it from the default value unless + you really understand what this is. + +.. ts:cv:: CONFIG proxy.config.quic.congestion_control.initial_window_scale INT 10 + :reloadable: + + This is just for debugging. Do not change it from the default value unless + you really understand what this is. + +.. ts:cv:: CONFIG proxy.config.quic.congestion_control.minimum_window_scale INT 2 + :reloadable: + + This is just for debugging. Do not change it from the default value unless + you really understand what this is. + +.. ts:cv:: CONFIG proxy.config.quic.congestion_control.loss_reduction_factor FLOAT 0.5 + :reloadable: + + This is just for debugging. Do not change it from the default value unless + you really understand what this is. + +.. ts:cv:: CONFIG proxy.config.quic.congestion_control.persistent_congestion_threshold INT 2 + :reloadable: + + This is just for debugging. Do not change it from the default value unless + you really understand what this is. + Plug-in Configuration ===================== From 478b7f8c8005756150db26afa73299476ff3ed5a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 10 May 2019 15:20:13 +0900 Subject: [PATCH 1260/1313] Fix some of compile warnings --- iocore/net/quic/QUICApplication.cc | 4 ++-- iocore/net/quic/test/test_QUICFlowController.cc | 2 -- iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc | 1 - iocore/net/quic/test/test_QUICStream.cc | 8 -------- proxy/http3/test/test_QPACK.cc | 2 +- 5 files changed, 3 insertions(+), 14 deletions(-) diff --git a/iocore/net/quic/QUICApplication.cc b/iocore/net/quic/QUICApplication.cc index 9039b998f3f..54ad68e1137 100644 --- a/iocore/net/quic/QUICApplication.cc +++ b/iocore/net/quic/QUICApplication.cc @@ -200,8 +200,8 @@ QUICApplication::QUICApplication(QUICConnection *qc) : Continuation(new_ProxyMut QUICApplication::~QUICApplication() { - for (const auto &[stream_id, stream_io] : this->_stream_map) { - delete stream_io; + for (auto const &kv : this->_stream_map) { + delete kv.second; } } diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index a5120b11a38..3df50b67ecb 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -401,7 +401,6 @@ TEST_CASE("Frame retransmission", "[quic]") SECTION("MAX_DATA frame") { - int ret = 0; uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; MockRTTProvider rp(DEFAULT_RTT); QUICLocalConnectionFlowController fc(&rp, 1024); @@ -438,7 +437,6 @@ TEST_CASE("Frame retransmission", "[quic]") SECTION("MAX_STREAM_DATA frame") { - int ret = 0; uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; MockRTTProvider rp(DEFAULT_RTT); QUICLocalStreamFlowController fc(&rp, 1024, 0); diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc index 6d8c9f55646..50a3dfaf364 100644 --- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc +++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc @@ -141,7 +141,6 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_pop", "[quic]") uint8_t frame_buf3[QUICFrame::MAX_INSTANCE_SIZE]; uint8_t frame_buf4[QUICFrame::MAX_INSTANCE_SIZE]; uint8_t frame_buf5[QUICFrame::MAX_INSTANCE_SIZE]; - uint8_t frame_buf6[QUICFrame::MAX_INSTANCE_SIZE]; QUICStreamFrame *stream1_frame_0_r = QUICFrameFactory::create_stream_frame(frame_buf0, block_1024, 1, 0); QUICStreamFrame *stream1_frame_1_r = QUICFrameFactory::create_stream_frame(frame_buf1, block_1024, 1, 1024); QUICStreamFrame *stream1_frame_empty = QUICFrameFactory::create_stream_frame(frame_buf2, block_0, 1, 2048); diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index dc3b619a792..581213881aa 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -590,17 +590,11 @@ TEST_CASE("QUIC receive only stream", "[quic]") SECTION("Retransmit STOP_SENDING frame") { - MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); - IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX)); SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); - MockContinuation mock_cont(stream->mutex); - // stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); - QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; QUICFrame *frame = nullptr; @@ -675,7 +669,6 @@ TEST_CASE("QUIC send only stream", "[quic]") { std::unique_ptr error = nullptr; - MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); @@ -685,7 +678,6 @@ TEST_CASE("QUIC send only stream", "[quic]") SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); MockContinuation mock_cont(stream->mutex); - // stream->do_io_read(nullptr, INT64_MAX, read_buffer); stream->do_io_write(&mock_cont, INT64_MAX, write_buffer_reader); QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; diff --git a/proxy/http3/test/test_QPACK.cc b/proxy/http3/test/test_QPACK.cc index 1d076fbc6e6..9acc6dd1190 100644 --- a/proxy/http3/test/test_QPACK.cc +++ b/proxy/http3/test/test_QPACK.cc @@ -219,7 +219,7 @@ output_decoded_headers(FILE *fd, HTTPHdr **headers, uint64_t n) if (!header_set) { continue; } - fprintf(fd, "# stream %llu\n", i + 1); + fprintf(fd, "# stream %" PRIu64 "\n", i + 1); MIMEFieldIter field_iter; for (MIMEField *field = header_set->iter_get_first(&field_iter); field != nullptr; field = header_set->iter_get_next(&field_iter)) { From 56484a48117fff092ceed19522aa21e4cd3f1d19 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Fri, 10 May 2019 17:25:14 +0900 Subject: [PATCH 1261/1313] Remove an unused variable --- proxy/http3/test/test_QPACK.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/proxy/http3/test/test_QPACK.cc b/proxy/http3/test/test_QPACK.cc index 9acc6dd1190..5ddb6788465 100644 --- a/proxy/http3/test/test_QPACK.cc +++ b/proxy/http3/test/test_QPACK.cc @@ -272,7 +272,6 @@ void acknowledge_header_block(TestQUICStream *stream, uint64_t stream_id) { uint8_t buf[128]; - int buf_len = 0; buf[0] = 0x80; int ret = xpack_encode_integer(buf, buf + sizeof(buf), stream_id, 7); From a9e0b8bc18263f56fa41dd0e1a0fea7ef4b83e32 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 13 May 2019 12:31:35 +0900 Subject: [PATCH 1262/1313] Fix checking progress of write vio --- iocore/net/quic/QUICBidirectionalStream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICBidirectionalStream.h b/iocore/net/quic/QUICBidirectionalStream.h index ed583bdee8c..fcbd5d7140b 100644 --- a/iocore/net/quic/QUICBidirectionalStream.h +++ b/iocore/net/quic/QUICBidirectionalStream.h @@ -88,7 +88,7 @@ class QUICBidirectionalStream : public QUICStreamVConnection, public QUICTransfe bool _is_transfer_complete = false; bool _is_reset_complete = false; - QUICTransferProgressProviderVIO _progress_vio = {this->_read_vio}; + QUICTransferProgressProviderVIO _progress_vio = {this->_write_vio}; QUICRemoteStreamFlowController _remote_flow_controller; QUICLocalStreamFlowController _local_flow_controller; From 509eef06bcd204b62cd35ab43cd4b767ea483b3e Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 25 Apr 2019 09:27:24 +0000 Subject: [PATCH 1263/1313] QUIC: recovery-19 combine loss detector into one --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 55 ++----- iocore/net/quic/QUICAckFrameCreator.cc | 24 +-- iocore/net/quic/QUICDebugNames.cc | 16 +- iocore/net/quic/QUICDebugNames.h | 2 +- iocore/net/quic/QUICLossDetector.cc | 220 ++++++++++++++----------- iocore/net/quic/QUICLossDetector.h | 46 +++--- iocore/net/quic/QUICPacketFactory.cc | 16 +- iocore/net/quic/QUICPinger.cc | 2 +- iocore/net/quic/QUICTypes.cc | 15 +- iocore/net/quic/QUICTypes.h | 9 +- 11 files changed, 211 insertions(+), 196 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index fc86bc872d1..f09f0b1f198 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -241,7 +241,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub // or make them just member variables. QUICHandshake *_handshake_handler = nullptr; QUICHandshakeProtocol *_hs_protocol = nullptr; - QUICLossDetector *_loss_detector[3] = {nullptr}; + QUICLossDetector *_loss_detector = nullptr; QUICFrameDispatcher *_frame_dispatcher = nullptr; QUICStreamManager *_stream_manager = nullptr; QUICCongestionController *_congestion_controller = nullptr; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 799b9946eea..a9e5418fca8 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -452,12 +452,9 @@ QUICNetVConnection::start() QUICCCConfigQCP cc_config(this->_quic_config); QUICLDConfigQCP ld_config(this->_quic_config); this->_congestion_controller = new QUICCongestionController(this, cc_config); - for (auto s : QUIC_PN_SPACES) { - int index = static_cast(s); - QUICLossDetector *ld = new QUICLossDetector(this, this->_congestion_controller, &this->_rtt_measure, index, ld_config); - this->_frame_dispatcher->add_handler(ld); - this->_loss_detector[index] = ld; - } + this->_loss_detector = new QUICLossDetector(this, this->_congestion_controller, &this->_rtt_measure, ld_config); + this->_frame_dispatcher->add_handler(this->_loss_detector); + this->_remote_flow_controller = new QUICRemoteConnectionFlowController(UINT64_MAX); this->_local_flow_controller = new QUICLocalConnectionFlowController(&this->_rtt_measure, UINT64_MAX); this->_path_validator = new QUICPathValidator(); @@ -943,11 +940,8 @@ QUICNetVConnection::state_connection_closed(int event, Event *data) // TODO: Drop record from Connection-ID - QUICNetVConnection table in QUICPacketHandler // Shutdown loss detector - for (auto s : QUIC_PN_SPACES) { - QUICLossDetector *ld = this->_loss_detector[static_cast(s)]; - SCOPED_MUTEX_LOCK(lock, ld->mutex, this_ethread()); - ld->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); - } + SCOPED_MUTEX_LOCK(lock2, this->_loss_detector->mutex, this_ethread()); + this->_loss_detector->handleEvent(QUIC_EVENT_LD_SHUTDOWN, nullptr); // FIXME I'm not sure whether we can block here, but it's needed to not crash. SCOPED_MUTEX_LOCK(lock, this->nh->mutex, this_ethread()); @@ -1039,9 +1033,9 @@ QUICNetVConnection::next_protocol_set() const QUICPacketNumber QUICNetVConnection::_largest_acked_packet_number(QUICEncryptionLevel level) const { - int index = QUICTypeUtil::pn_space_index(level); + auto index = QUICTypeUtil::pn_space(level); - return this->_loss_detector[index]->largest_acked_packet_number(); + return this->_loss_detector->largest_acked_packet_number(index); } std::string_view @@ -1105,9 +1099,8 @@ QUICNetVConnection::_state_handshake_process_version_negotiation_packet(const QU error = this->_handshake_handler->negotiate_version(packet, &this->_packet_factory); // discard all transport state except packet number - for (auto s : QUIC_PN_SPACES) { - this->_loss_detector[static_cast(s)]->reset(); - } + this->_loss_detector->reset(); + this->_congestion_controller->reset(); // start handshake over @@ -1181,9 +1174,8 @@ QUICNetVConnection::_state_handshake_process_retry_packet(const QUICPacket &pack // discard all transport state this->_handshake_handler->reset(); this->_packet_factory.reset(); - for (auto s : QUIC_PN_SPACES) { - this->_loss_detector[static_cast(s)]->reset(); - } + this->_loss_detector->reset(); + this->_congestion_controller->reset(); this->_packet_recv_queue.reset(); @@ -1397,7 +1389,8 @@ QUICNetVConnection::_state_common_send_packet() } else { packet_info->sent_bytes = 0; } - packet_info->type = packet->type(); + 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()); @@ -1423,8 +1416,7 @@ QUICNetVConnection::_state_common_send_packet() this->_minimum_encryption_level = QUICEncryptionLevel::HANDSHAKE; } - int index = QUICTypeUtil::pn_space_index(level); - this->_loss_detector[index]->on_packet_sent(std::move(packet_info)); + this->_loss_detector->on_packet_sent(std::move(packet_info)); packet_count++; } } @@ -1974,10 +1966,9 @@ QUICNetVConnection::_complete_handshake_if_possible() this->_handshake_handler->remote_transport_parameters()); // PN space doesn't matter but seems like this is the way to pick the LossDetector for 0-RTT and Short packet - int index_for_1rtt = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ONE_RTT); uint64_t ack_delay_exponent = this->_handshake_handler->remote_transport_parameters()->getAsUInt(QUICTransportParameterId::ACK_DELAY_EXPONENT); - this->_loss_detector[index_for_1rtt]->update_ack_delay_exponent(ack_delay_exponent); + this->_loss_detector->update_ack_delay_exponent(ack_delay_exponent); this->_start_application(); @@ -2090,8 +2081,7 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) this->remove_from_active_queue(); this->set_inactivity_timeout(0); - int index = QUICTypeUtil::pn_space_index(this->_hs_protocol->current_encryption_level()); - ink_hrtime rto = this->_loss_detector[index]->current_rto_period(); + ink_hrtime rto = this->_loss_detector->current_rto_period(); QUICConDebug("Enter state_connection_closing"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); @@ -2119,8 +2109,7 @@ QUICNetVConnection::_switch_to_draining_state(QUICConnectionErrorUPtr error) this->remove_from_active_queue(); this->set_inactivity_timeout(0); - int index = QUICTypeUtil::pn_space_index(this->_hs_protocol->current_encryption_level()); - ink_hrtime rto = this->_loss_detector[index]->current_rto_period(); + ink_hrtime rto = this->_loss_detector->current_rto_period(); QUICConDebug("Enter state_connection_draining"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_draining); @@ -2161,15 +2150,7 @@ QUICNetVConnection::_validate_new_path() this->_path_validator->validate(); // Not sure how long we should wait. The spec says just "enough time". // Use the same time amount as the closing timeout. - ink_hrtime rto = 0; - int current_level_index = QUICTypeUtil::pn_space_index(this->_hs_protocol->current_encryption_level()); - - // Workaround fix for #5111 - walk through PN Spaces to get correct RTO - // This could be removed when _loss_detectors are combined. - for (int i = 0; i <= current_level_index; ++i) { - rto = std::max(rto, this->_loss_detector[i]->current_rto_period()); - } - + ink_hrtime rto = this->_loss_detector->current_rto_period(); this->_schedule_path_validation_timeout(3 * rto); } diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index e60183e8171..576ff42b765 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -29,8 +29,8 @@ QUICAckFrameManager::QUICAckFrameManager() { for (auto level : QUIC_PN_SPACES) { - int index = QUICTypeUtil::pn_space_index(level); - this->_ack_creator[index] = std::make_unique(level, this); + auto index = QUICTypeUtil::pn_space(level); + this->_ack_creator[static_cast(index)] = std::make_unique(level, this); } } @@ -51,8 +51,8 @@ QUICAckFrameManager::update(QUICEncryptionLevel level, QUICPacketNumber packet_n return 0; } - int index = QUICTypeUtil::pn_space_index(level); - auto &ack_creator = this->_ack_creator[index]; + auto index = QUICTypeUtil::pn_space(level); + auto &ack_creator = this->_ack_creator[static_cast(index)]; ack_creator->push_back(packet_number, size, ack_only); return 0; } @@ -70,8 +70,8 @@ QUICAckFrameManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uin return ack_frame; } - int index = QUICTypeUtil::pn_space_index(level); - auto &ack_creator = this->_ack_creator[index]; + auto index = QUICTypeUtil::pn_space(level); + auto &ack_creator = this->_ack_creator[static_cast(index)]; ack_frame = ack_creator->generate_ack_frame(buf, maximum_frame_size); if (ack_frame != nullptr) { @@ -95,8 +95,8 @@ QUICAckFrameManager::will_generate_frame(QUICEncryptionLevel level, ink_hrtime t return false; } - int index = QUICTypeUtil::pn_space_index(level); - return this->_ack_creator[index]->is_ack_frame_ready(); + auto index = QUICTypeUtil::pn_space(level); + return this->_ack_creator[static_cast(index)]->is_ack_frame_ready(); } void @@ -104,17 +104,17 @@ QUICAckFrameManager::_on_frame_acked(QUICFrameInformationUPtr &info) { ink_assert(info->type == QUICFrameType::ACK); AckFrameInfo *ack_info = reinterpret_cast(info->data); - int index = QUICTypeUtil::pn_space_index(info->level); - this->_ack_creator[index]->forget(ack_info->largest_acknowledged); + auto index = QUICTypeUtil::pn_space(info->level); + this->_ack_creator[static_cast(index)]->forget(ack_info->largest_acknowledged); } void QUICAckFrameManager::_on_frame_lost(QUICFrameInformationUPtr &info) { ink_assert(info->type == QUICFrameType::ACK); - int index = QUICTypeUtil::pn_space_index(info->level); + auto index = QUICTypeUtil::pn_space(info->level); // when ack frame lost. Force to refresh the frame. - this->_ack_creator[index]->refresh_state(); + this->_ack_creator[static_cast(index)]->refresh_state(); } QUICFrameId diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc index 47e5e1b51d3..b70d95975bf 100644 --- a/iocore/net/quic/QUICDebugNames.cc +++ b/iocore/net/quic/QUICDebugNames.cc @@ -314,15 +314,15 @@ QUICDebugNames::encryption_level(QUICEncryptionLevel level) } const char * -QUICDebugNames::pn_space(int index) +QUICDebugNames::pn_space(QUICPacketNumberSpace pn_space) { - switch (index) { - case 0: - return "INITIAL"; - case 1: - return "PROTECTED"; - case 2: - return "HANDSHAKE"; + switch (pn_space) { + case QUICPacketNumberSpace::Initial: + return "QUICPacketNumberSpace::Initial"; + case QUICPacketNumberSpace::Handshake: + return "QUICPacketNumberSpace::Handshake"; + case QUICPacketNumberSpace::ApplicationData: + return "QUICPacketNumberSpace::ApplicationData"; default: return "UNKNOWN"; } diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h index 926f552efd9..f80c8ae6202 100644 --- a/iocore/net/quic/QUICDebugNames.h +++ b/iocore/net/quic/QUICDebugNames.h @@ -42,7 +42,7 @@ class QUICDebugNames static const char *quic_event(int event); static const char *key_phase(QUICKeyPhase phase); static const char *encryption_level(QUICEncryptionLevel level); - static const char *pn_space(int index); + static const char *pn_space(QUICPacketNumberSpace pn_space); }; class QUICDebug diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 0e3a8b9b1df..9414363c3f5 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -30,16 +30,12 @@ #include "QUICDebugNames.h" #include "QUICFrameGenerator.h" -#define QUICLDDebug(fmt, ...) \ - Debug("quic_loss_detector", "[%s] [%s] " fmt, this->_info->cids().data(), QUICDebugNames::pn_space(this->_pn_space_index), \ - ##__VA_ARGS__) -#define QUICLDVDebug(fmt, ...) \ - Debug("v_quic_loss_detector", "[%s] [%s] " fmt, this->_info->cids().data(), QUICDebugNames::pn_space(this->_pn_space_index), \ - ##__VA_ARGS__) +#define QUICLDDebug(fmt, ...) Debug("quic_loss_detector", "[%s] " fmt, this->_info->cids().data(), ##__VA_ARGS__) +#define QUICLDVDebug(fmt, ...) Debug("v_quic_loss_detector", "[%s] " fmt, this->_info->cids().data(), ##__VA_ARGS__) QUICLossDetector::QUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, - int index, const QUICLDConfig &ld_config) - : _info(info), _cc(cc), _rtt_measure(rtt_measure), _pn_space_index(index) + const QUICLDConfig &ld_config) + : _info(info), _cc(cc), _rtt_measure(rtt_measure) { this->mutex = new_ProxyMutex(); this->_loss_detection_mutex = new_ProxyMutex(); @@ -61,7 +57,9 @@ QUICLossDetector::~QUICLossDetector() this->_loss_detection_timer = nullptr; } - this->_sent_packets.clear(); + for (auto i = 0; i < kPacketNumberSpace; i++) { + this->_sent_packets[i].clear(); + } this->_cc = nullptr; } @@ -105,14 +103,10 @@ QUICLossDetector::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame { QUICConnectionErrorUPtr error = nullptr; - if (this->_pn_space_index != QUICTypeUtil::pn_space_index(level)) { - return error; - } - switch (frame.type()) { case QUICFrameType::ACK: this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); - this->_on_ack_received(static_cast(frame)); + this->_on_ack_received(static_cast(frame), QUICTypeUtil::pn_space(level)); break; default: QUICLDDebug("Unexpected frame type: %02x", static_cast(frame.type())); @@ -124,9 +118,10 @@ QUICLossDetector::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame } QUICPacketNumber -QUICLossDetector::largest_acked_packet_number() +QUICLossDetector::largest_acked_packet_number(QUICPacketNumberSpace pn_space) { - return this->_largest_acked_packet; + int index = static_cast(pn_space); + return this->_largest_acked_packet[index]; } void @@ -145,7 +140,6 @@ QUICLossDetector::on_packet_sent(QUICPacketInfoUPtr packet_info, bool in_flight) bool is_crypto_packet = packet_info->is_crypto_packet; ink_hrtime now = packet_info->time_sent; size_t sent_bytes = packet_info->sent_bytes; - this->_largest_sent_packet = packet_info->packet_number; this->_add_to_sent_packet_list(packet_number, std::move(packet_info)); @@ -171,19 +165,19 @@ QUICLossDetector::reset() this->_loss_detection_timer = nullptr; } - this->_sent_packets.clear(); - // [draft-17 recovery] 6.4.3. Initialization this->_crypto_count = 0; this->_pto_count = 0; - this->_loss_time = 0; this->_smoothed_rtt = 0; this->_rttvar = 0; this->_min_rtt = INT64_MAX; this->_time_of_last_sent_ack_eliciting_packet = 0; this->_time_of_last_sent_crypto_packet = 0; - this->_largest_sent_packet = 0; - this->_largest_acked_packet = 0; + for (auto i = 0; i < kPacketNumberSpace; i++) { + this->_largest_acked_packet[i] = 0; + this->_loss_time[i] = 0; + this->_sent_packets[i].clear(); + } } void @@ -193,34 +187,35 @@ QUICLossDetector::update_ack_delay_exponent(uint8_t ack_delay_exponent) } void -QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame) +QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame, QUICPacketNumberSpace pn_space) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - this->_largest_acked_packet = std::max(this->_largest_acked_packet, ack_frame.largest_acknowledged()); + int index = static_cast(pn_space); + this->_largest_acked_packet[index] = std::max(this->_largest_acked_packet[index], ack_frame.largest_acknowledged()); // If the largest acknowledged is newly acked and // ack-eliciting, update the RTT. - auto pi = this->_sent_packets.find(ack_frame.largest_acknowledged()); - if (pi != this->_sent_packets.end()) { + auto pi = this->_sent_packets[index].find(ack_frame.largest_acknowledged()); + if (pi != this->_sent_packets[index].end() && pi->second->ack_eliciting) { this->_latest_rtt = Thread::get_hrtime() - pi->second->time_sent; // _latest_rtt is nanosecond but ack_frame.ack_delay is microsecond and scaled ink_hrtime delay = HRTIME_USECONDS(ack_frame.ack_delay() << this->_ack_delay_exponent); this->_update_rtt(this->_latest_rtt, delay); } - QUICLDVDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), - this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); + QUICLDVDebug("[%s] Unacked packets %lu (retransmittable %u, includes %u handshake packets)", QUICDebugNames::pn_space(pn_space), + this->_sent_packets[index].size(), this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); // if (ACK frame contains ECN information): // ProcessECN(ack) - if (ack_frame.ecn_section() != nullptr && pi != this->_sent_packets.end()) { + if (ack_frame.ecn_section() != nullptr && pi != this->_sent_packets[index].end()) { this->_cc->process_ecn(*pi->second, ack_frame.ecn_section(), this->_pto_count); } // Find all newly acked packets. bool newly_acked_packets = false; for (auto &&range : this->_determine_newly_acked_packets(ack_frame)) { - for (auto ite = this->_sent_packets.begin(); ite != this->_sent_packets.end(); /* no increment here*/) { + for (auto ite = this->_sent_packets[index].begin(); ite != this->_sent_packets[index].end(); /* no increment here*/) { auto tmp_ite = ite; tmp_ite++; if (range.contains(ite->first)) { @@ -235,16 +230,16 @@ QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame) return; } - QUICLDVDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), - this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); + QUICLDVDebug("[%s] Unacked packets %lu (retransmittable %u, includes %u handshake packets)", QUICDebugNames::pn_space(pn_space), + this->_sent_packets[index].size(), this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); - this->_detect_lost_packets(); + this->_detect_lost_packets(pn_space); this->_crypto_count = 0; this->_pto_count = 0; - QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), - this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); + QUICLDDebug("[%s] Unacked packets %lu (retransmittable %u, includes %u handshake packets)", QUICDebugNames::pn_space(pn_space), + this->_sent_packets[index].size(), this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); this->_set_loss_detection_timer(); } @@ -292,7 +287,22 @@ QUICLossDetector::_on_packet_acked(const QUICPacketInfo &acked_packet) reactor->on_frame_acked(frame_info.id()); } - this->_remove_from_sent_packet_list(acked_packet.packet_number); + this->_remove_from_sent_packet_list(acked_packet.packet_number, acked_packet.pn_space); +} + +ink_hrtime +QUICLossDetector::_get_earliest_loss_time(QUICPacketNumberSpace &pn_space) +{ + ink_hrtime time = this->_loss_time[static_cast(QUICPacketNumberSpace::Initial)]; + pn_space = QUICPacketNumberSpace::Initial; + for (auto i = 1; i < kPacketNumberSpace; i++) { + if (this->_loss_time[i] != 0 && (time != 0 || this->_loss_time[i] < time)) { + time = this->_loss_time[i]; + pn_space = static_cast(i); + } + } + + return time; } void @@ -315,7 +325,14 @@ QUICLossDetector::_set_loss_detection_timer() } // -- END OF MODIFIED CODE -- - if (this->_crypto_outstanding) { + QUICPacketNumberSpace pn_space; + ink_hrtime loss_time = this->_get_earliest_loss_time(pn_space); + if (loss_time != 0) { + // Time threshold loss detection. + this->_loss_detection_alarm_at = loss_time; + QUICLDDebug("[%s] time threshold loss detection timer: %" PRId64, QUICDebugNames::pn_space(pn_space), + this->_loss_detection_alarm_at); + } else if (this->_crypto_outstanding) { // Handshake retransmission alarm. if (this->_smoothed_rtt == 0) { timeout = 2 * this->_k_initial_rtt; @@ -326,56 +343,50 @@ QUICLossDetector::_set_loss_detection_timer() timeout = timeout * (1 << this->_crypto_count); this->_loss_detection_alarm_at = this->_time_of_last_sent_crypto_packet + timeout; - QUICLDDebug("crypto packet alarm will be set: %" PRId64, this->_loss_detection_alarm_at); + QUICLDDebug("%s crypto packet alarm will be set: %" PRId64, QUICDebugNames::pn_space(pn_space), this->_loss_detection_alarm_at); // -- ADDITIONAL CODE -- // In psudocode returning here, but we don't do for scheduling _loss_detection_alarm event. // -- END OF ADDITIONAL CODE -- } else { - if (this->_loss_time != 0) { - // Time threshold loss detection. - this->_loss_detection_alarm_at = this->_loss_time; - QUICLDDebug("time threshold loss detection timer: %" PRId64, this->_loss_detection_alarm_at); - - } else { - // PTO Duration - timeout = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; - timeout = std::max(timeout, this->_k_granularity); - timeout = timeout * (1 << this->_pto_count); - this->_loss_detection_alarm_at = this->_time_of_last_sent_ack_eliciting_packet + timeout; - QUICLDDebug("PTO timeout will be set: %" PRId64, this->_loss_detection_alarm_at); - } - - QUICLDDebug("Loss detection alarm has been set to %" PRId64 "ms", timeout / HRTIME_MSECOND); + // PTO Duration + timeout = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; + timeout = std::max(timeout, this->_k_granularity); + timeout = timeout * (1 << this->_pto_count); + this->_loss_detection_alarm_at = this->_time_of_last_sent_ack_eliciting_packet + timeout; + QUICLDDebug("[%s] PTO timeout will be set: %" PRId64, QUICDebugNames::pn_space(pn_space), this->_loss_detection_alarm_at); + } - if (!this->_loss_detection_timer) { - this->_loss_detection_timer = eventProcessor.schedule_every(this, HRTIME_MSECONDS(25)); - } + if (!this->_loss_detection_timer) { + this->_loss_detection_timer = eventProcessor.schedule_every(this, HRTIME_MSECONDS(25)); } } void QUICLossDetector::_on_loss_detection_timeout() { - if (this->_crypto_outstanding) { + QUICPacketNumberSpace pn_space; + ink_hrtime loss_time = this->_get_earliest_loss_time(pn_space); + if (loss_time != 0) { + // Time threshold loss Detection + this->_detect_lost_packets(pn_space); + } else if (this->_crypto_outstanding) { // Handshake retransmission alarm. this->_retransmit_all_unacked_crypto_data(); this->_crypto_count++; - } else if (this->_loss_time != 0) { - // Early retransmit or Time Loss Detection - this->_detect_lost_packets(); } else { QUICLDVDebug("PTO"); this->_send_two_packets(); this->_pto_count++; } - QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(), - this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); + QUICLDDebug("[%s] Unacked packets %lu (retransmittable %u, includes %u handshake packets)", QUICDebugNames::pn_space(pn_space), + this->_sent_packets[static_cast(pn_space)].size(), this->_ack_eliciting_outstanding.load(), + this->_crypto_outstanding.load()); if (is_debug_tag_set("v_quic_loss_detector")) { - for (auto &unacked : this->_sent_packets) { - QUICLDVDebug("#%" PRIu64 " is_crypto=%i ack_eliciting=%i size=%zu", unacked.first, unacked.second->is_crypto_packet, - unacked.second->ack_eliciting, unacked.second->sent_bytes); + for (auto &unacked : this->_sent_packets[static_cast(pn_space)]) { + QUICLDVDebug("[%s] #%" PRIu64 " is_crypto=%i ack_eliciting=%i size=%zu", QUICDebugNames::pn_space(pn_space), unacked.first, + unacked.second->is_crypto_packet, unacked.second->ack_eliciting, unacked.second->sent_bytes); } } @@ -383,22 +394,23 @@ QUICLossDetector::_on_loss_detection_timeout() } void -QUICLossDetector::_detect_lost_packets() +QUICLossDetector::_detect_lost_packets(QUICPacketNumberSpace pn_space) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - this->_loss_time = 0; - ink_hrtime loss_delay = this->_k_time_threshold * std::max(this->_latest_rtt, this->_smoothed_rtt); + this->_loss_time[static_cast(pn_space)] = 0; + ink_hrtime loss_delay = this->_k_time_threshold * std::max(this->_latest_rtt, this->_smoothed_rtt); std::map lost_packets; // Packets sent before this time are deemed lost. ink_hrtime lost_send_time = Thread::get_hrtime() - loss_delay; // Packets with packet numbers before this are deemed lost. - QUICPacketNumber lost_pn = this->_largest_acked_packet - this->_k_packet_threshold; + QUICPacketNumber lost_pn = this->_largest_acked_packet[static_cast(pn_space)] - this->_k_packet_threshold; - for (auto it = this->_sent_packets.begin(); it != this->_sent_packets.end(); ++it) { - if (it->first >= this->_largest_acked_packet) { - break; + for (auto it = this->_sent_packets[static_cast(pn_space)].begin(); + it != this->_sent_packets[static_cast(pn_space)].end(); ++it) { + if (it->first > this->_largest_acked_packet[static_cast(pn_space)]) { + continue; } auto &unacked = it->second; @@ -406,20 +418,23 @@ QUICLossDetector::_detect_lost_packets() // Mark packet as lost, or set time when it should be marked. if (unacked->time_sent < lost_send_time || unacked->packet_number < lost_pn) { if (unacked->time_sent < lost_send_time) { - QUICLDDebug("Lost: time since sent is too long (#%" PRId64 " sent=%" PRId64 ", delay=%" PRId64 + QUICLDDebug("[%s] Lost: time since sent is too long (#%" PRId64 " sent=%" PRId64 ", delay=%" PRId64 ", fraction=%lf, lrtt=%" PRId64 ", srtt=%" PRId64 ")", - it->first, unacked->time_sent, lost_send_time, this->_k_time_threshold, this->_latest_rtt, this->_smoothed_rtt); + QUICDebugNames::pn_space(pn_space), it->first, unacked->time_sent, lost_send_time, this->_k_time_threshold, + this->_latest_rtt, this->_smoothed_rtt); } else { - QUICLDDebug("Lost: packet delta is too large (#%" PRId64 " largest=%" PRId64 " threshold=%" PRId32 ")", it->first, - this->_largest_acked_packet, this->_k_packet_threshold); + QUICLDDebug("[%s] Lost: packet delta is too large (#%" PRId64 " largest=%" PRId64 " threshold=%" PRId32 ")", + QUICDebugNames::pn_space(pn_space), it->first, this->_largest_acked_packet[static_cast(pn_space)], + this->_k_packet_threshold); } if (unacked->in_flight) { lost_packets.insert({it->first, it->second.get()}); } else if (this->_loss_time == 0) { - this->_loss_time = unacked->time_sent + loss_delay; + this->_loss_time[static_cast(pn_space)] = unacked->time_sent + loss_delay; } else { - this->_loss_time = std::min(this->_loss_time, unacked->time_sent + loss_delay); + this->_loss_time[static_cast(pn_space)] = + std::min(this->_loss_time[static_cast(pn_space)], unacked->time_sent + loss_delay); } } } @@ -436,7 +451,7 @@ QUICLossDetector::_detect_lost_packets() this->_retransmit_lost_packet(*lost_packet.second); // -- END OF ADDITIONAL CODE -- // -- ADDITIONAL CODE -- - this->_remove_from_sent_packet_list(lost_packet.first); + this->_remove_from_sent_packet_list(lost_packet.first, pn_space); // -- END OF ADDITIONAL CODE -- } } @@ -451,17 +466,19 @@ QUICLossDetector::_retransmit_all_unacked_crypto_data() std::set retransmitted_crypto_packets; std::map lost_packets; - for (auto &info : this->_sent_packets) { - if (info.second->is_crypto_packet) { - retransmitted_crypto_packets.insert(info.first); - this->_retransmit_lost_packet(*info.second); - lost_packets.insert({info.first, info.second.get()}); + for (auto i = 0; i < kPacketNumberSpace; i++) { + for (auto &info : this->_sent_packets[i]) { + if (info.second->is_crypto_packet) { + retransmitted_crypto_packets.insert(info.first); + this->_retransmit_lost_packet(*info.second); + lost_packets.insert({info.first, info.second.get()}); + } } - } - this->_cc->on_packets_lost(lost_packets, this->_pto_count); - for (auto packet_number : retransmitted_crypto_packets) { - this->_remove_from_sent_packet_list(packet_number); + this->_cc->on_packets_lost(lost_packets, this->_pto_count); + for (auto packet_number : retransmitted_crypto_packets) { + this->_remove_from_sent_packet_list(packet_number, static_cast(i)); + } } } @@ -512,11 +529,12 @@ QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, QUICP SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); // Add to the list - this->_sent_packets.insert(std::pair(packet_number, std::move(packet_info))); + int index = static_cast(packet_info->pn_space); + this->_sent_packets[index].insert(std::pair(packet_number, std::move(packet_info))); // Increment counters - auto ite = this->_sent_packets.find(packet_number); - if (ite != this->_sent_packets.end()) { + auto ite = this->_sent_packets[index].find(packet_number); + if (ite != this->_sent_packets[index].end()) { if (ite->second->is_crypto_packet) { ++this->_crypto_outstanding; ink_assert(this->_crypto_outstanding.load() > 0); @@ -529,28 +547,30 @@ QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, QUICP } void -QUICLossDetector::_remove_from_sent_packet_list(QUICPacketNumber packet_number) +QUICLossDetector::_remove_from_sent_packet_list(QUICPacketNumber packet_number, QUICPacketNumberSpace pn_space) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - auto ite = this->_sent_packets.find(packet_number); - this->_decrement_outstanding_counters(ite); - this->_sent_packets.erase(packet_number); + auto ite = this->_sent_packets[static_cast(pn_space)].find(packet_number); + this->_decrement_outstanding_counters(ite, pn_space); + this->_sent_packets[static_cast(pn_space)].erase(packet_number); } std::map::iterator -QUICLossDetector::_remove_from_sent_packet_list(std::map::iterator it) +QUICLossDetector::_remove_from_sent_packet_list(std::map::iterator it, + QUICPacketNumberSpace pn_space) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - this->_decrement_outstanding_counters(it); - return this->_sent_packets.erase(it); + this->_decrement_outstanding_counters(it, pn_space); + return this->_sent_packets[static_cast(pn_space)].erase(it); } void -QUICLossDetector::_decrement_outstanding_counters(std::map::iterator it) +QUICLossDetector::_decrement_outstanding_counters(std::map::iterator it, + QUICPacketNumberSpace pn_space) { - if (it != this->_sent_packets.end()) { + if (it != this->_sent_packets[static_cast(pn_space)].end()) { // Decrement counters if (it->second->is_crypto_packet) { ink_assert(this->_crypto_outstanding.load() > 0); diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 56787e75318..3f317330195 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -51,11 +51,14 @@ struct QUICPacketInfo { // addition QUICPacketType type; std::vector frames; + QUICPacketNumberSpace pn_space; // end }; using QUICPacketInfoUPtr = std::unique_ptr; +static constexpr uint8_t kPacketNumberSpace = 3; + class QUICRTTProvider { public: @@ -119,7 +122,7 @@ class QUICCongestionController class QUICLossDetector : public Continuation, public QUICFrameHandler { public: - QUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, int index, + QUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, const QUICLDConfig &ld_config); ~QUICLossDetector(); @@ -128,7 +131,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler std::vector interests() override; virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override; void on_packet_sent(QUICPacketInfoUPtr packet_info, bool in_flight = true); - QUICPacketNumber largest_acked_packet_number(); + QUICPacketNumber largest_acked_packet_number(QUICPacketNumberSpace pn_space); void update_ack_delay_exponent(uint8_t ack_delay_exponent); void reset(); ink_hrtime current_rto_period(); @@ -147,30 +150,29 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler // [draft-11 recovery] 3.5.2. Variables of interest // Keep the order as the same as the spec so that we can see the difference easily. - Action *_loss_detection_timer = nullptr; - uint32_t _crypto_count = 0; - uint32_t _pto_count = 0; - ink_hrtime _time_of_last_sent_ack_eliciting_packet = 0; - ink_hrtime _time_of_last_sent_crypto_packet = 0; - QUICPacketNumber _largest_sent_packet = 0; - QUICPacketNumber _largest_acked_packet = 0; - ink_hrtime _latest_rtt = 0; - ink_hrtime _smoothed_rtt = 0; - ink_hrtime _rttvar = 0; - ink_hrtime _min_rtt = INT64_MAX; - ink_hrtime _max_ack_delay = 0; - ink_hrtime _loss_time = 0; - std::map _sent_packets; + Action *_loss_detection_timer = nullptr; + uint32_t _crypto_count = 0; + uint32_t _pto_count = 0; + ink_hrtime _time_of_last_sent_ack_eliciting_packet = 0; + ink_hrtime _time_of_last_sent_crypto_packet = 0; + ink_hrtime _latest_rtt = 0; + ink_hrtime _smoothed_rtt = 0; + ink_hrtime _rttvar = 0; + ink_hrtime _min_rtt = INT64_MAX; + ink_hrtime _max_ack_delay = 0; + ink_hrtime _loss_time[kPacketNumberSpace] = {0}; + QUICPacketNumber _largest_acked_packet[kPacketNumberSpace] = {0}; + std::map _sent_packets[kPacketNumberSpace]; // These are not defined on the spec but expected to be count // These counter have to be updated when inserting / erasing packets from _sent_packets with following functions. std::atomic _crypto_outstanding; std::atomic _ack_eliciting_outstanding; void _add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr packet_info); - void _remove_from_sent_packet_list(QUICPacketNumber packet_number); + void _remove_from_sent_packet_list(QUICPacketNumber packet_number, QUICPacketNumberSpace pn_space); std::map::iterator _remove_from_sent_packet_list( - std::map::iterator it); - void _decrement_outstanding_counters(std::map::iterator it); + std::map::iterator it, QUICPacketNumberSpace pn_space); + void _decrement_outstanding_counters(std::map::iterator it, QUICPacketNumberSpace pn_space); /* * Because this alarm will be reset on every packet transmission, to reduce number of events, @@ -178,14 +180,16 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler */ ink_hrtime _loss_detection_alarm_at = 0; - void _on_ack_received(const QUICAckFrame &ack_frame); + void _on_ack_received(const QUICAckFrame &ack_frame, QUICPacketNumberSpace pn_space); void _on_packet_acked(const QUICPacketInfo &acked_packet); void _update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay); - void _detect_lost_packets(); + void _detect_lost_packets(QUICPacketNumberSpace pn_space); void _set_loss_detection_timer(); void _on_loss_detection_timeout(); void _retransmit_lost_packet(QUICPacketInfo &packet_info); + ink_hrtime _get_earliest_loss_time(QUICPacketNumberSpace &pn_space); + std::set _determine_newly_acked_packets(const QUICAckFrame &ack_frame); void _retransmit_all_unacked_crypto_data(); diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc index 14a8f930a33..8aab3fda0d0 100644 --- a/iocore/net/quic/QUICPacketFactory.cc +++ b/iocore/net/quic/QUICPacketFactory.cc @@ -212,8 +212,8 @@ QUICPacketFactory::create_initial_packet(QUICConnectionId destination_cid, QUICC 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) { - int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::INITIAL); - QUICPacketNumber pn = this->_packet_number_generator[index].next(); + QUICPacketNumberSpace index = QUICTypeUtil::pn_space(QUICEncryptionLevel::INITIAL); + QUICPacketNumber pn = this->_packet_number_generator[static_cast(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); @@ -238,8 +238,8 @@ QUICPacketFactory::create_handshake_packet(QUICConnectionId destination_cid, QUI QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable, bool probing, bool crypto) { - int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::HANDSHAKE); - QUICPacketNumber pn = this->_packet_number_generator[index].next(); + QUICPacketNumberSpace index = QUICTypeUtil::pn_space(QUICEncryptionLevel::INITIAL); + QUICPacketNumber pn = this->_packet_number_generator[static_cast(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); @@ -251,8 +251,8 @@ QUICPacketFactory::create_zero_rtt_packet(QUICConnectionId destination_cid, QUIC QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable, bool probing) { - int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ZERO_RTT); - QUICPacketNumber pn = this->_packet_number_generator[index].next(); + QUICPacketNumberSpace index = QUICTypeUtil::pn_space(QUICEncryptionLevel::INITIAL); + QUICPacketNumber pn = this->_packet_number_generator[static_cast(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); @@ -263,8 +263,8 @@ QUICPacketUPtr QUICPacketFactory::create_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload, size_t len, bool retransmittable, bool probing) { - int index = QUICTypeUtil::pn_space_index(QUICEncryptionLevel::ONE_RTT); - QUICPacketNumber pn = this->_packet_number_generator[index].next(); + QUICPacketNumberSpace index = QUICTypeUtil::pn_space(QUICEncryptionLevel::INITIAL); + QUICPacketNumber pn = this->_packet_number_generator[static_cast(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); diff --git a/iocore/net/quic/QUICPinger.cc b/iocore/net/quic/QUICPinger.cc index e1a70ee0f4b..e6f69c69d5d 100644 --- a/iocore/net/quic/QUICPinger.cc +++ b/iocore/net/quic/QUICPinger.cc @@ -51,7 +51,7 @@ QUICPinger::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) return false; } - return this->_need_to_fire[QUICTypeUtil::pn_space_index(level)] > 0; + return this->_need_to_fire[static_cast(QUICTypeUtil::pn_space(level))] > 0; } /** diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 28c363ad1b0..13fd10ddfa4 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -146,14 +146,17 @@ QUICTypeUtil::key_phase(QUICPacketType type) } // 0-RTT and 1-RTT use same Packet Number Space -int -QUICTypeUtil::pn_space_index(QUICEncryptionLevel level) +QUICPacketNumberSpace +QUICTypeUtil::pn_space(QUICEncryptionLevel level) { - if (level == QUICEncryptionLevel::ONE_RTT) { - level = QUICEncryptionLevel::ZERO_RTT; + switch (level) { + case QUICEncryptionLevel::HANDSHAKE: + return QUICPacketNumberSpace::Handshake; + case QUICEncryptionLevel::INITIAL: + return QUICPacketNumberSpace::Initial; + default: + return QUICPacketNumberSpace::ApplicationData; } - - return static_cast(level); } QUICConnectionId diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index c9273c8c9d5..3f3a16e39e5 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -71,6 +71,13 @@ constexpr QUICEncryptionLevel QUIC_ENCRYPTION_LEVELS[] = { QUICEncryptionLevel::ONE_RTT, }; +// introduce by draft-19 kPacketNumberSpace +enum class QUICPacketNumberSpace { + Initial, + Handshake, + ApplicationData, +}; + // 0-RTT and 1-RTT use same Packet Number Space constexpr QUICEncryptionLevel QUIC_PN_SPACES[] = { QUICEncryptionLevel::INITIAL, @@ -499,7 +506,7 @@ class QUICTypeUtil static QUICEncryptionLevel encryption_level(QUICPacketType type); static QUICPacketType packet_type(QUICEncryptionLevel level); static QUICKeyPhase key_phase(QUICPacketType type); - static int pn_space_index(QUICEncryptionLevel level); + static QUICPacketNumberSpace pn_space(QUICEncryptionLevel level); static QUICConnectionId read_QUICConnectionId(const uint8_t *buf, uint8_t n); static int read_QUICPacketNumberLen(const uint8_t *buf); From 2432f39f1535c420b05bc4f91152dc090733104b Mon Sep 17 00:00:00 2001 From: scw00 Date: Sun, 28 Apr 2019 02:42:48 +0000 Subject: [PATCH 1264/1313] Fixed coredump in Loss Detector --- iocore/net/quic/QUICLossDetector.cc | 22 ++++++++++++++-------- iocore/net/quic/QUICLossDetector.h | 1 - 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 9414363c3f5..bcd255c6a6d 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -165,6 +165,9 @@ QUICLossDetector::reset() this->_loss_detection_timer = nullptr; } + this->_ack_eliciting_outstanding = 0; + this->_crypto_outstanding = 0; + // [draft-17 recovery] 6.4.3. Initialization this->_crypto_count = 0; this->_pto_count = 0; @@ -384,9 +387,13 @@ QUICLossDetector::_on_loss_detection_timeout() this->_crypto_outstanding.load()); if (is_debug_tag_set("v_quic_loss_detector")) { - for (auto &unacked : this->_sent_packets[static_cast(pn_space)]) { - QUICLDVDebug("[%s] #%" PRIu64 " is_crypto=%i ack_eliciting=%i size=%zu", QUICDebugNames::pn_space(pn_space), unacked.first, - unacked.second->is_crypto_packet, unacked.second->ack_eliciting, unacked.second->sent_bytes); + for (auto i = 0; i < 3; i++) { + for (auto &unacked : this->_sent_packets[i]) { + QUICLDVDebug("[%s] #%" PRIu64 " is_crypto=%i ack_eliciting=%i size=%zu %u %u", + QUICDebugNames::pn_space(static_cast(i)), unacked.first, + unacked.second->is_crypto_packet, unacked.second->ack_eliciting, unacked.second->sent_bytes, + this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); + } } } @@ -463,10 +470,9 @@ void QUICLossDetector::_retransmit_all_unacked_crypto_data() { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); - std::set retransmitted_crypto_packets; - std::map lost_packets; - for (auto i = 0; i < kPacketNumberSpace; i++) { + std::set retransmitted_crypto_packets; + std::map lost_packets; for (auto &info : this->_sent_packets[i]) { if (info.second->is_crypto_packet) { retransmitted_crypto_packets.insert(info.first); @@ -539,7 +545,7 @@ QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, QUICP ++this->_crypto_outstanding; ink_assert(this->_crypto_outstanding.load() > 0); } - if (!ite->second->ack_eliciting) { + if (ite->second->ack_eliciting) { ++this->_ack_eliciting_outstanding; ink_assert(this->_ack_eliciting_outstanding.load() > 0); } @@ -576,7 +582,7 @@ QUICLossDetector::_decrement_outstanding_counters(std::map_crypto_outstanding.load() > 0); --this->_crypto_outstanding; } - if (!it->second->ack_eliciting) { + if (it->second->ack_eliciting) { ink_assert(this->_ack_eliciting_outstanding.load() > 0); --this->_ack_eliciting_outstanding; } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 3f317330195..8715149d9ba 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -199,5 +199,4 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler QUICConnectionInfoProvider *_info = nullptr; QUICCongestionController *_cc = nullptr; QUICRTTMeasure *_rtt_measure = nullptr; - int _pn_space_index = -1; }; From 97c9898c90cb1153fe015fc04cfc574f4c9b6281 Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 29 Apr 2019 01:04:44 +0000 Subject: [PATCH 1265/1313] QUIC: Update CC to draft 19 --- iocore/net/QUICNetVConnection.cc | 1 + iocore/net/quic/QUICCongestionController.cc | 75 ++++++++++++++++++--- iocore/net/quic/QUICLossDetector.cc | 13 +++- iocore/net/quic/QUICLossDetector.h | 14 +++- 4 files changed, 87 insertions(+), 16 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a9e5418fca8..602c7ce287e 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -453,6 +453,7 @@ QUICNetVConnection::start() QUICLDConfigQCP ld_config(this->_quic_config); this->_congestion_controller = new QUICCongestionController(this, cc_config); this->_loss_detector = new QUICLossDetector(this, this->_congestion_controller, &this->_rtt_measure, ld_config); + this->_congestion_controller->bind_loss_detector(this->_loss_detector); this->_frame_dispatcher->add_handler(this->_loss_detector); this->_remote_flow_controller = new QUICRemoteConnectionFlowController(UINT64_MAX); diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 93ff5497277..3a8e1437ca0 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -62,6 +62,13 @@ QUICCongestionController::_in_recovery(ink_hrtime sent_time) return sent_time <= this->_recovery_start_time; } +bool +QUICCongestionController::is_app_limited() +{ + // FIXME : don't known how does app worked here + return false; +} + void QUICCongestionController::on_packet_acked(const QUICPacketInfo &acked_packet) { @@ -72,6 +79,13 @@ QUICCongestionController::on_packet_acked(const QUICPacketInfo &acked_packet) // Do not increase congestion window in recovery period. return; } + + if (this->is_app_limited()) { + // Do not increase congestion_window if application + // limited. + return; + } + if (this->_congestion_window < this->_ssthresh) { // Slow start. this->_congestion_window += acked_packet.sent_bytes; @@ -87,7 +101,7 @@ QUICCongestionController::on_packet_acked(const QUICPacketInfo &acked_packet) // the original one is: // CongestionEvent(sent_time): void -QUICCongestionController::_congestion_event(ink_hrtime sent_time, uint32_t pto_count) +QUICCongestionController::_congestion_event(ink_hrtime sent_time) { // Start a new congestion event if the sent time is larger // than the start time of the previous recovery epoch. @@ -96,9 +110,6 @@ QUICCongestionController::_congestion_event(ink_hrtime sent_time, uint32_t pto_c 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; - if (pto_count > this->_k_persistent_congestion_threshold) { - this->_congestion_window = this->_k_minimum_window; - } } } @@ -106,8 +117,7 @@ QUICCongestionController::_congestion_event(ink_hrtime sent_time, uint32_t pto_c // the original one is: // ProcessECN(ack): void -QUICCongestionController::process_ecn(const QUICPacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section, - uint32_t pto_count) +QUICCongestionController::process_ecn(const QUICPacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section) { // If the ECN-CE counter reported by the peer has increased, // this could be a new congestion event. @@ -116,15 +126,26 @@ QUICCongestionController::process_ecn(const QUICPacketInfo &acked_largest_packet // Start a new congestion event if the last acknowledged // packet was sent after the start of the previous // recovery epoch. - this->_congestion_event(acked_largest_packet.time_sent, pto_count); + this->_congestion_event(acked_largest_packet.time_sent); } } +bool +QUICCongestionController::_in_persistent_congestion(const std::map &lost_packets, + QUICPacketInfo *largest_lost_packet) +{ + ink_hrtime period = this->_loss_detector->congestion_period(this->_k_persistent_congestion_threshold); + // Determine if all packets in the window before the + // newest lost packet, including the edges, are marked + // lost + return this->_in_window_lost(lost_packets, largest_lost_packet, period); +} + // additional code // the original one is: // OnPacketsLost(lost_packets): void -QUICCongestionController::on_packets_lost(const std::map &lost_packets, uint32_t pto_count) +QUICCongestionController::on_packets_lost(const std::map &lost_packets) { if (lost_packets.empty()) { return; @@ -135,10 +156,15 @@ QUICCongestionController::on_packets_lost(const std::map_bytes_in_flight -= lost_packet.second->sent_bytes; } - auto &largest_lost_packet = lost_packets.rbegin()->second; + QUICPacketInfo *largest_lost_packet = lost_packets.rbegin()->second; // Start a new recovery epoch if the lost packet is larger // than the end of the previous recovery epoch. - this->_congestion_event(largest_lost_packet->time_sent, pto_count); + this->_congestion_event(largest_lost_packet->time_sent); + + // Collapse congestion window if persistent congestion + if (this->_in_persistent_congestion(lost_packets, largest_lost_packet)) { + this->_congestion_window = this->_k_minimum_window; + } } bool @@ -190,3 +216,32 @@ QUICCongestionController::reset() this->_recovery_start_time = 0; this->_ssthresh = UINT32_MAX; } + +void +QUICCongestionController::bind_loss_detector(QUICLossDetector *loss_detector) +{ + this->_loss_detector = loss_detector; +} + +bool +QUICCongestionController::_in_window_lost(const std::map &lost_packets, + QUICPacketInfo *largest_lost_packet, ink_hrtime period) const +{ + QUICPacketNumber next_expected = UINT64_MAX; + for (auto &it : lost_packets) { + if (it.second->time_sent >= largest_lost_packet->time_sent - period) { + if (next_expected == UINT64_MAX) { + next_expected = it.second->packet_number + 1; + continue; + } + + if (next_expected != it.second->packet_number) { + return false; + } + + next_expected = it.second->packet_number + 1; + } + } + + return next_expected == UINT64_MAX ? false : true; +} diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index bcd255c6a6d..7d3884d6e86 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -212,7 +212,7 @@ QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame, QUICPacketNumb // if (ACK frame contains ECN information): // ProcessECN(ack) if (ack_frame.ecn_section() != nullptr && pi != this->_sent_packets[index].end()) { - this->_cc->process_ecn(*pi->second, ack_frame.ecn_section(), this->_pto_count); + this->_cc->process_ecn(*pi->second, ack_frame.ecn_section()); } // Find all newly acked packets. @@ -449,7 +449,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumberSpace pn_space) // Inform the congestion controller of lost packets and // lets it decide whether to retransmit immediately. if (!lost_packets.empty()) { - this->_cc->on_packets_lost(lost_packets, this->_pto_count); + this->_cc->on_packets_lost(lost_packets); for (auto lost_packet : lost_packets) { // -- 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 @@ -481,7 +481,7 @@ QUICLossDetector::_retransmit_all_unacked_crypto_data() } } - this->_cc->on_packets_lost(lost_packets, this->_pto_count); + this->_cc->on_packets_lost(lost_packets); for (auto packet_number : retransmitted_crypto_packets) { this->_remove_from_sent_packet_list(packet_number, static_cast(i)); } @@ -599,6 +599,13 @@ QUICLossDetector::current_rto_period() return alarm_duration; } +ink_hrtime +QUICLossDetector::congestion_period(uint32_t threshold) const +{ + ink_hrtime pto = this->_smoothed_rtt + std::max(this->_rttvar * 4, this->_k_granularity); + return pto * (1 << (threshold - 1)); +} + // // QUICRTTMeasure // diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 8715149d9ba..63a54f1838d 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -82,12 +82,14 @@ class QUICCongestionController virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); void on_packet_acked(const QUICPacketInfo &acked_packet); - virtual void on_packets_lost(const std::map &packets, uint32_t pto_count); + virtual void on_packets_lost(const std::map &packets); void on_retransmission_timeout_verified(); - void process_ecn(const QUICPacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section, uint32_t pto_count); + void process_ecn(const QUICPacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section); bool check_credit() const; uint32_t open_window() const; void reset(); + bool is_app_limited(); + void bind_loss_detector(QUICLossDetector *loss_detector); // Debug uint32_t bytes_in_flight() const; @@ -97,7 +99,11 @@ class QUICCongestionController private: Ptr _cc_mutex; - void _congestion_event(ink_hrtime sent_time, uint32_t pto_count); + void _congestion_event(ink_hrtime sent_time); + bool _in_persistent_congestion(const std::map &lost_packets, + QUICPacketInfo *largest_lost_packet); + bool _in_window_lost(const std::map &lost_packets, QUICPacketInfo *largest_lost_packet, + ink_hrtime period) const; // [draft-17 recovery] 7.9.1. Constants of interest // Values will be loaded from records.config via QUICConfig at constructor @@ -115,6 +121,7 @@ class QUICCongestionController uint32_t _ssthresh = UINT32_MAX; QUICConnectionInfoProvider *_info = nullptr; + QUICLossDetector *_loss_detector = nullptr; bool _in_recovery(ink_hrtime sent_time); }; @@ -135,6 +142,7 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void update_ack_delay_exponent(uint8_t ack_delay_exponent); void reset(); ink_hrtime current_rto_period(); + ink_hrtime congestion_period(uint32_t threshold) const; private: Ptr _loss_detection_mutex; From f51845b7eb1448cb8077771fadc026cbe1092e4c Mon Sep 17 00:00:00 2001 From: scw00 Date: Mon, 29 Apr 2019 01:33:19 +0000 Subject: [PATCH 1266/1313] QUIC: Fixed test changed by loss_detector --- iocore/net/quic/Mock.h | 6 +- .../net/quic/test/test_QUICFrameDispatcher.cc | 2 +- iocore/net/quic/test/test_QUICLossDetector.cc | 96 +++++++++++-------- 3 files changed, 59 insertions(+), 45 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 11d85b7631e..5cbee17c5ea 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -346,7 +346,7 @@ class MockQUICCongestionController : public QUICCongestionController } // Override virtual void - on_packets_lost(const std::map &packets, uint32_t pto_count) override + on_packets_lost(const std::map &packets) override { for (auto &p : packets) { lost_packets.insert(p.first); @@ -388,9 +388,9 @@ class MockQUICCongestionController : public QUICCongestionController class MockQUICLossDetector : public QUICLossDetector { public: - MockQUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, int index, + MockQUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, const QUICLDConfig &ld_config) - : QUICLossDetector(info, cc, rtt_measure, index, ld_config) + : QUICLossDetector(info, cc, rtt_measure, ld_config) { } void diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index dd8d6c3f218..6040df3cf49 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -43,7 +43,7 @@ TEST_CASE("QUICFrameHandler", "[quic]") MockQUICConnectionInfoProvider info; MockQUICCongestionController cc(&info, cc_config); QUICRTTMeasure rtt_measure; - MockQUICLossDetector lossDetector(&info, &cc, &rtt_measure, 0, ld_config); + MockQUICLossDetector lossDetector(&info, &cc, &rtt_measure, ld_config); QUICFrameDispatcher quicFrameDispatcher(&info); quicFrameDispatcher.add_handler(&connection); diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 9c5dbb025c8..7a63866def5 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -42,7 +42,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") MockQUICLDConfig ld_config; MockQUICConnectionInfoProvider info; MockQUICCongestionController cc(&info, cc_config); - QUICLossDetector detector(&info, &cc, &rtt_measure, 0, ld_config); + QUICLossDetector detector(&info, &cc, &rtt_measure, ld_config); ats_unique_buf payload = ats_unique_malloc(512); size_t payload_len = 512; QUICPacketUPtr packet = QUICPacketFactory::create_null_packet(); @@ -71,14 +71,17 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") false, std::move(payload), sizeof(raw)); QUICPacketUPtr packet = QUICPacketUPtr(new QUICPacket(std::move(header), std::move(payload), sizeof(raw), true, false), [](QUICPacket *p) { delete p; }); - detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet->packet_number(), - Thread::get_hrtime(), - packet->is_ack_eliciting(), - packet->is_crypto_packet(), - true, - packet->size(), - packet->type(), - {}})); + detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{ + packet->packet_number(), + Thread::get_hrtime(), + packet->is_ack_eliciting(), + packet->is_crypto_packet(), + true, + packet->size(), + packet->type(), + {}, + QUICPacketNumberSpace::Handshake, + })); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); CHECK(g.lost_frame_count >= 0); @@ -95,37 +98,38 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") SECTION("1-RTT") { // Send packet (1) to (7) - payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + QUICPacketNumberSpace pn_space = QUICPacketNumberSpace::ApplicationData; + payload = ats_unique_malloc(payload_len); + QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(pn_space), + std::move(payload), payload_len, true, false); REQUIRE(packet1 != nullptr); payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet2 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + QUICPacketUPtr packet2 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(pn_space), + std::move(payload), payload_len, true, false); payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet3 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + QUICPacketUPtr packet3 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(pn_space), + std::move(payload), payload_len, true, false); payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet4 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + QUICPacketUPtr packet4 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(pn_space), + std::move(payload), payload_len, true, false); payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet5 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + QUICPacketUPtr packet5 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(pn_space), + std::move(payload), payload_len, true, false); payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet6 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + QUICPacketUPtr packet6 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(pn_space), + std::move(payload), payload_len, true, false); payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet7 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + QUICPacketUPtr packet7 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(pn_space), + std::move(payload), payload_len, true, false); payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet8 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + QUICPacketUPtr packet8 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(pn_space), + std::move(payload), payload_len, true, false); payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet9 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + QUICPacketUPtr packet9 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(pn_space), + std::move(payload), payload_len, true, false); payload = ats_unique_malloc(payload_len); - QUICPacketUPtr packet10 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(), std::move(payload), - payload_len, true, false); + QUICPacketUPtr packet10 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(pn_space), + std::move(payload), payload_len, true, false); QUICPacketNumber pn1 = packet1->packet_number(); QUICPacketNumber pn2 = packet2->packet_number(); @@ -146,7 +150,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") true, packet1->size(), packet1->type(), - {}})); + {}, + pn_space})); detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet2->packet_number(), Thread::get_hrtime(), packet2->is_ack_eliciting(), @@ -154,7 +159,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") true, packet2->size(), packet2->type(), - {}})); + {}, + pn_space})); detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet3->packet_number(), Thread::get_hrtime(), packet3->is_ack_eliciting(), @@ -162,7 +168,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") true, packet3->size(), packet3->type(), - {}})); + {}, + pn_space})); detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet4->packet_number(), Thread::get_hrtime(), packet4->is_ack_eliciting(), @@ -170,7 +177,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") true, packet4->size(), packet4->type(), - {}})); + {}, + pn_space})); detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet5->packet_number(), Thread::get_hrtime(), packet5->is_ack_eliciting(), @@ -178,7 +186,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") true, packet5->size(), packet5->type(), - {}})); + {}, + pn_space})); detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet6->packet_number(), Thread::get_hrtime(), packet6->is_ack_eliciting(), @@ -186,7 +195,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") true, packet6->size(), packet6->type(), - {}})); + {}, + pn_space})); detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet7->packet_number(), Thread::get_hrtime(), packet6->is_ack_eliciting(), @@ -194,7 +204,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") true, packet7->size(), packet7->type(), - {}})); + {}, + pn_space})); detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet8->packet_number(), Thread::get_hrtime(), packet6->is_ack_eliciting(), @@ -202,7 +213,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") true, packet8->size(), packet8->type(), - {}})); + {}, + pn_space})); detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet9->packet_number(), Thread::get_hrtime(), packet6->is_ack_eliciting(), @@ -210,7 +222,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") true, packet9->size(), packet9->type(), - {}})); + {}, + pn_space})); detector.on_packet_sent(QUICPacketInfoUPtr(new QUICPacketInfo{packet10->packet_number(), Thread::get_hrtime(), packet10->is_ack_eliciting(), @@ -218,7 +231,8 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") true, packet10->size(), packet10->type(), - {}})); + {}, + pn_space})); ink_hrtime_sleep(HRTIME_MSECONDS(2000)); // Receive an ACK for (1) (4) (5) (7) (8) (9) @@ -259,7 +273,7 @@ TEST_CASE("QUICLossDetector_HugeGap", "[quic]") MockQUICLDConfig ld_config; MockQUICCongestionController cc(&info, cc_config); QUICRTTMeasure rtt_measure; - QUICLossDetector detector(&info, &cc, &rtt_measure, 0, ld_config); + QUICLossDetector detector(&info, &cc, &rtt_measure, ld_config); auto t1 = Thread::get_hrtime(); QUICAckFrame *ack = QUICFrameFactory::create_ack_frame(frame_buf, 100000000, 100, 10000000); From 41ae20a5d00551385a81c294346ac80a1604ca0e Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 9 May 2019 06:10:56 +0000 Subject: [PATCH 1267/1313] QUIC: remove pn_space and remove the dependency with ld --- iocore/net/QUICNetVConnection.cc | 10 +- iocore/net/quic/QUICAckFrameCreator.cc | 17 +- iocore/net/quic/QUICAckFrameCreator.h | 4 +- iocore/net/quic/QUICCongestionController.cc | 13 +- iocore/net/quic/QUICLossDetector.cc | 190 ++++++++++++-------- iocore/net/quic/QUICLossDetector.h | 81 ++++++--- iocore/net/quic/QUICPacketFactory.cc | 4 +- iocore/net/quic/QUICTypes.h | 9 +- 8 files changed, 196 insertions(+), 132 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 602c7ce287e..e088737c1da 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -451,9 +451,9 @@ QUICNetVConnection::start() // Create frame handlers QUICCCConfigQCP cc_config(this->_quic_config); QUICLDConfigQCP ld_config(this->_quic_config); - this->_congestion_controller = new QUICCongestionController(this, cc_config); + this->_rtt_measure.init(ld_config); + this->_congestion_controller = new QUICCongestionController(&this->_rtt_measure, this, cc_config); this->_loss_detector = new QUICLossDetector(this, this->_congestion_controller, &this->_rtt_measure, ld_config); - this->_congestion_controller->bind_loss_detector(this->_loss_detector); this->_frame_dispatcher->add_handler(this->_loss_detector); this->_remote_flow_controller = new QUICRemoteConnectionFlowController(UINT64_MAX); @@ -2082,7 +2082,7 @@ QUICNetVConnection::_switch_to_closing_state(QUICConnectionErrorUPtr error) this->remove_from_active_queue(); this->set_inactivity_timeout(0); - ink_hrtime rto = this->_loss_detector->current_rto_period(); + ink_hrtime rto = this->_rtt_measure.current_pto_period(); QUICConDebug("Enter state_connection_closing"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_closing); @@ -2110,7 +2110,7 @@ QUICNetVConnection::_switch_to_draining_state(QUICConnectionErrorUPtr error) this->remove_from_active_queue(); this->set_inactivity_timeout(0); - ink_hrtime rto = this->_loss_detector->current_rto_period(); + ink_hrtime rto = this->_rtt_measure.current_pto_period(); QUICConDebug("Enter state_connection_draining"); SET_HANDLER((NetVConnHandler)&QUICNetVConnection::state_connection_draining); @@ -2151,7 +2151,7 @@ QUICNetVConnection::_validate_new_path() this->_path_validator->validate(); // Not sure how long we should wait. The spec says just "enough time". // Use the same time amount as the closing timeout. - ink_hrtime rto = this->_loss_detector->current_rto_period(); + ink_hrtime rto = this->_rtt_measure.current_pto_period(); this->_schedule_path_validation_timeout(3 * rto); } diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 576ff42b765..6557f2ee8a4 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -28,9 +28,8 @@ QUICAckFrameManager::QUICAckFrameManager() { - for (auto level : QUIC_PN_SPACES) { - auto index = QUICTypeUtil::pn_space(level); - this->_ack_creator[static_cast(index)] = std::make_unique(level, this); + for (auto i = 0; i < kPacketNumberSpace; i++) { + this->_ack_creator[i] = std::make_unique(static_cast(i), this); } } @@ -132,8 +131,8 @@ QUICAckFrameManager::ack_delay_exponent() const void QUICAckFrameManager::set_max_ack_delay(uint16_t delay) { - for (auto level : QUIC_PN_SPACES) { - this->_ack_creator[static_cast(level)]->set_max_ack_delay(delay); + for (auto i = 0; i < kPacketNumberSpace; i++) { + this->_ack_creator[i]->set_max_ack_delay(delay); } } @@ -196,7 +195,7 @@ QUICAckFrameManager::QUICAckFrameCreator::push_back(QUICPacketNumber packet_numb } // can not delay handshake packet - if ((this->_level == QUICEncryptionLevel::INITIAL || this->_level == QUICEncryptionLevel::HANDSHAKE) && !ack_only) { + if ((this->_pn_space == QUICPacketNumberSpace::Initial || this->_pn_space == QUICPacketNumberSpace::Handshake) && !ack_only) { this->_should_send = true; } @@ -338,7 +337,7 @@ QUICAckFrameManager::QUICAckFrameCreator::_calculate_delay() ink_hrtime now = Thread::get_hrtime(); uint64_t delay = (now - this->_largest_ack_received_time) / 1000; uint8_t ack_delay_exponent = 3; - if (this->_level != QUICEncryptionLevel::INITIAL && this->_level != QUICEncryptionLevel::HANDSHAKE) { + if (this->_pn_space != QUICPacketNumberSpace::Initial && this->_pn_space != QUICPacketNumberSpace::Handshake) { ack_delay_exponent = this->_ack_manager->ack_delay_exponent(); } return delay >> ack_delay_exponent; @@ -368,8 +367,8 @@ QUICAckFrameManager::QUICAckFrameCreator::set_max_ack_delay(uint16_t delay) this->_max_ack_delay = delay; } -QUICAckFrameManager::QUICAckFrameCreator::QUICAckFrameCreator(QUICEncryptionLevel level, QUICAckFrameManager *ack_manager) - : _ack_manager(ack_manager), _level(level) +QUICAckFrameManager::QUICAckFrameCreator::QUICAckFrameCreator(QUICPacketNumberSpace pn_space, QUICAckFrameManager *ack_manager) + : _ack_manager(ack_manager), _pn_space(pn_space) { } diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index c9ea683a9f7..4f4c49473e9 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -41,7 +41,7 @@ class QUICAckFrameManager : public QUICFrameGenerator bool ack_only = false; QUICPacketNumber packet_number = 0; }; - QUICAckFrameCreator(QUICEncryptionLevel level, QUICAckFrameManager *ack_manager); + QUICAckFrameCreator(QUICPacketNumberSpace pn_space, QUICAckFrameManager *ack_manager); ~QUICAckFrameCreator(); void push_back(QUICPacketNumber packet_number, size_t size, bool ack_only); @@ -79,7 +79,7 @@ class QUICAckFrameManager : public QUICFrameGenerator QUICAckFrameManager *_ack_manager = nullptr; - QUICEncryptionLevel _level = QUICEncryptionLevel::NONE; + QUICPacketNumberSpace _pn_space = QUICPacketNumberSpace::Initial; }; static constexpr int MAXIMUM_PACKET_COUNT = 256; diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 3a8e1437ca0..4be6d532848 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -36,7 +36,9 @@ "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ this->_info->cids().data(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, ##__VA_ARGS__) -QUICCongestionController::QUICCongestionController(QUICConnectionInfoProvider *info, const QUICCCConfig &cc_config) : _info(info) +QUICCongestionController::QUICCongestionController(QUICRTTMeasure *rtt_measure, QUICConnectionInfoProvider *info, + const QUICCCConfig &cc_config) + : _info(info), _rtt_measure(rtt_measure) { this->_cc_mutex = new_ProxyMutex(); @@ -134,7 +136,7 @@ bool QUICCongestionController::_in_persistent_congestion(const std::map &lost_packets, QUICPacketInfo *largest_lost_packet) { - ink_hrtime period = this->_loss_detector->congestion_period(this->_k_persistent_congestion_threshold); + ink_hrtime period = this->_rtt_measure->congestion_period(this->_k_persistent_congestion_threshold); // Determine if all packets in the window before the // newest lost packet, including the edges, are marked // lost @@ -217,16 +219,11 @@ QUICCongestionController::reset() this->_ssthresh = UINT32_MAX; } -void -QUICCongestionController::bind_loss_detector(QUICLossDetector *loss_detector) -{ - this->_loss_detector = loss_detector; -} - bool QUICCongestionController::_in_window_lost(const std::map &lost_packets, QUICPacketInfo *largest_lost_packet, ink_hrtime period) const { + // check whether packets are continuous. return true if all continuous packets are in period QUICPacketNumber next_expected = UINT64_MAX; for (auto &it : lost_packets) { if (it.second->time_sent >= largest_lost_packet->time_sent - period) { diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 7d3884d6e86..cd3eb470db9 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -35,15 +35,13 @@ QUICLossDetector::QUICLossDetector(QUICConnectionInfoProvider *info, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, const QUICLDConfig &ld_config) - : _info(info), _cc(cc), _rtt_measure(rtt_measure) + : _info(info), _rtt_measure(rtt_measure), _cc(cc) { this->mutex = new_ProxyMutex(); this->_loss_detection_mutex = new_ProxyMutex(); this->_k_packet_threshold = ld_config.packet_threshold(); this->_k_time_threshold = ld_config.time_threshold(); - this->_k_granularity = ld_config.granularity(); - this->_k_initial_rtt = ld_config.initial_rtt(); this->reset(); @@ -60,8 +58,6 @@ QUICLossDetector::~QUICLossDetector() for (auto i = 0; i < kPacketNumberSpace; i++) { this->_sent_packets[i].clear(); } - - this->_cc = nullptr; } int @@ -71,7 +67,6 @@ QUICLossDetector::event_handler(int event, Event *edata) case EVENT_INTERVAL: { if (this->_loss_detection_alarm_at <= Thread::get_hrtime()) { this->_loss_detection_alarm_at = 0; - this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); this->_on_loss_detection_timeout(); } break; @@ -105,7 +100,6 @@ QUICLossDetector::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame switch (frame.type()) { case QUICFrameType::ACK: - this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); this->_on_ack_received(static_cast(frame), QUICTypeUtil::pn_space(level)); break; default: @@ -131,8 +125,6 @@ QUICLossDetector::on_packet_sent(QUICPacketInfoUPtr packet_info, bool in_flight) return; } - this->_smoothed_rtt = this->_rtt_measure->smoothed_rtt(); - SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); QUICPacketNumber packet_number = packet_info->packet_number; @@ -169,11 +161,6 @@ QUICLossDetector::reset() this->_crypto_outstanding = 0; // [draft-17 recovery] 6.4.3. Initialization - this->_crypto_count = 0; - this->_pto_count = 0; - this->_smoothed_rtt = 0; - this->_rttvar = 0; - this->_min_rtt = INT64_MAX; this->_time_of_last_sent_ack_eliciting_packet = 0; this->_time_of_last_sent_crypto_packet = 0; for (auto i = 0; i < kPacketNumberSpace; i++) { @@ -181,6 +168,8 @@ QUICLossDetector::reset() this->_loss_time[i] = 0; this->_sent_packets[i].clear(); } + + this->_rtt_measure->reset(); } void @@ -200,10 +189,10 @@ QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame, QUICPacketNumb // ack-eliciting, update the RTT. auto pi = this->_sent_packets[index].find(ack_frame.largest_acknowledged()); if (pi != this->_sent_packets[index].end() && pi->second->ack_eliciting) { - this->_latest_rtt = Thread::get_hrtime() - pi->second->time_sent; + ink_hrtime latest_rtt = Thread::get_hrtime() - pi->second->time_sent; // _latest_rtt is nanosecond but ack_frame.ack_delay is microsecond and scaled ink_hrtime delay = HRTIME_USECONDS(ack_frame.ack_delay() << this->_ack_delay_exponent); - this->_update_rtt(this->_latest_rtt, delay); + this->_rtt_measure->update_rtt(latest_rtt, delay); } QUICLDVDebug("[%s] Unacked packets %lu (retransmittable %u, includes %u handshake packets)", QUICDebugNames::pn_space(pn_space), @@ -238,8 +227,8 @@ QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame, QUICPacketNumb this->_detect_lost_packets(pn_space); - this->_crypto_count = 0; - this->_pto_count = 0; + this->_rtt_measure->set_crypto_count(0); + this->_rtt_measure->set_pto_count(0); QUICLDDebug("[%s] Unacked packets %lu (retransmittable %u, includes %u handshake packets)", QUICDebugNames::pn_space(pn_space), this->_sent_packets[index].size(), this->_ack_eliciting_outstanding.load(), this->_crypto_outstanding.load()); @@ -247,30 +236,6 @@ QUICLossDetector::_on_ack_received(const QUICAckFrame &ack_frame, QUICPacketNumb this->_set_loss_detection_timer(); } -void -QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay) -{ - // min_rtt ignores ack delay. - this->_min_rtt = std::min(this->_min_rtt, latest_rtt); - // Limit ack_delay by max_ack_delay - ack_delay = std::min(ack_delay, this->_max_ack_delay); - // Adjust for ack delay if it's plausible. - if (latest_rtt - this->_min_rtt > ack_delay) { - latest_rtt -= ack_delay; - } - // Based on {{RFC6298}}. - if (this->_smoothed_rtt == 0) { - this->_smoothed_rtt = latest_rtt; - this->_rttvar = latest_rtt / 2.0; - } else { - double rttvar_sample = ABS(this->_smoothed_rtt - latest_rtt); - this->_rttvar = 3.0 / 4.0 * this->_rttvar + 1.0 / 4.0 * rttvar_sample; - this->_smoothed_rtt = 7.0 / 8.0 * this->_smoothed_rtt + 1.0 / 8.0 * latest_rtt; - } - - this->_rtt_measure->update_smoothed_rtt(this->_smoothed_rtt); -} - void QUICLossDetector::_on_packet_acked(const QUICPacketInfo &acked_packet) { @@ -311,8 +276,6 @@ QUICLossDetector::_get_earliest_loss_time(QUICPacketNumberSpace &pn_space) void QUICLossDetector::_set_loss_detection_timer() { - ink_hrtime timeout; - // Don't arm the alarm if there are no packets with retransmittable data in flight. // -- MODIFIED CODE -- // In psuedocode, `bytes_in_flight` is used, but we're tracking "retransmittable data in flight" by `_ack_eliciting_outstanding` @@ -337,25 +300,14 @@ QUICLossDetector::_set_loss_detection_timer() this->_loss_detection_alarm_at); } else if (this->_crypto_outstanding) { // Handshake retransmission alarm. - if (this->_smoothed_rtt == 0) { - timeout = 2 * this->_k_initial_rtt; - } else { - timeout = 2 * this->_smoothed_rtt; - } - timeout = std::max(timeout, this->_k_granularity); - timeout = timeout * (1 << this->_crypto_count); - - this->_loss_detection_alarm_at = this->_time_of_last_sent_crypto_packet + timeout; + this->_loss_detection_alarm_at = this->_time_of_last_sent_crypto_packet + this->_rtt_measure->handshake_retransmit_timeout(); QUICLDDebug("%s crypto packet alarm will be set: %" PRId64, QUICDebugNames::pn_space(pn_space), this->_loss_detection_alarm_at); // -- ADDITIONAL CODE -- // In psudocode returning here, but we don't do for scheduling _loss_detection_alarm event. // -- END OF ADDITIONAL CODE -- } else { // PTO Duration - timeout = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; - timeout = std::max(timeout, this->_k_granularity); - timeout = timeout * (1 << this->_pto_count); - this->_loss_detection_alarm_at = this->_time_of_last_sent_ack_eliciting_packet + timeout; + this->_loss_detection_alarm_at = this->_time_of_last_sent_ack_eliciting_packet + this->_rtt_measure->current_pto_period(); QUICLDDebug("[%s] PTO timeout will be set: %" PRId64, QUICDebugNames::pn_space(pn_space), this->_loss_detection_alarm_at); } @@ -375,11 +327,11 @@ QUICLossDetector::_on_loss_detection_timeout() } else if (this->_crypto_outstanding) { // Handshake retransmission alarm. this->_retransmit_all_unacked_crypto_data(); - this->_crypto_count++; + this->_rtt_measure->set_crypto_count(this->_rtt_measure->crypto_count() + 1); } else { QUICLDVDebug("PTO"); this->_send_two_packets(); - this->_pto_count++; + this->_rtt_measure->set_pto_count(this->_rtt_measure->pto_count() + 1); } QUICLDDebug("[%s] Unacked packets %lu (retransmittable %u, includes %u handshake packets)", QUICDebugNames::pn_space(pn_space), @@ -405,7 +357,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumberSpace pn_space) { SCOPED_MUTEX_LOCK(lock, this->_loss_detection_mutex, this_ethread()); this->_loss_time[static_cast(pn_space)] = 0; - ink_hrtime loss_delay = this->_k_time_threshold * std::max(this->_latest_rtt, this->_smoothed_rtt); + ink_hrtime loss_delay = this->_k_time_threshold * std::max(this->_rtt_measure->latest_rtt(), this->_rtt_measure->smoothed_rtt()); std::map lost_packets; // Packets sent before this time are deemed lost. @@ -417,7 +369,8 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumberSpace pn_space) for (auto it = this->_sent_packets[static_cast(pn_space)].begin(); it != this->_sent_packets[static_cast(pn_space)].end(); ++it) { if (it->first > this->_largest_acked_packet[static_cast(pn_space)]) { - continue; + // the spec uses continue but we can break here because the _sent_packets is sorted by packet_number. + break; } auto &unacked = it->second; @@ -428,7 +381,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumberSpace pn_space) QUICLDDebug("[%s] Lost: time since sent is too long (#%" PRId64 " sent=%" PRId64 ", delay=%" PRId64 ", fraction=%lf, lrtt=%" PRId64 ", srtt=%" PRId64 ")", QUICDebugNames::pn_space(pn_space), it->first, unacked->time_sent, lost_send_time, this->_k_time_threshold, - this->_latest_rtt, this->_smoothed_rtt); + this->_rtt_measure->latest_rtt(), this->_rtt_measure->smoothed_rtt()); } else { QUICLDDebug("[%s] Lost: packet delta is too large (#%" PRId64 " largest=%" PRId64 " threshold=%" PRId32 ")", QUICDebugNames::pn_space(pn_space), it->first, this->_largest_acked_packet[static_cast(pn_space)], @@ -589,9 +542,57 @@ QUICLossDetector::_decrement_outstanding_counters(std::map_k_granularity = ld_config.granularity(); + this->_k_initial_rtt = ld_config.initial_rtt(); +} + +void +QUICRTTMeasure::init(const QUICLDConfig &ld_config) +{ + this->_k_granularity = ld_config.granularity(); + this->_k_initial_rtt = ld_config.initial_rtt(); +} + +ink_hrtime +QUICRTTMeasure::smoothed_rtt() const +{ + return this->_smoothed_rtt; +} + +void +QUICRTTMeasure::update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay) +{ + // additional code + this->_latest_rtt = latest_rtt; + + // min_rtt ignores ack delay. + this->_min_rtt = std::min(this->_min_rtt, latest_rtt); + // Limit ack_delay by max_ack_delay + ack_delay = std::min(ack_delay, this->_max_ack_delay); + // Adjust for ack delay if it's plausible. + if (this->_latest_rtt - this->_min_rtt > ack_delay) { + this->_latest_rtt -= ack_delay; + } + // Based on {{RFC6298}}. + if (this->_smoothed_rtt == 0) { + this->_smoothed_rtt = latest_rtt; + this->_rttvar = latest_rtt / 2.0; + } else { + double rttvar_sample = ABS(this->_smoothed_rtt - latest_rtt); + this->_rttvar = 3.0 / 4.0 * this->_rttvar + 1.0 / 4.0 * rttvar_sample; + this->_smoothed_rtt = 7.0 / 8.0 * this->_smoothed_rtt + 1.0 / 8.0 * latest_rtt; + } +} + ink_hrtime -QUICLossDetector::current_rto_period() +QUICRTTMeasure::current_pto_period() const { + // PTO timeout ink_hrtime alarm_duration; alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar + this->_max_ack_delay; alarm_duration = std::max(alarm_duration, this->_k_granularity); @@ -600,23 +601,70 @@ QUICLossDetector::current_rto_period() } ink_hrtime -QUICLossDetector::congestion_period(uint32_t threshold) const +QUICRTTMeasure::congestion_period(uint32_t threshold) const { ink_hrtime pto = this->_smoothed_rtt + std::max(this->_rttvar * 4, this->_k_granularity); return pto * (1 << (threshold - 1)); } -// -// QUICRTTMeasure -// ink_hrtime -QUICRTTMeasure::smoothed_rtt() const +QUICRTTMeasure::handshake_retransmit_timeout() const +{ + // Handshake retransmission alarm. + ink_hrtime timeout = 0; + if (this->_smoothed_rtt == 0) { + timeout = 2 * this->_k_initial_rtt; + } else { + timeout = 2 * this->_smoothed_rtt; + } + timeout = std::max(timeout, this->_k_granularity); + timeout = timeout * (1 << this->_crypto_count); + + return timeout; +} + +void +QUICRTTMeasure::set_crypto_count(uint32_t count) +{ + this->_crypto_count = count; +} + +void +QUICRTTMeasure::set_pto_count(uint32_t count) +{ + this->_pto_count = count; +} + +ink_hrtime +QUICRTTMeasure::rttvar() const { - return this->_smoothed_rtt.load(); + return this->_rttvar; +} + +ink_hrtime +QUICRTTMeasure::latest_rtt() const +{ + return this->_latest_rtt; +} + +uint32_t +QUICRTTMeasure::crypto_count() const +{ + return this->_crypto_count; +} + +uint32_t +QUICRTTMeasure::pto_count() const +{ + return this->_pto_count; } void -QUICRTTMeasure::update_smoothed_rtt(ink_hrtime rtt) +QUICRTTMeasure::reset() { - this->_smoothed_rtt.store(rtt); + this->_crypto_count = 0; + this->_pto_count = 0; + this->_smoothed_rtt = 0; + this->_rttvar = 0; + this->_min_rtt = INT64_MAX; } diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 63a54f1838d..98536e509ff 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -38,6 +38,7 @@ #include "QUICConnection.h" class QUICLossDetector; +class QUICRTTMeasure; struct QUICPacketInfo { // 6.3.1. Sent Packet Fields @@ -57,28 +58,18 @@ struct QUICPacketInfo { using QUICPacketInfoUPtr = std::unique_ptr; -static constexpr uint8_t kPacketNumberSpace = 3; - class QUICRTTProvider { public: virtual ink_hrtime smoothed_rtt() const = 0; -}; - -class QUICRTTMeasure : public QUICRTTProvider -{ -public: - ink_hrtime smoothed_rtt() const override; - void update_smoothed_rtt(ink_hrtime rtt); - -private: - std::atomic _smoothed_rtt = 0; + virtual ink_hrtime rttvar() const = 0; + virtual ink_hrtime latest_rtt() const = 0; }; class QUICCongestionController { public: - QUICCongestionController(QUICConnectionInfoProvider *info, const QUICCCConfig &cc_config); + QUICCongestionController(QUICRTTMeasure *rtt_measure, QUICConnectionInfoProvider *info, const QUICCCConfig &cc_config); virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); void on_packet_acked(const QUICPacketInfo &acked_packet); @@ -89,7 +80,6 @@ class QUICCongestionController uint32_t open_window() const; void reset(); bool is_app_limited(); - void bind_loss_detector(QUICLossDetector *loss_detector); // Debug uint32_t bytes_in_flight() const; @@ -121,7 +111,7 @@ class QUICCongestionController uint32_t _ssthresh = UINT32_MAX; QUICConnectionInfoProvider *_info = nullptr; - QUICLossDetector *_loss_detector = nullptr; + QUICRTTMeasure *_rtt_measure = nullptr; bool _in_recovery(ink_hrtime sent_time); }; @@ -141,8 +131,6 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler QUICPacketNumber largest_acked_packet_number(QUICPacketNumberSpace pn_space); void update_ack_delay_exponent(uint8_t ack_delay_exponent); void reset(); - ink_hrtime current_rto_period(); - ink_hrtime congestion_period(uint32_t threshold) const; private: Ptr _loss_detection_mutex; @@ -153,21 +141,12 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler // Values will be loaded from records.config via QUICConfig at constructor uint32_t _k_packet_threshold = 0; float _k_time_threshold = 0.0; - ink_hrtime _k_granularity = 0; - ink_hrtime _k_initial_rtt = 0; // [draft-11 recovery] 3.5.2. Variables of interest // Keep the order as the same as the spec so that we can see the difference easily. Action *_loss_detection_timer = nullptr; - uint32_t _crypto_count = 0; - uint32_t _pto_count = 0; ink_hrtime _time_of_last_sent_ack_eliciting_packet = 0; ink_hrtime _time_of_last_sent_crypto_packet = 0; - ink_hrtime _latest_rtt = 0; - ink_hrtime _smoothed_rtt = 0; - ink_hrtime _rttvar = 0; - ink_hrtime _min_rtt = INT64_MAX; - ink_hrtime _max_ack_delay = 0; ink_hrtime _loss_time[kPacketNumberSpace] = {0}; QUICPacketNumber _largest_acked_packet[kPacketNumberSpace] = {0}; std::map _sent_packets[kPacketNumberSpace]; @@ -190,7 +169,6 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _on_ack_received(const QUICAckFrame &ack_frame, QUICPacketNumberSpace pn_space); void _on_packet_acked(const QUICPacketInfo &acked_packet); - void _update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay); void _detect_lost_packets(QUICPacketNumberSpace pn_space); void _set_loss_detection_timer(); void _on_loss_detection_timeout(); @@ -205,6 +183,53 @@ class QUICLossDetector : public Continuation, public QUICFrameHandler void _send_two_packets(); QUICConnectionInfoProvider *_info = nullptr; - QUICCongestionController *_cc = nullptr; QUICRTTMeasure *_rtt_measure = nullptr; + QUICCongestionController *_cc = nullptr; +}; + +class QUICRTTMeasure : public QUICRTTProvider +{ +public: + // use `friend` so ld can acesss RTTMeasure. + // friend QUICLossDetector; + + QUICRTTMeasure(const QUICLDConfig &ld_config); + QUICRTTMeasure() = default; + + void init(const QUICLDConfig &ld_config); + + // period + ink_hrtime handshake_retransmit_timeout() const; + ink_hrtime current_pto_period() const; + ink_hrtime congestion_period(uint32_t threshold) const; + + // get members + ink_hrtime smoothed_rtt() const override; + ink_hrtime rttvar() const override; + ink_hrtime latest_rtt() const override; + + uint32_t pto_count() const; + uint32_t crypto_count() const; + + void set_crypto_count(uint32_t count); + void set_pto_count(uint32_t count); + + void update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay); + void reset(); + +private: + // related to rtt calculate + uint32_t _crypto_count = 0; + uint32_t _pto_count = 0; + ink_hrtime _max_ack_delay = 0; + + // rtt vars + ink_hrtime _latest_rtt = 0; + ink_hrtime _smoothed_rtt = 0; + ink_hrtime _rttvar = 0; + ink_hrtime _min_rtt = INT64_MAX; + + // config + ink_hrtime _k_granularity = 0; + ink_hrtime _k_initial_rtt = 0; }; diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc index 8aab3fda0d0..8b086983924 100644 --- a/iocore/net/quic/QUICPacketFactory.cc +++ b/iocore/net/quic/QUICPacketFactory.cc @@ -355,7 +355,7 @@ QUICPacketFactory::is_ready_to_create_protected_packet() void QUICPacketFactory::reset() { - for (auto s : QUIC_PN_SPACES) { - this->_packet_number_generator[static_cast(s)].reset(); + for (auto i = 0; i < kPacketNumberSpace; i++) { + this->_packet_number_generator[i].reset(); } } diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 3f3a16e39e5..6df43291090 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -43,6 +43,8 @@ using QUICVersion = uint32_t; using QUICStreamId = uint64_t; using QUICOffset = uint64_t; +static constexpr uint8_t kPacketNumberSpace = 3; + // TODO: Update version number // Note: Prefix for drafts (0xff000000) + draft number // Note: Fix "Supported Version" field in test case of QUICPacketFactory_Create_VersionNegotiationPacket @@ -78,13 +80,6 @@ enum class QUICPacketNumberSpace { ApplicationData, }; -// 0-RTT and 1-RTT use same Packet Number Space -constexpr QUICEncryptionLevel QUIC_PN_SPACES[] = { - QUICEncryptionLevel::INITIAL, - QUICEncryptionLevel::ZERO_RTT, - QUICEncryptionLevel::HANDSHAKE, -}; - // Devide to QUICPacketType and QUICPacketLongHeaderType ? enum class QUICPacketType : uint8_t { INITIAL = 0x00, // draft-17 version-specific type From 6562700146c8736b67fe5e20b490f1d08f1653a5 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 10 May 2019 05:44:54 +0000 Subject: [PATCH 1268/1313] QUIC: Fix test due to pre commits --- iocore/net/quic/Mock.h | 18 ++++++++++++++++-- .../net/quic/test/test_QUICAckFrameCreator.cc | 3 +-- .../net/quic/test/test_QUICFlowController.cc | 12 ++++++++++++ iocore/net/quic/test/test_QUICLossDetector.cc | 19 ++++++++++--------- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 5cbee17c5ea..5cdc73f7031 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -341,7 +341,7 @@ class MockQUICCongestionController : public QUICCongestionController { public: MockQUICCongestionController(QUICConnectionInfoProvider *info, const QUICCCConfig &cc_config) - : QUICCongestionController(info, cc_config) + : QUICCongestionController(&this->_rtt_measure, info, cc_config) { } // Override @@ -383,6 +383,8 @@ class MockQUICCongestionController : public QUICCongestionController private: int _totalFrameCount = 0; int _frameCount[256] = {0}; + + QUICRTTMeasure _rtt_measure; }; class MockQUICLossDetector : public QUICLossDetector @@ -547,7 +549,19 @@ class MockContinuation : public Continuation class MockQUICRTTProvider : public QUICRTTProvider { ink_hrtime - smoothed_rtt() const + latest_rtt() const override + { + return HRTIME_MSECONDS(1); + } + + ink_hrtime + rttvar() const override + { + return HRTIME_MSECONDS(1); + } + + ink_hrtime + smoothed_rtt() const override { return HRTIME_MSECONDS(1); } diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 48fc90f0108..94913b47dba 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -254,8 +254,7 @@ TEST_CASE("QUICAckFrameManager_loss_recover", "[quic]") TEST_CASE("QUICAckFrameManager_QUICAckFrameCreator", "[quic]") { QUICAckFrameManager ack_manager; - QUICEncryptionLevel level = QUICEncryptionLevel::INITIAL; - QUICAckFrameManager::QUICAckFrameCreator packet_numbers(level, &ack_manager); + QUICAckFrameManager::QUICAckFrameCreator packet_numbers(QUICPacketNumberSpace::Initial, &ack_manager); CHECK(packet_numbers.size() == 0); CHECK(packet_numbers.largest_ack_number() == 0); diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index 3df50b67ecb..1d369a9e10e 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -45,6 +45,18 @@ class MockRTTProvider : public QUICRTTProvider this->_smoothed_rtt = rtt; } + ink_hrtime + latest_rtt() const override + { + return HRTIME_MSECONDS(1); + } + + ink_hrtime + rttvar() const override + { + return HRTIME_MSECONDS(1); + } + private: ink_hrtime _smoothed_rtt = 0; }; diff --git a/iocore/net/quic/test/test_QUICLossDetector.cc b/iocore/net/quic/test/test_QUICLossDetector.cc index 7a63866def5..00167247299 100644 --- a/iocore/net/quic/test/test_QUICLossDetector.cc +++ b/iocore/net/quic/test/test_QUICLossDetector.cc @@ -99,6 +99,7 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") { // Send packet (1) to (7) QUICPacketNumberSpace pn_space = QUICPacketNumberSpace::ApplicationData; + QUICEncryptionLevel level = QUICEncryptionLevel::ONE_RTT; payload = ats_unique_malloc(payload_len); QUICPacketUPtr packet1 = pf.create_protected_packet(connection_id, detector.largest_acked_packet_number(pn_space), std::move(payload), payload_len, true, false); @@ -236,18 +237,18 @@ TEST_CASE("QUICLossDetector_Loss", "[quic]") ink_hrtime_sleep(HRTIME_MSECONDS(2000)); // Receive an ACK for (1) (4) (5) (7) (8) (9) - afm.update(QUICEncryptionLevel::INITIAL, pn1, payload_len, false); - afm.update(QUICEncryptionLevel::INITIAL, pn4, payload_len, false); - afm.update(QUICEncryptionLevel::INITIAL, pn5, payload_len, false); - afm.update(QUICEncryptionLevel::INITIAL, pn7, payload_len, false); - afm.update(QUICEncryptionLevel::INITIAL, pn8, payload_len, false); - afm.update(QUICEncryptionLevel::INITIAL, pn9, payload_len, false); - afm.update(QUICEncryptionLevel::INITIAL, pn10, payload_len, false); + afm.update(level, pn1, payload_len, false); + afm.update(level, pn4, payload_len, false); + afm.update(level, pn5, payload_len, false); + afm.update(level, pn7, payload_len, false); + afm.update(level, pn8, payload_len, false); + afm.update(level, pn9, payload_len, false); + afm.update(level, pn10, payload_len, false); uint8_t buf[QUICFrame::MAX_INSTANCE_SIZE]; - QUICFrame *x = afm.generate_frame(buf, QUICEncryptionLevel::INITIAL, 2048, 2048, 0); + QUICFrame *x = afm.generate_frame(buf, level, 2048, 2048, 0); frame = static_cast(x); ink_hrtime_sleep(HRTIME_MSECONDS(1000)); - detector.handle_frame(QUICEncryptionLevel::INITIAL, *frame); + detector.handle_frame(level, *frame); // Lost because of packet_threshold. CHECK(cc.lost_packets.size() == 3); From b7bf6582cb0cdb502b0b256228619e2d4435dcc2 Mon Sep 17 00:00:00 2001 From: scw00 Date: Fri, 10 May 2019 07:43:11 +0000 Subject: [PATCH 1269/1313] QUIC: Make congestion period in QUICRTTProvider --- iocore/net/QUICNetVConnection.cc | 2 +- iocore/net/quic/QUICCongestionController.cc | 6 +++--- iocore/net/quic/QUICLossDetector.cc | 4 ++++ iocore/net/quic/QUICLossDetector.h | 8 +++++--- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e088737c1da..b1086a3a66e 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -452,7 +452,7 @@ QUICNetVConnection::start() QUICCCConfigQCP cc_config(this->_quic_config); QUICLDConfigQCP ld_config(this->_quic_config); this->_rtt_measure.init(ld_config); - this->_congestion_controller = new QUICCongestionController(&this->_rtt_measure, this, cc_config); + this->_congestion_controller = new QUICCongestionController(this->_rtt_measure, this, cc_config); this->_loss_detector = new QUICLossDetector(this, this->_congestion_controller, &this->_rtt_measure, ld_config); this->_frame_dispatcher->add_handler(this->_loss_detector); diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 4be6d532848..0ba0e094864 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -36,9 +36,9 @@ "window: %" PRIu32 " bytes: %" PRIu32 " ssthresh: %" PRIu32 " " fmt, \ this->_info->cids().data(), this->_congestion_window, this->_bytes_in_flight, this->_ssthresh, ##__VA_ARGS__) -QUICCongestionController::QUICCongestionController(QUICRTTMeasure *rtt_measure, QUICConnectionInfoProvider *info, +QUICCongestionController::QUICCongestionController(const QUICRTTProvider &rtt_provider, QUICConnectionInfoProvider *info, const QUICCCConfig &cc_config) - : _info(info), _rtt_measure(rtt_measure) + : _info(info), _rtt_provider(rtt_provider) { this->_cc_mutex = new_ProxyMutex(); @@ -136,7 +136,7 @@ bool QUICCongestionController::_in_persistent_congestion(const std::map &lost_packets, QUICPacketInfo *largest_lost_packet) { - ink_hrtime period = this->_rtt_measure->congestion_period(this->_k_persistent_congestion_threshold); + ink_hrtime period = this->_rtt_provider.congestion_period(this->_k_persistent_congestion_threshold); // Determine if all packets in the window before the // newest lost packet, including the edges, are marked // lost diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index cd3eb470db9..6f73f2bd471 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -577,6 +577,10 @@ QUICRTTMeasure::update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay) // Adjust for ack delay if it's plausible. if (this->_latest_rtt - this->_min_rtt > ack_delay) { this->_latest_rtt -= ack_delay; + + // the newest spec has removed the max_ack_delay assignment. but we need to assign it in somewhere + // this code is from draft-19 + this->_max_ack_delay = std::max(ack_delay, this->_max_ack_delay); } // Based on {{RFC6298}}. if (this->_smoothed_rtt == 0) { diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index 98536e509ff..b03fdfd70f1 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -64,12 +64,14 @@ class QUICRTTProvider virtual ink_hrtime smoothed_rtt() const = 0; virtual ink_hrtime rttvar() const = 0; virtual ink_hrtime latest_rtt() const = 0; + + virtual ink_hrtime congestion_period(uint32_t period) const = 0; }; class QUICCongestionController { public: - QUICCongestionController(QUICRTTMeasure *rtt_measure, QUICConnectionInfoProvider *info, const QUICCCConfig &cc_config); + QUICCongestionController(const QUICRTTProvider &rtt_provider, QUICConnectionInfoProvider *info, const QUICCCConfig &cc_config); virtual ~QUICCongestionController() {} void on_packet_sent(size_t bytes_sent); void on_packet_acked(const QUICPacketInfo &acked_packet); @@ -111,7 +113,7 @@ class QUICCongestionController uint32_t _ssthresh = UINT32_MAX; QUICConnectionInfoProvider *_info = nullptr; - QUICRTTMeasure *_rtt_measure = nullptr; + const QUICRTTProvider &_rtt_provider; bool _in_recovery(ink_hrtime sent_time); }; @@ -201,7 +203,7 @@ class QUICRTTMeasure : public QUICRTTProvider // period ink_hrtime handshake_retransmit_timeout() const; ink_hrtime current_pto_period() const; - ink_hrtime congestion_period(uint32_t threshold) const; + ink_hrtime congestion_period(uint32_t threshold) const override; // get members ink_hrtime smoothed_rtt() const override; From ee689f178522a488741a772c3729fced905c916a Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 13 May 2019 15:19:18 +0900 Subject: [PATCH 1270/1313] Fix autological-pointer-compare warning > comparison of array 'this->_loss_time' equal to a null pointer is always false [-Werror,-Wtautological-pointer-compare] --- iocore/net/quic/QUICLossDetector.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 6f73f2bd471..16ddc908e97 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -390,7 +390,7 @@ QUICLossDetector::_detect_lost_packets(QUICPacketNumberSpace pn_space) if (unacked->in_flight) { lost_packets.insert({it->first, it->second.get()}); - } else if (this->_loss_time == 0) { + } else if (this->_loss_time[static_cast(pn_space)] == 0) { this->_loss_time[static_cast(pn_space)] = unacked->time_sent + loss_delay; } else { this->_loss_time[static_cast(pn_space)] = From 2d883e02b3a0e402581070030b739b468977a36c Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 1 May 2019 17:09:49 +0900 Subject: [PATCH 1271/1313] Update QUIC draft nubmers to 20 --- iocore/net/quic/Mock.h | 7 +++++-- iocore/net/quic/QUICTypes.h | 2 +- iocore/net/quic/test/test_QUICPacketFactory.cc | 2 +- src/traffic_quic/quic_client.cc | 4 ++-- src/tscore/ink_inet.cc | 4 ++-- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 5cdc73f7031..bf549adb435 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -30,6 +30,9 @@ #include "QUICLossDetector.h" #include "QUICEvents.h" +using namespace std::literals; +std::string_view negotiated_application_name_sv = "h3-20"sv; + class MockQUICStreamManager : public QUICStreamManager { public: @@ -253,7 +256,7 @@ class MockQUICConnection : public QUICConnection std::string_view negotiated_application_name() const override { - return "h3-19"; + return negotiated_application_name_sv; } int _transmit_count = 0; @@ -333,7 +336,7 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider std::string_view negotiated_application_name() const override { - return "h3-19"; + return negotiated_application_name_sv; } }; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 6df43291090..847215fa716 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -51,7 +51,7 @@ static constexpr uint8_t kPacketNumberSpace = 3; // Note: Fix QUIC_ALPN_PROTO_LIST in QUICConfig.cc // Note: Change ExtensionType (QUICTransportParametersHandler::TRANSPORT_PARAMETER_ID) if it's changed constexpr QUICVersion QUIC_SUPPORTED_VERSIONS[] = { - 0xff000013, + 0xff000014, }; constexpr QUICVersion QUIC_EXERCISE_VERSION = 0x1a2a3a4a; diff --git a/iocore/net/quic/test/test_QUICPacketFactory.cc b/iocore/net/quic/test/test_QUICPacketFactory.cc index 7c04a7055fe..08d94b494ca 100644 --- a/iocore/net/quic/test/test_QUICPacketFactory.cc +++ b/iocore/net/quic/test/test_QUICPacketFactory.cc @@ -53,7 +53,7 @@ TEST_CASE("QUICPacketFactory_Create_VersionNegotiationPacket", "[quic]") 0x55, // DCIL/SCIL 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // Destination Connection ID 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Source Connection ID - 0xff, 0x00, 0x00, 0x13, // Supported Version + 0xff, 0x00, 0x00, 0x14, // Supported Version 0x1a, 0x2a, 0x3a, 0x4a, // Excercise Version }; uint8_t buf[1024] = {0}; diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc index 344028ff085..92ba7974d36 100644 --- a/src/traffic_quic/quic_client.cc +++ b/src/traffic_quic/quic_client.cc @@ -34,8 +34,8 @@ // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html // Should be integrate with IP_PROTO_TAG_HTTP_QUIC in ts/ink_inet.h ? using namespace std::literals; -static constexpr std::string_view HQ_ALPN_PROTO_LIST("\5hq-19"sv); -static constexpr std::string_view H3_ALPN_PROTO_LIST("\5h3-19"sv); +static constexpr std::string_view HQ_ALPN_PROTO_LIST("\5hq-20"sv); +static constexpr std::string_view H3_ALPN_PROTO_LIST("\5h3-20"sv); QUICClient::QUICClient(const QUICClientConfig *config) : Continuation(new_ProxyMutex()), _config(config) { diff --git a/src/tscore/ink_inet.cc b/src/tscore/ink_inet.cc index 80d80eee321..092342f62db 100644 --- a/src/tscore/ink_inet.cc +++ b/src/tscore/ink_inet.cc @@ -50,8 +50,8 @@ const std::string_view IP_PROTO_TAG_HTTP_0_9("http/0.9"sv); const std::string_view IP_PROTO_TAG_HTTP_1_0("http/1.0"sv); const std::string_view IP_PROTO_TAG_HTTP_1_1("http/1.1"sv); const std::string_view IP_PROTO_TAG_HTTP_2_0("h2"sv); // HTTP/2 over TLS -const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-19"sv); // HTTP/0.9 over QUIC -const std::string_view IP_PROTO_TAG_HTTP_3("h3-19"sv); // HTTP/3 over QUIC +const std::string_view IP_PROTO_TAG_HTTP_QUIC("hq-20"sv); // HTTP/0.9 over QUIC +const std::string_view IP_PROTO_TAG_HTTP_3("h3-20"sv); // HTTP/3 over QUIC const std::string_view UNIX_PROTO_TAG{"unix"sv}; From 9e593ff209c324917ed9c2bb0f33d5df9b44ed36 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 1 May 2019 17:19:45 +0900 Subject: [PATCH 1272/1313] Update code for NUM_PLACEHOLDERS --- proxy/http3/Http3Types.h | 2 +- proxy/http3/test/test_Http3Frame.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/proxy/http3/Http3Types.h b/proxy/http3/Http3Types.h index d753edbc3e0..54c619687da 100644 --- a/proxy/http3/Http3Types.h +++ b/proxy/http3/Http3Types.h @@ -44,7 +44,7 @@ enum class Http3SettingsId : uint64_t { RESERVED_4 = 0x05, ///< HTTP/3 Settings MAX_HEADER_LIST_SIZE = 0x06, ///< HTTP/3 Settings QPACK_BLOCKED_STREAMS = 0x07, ///< QPACK Settings - NUM_PLACEHOLDERS = 0x08, ///< HTTP/3 Settings + NUM_PLACEHOLDERS = 0x09, ///< HTTP/3 Settings UNKNOWN = 0x0A0A, }; diff --git a/proxy/http3/test/test_Http3Frame.cc b/proxy/http3/test/test_Http3Frame.cc index c9a606ab3df..242178a3227 100644 --- a/proxy/http3/test/test_Http3Frame.cc +++ b/proxy/http3/test/test_Http3Frame.cc @@ -130,7 +130,7 @@ TEST_CASE("Load SETTINGS Frame", "[http3]") 0x08, // Length 0x06, // Identifier 0x44, 0x00, // Value - 0x08, // Identifier + 0x09, // Identifier 0x0f, // Value 0x4a, 0xba, // Identifier 0x00, // Value @@ -157,7 +157,7 @@ TEST_CASE("Store SETTINGS Frame", "[http3]") 0x08, // Length 0x06, // Identifier 0x44, 0x00, // Value - 0x08, // Identifier + 0x09, // Identifier 0x0f, // Value 0x4a, 0x0a, // Identifier 0x00, // Value From 919183e6f235e0904a30d9828dbb889053683bae Mon Sep 17 00:00:00 2001 From: scw00 Date: Tue, 14 May 2019 02:17:58 +0000 Subject: [PATCH 1273/1313] QUIC: Fix test for pervious changes --- iocore/net/quic/Mock.h | 2 +- .../net/quic/test/test_QUICFlowController.cc | 6 ++++ iocore/net/quic/test/test_QUICFrame.cc | 2 +- iocore/net/quic/test/test_QUICStream.cc | 32 +++++++++---------- .../net/quic/test/test_QUICStreamManager.cc | 10 +++--- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index bf549adb435..ed8fce9a514 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -344,7 +344,7 @@ class MockQUICCongestionController : public QUICCongestionController { public: MockQUICCongestionController(QUICConnectionInfoProvider *info, const QUICCCConfig &cc_config) - : QUICCongestionController(&this->_rtt_measure, info, cc_config) + : QUICCongestionController(this->_rtt_measure, info, cc_config) { } // Override diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc index 1d369a9e10e..d58a31172a7 100644 --- a/iocore/net/quic/test/test_QUICFlowController.cc +++ b/iocore/net/quic/test/test_QUICFlowController.cc @@ -57,6 +57,12 @@ class MockRTTProvider : public QUICRTTProvider return HRTIME_MSECONDS(1); } + ink_hrtime + congestion_period(uint32_t period) const override + { + return HRTIME_MSECONDS(1); + } + private: ink_hrtime _smoothed_rtt = 0; }; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 2ef3dcb353a..9f42e79b3b1 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -1520,7 +1520,7 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError", TEST_CASE("QUICFrameFactory Create RESET_STREAM with a QUICStreamError", "[quic]") { uint8_t frame_buf[QUICFrame::MAX_INSTANCE_SIZE]; - MockQUICRTTProvider mock_rtt; + QUICRTTMeasure mock_rtt; MockQUICConnection mock_connection; QUICBidirectionalStream stream(&mock_rtt, &mock_connection, 0x1234, 0, 0); std::unique_ptr error = diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc index 581213881aa..aefc4883033 100644 --- a/iocore/net/quic/test/test_QUICStream.cc +++ b/iocore/net/quic/test/test_QUICStream.cc @@ -84,7 +84,7 @@ TEST_CASE("QUICBidiStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream( new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, 1024, 1024)); @@ -112,7 +112,7 @@ TEST_CASE("QUICBidiStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream( new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); @@ -140,7 +140,7 @@ TEST_CASE("QUICBidiStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream( new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); @@ -171,7 +171,7 @@ TEST_CASE("QUICBidiStream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream( new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, 4096, 4096)); @@ -212,7 +212,7 @@ TEST_CASE("QUICBidiStream", "[quic]") MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream( new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, 4096, 4096)); @@ -308,7 +308,7 @@ TEST_CASE("QUICBidiStream", "[quic]") MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream( new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); @@ -357,7 +357,7 @@ TEST_CASE("QUICBidiStream", "[quic]") MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream( new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); @@ -388,7 +388,7 @@ TEST_CASE("QUICBidiStream", "[quic]") MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream( new QUICBidirectionalStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX, UINT64_MAX)); @@ -472,7 +472,7 @@ TEST_CASE("QUIC receive only stream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, 1024)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); @@ -499,7 +499,7 @@ TEST_CASE("QUIC receive only stream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); @@ -526,7 +526,7 @@ TEST_CASE("QUIC receive only stream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *reader = read_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); @@ -556,7 +556,7 @@ TEST_CASE("QUIC receive only stream", "[quic]") MIOBuffer *read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, 4096)); stream->do_io_read(nullptr, INT64_MAX, read_buffer); @@ -590,7 +590,7 @@ TEST_CASE("QUIC receive only stream", "[quic]") SECTION("Retransmit STOP_SENDING frame") { - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream(new QUICReceiveStream(&rtt_provider, &cinfo_provider, stream_id, UINT64_MAX)); SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); @@ -672,7 +672,7 @@ TEST_CASE("QUIC send only stream", "[quic]") MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream(new QUICSendStream(&cinfo_provider, stream_id, 4096)); SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); @@ -766,7 +766,7 @@ TEST_CASE("QUIC send only stream", "[quic]") MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream(new QUICSendStream(&cinfo_provider, stream_id, UINT64_MAX)); SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); @@ -814,7 +814,7 @@ TEST_CASE("QUIC send only stream", "[quic]") MIOBuffer *write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_8K); IOBufferReader *write_buffer_reader = write_buffer->alloc_reader(); - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; MockQUICConnectionInfoProvider cinfo_provider; std::unique_ptr stream(new QUICSendStream(&cinfo_provider, stream_id, UINT64_MAX)); SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread()); diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index d42fdd8ba5a..03f316cecec 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -37,7 +37,7 @@ TEST_CASE("QUICStreamManager_NewStream", "[quic]") MockQUICApplication mock_app(&connection); app_map.set_default(&mock_app); MockQUICConnectionInfoProvider cinfo_provider; - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; QUICStreamManager sm(&cinfo_provider, &rtt_provider, &app_map); uint8_t local_tp_buf[] = { @@ -111,7 +111,7 @@ TEST_CASE("QUICStreamManager_first_initial_map", "[quic]") MockQUICApplication mock_app(&connection); app_map.set_default(&mock_app); MockQUICConnectionInfoProvider cinfo_provider; - MockQUICRTTProvider rtt_provider; + QUICRTTMeasure rtt_provider; QUICStreamManager sm(&cinfo_provider, &rtt_provider, &app_map); std::shared_ptr local_tp = std::make_shared(); std::shared_ptr remote_tp = std::make_shared(); @@ -137,7 +137,8 @@ TEST_CASE("QUICStreamManager_total_offset_received", "[quic]") MockQUICConnection connection; MockQUICApplication mock_app(&connection); app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); + QUICRTTMeasure rtt_provider; + QUICStreamManager sm(new MockQUICConnectionInfoProvider(), &rtt_provider, &app_map); uint8_t local_tp_buf[] = { 0x00, 0x0e, // size of parameters @@ -194,7 +195,8 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") MockQUICConnection connection; MockQUICApplication mock_app(&connection); app_map.set_default(&mock_app); - QUICStreamManager sm(new MockQUICConnectionInfoProvider(), new MockQUICRTTProvider(), &app_map); + QUICRTTMeasure rtt_provider; + QUICStreamManager sm(new MockQUICConnectionInfoProvider(), &rtt_provider, &app_map); uint8_t local_tp_buf[] = { 0x00, 0x06, // size of parameters From 35cacaa26046bfb8e0e6fa0492762b43e15af645 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 14 May 2019 11:54:58 +0900 Subject: [PATCH 1274/1313] Fix tests for h3 --- iocore/net/quic/Mock.h | 6 ++++++ iocore/net/quic/QUICLossDetector.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index ed8fce9a514..f7279c0db5d 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -568,6 +568,12 @@ class MockQUICRTTProvider : public QUICRTTProvider { return HRTIME_MSECONDS(1); } + + ink_hrtime + congestion_period(uint32_t threshold) const override + { + return HRTIME_MSECONDS(1); + } }; class MockQUICTransferProgressProvider : public QUICTransferProgressProvider diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h index b03fdfd70f1..1b7a536a7c6 100644 --- a/iocore/net/quic/QUICLossDetector.h +++ b/iocore/net/quic/QUICLossDetector.h @@ -65,7 +65,7 @@ class QUICRTTProvider virtual ink_hrtime rttvar() const = 0; virtual ink_hrtime latest_rtt() const = 0; - virtual ink_hrtime congestion_period(uint32_t period) const = 0; + virtual ink_hrtime congestion_period(uint32_t threshold) const = 0; }; class QUICCongestionController From 08042e622c34c3d2658ace4f16a540a6465c3d08 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 14 May 2019 11:58:11 +0900 Subject: [PATCH 1275/1313] Avoid read_avail() calls for performance --- iocore/net/quic/QUICBidirectionalStream.cc | 2 +- iocore/net/quic/QUICUnidirectionalStream.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICBidirectionalStream.cc b/iocore/net/quic/QUICBidirectionalStream.cc index 891e58e774b..bbd98d9652a 100644 --- a/iocore/net/quic/QUICBidirectionalStream.cc +++ b/iocore/net/quic/QUICBidirectionalStream.cc @@ -355,7 +355,7 @@ bool QUICBidirectionalStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { return this->_local_flow_controller.will_generate_frame(level, timestamp) || !this->is_retransmited_frame_queue_empty() || - (this->_write_vio.get_reader()->read_avail() > 0); + this->_write_vio.get_reader()->is_read_avail_more_than(0); } QUICFrame * diff --git a/iocore/net/quic/QUICUnidirectionalStream.cc b/iocore/net/quic/QUICUnidirectionalStream.cc index 2cd27d9b7a0..b6dae8f6f0a 100644 --- a/iocore/net/quic/QUICUnidirectionalStream.cc +++ b/iocore/net/quic/QUICUnidirectionalStream.cc @@ -127,7 +127,7 @@ QUICSendStream::state_stream_closed(int event, void *data) bool QUICSendStream::will_generate_frame(QUICEncryptionLevel level, ink_hrtime timestamp) { - return !this->is_retransmited_frame_queue_empty() || (this->_write_vio.get_reader()->read_avail() > 0); + return !this->is_retransmited_frame_queue_empty() || this->_write_vio.get_reader()->is_read_avail_more_than(0); } QUICFrame * From 9fc03ee395ebe56b8b2c2d555ef52f693b8e3f86 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 14 May 2019 14:09:07 +0900 Subject: [PATCH 1276/1313] Fix tests for QUICStreamManager add_total_offset_sent was used in the tests but it only checks the function increment offset, and doesn't check check Stream Manager's expected behavior. --- iocore/net/quic/QUICStreamManager.cc | 4 +-- iocore/net/quic/QUICStreamManager.h | 2 +- .../net/quic/test/test_QUICStreamManager.cc | 33 ++++++++++--------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 22e6c2fed67..e9a4cd3ed9e 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -361,7 +361,7 @@ QUICStreamManager::total_offset_sent() const } void -QUICStreamManager::add_total_offset_sent(uint32_t sent_byte) +QUICStreamManager::_add_total_offset_sent(uint32_t sent_byte) { // FIXME: use atomic increment this->_total_offset_sent += sent_byte; @@ -428,7 +428,7 @@ QUICStreamManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint6 } if (frame != nullptr && frame->type() == QUICFrameType::STREAM) { - this->add_total_offset_sent(static_cast(frame)->data_length()); + this->_add_total_offset_sent(static_cast(frame)->data_length()); } return frame; diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index d618afb7f35..3c39003eccd 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -47,7 +47,6 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator uint64_t total_reordered_bytes() const; uint64_t total_offset_received() const; uint64_t total_offset_sent() const; - void add_total_offset_sent(uint32_t sent_byte); uint32_t stream_count() const; QUICConnectionErrorUPtr create_stream(QUICStreamId stream_id); @@ -71,6 +70,7 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator private: QUICStreamVConnection *_find_stream_vc(QUICStreamId id); QUICStreamVConnection *_find_or_create_stream_vc(QUICStreamId stream_id); + void _add_total_offset_sent(uint32_t sent_byte); QUICConnectionErrorUPtr _handle_frame(const QUICStreamFrame &frame); QUICConnectionErrorUPtr _handle_frame(const QUICRstStreamFrame &frame); QUICConnectionErrorUPtr _handle_frame(const QUICStopSendingFrame &frame); diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index 03f316cecec..c5a44da3ee2 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -199,19 +199,25 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") QUICStreamManager sm(new MockQUICConnectionInfoProvider(), &rtt_provider, &app_map); uint8_t local_tp_buf[] = { - 0x00, 0x06, // size of parameters - 0x00, 0x08, // parameter id - initial_max_streams_bidi - 0x00, 0x02, // length of value - 0x40, 0x10 // value + 0x00, 0x0e, // size of parameters + 0x00, 0x08, // parameter id - initial_max_streams_bidi + 0x00, 0x02, // length of value + 0x40, 0x10, // value + 0x00, 0x05, // parameter id - initial_max_stream_data_bidi_local + 0x00, 0x04, // length of value + 0xbf, 0xff, 0xff, 0xff // value }; std::shared_ptr local_tp = std::make_shared(local_tp_buf, sizeof(local_tp_buf)); uint8_t remote_tp_buf[] = { - 0x00, 0x06, // size of parameters - 0x00, 0x08, // parameter id - initial_max_streams_bidi - 0x00, 0x02, // length of value - 0x40, 0x10 // value + 0x00, 0x0e, // size of parameters + 0x00, 0x08, // parameter id - initial_max_streams_bidi + 0x00, 0x02, // length of value + 0x40, 0x10, // value + 0x00, 0x06, // parameter id - initial_max_stream_data_bidi_remote + 0x00, 0x04, // length of value + 0xbf, 0xff, 0xff, 0xff // value }; std::shared_ptr remote_tp = std::make_shared(remote_tp_buf, sizeof(remote_tp_buf)); @@ -239,18 +245,13 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") CHECK(block_1024->read_avail() == 1024); // total_offset should be a integer in unit of octets - uint8_t stream_frame0_buf[QUICFrame::MAX_INSTANCE_SIZE]; - QUICFrame *stream_frame_0 = QUICFrameFactory::create_stream_frame(stream_frame0_buf, block_1024, 0, 0); + uint8_t frame_buf[4096]; mock_app.send(reinterpret_cast(block_1024->buf()), 1024, 0); - sm.add_total_offset_sent(1024); - sleep(2); + sm.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 16384, 16384, 0); CHECK(sm.total_offset_sent() == 1024); // total_offset should be a integer in unit of octets - uint8_t stream_frame4_buf[QUICFrame::MAX_INSTANCE_SIZE]; - QUICFrame *stream_frame_4 = QUICFrameFactory::create_stream_frame(stream_frame4_buf, block_1024, 4, 0); mock_app.send(reinterpret_cast(block_1024->buf()), 1024, 4); - sm.add_total_offset_sent(1024); - sleep(2); + sm.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 16384, 16384, 0); CHECK(sm.total_offset_sent() == 2048); } From d39392d077162983c0b4aa6b23e306cc6deb6aea Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 14 May 2019 14:51:34 +0900 Subject: [PATCH 1277/1313] Satisfy gcc9 --- iocore/net/quic/QUICPacket.cc | 10 +++++----- proxy/http3/test/test_QPACK.cc | 14 +++++--------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index a78351ce2f5..27194228c1c 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -255,7 +255,7 @@ QUICPacketType QUICPacketLongHeader::type() const { if (this->_buf) { - QUICPacketType type; + QUICPacketType type = QUICPacketType::UNINITIALIZED; QUICPacketLongHeader::type(type, this->_buf.get(), this->_buf_len); return type; } else { @@ -326,7 +326,7 @@ QUICPacketLongHeader::scil(uint8_t &scil, const uint8_t *packet, size_t packet_l bool QUICPacketLongHeader::token_length(size_t &token_length, uint8_t *field_len, const uint8_t *packet, size_t packet_len) { - QUICPacketType type; + QUICPacketType type = QUICPacketType::UNINITIALIZED; QUICPacketLongHeader::type(type, packet, packet_len); if (type != QUICPacketType::INITIAL) { @@ -408,7 +408,7 @@ QUICPacketLongHeader::packet_number_offset(uint8_t &pn_offset, const uint8_t *pa bool QUICPacketLongHeader::key_phase(QUICKeyPhase &phase, const uint8_t *packet, size_t packet_len) { - QUICPacketType type; + QUICPacketType type = QUICPacketType::UNINITIALIZED; QUICPacketLongHeader::type(type, packet, packet_len); phase = QUICTypeUtil::key_phase(type); return true; @@ -464,7 +464,7 @@ QUICVersion QUICPacketLongHeader::version() const { if (this->_buf) { - QUICVersion version; + QUICVersion version = 0; QUICPacketLongHeader::version(version, this->_buf.get(), this->_buf_len); return version; } else { @@ -707,7 +707,7 @@ QUICKeyPhase QUICPacketShortHeader::key_phase() const { if (this->_buf) { - QUICKeyPhase phase; + QUICKeyPhase phase = QUICKeyPhase::INITIAL; QUICPacketShortHeader::key_phase(phase, this->_buf.get(), this->_buf_len); return phase; } else { diff --git a/proxy/http3/test/test_QPACK.cc b/proxy/http3/test/test_QPACK.cc index 5ddb6788465..b4abdcc7824 100644 --- a/proxy/http3/test/test_QPACK.cc +++ b/proxy/http3/test/test_QPACK.cc @@ -399,7 +399,7 @@ TEST_CASE("Encoding", "[qpack-encode]") strcat(out_file, encdir); while ((d = readdir(dir)) != nullptr) { - char section_name[128]; + char section_name[1024]; sprintf(section_name, "%s: DTS=%d, MBS=%d, AM=%d", d->d_name, tablesize, streams, ackmode); SECTION(section_name) { @@ -408,8 +408,7 @@ TEST_CASE("Encoding", "[qpack-encode]") ink_strlcat(qif_file, d->d_name, sizeof(qif_file)); stat(qif_file, &st); if (S_ISREG(st.st_mode) && strstr(d->d_name, ".qif") == (d->d_name + (strlen(d->d_name) - 4))) { - out_file[strlen(encdir)] = '\0'; - sprintf(out_file, "%s/ats/%s.ats.%d.%d.%d", out_file, d->d_name, tablesize, streams, ackmode); + sprintf(out_file + strlen(encdir), "/ats/%s.ats.%d.%d.%d", d->d_name, tablesize, streams, ackmode); CHECK(test_encode(qif_file, out_file, tablesize, streams, ackmode) == 0); } } @@ -434,17 +433,14 @@ TEST_CASE("Decoding", "[qpack-decode]") strcat(out_file, decdir); while ((d = readdir(dir)) != nullptr) { - char section_name[128]; + char section_name[1024]; sprintf(section_name, "%s: DTS=%d, MBS=%d, AM=%d, APP=%s", d->d_name, tablesize, streams, ackmode, appname); SECTION(section_name) { - enc_file[strlen(encdir)] = '/'; - enc_file[strlen(encdir) + 1] = '\0'; - sprintf(enc_file, "%s/%s/%s", enc_file, appname, d->d_name); + sprintf(enc_file + strlen(encdir), "/%s/%s", appname, d->d_name); stat(enc_file, &st); if (S_ISREG(st.st_mode) && strstr(d->d_name, pattern)) { - out_file[strlen(decdir)] = '\0'; - sprintf(out_file, "%s/%s/%s.decoded", out_file, appname, d->d_name); + sprintf(out_file + strlen(decdir), "/%s/%s.decoded", appname, d->d_name); CHECK(test_decode(enc_file, out_file, tablesize, streams, ackmode, appname) == 0); } } From 8e4517ecb7538a20df1a779d6f276bc6f42c6531 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 14 May 2019 17:19:07 +0900 Subject: [PATCH 1278/1313] Prevent event-processing-after-free on a test --- iocore/net/quic/test/test_QUICStreamManager.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iocore/net/quic/test/test_QUICStreamManager.cc b/iocore/net/quic/test/test_QUICStreamManager.cc index c5a44da3ee2..ced351aba7e 100644 --- a/iocore/net/quic/test/test_QUICStreamManager.cc +++ b/iocore/net/quic/test/test_QUICStreamManager.cc @@ -254,4 +254,7 @@ TEST_CASE("QUICStreamManager_total_offset_sent", "[quic]") mock_app.send(reinterpret_cast(block_1024->buf()), 1024, 4); sm.generate_frame(frame_buf, QUICEncryptionLevel::ONE_RTT, 16384, 16384, 0); CHECK(sm.total_offset_sent() == 2048); + + // Wait for event processing + sleep(2); } From 85fbeccff0c1ae7c6ab6a002fb24012e549c435e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 14 May 2019 17:37:50 +0900 Subject: [PATCH 1279/1313] clang-tidy --- iocore/net/quic/QUICTLS_openssl.cc | 2 +- iocore/net/quic/test/event_processor_main.cc | 2 +- iocore/net/quic/test/main.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index 7f7c9613459..ff244f1f89a 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -420,7 +420,7 @@ QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, Net return; } - auto session = PEM_read_bio_SSL_SESSION(file, nullptr, 0, nullptr); + auto session = PEM_read_bio_SSL_SESSION(file, nullptr, nullptr, nullptr); if (session == nullptr) { Debug(tag, "Could not read tls session file %s", session_file); } else { diff --git a/iocore/net/quic/test/event_processor_main.cc b/iocore/net/quic/test/event_processor_main.cc index a56e62023d8..4c1d2dd5b3c 100644 --- a/iocore/net/quic/test/event_processor_main.cc +++ b/iocore/net/quic/test/event_processor_main.cc @@ -39,7 +39,7 @@ struct EventProcessorListener : Catch::TestEventListenerBase { using TestEventListenerBase::TestEventListenerBase; // inherit constructor - virtual void + void testRunStarting(Catch::TestRunInfo const &testRunInfo) override { BaseLogFile *base_log_file = new BaseLogFile("stderr"); diff --git a/iocore/net/quic/test/main.cc b/iocore/net/quic/test/main.cc index fe4783cc916..96767a2f97b 100644 --- a/iocore/net/quic/test/main.cc +++ b/iocore/net/quic/test/main.cc @@ -35,7 +35,7 @@ struct EventProcessorListener : Catch::TestEventListenerBase { using TestEventListenerBase::TestEventListenerBase; // inherit constructor - virtual void + void testRunStarting(Catch::TestRunInfo const &testRunInfo) override { BaseLogFile *base_log_file = new BaseLogFile("stderr"); From 4aa5ba259e5d70fa0d1e420513435df5bbc83039 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 15 May 2019 09:52:54 +0900 Subject: [PATCH 1280/1313] Performance: Initialize QUICConnectionId with ZERO to avoid calling randomize() --- iocore/net/QUICPacketHandler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 611023cb5de..2795d813acb 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -286,7 +286,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) // Server Stateless Retry QUICConfig::scoped_config params; - QUICConnectionId cid_in_retry_token; + QUICConnectionId cid_in_retry_token = QUICConnectionId::ZERO(); if (!vc && params->stateless_retry() && QUICInvariants::is_long_header(buf)) { int ret = this->_stateless_retry(buf, buf_len, udp_packet->getConnection(), udp_packet->from, dcid, scid, &cid_in_retry_token); if (ret < 0) { From 0c80e6b11414152636d2253d0ab2474e7a4750b1 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Wed, 15 May 2019 14:58:01 +0900 Subject: [PATCH 1281/1313] Performance: Optimize QUICFrameGenerator::_is_level_matched() Prior this change, std::vector was copied everytime. QUICAckFrameManager and QUICHandshake don't need this check, because these should work with all encryptio level. --- iocore/net/P_QUICNetVConnection.h | 7 ----- iocore/net/quic/QUICAckFrameCreator.cc | 17 ++++++++++++ iocore/net/quic/QUICAckFrameCreator.h | 13 +++------ iocore/net/quic/QUICFrameGenerator.cc | 15 +++-------- iocore/net/quic/QUICFrameGenerator.h | 4 +-- iocore/net/quic/QUICHandshake.cc | 17 ++++++++++++ iocore/net/quic/QUICHandshake.h | 13 +++------ iocore/net/quic/QUICPinger.h | 9 ------- iocore/net/quic/QUICStreamManager.cc | 12 +++++++++ iocore/net/quic/QUICStreamManager.h | 37 +++++++++++++------------- 10 files changed, 76 insertions(+), 68 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index f09f0b1f198..709bb5717ba 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -364,13 +364,6 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub // QUICFrameGenerator void _on_frame_lost(QUICFrameInformationUPtr &info) override; - std::vector - _encryption_level_filter() override - { - return { - QUICEncryptionLevel::ONE_RTT, - }; - } }; typedef int (QUICNetVConnection::*QUICNetVConnHandler)(int, void *); diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index 6557f2ee8a4..a69f85880f6 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -373,3 +373,20 @@ QUICAckFrameManager::QUICAckFrameCreator::QUICAckFrameCreator(QUICPacketNumberSp } QUICAckFrameManager::QUICAckFrameCreator::~QUICAckFrameCreator() {} + +/* + No limit of encryption level. + ``` + std::array _encryption_level_filter = { + QUICEncryptionLevel::INITIAL, + QUICEncryptionLevel::ZERO_RTT, + QUICEncryptionLevel::HANDSHAKE, + QUICEncryptionLevel::ONE_RTT, + }; + ``` +*/ +bool +QUICAckFrameManager::_is_level_matched(QUICEncryptionLevel level) +{ + return true; +} diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 4f4c49473e9..081c7d99694 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -112,6 +112,9 @@ class QUICAckFrameManager : public QUICFrameGenerator QUICFrameId issue_frame_id(); uint8_t ack_delay_exponent() const; +protected: + virtual bool _is_level_matched(QUICEncryptionLevel level) override; + private: virtual void _on_frame_acked(QUICFrameInformationUPtr &info) override; virtual void _on_frame_lost(QUICFrameInformationUPtr &info) override; @@ -122,16 +125,6 @@ class QUICAckFrameManager : public QUICFrameGenerator */ QUICAckFrame *_create_ack_frame(uint8_t *buf, QUICEncryptionLevel level); uint64_t _calculate_delay(QUICEncryptionLevel level); - std::vector - _encryption_level_filter() override - { - return { - QUICEncryptionLevel::INITIAL, - QUICEncryptionLevel::ZERO_RTT, - QUICEncryptionLevel::HANDSHAKE, - QUICEncryptionLevel::ONE_RTT, - }; - } bool _available[4] = {false}; bool _should_send[4] = {false}; diff --git a/iocore/net/quic/QUICFrameGenerator.cc b/iocore/net/quic/QUICFrameGenerator.cc index 0969445639a..3dce9665d4a 100644 --- a/iocore/net/quic/QUICFrameGenerator.cc +++ b/iocore/net/quic/QUICFrameGenerator.cc @@ -29,21 +29,14 @@ QUICFrameGenerator::_records_frame(QUICFrameId id, QUICFrameInformationUPtr info this->_info.insert(std::make_pair(id, std::move(info))); } -std::vector -QUICFrameGenerator::_encryption_level_filter() -{ - return {QUICEncryptionLevel::ONE_RTT}; -} - bool QUICFrameGenerator::_is_level_matched(QUICEncryptionLevel level) { - for (auto l : this->_encryption_level_filter()) { - if (l == level) { - return true; - } + if (level == this->_encryption_level_filter) { + return true; + } else { + return false; } - return false; } void diff --git a/iocore/net/quic/QUICFrameGenerator.h b/iocore/net/quic/QUICFrameGenerator.h index af04928d89d..2298de597d0 100644 --- a/iocore/net/quic/QUICFrameGenerator.h +++ b/iocore/net/quic/QUICFrameGenerator.h @@ -59,11 +59,11 @@ class QUICFrameGenerator { } - virtual std::vector _encryption_level_filter(); virtual bool _is_level_matched(QUICEncryptionLevel level); void _records_frame(QUICFrameId id, QUICFrameInformationUPtr info); private: - QUICFrameId _latest_frame_Id = 0; + QUICFrameId _latest_frame_Id = 0; + QUICEncryptionLevel _encryption_level_filter = QUICEncryptionLevel::ONE_RTT; std::map _info; }; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index d666fb8bcd6..6042d26a67c 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -491,3 +491,20 @@ QUICHandshake::_abort_handshake(QUICTransErrorCode code) this->_qc->close(QUICConnectionErrorUPtr(new QUICConnectionError(code))); } + +/* + No limit of encryption level. + ``` + std::array _encryption_level_filter = { + QUICEncryptionLevel::INITIAL, + QUICEncryptionLevel::ZERO_RTT, + QUICEncryptionLevel::HANDSHAKE, + QUICEncryptionLevel::ONE_RTT, + }; + ``` +*/ +bool +QUICHandshake::_is_level_matched(QUICEncryptionLevel level) +{ + return true; +} diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 10202f63b8c..4dda103616a 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -80,6 +80,9 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator bool is_stateless_retry_enabled() const; bool has_remote_tp() const; +protected: + virtual bool _is_level_matched(QUICEncryptionLevel level) override; + private: QUICConnection *_qc = nullptr; QUICHandshakeProtocol *_hs_protocol = nullptr; @@ -91,16 +94,6 @@ class QUICHandshake : public QUICFrameHandler, public QUICFrameGenerator QUICCryptoStream _crypto_streams[4]; - std::vector - _encryption_level_filter() override - { - return { - QUICEncryptionLevel::INITIAL, - QUICEncryptionLevel::ZERO_RTT, - QUICEncryptionLevel::HANDSHAKE, - QUICEncryptionLevel::ONE_RTT, - }; - } void _load_local_server_transport_parameters(const QUICTPConfig &tp_config, const QUICPreferredAddress *pref_addr); void _load_local_client_transport_parameters(const QUICTPConfig &tp_config); bool _check_remote_transport_parameters(std::shared_ptr tp); diff --git a/iocore/net/quic/QUICPinger.h b/iocore/net/quic/QUICPinger.h index 26b967dbe4c..efa59a375d9 100644 --- a/iocore/net/quic/QUICPinger.h +++ b/iocore/net/quic/QUICPinger.h @@ -44,13 +44,4 @@ class QUICPinger : public QUICFrameGenerator private: // Initial, 0/1-RTT, and Handshake uint64_t _need_to_fire[4] = {0}; - - // QUICFrameGenerator - std::vector - _encryption_level_filter() override - { - return { - QUICEncryptionLevel::ONE_RTT, - }; - } }; diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index e9a4cd3ed9e..826d3e23979 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -433,3 +433,15 @@ QUICStreamManager::generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint6 return frame; } + +bool +QUICStreamManager::_is_level_matched(QUICEncryptionLevel level) +{ + for (auto l : this->_encryption_level_filter) { + if (l == level) { + return true; + } + } + + return false; +} diff --git a/iocore/net/quic/QUICStreamManager.h b/iocore/net/quic/QUICStreamManager.h index 3c39003eccd..fbdc49d78fd 100644 --- a/iocore/net/quic/QUICStreamManager.h +++ b/iocore/net/quic/QUICStreamManager.h @@ -67,6 +67,9 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICFrame *generate_frame(uint8_t *buf, QUICEncryptionLevel level, uint64_t connection_credit, uint16_t maximum_frame_size, ink_hrtime timestamp) override; +protected: + virtual bool _is_level_matched(QUICEncryptionLevel level) override; + private: QUICStreamVConnection *_find_stream_vc(QUICStreamId id); QUICStreamVConnection *_find_or_create_stream_vc(QUICStreamId stream_id); @@ -77,26 +80,22 @@ class QUICStreamManager : public QUICFrameHandler, public QUICFrameGenerator QUICConnectionErrorUPtr _handle_frame(const QUICMaxStreamDataFrame &frame); QUICConnectionErrorUPtr _handle_frame(const QUICStreamDataBlockedFrame &frame); QUICConnectionErrorUPtr _handle_frame(const QUICMaxStreamsFrame &frame); - std::vector - _encryption_level_filter() override - { - return { - QUICEncryptionLevel::ZERO_RTT, - QUICEncryptionLevel::ONE_RTT, - }; - } QUICStreamFactory _stream_factory; - QUICConnectionInfoProvider *_info = nullptr; - QUICApplicationMap *_app_map = nullptr; - std::shared_ptr _local_tp = nullptr; - std::shared_ptr _remote_tp = nullptr; - QUICStreamId _local_max_streams_bidi = 0; - QUICStreamId _local_max_streams_uni = 0; - QUICStreamId _remote_max_streams_bidi = 0; - QUICStreamId _remote_max_streams_uni = 0; - QUICStreamId _next_stream_id_uni = 0; - QUICStreamId _next_stream_id_bidi = 0; - uint64_t _total_offset_sent = 0; + QUICConnectionInfoProvider *_info = nullptr; + QUICApplicationMap *_app_map = nullptr; + std::shared_ptr _local_tp = nullptr; + std::shared_ptr _remote_tp = nullptr; + QUICStreamId _local_max_streams_bidi = 0; + QUICStreamId _local_max_streams_uni = 0; + QUICStreamId _remote_max_streams_bidi = 0; + QUICStreamId _remote_max_streams_uni = 0; + QUICStreamId _next_stream_id_uni = 0; + QUICStreamId _next_stream_id_bidi = 0; + uint64_t _total_offset_sent = 0; + std::array _encryption_level_filter = { + QUICEncryptionLevel::ZERO_RTT, + QUICEncryptionLevel::ONE_RTT, + }; }; From c517e0e42969ccadaa9b59ff0f8bc7441d0df760 Mon Sep 17 00:00:00 2001 From: scw00 Date: Thu, 16 May 2019 10:18:51 +0800 Subject: [PATCH 1282/1313] Http3: close connection when buffer release --- proxy/http3/Http3ClientTransaction.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/proxy/http3/Http3ClientTransaction.cc b/proxy/http3/Http3ClientTransaction.cc index 1f70d0f0931..ccbb4d263a3 100644 --- a/proxy/http3/Http3ClientTransaction.cc +++ b/proxy/http3/Http3ClientTransaction.cc @@ -108,6 +108,7 @@ void HQClientTransaction::release(IOBufferReader *r) { super::release(r); + this->do_io_close(); this->current_reader = nullptr; } From f2f49b3333844a3218454e7b461930b11181e63b Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 16 May 2019 09:37:50 +0900 Subject: [PATCH 1283/1313] Use QUICStreamFrame::to_io_buffer_block to avoid memcpy --- iocore/net/QUICNetVConnection.cc | 22 +++-- iocore/net/quic/QUICFrame.cc | 37 +++++++-- iocore/net/quic/QUICFrame.h | 5 ++ iocore/net/quic/test/test_QUICFrame.cc | 80 +++++++++++++------ .../net/quic/test/test_QUICFrameDispatcher.cc | 10 ++- 5 files changed, 108 insertions(+), 46 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index b1086a3a66e..db16db14a39 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -1466,8 +1466,8 @@ QUICNetVConnection::_store_frame(Ptr parent_block, size_t &size_a size_added = 0; Ptr tmp = new_block; while (tmp) { - size_added += new_block->size(); - tmp = new_block->next; + size_added += tmp->size(); + tmp = tmp->next; } if (parent_block == nullptr) { @@ -1526,11 +1526,13 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa } max_frame_size = std::min(max_frame_size, this->_maximum_stream_frame_data_size()); - bool probing = false; - int frame_count = 0; - size_t len = 0; - Ptr first_block; - Ptr last_block; + bool probing = false; + int frame_count = 0; + size_t len = 0; + Ptr first_block = make_ptr(new_IOBufferBlock()); + Ptr last_block = first_block; + first_block->alloc(iobuffer_size_to_index(0)); + first_block->fill(0); if (!this->_has_ack_eliciting_packet_out) { // Sent too much ack_only packet. At this moment we need to packetize a ping frame @@ -1567,10 +1569,6 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa last_block = this->_store_frame(last_block, size_added, max_frame_size, *frame, frames); len += size_added; - if (first_block == nullptr) { - first_block = last_block; - } - // FIXME ACK frame should have priority if (frame->type() == QUICFrameType::STREAM) { if (++this->_stream_frames_sent % MAX_CONSECUTIVE_STREAMS == 0) { @@ -1710,7 +1708,7 @@ QUICNetVConnection::_build_packet(QUICEncryptionLevel level, Ptr uint8_t *raw_buf = buf.get(); size_t len = 0; while (parent_block) { - memcpy(raw_buf + len, parent_block->buf(), parent_block->size()); + memcpy(raw_buf + len, parent_block->start(), parent_block->size()); len += parent_block->size(); parent_block = parent_block->next; } diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc index b585460b5ef..903c4e96679 100644 --- a/iocore/net/quic/QUICFrame.cc +++ b/iocore/net/quic/QUICFrame.cc @@ -274,13 +274,33 @@ QUICStreamFrame::debug_msg(char *msg, size_t msg_len) const this->stream_id(), this->offset(), this->data_length(), this->has_fin_flag()); } -size_t -QUICStreamFrame::store(uint8_t *buf, size_t *len, size_t limit, bool include_length_field) const +Ptr +QUICStreamFrame::to_io_buffer_block(size_t limit) const { + Ptr header; + if (limit < this->size()) { - return 0; + return header; } + // Create header block + size_t written_len = 0; + header = make_ptr(new_IOBufferBlock()); + header->alloc(iobuffer_size_to_index(MAX_HEADER_SIZE)); + this->_store_header(reinterpret_cast(header->start()), &written_len, true); + header->fill(written_len); + + // Append payload block to a chain + ink_assert(written_len + this->data_length() <= limit); + header->next = this->data(); + + // Return the chain + return header; +} + +size_t +QUICStreamFrame::_store_header(uint8_t *buf, size_t *len, bool include_length_field) const +{ // Build Frame Type: "0b0010OLF" buf[0] = static_cast(QUICFrameType::STREAM); *len = 1; @@ -310,13 +330,16 @@ QUICStreamFrame::store(uint8_t *buf, size_t *len, size_t limit, bool include_len buf[0] += 0x01; } - // Stream Data (*) - memcpy(buf + *len, this->data()->start(), this->data_length()); - *len += this->data_length(); - return *len; } +size_t +QUICStreamFrame::store(uint8_t *buf, size_t *len, size_t limit, bool include_length_field) const +{ + ink_assert(!"Call to_io_buffer_block() instead"); + return 0; +} + QUICStreamId QUICStreamFrame::stream_id() const { diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index e9e63ee321a..4dd41ea5160 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -90,6 +90,7 @@ class QUICStreamFrame : public QUICFrame virtual size_t size() const override; virtual bool is_flow_controlled() const override; virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override; + virtual Ptr 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) override; @@ -105,8 +106,12 @@ class QUICStreamFrame : public QUICFrame LINK(QUICStreamFrame, link); private: + static constexpr uint8_t MAX_HEADER_SIZE = 32; + virtual void _reset() override; + size_t _store_header(uint8_t *buf, size_t *len, bool include_length_field) const; + Ptr _block; QUICStreamId _stream_id = 0; QUICOffset _offset = 0; diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc index 9f42e79b3b1..a8f81fd5538 100644 --- a/iocore/net/quic/test/test_QUICFrame.cc +++ b/iocore/net/quic/test/test_QUICFrame.cc @@ -186,8 +186,8 @@ TEST_CASE("Store STREAM Frame", "[quic]") { SECTION("8bit stream id, 0bit offset") { - uint8_t buf[32] = {0}; - size_t len; + uint8_t buf[32] = {0}; + size_t len = 0; uint8_t expected1[] = { 0x0a, // 0b00001OLF (OLF=010) 0x01, // Stream ID @@ -204,15 +204,19 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(block, 0x01, 0x00, false, false, true); CHECK(stream_frame.size() == 8); - stream_frame.store(buf, &len, 32); + Ptr ibb = stream_frame.to_io_buffer_block(sizeof(buf)); + for (auto b = ibb; b; b = b->next) { + memcpy(buf + len, b->start(), b->size()); + len += b->size(); + } CHECK(len == 8); CHECK(memcmp(buf, expected1, len) == 0); } SECTION("8bit stream id, 16bit offset") { - uint8_t buf[32] = {0}; - size_t len; + uint8_t buf[32] = {0}; + size_t len = 0; uint8_t expected2[] = { 0x0e, // 0b00001OLF (OLF=110) 0x01, // Stream ID @@ -229,15 +233,19 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(block, 0x01, 0x01); CHECK(stream_frame.size() == 9); - stream_frame.store(buf, &len, 32); + Ptr ibb = stream_frame.to_io_buffer_block(sizeof(buf)); + for (auto b = ibb; b; b = b->next) { + memcpy(buf + len, b->start(), b->size()); + len += b->size(); + } CHECK(len == 9); CHECK(memcmp(buf, expected2, len) == 0); } SECTION("8bit stream id, 32bit offset") { - uint8_t buf[32] = {0}; - size_t len; + uint8_t buf[32] = {0}; + size_t len = 0; uint8_t expected3[] = { 0x0e, // 0b00001OLF (OLF=110) 0x01, // Stream ID @@ -254,15 +262,19 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(block, 0x01, 0x010000); CHECK(stream_frame.size() == 12); - stream_frame.store(buf, &len, 32); + Ptr ibb = stream_frame.to_io_buffer_block(sizeof(buf)); + for (auto b = ibb; b; b = b->next) { + memcpy(buf + len, b->start(), b->size()); + len += b->size(); + } CHECK(len == 12); CHECK(memcmp(buf, expected3, len) == 0); } SECTION("8bit stream id, 64bit offset") { - uint8_t buf[32] = {0}; - size_t len; + uint8_t buf[32] = {0}; + size_t len = 0; uint8_t expected4[] = { 0x0e, // 0b00001OLF (OLF=110) 0x01, // Stream ID @@ -279,15 +291,19 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(block, 0x01, 0x0100000000); CHECK(stream_frame.size() == 16); - stream_frame.store(buf, &len, 32); + Ptr ibb = stream_frame.to_io_buffer_block(sizeof(buf)); + for (auto b = ibb; b; b = b->next) { + memcpy(buf + len, b->start(), b->size()); + len += b->size(); + } CHECK(len == 16); CHECK(memcmp(buf, expected4, len) == 0); } SECTION("16bit stream id, 64bit offset") { - uint8_t buf[32] = {0}; - size_t len; + uint8_t buf[32] = {0}; + size_t len = 0; uint8_t expected5[] = { 0x0e, // 0b00001OLF (OLF=110) 0x41, 0x00, // Stream ID @@ -304,15 +320,19 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(block, 0x0100, 0x0100000000); CHECK(stream_frame.size() == 17); - stream_frame.store(buf, &len, 32); + Ptr ibb = stream_frame.to_io_buffer_block(sizeof(buf)); + for (auto b = ibb; b; b = b->next) { + memcpy(buf + len, b->start(), b->size()); + len += b->size(); + } CHECK(len == 17); CHECK(memcmp(buf, expected5, len) == 0); } SECTION("24bit stream id, 64bit offset") { - uint8_t buf[32] = {0}; - size_t len; + uint8_t buf[32] = {0}; + size_t len = 0; uint8_t expected6[] = { 0x0e, // 0b00001OLF (OLF=110) 0x80, 0x01, 0x00, 0x00, // Stream ID @@ -329,15 +349,19 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(block, 0x010000, 0x0100000000); CHECK(stream_frame.size() == 19); - stream_frame.store(buf, &len, 32); + Ptr ibb = stream_frame.to_io_buffer_block(sizeof(buf)); + for (auto b = ibb; b; b = b->next) { + memcpy(buf + len, b->start(), b->size()); + len += b->size(); + } CHECK(len == 19); CHECK(memcmp(buf, expected6, len) == 0); } SECTION("32bit stream id, 64bit offset") { - uint8_t buf[32] = {0}; - size_t len; + uint8_t buf[32] = {0}; + size_t len = 0; uint8_t expected7[] = { 0x0e, // 0b00001OLF (OLF=110) 0x81, 0x00, 0x00, 0x00, // Stream ID @@ -354,15 +378,19 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(block, 0x01000000, 0x0100000000); CHECK(stream_frame.size() == 19); - stream_frame.store(buf, &len, 32); + Ptr ibb = stream_frame.to_io_buffer_block(sizeof(buf)); + for (auto b = ibb; b; b = b->next) { + memcpy(buf + len, b->start(), b->size()); + len += b->size(); + } CHECK(len == 19); CHECK(memcmp(buf, expected7, len) == 0); } SECTION("32bit stream id, 64bit offset, FIN bit") { - uint8_t buf[32] = {0}; - size_t len; + uint8_t buf[32] = {0}; + size_t len = 0; uint8_t expected[] = { 0x0f, // 0b00001OLF (OLF=111) 0x81, 0x00, 0x00, 0x00, // Stream ID @@ -379,7 +407,11 @@ TEST_CASE("Store STREAM Frame", "[quic]") QUICStreamFrame stream_frame(block, 0x01000000, 0x0100000000, true); CHECK(stream_frame.size() == 19); - stream_frame.store(buf, &len, 32); + Ptr ibb = stream_frame.to_io_buffer_block(sizeof(buf)); + for (auto b = ibb; b; b = b->next) { + memcpy(buf + len, b->start(), b->size()); + len += b->size(); + } CHECK(len == 19); CHECK(memcmp(buf, expected, len) == 0); } diff --git a/iocore/net/quic/test/test_QUICFrameDispatcher.cc b/iocore/net/quic/test/test_QUICFrameDispatcher.cc index 6040df3cf49..be81c2e37fe 100644 --- a/iocore/net/quic/test/test_QUICFrameDispatcher.cc +++ b/iocore/net/quic/test/test_QUICFrameDispatcher.cc @@ -55,9 +55,13 @@ TEST_CASE("QUICFrameHandler", "[quic]") CHECK(streamManager.getTotalFrameCount() == 0); // STREAM frame - uint8_t buf[4096] = {0}; - size_t len = 0; - streamFrame.store(buf, &len, 4096); + uint8_t buf[4096] = {0}; + size_t len = 0; + Ptr ibb = streamFrame.to_io_buffer_block(sizeof(buf)); + for (auto b = ibb; b; b = b->next) { + memcpy(buf + len, b->start(), b->size()); + len += b->size(); + } bool should_send_ack; bool is_flow_controlled; quicFrameDispatcher.receive_frames(QUICEncryptionLevel::INITIAL, buf, len, should_send_ack, is_flow_controlled, nullptr); From 37f963fa3b98e9cf4003bdc4f2f831c1e9e7c1cf Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 16 May 2019 15:51:06 +0900 Subject: [PATCH 1284/1313] cppcheck: fix peformance issues --- iocore/net/quic/QUICAckFrameCreator.cc | 2 +- iocore/net/quic/QUICAltConnectionManager.cc | 12 ++--- iocore/net/quic/QUICAltConnectionManager.h | 12 ++--- iocore/net/quic/QUICCongestionController.cc | 4 +- iocore/net/quic/QUICFrame.h | 2 +- iocore/net/quic/QUICLossDetector.cc | 3 +- iocore/net/quic/QUICPacket.cc | 60 ++++++++------------- iocore/net/quic/QUICPacket.h | 26 ++++++--- iocore/net/quic/QUICTypes.cc | 2 +- iocore/net/quic/QUICTypes.h | 5 +- 10 files changed, 61 insertions(+), 67 deletions(-) diff --git a/iocore/net/quic/QUICAckFrameCreator.cc b/iocore/net/quic/QUICAckFrameCreator.cc index a69f85880f6..27923b0f499 100644 --- a/iocore/net/quic/QUICAckFrameCreator.cc +++ b/iocore/net/quic/QUICAckFrameCreator.cc @@ -270,7 +270,7 @@ QUICAckFrameManager::QUICAckFrameCreator::generate_ack_frame(uint8_t *buf, uint1 QUICAckFrame * QUICAckFrameManager::QUICAckFrameCreator::_create_ack_frame(uint8_t *buf) { - ink_assert(this->_packet_numbers.size() > 0); + ink_assert(!this->_packet_numbers.empty()); QUICAckFrame *ack_frame = nullptr; this->sort(); std::list &list = this->_packet_numbers; diff --git a/iocore/net/quic/QUICAltConnectionManager.cc b/iocore/net/quic/QUICAltConnectionManager.cc index ae6d65671e2..faca19e8743 100644 --- a/iocore/net/quic/QUICAltConnectionManager.cc +++ b/iocore/net/quic/QUICAltConnectionManager.cc @@ -29,8 +29,8 @@ 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, - QUICConnectionId peer_initial_cid, uint32_t instance_id, uint8_t num_alt_con, - const QUICPreferredAddress preferred_address) + const QUICConnectionId &peer_initial_cid, uint32_t instance_id, + uint8_t num_alt_con, const QUICPreferredAddress &preferred_address) : _qc(qc), _ctable(ctable), _instance_id(instance_id), _nids(num_alt_con) { // Sequence number of the initial CID is 0 @@ -45,8 +45,8 @@ QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConne } QUICAltConnectionManager::QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, - QUICConnectionId peer_initial_cid, uint32_t instance_id, uint8_t num_alt_con, - const IpEndpoint *preferred_endpoint_ipv4, + const QUICConnectionId &peer_initial_cid, uint32_t instance_id, + uint8_t num_alt_con, const IpEndpoint *preferred_endpoint_ipv4, const IpEndpoint *preferred_endpoint_ipv6) : _qc(qc), _ctable(ctable), _instance_id(instance_id), _nids(num_alt_con) { @@ -231,7 +231,7 @@ QUICAltConnectionManager::migrate_to_alt_cid() } bool -QUICAltConnectionManager::migrate_to(QUICConnectionId cid, QUICStatelessResetToken &new_reset_token) +QUICAltConnectionManager::migrate_to(const QUICConnectionId &cid, QUICStatelessResetToken &new_reset_token) { for (unsigned int i = 0; i < this->_nids; ++i) { AltConnectionInfo &info = this->_alt_quic_connection_ids_local[i]; @@ -245,7 +245,7 @@ QUICAltConnectionManager::migrate_to(QUICConnectionId cid, QUICStatelessResetTok } void -QUICAltConnectionManager::drop_cid(QUICConnectionId cid) +QUICAltConnectionManager::drop_cid(const QUICConnectionId &cid) { for (auto it = this->_alt_quic_connection_ids_remote.begin(); it != this->_alt_quic_connection_ids_remote.end(); ++it) { if (it->id == cid) { diff --git a/iocore/net/quic/QUICAltConnectionManager.h b/iocore/net/quic/QUICAltConnectionManager.h index f16f2ba5bd4..501ab99a28c 100644 --- a/iocore/net/quic/QUICAltConnectionManager.h +++ b/iocore/net/quic/QUICAltConnectionManager.h @@ -38,13 +38,13 @@ class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenera /** * Constructor for clients */ - QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, QUICConnectionId peer_initial_cid, uint32_t instance_id, - uint8_t num_alt_con, const QUICPreferredAddress preferred_address); + QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, const QUICConnectionId &peer_initial_cid, + uint32_t instance_id, uint8_t num_alt_con, const QUICPreferredAddress &preferred_address); /** * Constructor for servers */ - QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, QUICConnectionId peer_initial_cid, uint32_t instance_id, - uint8_t num_alt_con, const IpEndpoint *preferred_endpoint_ipv4 = nullptr, + QUICAltConnectionManager(QUICConnection *qc, QUICConnectionTable &ctable, const QUICConnectionId &peer_initial_cid, + uint32_t instance_id, uint8_t num_alt_con, const IpEndpoint *preferred_endpoint_ipv4 = nullptr, const IpEndpoint *preferred_endpoint_ipv6 = nullptr); ~QUICAltConnectionManager(); @@ -64,9 +64,9 @@ class QUICAltConnectionManager : public QUICFrameHandler, public QUICFrameGenera * * cid need to match with one of alt CID that AltConnnectionManager prepared. */ - bool migrate_to(QUICConnectionId cid, QUICStatelessResetToken &new_reset_token); + bool migrate_to(const QUICConnectionId &cid, QUICStatelessResetToken &new_reset_token); - void drop_cid(QUICConnectionId cid); + void drop_cid(const QUICConnectionId &cid); /** * Invalidate all CIDs prepared diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc index 0ba0e094864..79d8fd8df18 100644 --- a/iocore/net/quic/QUICCongestionController.cc +++ b/iocore/net/quic/QUICCongestionController.cc @@ -38,10 +38,8 @@ QUICCongestionController::QUICCongestionController(const QUICRTTProvider &rtt_provider, QUICConnectionInfoProvider *info, const QUICCCConfig &cc_config) - : _info(info), _rtt_provider(rtt_provider) + : _cc_mutex(new_ProxyMutex()), _info(info), _rtt_provider(rtt_provider) { - this->_cc_mutex = new_ProxyMutex(); - this->_k_max_datagram_size = cc_config.max_datagram_size(); this->_k_initial_window = cc_config.initial_window(); this->_k_minimum_window = cc_config.minimum_window(); diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h index 4dd41ea5160..20f1bfe035d 100644 --- a/iocore/net/quic/QUICFrame.h +++ b/iocore/net/quic/QUICFrame.h @@ -540,7 +540,7 @@ class QUICNewConnectionIdFrame : public QUICFrame public: QUICNewConnectionIdFrame(QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner) {} QUICNewConnectionIdFrame(const uint8_t *buf, size_t len); - QUICNewConnectionIdFrame(uint64_t seq, QUICConnectionId cid, QUICStatelessResetToken token, QUICFrameId id = 0, + QUICNewConnectionIdFrame(uint64_t seq, const QUICConnectionId &cid, QUICStatelessResetToken token, QUICFrameId id = 0, QUICFrameGenerator *owner = nullptr) : QUICFrame(id, owner), _sequence(seq), _connection_id(cid), _stateless_reset_token(token){}; diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc index 16ddc908e97..7cd94c0f394 100644 --- a/iocore/net/quic/QUICLossDetector.cc +++ b/iocore/net/quic/QUICLossDetector.cc @@ -546,9 +546,8 @@ QUICLossDetector::_decrement_outstanding_counters(std::map_k_granularity = ld_config.granularity(); - this->_k_initial_rtt = ld_config.initial_rtt(); } void diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 27194228c1c..4280b521cb3 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -206,25 +206,17 @@ QUICPacketLongHeader::QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf this->_payload_length = len - this->_payload_offset; } -QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId destination_cid, - QUICConnectionId source_cid, QUICPacketNumber packet_number, +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) { - this->_type = type; - this->_destination_cid = destination_cid; - this->_source_cid = source_cid; - this->_packet_number = packet_number; - this->_base_packet_number = base_packet_number; - this->_has_version = true; - this->_version = version; - this->_token = std::move(token); - this->_token_len = token_len; - this->_payload = std::move(buf); - this->_payload_length = len; - this->_key_phase = key_phase; - this->_is_crypto_packet = crypto; - if (this->_type == QUICPacketType::VERSION_NEGOTIATION) { this->_buf_len = LONG_HDR_OFFSET_CONNECTION_ID + this->_destination_cid.length() + this->_source_cid.length() + this->_payload_length; @@ -234,19 +226,15 @@ QUICPacketLongHeader::QUICPacketLongHeader(QUICPacketType type, QUICKeyPhase key } QUICPacketLongHeader::QUICPacketLongHeader(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) -{ - this->_type = type; - this->_destination_cid = destination_cid; - this->_source_cid = source_cid; - this->_original_dcid = original_dcid; - this->_has_version = true; - this->_version = version; - this->_payload = std::move(retry_token); - this->_payload_length = retry_token_len; - this->_key_phase = key_phase; + 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) +{ // this->_buf_len will be set this->buf(); } @@ -626,7 +614,7 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase k this->_payload_length = len; } -QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICKeyPhase key_phase, QUICConnectionId connection_id, +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) { @@ -783,19 +771,17 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const QUICPacket::QUICPacket() {} QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len) + : _header(std::move(header)), _payload(std::move(payload)), _payload_size(payload_len) { - this->_header = std::move(header); - this->_payload = std::move(payload); - this->_payload_size = payload_len; } 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) { - this->_header = std::move(header); - this->_payload = std::move(payload); - this->_payload_size = payload_len; - this->_is_ack_eliciting = ack_eliciting; - this->_is_probing_packet = probing; } QUICPacket::~QUICPacket() diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 09d5ce3d949..0a4a38ed878 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -170,6 +170,16 @@ class QUICPacketHeader 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; @@ -198,11 +208,12 @@ class QUICPacketLongHeader : public QUICPacketHeader QUICPacketLongHeader() : QUICPacketHeader(){}; virtual ~QUICPacketLongHeader(){}; QUICPacketLongHeader(const IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base); - QUICPacketLongHeader(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 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, QUICConnectionId destination_cid, - QUICConnectionId source_cid, QUICConnectionId original_dcid, ats_unique_buf retry_token, + 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); QUICPacketType type() const override; @@ -237,7 +248,6 @@ class QUICPacketLongHeader : public QUICPacketHeader static bool packet_number_offset(uint8_t &pn_offset, const uint8_t *packet, size_t packet_len); private: - QUICPacketNumber _packet_number; QUICConnectionId _destination_cid = QUICConnectionId::ZERO(); QUICConnectionId _source_cid = QUICConnectionId::ZERO(); QUICConnectionId _original_dcid = QUICConnectionId::ZERO(); //< RETRY packet only @@ -256,8 +266,8 @@ class QUICPacketShortHeader : public QUICPacketHeader QUICPacketShortHeader(const IpEndpoint from, 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, QUICConnectionId connection_id, 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); QUICPacketType type() const override; QUICConnectionId destination_cid() const override; QUICConnectionId diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 13fd10ddfa4..1b2380870cb 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -269,7 +269,7 @@ QUICTypeUtil::write_QUICMaxData(uint64_t max_data, uint8_t *buf, size_t *len) QUICIntUtil::write_QUICVariableInt(max_data, buf, len); } -QUICStatelessResetToken::QUICStatelessResetToken(QUICConnectionId conn_id, uint32_t instance_id) +QUICStatelessResetToken::QUICStatelessResetToken(const QUICConnectionId &conn_id, uint32_t instance_id) { uint64_t data = conn_id ^ instance_id; CryptoHash _hash; diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h index 847215fa716..ee19ab05d90 100644 --- a/iocore/net/quic/QUICTypes.h +++ b/iocore/net/quic/QUICTypes.h @@ -277,7 +277,7 @@ class QUICStatelessResetToken constexpr static int8_t LEN = 16; QUICStatelessResetToken() {} - QUICStatelessResetToken(QUICConnectionId conn_id, uint32_t instance_id); + QUICStatelessResetToken(const QUICConnectionId &conn_id, uint32_t instance_id); QUICStatelessResetToken(const uint8_t *buf) { memcpy(this->_token, buf, QUICStatelessResetToken::LEN); } bool @@ -401,7 +401,8 @@ class QUICPreferredAddress constexpr static int16_t MIN_LEN = 26; constexpr static int16_t MAX_LEN = 295; - QUICPreferredAddress(IpEndpoint endpoint_ipv4, IpEndpoint endpoint_ipv6, QUICConnectionId cid, QUICStatelessResetToken token) + QUICPreferredAddress(IpEndpoint endpoint_ipv4, IpEndpoint endpoint_ipv6, const QUICConnectionId &cid, + QUICStatelessResetToken token) : _endpoint_ipv4(endpoint_ipv4), _endpoint_ipv6(endpoint_ipv6), _cid(cid), _token(token), _valid(true) { } From d0a0dc0247929eda6df9de7b2d751ccb9f1ca651 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 16 May 2019 22:33:42 +0900 Subject: [PATCH 1285/1313] Make QUIC code compilable with BoringSSL --- configure.ac | 4 ++++ iocore/net/quic/Mock.h | 3 ++- iocore/net/quic/QUICConfig.cc | 24 ++++++++++++++++++- iocore/net/quic/QUICKeyGenerator_boringssl.cc | 4 +++- iocore/net/quic/QUICPacketHeaderProtector.cc | 4 ++-- iocore/net/quic/QUICPacketHeaderProtector.h | 2 +- .../QUICPacketHeaderProtector_boringssl.cc | 2 +- .../quic/QUICPacketHeaderProtector_openssl.cc | 6 ++--- iocore/net/quic/QUICPacketPayloadProtector.cc | 8 +++---- iocore/net/quic/QUICPacketPayloadProtector.h | 16 ++++++------- .../QUICPacketPayloadProtector_boringssl.cc | 16 +++++++------ .../net/quic/QUICPacketProtectionKeyInfo.cc | 20 ++++++++-------- iocore/net/quic/QUICPacketProtectionKeyInfo.h | 22 ++++++++--------- iocore/net/quic/QUICTLS.cc | 6 +++++ iocore/net/quic/QUICTLS_boringssl.cc | 17 ++++++++----- iocore/net/quic/QUICTLS_openssl.cc | 6 ----- iocore/net/quic/QUICTransportParameters.cc | 8 +++++-- .../quic/test/test_QUICHandshakeProtocol.cc | 12 ++++++++++ .../test/test_QUICPacketHeaderProtector.cc | 4 ++++ src/tscore/HKDF_boringssl.cc | 3 ++- 20 files changed, 122 insertions(+), 65 deletions(-) diff --git a/configure.ac b/configure.ac index 93ff3f3d14b..0ccaf942c89 100644 --- a/configure.ac +++ b/configure.ac @@ -1203,9 +1203,13 @@ enable_quic=no AC_MSG_CHECKING([whether APIs for QUIC are available]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ + #ifdef OPENSSL_IS_BORINGSSL + SSL_QUIC_METHOD var; + #else #ifndef SSL_MODE_QUIC_HACK # error no hack for quic #endif + #endif ]]) ], [AC_MSG_RESULT([yes]); enable_quic=yes], diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index f7279c0db5d..963be82d60a 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -29,6 +29,7 @@ #include "QUICStreamManager.h" #include "QUICLossDetector.h" #include "QUICEvents.h" +#include using namespace std::literals; std::string_view negotiated_application_name_sv = "h3-20"sv; @@ -437,7 +438,7 @@ class MockQUICApplication : public QUICApplication class MockQUICPacketProtectionKeyInfo : public QUICPacketProtectionKeyInfo { public: - const QUIC_EVP_CIPHER * + const EVP_CIPHER * get_cipher(QUICKeyPhase phase) const override { return EVP_aes_128_gcm(); diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index ee6c477012b..8ad22ce675d 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -50,7 +50,6 @@ quic_new_ssl_ctx() #ifndef OPENSSL_IS_BORINGSSL // FIXME: OpenSSL (1.1.1-alpha) enable this option by default. But this shoule be removed when OpenSSL disable this by default. SSL_CTX_clear_options(ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); -#endif SSL_CTX_set_max_early_data(ssl_ctx, UINT32_C(0xFFFFFFFF)); @@ -58,6 +57,9 @@ quic_new_ssl_ctx() 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 #ifdef SSL_MODE_QUIC_HACK // tatsuhiro-t's custom OpenSSL for QUIC draft-13 @@ -76,11 +78,17 @@ quic_init_client_ssl_ctx(const QUICConfigParams *params) { SSL_CTX *ssl_ctx = quic_new_ssl_ctx(); +#if defined(SSL_CTX_set1_groups_list) || defined(SSL_CTX_set1_curves_list) if (params->client_supported_groups() != nullptr) { +#ifdef SSL_CTX_set1_groups_list if (SSL_CTX_set1_groups_list(ssl_ctx, params->client_supported_groups()) != 1) { +#else + if (SSL_CTX_set1_curves_list(ssl_ctx, params->client_supported_groups()) != 1) { +#endif Error("SSL_CTX_set1_groups_list failed"); } } +#endif if (params->client_session_file() != nullptr) { SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE); @@ -557,24 +565,33 @@ QUICMultiCertConfigLoader::init_server_ssl_ctx(std::vector &cert_list, c goto fail; } +#if TS_USE_TLS_SET_CIPHERSUITES if (params->server_tls13_cipher_suites != nullptr) { if (!SSL_CTX_set_ciphersuites(ctx, params->server_tls13_cipher_suites)) { Error("invalid tls server cipher suites in records.config"); goto fail; } } +#endif +#if defined(SSL_CTX_set1_groups_list) || defined(SSL_CTX_set1_curves_list) if (params->server_groups_list != nullptr) { +#ifdef SSL_CTX_set1_groups_list if (!SSL_CTX_set1_groups_list(ctx, params->server_groups_list)) { +#else + if (!SSL_CTX_set1_curves_list(ctx, params->server_groups_list)) { +#endif Error("invalid groups list for server in records.config"); goto fail; } } +#endif // SSL_CTX_set_info_callback(ctx, ssl_callback_info); SSL_CTX_set_alpn_select_cb(ctx, QUIC::ssl_select_next_protocol, nullptr); +#if TS_USE_TLS_OCSP if (SSLConfigParams::ssl_ocsp_enabled) { QUICConfDebug("SSL OCSP Stapling is enabled"); SSL_CTX_set_tlsext_status_cb(ctx, ssl_callback_ocsp_stapling); @@ -588,6 +605,11 @@ QUICMultiCertConfigLoader::init_server_ssl_ctx(std::vector &cert_list, c } else { QUICConfDebug("SSL OCSP Stapling is disabled"); } +#else + if (SSLConfigParams::ssl_ocsp_enabled) { + Warning("failed to enable SSL OCSP Stapling; this version of OpenSSL does not support it"); + } +#endif /* TS_USE_TLS_OCSP */ if (SSLConfigParams::init_ssl_ctx_cb) { SSLConfigParams::init_ssl_ctx_cb(ctx, true); diff --git a/iocore/net/quic/QUICKeyGenerator_boringssl.cc b/iocore/net/quic/QUICKeyGenerator_boringssl.cc index fe94a1c83de..e2204bbd3b0 100644 --- a/iocore/net/quic/QUICKeyGenerator_boringssl.cc +++ b/iocore/net/quic/QUICKeyGenerator_boringssl.cc @@ -20,7 +20,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "ts/ink_assert.h" +#include "tscore/ink_assert.h" #include "QUICKeyGenerator.h" #include @@ -59,6 +59,7 @@ QUICKeyGenerator::_get_cipher_for_protected_packet(const SSL *ssl) const } // 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) { @@ -73,3 +74,4 @@ QUICKeyGenerator::get_handshake_digest(const SSL *ssl) return nullptr; } } +*/ diff --git a/iocore/net/quic/QUICPacketHeaderProtector.cc b/iocore/net/quic/QUICPacketHeaderProtector.cc index 3acdef25585..49a29adb3ba 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector.cc @@ -54,7 +54,7 @@ QUICPacketHeaderProtector::protect(uint8_t *unprotected_packet, size_t unprotect Debug("v_quic_pne", "Protecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), QUICDebugNames::key_phase(phase)); - const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher_for_hp(phase); + const EVP_CIPHER *aead = this->_pp_key_info.get_cipher_for_hp(phase); if (!aead) { Debug("quic_pne", "Failed to encrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; @@ -116,7 +116,7 @@ QUICPacketHeaderProtector::unprotect(uint8_t *protected_packet, size_t protected Debug("v_quic_pne", "Unprotecting a packet number of %s packet using %s", QUICDebugNames::packet_type(type), QUICDebugNames::key_phase(phase)); - const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher_for_hp(phase); + const EVP_CIPHER *aead = this->_pp_key_info.get_cipher_for_hp(phase); if (!aead) { Debug("quic_pne", "Failed to decrypt a packet number: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return false; diff --git a/iocore/net/quic/QUICPacketHeaderProtector.h b/iocore/net/quic/QUICPacketHeaderProtector.h index 9fa8f3402ba..215b3ed0d43 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector.h +++ b/iocore/net/quic/QUICPacketHeaderProtector.h @@ -41,7 +41,7 @@ class QUICPacketHeaderProtector bool _calc_sample_offset(uint8_t *sample_offset, const uint8_t *protected_packet, size_t protected_packet_len, int dcil) const; - bool _generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const QUIC_EVP_CIPHER *aead) const; + bool _generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *cipher) const; bool _unprotect(uint8_t *packet, size_t packet_len, const uint8_t *mask) const; bool _protect(uint8_t *packet, size_t packet_len, const uint8_t *mask, int dcil) const; diff --git a/iocore/net/quic/QUICPacketHeaderProtector_boringssl.cc b/iocore/net/quic/QUICPacketHeaderProtector_boringssl.cc index 999ebda830d..54c539e6c59 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector_boringssl.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector_boringssl.cc @@ -24,7 +24,7 @@ #include "QUICPacketHeaderProtector.h" bool -QUICPacketHeaderProtector::_generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *aead) const +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; diff --git a/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc b/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc index 5039638332a..43bbba8e901 100644 --- a/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc +++ b/iocore/net/quic/QUICPacketHeaderProtector_openssl.cc @@ -24,17 +24,17 @@ #include "QUICPacketHeaderProtector.h" bool -QUICPacketHeaderProtector::_generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *aead) const +QUICPacketHeaderProtector::_generate_mask(uint8_t *mask, const uint8_t *sample, const uint8_t *key, const EVP_CIPHER *cipher) const { 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, aead, nullptr, key, sample)) { + if (!ctx || !EVP_EncryptInit_ex(ctx, cipher, nullptr, key, sample)) { return false; } int len = 0; - if (aead == EVP_chacha20()) { + if (cipher == EVP_chacha20()) { if (!EVP_EncryptUpdate(ctx, mask, &len, FIVE_ZEROS, sizeof(FIVE_ZEROS))) { return false; } diff --git a/iocore/net/quic/QUICPacketPayloadProtector.cc b/iocore/net/quic/QUICPacketPayloadProtector.cc index 35c44b51b4a..ca690577c2d 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector.cc +++ b/iocore/net/quic/QUICPacketPayloadProtector.cc @@ -44,7 +44,7 @@ QUICPacketPayloadProtector::protect(const Ptr unprotected_header, const uint8_t *iv = this->_pp_key_info.encryption_iv(phase); size_t iv_len = *this->_pp_key_info.encryption_iv_len(phase); - const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher(phase); + const EVP_CIPHER *cipher = this->_pp_key_info.get_cipher(phase); protected_payload = make_ptr(new_IOBufferBlock()); protected_payload->alloc(iobuffer_size_to_index(unprotected_payload->size() + tag_len)); @@ -52,7 +52,7 @@ QUICPacketPayloadProtector::protect(const Ptr unprotected_header, size_t written_len = 0; if (!this->_protect(reinterpret_cast(protected_payload->start()), written_len, protected_payload->write_avail(), unprotected_payload, pkt_num, reinterpret_cast(unprotected_header->buf()), - unprotected_header->size(), key, iv, iv_len, aead, tag_len)) { + 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; } else { @@ -77,7 +77,7 @@ QUICPacketPayloadProtector::unprotect(const Ptr unprotected_heade Debug(tag, "Failed to decrypt a packet: keys for %s is not ready", QUICDebugNames::key_phase(phase)); return unprotected_payload; } - const QUIC_EVP_CIPHER *aead = this->_pp_key_info.get_cipher(phase); + const EVP_CIPHER *cipher = this->_pp_key_info.get_cipher(phase); unprotected_payload = make_ptr(new_IOBufferBlock()); unprotected_payload->alloc(iobuffer_size_to_index(protected_payload->size())); @@ -85,7 +85,7 @@ QUICPacketPayloadProtector::unprotect(const Ptr unprotected_heade size_t written_len = 0; if (!this->_unprotect(reinterpret_cast(unprotected_payload->start()), written_len, unprotected_payload->write_avail(), reinterpret_cast(protected_payload->buf()), protected_payload->size(), pkt_num, - reinterpret_cast(unprotected_header->buf()), unprotected_header->size(), key, iv, iv_len, aead, + reinterpret_cast(unprotected_header->buf()), unprotected_header->size(), key, iv, iv_len, cipher, tag_len)) { Debug(tag, "Failed to decrypt a packet #%" PRIu64, pkt_num); unprotected_payload = nullptr; diff --git a/iocore/net/quic/QUICPacketPayloadProtector.h b/iocore/net/quic/QUICPacketPayloadProtector.h index 5083d37e0e0..a11197d83ea 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector.h +++ b/iocore/net/quic/QUICPacketPayloadProtector.h @@ -34,20 +34,20 @@ class QUICPacketPayloadProtector public: QUICPacketPayloadProtector(const QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info) {} - Ptr protect(const Ptr unprotected_header, const Ptr unprotected_payload, + Ptr protect(const Ptr protected_payload, const Ptr unprotected_payload, uint64_t pkt_num, QUICKeyPhase phase) const; - Ptr unprotect(const Ptr unprotected_header, const Ptr protected_payload, + Ptr unprotect(const Ptr unprotected_payload, const Ptr protected_payload, uint64_t pkt_num, QUICKeyPhase phase) const; private: const QUICPacketProtectionKeyInfo &_pp_key_info; - bool _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 QUIC_EVP_CIPHER *aead, size_t tag_len) const; - bool _protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const Ptr 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 QUIC_EVP_CIPHER *aead, - size_t tag_len) const; + bool _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; + bool _protect(uint8_t *protected_payload, size_t &protected_payload_len, size_t max_protected_payload_len, + const Ptr 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; void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const; }; diff --git a/iocore/net/quic/QUICPacketPayloadProtector_boringssl.cc b/iocore/net/quic/QUICPacketPayloadProtector_boringssl.cc index eeedab1143e..56e88dd45fd 100644 --- a/iocore/net/quic/QUICPacketPayloadProtector_boringssl.cc +++ b/iocore/net/quic/QUICPacketPayloadProtector_boringssl.cc @@ -25,21 +25,23 @@ #include "QUICPacketPayloadProtector.h" #include "tscore/Diags.h" -static constexpr char tag[] = "quic_ppp"; +// static constexpr char tag[] = "quic_ppp"; bool -QUICPacketPayloadProtector::_protect(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const Ptr 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 +QUICPacketPayloadProtector::_protect(uint8_t *protected_payload, size_t &protected_payload_len, size_t max_protecgted_payload_len, + const Ptr 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 { ink_assert(!"not implemented"); return false; } 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 +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 { ink_assert(!"not implemented"); return false; diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.cc b/iocore/net/quic/QUICPacketProtectionKeyInfo.cc index 2f791cb2c03..55c2e2ee5bd 100644 --- a/iocore/net/quic/QUICPacketProtectionKeyInfo.cc +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.cc @@ -50,7 +50,7 @@ QUICPacketProtectionKeyInfo::drop_keys(QUICKeyPhase phase) memset(this->_server_key_for_hp[index], 0x00, sizeof(this->_server_key_for_hp[index])); } -const QUIC_EVP_CIPHER * +const EVP_CIPHER * QUICPacketProtectionKeyInfo::get_cipher(QUICKeyPhase phase) const { switch (phase) { @@ -114,7 +114,7 @@ QUICPacketProtectionKeyInfo::encryption_key(QUICKeyPhase phase) size_t QUICPacketProtectionKeyInfo::encryption_key_len(QUICKeyPhase phase) const { - const QUIC_EVP_CIPHER *cipher; + const EVP_CIPHER *cipher; switch (phase) { case QUICKeyPhase::INITIAL: @@ -205,7 +205,7 @@ QUICPacketProtectionKeyInfo::decryption_key(QUICKeyPhase phase) size_t QUICPacketProtectionKeyInfo::decryption_key_len(QUICKeyPhase phase) const { - const QUIC_EVP_CIPHER *cipher; + const EVP_CIPHER *cipher; switch (phase) { case QUICKeyPhase::INITIAL: @@ -254,19 +254,19 @@ QUICPacketProtectionKeyInfo::decryption_iv_len(QUICKeyPhase phase) } void -QUICPacketProtectionKeyInfo::set_cipher_initial(const QUIC_EVP_CIPHER *cipher) +QUICPacketProtectionKeyInfo::set_cipher_initial(const EVP_CIPHER *cipher) { this->_cipher_initial = cipher; } void -QUICPacketProtectionKeyInfo::set_cipher(const QUIC_EVP_CIPHER *cipher, size_t tag_len) +QUICPacketProtectionKeyInfo::set_cipher(const EVP_CIPHER *cipher, size_t tag_len) { this->_cipher = cipher; this->_tag_len = tag_len; } -const QUIC_EVP_CIPHER * +const EVP_CIPHER * QUICPacketProtectionKeyInfo::get_cipher_for_hp(QUICKeyPhase phase) const { switch (phase) { @@ -278,13 +278,13 @@ QUICPacketProtectionKeyInfo::get_cipher_for_hp(QUICKeyPhase phase) const } void -QUICPacketProtectionKeyInfo::set_cipher_for_hp_initial(const QUIC_EVP_CIPHER *cipher) +QUICPacketProtectionKeyInfo::set_cipher_for_hp_initial(const EVP_CIPHER *cipher) { this->_cipher_for_hp_initial = cipher; } void -QUICPacketProtectionKeyInfo::set_cipher_for_hp(const QUIC_EVP_CIPHER *cipher) +QUICPacketProtectionKeyInfo::set_cipher_for_hp(const EVP_CIPHER *cipher) { this->_cipher_for_hp = cipher; } @@ -314,7 +314,7 @@ QUICPacketProtectionKeyInfo::encryption_key_for_hp(QUICKeyPhase phase) size_t QUICPacketProtectionKeyInfo::encryption_key_for_hp_len(QUICKeyPhase phase) const { - const QUIC_EVP_CIPHER *cipher; + const EVP_CIPHER *cipher; switch (phase) { case QUICKeyPhase::INITIAL: @@ -353,7 +353,7 @@ QUICPacketProtectionKeyInfo::decryption_key_for_hp(QUICKeyPhase phase) size_t QUICPacketProtectionKeyInfo::decryption_key_for_hp_len(QUICKeyPhase phase) const { - const QUIC_EVP_CIPHER *cipher; + const EVP_CIPHER *cipher; switch (phase) { case QUICKeyPhase::INITIAL: diff --git a/iocore/net/quic/QUICPacketProtectionKeyInfo.h b/iocore/net/quic/QUICPacketProtectionKeyInfo.h index de0385dee8b..32a38d41383 100644 --- a/iocore/net/quic/QUICPacketProtectionKeyInfo.h +++ b/iocore/net/quic/QUICPacketProtectionKeyInfo.h @@ -38,10 +38,10 @@ class QUICPacketProtectionKeyInfo // Payload Protection (common) - virtual const QUIC_EVP_CIPHER *get_cipher(QUICKeyPhase phase) const; + virtual const EVP_CIPHER *get_cipher(QUICKeyPhase phase) const; virtual size_t get_tag_len(QUICKeyPhase phase) const; - virtual void set_cipher_initial(const QUIC_EVP_CIPHER *cipher); - virtual void set_cipher(const QUIC_EVP_CIPHER *cipher, size_t tag_len); + virtual void set_cipher_initial(const EVP_CIPHER *cipher); + virtual void set_cipher(const EVP_CIPHER *cipher, size_t tag_len); // Payload Protection (encryption) @@ -77,9 +77,9 @@ class QUICPacketProtectionKeyInfo // Header Protection - virtual const QUIC_EVP_CIPHER *get_cipher_for_hp(QUICKeyPhase phase) const; - virtual void set_cipher_for_hp_initial(const QUIC_EVP_CIPHER *cipher); - virtual void set_cipher_for_hp(const QUIC_EVP_CIPHER *cipher); + virtual const EVP_CIPHER *get_cipher_for_hp(QUICKeyPhase phase) const; + virtual void set_cipher_for_hp_initial(const EVP_CIPHER *cipher); + virtual void set_cipher_for_hp(const EVP_CIPHER *cipher); virtual const uint8_t *encryption_key_for_hp(QUICKeyPhase phase) const; virtual uint8_t *encryption_key_for_hp(QUICKeyPhase phase); @@ -96,9 +96,9 @@ class QUICPacketProtectionKeyInfo // Payload Protection - const QUIC_EVP_CIPHER *_cipher_initial = nullptr; - const QUIC_EVP_CIPHER *_cipher = nullptr; - size_t _tag_len = 0; + const EVP_CIPHER *_cipher_initial = nullptr; + const EVP_CIPHER *_cipher = nullptr; + size_t _tag_len = 0; bool _is_client_key_available[5] = {false}; bool _is_server_key_available[5] = {false}; @@ -115,8 +115,8 @@ class QUICPacketProtectionKeyInfo // Header Protection - const QUIC_EVP_CIPHER *_cipher_for_hp_initial = nullptr; - const QUIC_EVP_CIPHER *_cipher_for_hp = nullptr; + const EVP_CIPHER *_cipher_for_hp_initial = nullptr; + const EVP_CIPHER *_cipher_for_hp = nullptr; uint8_t _client_key_for_hp[5][512]; uint8_t _server_key_for_hp[5][512]; diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc index f03a5a7bac3..5736ef46191 100644 --- a/iocore/net/quic/QUICTLS.cc +++ b/iocore/net/quic/QUICTLS.cc @@ -79,6 +79,12 @@ QUICTLS::~QUICTLS() SSL_free(this->_ssl); } +void +QUICTLS::reset() +{ + SSL_clear(this->_ssl); +} + uint16_t QUICTLS::convert_to_quic_trans_error_code(uint8_t alert) { diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc index 966d69a8f97..a535e79bccb 100644 --- a/iocore/net/quic/QUICTLS_boringssl.cc +++ b/iocore/net/quic/QUICTLS_boringssl.cc @@ -29,12 +29,15 @@ #include #include -static constexpr char tag[] = "quic_tls"; - -QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICTLS(ssl, nvc_ctx, false) {} - -QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless) - : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx), _stateless(stateless) +// static constexpr char tag[] = "quic_tls"; + +QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx, + const NetVCOptions &netvc_options, const char *session_file, const char *keylog_file) + : QUICHandshakeProtocol(pp_key_info), + _session_file(session_file), + _keylog_file(keylog_file), + _ssl(SSL_new(ssl_ctx)), + _netvc_context(nvc_ctx) { ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET); } @@ -66,6 +69,7 @@ QUICTLS::_read_early_data() return 1; } +/* const EVP_AEAD * QUICTLS::_get_evp_aead(QUICKeyPhase phase) const { @@ -173,3 +177,4 @@ QUICTLS::_decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const return true; } +*/ diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc index ff244f1f89a..0eabec13a23 100644 --- a/iocore/net/quic/QUICTLS_openssl.cc +++ b/iocore/net/quic/QUICTLS_openssl.cc @@ -580,12 +580,6 @@ QUICTLS::_process_post_handshake_messages(QUICHandshakeMsgs *out, const QUICHand return 1; } -void -QUICTLS::reset() -{ - SSL_clear(this->_ssl); -} - void QUICTLS::_store_negotiated_cipher() { diff --git a/iocore/net/quic/QUICTransportParameters.cc b/iocore/net/quic/QUICTransportParameters.cc index 4d3bc7dae4c..04f0009930b 100644 --- a/iocore/net/quic/QUICTransportParameters.cc +++ b/iocore/net/quic/QUICTransportParameters.cc @@ -32,8 +32,7 @@ #include "QUICTLS.h" #include "QUICTypes.h" -static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; -static constexpr char tag[] = "quic_handshake"; +static constexpr char tag[] = "quic_handshake"; static constexpr uint32_t TP_ERROR_LENGTH = 0x010000; static constexpr uint32_t TP_ERROR_VALUE = 0x020000; @@ -424,6 +423,10 @@ QUICTransportParametersInEncryptedExtensions::_validate_parameters() const return 0; } +#ifndef OPENSSL_IS_BORINGSSL + +static constexpr int TRANSPORT_PARAMETERS_MAXIMUM_SIZE = 65535; + // // QUICTransportParametersHandler // @@ -465,3 +468,4 @@ QUICTransportParametersHandler::parse(SSL *s, unsigned int ext_type, unsigned in return 1; } +#endif diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc index fa13302038a..f90b10af3fa 100644 --- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc +++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc @@ -81,7 +81,9 @@ TEST_CASE("QUICHandshakeProtocol") SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); +#ifndef OPENSSL_IS_BORINGSSL SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +#endif #ifdef SSL_MODE_QUIC_HACK SSL_CTX_set_mode(client_ssl_ctx, SSL_MODE_QUIC_HACK); #endif @@ -90,7 +92,9 @@ TEST_CASE("QUICHandshakeProtocol") SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); +#ifndef OPENSSL_IS_BORINGSSL SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +#endif #ifdef SSL_MODE_QUIC_HACK SSL_CTX_set_mode(server_ssl_ctx, SSL_MODE_QUIC_HACK); #endif @@ -227,7 +231,11 @@ TEST_CASE("QUICHandshakeProtocol") SECTION("Full Handshake with HRR", "[quic]") { // client key_share will be X25519 (default of OpenSSL) +#ifdef SSL_CTX_set1_groups_list if (SSL_CTX_set1_groups_list(server_ssl_ctx, "P-521:P-384:P-256") != 1) { +#else + if (SSL_CTX_set1_curves_list(server_ssl_ctx, "P-521:P-384:P-256") != 1) { +#endif REQUIRE(false); } @@ -362,7 +370,11 @@ TEST_CASE("QUICHandshakeProtocol") // Teardown // Make it back to the default settings +#ifdef SSL_CTX_set1_groups_list if (SSL_CTX_set1_groups_list(server_ssl_ctx, "X25519:P-521:P-384:P-256") != 1) { +#else + if (SSL_CTX_set1_curves_list(server_ssl_ctx, "X25519:P-521:P-384:P-256") != 1) { +#endif REQUIRE(false); } diff --git a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc index 9b7c0c4114d..dc754a4a2f6 100644 --- a/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc +++ b/iocore/net/quic/test/test_QUICPacketHeaderProtector.cc @@ -43,7 +43,9 @@ TEST_CASE("QUICPacketHeaderProtector") SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION); +#ifndef OPENSSL_IS_BORINGSSL SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +#endif #ifdef SSL_MODE_QUIC_HACK SSL_CTX_set_mode(client_ssl_ctx, SSL_MODE_QUIC_HACK); #endif @@ -52,7 +54,9 @@ TEST_CASE("QUICPacketHeaderProtector") SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION); +#ifndef OPENSSL_IS_BORINGSSL SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); +#endif #ifdef SSL_MODE_QUIC_HACK SSL_CTX_set_mode(server_ssl_ctx, SSL_MODE_QUIC_HACK); #endif diff --git a/src/tscore/HKDF_boringssl.cc b/src/tscore/HKDF_boringssl.cc index 08fcd66ea89..18ecd720ef1 100644 --- a/src/tscore/HKDF_boringssl.cc +++ b/src/tscore/HKDF_boringssl.cc @@ -21,7 +21,8 @@ * limitations under the License. */ #include "tscore/HKDF.h" -#include +#include "tscore/ink_assert.h" +#include HKDF::HKDF(const EVP_MD *digest) : _digest(digest) { From df42ccf6906b0c3d893f7a932d04a2d96a3cd7a8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Sun, 19 May 2019 11:06:42 +0900 Subject: [PATCH 1286/1313] Remove an unnecessary header include --- iocore/net/quic/Mock.h | 1 - 1 file changed, 1 deletion(-) diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 963be82d60a..45f5e8f49b4 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -29,7 +29,6 @@ #include "QUICStreamManager.h" #include "QUICLossDetector.h" #include "QUICEvents.h" -#include using namespace std::literals; std::string_view negotiated_application_name_sv = "h3-20"sv; From 39ddacee594fb8f2b19d5e63369e916bb00a69a8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 20 May 2019 10:46:49 +0100 Subject: [PATCH 1287/1313] Fix asan issues --- iocore/net/quic/QUICKeyGenerator.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc index 9b2a1d644e8..05c1796f950 100644 --- a/iocore/net/quic/QUICKeyGenerator.cc +++ b/iocore/net/quic/QUICKeyGenerator.cc @@ -56,7 +56,7 @@ QUICKeyGenerator::generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t this->_generate_initial_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_CLIENT_INITIAL_SECRET.data(), LABEL_FOR_CLIENT_INITIAL_SECRET.length(), EVP_MD_size(md)); if (is_debug_tag_set("vv_quic_crypto")) { - uint8_t print_buf[512]; + uint8_t print_buf[1024 + 1]; QUICDebug::to_hex(print_buf, secret, secret_len); Debug("vv_quic_crypto", "client_in_secret=%s", print_buf); } @@ -66,7 +66,7 @@ QUICKeyGenerator::generate(uint8_t *hp_key, uint8_t *pp_key, uint8_t *iv, size_t this->_generate_initial_secret(secret, &secret_len, hkdf, cid, LABEL_FOR_SERVER_INITIAL_SECRET.data(), LABEL_FOR_SERVER_INITIAL_SECRET.length(), EVP_MD_size(md)); if (is_debug_tag_set("vv_quic_crypto")) { - uint8_t print_buf[512]; + uint8_t print_buf[1024 + 1]; QUICDebug::to_hex(print_buf, secret, secret_len); Debug("vv_quic_crypto", "server_in_secret=%s", print_buf); } @@ -117,7 +117,7 @@ QUICKeyGenerator::_generate_initial_secret(uint8_t *out, size_t *out_len, QUICHK } if (is_debug_tag_set("vv_quic_crypto")) { - uint8_t print_buf[512]; + uint8_t print_buf[1024 + 1]; QUICDebug::to_hex(print_buf, initial_secret, initial_secret_len); Debug("vv_quic_crypto", "initial_secret=%s", print_buf); } From 955d380371c3b9fa6aeb7cac10331d2b84ef19e1 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 20 May 2019 14:21:38 +0100 Subject: [PATCH 1288/1313] Fix a bug in ConnectionId::_hashcode It should use the upper 64 bits but it wasn't because of signed and unsigned --- iocore/net/quic/QUICTypes.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc index 1b2380870cb..29e09d2de00 100644 --- a/iocore/net/quic/QUICTypes.cc +++ b/iocore/net/quic/QUICTypes.cc @@ -607,8 +607,9 @@ uint64_t QUICConnectionId::_hashcode() const { return (static_cast(this->_id[0]) << 56) + (static_cast(this->_id[1]) << 48) + - (static_cast(this->_id[2]) << 40) + (static_cast(this->_id[3]) << 32) + (this->_id[4] << 24) + - (this->_id[5] << 16) + (this->_id[6] << 8) + this->_id[7]; + (static_cast(this->_id[2]) << 40) + (static_cast(this->_id[3]) << 32) + + (static_cast(this->_id[4]) << 24) + (static_cast(this->_id[5]) << 16) + + (static_cast(this->_id[6]) << 8) + (static_cast(this->_id[7])); } uint32_t From a8c14edbc062409079f41cacb4887a8af812b31a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 20 May 2019 15:53:53 +0100 Subject: [PATCH 1289/1313] idle_timeout TP is milisecond since -19 --- doc/admin-guide/files/records.config.en.rst | 4 ++-- iocore/net/QUICNetVConnection.cc | 4 ++-- mgmt/RecordsConfig.cc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst index 9d41ef8a7f9..4e616d3bf3d 100644 --- a/doc/admin-guide/files/records.config.en.rst +++ b/doc/admin-guide/files/records.config.en.rst @@ -3694,12 +3694,12 @@ removed in the future without prior notice. Only available for :program:`traffic_quic`. If specified, key information will be stored to the file. -.. ts:cv:: CONFIG proxy.config.quic.no_activity_timeout_in INT 30 +.. ts:cv:: CONFIG proxy.config.quic.no_activity_timeout_in INT 30000 :reloadable: This value will be advertised as ``idle_timeout`` Transport Parameter. -.. ts:cv:: CONFIG proxy.config.quic.no_activity_timeout_out INT 30 +.. ts:cv:: CONFIG proxy.config.quic.no_activity_timeout_out INT 30000 :reloadable: This value will be advertised as ``idle_timeout`` Transport Parameter. diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index db16db14a39..15752fb547e 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -745,9 +745,9 @@ QUICNetVConnection::state_pre_handshake(int event, Event *data) // FIXME: Should be accept_no_activity_timeout? if (this->get_context() == NET_VCONNECTION_IN) { - this->set_inactivity_timeout(HRTIME_SECONDS(this->_quic_config->no_activity_timeout_in())); + this->set_inactivity_timeout(HRTIME_MSECONDS(this->_quic_config->no_activity_timeout_in())); } else { - this->set_inactivity_timeout(HRTIME_SECONDS(this->_quic_config->no_activity_timeout_out())); + this->set_inactivity_timeout(HRTIME_MSECONDS(this->_quic_config->no_activity_timeout_out())); } this->add_to_active_queue(); diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index f22cec004ac..5be7602d5e7 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1353,9 +1353,9 @@ static const RecordElement RecordsConfig[] = {RECT_CONFIG, "proxy.config.quic.client.keylog_file", RECD_STRING, nullptr , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , // Transport Parameters - {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_in", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_in", RECD_INT, "30000", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_out", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_out", RECD_INT, "30000", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.preferred_address_ipv4", RECD_STRING, nullptr , RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , From 142dd26851659214316d50bb76b29879affe609e Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 20 May 2019 16:36:14 +0100 Subject: [PATCH 1290/1313] Fix handling 0 length HTTP/3 frame --- proxy/http3/Http3Frame.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc index f60b530fb8d..ac47752a423 100644 --- a/proxy/http3/Http3Frame.cc +++ b/proxy/http3/Http3Frame.cc @@ -374,10 +374,6 @@ Http3FrameFactory::create(const uint8_t *buf, size_t len) std::shared_ptr Http3FrameFactory::fast_create(const uint8_t *buf, size_t len) { - uint64_t frame_length = 0; - if (Http3Frame::length(buf, len, frame_length) == -1 || frame_length > len) { - return nullptr; - } Http3FrameType type = Http3Frame::type(buf, len); if (type == Http3FrameType::UNKNOWN) { if (!this->_unknown_frame) { From 4a7bc099c4f0ca75d68bfa68112f2a3651ec5f34 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 21 May 2019 09:35:51 +0100 Subject: [PATCH 1291/1313] Fix a test for Http3Frame --- proxy/http3/test/test_Http3Frame.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proxy/http3/test/test_Http3Frame.cc b/proxy/http3/test/test_Http3Frame.cc index 242178a3227..a7f90d8938d 100644 --- a/proxy/http3/test/test_Http3Frame.cc +++ b/proxy/http3/test/test_Http3Frame.cc @@ -247,5 +247,6 @@ TEST_CASE("Http3FrameFactory Fast Create Unknown Frame", "[http3]") 0x0f, // Type }; std::shared_ptr frame1 = factory.fast_create(buf1, sizeof(buf1)); - CHECK(frame1 == nullptr); + CHECK(frame1); + CHECK(frame1->type() == Http3FrameType::UNKNOWN); } From 14a4f67d838f421e88f0d7be79b26795573aceb8 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 21 May 2019 10:30:44 +0100 Subject: [PATCH 1292/1313] Share a QUIC connection table among QUIC ports --- iocore/net/P_QUICNetProcessor.h | 4 +++- iocore/net/P_QUICPacketHandler.h | 4 ++-- iocore/net/QUICNetProcessor.cc | 14 +++++++------- iocore/net/QUICPacketHandler.cc | 16 ++++++---------- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/iocore/net/P_QUICNetProcessor.h b/iocore/net/P_QUICNetProcessor.h index 5c6bfb434fa..bb3e8576b74 100644 --- a/iocore/net/P_QUICNetProcessor.h +++ b/iocore/net/P_QUICNetProcessor.h @@ -39,6 +39,7 @@ #include "tscore/ink_platform.h" #include "P_Net.h" +#include "quic/QUICConnectionTable.h" class UnixNetVConnection; struct NetAccept; @@ -56,7 +57,6 @@ class QUICNetProcessor : public UnixNetProcessor void init() override; virtual int start(int, size_t stacksize) override; - void cleanup(); // TODO: refactoring NetProcessor::connect_re and UnixNetProcessor::connect_re_internal // Action *connect_re(Continuation *cont, sockaddr const *addr, NetVCOptions *opts) override; Action *connect_re(Continuation *cont, sockaddr const *addr, NetVCOptions *opts); @@ -71,6 +71,8 @@ class QUICNetProcessor : public UnixNetProcessor private: QUICNetProcessor(const QUICNetProcessor &); QUICNetProcessor &operator=(const QUICNetProcessor &); + + QUICConnectionTable *_ctable = nullptr; }; extern QUICNetProcessor quic_NetProcessor; diff --git a/iocore/net/P_QUICPacketHandler.h b/iocore/net/P_QUICPacketHandler.h index d7337e2d867..27a5235d911 100644 --- a/iocore/net/P_QUICPacketHandler.h +++ b/iocore/net/P_QUICPacketHandler.h @@ -67,7 +67,7 @@ class QUICPacketHandler class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler { public: - QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt); + QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt, QUICConnectionTable &ctable); ~QUICPacketHandlerIn(); // NetAccept @@ -85,7 +85,7 @@ class QUICPacketHandlerIn : public NetAccept, public QUICPacketHandler int _stateless_retry(const uint8_t *buf, uint64_t buf_len, UDPConnection *connection, IpEndpoint from, QUICConnectionId dcid, QUICConnectionId scid, QUICConnectionId *original_cid); - QUICConnectionTable *_ctable = nullptr; + QUICConnectionTable &_ctable; }; /* diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index 5a2e373bb59..bf3bb1fd972 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -38,12 +38,8 @@ QUICNetProcessor::QUICNetProcessor() {} QUICNetProcessor::~QUICNetProcessor() { - cleanup(); -} - -void -QUICNetProcessor::cleanup() -{ + // TODO: clear all values before destory the table. + delete this->_ctable; } void @@ -76,7 +72,11 @@ QUICNetProcessor::start(int, size_t stacksize) NetAccept * QUICNetProcessor::createNetAccept(const NetProcessor::AcceptOptions &opt) { - return (NetAccept *)new QUICPacketHandlerIn(opt); + if (this->_ctable == nullptr) { + QUICConfig::scoped_config params; + this->_ctable = new QUICConnectionTable(params->connection_table_size()); + } + return (NetAccept *)new QUICPacketHandlerIn(opt, *this->_ctable); } NetVConnection * diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 2795d813acb..34e076bac76 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -122,19 +122,15 @@ QUICPacketHandler::_send_packet(UDPConnection *udp_con, IpEndpoint &addr, Ptrmutex = new_ProxyMutex(); // create Connection Table QUICConfig::scoped_config params; - _ctable = new QUICConnectionTable(params->connection_table_size()); } -QUICPacketHandlerIn::~QUICPacketHandlerIn() -{ - // TODO: clear all values before destory the table. - delete _ctable; -} +QUICPacketHandlerIn::~QUICPacketHandlerIn() {} NetProcessor * QUICPacketHandlerIn::getNetProcessor() const @@ -146,7 +142,7 @@ NetAccept * QUICPacketHandlerIn::clone() const { NetAccept *na; - na = new QUICPacketHandlerIn(opt); + na = new QUICPacketHandlerIn(opt, this->_ctable); *na = *this; return na; } @@ -281,7 +277,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) } } - QUICConnection *qc = this->_ctable->lookup(dcid); + QUICConnection *qc = this->_ctable.lookup(dcid); QUICNetVConnection *vc = static_cast(qc); // Server Stateless Retry @@ -334,7 +330,7 @@ QUICPacketHandlerIn::_recv_packet(int event, UDPPacket *udp_packet) } vc = static_cast(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->_ctable); vc->id = net_next_connection_number(); vc->con.move(con); vc->submit_time = Thread::get_hrtime(); From d99371e341b797d7166aa7e392847802d9e48c59 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 21 May 2019 12:30:08 +0100 Subject: [PATCH 1293/1313] Fix calculation of end of buf in QPACK::_decode_literal_header_field_without_name_ref() --- proxy/http3/QPACK.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/http3/QPACK.cc b/proxy/http3/QPACK.cc index a2d205409ac..156a9d45792 100644 --- a/proxy/http3/QPACK.cc +++ b/proxy/http3/QPACK.cc @@ -753,7 +753,7 @@ QPACK::_decode_literal_header_field_without_name_ref(const uint8_t *buf, size_t char *value; uint64_t value_len; - if ((ret = xpack_decode_string(arena, &value, value_len, buf + read_len, buf + buf_len - read_len, 7)) < 0) { + if ((ret = xpack_decode_string(arena, &value, value_len, buf + read_len, buf + buf_len, 7)) < 0) { return -1; } read_len += ret; From 8aac785b6aaa08d9dbaa6dad0210761bf5bba52e Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 21 May 2019 12:43:21 +0100 Subject: [PATCH 1294/1313] Fix a nullptr dereference --- iocore/net/quic/QUICPacketFactory.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc index 8b086983924..143f69b6cc3 100644 --- a/iocore/net/quic/QUICPacketFactory.cc +++ b/iocore/net/quic/QUICPacketFactory.cc @@ -108,10 +108,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP 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()); - memcpy(plain_txt.get(), plain->buf(), plain->size()); - plain_txt_len = plain->size(); if (plain != nullptr) { - result = QUICPacketCreationResult::SUCCESS; + memcpy(plain_txt.get(), plain->buf(), plain->size()); + plain_txt_len = plain->size(); + result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; } @@ -123,10 +123,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP 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()); - memcpy(plain_txt.get(), plain->buf(), plain->size()); - plain_txt_len = plain->size(); if (plain != nullptr) { - result = QUICPacketCreationResult::SUCCESS; + memcpy(plain_txt.get(), plain->buf(), plain->size()); + plain_txt_len = plain->size(); + result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; } @@ -140,10 +140,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP 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()); - memcpy(plain_txt.get(), plain->buf(), plain->size()); - plain_txt_len = plain->size(); if (plain != nullptr) { - result = QUICPacketCreationResult::SUCCESS; + memcpy(plain_txt.get(), plain->buf(), plain->size()); + plain_txt_len = plain->size(); + result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::FAILED; } @@ -154,10 +154,10 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP 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()); - memcpy(plain_txt.get(), plain->buf(), plain->size()); - plain_txt_len = plain->size(); if (plain != nullptr) { - result = QUICPacketCreationResult::SUCCESS; + memcpy(plain_txt.get(), plain->buf(), plain->size()); + plain_txt_len = plain->size(); + result = QUICPacketCreationResult::SUCCESS; } else { result = QUICPacketCreationResult::IGNORED; } From 2eb96736f939e4538464ebfb1eae36627993cc45 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Mon, 20 May 2019 14:25:03 +0100 Subject: [PATCH 1295/1313] Fix local/remote TP for checking stream id --- iocore/net/quic/QUICStreamManager.cc | 47 +++++++++++++++++++++------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/iocore/net/quic/QUICStreamManager.cc b/iocore/net/quic/QUICStreamManager.cc index 826d3e23979..91edd1b7c8b 100644 --- a/iocore/net/quic/QUICStreamManager.cc +++ b/iocore/net/quic/QUICStreamManager.cc @@ -270,24 +270,36 @@ QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id) switch (QUICTypeUtil::detect_stream_type(stream_id)) { case QUICStreamType::CLIENT_BIDI: - if (this->_local_max_streams_bidi == 0 || stream_id > this->_local_max_streams_bidi) { - return nullptr; - } - if (this->_info->direction() == NET_VCONNECTION_OUT) { // client + if (this->_remote_max_streams_bidi == 0 || stream_id > this->_remote_max_streams_bidi) { + return nullptr; + } + local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); 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) { + return nullptr; + } + local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); } break; case QUICStreamType::CLIENT_UNI: - if (this->_local_max_streams_uni == 0 || stream_id > this->_local_max_streams_uni) { - return nullptr; + if (this->_info->direction() == NET_VCONNECTION_OUT) { + // client + if (this->_remote_max_streams_uni == 0 || stream_id > this->_remote_max_streams_uni) { + return nullptr; + } + } else { + // server + if (this->_local_max_streams_uni == 0 || stream_id > this->_local_max_streams_uni) { + return nullptr; + } } local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); @@ -295,27 +307,38 @@ QUICStreamManager::_find_or_create_stream_vc(QUICStreamId stream_id) break; case QUICStreamType::SERVER_BIDI: - if (this->_remote_max_streams_bidi == 0 || stream_id > this->_remote_max_streams_bidi) { - return nullptr; - } - if (this->_info->direction() == NET_VCONNECTION_OUT) { // client + if (this->_local_max_streams_bidi == 0 || stream_id > this->_local_max_streams_bidi) { + return nullptr; + } + local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); 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) { + return nullptr; + } + local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL); remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE); } break; case QUICStreamType::SERVER_UNI: - if (this->_remote_max_streams_uni == 0 || stream_id > this->_remote_max_streams_uni) { - return nullptr; + if (this->_info->direction() == NET_VCONNECTION_OUT) { + if (this->_local_max_streams_uni == 0 || stream_id > this->_local_max_streams_uni) { + return nullptr; + } + } else { + if (this->_remote_max_streams_uni == 0 || stream_id > this->_remote_max_streams_uni) { + return nullptr; + } } local_max_stream_data = this->_local_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); remote_max_stream_data = this->_remote_tp->getAsUInt(QUICTransportParameterId::INITIAL_MAX_STREAM_DATA_UNI); + break; default: ink_release_assert(false); From 396a0fced5bcb1c6d97951c91805f596032143df Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 21 May 2019 14:35:02 +0100 Subject: [PATCH 1296/1313] More fix calculation of end of buf Same issue to d99371e341b797d7166aa7e392847802d9e48c59. --- proxy/http3/QPACK.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/http3/QPACK.cc b/proxy/http3/QPACK.cc index 156a9d45792..c331dce81fe 100644 --- a/proxy/http3/QPACK.cc +++ b/proxy/http3/QPACK.cc @@ -715,7 +715,7 @@ QPACK::_decode_literal_header_field_with_name_ref(int16_t base_index, const uint Arena arena; char *value; uint64_t value_len; - if ((ret = xpack_decode_string(arena, &value, value_len, buf + read_len, buf + buf_len - read_len, 7)) < 0) { + if ((ret = xpack_decode_string(arena, &value, value_len, buf + read_len, buf + buf_len, 7)) < 0) { return -1; } read_len += ret; @@ -841,7 +841,7 @@ QPACK::_decode_literal_header_field_with_postbase_name_ref(int16_t base_index, c Arena arena; char *value; uint64_t value_len; - if ((ret = xpack_decode_string(arena, &value, value_len, buf + read_len, buf + buf_len - read_len, 7)) < 0) { + if ((ret = xpack_decode_string(arena, &value, value_len, buf + read_len, buf + buf_len, 7)) < 0) { return -1; } read_len += ret; From 1e8a3a65dfaf1cc0ca15b6bfb3203e1478ed0cdb Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 21 May 2019 15:01:39 +0100 Subject: [PATCH 1297/1313] Use preferred address once a client initiated a migration to the address --- iocore/net/QUICNetVConnection.cc | 2 ++ iocore/net/quic/QUICPacket.cc | 10 ++++++++-- iocore/net/quic/QUICPacket.h | 5 ++++- iocore/net/quic/QUICPacketFactory.cc | 6 +++--- iocore/net/quic/QUICPacketFactory.h | 4 ++-- iocore/net/quic/QUICPacketReceiveQueue.cc | 4 +++- iocore/net/quic/QUICPacketReceiveQueue.h | 1 + 7 files changed, 23 insertions(+), 9 deletions(-) diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 15752fb547e..e46686a5826 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -2248,6 +2248,7 @@ QUICNetVConnection::_state_connection_established_migrate_connection(const QUICP con.setRemote(&(p.from().sa)); this->con.move(con); this->set_remote_addr(); + this->_udp_con = p.udp_con(); this->_validate_new_path(); } } else { @@ -2261,6 +2262,7 @@ QUICNetVConnection::_state_connection_established_migrate_connection(const QUICP con.setRemote(&(p.from().sa)); this->con.move(con); this->set_remote_addr(); + this->_udp_con = p.udp_con(); this->_update_peer_cid(this->_alt_con_manager->migrate_to_alt_cid()); this->_validate_new_path(); diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc index 4280b521cb3..ec8ac37c6ba 100644 --- a/iocore/net/quic/QUICPacket.cc +++ b/iocore/net/quic/QUICPacket.cc @@ -770,8 +770,8 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const QUICPacket::QUICPacket() {} -QUICPacket::QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len) - : _header(std::move(header)), _payload(std::move(payload)), _payload_size(payload_len) +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) { } @@ -795,6 +795,12 @@ QUICPacket::from() const return this->_header->from(); } +UDPConnection * +QUICPacket::udp_con() const +{ + return this->_udp_con; +} + /** * When packet is "Short Header Packet", QUICPacket::type() will return 1-RTT Protected (key phase 0) * or 1-RTT Protected (key phase 1) diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h index 0a4a38ed878..dd9c9bcdb90 100644 --- a/iocore/net/quic/QUICPacket.h +++ b/iocore/net/quic/QUICPacket.h @@ -39,6 +39,7 @@ #define QUIC_FIELD_OFFSET_PACKET_NUMBER 4 #define QUIC_FIELD_OFFSET_PAYLOAD 5 +class UDPConnection; class QUICPacketHeader; class QUICPacket; class QUICPacketLongHeader; @@ -330,7 +331,7 @@ class QUICPacket * 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. */ - QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len); + QUICPacket(UDPConnection *udp_con, QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len); QUICPacket(QUICPacketHeaderUPtr header, ats_unique_buf payload, size_t payload_len, std::vector &frames); @@ -348,6 +349,7 @@ class QUICPacket ~QUICPacket(); + UDPConnection *udp_con() const; const IpEndpoint &from() const; QUICPacketType type() const; QUICConnectionId destination_cid() const; @@ -387,6 +389,7 @@ class QUICPacket LINK(QUICPacket, link); 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; diff --git a/iocore/net/quic/QUICPacketFactory.cc b/iocore/net/quic/QUICPacketFactory.cc index 143f69b6cc3..4c88c1b3151 100644 --- a/iocore/net/quic/QUICPacketFactory.cc +++ b/iocore/net/quic/QUICPacketFactory.cc @@ -62,8 +62,8 @@ QUICPacketFactory::create_null_packet() } QUICPacketUPtr -QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, - QUICPacketCreationResult &result) +QUICPacketFactory::create(UDPConnection *udp_con, IpEndpoint from, 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); @@ -174,7 +174,7 @@ QUICPacketFactory::create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICP QUICPacket *packet = nullptr; if (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::UNSUPPORTED) { packet = quicPacketAllocator.alloc(); - new (packet) QUICPacket(std::move(header), std::move(plain_txt), plain_txt_len); + new (packet) QUICPacket(udp_con, std::move(header), std::move(plain_txt), plain_txt_len); } return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet); diff --git a/iocore/net/quic/QUICPacketFactory.h b/iocore/net/quic/QUICPacketFactory.h index ec4b42f4934..a00639dfda4 100644 --- a/iocore/net/quic/QUICPacketFactory.h +++ b/iocore/net/quic/QUICPacketFactory.h @@ -52,8 +52,8 @@ class QUICPacketFactory QUICPacketFactory(const QUICPacketProtectionKeyInfo &pp_key_info) : _pp_key_info(pp_key_info), _pp_protector(pp_key_info) {} - QUICPacketUPtr create(IpEndpoint from, ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, - QUICPacketCreationResult &result); + QUICPacketUPtr create(UDPConnection *udp_con, IpEndpoint from, 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), diff --git a/iocore/net/quic/QUICPacketReceiveQueue.cc b/iocore/net/quic/QUICPacketReceiveQueue.cc index 255a2662dcf..405c29533de 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.cc +++ b/iocore/net/quic/QUICPacketReceiveQueue.cc @@ -89,6 +89,7 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) } // Create a QUIC packet + this->_udp_con = udp_packet->getConnection(); this->_from = udp_packet->from; this->_payload_len = udp_packet->getPktLength(); this->_payload = ats_unique_malloc(this->_payload_len); @@ -176,7 +177,8 @@ QUICPacketReceiveQueue::dequeue(QUICPacketCreationResult &result) } if (this->_ph_protector.unprotect(pkt.get(), pkt_len)) { - quic_packet = this->_packet_factory.create(this->_from, std::move(pkt), pkt_len, this->_largest_received_packet_number, result); + quic_packet = this->_packet_factory.create(this->_udp_con, this->_from, std::move(pkt), pkt_len, + this->_largest_received_packet_number, result); } else { // ZERO_RTT might be rejected if (type == QUICPacketType::ZERO_RTT_PROTECTED) { diff --git a/iocore/net/quic/QUICPacketReceiveQueue.h b/iocore/net/quic/QUICPacketReceiveQueue.h index 5eccb8a0793..5027df37b9a 100644 --- a/iocore/net/quic/QUICPacketReceiveQueue.h +++ b/iocore/net/quic/QUICPacketReceiveQueue.h @@ -49,5 +49,6 @@ class QUICPacketReceiveQueue ats_unique_buf _payload = {nullptr}; size_t _payload_len = 0; size_t _offset = 0; + UDPConnection *_udp_con; IpEndpoint _from; }; From b3701a4691524eb3e5a43f7bf57d837f789ae786 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 21 May 2019 15:13:42 +0100 Subject: [PATCH 1298/1313] Print source port number --- iocore/net/QUICPacketHandler.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc index 34e076bac76..fc906b2d366 100644 --- a/iocore/net/QUICPacketHandler.cc +++ b/iocore/net/QUICPacketHandler.cc @@ -111,8 +111,8 @@ QUICPacketHandler::_send_packet(UDPConnection *udp_con, IpEndpoint &addr, PtrgetPortNum(), buf_len); } udp_con->send(this->_get_continuation(), udp_packet); From 4dda42c62d1ab1390a4138f96e9713a84602fa2b Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Tue, 21 May 2019 16:29:32 +0100 Subject: [PATCH 1299/1313] Fix test_quic command --q-decoded-dir option --- proxy/http3/test/main_qpack.cc | 2 +- proxy/http3/test/test_QPACK.cc | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/proxy/http3/test/main_qpack.cc b/proxy/http3/test/main_qpack.cc index a53b20df860..d0626372708 100644 --- a/proxy/http3/test/main_qpack.cc +++ b/proxy/http3/test/main_qpack.cc @@ -89,7 +89,7 @@ main(int argc, char *argv[]) auto cli = session.cli() | Opt(qifdir, "qifdir")["--q-qif-dir"]("path for a directory that contains QIF files (default:qifs/qifs") | Opt(encdir, "encdir")["--q-encoded-dir"]("path for a directory that encoded files will be stored (default:qifs/encoded)") | - Opt(encdir, "decdir")["--q-decoded-dir"]("path for a directory that decoded files will be stored (default:qifs/decoded)") | + Opt(decdir, "decdir")["--q-decoded-dir"]("path for a directory that decoded files will be stored (default:qifs/decoded)") | Opt(tablesize, "size")["--q-dynamic-table-size"]("dynamic table size for encoding: 0-65535 (default:4096)") | Opt(streams, "n")["--q-max-blocked-streams"]("max blocked streams for encoding: 0-65535 (default:100)") | Opt(ackmode, "mode")["--q-ack-mode"]("acknowledgement modes for encoding: none(default:0) or immediate(1)") | diff --git a/proxy/http3/test/test_QPACK.cc b/proxy/http3/test/test_QPACK.cc index b4abdcc7824..015fd9e4a37 100644 --- a/proxy/http3/test/test_QPACK.cc +++ b/proxy/http3/test/test_QPACK.cc @@ -284,6 +284,11 @@ test_encode(const char *qif_file, const char *out_file, int dts, int mbs, int am int ret = 0; FILE *fd = fopen(out_file, "w"); + if (!fd) { + std::cerr << "couldn't open file: " << out_file << std::endl; + REQUIRE(false); + return -1; + } HTTPHdr *requests[MAX_SEQUENCE] = {nullptr}; int n_requests = load_qif_file(qif_file, requests); @@ -327,8 +332,19 @@ test_decode(const char *enc_file, const char *out_file, int dts, int mbs, int am { int ret = 0; - FILE *fd_in = fopen(enc_file, "r"); + FILE *fd_in = fopen(enc_file, "r"); + if (!fd_in) { + std::cerr << "couldn't open file: " << enc_file << std::endl; + REQUIRE(false); + return -1; + } + FILE *fd_out = fopen(out_file, "w"); + if (!fd_out) { + std::cerr << "couldn't open file: " << out_file << std::endl; + REQUIRE(false); + return -1; + } // HTTPHdr *requests[MAX_SEQUENCE]; // int n_requests = load_qif_file(qif_file, requests); @@ -389,6 +405,8 @@ TEST_CASE("Encoding", "[qpack-encode]") DIR *dir = opendir(qifdir); if (dir == nullptr) { + std::cerr << "couldn't open dir: " << qifdir << std::endl; + REQUIRE(false); return; } @@ -423,6 +441,8 @@ TEST_CASE("Decoding", "[qpack-decode]") DIR *dir = opendir(app_dir); if (dir == nullptr) { + std::cerr << "couldn't open dir: " << qifdir << std::endl; + REQUIRE(false); return; } From 0afaec6934c4b2039a32b2817acded4bc1a4875d Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 21 May 2019 17:55:05 +0100 Subject: [PATCH 1300/1313] Allow number of settings per H3 session to be configurable --- mgmt/RecordsConfig.cc | 2 ++ proxy/http3/Http3App.cc | 4 +++ proxy/http3/Http3Config.cc | 7 +++++ proxy/http3/Http3Config.h | 2 ++ proxy/http3/Http3DebugNames.cc | 8 +++--- proxy/http3/Http3Frame.cc | 22 +++++++++++++-- proxy/http3/Http3Frame.h | 5 +++- proxy/http3/Http3Types.h | 50 +++++++++++++++++----------------- proxy/http3/test/main.cc | 10 +++++++ 9 files changed, 77 insertions(+), 33 deletions(-) diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 5be7602d5e7..a1a3aa5462f 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1325,6 +1325,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.http3.num_placeholders", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} , + {RECT_CONFIG, "proxy.config.http3.max_settings", RECD_INT, "10", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} + , //############ diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index f4cd6e3a6a7..cf22b9ddff2 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -308,6 +308,10 @@ Http3SettingsHandler::handle_frame(std::shared_ptr frame) return Http3ErrorUPtr(new Http3NoError()); } + if (settings_frame->is_valid()) { + return settings_frame->get_error(); + } + // TODO: Add length check: the maximum number of values are 2^62 - 1, but some fields have shorter maximum than it. if (settings_frame->contains(Http3SettingsId::HEADER_TABLE_SIZE)) { uint64_t header_table_size = settings_frame->get(Http3SettingsId::HEADER_TABLE_SIZE); diff --git a/proxy/http3/Http3Config.cc b/proxy/http3/Http3Config.cc index 87c33f7b426..a152af5aa87 100644 --- a/proxy/http3/Http3Config.cc +++ b/proxy/http3/Http3Config.cc @@ -35,6 +35,7 @@ Http3ConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_max_header_list_size, "proxy.config.http3.max_header_list_size"); REC_EstablishStaticConfigInt32U(this->_qpack_blocked_streams, "proxy.config.http3.qpack_blocked_streams"); REC_EstablishStaticConfigInt32U(this->_num_placeholders, "proxy.config.http3.num_placeholders"); + REC_EstablishStaticConfigInt32U(this->_max_settings, "proxy.config.http3.max_settings"); } uint32_t @@ -61,6 +62,12 @@ Http3ConfigParams::num_placeholders() const return this->_num_placeholders; } +uint32_t +Http3ConfigParams::max_settings() const +{ + return this->_max_settings; +} + // // Http3Config // diff --git a/proxy/http3/Http3Config.h b/proxy/http3/Http3Config.h index 9694765549c..27ae9a274b7 100644 --- a/proxy/http3/Http3Config.h +++ b/proxy/http3/Http3Config.h @@ -37,12 +37,14 @@ class Http3ConfigParams : public ConfigInfo uint32_t max_header_list_size() const; uint32_t qpack_blocked_streams() const; uint32_t num_placeholders() const; + uint32_t max_settings() const; private: uint32_t _header_table_size = 0; uint32_t _max_header_list_size = 0; uint32_t _qpack_blocked_streams = 0; uint32_t _num_placeholders = 0; + uint32_t _max_settings = 10; }; class Http3Config diff --git a/proxy/http3/Http3DebugNames.cc b/proxy/http3/Http3DebugNames.cc index e1a78414671..2d1e87a605a 100644 --- a/proxy/http3/Http3DebugNames.cc +++ b/proxy/http3/Http3DebugNames.cc @@ -116,8 +116,8 @@ Http3DebugNames::error_code(uint16_t code) return "VERSION_FALLBACK"; case static_cast(Http3ErrorCode::WRONG_STREAM): return "WRONG_STREAM"; - case static_cast(Http3ErrorCode::PUSH_LIMIT_EXCEEDED): - return "PUSH_LIMIT_EXCEEDED"; + case static_cast(Http3ErrorCode::LIMIT_EXCEEDED): + return "LIMIT_EXCEEDED"; case static_cast(Http3ErrorCode::DUPLICATE_PUSH): return "DUPLICATE_PUSH"; case static_cast(Http3ErrorCode::UNKNOWN_STREAM_TYPE): @@ -134,14 +134,14 @@ Http3DebugNames::error_code(uint16_t code) return "MISSING_SETTINGS"; case static_cast(Http3ErrorCode::UNEXPECTED_FRAME): return "UNEXPECTED_FRAME"; + case static_cast(Http3ErrorCode::REQUEST_REJECTED): + return "REQUEST_REJECTED"; case static_cast(Http3ErrorCode::QPACK_DECOMPRESSION_FAILED): return "QPACK_DECOMPRESSION_FAILED"; case static_cast(Http3ErrorCode::QPACK_ENCODER_STREAM_ERROR): return "QPACK_ENCODER_STREAM_ERROR"; case static_cast(Http3ErrorCode::QPACK_DECODER_STREAM_ERROR): return "QPACK_DECODER_STREAM_ERROR"; - case static_cast(Http3ErrorCode::GENERAL_PROTOCOL_ERROR): - return "GENERAL_PROTOCOL_ERROR"; default: if (0x0100 <= code && code <= 0x01FF) { return "MALFORMED_FRAME"; diff --git a/proxy/http3/Http3Frame.cc b/proxy/http3/Http3Frame.cc index ac47752a423..b9102dc3afd 100644 --- a/proxy/http3/Http3Frame.cc +++ b/proxy/http3/Http3Frame.cc @@ -24,6 +24,7 @@ #include "tscore/Diags.h" #include "quic/QUICIntUtil.h" #include "Http3Frame.h" +#include "Http3Config.h" ClassAllocator http3FrameAllocator("http3FrameAllocator"); ClassAllocator http3DataFrameAllocator("http3DataFrameAllocator"); @@ -227,11 +228,18 @@ Http3HeadersFrame::header_block_length() const // SETTINGS Frame // -Http3SettingsFrame::Http3SettingsFrame(const uint8_t *buf, size_t buf_len) : Http3Frame(buf, buf_len) +Http3SettingsFrame::Http3SettingsFrame(const uint8_t *buf, size_t buf_len, uint32_t max_settings) : Http3Frame(buf, buf_len) { - size_t len = this->_payload_offset; + size_t len = this->_payload_offset; + uint32_t nsettings = 0; while (len < buf_len) { + if (nsettings >= max_settings) { + this->_error_code = Http3ErrorCode::EXCESSIVE_LOAD; + this->_error_reason = reinterpret_cast("too many settings"); + break; + } + size_t id_len = QUICVariableInt::size(buf + len); uint16_t id = QUICIntUtil::read_QUICVariableInt(buf + len); len += id_len; @@ -254,6 +262,7 @@ Http3SettingsFrame::Http3SettingsFrame(const uint8_t *buf, size_t buf_len) : Htt } this->_settings.insert(std::make_pair(static_cast(id), value)); + ++nsettings; } if (len == buf_len) { @@ -310,6 +319,12 @@ Http3SettingsFrame::is_valid() const return this->_valid; } +Http3ErrorUPtr +Http3SettingsFrame::get_error() const +{ + return std::make_unique(this->_error_code, this->_error_reason); +} + bool Http3SettingsFrame::contains(Http3SettingsId id) const { @@ -346,6 +361,7 @@ Http3FrameFactory::create_null_frame() Http3FrameUPtr Http3FrameFactory::create(const uint8_t *buf, size_t len) { + Http3Config::scoped_config params; Http3Frame *frame = nullptr; Http3FrameType type = Http3Frame::type(buf, len); @@ -360,7 +376,7 @@ Http3FrameFactory::create(const uint8_t *buf, size_t len) return Http3FrameUPtr(frame, &Http3FrameDeleter::delete_data_frame); case Http3FrameType::SETTINGS: frame = http3SettingsFrameAllocator.alloc(); - new (frame) Http3SettingsFrame(buf, len); + new (frame) Http3SettingsFrame(buf, len, params->max_settings()); return Http3FrameUPtr(frame, &Http3FrameDeleter::delete_settings_frame); default: // Unknown frame diff --git a/proxy/http3/Http3Frame.h b/proxy/http3/Http3Frame.h index adc2fae7a3a..4ae00a9d33a 100644 --- a/proxy/http3/Http3Frame.h +++ b/proxy/http3/Http3Frame.h @@ -120,7 +120,7 @@ class Http3SettingsFrame : public Http3Frame { public: Http3SettingsFrame() : Http3Frame(Http3FrameType::SETTINGS) {} - Http3SettingsFrame(const uint8_t *buf, size_t len); + Http3SettingsFrame(const uint8_t *buf, size_t len, uint32_t max_settings = 0); static constexpr size_t MAX_PAYLOAD_SIZE = 60; static constexpr std::array VALID_SETTINGS_IDS{ @@ -134,6 +134,7 @@ class Http3SettingsFrame : public Http3Frame void reset(const uint8_t *buf, size_t len) override; bool is_valid() const; + Http3ErrorUPtr get_error() const; bool contains(Http3SettingsId id) const; uint64_t get(Http3SettingsId id) const; @@ -143,6 +144,8 @@ class Http3SettingsFrame : public Http3Frame std::map _settings; // TODO: make connection error with HTTP_MALFORMED_FRAME bool _valid = false; + Http3ErrorCode _error_code; + const char *_error_reason = nullptr; }; using Http3FrameDeleterFunc = void (*)(Http3Frame *p); diff --git a/proxy/http3/Http3Types.h b/proxy/http3/Http3Types.h index 54c619687da..c6bba88483f 100644 --- a/proxy/http3/Http3Types.h +++ b/proxy/http3/Http3Types.h @@ -73,31 +73,31 @@ enum class Http3ErrorClass { // Actual error code of QPACK is not decided yet on qpack-05. It will be changed. enum class Http3ErrorCode : uint16_t { - NO_ERROR = 0x00, - WRONG_SETTING_DIRECTION = 0x01, - PUSH_REFUSED = 0x02, - INTERNAL_ERROR = 0x03, - PUSH_ALREADY_IN_CACHE = 0x04, - REQUEST_CANCELLED = 0x05, - INCOMPLETE_REQUEST = 0x06, - CONNECT_ERROR = 0x07, - EXCESSIVE_LOAD = 0x08, - VERSION_FALLBACK = 0x09, - WRONG_STREAM = 0x0A, - PUSH_LIMIT_EXCEEDED = 0x0B, - DUPLICATE_PUSH = 0x0C, - UNKNOWN_STREAM_TYPE = 0x0D, - WRONG_STREAM_COUNT = 0x0E, - CLOSED_CRITICAL_STREAM = 0x0F, - WRONG_STREAM_DIRECTION = 0x10, - EARLY_RESPONSE = 0x11, - MISSING_SETTINGS = 0x12, - UNEXPECTED_FRAME = 0x13, - QPACK_DECOMPRESSION_FAILED, ///< QPACK Error Code - QPACK_ENCODER_STREAM_ERROR, ///< QPACK Error Code - QPACK_DECODER_STREAM_ERROR, ///< QPACK Error Code - GENERAL_PROTOCOL_ERROR = 0xFF, - MALFORMED_FRAME = 0x0100, + NO_ERROR = 0x0000, + WRONG_SETTING_DIRECTION = 0x0001, + PUSH_REFUSED = 0x0002, + INTERNAL_ERROR = 0x0003, + PUSH_ALREADY_IN_CACHE = 0x0004, + REQUEST_CANCELLED = 0x0005, + INCOMPLETE_REQUEST = 0x0006, + CONNECT_ERROR = 0x0007, + EXCESSIVE_LOAD = 0x0008, + VERSION_FALLBACK = 0x0009, + WRONG_STREAM = 0x000A, + LIMIT_EXCEEDED = 0x000B, + DUPLICATE_PUSH = 0x000C, + UNKNOWN_STREAM_TYPE = 0x000D, + WRONG_STREAM_COUNT = 0x000E, + CLOSED_CRITICAL_STREAM = 0x000F, + WRONG_STREAM_DIRECTION = 0x0010, + EARLY_RESPONSE = 0x0011, + MISSING_SETTINGS = 0x0012, + UNEXPECTED_FRAME = 0x0013, + REQUEST_REJECTED = 0x0014, + MALFORMED_FRAME = 0x0100, + QPACK_DECOMPRESSION_FAILED = 0x200, + QPACK_ENCODER_STREAM_ERROR = 0x201, + QPACK_DECODER_STREAM_ERROR = 0x202, }; class Http3Error diff --git a/proxy/http3/test/main.cc b/proxy/http3/test/main.cc index 8da7c687bf9..002e9d6dd8b 100644 --- a/proxy/http3/test/main.cc +++ b/proxy/http3/test/main.cc @@ -26,8 +26,12 @@ #define CATCH_CONFIG_MAIN #include "catch.hpp" +#include "tscore/I_Layout.h" #include "tscore/Diags.h" +#include "RecordsConfig.h" +#include "Http3Config.h" + struct EventProcessorListener : Catch::TestEventListenerBase { using TestEventListenerBase::TestEventListenerBase; // inherit constructor @@ -39,6 +43,12 @@ struct EventProcessorListener : Catch::TestEventListenerBase { diags->activate_taglist("vv_quic|quic", DiagsTagType_Debug); diags->config.enabled[DiagsTagType_Debug] = true; diags->show_location = SHOW_LOCATION_DEBUG; + + Layout::create(); + RecProcessInit(RECM_STAND_ALONE); + LibRecordsConfigInit(); + + Http3Config::startup(); } }; CATCH_REGISTER_LISTENER(EventProcessorListener); From d23fe12e3d327f1761f065bf97e643f4e39cb9c8 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 31 May 2019 09:25:07 +0900 Subject: [PATCH 1301/1313] Follow proxy ssn/txn cleanups on master --- proxy/http3/Http09App.cc | 23 +++++++++++++------ proxy/http3/Http09App.h | 6 +++-- proxy/http3/Http3App.cc | 12 +++++++++- proxy/http3/Http3App.h | 4 +++- proxy/http3/Http3ClientSession.cc | 2 +- proxy/http3/Http3ClientSession.h | 14 ++++++------ proxy/http3/Http3ClientTransaction.cc | 32 +++++++++++++-------------- proxy/http3/Http3ClientTransaction.h | 6 ++--- proxy/http3/Http3SessionAccept.cc | 4 ++-- proxy/http3/test/stub.cc | 2 +- src/traffic_quic/quic_client.cc | 7 +++--- src/traffic_quic/quic_client.h | 4 +++- src/traffic_quic/traffic_quic.cc | 2 +- 13 files changed, 72 insertions(+), 46 deletions(-) diff --git a/proxy/http3/Http09App.cc b/proxy/http3/Http09App.cc index 0d70afd3b80..01c7a4c5119 100644 --- a/proxy/http3/Http09App.cc +++ b/proxy/http3/Http09App.cc @@ -23,6 +23,8 @@ #include "Http09App.h" +#include "tscore/ink_resolver.h" + #include "P_Net.h" #include "P_VConnection.h" #include "QUICDebugNames.h" @@ -33,11 +35,18 @@ static constexpr char debug_tag[] = "quic_simple_app"; static constexpr char debug_tag_v[] = "v_quic_simple_app"; -Http09App::Http09App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl) : QUICApplication(client_vc) +Http09App::Http09App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options) + : QUICApplication(client_vc) { - this->_client_session = new Http09ClientSession(client_vc); - this->_client_session->acl = std::move(session_acl); - this->_client_session->new_connection(client_vc, nullptr, nullptr); + this->_ssn = new Http09ClientSession(client_vc); + this->_ssn->acl = std::move(session_acl); + // TODO: avoid const cast + this->_ssn->host_res_style = + ats_host_res_from(client_vc->get_remote_addr()->sa_family, const_cast(options.host_res_preference)); + this->_ssn->outbound_ip4 = options.outbound_ip4; + this->_ssn->outbound_ip6 = options.outbound_ip6; + this->_ssn->outbound_port = options.outbound_port; + this->_ssn->new_connection(client_vc, nullptr, nullptr); this->_qc->stream_manager()->set_default_application(this); @@ -46,7 +55,7 @@ Http09App::Http09App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl) Http09App::~Http09App() { - delete this->_client_session; + delete this->_ssn; } int @@ -63,7 +72,7 @@ Http09App::main_event_handler(int event, Event *data) } QUICStreamId stream_id = stream_io->stream_id(); - Http09ClientTransaction *txn = static_cast(this->_client_session->get_transaction(stream_id)); + Http09ClientTransaction *txn = static_cast(this->_ssn->get_transaction(stream_id)); uint8_t dummy; switch (event) { @@ -75,7 +84,7 @@ Http09App::main_event_handler(int event, Event *data) } if (stream_io->peek(&dummy, 1)) { if (txn == nullptr) { - txn = new Http09ClientTransaction(this->_client_session, stream_io); + txn = new Http09ClientTransaction(this->_ssn, stream_io); SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); txn->new_transaction(); diff --git a/proxy/http3/Http09App.h b/proxy/http3/Http09App.h index 85f9afd923e..5943d6b3bb1 100644 --- a/proxy/http3/Http09App.h +++ b/proxy/http3/Http09App.h @@ -25,6 +25,8 @@ #include "IPAllow.h" +#include "HttpSessionAccept.h" + #include "QUICApplication.h" class QUICNetVConnection; @@ -39,11 +41,11 @@ class Http09ClientSession; class Http09App : public QUICApplication { public: - Http09App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl); + Http09App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options); ~Http09App(); int main_event_handler(int event, Event *data); private: - Http09ClientSession *_client_session = nullptr; + Http09ClientSession *_ssn = nullptr; }; diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index cf22b9ddff2..5e973d21928 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -23,6 +23,8 @@ #include "Http3App.h" +#include "tscore/ink_resolver.h" + #include "P_Net.h" #include "P_VConnection.h" @@ -35,10 +37,18 @@ static constexpr char debug_tag[] = "http3"; static constexpr char debug_tag_v[] = "v_http3"; -Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl) : QUICApplication(client_vc) +Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options) + : QUICApplication(client_vc) { this->_ssn = new Http3ClientSession(client_vc); this->_ssn->acl = std::move(session_acl); + // TODO: avoid const cast + this->_ssn->host_res_style = + ats_host_res_from(client_vc->get_remote_addr()->sa_family, const_cast(options.host_res_preference)); + this->_ssn->outbound_ip4 = options.outbound_ip4; + this->_ssn->outbound_ip6 = options.outbound_ip6; + this->_ssn->outbound_port = options.outbound_port; + this->_ssn->new_connection(client_vc, nullptr, nullptr); this->_qc->stream_manager()->set_default_application(this); diff --git a/proxy/http3/Http3App.h b/proxy/http3/Http3App.h index 4deff20fe72..f7f77949e36 100644 --- a/proxy/http3/Http3App.h +++ b/proxy/http3/Http3App.h @@ -27,6 +27,8 @@ #include "QUICApplication.h" +#include "HttpSessionAccept.h" + #include "Http3Types.h" #include "Http3FrameDispatcher.h" #include "Http3FrameCollector.h" @@ -43,7 +45,7 @@ class Http3ClientSession; class Http3App : public QUICApplication { public: - Http3App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl); + Http3App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options); virtual ~Http3App(); virtual void start(); diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3ClientSession.cc index d1d4e2afbd0..f711b408d8d 100644 --- a/proxy/http3/Http3ClientSession.cc +++ b/proxy/http3/Http3ClientSession.cc @@ -113,7 +113,7 @@ HQClientSession::destroy() } void -HQClientSession::release(ProxyClientTransaction *trans) +HQClientSession::release(ProxyTransaction *trans) { return; } diff --git a/proxy/http3/Http3ClientSession.h b/proxy/http3/Http3ClientSession.h index 190726a6afa..960b2aaa795 100644 --- a/proxy/http3/Http3ClientSession.h +++ b/proxy/http3/Http3ClientSession.h @@ -23,14 +23,14 @@ #pragma once -#include "ProxyClientSession.h" +#include "ProxySession.h" #include "Http3ClientTransaction.h" #include "QPACK.h" -class HQClientSession : public ProxyClientSession +class HQClientSession : public ProxySession { public: - using super = ProxyClientSession; ///< Parent type + using super = ProxySession; ///< Parent type HQClientSession(NetVConnection *vc) : _client_vc(vc){}; virtual ~HQClientSession(); @@ -42,11 +42,11 @@ class HQClientSession : public ProxyClientSession void do_io_shutdown(ShutdownHowTo_t howto) override; void reenable(VIO *vio) override; - // Implement ProxyClienSession interface + // Implement ProxySession interface void new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader) override; void start() override; void destroy() override; - void release(ProxyClientTransaction *trans) override; + void release(ProxyTransaction *trans) override; NetVConnection *get_netvc() const override; int get_transact_count() const override; @@ -70,7 +70,7 @@ class Http3ClientSession : public HQClientSession Http3ClientSession(NetVConnection *vc); ~Http3ClientSession(); - // ProxyClienSession interface + // ProxySession interface const char *get_protocol_string() const override; int populate_protocol(std::string_view *result, int size) const override; void increment_current_active_client_connections_stat() override; @@ -95,7 +95,7 @@ class Http09ClientSession : public HQClientSession Http09ClientSession(NetVConnection *vc) : HQClientSession(vc) {} ~Http09ClientSession(); - // ProxyClienSession interface + // ProxySession interface const char *get_protocol_string() const override; int populate_protocol(std::string_view *result, int size) const override; void increment_current_active_client_connections_stat() override; diff --git a/proxy/http3/Http3ClientTransaction.cc b/proxy/http3/Http3ClientTransaction.cc index ccbb4d263a3..abfe2235112 100644 --- a/proxy/http3/Http3ClientTransaction.cc +++ b/proxy/http3/Http3ClientTransaction.cc @@ -33,14 +33,14 @@ #include "HttpSM.h" #include "HTTP2.h" -#define Http3TransDebug(fmt, ...) \ - Debug("http3_trans", "[%s] [%" PRIx32 "] " fmt, \ - static_cast(reinterpret_cast(this->parent->get_netvc()))->cids().data(), \ +#define Http3TransDebug(fmt, ...) \ + Debug("http3_trans", "[%s] [%" PRIx32 "] " fmt, \ + static_cast(reinterpret_cast(this->proxy_ssn->get_netvc()))->cids().data(), \ this->get_transaction_id(), ##__VA_ARGS__) -#define Http3TransVDebug(fmt, ...) \ - Debug("v_http3_trans", "[%s] [%" PRIx32 "] " fmt, \ - static_cast(reinterpret_cast(this->parent->get_netvc()))->cids().data(), \ +#define Http3TransVDebug(fmt, ...) \ + Debug("v_http3_trans", "[%s] [%" PRIx32 "] " fmt, \ + static_cast(reinterpret_cast(this->proxy_ssn->get_netvc()))->cids().data(), \ this->get_transaction_id(), ##__VA_ARGS__) // static void @@ -83,24 +83,24 @@ HQClientTransaction::~HQClientTransaction() void HQClientTransaction::set_active_timeout(ink_hrtime timeout_in) { - if (parent) { - parent->set_active_timeout(timeout_in); + if (this->proxy_ssn) { + this->proxy_ssn->set_active_timeout(timeout_in); } } void HQClientTransaction::set_inactivity_timeout(ink_hrtime timeout_in) { - if (parent) { - parent->set_inactivity_timeout(timeout_in); + if (this->proxy_ssn) { + this->proxy_ssn->set_inactivity_timeout(timeout_in); } } void HQClientTransaction::cancel_inactivity_timeout() { - if (parent) { - parent->cancel_inactivity_timeout(); + if (this->proxy_ssn) { + this->proxy_ssn->cancel_inactivity_timeout(); } } @@ -185,7 +185,7 @@ HQClientTransaction::do_io_close(int lerrno) this->_write_vio.op = VIO::NONE; this->_write_vio.cont = nullptr; - parent->do_io_close(lerrno); + this->proxy_ssn->do_io_close(lerrno); } void @@ -248,7 +248,7 @@ HQClientTransaction::decrement_client_transactions_stat() NetVConnectionContext_t HQClientTransaction::direction() const { - return this->parent->get_netvc()->get_context(); + return this->proxy_ssn->get_netvc()->get_context(); } /** @@ -318,7 +318,7 @@ HQClientTransaction::_signal_write_event() // Http3ClientTransaction::Http3ClientTransaction(Http3ClientSession *session, QUICStreamIO *stream_io) : super(session, stream_io) { - static_cast(this->parent)->add_transaction(static_cast(this)); + static_cast(this->proxy_ssn)->add_transaction(static_cast(this)); this->_header_framer = new Http3HeaderFramer(this, &this->_write_vio, session->local_qpack(), stream_io->stream_id()); this->_data_framer = new Http3DataFramer(this, &this->_write_vio); @@ -597,7 +597,7 @@ Http3ClientTransaction::_on_qpack_decode_complete() // Http09ClientTransaction::Http09ClientTransaction(Http09ClientSession *session, QUICStreamIO *stream_io) : super(session, stream_io) { - static_cast(this->parent)->add_transaction(static_cast(this)); + static_cast(this->proxy_ssn)->add_transaction(static_cast(this)); SET_HANDLER(&Http09ClientTransaction::state_stream_open); } diff --git a/proxy/http3/Http3ClientTransaction.h b/proxy/http3/Http3ClientTransaction.h index a6fe36b9cff..6be2f781187 100644 --- a/proxy/http3/Http3ClientTransaction.h +++ b/proxy/http3/Http3ClientTransaction.h @@ -24,7 +24,7 @@ #pragma once #include "I_VConnection.h" -#include "ProxyClientTransaction.h" +#include "ProxyTransaction.h" #include "Http3FrameDispatcher.h" #include "Http3FrameCollector.h" @@ -35,10 +35,10 @@ class Http3ClientSession; class Http3HeaderFramer; class Http3DataFramer; -class HQClientTransaction : public ProxyClientTransaction +class HQClientTransaction : public ProxyTransaction { public: - using super = ProxyClientTransaction; + using super = ProxyTransaction; HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io); virtual ~HQClientTransaction(); diff --git a/proxy/http3/Http3SessionAccept.cc b/proxy/http3/Http3SessionAccept.cc index 6a12f3a667b..9763f95c067 100644 --- a/proxy/http3/Http3SessionAccept.cc +++ b/proxy/http3/Http3SessionAccept.cc @@ -68,11 +68,11 @@ Http3SessionAccept::accept(NetVConnection *netvc, MIOBuffer *iobuf, IOBufferRead Debug("http3", "[%s] start HTTP/0.9 app (ALPN=%s)", qvc->cids().data(), IP_PROTO_TAG_HTTP_QUIC.data()); } - new Http09App(qvc, std::move(session_acl)); + new Http09App(qvc, std::move(session_acl), this->options); } else if (IP_PROTO_TAG_HTTP_3.compare(alpn) == 0) { Debug("http3", "[%s] start HTTP/3 app (ALPN=%s)", qvc->cids().data(), IP_PROTO_TAG_HTTP_3.data()); - Http3App *app = new Http3App(qvc, std::move(session_acl)); + Http3App *app = new Http3App(qvc, std::move(session_acl), this->options); app->start(); } else { ink_abort("Negotiated App Name is unknown"); diff --git a/proxy/http3/test/stub.cc b/proxy/http3/test/stub.cc index cfbf5fba875..a4fc9c0d114 100644 --- a/proxy/http3/test/stub.cc +++ b/proxy/http3/test/stub.cc @@ -85,7 +85,7 @@ HttpSM::kill_this_async_hook(int /* event ATS_UNUSED */, void * /* data ATS_UNUS } void -HttpSM::attach_client_session(ProxyClientTransaction *, IOBufferReader *) +HttpSM::attach_client_session(ProxyTransaction *, IOBufferReader *) { ink_abort("do not call stub"); } diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc index 92ba7974d36..35849589ce3 100644 --- a/src/traffic_quic/quic_client.cc +++ b/src/traffic_quic/quic_client.cc @@ -110,7 +110,7 @@ QUICClient::state_http_server_open(int event, void *data) } else if (this->_config->http3) { // TODO: see what server session is doing with IpAllow::ACL IpAllow::ACL session_acl; - Http3ClientApp *app = new Http3ClientApp(conn, std::move(session_acl), this->_config); + Http3ClientApp *app = new Http3ClientApp(conn, std::move(session_acl), options, this->_config); SCOPED_MUTEX_LOCK(lock, app->mutex, this_ethread()); app->start(); } else { @@ -249,8 +249,9 @@ Http09ClientApp::main_event_handler(int event, Event *data) // // Http3ClientApp // -Http3ClientApp::Http3ClientApp(QUICNetVConnection *qvc, IpAllow::ACL &&session_acl, const QUICClientConfig *config) - : super(qvc, std::move(session_acl)), _config(config) +Http3ClientApp::Http3ClientApp(QUICNetVConnection *qvc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options, + const QUICClientConfig *config) + : super(qvc, std::move(session_acl), options), _config(config) { } diff --git a/src/traffic_quic/quic_client.h b/src/traffic_quic/quic_client.h index 0097ff078e9..9af9f0d3593 100644 --- a/src/traffic_quic/quic_client.h +++ b/src/traffic_quic/quic_client.h @@ -70,6 +70,7 @@ class QUICClient : public Continuation private: const QUICClientConfig *_config = nullptr; struct addrinfo *_remote_addr_info = nullptr; + HttpSessionAccept::Options options; }; class Http09ClientApp : public QUICApplication @@ -92,7 +93,8 @@ class Http3ClientApp : public Http3App public: using super = Http3App; - Http3ClientApp(QUICNetVConnection *qvc, IpAllow::ACL &&session_acl, const QUICClientConfig *config); + Http3ClientApp(QUICNetVConnection *qvc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options, + const QUICClientConfig *config); ~Http3ClientApp(); void start() override; diff --git a/src/traffic_quic/traffic_quic.cc b/src/traffic_quic/traffic_quic.cc index 9ac59b5c64d..a03c29a90a5 100644 --- a/src/traffic_quic/traffic_quic.cc +++ b/src/traffic_quic/traffic_quic.cc @@ -300,7 +300,7 @@ HttpSM::kill_this_async_hook(int /* event ATS_UNUSED */, void * /* data ATS_UNUS } void -HttpSM::attach_client_session(ProxyClientTransaction *, IOBufferReader *) +HttpSM::attach_client_session(ProxyTransaction *, IOBufferReader *) { ink_abort("do not call stub"); } From 7d8d7df3b286ea3dcbfec86d0d6baa83729dd00c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 31 May 2019 15:03:23 +0900 Subject: [PATCH 1302/1313] Rename Http3ClientTransaction to Http3Transaction --- proxy/http3/Http09App.cc | 8 +- proxy/http3/Http3App.cc | 12 +-- proxy/http3/Http3ClientSession.cc | 8 +- proxy/http3/Http3ClientSession.h | 8 +- proxy/http3/Http3DataFramer.cc | 6 +- proxy/http3/Http3DataFramer.h | 8 +- proxy/http3/Http3HeaderFramer.cc | 4 +- proxy/http3/Http3HeaderFramer.h | 6 +- ...ientTransaction.cc => Http3Transaction.cc} | 98 +++++++++---------- ...ClientTransaction.h => Http3Transaction.h} | 24 ++--- proxy/http3/Makefile.am | 2 +- src/traffic_quic/quic_client.cc | 4 +- 12 files changed, 93 insertions(+), 95 deletions(-) rename proxy/http3/{Http3ClientTransaction.cc => Http3Transaction.cc} (87%) rename proxy/http3/{Http3ClientTransaction.h => Http3Transaction.h} (87%) diff --git a/proxy/http3/Http09App.cc b/proxy/http3/Http09App.cc index 01c7a4c5119..0b7d9756df3 100644 --- a/proxy/http3/Http09App.cc +++ b/proxy/http3/Http09App.cc @@ -30,7 +30,7 @@ #include "QUICDebugNames.h" #include "Http3ClientSession.h" -#include "Http3ClientTransaction.h" +#include "Http3Transaction.h" static constexpr char debug_tag[] = "quic_simple_app"; static constexpr char debug_tag_v[] = "v_quic_simple_app"; @@ -71,8 +71,8 @@ Http09App::main_event_handler(int event, Event *data) return -1; } - QUICStreamId stream_id = stream_io->stream_id(); - Http09ClientTransaction *txn = static_cast(this->_ssn->get_transaction(stream_id)); + QUICStreamId stream_id = stream_io->stream_id(); + Http09Transaction *txn = static_cast(this->_ssn->get_transaction(stream_id)); uint8_t dummy; switch (event) { @@ -84,7 +84,7 @@ Http09App::main_event_handler(int event, Event *data) } if (stream_io->peek(&dummy, 1)) { if (txn == nullptr) { - txn = new Http09ClientTransaction(this->_ssn, stream_io); + txn = new Http09Transaction(this->_ssn, stream_io); SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); txn->new_transaction(); diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 5e973d21928..45443b3f9c4 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -32,7 +32,7 @@ #include "Http3Config.h" #include "Http3DebugNames.h" #include "Http3ClientSession.h" -#include "Http3ClientTransaction.h" +#include "Http3Transaction.h" static constexpr char debug_tag[] = "http3"; static constexpr char debug_tag_v[] = "v_http3"; @@ -212,11 +212,11 @@ Http3App::_handle_bidi_stream_on_read_ready(int event, QUICStreamIO *stream_io) { uint8_t dummy; if (stream_io->peek(&dummy, 1)) { - QUICStreamId stream_id = stream_io->stream_id(); - Http3ClientTransaction *txn = static_cast(this->_ssn->get_transaction(stream_id)); + QUICStreamId stream_id = stream_io->stream_id(); + Http3Transaction *txn = static_cast(this->_ssn->get_transaction(stream_id)); if (txn == nullptr) { - txn = new Http3ClientTransaction(this->_ssn, stream_io); + txn = new Http3Transaction(this->_ssn, stream_io); SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); txn->new_transaction(); @@ -289,8 +289,8 @@ Http3App::_set_qpack_stream(Http3StreamType type, QUICStreamIO *stream_io) void Http3App::_handle_bidi_stream_on_write_ready(int event, QUICStreamIO *stream_io) { - QUICStreamId stream_id = stream_io->stream_id(); - Http3ClientTransaction *txn = static_cast(this->_ssn->get_transaction(stream_id)); + QUICStreamId stream_id = stream_io->stream_id(); + Http3Transaction *txn = static_cast(this->_ssn->get_transaction(stream_id)); if (txn != nullptr) { SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); txn->handleEvent(event); diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3ClientSession.cc index f711b408d8d..22d820ea369 100644 --- a/proxy/http3/Http3ClientSession.cc +++ b/proxy/http3/Http3ClientSession.cc @@ -30,23 +30,23 @@ // HQClientSession ::~HQClientSession() { - for (HQClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { + for (HQTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { delete t; } } void -HQClientSession::add_transaction(HQClientTransaction *trans) +HQClientSession::add_transaction(HQTransaction *trans) { this->_transaction_list.enqueue(trans); return; } -HQClientTransaction * +HQTransaction * HQClientSession::get_transaction(QUICStreamId id) { - for (HQClientTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { + for (HQTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { if (t->get_transaction_id() == static_cast(id)) { return t; } diff --git a/proxy/http3/Http3ClientSession.h b/proxy/http3/Http3ClientSession.h index 960b2aaa795..ffc928924b9 100644 --- a/proxy/http3/Http3ClientSession.h +++ b/proxy/http3/Http3ClientSession.h @@ -24,7 +24,7 @@ #pragma once #include "ProxySession.h" -#include "Http3ClientTransaction.h" +#include "Http3Transaction.h" #include "QPACK.h" class HQClientSession : public ProxySession @@ -51,15 +51,15 @@ class HQClientSession : public ProxySession int get_transact_count() const override; // HQClientSession - void add_transaction(HQClientTransaction *); - HQClientTransaction *get_transaction(QUICStreamId); + void add_transaction(HQTransaction *); + HQTransaction *get_transaction(QUICStreamId); protected: NetVConnection *_client_vc = nullptr; private: // this should be unordered map? - Queue _transaction_list; + Queue _transaction_list; }; class Http3ClientSession : public HQClientSession diff --git a/proxy/http3/Http3DataFramer.cc b/proxy/http3/Http3DataFramer.cc index af547733881..eaf58627573 100644 --- a/proxy/http3/Http3DataFramer.cc +++ b/proxy/http3/Http3DataFramer.cc @@ -23,11 +23,9 @@ #include "Http3Frame.h" #include "Http3DataFramer.h" -#include "Http3ClientTransaction.h" +#include "Http3Transaction.h" -Http3DataFramer::Http3DataFramer(Http3ClientTransaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) -{ -} +Http3DataFramer::Http3DataFramer(Http3Transaction *transaction, VIO *source) : _transaction(transaction), _source_vio(source) {} Http3FrameUPtr Http3DataFramer::generate_frame(uint16_t max_size) diff --git a/proxy/http3/Http3DataFramer.h b/proxy/http3/Http3DataFramer.h index ded46293d02..045e86c6b47 100644 --- a/proxy/http3/Http3DataFramer.h +++ b/proxy/http3/Http3DataFramer.h @@ -26,19 +26,19 @@ #include "Http3FrameGenerator.h" #include "Http3Frame.h" -class Http3ClientTransaction; +class Http3Transaction; class VIO; class Http3DataFramer : public Http3FrameGenerator { public: - Http3DataFramer(Http3ClientTransaction *transaction, VIO *source); + Http3DataFramer(Http3Transaction *transaction, VIO *source); // Http3FrameGenerator Http3FrameUPtr generate_frame(uint16_t max_size) override; bool is_done() const override; private: - Http3ClientTransaction *_transaction = nullptr; - VIO *_source_vio = nullptr; + Http3Transaction *_transaction = nullptr; + VIO *_source_vio = nullptr; }; diff --git a/proxy/http3/Http3HeaderFramer.cc b/proxy/http3/Http3HeaderFramer.cc index 1d493f5848a..0931acc36eb 100644 --- a/proxy/http3/Http3HeaderFramer.cc +++ b/proxy/http3/Http3HeaderFramer.cc @@ -29,9 +29,9 @@ #include "HTTP2.h" #include "Http3Frame.h" -#include "Http3ClientTransaction.h" +#include "Http3Transaction.h" -Http3HeaderFramer::Http3HeaderFramer(Http3ClientTransaction *transaction, VIO *source, QPACK *qpack, uint64_t stream_id) +Http3HeaderFramer::Http3HeaderFramer(Http3Transaction *transaction, VIO *source, QPACK *qpack, uint64_t stream_id) : _transaction(transaction), _source_vio(source), _qpack(qpack), _stream_id(stream_id) { http_parser_init(&this->_http_parser); diff --git a/proxy/http3/Http3HeaderFramer.h b/proxy/http3/Http3HeaderFramer.h index 165d178518c..55ce58627a7 100644 --- a/proxy/http3/Http3HeaderFramer.h +++ b/proxy/http3/Http3HeaderFramer.h @@ -30,20 +30,20 @@ #include "Http3FrameGenerator.h" #include "Http3Frame.h" -class Http3ClientTransaction; +class Http3Transaction; class VIO; class Http3HeaderFramer : public Http3FrameGenerator { public: - Http3HeaderFramer(Http3ClientTransaction *transaction, VIO *source, QPACK *qpack, uint64_t stream_id); + Http3HeaderFramer(Http3Transaction *transaction, VIO *source, QPACK *qpack, uint64_t stream_id); // Http3FrameGenerator Http3FrameUPtr generate_frame(uint16_t max_size) override; bool is_done() const override; private: - Http3ClientTransaction *_transaction = nullptr; + Http3Transaction *_transaction = nullptr; VIO *_source_vio = nullptr; QPACK *_qpack = nullptr; MIOBuffer *_header_block = nullptr; diff --git a/proxy/http3/Http3ClientTransaction.cc b/proxy/http3/Http3Transaction.cc similarity index 87% rename from proxy/http3/Http3ClientTransaction.cc rename to proxy/http3/Http3Transaction.cc index abfe2235112..41611cd67ad 100644 --- a/proxy/http3/Http3ClientTransaction.cc +++ b/proxy/http3/Http3Transaction.cc @@ -21,7 +21,7 @@ limitations under the License. */ -#include "Http3ClientTransaction.h" +#include "Http3Transaction.h" #include "QUICDebugNames.h" @@ -54,9 +54,9 @@ // } // -// HQClientTransaction +// HQTransaction // -HQClientTransaction::HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) +HQTransaction::HQTransaction(HQClientSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) { this->mutex = new_ProxyMutex(); this->_thread = this_ethread(); @@ -75,13 +75,13 @@ HQClientTransaction::HQClientTransaction(HQClientSession *session, QUICStreamIO this->_header.create(http_type); } -HQClientTransaction::~HQClientTransaction() +HQTransaction::~HQTransaction() { this->_header.destroy(); } void -HQClientTransaction::set_active_timeout(ink_hrtime timeout_in) +HQTransaction::set_active_timeout(ink_hrtime timeout_in) { if (this->proxy_ssn) { this->proxy_ssn->set_active_timeout(timeout_in); @@ -89,7 +89,7 @@ HQClientTransaction::set_active_timeout(ink_hrtime timeout_in) } void -HQClientTransaction::set_inactivity_timeout(ink_hrtime timeout_in) +HQTransaction::set_inactivity_timeout(ink_hrtime timeout_in) { if (this->proxy_ssn) { this->proxy_ssn->set_inactivity_timeout(timeout_in); @@ -97,7 +97,7 @@ HQClientTransaction::set_inactivity_timeout(ink_hrtime timeout_in) } void -HQClientTransaction::cancel_inactivity_timeout() +HQTransaction::cancel_inactivity_timeout() { if (this->proxy_ssn) { this->proxy_ssn->cancel_inactivity_timeout(); @@ -105,7 +105,7 @@ HQClientTransaction::cancel_inactivity_timeout() } void -HQClientTransaction::release(IOBufferReader *r) +HQTransaction::release(IOBufferReader *r) { super::release(r); this->do_io_close(); @@ -113,13 +113,13 @@ HQClientTransaction::release(IOBufferReader *r) } bool -HQClientTransaction::allow_half_open() const +HQTransaction::allow_half_open() const { return false; } VIO * -HQClientTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +HQTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) { if (buf) { this->_read_vio.buffer.writer_for(buf); @@ -141,7 +141,7 @@ HQClientTransaction::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) } VIO * -HQClientTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +HQTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) { if (buf) { this->_write_vio.buffer.reader_for(buf); @@ -163,7 +163,7 @@ HQClientTransaction::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader } void -HQClientTransaction::do_io_close(int lerrno) +HQTransaction::do_io_close(int lerrno) { if (this->_read_event) { this->_read_event->cancel(); @@ -189,13 +189,13 @@ HQClientTransaction::do_io_close(int lerrno) } void -HQClientTransaction::do_io_shutdown(ShutdownHowTo_t howto) +HQTransaction::do_io_shutdown(ShutdownHowTo_t howto) { return; } void -HQClientTransaction::reenable(VIO *vio) +HQTransaction::reenable(VIO *vio) { if (vio->op == VIO::READ) { int64_t len = this->_process_read_vio(); @@ -215,38 +215,38 @@ HQClientTransaction::reenable(VIO *vio) } void -HQClientTransaction::destroy() +HQTransaction::destroy() { current_reader = nullptr; } void -HQClientTransaction::transaction_done() +HQTransaction::transaction_done() { // TODO: start closing transaction return; } int -HQClientTransaction::get_transaction_id() const +HQTransaction::get_transaction_id() const { return this->_stream_io->stream_id(); } void -HQClientTransaction::increment_client_transactions_stat() +HQTransaction::increment_client_transactions_stat() { // TODO } void -HQClientTransaction::decrement_client_transactions_stat() +HQTransaction::decrement_client_transactions_stat() { // TODO } NetVConnectionContext_t -HQClientTransaction::direction() const +HQTransaction::direction() const { return this->proxy_ssn->get_netvc()->get_context(); } @@ -255,7 +255,7 @@ HQClientTransaction::direction() const * @brief Replace existing event only if the new event is different than the inprogress event */ Event * -HQClientTransaction::_send_tracked_event(Event *event, int send_event, VIO *vio) +HQTransaction::_send_tracked_event(Event *event, int send_event, VIO *vio) { if (event != nullptr) { if (event->callback_event != send_event) { @@ -275,7 +275,7 @@ HQClientTransaction::_send_tracked_event(Event *event, int send_event, VIO *vio) * @brief Signal event to this->_read_vio.cont */ void -HQClientTransaction::_signal_read_event() +HQTransaction::_signal_read_event() { if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return; @@ -296,7 +296,7 @@ HQClientTransaction::_signal_read_event() * @brief Signal event to this->_write_vio.cont */ void -HQClientTransaction::_signal_write_event() +HQTransaction::_signal_write_event() { if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { return; @@ -314,11 +314,11 @@ HQClientTransaction::_signal_write_event() } // -// Http3ClientTransaction +// Http3Transaction // -Http3ClientTransaction::Http3ClientTransaction(Http3ClientSession *session, QUICStreamIO *stream_io) : super(session, stream_io) +Http3Transaction::Http3Transaction(Http3ClientSession *session, QUICStreamIO *stream_io) : super(session, stream_io) { - static_cast(this->proxy_ssn)->add_transaction(static_cast(this)); + static_cast(this->proxy_ssn)->add_transaction(static_cast(this)); this->_header_framer = new Http3HeaderFramer(this, &this->_write_vio, session->local_qpack(), stream_io->stream_id()); this->_data_framer = new Http3DataFramer(this, &this->_write_vio); @@ -332,10 +332,10 @@ Http3ClientTransaction::Http3ClientTransaction(Http3ClientSession *session, QUIC this->_frame_dispatcher.add_handler(this->_header_handler); this->_frame_dispatcher.add_handler(this->_data_handler); - SET_HANDLER(&Http3ClientTransaction::state_stream_open); + SET_HANDLER(&Http3Transaction::state_stream_open); } -Http3ClientTransaction::~Http3ClientTransaction() +Http3Transaction::~Http3Transaction() { delete this->_header_framer; delete this->_data_framer; @@ -344,7 +344,7 @@ Http3ClientTransaction::~Http3ClientTransaction() } int -Http3ClientTransaction::state_stream_open(int event, void *edata) +Http3Transaction::state_stream_open(int event, void *edata) { // TODO: should check recursive call? if (this->_thread != this_ethread()) { @@ -416,7 +416,7 @@ Http3ClientTransaction::state_stream_open(int event, void *edata) } int -Http3ClientTransaction::state_stream_closed(int event, void *data) +Http3Transaction::state_stream_closed(int event, void *data) { Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); @@ -447,26 +447,26 @@ Http3ClientTransaction::state_stream_closed(int event, void *data) } void -Http3ClientTransaction::do_io_close(int lerrno) +Http3Transaction::do_io_close(int lerrno) { - SET_HANDLER(&Http3ClientTransaction::state_stream_closed); + SET_HANDLER(&Http3Transaction::state_stream_closed); super::do_io_close(lerrno); } bool -Http3ClientTransaction::is_response_header_sent() const +Http3Transaction::is_response_header_sent() const { return this->_header_framer->is_done(); } bool -Http3ClientTransaction::is_response_body_sent() const +Http3Transaction::is_response_body_sent() const { return this->_data_framer->is_done(); } int64_t -Http3ClientTransaction::_process_read_vio() +Http3Transaction::_process_read_vio() { if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return 0; @@ -489,7 +489,7 @@ Http3ClientTransaction::_process_read_vio() } int64_t -Http3ClientTransaction::_process_write_vio() +Http3Transaction::_process_write_vio() { if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { return 0; @@ -520,7 +520,7 @@ const unsigned HTTP3_LEN_SCHEME = countof(":scheme") - 1; const unsigned HTTP3_LEN_AUTHORITY = countof(":authority") - 1; ParseResult -Http3ClientTransaction::_convert_header_from_3_to_1_1(HTTPHdr *hdrs) +Http3Transaction::_convert_header_from_3_to_1_1(HTTPHdr *hdrs) { // TODO: do HTTP/3 specific convert, if there @@ -546,7 +546,7 @@ Http3ClientTransaction::_convert_header_from_3_to_1_1(HTTPHdr *hdrs) } int -Http3ClientTransaction::_on_qpack_decode_complete() +Http3Transaction::_on_qpack_decode_complete() { ParseResult res = this->_convert_header_from_3_to_1_1(&this->_header); if (res == PARSE_RESULT_ERROR) { @@ -593,19 +593,19 @@ Http3ClientTransaction::_on_qpack_decode_complete() } // -// Http09ClientTransaction +// Http09Transaction // -Http09ClientTransaction::Http09ClientTransaction(Http09ClientSession *session, QUICStreamIO *stream_io) : super(session, stream_io) +Http09Transaction::Http09Transaction(Http09ClientSession *session, QUICStreamIO *stream_io) : super(session, stream_io) { - static_cast(this->proxy_ssn)->add_transaction(static_cast(this)); + static_cast(this->proxy_ssn)->add_transaction(static_cast(this)); - SET_HANDLER(&Http09ClientTransaction::state_stream_open); + SET_HANDLER(&Http09Transaction::state_stream_open); } -Http09ClientTransaction::~Http09ClientTransaction() {} +Http09Transaction::~Http09Transaction() {} int -Http09ClientTransaction::state_stream_open(int event, void *edata) +Http09Transaction::state_stream_open(int event, void *edata) { // TODO: should check recursive call? Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); @@ -662,14 +662,14 @@ Http09ClientTransaction::state_stream_open(int event, void *edata) } void -Http09ClientTransaction::do_io_close(int lerrno) +Http09Transaction::do_io_close(int lerrno) { - SET_HANDLER(&Http09ClientTransaction::state_stream_closed); + SET_HANDLER(&Http09Transaction::state_stream_closed); super::do_io_close(lerrno); } int -Http09ClientTransaction::state_stream_closed(int event, void *data) +Http09Transaction::state_stream_closed(int event, void *data) { Http3TransVDebug("%s (%d)", get_vc_event_name(event), event); @@ -700,7 +700,7 @@ Http09ClientTransaction::state_stream_closed(int event, void *data) // Convert HTTP/0.9 to HTTP/1.1 int64_t -Http09ClientTransaction::_process_read_vio() +Http09Transaction::_process_read_vio() { if (this->_read_vio.cont == nullptr || this->_read_vio.op == VIO::NONE) { return 0; @@ -788,7 +788,7 @@ static constexpr char http_1_1_version[] = "HTTP/1.1"; // Convert HTTP/1.1 to HTTP/0.9 int64_t -Http09ClientTransaction::_process_write_vio() +Http09Transaction::_process_write_vio() { if (this->_write_vio.cont == nullptr || this->_write_vio.op == VIO::NONE) { return 0; diff --git a/proxy/http3/Http3ClientTransaction.h b/proxy/http3/Http3Transaction.h similarity index 87% rename from proxy/http3/Http3ClientTransaction.h rename to proxy/http3/Http3Transaction.h index 6be2f781187..a4e0bdb4215 100644 --- a/proxy/http3/Http3ClientTransaction.h +++ b/proxy/http3/Http3Transaction.h @@ -35,13 +35,13 @@ class Http3ClientSession; class Http3HeaderFramer; class Http3DataFramer; -class HQClientTransaction : public ProxyTransaction +class HQTransaction : public ProxyTransaction { public: using super = ProxyTransaction; - HQClientTransaction(HQClientSession *session, QUICStreamIO *stream_io); - virtual ~HQClientTransaction(); + HQTransaction(HQClientSession *session, QUICStreamIO *stream_io); + virtual ~HQTransaction(); // Implement ProxyClienTransaction interface void set_active_timeout(ink_hrtime timeout_in) override; @@ -63,7 +63,7 @@ class HQClientTransaction : public ProxyTransaction virtual void do_io_shutdown(ShutdownHowTo_t) override; virtual void reenable(VIO *) override; - // HQClientTransaction + // HQTransaction virtual int state_stream_open(int, void *) = 0; virtual int state_stream_closed(int event, void *data) = 0; NetVConnectionContext_t direction() const; @@ -89,13 +89,13 @@ class HQClientTransaction : public ProxyTransaction HTTPHdr _header; ///< HTTP header buffer for decoding }; -class Http3ClientTransaction : public HQClientTransaction +class Http3Transaction : public HQTransaction { public: - using super = HQClientTransaction; + using super = HQTransaction; - Http3ClientTransaction(Http3ClientSession *session, QUICStreamIO *stream_io); - ~Http3ClientTransaction(); + Http3Transaction(Http3ClientSession *session, QUICStreamIO *stream_io); + ~Http3Transaction(); int state_stream_open(int event, void *data) override; int state_stream_closed(int event, void *data) override; @@ -124,13 +124,13 @@ class Http3ClientTransaction : public HQClientTransaction /** Only for interop. Will be removed. */ -class Http09ClientTransaction : public HQClientTransaction +class Http09Transaction : public HQTransaction { public: - using super = HQClientTransaction; + using super = HQTransaction; - Http09ClientTransaction(Http09ClientSession *session, QUICStreamIO *stream_io); - ~Http09ClientTransaction(); + Http09Transaction(Http09ClientSession *session, QUICStreamIO *stream_io); + ~Http09Transaction(); int state_stream_open(int event, void *data) override; int state_stream_closed(int event, void *data) override; diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index 789b05ec77a..afea4c54821 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -42,7 +42,7 @@ libhttp3_a_SOURCES = \ Http3Types.cc \ Http3SessionAccept.cc \ Http3ClientSession.cc \ - Http3ClientTransaction.cc \ + Http3Transaction.cc \ Http3DebugNames.cc \ Http3Frame.cc \ Http3FrameCollector.cc \ diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc index 35849589ce3..260c0f1d1fa 100644 --- a/src/traffic_quic/quic_client.cc +++ b/src/traffic_quic/quic_client.cc @@ -28,7 +28,7 @@ #include #include "Http3ClientSession.h" -#include "Http3ClientTransaction.h" +#include "Http3Transaction.h" // OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings) // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_alpn_protos.html @@ -293,7 +293,7 @@ Http3ClientApp::_do_http_request() QUICStreamIO *stream_io = this->_find_stream_io(stream_id); // TODO: create Http3ServerTransaction - Http3ClientTransaction *txn = new Http3ClientTransaction(this->_ssn, stream_io); + Http3Transaction *txn = new Http3Transaction(this->_ssn, stream_io); SCOPED_MUTEX_LOCK(lock, txn->mutex, this_ethread()); // TODO: fix below issue with H2 origin conn stuff From fe277104391e7d64938e50b2c5fac6a81cbbe13c Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 31 May 2019 15:17:40 +0900 Subject: [PATCH 1303/1313] Rename Http3ClientSession to Http3Session --- proxy/http3/Http09App.cc | 4 +- proxy/http3/Http09App.h | 4 +- proxy/http3/Http3App.cc | 4 +- proxy/http3/Http3App.h | 11 ++-- ...{Http3ClientSession.cc => Http3Session.cc} | 62 +++++++++---------- .../{Http3ClientSession.h => Http3Session.h} | 24 +++---- proxy/http3/Http3Transaction.cc | 12 ++-- proxy/http3/Http3Transaction.h | 12 ++-- proxy/http3/Makefile.am | 2 +- src/traffic_quic/quic_client.cc | 1 - 10 files changed, 67 insertions(+), 69 deletions(-) rename proxy/http3/{Http3ClientSession.cc => Http3Session.cc} (66%) rename proxy/http3/{Http3ClientSession.h => Http3Session.h} (84%) diff --git a/proxy/http3/Http09App.cc b/proxy/http3/Http09App.cc index 0b7d9756df3..0b317ff0816 100644 --- a/proxy/http3/Http09App.cc +++ b/proxy/http3/Http09App.cc @@ -29,7 +29,7 @@ #include "P_VConnection.h" #include "QUICDebugNames.h" -#include "Http3ClientSession.h" +#include "Http3Session.h" #include "Http3Transaction.h" static constexpr char debug_tag[] = "quic_simple_app"; @@ -38,7 +38,7 @@ static constexpr char debug_tag_v[] = "v_quic_simple_app"; Http09App::Http09App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options) : QUICApplication(client_vc) { - this->_ssn = new Http09ClientSession(client_vc); + this->_ssn = new Http09Session(client_vc); this->_ssn->acl = std::move(session_acl); // TODO: avoid const cast this->_ssn->host_res_style = diff --git a/proxy/http3/Http09App.h b/proxy/http3/Http09App.h index 5943d6b3bb1..ab35399e2c9 100644 --- a/proxy/http3/Http09App.h +++ b/proxy/http3/Http09App.h @@ -30,7 +30,7 @@ #include "QUICApplication.h" class QUICNetVConnection; -class Http09ClientSession; +class Http09Session; /** * @brief A simple multi-streamed application. @@ -47,5 +47,5 @@ class Http09App : public QUICApplication int main_event_handler(int event, Event *data); private: - Http09ClientSession *_ssn = nullptr; + Http09Session *_ssn = nullptr; }; diff --git a/proxy/http3/Http3App.cc b/proxy/http3/Http3App.cc index 45443b3f9c4..946a73d7a59 100644 --- a/proxy/http3/Http3App.cc +++ b/proxy/http3/Http3App.cc @@ -31,7 +31,7 @@ #include "Http3.h" #include "Http3Config.h" #include "Http3DebugNames.h" -#include "Http3ClientSession.h" +#include "Http3Session.h" #include "Http3Transaction.h" static constexpr char debug_tag[] = "http3"; @@ -40,7 +40,7 @@ static constexpr char debug_tag_v[] = "v_http3"; Http3App::Http3App(QUICNetVConnection *client_vc, IpAllow::ACL &&session_acl, const HttpSessionAccept::Options &options) : QUICApplication(client_vc) { - this->_ssn = new Http3ClientSession(client_vc); + this->_ssn = new Http3Session(client_vc); this->_ssn->acl = std::move(session_acl); // TODO: avoid const cast this->_ssn->host_res_style = diff --git a/proxy/http3/Http3App.h b/proxy/http3/Http3App.h index f7f77949e36..fd1893d9722 100644 --- a/proxy/http3/Http3App.h +++ b/proxy/http3/Http3App.h @@ -36,7 +36,7 @@ #include "Http3FrameHandler.h" class QUICNetVConnection; -class Http3ClientSession; +class Http3Session; /** * @brief A HTTP/3 application @@ -56,8 +56,7 @@ class Http3App : public QUICApplication QUICConnectionErrorUPtr create_uni_stream(QUICStreamId &new_stream_id, Http3StreamType type); protected: - // TODO: create Http3Session - Http3ClientSession *_ssn = nullptr; + Http3Session *_ssn = nullptr; private: void _handle_uni_stream_on_read_ready(int event, QUICStreamIO *stream_io); @@ -85,15 +84,15 @@ class Http3App : public QUICApplication class Http3SettingsHandler : public Http3FrameHandler { public: - Http3SettingsHandler(Http3ClientSession *session) : _session(session){}; + Http3SettingsHandler(Http3Session *session) : _session(session){}; // Http3FrameHandler std::vector interests() override; Http3ErrorUPtr handle_frame(std::shared_ptr frame) override; private: - // TODO: clarify Http3ClientSession I/F for Http3SettingsHandler and Http3App - Http3ClientSession *_session = nullptr; + // TODO: clarify Http3Session I/F for Http3SettingsHandler and Http3App + Http3Session *_session = nullptr; }; class Http3SettingsFramer : public Http3FrameGenerator diff --git a/proxy/http3/Http3ClientSession.cc b/proxy/http3/Http3Session.cc similarity index 66% rename from proxy/http3/Http3ClientSession.cc rename to proxy/http3/Http3Session.cc index 22d820ea369..e552f953f9d 100644 --- a/proxy/http3/Http3ClientSession.cc +++ b/proxy/http3/Http3Session.cc @@ -21,14 +21,14 @@ limitations under the License. */ -#include "Http3ClientSession.h" +#include "Http3Session.h" #include "Http3.h" // -// HQClientSession +// HQSession // -HQClientSession ::~HQClientSession() +HQSession ::~HQSession() { for (HQTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { delete t; @@ -36,7 +36,7 @@ HQClientSession ::~HQClientSession() } void -HQClientSession::add_transaction(HQTransaction *trans) +HQSession::add_transaction(HQTransaction *trans) { this->_transaction_list.enqueue(trans); @@ -44,7 +44,7 @@ HQClientSession::add_transaction(HQTransaction *trans) } HQTransaction * -HQClientSession::get_transaction(QUICStreamId id) +HQSession::get_transaction(QUICStreamId id) { for (HQTransaction *t = this->_transaction_list.head; t; t = static_cast(t->link.next)) { if (t->get_transaction_id() == static_cast(id)) { @@ -56,42 +56,42 @@ HQClientSession::get_transaction(QUICStreamId id) } VIO * -HQClientSession::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +HQSession::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) { ink_assert(false); return nullptr; } VIO * -HQClientSession::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +HQSession::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) { ink_assert(false); return nullptr; } void -HQClientSession::do_io_close(int lerrno) +HQSession::do_io_close(int lerrno) { // TODO return; } void -HQClientSession::do_io_shutdown(ShutdownHowTo_t howto) +HQSession::do_io_shutdown(ShutdownHowTo_t howto) { ink_assert(false); return; } void -HQClientSession::reenable(VIO *vio) +HQSession::reenable(VIO *vio) { ink_assert(false); return; } void -HQClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reade) +HQSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reade) { this->con_id = static_cast(reinterpret_cast(new_vc))->connection_id(); @@ -99,41 +99,41 @@ HQClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBuff } void -HQClientSession::start() +HQSession::start() { ink_assert(false); return; } void -HQClientSession::destroy() +HQSession::destroy() { ink_assert(false); return; } void -HQClientSession::release(ProxyTransaction *trans) +HQSession::release(ProxyTransaction *trans) { return; } NetVConnection * -HQClientSession::get_netvc() const +HQSession::get_netvc() const { return this->_client_vc; } int -HQClientSession::get_transact_count() const +HQSession::get_transact_count() const { return 0; } // -// Http3ClientSession +// Http3Session // -Http3ClientSession::Http3ClientSession(NetVConnection *vc) : HQClientSession(vc) +Http3Session::Http3Session(NetVConnection *vc) : HQSession(vc) { this->_local_qpack = new QPACK(static_cast(vc), HTTP3_DEFAULT_MAX_HEADER_LIST_SIZE, HTTP3_DEFAULT_HEADER_TABLE_SIZE, HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS); @@ -141,7 +141,7 @@ Http3ClientSession::Http3ClientSession(NetVConnection *vc) : HQClientSession(vc) HTTP3_DEFAULT_HEADER_TABLE_SIZE, HTTP3_DEFAULT_QPACK_BLOCKED_STREAMS); } -Http3ClientSession::~Http3ClientSession() +Http3Session::~Http3Session() { this->_client_vc = nullptr; delete this->_local_qpack; @@ -149,13 +149,13 @@ Http3ClientSession::~Http3ClientSession() } const char * -Http3ClientSession::get_protocol_string() const +Http3Session::get_protocol_string() const { return IP_PROTO_TAG_HTTP_3.data(); } int -Http3ClientSession::populate_protocol(std::string_view *result, int size) const +Http3Session::populate_protocol(std::string_view *result, int size) const { int retval = 0; if (size > retval) { @@ -168,45 +168,45 @@ Http3ClientSession::populate_protocol(std::string_view *result, int size) const } void -Http3ClientSession::increment_current_active_client_connections_stat() +Http3Session::increment_current_active_client_connections_stat() { // TODO Implement stats } void -Http3ClientSession::decrement_current_active_client_connections_stat() +Http3Session::decrement_current_active_client_connections_stat() { // TODO Implement stats } QPACK * -Http3ClientSession::local_qpack() +Http3Session::local_qpack() { return this->_local_qpack; } QPACK * -Http3ClientSession::remote_qpack() +Http3Session::remote_qpack() { return this->_remote_qpack; } // -// Http09ClientSession +// Http09Session // -Http09ClientSession::~Http09ClientSession() +Http09Session::~Http09Session() { this->_client_vc = nullptr; } const char * -Http09ClientSession::get_protocol_string() const +Http09Session::get_protocol_string() const { return IP_PROTO_TAG_HTTP_QUIC.data(); } int -Http09ClientSession::populate_protocol(std::string_view *result, int size) const +Http09Session::populate_protocol(std::string_view *result, int size) const { int retval = 0; if (size > retval) { @@ -219,13 +219,13 @@ Http09ClientSession::populate_protocol(std::string_view *result, int size) const } void -Http09ClientSession::increment_current_active_client_connections_stat() +Http09Session::increment_current_active_client_connections_stat() { // TODO Implement stats } void -Http09ClientSession::decrement_current_active_client_connections_stat() +Http09Session::decrement_current_active_client_connections_stat() { // TODO Implement stats } diff --git a/proxy/http3/Http3ClientSession.h b/proxy/http3/Http3Session.h similarity index 84% rename from proxy/http3/Http3ClientSession.h rename to proxy/http3/Http3Session.h index ffc928924b9..49fb40c185f 100644 --- a/proxy/http3/Http3ClientSession.h +++ b/proxy/http3/Http3Session.h @@ -27,13 +27,13 @@ #include "Http3Transaction.h" #include "QPACK.h" -class HQClientSession : public ProxySession +class HQSession : public ProxySession { public: using super = ProxySession; ///< Parent type - HQClientSession(NetVConnection *vc) : _client_vc(vc){}; - virtual ~HQClientSession(); + HQSession(NetVConnection *vc) : _client_vc(vc){}; + virtual ~HQSession(); // Implement VConnection interface VIO *do_io_read(Continuation *c, int64_t nbytes = INT64_MAX, MIOBuffer *buf = nullptr) override; @@ -50,7 +50,7 @@ class HQClientSession : public ProxySession NetVConnection *get_netvc() const override; int get_transact_count() const override; - // HQClientSession + // HQSession void add_transaction(HQTransaction *); HQTransaction *get_transaction(QUICStreamId); @@ -62,13 +62,13 @@ class HQClientSession : public ProxySession Queue _transaction_list; }; -class Http3ClientSession : public HQClientSession +class Http3Session : public HQSession { public: - using super = HQClientSession; ///< Parent type + using super = HQSession; ///< Parent type - Http3ClientSession(NetVConnection *vc); - ~Http3ClientSession(); + Http3Session(NetVConnection *vc); + ~Http3Session(); // ProxySession interface const char *get_protocol_string() const override; @@ -87,13 +87,13 @@ class Http3ClientSession : public HQClientSession /** Only for interop. Will be removed. */ -class Http09ClientSession : public HQClientSession +class Http09Session : public HQSession { public: - using super = HQClientSession; ///< Parent type + using super = HQSession; ///< Parent type - Http09ClientSession(NetVConnection *vc) : HQClientSession(vc) {} - ~Http09ClientSession(); + Http09Session(NetVConnection *vc) : HQSession(vc) {} + ~Http09Session(); // ProxySession interface const char *get_protocol_string() const override; diff --git a/proxy/http3/Http3Transaction.cc b/proxy/http3/Http3Transaction.cc index 41611cd67ad..3ee0e7711df 100644 --- a/proxy/http3/Http3Transaction.cc +++ b/proxy/http3/Http3Transaction.cc @@ -25,7 +25,7 @@ #include "QUICDebugNames.h" -#include "Http3ClientSession.h" +#include "Http3Session.h" #include "Http3StreamDataVIOAdaptor.h" #include "Http3HeaderVIOAdaptor.h" #include "Http3HeaderFramer.h" @@ -56,7 +56,7 @@ // // HQTransaction // -HQTransaction::HQTransaction(HQClientSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) +HQTransaction::HQTransaction(HQSession *session, QUICStreamIO *stream_io) : super(), _stream_io(stream_io) { this->mutex = new_ProxyMutex(); this->_thread = this_ethread(); @@ -316,9 +316,9 @@ HQTransaction::_signal_write_event() // // Http3Transaction // -Http3Transaction::Http3Transaction(Http3ClientSession *session, QUICStreamIO *stream_io) : super(session, stream_io) +Http3Transaction::Http3Transaction(Http3Session *session, QUICStreamIO *stream_io) : super(session, stream_io) { - static_cast(this->proxy_ssn)->add_transaction(static_cast(this)); + static_cast(this->proxy_ssn)->add_transaction(static_cast(this)); this->_header_framer = new Http3HeaderFramer(this, &this->_write_vio, session->local_qpack(), stream_io->stream_id()); this->_data_framer = new Http3DataFramer(this, &this->_write_vio); @@ -595,9 +595,9 @@ Http3Transaction::_on_qpack_decode_complete() // // Http09Transaction // -Http09Transaction::Http09Transaction(Http09ClientSession *session, QUICStreamIO *stream_io) : super(session, stream_io) +Http09Transaction::Http09Transaction(Http09Session *session, QUICStreamIO *stream_io) : super(session, stream_io) { - static_cast(this->proxy_ssn)->add_transaction(static_cast(this)); + static_cast(this->proxy_ssn)->add_transaction(static_cast(this)); SET_HANDLER(&Http09Transaction::state_stream_open); } diff --git a/proxy/http3/Http3Transaction.h b/proxy/http3/Http3Transaction.h index a4e0bdb4215..1bed5b058fd 100644 --- a/proxy/http3/Http3Transaction.h +++ b/proxy/http3/Http3Transaction.h @@ -29,9 +29,9 @@ #include "Http3FrameCollector.h" class QUICStreamIO; -class HQClientSession; -class Http09ClientSession; -class Http3ClientSession; +class HQSession; +class Http09Session; +class Http3Session; class Http3HeaderFramer; class Http3DataFramer; @@ -40,7 +40,7 @@ class HQTransaction : public ProxyTransaction public: using super = ProxyTransaction; - HQTransaction(HQClientSession *session, QUICStreamIO *stream_io); + HQTransaction(HQSession *session, QUICStreamIO *stream_io); virtual ~HQTransaction(); // Implement ProxyClienTransaction interface @@ -94,7 +94,7 @@ class Http3Transaction : public HQTransaction public: using super = HQTransaction; - Http3Transaction(Http3ClientSession *session, QUICStreamIO *stream_io); + Http3Transaction(Http3Session *session, QUICStreamIO *stream_io); ~Http3Transaction(); int state_stream_open(int event, void *data) override; @@ -129,7 +129,7 @@ class Http09Transaction : public HQTransaction public: using super = HQTransaction; - Http09Transaction(Http09ClientSession *session, QUICStreamIO *stream_io); + Http09Transaction(Http09Session *session, QUICStreamIO *stream_io); ~Http09Transaction(); int state_stream_open(int event, void *data) override; diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index afea4c54821..8ad79f887fa 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -41,7 +41,7 @@ libhttp3_a_SOURCES = \ Http3App.cc \ Http3Types.cc \ Http3SessionAccept.cc \ - Http3ClientSession.cc \ + Http3Session.cc \ Http3Transaction.cc \ Http3DebugNames.cc \ Http3Frame.cc \ diff --git a/src/traffic_quic/quic_client.cc b/src/traffic_quic/quic_client.cc index 260c0f1d1fa..007c20ae3e8 100644 --- a/src/traffic_quic/quic_client.cc +++ b/src/traffic_quic/quic_client.cc @@ -27,7 +27,6 @@ #include #include -#include "Http3ClientSession.h" #include "Http3Transaction.h" // OpenSSL protocol-lists format (vector of 8-bit length-prefixed, byte strings) From 2805b749e1444e54373491584b2955a47e6cca29 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Fri, 31 May 2019 15:44:53 +0900 Subject: [PATCH 1304/1313] Skip running test_QPACK when qif dir is not found --- proxy/http3/test/test_QPACK.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/proxy/http3/test/test_QPACK.cc b/proxy/http3/test/test_QPACK.cc index 015fd9e4a37..f76626d457c 100644 --- a/proxy/http3/test/test_QPACK.cc +++ b/proxy/http3/test/test_QPACK.cc @@ -406,7 +406,6 @@ TEST_CASE("Encoding", "[qpack-encode]") if (dir == nullptr) { std::cerr << "couldn't open dir: " << qifdir << std::endl; - REQUIRE(false); return; } @@ -441,8 +440,7 @@ TEST_CASE("Decoding", "[qpack-decode]") DIR *dir = opendir(app_dir); if (dir == nullptr) { - std::cerr << "couldn't open dir: " << qifdir << std::endl; - REQUIRE(false); + std::cerr << "couldn't open dir: " << app_dir << std::endl; return; } From 9d561a5a3945354e55be6edac6eeecca416b1842 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Mon, 17 Jun 2019 15:40:16 +0900 Subject: [PATCH 1305/1313] Catch up changes on master --- iocore/net/P_QUICNetVConnection.h | 2 +- iocore/net/QUICNetVConnection.cc | 6 ++--- iocore/net/quic/QUICConfig.cc | 41 ++++++++++++++++--------------- iocore/net/quic/QUICConfig.h | 6 ++--- iocore/net/quic/QUICGlobals.cc | 20 +++++++++------ proxy/http3/Http3Transaction.cc | 2 +- 6 files changed, 41 insertions(+), 36 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 709bb5717ba..8ca25880df5 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -346,7 +346,7 @@ class QUICNetVConnection : public UnixNetVConnection, public QUICConnection, pub void _update_local_cid(const QUICConnectionId &new_cid); void _rerandomize_original_cid(); - QUICHandshakeProtocol *_setup_handshake_protocol(SSL_CTX *ctx); + QUICHandshakeProtocol *_setup_handshake_protocol(shared_SSL_CTX ctx); QUICPacketUPtr _the_final_packet = QUICPacketFactory::create_null_packet(); QUICStatelessResetToken _reset_token; diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index e46686a5826..260ac5fa4b8 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -2212,12 +2212,12 @@ QUICNetVConnection::_rerandomize_original_cid() } QUICHandshakeProtocol * -QUICNetVConnection::_setup_handshake_protocol(SSL_CTX *ctx) +QUICNetVConnection::_setup_handshake_protocol(shared_SSL_CTX ctx) { // Initialize handshake protocol specific stuff // For QUICv1 TLS is the only option - QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx, this->direction(), this->options, this->_quic_config->client_session_file(), - this->_quic_config->client_keylog_file()); + 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(this)); return tls; diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 8ad22ce675d..c6ece00300e 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -73,17 +73,18 @@ quic_new_ssl_ctx() /** ALPN and SNI should be set to SSL object with NETVC_OPTIONS **/ -static SSL_CTX * +static shared_SSL_CTX quic_init_client_ssl_ctx(const QUICConfigParams *params) { - SSL_CTX *ssl_ctx = quic_new_ssl_ctx(); + std::unique_ptr ssl_ctx(nullptr, &SSL_CTX_free); + ssl_ctx.reset(quic_new_ssl_ctx()); #if defined(SSL_CTX_set1_groups_list) || defined(SSL_CTX_set1_curves_list) if (params->client_supported_groups() != nullptr) { #ifdef SSL_CTX_set1_groups_list - if (SSL_CTX_set1_groups_list(ssl_ctx, params->client_supported_groups()) != 1) { + if (SSL_CTX_set1_groups_list(ssl_ctx.get(), params->client_supported_groups()) != 1) { #else - if (SSL_CTX_set1_curves_list(ssl_ctx, params->client_supported_groups()) != 1) { + if (SSL_CTX_set1_curves_list(ssl_ctx.get(), params->client_supported_groups()) != 1) { #endif Error("SSL_CTX_set1_groups_list failed"); } @@ -91,13 +92,13 @@ quic_init_client_ssl_ctx(const QUICConfigParams *params) #endif if (params->client_session_file() != nullptr) { - SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE); - SSL_CTX_sess_set_new_cb(ssl_ctx, QUIC::ssl_client_new_session); + SSL_CTX_set_session_cache_mode(ssl_ctx.get(), SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE); + SSL_CTX_sess_set_new_cb(ssl_ctx.get(), QUIC::ssl_client_new_session); } #ifdef SSL_MODE_QUIC_HACK if (params->client_keylog_file() != nullptr) { - SSL_CTX_set_keylog_callback(ssl_ctx, QUIC::ssl_client_keylog_cb); + SSL_CTX_set_keylog_callback(ssl_ctx.get(), QUIC::ssl_client_keylog_cb); } #endif @@ -112,7 +113,7 @@ QUICConfigParams::~QUICConfigParams() this->_server_supported_groups = (char *)ats_free_null(this->_server_supported_groups); this->_client_supported_groups = (char *)ats_free_null(this->_client_supported_groups); - SSL_CTX_free(this->_client_ssl_ctx); + SSL_CTX_free(this->_client_ssl_ctx.get()); }; void @@ -360,7 +361,7 @@ QUICConfigParams::client_supported_groups() const return this->_client_supported_groups; } -SSL_CTX * +shared_SSL_CTX QUICConfigParams::client_ssl_ctx() const { return this->_client_ssl_ctx; @@ -627,12 +628,12 @@ QUICMultiCertConfigLoader::init_server_ssl_ctx(std::vector &cert_list, c } SSL_CTX * -QUICMultiCertConfigLoader::_store_ssl_ctx(SSLCertLookup *lookup, const SSLMultiCertConfigParams *multi_cert_params) +QUICMultiCertConfigLoader::_store_ssl_ctx(SSLCertLookup *lookup, const shared_SSLMultiCertConfigParams multi_cert_params) { std::vector cert_list; - SSL_CTX *ctx = this->init_server_ssl_ctx(cert_list, multi_cert_params); - ssl_ticket_key_block *keyblock = nullptr; - bool inserted = false; + shared_SSL_CTX ctx(this->init_server_ssl_ctx(cert_list, multi_cert_params.get()), SSL_CTX_free); + shared_ssl_ticket_key_block keyblock = nullptr; + bool inserted = false; if (!ctx || !multi_cert_params) { lookup->is_valid = false; @@ -652,17 +653,17 @@ QUICMultiCertConfigLoader::_store_ssl_ctx(SSLCertLookup *lookup, const SSLMultiC // Index this certificate by the specified IP(v6) address. If the address is "*", make it the default context. if (multi_cert_params->addr) { if (strcmp(multi_cert_params->addr, "*") == 0) { - if (lookup->insert(multi_cert_params->addr, SSLCertContext(ctx, multi_cert_params->opt, keyblock)) >= 0) { + if (lookup->insert(multi_cert_params->addr, SSLCertContext(ctx, multi_cert_params, keyblock)) >= 0) { inserted = true; lookup->ssl_default = ctx; - this->_set_handshake_callbacks(ctx); + this->_set_handshake_callbacks(ctx.get()); } } else { IpEndpoint ep; if (ats_ip_pton(multi_cert_params->addr, &ep) == 0) { QUICConfDebug("mapping '%s' to certificate %s", (const char *)multi_cert_params->addr, (const char *)certname); - if (lookup->insert(ep, SSLCertContext(ctx, multi_cert_params->opt, keyblock)) >= 0) { + if (lookup->insert(ep, SSLCertContext(ctx, multi_cert_params, keyblock)) >= 0) { inserted = true; } } else { @@ -677,19 +678,19 @@ QUICMultiCertConfigLoader::_store_ssl_ctx(SSLCertLookup *lookup, const SSLMultiC // refcounting or alternate way of avoiding double frees. QUICConfDebug("importing SNI names from %s", (const char *)certname); for (auto cert : cert_list) { - if (SSLMultiCertConfigLoader::index_certificate(lookup, SSLCertContext(ctx, multi_cert_params->opt), cert, certname)) { + if (SSLMultiCertConfigLoader::index_certificate(lookup, SSLCertContext(ctx, multi_cert_params), cert, certname)) { inserted = true; } } if (inserted) { if (SSLConfigParams::init_ssl_ctx_cb) { - SSLConfigParams::init_ssl_ctx_cb(ctx, true); + SSLConfigParams::init_ssl_ctx_cb(ctx.get(), true); } } if (!inserted) { - SSLReleaseContext(ctx); + SSLReleaseContext(ctx.get()); ctx = nullptr; } @@ -697,7 +698,7 @@ QUICMultiCertConfigLoader::_store_ssl_ctx(SSLCertLookup *lookup, const SSLMultiC X509_free(i); } - return ctx; + return ctx.get(); } void diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index c56d74f76bf..e0ac1dcfdb0 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -48,7 +48,7 @@ class QUICConfigParams : public ConfigInfo const char *client_session_file() const; const char *client_keylog_file() const; - SSL_CTX *client_ssl_ctx() const; + shared_SSL_CTX client_ssl_ctx() const; // Transport Parameters uint32_t no_activity_timeout_in() const; @@ -104,7 +104,7 @@ class QUICConfigParams : public ConfigInfo char *_client_session_file = nullptr; char *_client_keylog_file = nullptr; - SSL_CTX *_client_ssl_ctx = nullptr; + shared_SSL_CTX _client_ssl_ctx = nullptr; // Transport Parameters uint32_t _no_activity_timeout_in = 0; @@ -181,6 +181,6 @@ class QUICMultiCertConfigLoader : public SSLMultiCertConfigLoader virtual SSL_CTX *init_server_ssl_ctx(std::vector &cert_list, const SSLMultiCertConfigParams *multi_cert_params) override; private: - virtual SSL_CTX *_store_ssl_ctx(SSLCertLookup *lookup, const SSLMultiCertConfigParams *multi_cert_params) override; + virtual SSL_CTX *_store_ssl_ctx(SSLCertLookup *lookup, const shared_SSLMultiCertConfigParams multi_cert_params) override; virtual void _set_handshake_callbacks(SSL_CTX *ssl_ctx) override; }; diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index 661f816a57e..4b54d372398 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -106,7 +106,7 @@ QUIC::ssl_client_keylog_cb(const SSL *ssl, const char *line) int QUIC::ssl_cert_cb(SSL *ssl, void * /*arg*/) { - SSL_CTX *ctx = nullptr; + shared_SSL_CTX ctx = nullptr; SSLCertContext *cc = nullptr; QUICCertConfig::scoped_config lookup; const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); @@ -122,8 +122,8 @@ QUIC::ssl_cert_cb(SSL *ssl, void * /*arg*/) // already made a best effort to find the best match. if (likely(servername)) { cc = lookup->find((char *)servername); - if (cc && cc->ctx) { - ctx = cc->ctx; + if (cc && cc->getCtx()) { + ctx = cc->getCtx(); } } @@ -133,21 +133,25 @@ QUIC::ssl_cert_cb(SSL *ssl, void * /*arg*/) IpEndpoint ip = five_tuple.destination(); cc = lookup->find(ip); - if (cc && cc->ctx) { - ctx = cc->ctx; + if (cc && cc->getCtx()) { + ctx = cc->getCtx(); } } bool found = true; if (ctx != nullptr) { - SSL_set_SSL_CTX(ssl, ctx); + SSL_set_SSL_CTX(ssl, ctx.get()); } else { found = false; } - ctx = SSL_get_SSL_CTX(ssl); + SSL_CTX *verify_ctx = nullptr; + verify_ctx = SSL_get_SSL_CTX(ssl); + QUICGlobalQCDebug(qc, "%s SSL_CTX %p for requested name '%s'", found ? "found" : "using", verify_ctx, servername); - QUICGlobalQCDebug(qc, "%s SSL_CTX %p for requested name '%s'", found ? "found" : "using", ctx, servername); + if (verify_ctx == nullptr) { + return 0; + } return 1; } diff --git a/proxy/http3/Http3Transaction.cc b/proxy/http3/Http3Transaction.cc index 3ee0e7711df..b72f33a9b02 100644 --- a/proxy/http3/Http3Transaction.cc +++ b/proxy/http3/Http3Transaction.cc @@ -61,7 +61,7 @@ HQTransaction::HQTransaction(HQSession *session, QUICStreamIO *stream_io) : supe this->mutex = new_ProxyMutex(); this->_thread = this_ethread(); - this->set_parent(session); + this->set_proxy_ssn(session); this->sm_reader = this->_read_vio_buf.alloc_reader(); From e6a546700dd9317efd49744723e82e43f668b6e6 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Tue, 25 Jun 2019 16:37:40 +0900 Subject: [PATCH 1306/1313] Reduce trivial diff from master --- iocore/net/P_Net.h | 1 - iocore/net/P_SSLUtils.h | 2 -- iocore/net/UnixNetVConnection.cc | 1 + 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/iocore/net/P_Net.h b/iocore/net/P_Net.h index 253026d8b1d..581e066ce70 100644 --- a/iocore/net/P_Net.h +++ b/iocore/net/P_Net.h @@ -116,7 +116,6 @@ extern RecRawStatBlock *net_rsb; #include "P_QUICPacketHandler.h" #include "P_QUICNet.h" #endif -// #include "P_QUICCertLookup.h" static constexpr ts::ModuleVersion NET_SYSTEM_MODULE_INTERNAL_VERSION(NET_SYSTEM_MODULE_PUBLIC_VERSION, ts::ModuleVersion::PRIVATE); diff --git a/iocore/net/P_SSLUtils.h b/iocore/net/P_SSLUtils.h index fd28d50282a..19f6bc1008d 100644 --- a/iocore/net/P_SSLUtils.h +++ b/iocore/net/P_SSLUtils.h @@ -92,8 +92,6 @@ ssl_error_t SSLReadBuffer(SSL *ssl, void *buf, int64_t nbytes, int64_t &nread); ssl_error_t SSLAccept(SSL *ssl); ssl_error_t SSLConnect(SSL *ssl); -bool SSLParseCertificateConfiguration(const SSLConfigParams *params, SSL_CTX *ssl_ctx); - // Attach a SSL NetVC back pointer to a SSL session. void SSLNetVCAttach(SSL *ssl, SSLNetVConnection *vc); diff --git a/iocore/net/UnixNetVConnection.cc b/iocore/net/UnixNetVConnection.cc index 6df4c50b62d..5ecc216b304 100644 --- a/iocore/net/UnixNetVConnection.cc +++ b/iocore/net/UnixNetVConnection.cc @@ -33,6 +33,7 @@ // Global ClassAllocator netVCAllocator("netVCAllocator"); + // // Reschedule a UnixNetVConnection by moving it // onto or off of the ready_list From 749f9090c8ffae7d5a20ec0c4551c83e348faf30 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 27 Jun 2019 11:31:57 +0900 Subject: [PATCH 1307/1313] Remove libtsconfig from Makefiles (cherry picked from commit d034bd6bfd6613adb9dddd86affa9c71ebee5689) --- iocore/net/quic/Makefile.am | 1 - proxy/http3/Makefile.am | 1 - src/traffic_quic/Makefile.inc | 1 - 3 files changed, 3 deletions(-) diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index d0fbc3360ab..7e2bfcab2f3 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -133,7 +133,6 @@ test_LDADD = \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/src/tscore/libtscore.la \ $(top_builddir)/src/tscpp/util/libtscpputil.la \ - $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ @HWLOC_LIBS@ @OPENSSL_LIBS@ @LIBPCRE@ @YAMLCPP_LIBS@ diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index 8ad79f887fa..3118ef24b49 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -76,7 +76,6 @@ test_LDADD = \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/src/tscore/libtscore.la \ $(top_builddir)/src/tscpp/util/libtscpputil.la \ - $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ $(top_builddir)/proxy/http2/libhttp2.a \ $(top_builddir)/proxy/libproxy.a \ diff --git a/src/traffic_quic/Makefile.inc b/src/traffic_quic/Makefile.inc index 4b2dbe6f4be..963576f5c2d 100644 --- a/src/traffic_quic/Makefile.inc +++ b/src/traffic_quic/Makefile.inc @@ -51,7 +51,6 @@ traffic_quic_traffic_quic_LDADD = \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/src/tscore/libtscore.la \ $(top_builddir)/src/tscpp/util/libtscpputil.la \ - $(top_builddir)/lib/tsconfig/libtsconfig.la \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ $(top_builddir)/proxy/http3/libhttp3.a \ $(top_builddir)/proxy/http2/libhttp2.a \ From 08b898b5945149ee26f37ebec7c1b85e6c43ec22 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 3 Jul 2019 17:28:29 +0900 Subject: [PATCH 1308/1313] Remove many dependency for libinknet from QUIC module (cherry picked from commit 39c2c16d908887b079e5ad8dcad19a96ca5439c6) --- iocore/net/Makefile.am | 1 + iocore/net/QUICMultiCertConfigLoader.cc | 350 ++++++++++++++++++++++++ iocore/net/QUICMultiCertConfigLoader.h | 58 ++++ iocore/net/QUICNetProcessor.cc | 1 + iocore/net/QUICNetVConnection.cc | 1 + iocore/net/quic/Makefile.am | 3 - iocore/net/quic/QUICConfig.cc | 240 +--------------- iocore/net/quic/QUICConfig.h | 28 +- iocore/net/quic/QUICGlobals.cc | 82 +----- iocore/net/quic/QUICGlobals.h | 4 - 10 files changed, 414 insertions(+), 354 deletions(-) create mode 100644 iocore/net/QUICMultiCertConfigLoader.cc create mode 100644 iocore/net/QUICMultiCertConfigLoader.h diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am index e4ab3b33f7f..e3514575d4a 100644 --- a/iocore/net/Makefile.am +++ b/iocore/net/Makefile.am @@ -175,6 +175,7 @@ libinknet_a_SOURCES += \ P_QUICNextProtocolAccept.h \ QUICClosedConCollector.cc \ QUICPacketHandler.cc \ + QUICMultiCertConfigLoader.cc \ QUICNet.cc \ QUICNetProcessor.cc \ QUICNetVConnection.cc \ diff --git a/iocore/net/QUICMultiCertConfigLoader.cc b/iocore/net/QUICMultiCertConfigLoader.cc new file mode 100644 index 00000000000..a948a6f8f2e --- /dev/null +++ b/iocore/net/QUICMultiCertConfigLoader.cc @@ -0,0 +1,350 @@ +/** @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 "QUICMultiCertConfigLoader.h" +#include "P_SSLConfig.h" +#include "P_SSLNextProtocolSet.h" +#include "P_OCSPStapling.h" +#include "QUICGlobals.h" +#include "QUICConfig.h" +#include "QUICConnection.h" +#include "QUICTypes.h" +// #include "QUICGlobals.h" + +#define QUICConfDebug(fmt, ...) Debug("quic_conf", fmt, ##__VA_ARGS__) +#define QUICGlobalQCDebug(qc, fmt, ...) Debug("quic_global", "[%s] " fmt, qc->cids().data(), ##__VA_ARGS__) + +int QUICCertConfig::_config_id = 0; + +// +// QUICCertConfig +// +void +QUICCertConfig::startup() +{ + reconfigure(); +} + +void +QUICCertConfig::reconfigure() +{ + SSLConfig::scoped_config params; + SSLCertLookup *lookup = new SSLCertLookup(); + + QUICMultiCertConfigLoader loader(params); + loader.load(lookup); + + _config_id = configProcessor.set(_config_id, lookup); +} + +SSLCertLookup * +QUICCertConfig::acquire() +{ + return static_cast(configProcessor.get(_config_id)); +} + +void +QUICCertConfig::release(SSLCertLookup *lookup) +{ + configProcessor.release(_config_id, lookup); +} + +// +// QUICMultiCertConfigLoader +// +SSL_CTX * +QUICMultiCertConfigLoader::default_server_ssl_ctx() +{ + return quic_new_ssl_ctx(); +} + +SSL_CTX * +QUICMultiCertConfigLoader::init_server_ssl_ctx(std::vector &cert_list, const SSLMultiCertConfigParams *multi_cert_params) +{ + const SSLConfigParams *params = this->_params; + + SSL_CTX *ctx = this->default_server_ssl_ctx(); + + if (multi_cert_params) { + if (multi_cert_params->dialog) { + // TODO: dialog support + } + + if (multi_cert_params->cert) { + if (!SSLMultiCertConfigLoader::load_certs(ctx, cert_list, params, multi_cert_params)) { + goto fail; + } + } + + // SSL_CTX_load_verify_locations() builds the cert chain from the + // serverCACertFilename if that is not nullptr. Otherwise, it uses the hashed + // symlinks in serverCACertPath. + // + // if ssl_ca_name is NOT configured for this cert in ssl_multicert.config + // AND + // if proxy.config.ssl.CA.cert.filename and proxy.config.ssl.CA.cert.path + // are configured + // pass that file as the chain (include all certs in that file) + // else if proxy.config.ssl.CA.cert.path is configured (and + // proxy.config.ssl.CA.cert.filename is nullptr) + // use the hashed symlinks in that directory to build the chain + if (!multi_cert_params->ca && params->serverCACertPath != nullptr) { + if ((!SSL_CTX_load_verify_locations(ctx, params->serverCACertFilename, params->serverCACertPath)) || + (!SSL_CTX_set_default_verify_paths(ctx))) { + Error("invalid CA Certificate file or CA Certificate path"); + goto fail; + } + } + } + + if (params->clientCertLevel != 0) { + // TODO: client cert support + } + + if (!SSLMultiCertConfigLoader::set_session_id_context(ctx, params, multi_cert_params)) { + goto fail; + } + +#if TS_USE_TLS_SET_CIPHERSUITES + if (params->server_tls13_cipher_suites != nullptr) { + if (!SSL_CTX_set_ciphersuites(ctx, params->server_tls13_cipher_suites)) { + Error("invalid tls server cipher suites in records.config"); + goto fail; + } + } +#endif + +#if defined(SSL_CTX_set1_groups_list) || defined(SSL_CTX_set1_curves_list) + if (params->server_groups_list != nullptr) { +#ifdef SSL_CTX_set1_groups_list + if (!SSL_CTX_set1_groups_list(ctx, params->server_groups_list)) { +#else + if (!SSL_CTX_set1_curves_list(ctx, params->server_groups_list)) { +#endif + Error("invalid groups list for server in records.config"); + goto fail; + } + } +#endif + + // SSL_CTX_set_info_callback(ctx, ssl_callback_info); + + SSL_CTX_set_alpn_select_cb(ctx, QUICMultiCertConfigLoader::ssl_select_next_protocol, nullptr); + +#if TS_USE_TLS_OCSP + if (SSLConfigParams::ssl_ocsp_enabled) { + QUICConfDebug("SSL OCSP Stapling is enabled"); + SSL_CTX_set_tlsext_status_cb(ctx, ssl_callback_ocsp_stapling); + const char *cert_name = multi_cert_params ? multi_cert_params->cert.get() : nullptr; + + for (auto cert : cert_list) { + if (!ssl_stapling_init_cert(ctx, cert, cert_name, nullptr)) { + Warning("failed to configure SSL_CTX for OCSP Stapling info for certificate at %s", cert_name); + } + } + } else { + QUICConfDebug("SSL OCSP Stapling is disabled"); + } +#else + if (SSLConfigParams::ssl_ocsp_enabled) { + Warning("failed to enable SSL OCSP Stapling; this version of OpenSSL does not support it"); + } +#endif /* TS_USE_TLS_OCSP */ + + if (SSLConfigParams::init_ssl_ctx_cb) { + SSLConfigParams::init_ssl_ctx_cb(ctx, true); + } + + return ctx; + +fail: + SSLReleaseContext(ctx); + for (auto cert : cert_list) { + X509_free(cert); + } + + return nullptr; +} + +SSL_CTX * +QUICMultiCertConfigLoader::_store_ssl_ctx(SSLCertLookup *lookup, const shared_SSLMultiCertConfigParams multi_cert_params) +{ + std::vector cert_list; + shared_SSL_CTX ctx(this->init_server_ssl_ctx(cert_list, multi_cert_params.get()), SSL_CTX_free); + shared_ssl_ticket_key_block keyblock = nullptr; + bool inserted = false; + + if (!ctx || !multi_cert_params) { + lookup->is_valid = false; + return nullptr; + } + + const char *certname = multi_cert_params->cert.get(); + for (auto cert : cert_list) { + if (0 > SSLMultiCertConfigLoader::check_server_cert_now(cert, certname)) { + /* At this point, we know cert is bad, and we've already printed a + descriptive reason as to why cert is bad to the log file */ + QUICConfDebug("Marking certificate as NOT VALID: %s", certname); + lookup->is_valid = false; + } + } + + // Index this certificate by the specified IP(v6) address. If the address is "*", make it the default context. + if (multi_cert_params->addr) { + if (strcmp(multi_cert_params->addr, "*") == 0) { + if (lookup->insert(multi_cert_params->addr, SSLCertContext(ctx, multi_cert_params, keyblock)) >= 0) { + inserted = true; + lookup->ssl_default = ctx; + this->_set_handshake_callbacks(ctx.get()); + } + } else { + IpEndpoint ep; + + if (ats_ip_pton(multi_cert_params->addr, &ep) == 0) { + QUICConfDebug("mapping '%s' to certificate %s", (const char *)multi_cert_params->addr, (const char *)certname); + if (lookup->insert(ep, SSLCertContext(ctx, multi_cert_params, keyblock)) >= 0) { + inserted = true; + } + } else { + Error("'%s' is not a valid IPv4 or IPv6 address", (const char *)multi_cert_params->addr); + lookup->is_valid = false; + } + } + } + + // Insert additional mappings. Note that this maps multiple keys to the same value, so when + // this code is updated to reconfigure the SSL certificates, it will need some sort of + // refcounting or alternate way of avoiding double frees. + QUICConfDebug("importing SNI names from %s", (const char *)certname); + for (auto cert : cert_list) { + if (SSLMultiCertConfigLoader::index_certificate(lookup, SSLCertContext(ctx, multi_cert_params), cert, certname)) { + inserted = true; + } + } + + if (inserted) { + if (SSLConfigParams::init_ssl_ctx_cb) { + SSLConfigParams::init_ssl_ctx_cb(ctx.get(), true); + } + } + + if (!inserted) { + SSLReleaseContext(ctx.get()); + ctx = nullptr; + } + + for (auto &i : cert_list) { + X509_free(i); + } + + return ctx.get(); +} + +void +QUICMultiCertConfigLoader::_set_handshake_callbacks(SSL_CTX *ssl_ctx) +{ + SSL_CTX_set_cert_cb(ssl_ctx, QUICMultiCertConfigLoader::ssl_cert_cb, nullptr); + SSL_CTX_set_tlsext_servername_callback(ssl_ctx, QUICMultiCertConfigLoader::ssl_sni_cb); + + // Set client hello callback if needed + // SSL_CTX_set_client_hello_cb(ctx, QUIC::ssl_client_hello_cb, nullptr); +} + +int +QUICMultiCertConfigLoader::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned inlen, void *) +{ + const unsigned char *npn; + unsigned npnsz = 0; + QUICConnection *qc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); + + qc->next_protocol_set()->advertiseProtocols(&npn, &npnsz); + if (SSL_select_next_proto((unsigned char **)out, outlen, npn, npnsz, in, inlen) == OPENSSL_NPN_NEGOTIATED) { + return SSL_TLSEXT_ERR_OK; + } + + *out = nullptr; + *outlen = 0; + return SSL_TLSEXT_ERR_NOACK; +} + +int +QUICMultiCertConfigLoader::ssl_sni_cb(SSL *ssl, int * /*ad*/, void * /*arg*/) +{ + // XXX: add SNIConfig support ? + // XXX: add TRANSPORT_BLIND_TUNNEL support ? + return 1; +} + +int +QUICMultiCertConfigLoader::ssl_cert_cb(SSL *ssl, void * /*arg*/) +{ + shared_SSL_CTX ctx = nullptr; + SSLCertContext *cc = nullptr; + QUICCertConfig::scoped_config lookup; + const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + QUICConnection *qc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); + + if (servername == nullptr) { + servername = ""; + } + QUICGlobalQCDebug(qc, "SNI=%s", servername); + + // The incoming SSL_CTX is either the one mapped from the inbound IP address or the default one. If we + // don't find a name-based match at this point, we *do not* want to mess with the context because we've + // already made a best effort to find the best match. + if (likely(servername)) { + cc = lookup->find((char *)servername); + if (cc && cc->getCtx()) { + ctx = cc->getCtx(); + } + } + + // If there's no match on the server name, try to match on the peer address. + if (ctx == nullptr) { + QUICFiveTuple five_tuple = qc->five_tuple(); + IpEndpoint ip = five_tuple.destination(); + cc = lookup->find(ip); + + if (cc && cc->getCtx()) { + ctx = cc->getCtx(); + } + } + + bool found = true; + if (ctx != nullptr) { + SSL_set_SSL_CTX(ssl, ctx.get()); + } else { + found = false; + } + + SSL_CTX *verify_ctx = nullptr; + verify_ctx = SSL_get_SSL_CTX(ssl); + QUICGlobalQCDebug(qc, "%s SSL_CTX %p for requested name '%s'", found ? "found" : "using", verify_ctx, servername); + + if (verify_ctx == nullptr) { + return 0; + } + + return 1; +} diff --git a/iocore/net/QUICMultiCertConfigLoader.h b/iocore/net/QUICMultiCertConfigLoader.h new file mode 100644 index 00000000000..f29bda6ff25 --- /dev/null +++ b/iocore/net/QUICMultiCertConfigLoader.h @@ -0,0 +1,58 @@ +/** @file + * + * A brief file description + * + * @section license License + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "P_SSLCertLookup.h" +#include "P_SSLUtils.h" + +class QUICCertConfig +{ +public: + static void startup(); + static void reconfigure(); + static SSLCertLookup *acquire(); + static void release(SSLCertLookup *lookup); + + using scoped_config = ConfigProcessor::scoped_config; + +private: + static int _config_id; +}; + +class QUICMultiCertConfigLoader : public SSLMultiCertConfigLoader +{ +public: + QUICMultiCertConfigLoader(const SSLConfigParams *p) : SSLMultiCertConfigLoader(p) {} + + virtual SSL_CTX *default_server_ssl_ctx() override; + virtual SSL_CTX *init_server_ssl_ctx(std::vector &cert_list, const SSLMultiCertConfigParams *multi_cert_params) override; + +private: + virtual SSL_CTX *_store_ssl_ctx(SSLCertLookup *lookup, const shared_SSLMultiCertConfigParams multi_cert_params) override; + virtual void _set_handshake_callbacks(SSL_CTX *ssl_ctx) override; + static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, + unsigned inlen, void *); + static int ssl_cert_cb(SSL *ssl, void *arg); + static int ssl_sni_cb(SSL *ssl, int *ad, void *arg); +}; diff --git a/iocore/net/QUICNetProcessor.cc b/iocore/net/QUICNetProcessor.cc index bf3bb1fd972..c14e000230c 100644 --- a/iocore/net/QUICNetProcessor.cc +++ b/iocore/net/QUICNetProcessor.cc @@ -27,6 +27,7 @@ #include "QUICGlobals.h" #include "QUICConfig.h" +#include "QUICMultiCertConfigLoader.h" // // Global Data diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 260ac5fa4b8..5bbd25b8781 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -32,6 +32,7 @@ #include "Log.h" #include "P_SSLNextProtocolSet.h" +#include "QUICMultiCertConfigLoader.h" #include "QUICTLS.h" #include "QUICStats.h" diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 7e2bfcab2f3..ab0af7d79d1 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -126,7 +126,6 @@ test_CPPFLAGS = \ -I$(abs_top_srcdir)/tests/include test_LDADD = \ - $(top_builddir)/iocore/net/libinknet.a \ libquic.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/mgmt/libmgmt_p.la \ @@ -137,11 +136,9 @@ test_LDADD = \ @HWLOC_LIBS@ @OPENSSL_LIBS@ @LIBPCRE@ @YAMLCPP_LIBS@ test_event_main_SOURCES = \ - ../libinknet_stub.cc \ ./test/event_processor_main.cc test_main_SOURCES = \ - ../libinknet_stub.cc \ ./test/main.cc test_QUICAckFrameCreator_CPPFLAGS = $(test_CPPFLAGS) diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index c6ece00300e..600cef8e75f 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -28,18 +28,14 @@ #include #include "P_SSLConfig.h" -#include "P_OCSPStapling.h" #include "QUICGlobals.h" #include "QUICTransportParameters.h" -#define QUICConfDebug(fmt, ...) Debug("quic_conf", fmt, ##__VA_ARGS__) - int QUICConfig::_config_id = 0; int QUICConfigParams::_connection_table_size = 65521; -int QUICCertConfig::_config_id = 0; -static SSL_CTX * +SSL_CTX * quic_new_ssl_ctx() { SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); @@ -476,237 +472,3 @@ QUICConfig::release(QUICConfigParams *params) { configProcessor.release(_config_id, params); } - -// -// QUICCertConfig -// -void -QUICCertConfig::startup() -{ - reconfigure(); -} - -void -QUICCertConfig::reconfigure() -{ - SSLConfig::scoped_config params; - SSLCertLookup *lookup = new SSLCertLookup(); - - QUICMultiCertConfigLoader loader(params); - loader.load(lookup); - - _config_id = configProcessor.set(_config_id, lookup); -} - -SSLCertLookup * -QUICCertConfig::acquire() -{ - return static_cast(configProcessor.get(_config_id)); -} - -void -QUICCertConfig::release(SSLCertLookup *lookup) -{ - configProcessor.release(_config_id, lookup); -} - -// -// QUICMultiCertConfigLoader -// -SSL_CTX * -QUICMultiCertConfigLoader::default_server_ssl_ctx() -{ - return quic_new_ssl_ctx(); -} - -SSL_CTX * -QUICMultiCertConfigLoader::init_server_ssl_ctx(std::vector &cert_list, const SSLMultiCertConfigParams *multi_cert_params) -{ - const SSLConfigParams *params = this->_params; - - SSL_CTX *ctx = this->default_server_ssl_ctx(); - - if (multi_cert_params) { - if (multi_cert_params->dialog) { - // TODO: dialog support - } - - if (multi_cert_params->cert) { - if (!SSLMultiCertConfigLoader::load_certs(ctx, cert_list, params, multi_cert_params)) { - goto fail; - } - } - - // SSL_CTX_load_verify_locations() builds the cert chain from the - // serverCACertFilename if that is not nullptr. Otherwise, it uses the hashed - // symlinks in serverCACertPath. - // - // if ssl_ca_name is NOT configured for this cert in ssl_multicert.config - // AND - // if proxy.config.ssl.CA.cert.filename and proxy.config.ssl.CA.cert.path - // are configured - // pass that file as the chain (include all certs in that file) - // else if proxy.config.ssl.CA.cert.path is configured (and - // proxy.config.ssl.CA.cert.filename is nullptr) - // use the hashed symlinks in that directory to build the chain - if (!multi_cert_params->ca && params->serverCACertPath != nullptr) { - if ((!SSL_CTX_load_verify_locations(ctx, params->serverCACertFilename, params->serverCACertPath)) || - (!SSL_CTX_set_default_verify_paths(ctx))) { - Error("invalid CA Certificate file or CA Certificate path"); - goto fail; - } - } - } - - if (params->clientCertLevel != 0) { - // TODO: client cert support - } - - if (!SSLMultiCertConfigLoader::set_session_id_context(ctx, params, multi_cert_params)) { - goto fail; - } - -#if TS_USE_TLS_SET_CIPHERSUITES - if (params->server_tls13_cipher_suites != nullptr) { - if (!SSL_CTX_set_ciphersuites(ctx, params->server_tls13_cipher_suites)) { - Error("invalid tls server cipher suites in records.config"); - goto fail; - } - } -#endif - -#if defined(SSL_CTX_set1_groups_list) || defined(SSL_CTX_set1_curves_list) - if (params->server_groups_list != nullptr) { -#ifdef SSL_CTX_set1_groups_list - if (!SSL_CTX_set1_groups_list(ctx, params->server_groups_list)) { -#else - if (!SSL_CTX_set1_curves_list(ctx, params->server_groups_list)) { -#endif - Error("invalid groups list for server in records.config"); - goto fail; - } - } -#endif - - // SSL_CTX_set_info_callback(ctx, ssl_callback_info); - - SSL_CTX_set_alpn_select_cb(ctx, QUIC::ssl_select_next_protocol, nullptr); - -#if TS_USE_TLS_OCSP - if (SSLConfigParams::ssl_ocsp_enabled) { - QUICConfDebug("SSL OCSP Stapling is enabled"); - SSL_CTX_set_tlsext_status_cb(ctx, ssl_callback_ocsp_stapling); - const char *cert_name = multi_cert_params ? multi_cert_params->cert.get() : nullptr; - - for (auto cert : cert_list) { - if (!ssl_stapling_init_cert(ctx, cert, cert_name, nullptr)) { - Warning("failed to configure SSL_CTX for OCSP Stapling info for certificate at %s", cert_name); - } - } - } else { - QUICConfDebug("SSL OCSP Stapling is disabled"); - } -#else - if (SSLConfigParams::ssl_ocsp_enabled) { - Warning("failed to enable SSL OCSP Stapling; this version of OpenSSL does not support it"); - } -#endif /* TS_USE_TLS_OCSP */ - - if (SSLConfigParams::init_ssl_ctx_cb) { - SSLConfigParams::init_ssl_ctx_cb(ctx, true); - } - - return ctx; - -fail: - SSLReleaseContext(ctx); - for (auto cert : cert_list) { - X509_free(cert); - } - - return nullptr; -} - -SSL_CTX * -QUICMultiCertConfigLoader::_store_ssl_ctx(SSLCertLookup *lookup, const shared_SSLMultiCertConfigParams multi_cert_params) -{ - std::vector cert_list; - shared_SSL_CTX ctx(this->init_server_ssl_ctx(cert_list, multi_cert_params.get()), SSL_CTX_free); - shared_ssl_ticket_key_block keyblock = nullptr; - bool inserted = false; - - if (!ctx || !multi_cert_params) { - lookup->is_valid = false; - return nullptr; - } - - const char *certname = multi_cert_params->cert.get(); - for (auto cert : cert_list) { - if (0 > SSLMultiCertConfigLoader::check_server_cert_now(cert, certname)) { - /* At this point, we know cert is bad, and we've already printed a - descriptive reason as to why cert is bad to the log file */ - QUICConfDebug("Marking certificate as NOT VALID: %s", certname); - lookup->is_valid = false; - } - } - - // Index this certificate by the specified IP(v6) address. If the address is "*", make it the default context. - if (multi_cert_params->addr) { - if (strcmp(multi_cert_params->addr, "*") == 0) { - if (lookup->insert(multi_cert_params->addr, SSLCertContext(ctx, multi_cert_params, keyblock)) >= 0) { - inserted = true; - lookup->ssl_default = ctx; - this->_set_handshake_callbacks(ctx.get()); - } - } else { - IpEndpoint ep; - - if (ats_ip_pton(multi_cert_params->addr, &ep) == 0) { - QUICConfDebug("mapping '%s' to certificate %s", (const char *)multi_cert_params->addr, (const char *)certname); - if (lookup->insert(ep, SSLCertContext(ctx, multi_cert_params, keyblock)) >= 0) { - inserted = true; - } - } else { - Error("'%s' is not a valid IPv4 or IPv6 address", (const char *)multi_cert_params->addr); - lookup->is_valid = false; - } - } - } - - // Insert additional mappings. Note that this maps multiple keys to the same value, so when - // this code is updated to reconfigure the SSL certificates, it will need some sort of - // refcounting or alternate way of avoiding double frees. - QUICConfDebug("importing SNI names from %s", (const char *)certname); - for (auto cert : cert_list) { - if (SSLMultiCertConfigLoader::index_certificate(lookup, SSLCertContext(ctx, multi_cert_params), cert, certname)) { - inserted = true; - } - } - - if (inserted) { - if (SSLConfigParams::init_ssl_ctx_cb) { - SSLConfigParams::init_ssl_ctx_cb(ctx.get(), true); - } - } - - if (!inserted) { - SSLReleaseContext(ctx.get()); - ctx = nullptr; - } - - for (auto &i : cert_list) { - X509_free(i); - } - - return ctx.get(); -} - -void -QUICMultiCertConfigLoader::_set_handshake_callbacks(SSL_CTX *ssl_ctx) -{ - SSL_CTX_set_cert_cb(ssl_ctx, QUIC::ssl_cert_cb, nullptr); - SSL_CTX_set_tlsext_servername_callback(ssl_ctx, QUIC::ssl_sni_cb); - - // Set client hello callback if needed - // SSL_CTX_set_client_hello_cb(ctx, QUIC::ssl_client_hello_cb, nullptr); -} diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index e0ac1dcfdb0..36ff7af9554 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -27,7 +27,6 @@ #include "ProxyConfig.h" #include "P_SSLCertLookup.h" -#include "P_SSLUtils.h" class QUICConfigParams : public ConfigInfo { @@ -158,29 +157,4 @@ class QUICConfig static int _config_id; }; -class QUICCertConfig -{ -public: - static void startup(); - static void reconfigure(); - static SSLCertLookup *acquire(); - static void release(SSLCertLookup *lookup); - - using scoped_config = ConfigProcessor::scoped_config; - -private: - static int _config_id; -}; - -class QUICMultiCertConfigLoader : public SSLMultiCertConfigLoader -{ -public: - QUICMultiCertConfigLoader(const SSLConfigParams *p) : SSLMultiCertConfigLoader(p) {} - - virtual SSL_CTX *default_server_ssl_ctx() override; - virtual SSL_CTX *init_server_ssl_ctx(std::vector &cert_list, const SSLMultiCertConfigParams *multi_cert_params) override; - -private: - virtual SSL_CTX *_store_ssl_ctx(SSLCertLookup *lookup, const shared_SSLMultiCertConfigParams multi_cert_params) override; - virtual void _set_handshake_callbacks(SSL_CTX *ssl_ctx) override; -}; +SSL_CTX *quic_new_ssl_ctx(); diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc index 4b54d372398..14761aa5d8d 100644 --- a/iocore/net/quic/QUICGlobals.cc +++ b/iocore/net/quic/QUICGlobals.cc @@ -26,7 +26,7 @@ #include #include -#include "P_SSLNextProtocolSet.h" +#include "QUICMultiCertConfigLoader.h" #include "QUICStats.h" #include "QUICConfig.h" @@ -36,7 +36,6 @@ #include #define QUICGlobalDebug(fmt, ...) Debug("quic_global", fmt, ##__VA_ARGS__) -#define QUICGlobalQCDebug(qc, fmt, ...) Debug("quic_global", "[%s] " fmt, qc->cids().data(), ##__VA_ARGS__) RecRawStatBlock *quic_rsb; @@ -51,24 +50,6 @@ QUIC::init() ssl_quic_tls_index = SSL_get_ex_new_index(0, (void *)"QUICTLS index", nullptr, nullptr, nullptr); } -int -QUIC::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen, - void *) -{ - const unsigned char *npn; - unsigned npnsz = 0; - QUICConnection *qc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); - - qc->next_protocol_set()->advertiseProtocols(&npn, &npnsz); - if (SSL_select_next_proto((unsigned char **)out, outlen, npn, npnsz, in, inlen) == OPENSSL_NPN_NEGOTIATED) { - return SSL_TLSEXT_ERR_OK; - } - - *out = nullptr; - *outlen = 0; - return SSL_TLSEXT_ERR_NOACK; -} - int QUIC::ssl_client_new_session(SSL *ssl, SSL_SESSION *session) { @@ -103,67 +84,6 @@ QUIC::ssl_client_keylog_cb(const SSL *ssl, const char *line) file.flush(); } -int -QUIC::ssl_cert_cb(SSL *ssl, void * /*arg*/) -{ - shared_SSL_CTX ctx = nullptr; - SSLCertContext *cc = nullptr; - QUICCertConfig::scoped_config lookup; - const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); - QUICConnection *qc = static_cast(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); - - if (servername == nullptr) { - servername = ""; - } - QUICGlobalQCDebug(qc, "SNI=%s", servername); - - // The incoming SSL_CTX is either the one mapped from the inbound IP address or the default one. If we - // don't find a name-based match at this point, we *do not* want to mess with the context because we've - // already made a best effort to find the best match. - if (likely(servername)) { - cc = lookup->find((char *)servername); - if (cc && cc->getCtx()) { - ctx = cc->getCtx(); - } - } - - // If there's no match on the server name, try to match on the peer address. - if (ctx == nullptr) { - QUICFiveTuple five_tuple = qc->five_tuple(); - IpEndpoint ip = five_tuple.destination(); - cc = lookup->find(ip); - - if (cc && cc->getCtx()) { - ctx = cc->getCtx(); - } - } - - bool found = true; - if (ctx != nullptr) { - SSL_set_SSL_CTX(ssl, ctx.get()); - } else { - found = false; - } - - SSL_CTX *verify_ctx = nullptr; - verify_ctx = SSL_get_SSL_CTX(ssl); - QUICGlobalQCDebug(qc, "%s SSL_CTX %p for requested name '%s'", found ? "found" : "using", verify_ctx, servername); - - if (verify_ctx == nullptr) { - return 0; - } - - return 1; -} - -int -QUIC::ssl_sni_cb(SSL *ssl, int * /*ad*/, void * /*arg*/) -{ - // XXX: add SNIConfig support ? - // XXX: add TRANSPORT_BLIND_TUNNEL support ? - return 1; -} - void QUIC::_register_stats() { diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h index 0bbde28373d..41b29afbf12 100644 --- a/iocore/net/quic/QUICGlobals.h +++ b/iocore/net/quic/QUICGlobals.h @@ -31,12 +31,8 @@ class QUIC static void init(); // SSL callbacks - static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, - unsigned inlen, void *); static int ssl_client_new_session(SSL *ssl, SSL_SESSION *session); static void ssl_client_keylog_cb(const SSL *ssl, const char *line); - static int ssl_cert_cb(SSL *ssl, void *arg); - static int ssl_sni_cb(SSL *ssl, int *ad, void *arg); static int ssl_quic_qc_index; static int ssl_quic_tls_index; From cf7b61e8d320e8fee909c4dec35359495d525172 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 3 Jul 2019 18:00:22 +0900 Subject: [PATCH 1309/1313] Add dependency for libUglyLogStubs.a for now to pass the CI job (cherry picked from commit 065983974c9e8fd0d71240f7e3b420860a7f8d13) --- iocore/net/quic/Makefile.am | 1 + iocore/net/quic/QUICAckFrameCreator.h | 1 - iocore/net/quic/test/test_QUICAckFrameCreator.cc | 2 -- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index ab0af7d79d1..4b215d0a93e 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -130,6 +130,7 @@ test_LDADD = \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ $(top_builddir)/src/tscore/libtscore.la \ $(top_builddir)/src/tscpp/util/libtscpputil.la \ $(top_builddir)/proxy/ParentSelectionStrategy.o \ diff --git a/iocore/net/quic/QUICAckFrameCreator.h b/iocore/net/quic/QUICAckFrameCreator.h index 081c7d99694..08b50d470bc 100644 --- a/iocore/net/quic/QUICAckFrameCreator.h +++ b/iocore/net/quic/QUICAckFrameCreator.h @@ -27,7 +27,6 @@ #include "QUICTypes.h" #include "QUICFrame.h" #include -#include class QUICConnection; diff --git a/iocore/net/quic/test/test_QUICAckFrameCreator.cc b/iocore/net/quic/test/test_QUICAckFrameCreator.cc index 94913b47dba..99b40e73555 100644 --- a/iocore/net/quic/test/test_QUICAckFrameCreator.cc +++ b/iocore/net/quic/test/test_QUICAckFrameCreator.cc @@ -23,9 +23,7 @@ #include "catch.hpp" -#include "I_EventSystem.h" #include "quic/QUICAckFrameCreator.h" -#include "Mock.h" TEST_CASE("QUICAckFrameManager", "[quic]") { From b4f20d9d7ba21024b99aebf23567a1889e1ed0ff Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 4 Jul 2019 11:39:01 +0900 Subject: [PATCH 1310/1313] Fix a build issue on CentOS (cherry picked from commit d88d887d8d33656f044e0076b56c4678a62c85b0) --- iocore/net/quic/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am index 4b215d0a93e..e13d1de2a93 100644 --- a/iocore/net/quic/Makefile.am +++ b/iocore/net/quic/Makefile.am @@ -128,8 +128,8 @@ test_CPPFLAGS = \ test_LDADD = \ libquic.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/proxy/shared/libUglyLogStubs.a \ $(top_builddir)/src/tscore/libtscore.la \ $(top_builddir)/src/tscpp/util/libtscpputil.la \ From f428cc465941ba242d1d01e146e7196fb83cb5e5 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 4 Jul 2019 12:48:28 +0900 Subject: [PATCH 1311/1313] Remove dependency for libinknet and etc (cherry picked from commit 91f1726b39403890158cdf1a308ef190e0f7b5c8) --- proxy/http3/Makefile.am | 18 +----- proxy/http3/test/stub.cc | 117 --------------------------------------- 2 files changed, 3 insertions(+), 132 deletions(-) delete mode 100644 proxy/http3/test/stub.cc diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index 3118ef24b49..561b3a1731b 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -69,17 +69,15 @@ test_CPPFLAGS = \ test_LDADD = \ libhttp3.a \ - $(top_builddir)/iocore/net/libinknet.a \ $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/src/tscore/libtscore.la \ $(top_builddir)/src/tscpp/util/libtscpputil.la \ - $(top_builddir)/proxy/ParentSelectionStrategy.o \ $(top_builddir)/proxy/http2/libhttp2.a \ - $(top_builddir)/proxy/libproxy.a \ $(top_builddir)/proxy/hdrs/libhdrs.a \ + $(top_builddir)/proxy/shared/libUglyLogStubs.a \ @LIBPCRE@ \ @OPENSSL_LIBS@ \ @HWLOC_LIBS@ @@ -89,24 +87,14 @@ test_libhttp3_LDFLAGS = @AM_LDFLAGS@ test_libhttp3_LDADD = $(test_LDADD) test_libhttp3_SOURCES = \ ./test/main.cc \ - ./test/test_Http3Frame.cc \ - ./test/stub.cc \ - ../http/HttpConfig.cc \ - ../http/HttpConnectionCount.cc \ - ../http/ForwardedConfig.cc \ - ../../iocore/net/libinknet_stub.cc + ./test/test_Http3Frame.cc test_qpack_CPPFLAGS = $(test_CPPFLAGS) test_qpack_LDFLAGS = @AM_LDFLAGS@ test_qpack_LDADD = $(test_LDADD) test_qpack_SOURCES = \ ./test/main_qpack.cc \ - ./test/test_QPACK.cc \ - ./test/stub.cc \ - ../http/HttpConfig.cc \ - ../http/HttpConnectionCount.cc \ - ../http/ForwardedConfig.cc \ - ../../iocore/net/libinknet_stub.cc + ./test/test_QPACK.cc # diff --git a/proxy/http3/test/stub.cc b/proxy/http3/test/stub.cc deleted file mode 100644 index a4fc9c0d114..00000000000 --- a/proxy/http3/test/stub.cc +++ /dev/null @@ -1,117 +0,0 @@ -/** @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. - */ - -// FIXME: remove stub - -#include "I_EventSystem.h" -#include "InkAPIInternal.h" - -void -APIHooks::clear() -{ - ink_abort("do not call stub"); -} - -void -APIHooks::append(INKContInternal *) -{ - ink_abort("do not call stub"); -} - -void -APIHooks::prepend(INKContInternal *) -{ - ink_abort("do not call stub"); -} - -#include "HttpDebugNames.h" -const char * -HttpDebugNames::get_api_hook_name(TSHttpHookID t) -{ - return "dummy"; -} - -#include "HttpSM.h" -HttpSM::HttpSM() : Continuation(nullptr), vc_table(this) {} - -void -HttpSM::cleanup() -{ - ink_abort("do not call stub"); -} - -void -HttpSM::destroy() -{ - ink_abort("do not call stub"); -} - -void -HttpSM::set_next_state() -{ - ink_abort("do not call stub"); -} - -void -HttpSM::handle_api_return() -{ - ink_abort("do not call stub"); -} - -int -HttpSM::kill_this_async_hook(int /* event ATS_UNUSED */, void * /* data ATS_UNUSED */) -{ - return EVENT_DONE; -} - -void -HttpSM::attach_client_session(ProxyTransaction *, IOBufferReader *) -{ - ink_abort("do not call stub"); -} - -void -HttpSM::init() -{ - ink_abort("do not call stub"); -} - -ClassAllocator httpSMAllocator("httpSMAllocator"); -HttpAPIHooks *http_global_hooks; - -HttpVCTable::HttpVCTable(HttpSM *) {} - -PostDataBuffers::~PostDataBuffers() {} - -HttpTunnel::HttpTunnel() : Continuation(nullptr) {} -HttpTunnelConsumer::HttpTunnelConsumer() {} -HttpTunnelProducer::HttpTunnelProducer() {} -ChunkedHandler::ChunkedHandler() {} - -HttpCacheSM::HttpCacheSM() {} - -HttpCacheAction::HttpCacheAction() : sm(nullptr) {} -void -HttpCacheAction::cancel(Continuation *c) -{ -} From 319a46fabc1b0dae3651548b11d3ebd752acce3a Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 4 Jul 2019 12:52:45 +0900 Subject: [PATCH 1312/1313] Fix a build issue on CentOS (cherry picked from commit 96293892f9306948c45f4adbd6e99e47d72cc5e3) --- proxy/http3/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index 561b3a1731b..43fcddf9cc3 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -71,8 +71,8 @@ test_LDADD = \ libhttp3.a \ $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ $(top_builddir)/src/tscore/libtscore.la \ $(top_builddir)/src/tscpp/util/libtscpputil.la \ $(top_builddir)/proxy/http2/libhttp2.a \ From 5f39e7f270ce211e274391357ced328560500ad4 Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Thu, 4 Jul 2019 14:08:35 +0900 Subject: [PATCH 1313/1313] Fix build issues on macOS (cherry picked from commit ec333e7e62ce61d87774b3801dc37cba6fff0354) --- proxy/http3/Makefile.am | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/proxy/http3/Makefile.am b/proxy/http3/Makefile.am index 43fcddf9cc3..f5d4de5906f 100644 --- a/proxy/http3/Makefile.am +++ b/proxy/http3/Makefile.am @@ -68,7 +68,6 @@ test_CPPFLAGS = \ -I$(abs_top_srcdir)/tests/include test_LDADD = \ - libhttp3.a \ $(top_builddir)/iocore/net/quic/libquic.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/lib/records/librecords_p.a \ @@ -87,14 +86,17 @@ test_libhttp3_LDFLAGS = @AM_LDFLAGS@ test_libhttp3_LDADD = $(test_LDADD) test_libhttp3_SOURCES = \ ./test/main.cc \ - ./test/test_Http3Frame.cc + ./test/test_Http3Frame.cc \ + ./Http3Config.cc \ + ./Http3Frame.cc test_qpack_CPPFLAGS = $(test_CPPFLAGS) test_qpack_LDFLAGS = @AM_LDFLAGS@ test_qpack_LDADD = $(test_LDADD) test_qpack_SOURCES = \ ./test/main_qpack.cc \ - ./test/test_QPACK.cc + ./test/test_QPACK.cc \ + ./QPACK.cc #